|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// デバッガ (外部用)
//
#pragma once
#include "debugger_defs.h"
#include "bus.h"
#include "monitor.h"
#include "textscreen.h"
#include "thread.h"
#include <array>
#include <condition_variable>
#include <mutex>
class BranchHistory;
class HostCOMDevice;
class MemdumpMonitor;
class Syncer;
class VectorTable;
class Debugger : public ThreadDevice
{
using inherited = ThreadDevice;
friend class DebuggerMD_m680x0;
friend class DebuggerMD_m88xx0;
private:
// リクエストフラグ
static const uint32 REQUEST_EXIT = 0x0001; // 終了
static const uint32 REQUEST_RXCHAR = 0x0002; // 1文字受信
static const uint32 REQUEST_ACCEPT = 0x0004; // 着信通知
static const uint32 REQUEST_PROMPT = 0x0008; // プロンプト要求
// コマンド
enum CmdAct {
Stay, // デバッガプロンプトに留まる
Leave, // デバッガプロンプトを抜けて VM を実行する
Quit, // デバッガとの接続を終了する
};
struct cmddef_t {
const char *name;
CmdAct (Debugger::*func)();
};
// ブレークポイント種別
enum BreakpointType {
Unused = 0,
Address, // このアドレスに来る直前
Memory, // このアドレスをアクセスした直後
Exception, // この例外を検出した直後
Instruction, // この命令を実行する直前
};
// ブレークポイント
struct breakpoint_t {
DebuggerMD *md {}; // CPU
BreakpointType type {}; // 種別
// 種別ごとのパラメータ
union {
uint32 addr {}; // ターゲットアドレス (Address/Memory)
struct {
int vec1; // ベクタ番号 (開始)
int vec2; // ベクタ番号 (終了)
};
struct {
uint32 inst; // 命令ワード
uint32 mask; // マスク
int instbytes; // 命令バイト数
};
};
uint32 matched {}; // 成立回数 (積算)
// skip はユーザ指定値。ただし
// -1 なら常にスキップ、つまりブレークせずカウントのみ行う、
// 0 ならスキップなし、つまり成立ごとにブレーク(これがデフォルト)、
// n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。
int32 skip {}; // スキップ回数 (ユーザ指定値)
int32 skipremain {}; // 残りスキップ回数 (0 で成立)
};
static const int MAX_BREAKPOINTS = 8;
// ステップ実行種別
enum StepType {
None, // なし
Count, // 命令数指定
CountSkipSub, // 命令数指定 (サブルーチンをスキップ)
StepOut, // ステップアウト
Addr, // アドレス指定
Time, // 時間指定
};
public:
Debugger();
~Debugger() override;
bool Create() override;
void SetLogLevel(int) override;
bool Init() override;
void ThreadRun() override;
void Terminate() override;
void ExecMain() { Exec(md_mpu.get()); }
void ExecXP() { Exec(md_xp.get()); }
// MPU トレースが必要なら true を返す
bool IsTrace() const;
// FILE コールバック
int ReadFunc(char *, int);
int WriteFunc(const char *, int);
private:
void Close();
void RxCallback(uint32);
void AcceptCallback(uint32);
void Input(int);
void EnterPrompt();
void QuitPrompt();
void LeavePrompt(bool trace);
void PrintPrompt();
void Exec(DebuggerMD *);
CmdAct Command();
bool CheckAllBreakpoints(DebuggerMD *);
uint64 ReadBreakpointInst(breakpoint_t&);
void ParseCmdbuf();
// コマンド名は大文字小文字を区別する関係でスネークスタイル。
CmdAct cmd_b();
CmdAct cmd_bi();
CmdAct cmd_bm();
CmdAct cmd_bv();
CmdAct cmd_b_list();
CmdAct cmd_b_set(BreakpointType);
CmdAct cmd_b_delete();
CmdAct cmd_brhist();
CmdAct cmd_bx();
CmdAct cmd_c();
CmdAct cmd_ct();
CmdAct cmd_d();
CmdAct cmd_D();
CmdAct cmd_disp();
CmdAct cmd_exhist();
CmdAct cmd_h();
CmdAct cmd_hb();
CmdAct cmd_hr();
CmdAct cmd_L();
CmdAct cmd_m();
CmdAct cmd_mpu();
CmdAct cmd_M();
CmdAct cmd_minus();
CmdAct cmd_n();
CmdAct cmd_nt();
CmdAct cmd_pe();
CmdAct cmd_pf();
CmdAct cmd_q();
CmdAct cmd_reset();
CmdAct cmd_s();
CmdAct cmd_st();
CmdAct cmd_so();
CmdAct cmd_sot();
CmdAct cmd_show();
CmdAct cmd_t();
CmdAct cmd_xp();
CmdAct cmd_z();
bool Check(DebuggerMD *);
bool ParseOptBreakAddr(const std::string&);
bool ParseOptBreakInst(const std::string&);
bool ParseOptBreakVector(const std::string&);
bool IsCPUStr(const std::string&) const;
DebuggerMD *ParseCPU(const std::string&) const;
int AddBreakInst(const std::string& cpustr, const std::string& inststr,
const std::string& skipstr, std::string *errstr);
int AddBreakVector(const std::string& cpustr, const std::string& vecstr,
const std::string& skipstr, std::string *errstr);
int AddBreakpoint(const breakpoint_t&);
bool GetAddr(busaddr *addr, bool);
CmdAct cmd_d_common(busaddr access_mode);
CmdAct cmd_hist_common(BranchHistory& hist);
CmdAct cmd_m_common(busaddr access_mode);
CmdAct cmd_n_common(bool);
CmdAct cmd_s_common(bool);
CmdAct cmd_so_common(bool);
bool ParseVector(DebuggerMD *, const char *arg, uint32 *valp);
bool ParseVerbHex(const char *arg, uint32 *valp);
bool ParseAddr(const char *arg, uint32_t *addrp);
bool ParseTime(const char *arg, uint64 *timep);
void SetNBreakpoint();
void ChangeMD(DebuggerMD *);
void ResetStickyAddr();
static const HelpMessages HelpListMain;
static const HelpMessages HelpListBreakpoints;
static const HelpMessages HelpDetails;
CmdAct ShowHelpList(const HelpMessages& msgs);
// 個別ヘルプメッセージを出力用に置換
std::string HelpConvert(const std::string& msg);
// モニタを更新して表示
void ShowMonitor(Monitor *monitor);
// テキストスクリーンを表示
void ShowTextScreen(TextScreen& screen);
// 機種依存部分
std::unique_ptr<DebuggerMD> md_mpu /*{}*/; // メイン
std::unique_ptr<DebuggerMD> md_xp /*{}*/; // XP
// 現行
DebuggerMD *curmd {};
std::mutex mtx {};
// このスレッドへのリクエスト
std::condition_variable cv_request {};
uint32 request {};
// コマンドモード(プロンプト)なら true
std::condition_variable cv_prompt {};
bool prompt_released {};
bool is_prompt {};
// コンソール
std::unique_ptr<HostCOMDevice> hostcom /*{}*/;
FILE *cons {};
const char *prompt {}; // プロンプト文字列
std::string cmdbuf {}; // 現在のコマンドライン
std::string last_cmdbuf {}; // 直前のコマンドライン
std::vector<std::string> cmdargs {};
uint32 pc {};
std::array<breakpoint_t, MAX_BREAKPOINTS> bpoint {};
uint64 ct_timespan {};
busaddr d_last_addr {};
busaddr m_last_addr {};
StepType step_type {}; // ステップ実行種別
DebuggerMD *step_md {}; // ステップ実行中の CPU
uint32 step_count {};
uint64 step_addr {};
uint64 step_time {};
DebuggerMD *t_enable {};
uint32 t_count {};
// 一度VMを実行して再びプロンプトに来たら true
bool is_continued {};
// MPU を一時停止するとき true (ワンショット)
bool is_pause {};
// プロンプトで表示するレジスタ群
std::vector<std::string> disp_regs {};
// ブレークポイント到達メッセージ
// (コンソールが獲得できるまで保留しておくため)
std::string bpointmsg {};
// ブレークポイントモニタ
DECLARE_MONITOR_SCREEN(MonitorScreenBpoint);
Monitor *bpoint_monitor {};
// 逆アセンブルとメモリダンプモニタ
std::array<std::unique_ptr<MemdumpMonitor>, MAX_MEMDUMP_MONITOR>
memdump_monitor /*{}*/;
std::array<std::unique_ptr<MemdumpMonitor>, MAX_XPMEMDUMP_MONITOR>
xpmemdump_monitor /*{}*/;
// ベクタテーブル
std::unique_ptr<VectorTable> pVectorTable /*{}*/;
Syncer *syncer {};
static std::vector<cmddef_t> cmdtable;
};
inline Debugger *GetDebugger() {
return Object::GetObject<Debugger>(OBJ_DEBUGGER);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.