|
|
1.1 root 1: //
2: // nono
1.1.1.2 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
7: #pragma once
8:
1.1.1.3 root 9: #include "branchhistory.h"
1.1 root 10: #include "bus.h"
11: #include "cvprompt.h"
1.1.1.7 ! root 12: #include "monitor.h"
1.1 root 13: #include "textscreen.h"
1.1.1.2 root 14: #include <array>
15:
16: using ConstStringPair = std::pair<const std::string, const std::string>;
17: using HelpMessages = std::vector<ConstStringPair>;
1.1 root 18:
19: // 諸情報付きのアドレス
1.1.1.5 root 20: class saddr_t
1.1 root 21: {
1.1.1.5 root 22: public:
23: // コンストラクタ
24: saddr_t() { }
25:
26: saddr_t(uint32 addr_, bool super_)
27: : saddr_t(addr_, super_, false) { }
28:
29: saddr_t(uint32 addr_, bool super_, bool data_) {
30: Set(addr_, super_, data_);
31: }
32: // コピーコンストラクタ
33: saddr_t(const saddr_t& rhs) {
34: Set(rhs);
35: }
36: // 代入演算子
37: saddr_t& operator=(const saddr_t& rhs) {
38: Set(rhs);
39: return *this;
40: }
41:
42: // 代入演算子 (uint32 を代入するとアドレスだけ差し替える)
43: saddr_t& operator=(uint32 rhs) {
44: SetAddr(rhs);
45: return *this;
46: }
47:
48: // 代入
49: void Set(uint32 addr_, bool super_, bool data_) {
50: addr = addr_;
51: super = super_;
52: data = data_;
53: }
54:
55: uint32 GetAddr() const { return addr; }
56: bool IsSuper() const { return super; }
57: bool IsData() const { return data; }
58: void SetAddr(uint32 addr_) { addr = addr_; }
59: void SetSuper(bool super_) { super = super_; }
60: void SetData(bool data_) { data = data_; }
61:
62: // (uint32)saddr でアドレスだけ取り出せると楽
63: explicit operator uint32() const { return GetAddr(); }
64:
65: // saddr += n でアドレス進められると楽
66: uint32 operator+=(uint32 val) {
67: addr += val;
68: return addr;
69: }
70: // saddr++ でアドレス進められると楽
71: void operator++(int n) {
72: addr++;
73: }
1.1 root 74:
1.1.1.5 root 75: private:
76: void Set(const saddr_t& rhs) {
77: addr = rhs.addr;
78: super = rhs.super;
79: data = rhs.data;
1.1 root 80: }
1.1.1.5 root 81:
82: uint32 addr {}; // アドレス (32bit)
83: bool super {}; // スーパーバイザアクセスなら true
84: bool data {}; // データ空間アクセスなら true
1.1 root 85: };
86:
1.1.1.5 root 87: enum class MemoryMode : bool
88: {
89: Logical = false,
90: Physical = true,
1.1 root 91: };
92:
1.1.1.5 root 93: enum class MMULookupMode : bool
94: {
95: False = false,
96: True = true,
97: // MemoryMode::Physical ならこの項は意味を持たないので、
98: // True でも False でもないと言いたい。
99: None = false,
100: };
101:
102: // saddr_t の後で Debugger の前...
103: #include "debugger_memory.h"
104:
1.1 root 105: class Console;
106: class DebuggerMD;
107: class Disasm;
108:
1.1.1.7 ! root 109: class Debugger final : public Object
1.1 root 110: {
1.1.1.7 ! root 111: using inherited = Object;
1.1 root 112: friend class DebuggerMD_m680x0;
113: friend class DebuggerMD_m88xx0;
1.1.1.5 root 114: public:
115: enum class Arch {
116: M680x0,
117: M88xx0,
118: };
119:
1.1 root 120: private:
121: // 型
1.1.1.2 root 122: enum CommandAction {
123: Stay, // デバッガプロンプトに留まる
124: Leave, // デバッガプロンプトを抜けて VM を実行する
125: Quit, // デバッガとの接続を終了する
126: };
127: using cmdfunc_t = void (Debugger::*)();
1.1 root 128: typedef struct {
129: const char *name;
130: cmdfunc_t func;
1.1.1.2 root 131: CommandAction action;
1.1 root 132: } cmddef_t;
133:
1.1.1.3 root 134: // ブレークポイント種別
135: enum BreakpointType {
136: Unused = 0,
137: Address, // このアドレスに来る直前
138: Memory, // このアドレスをアクセスした直後
139: Exception, // この例外を検出した直後
140: Instruction, // この命令を実行する直前
141: };
142:
1.1 root 143: // ブレークポイント
144: typedef struct {
1.1.1.3 root 145: BreakpointType type {}; // 種別
146: // 種別ごとのパラメータ
147: union {
148: uint32 addr {}; // ターゲットアドレス (Address/Memory)
149: struct {
150: int vec1; // ベクタ番号 (開始)
151: int vec2; // ベクタ番号 (終了)
152: };
153: struct {
154: uint32 inst; // 命令ワード
155: uint32 mask; // マスク
156: };
157: };
158:
159: uint32 matched {}; // 成立回数 (積算)
160:
161: // skip はユーザ指定値。ただし
162: // -1 なら常にスキップ、つまりブレークせずカウントのみ行う、
163: // 0 ならスキップなし、つまり成立ごとにブレーク(これがデフォルト)、
164: // n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。
165: int32 skip {}; // スキップ回数 (ユーザ指定値)
166: int32 skipremain {}; // 残りスキップ回数 (0 で成立)
1.1 root 167: } breakpoint_t;
168: static const int MAX_BREAKPOINTS = 8;
169:
170: public:
171: Debugger();
1.1.1.2 root 172: ~Debugger() { }
1.1 root 173:
174: void Init();
175: void ThreadRun();
176: bool Check();
1.1.1.3 root 177: void NotifyException(int vector);
178:
1.1.1.7 ! root 179: // メモリダンプモニタ
! 180: // GUI 用 (show コマンドでも見れるけど)
! 181: std::array<Monitor, MAX_MEMDUMP_MONITOR> memdump_monitor;
! 182:
! 183: // m/M コマンド用のメモリダンプモニタ
! 184: Monitor m_monitor { this };
1.1 root 185:
186: private:
1.1.1.2 root 187: bool Accept();
188: bool AcquirePrompt();
189: CommandAction MainLoop();
1.1.1.3 root 190: bool CheckAllBreakpoints();
191: bool CheckBreakpointInst(breakpoint_t&);
1.1.1.2 root 192: void ParseCmdbuf();
1.1 root 193: // コマンド名は大文字小文字を区別する関係でスネークスタイル。
194: void cmd_b();
1.1.1.3 root 195: void cmd_bi();
196: void cmd_bm();
197: void cmd_bv();
1.1 root 198: void cmd_b_list();
1.1.1.3 root 199: void cmd_b_set(BreakpointType);
1.1 root 200: void cmd_brhist();
201: void cmd_bx();
202: void cmd_c();
203: void cmd_d();
204: void cmd_dt();
205: void cmd_D();
1.1.1.4 root 206: void cmd_disp();
1.1.1.3 root 207: void cmd_exhist();
1.1 root 208: void cmd_h();
1.1.1.4 root 209: void cmd_hb();
210: void cmd_hr();
1.1 root 211: void cmd_L();
212: void cmd_m();
213: void cmd_mt();
214: void cmd_M();
215: void cmd_minus();
216: void cmd_n();
1.1.1.4 root 217: void cmd_nt();
1.1 root 218: void cmd_q();
1.1.1.4 root 219: void cmd_reset();
1.1 root 220: void cmd_s();
1.1.1.4 root 221: void cmd_st();
1.1 root 222: void cmd_so();
1.1.1.4 root 223: void cmd_sot();
1.1 root 224: void cmd_show();
225: void cmd_t();
226:
1.1.1.3 root 227: int AddBreakpoint(const breakpoint_t&);
228: void RecalcInstMask();
1.1.1.5 root 229: bool GetAddr(saddr_t *addr, bool);
230: void cmd_d_common(MemoryMode access_mode, MMULookupMode lookup_mode);
1.1.1.7 ! root 231: void cmd_hist_common(BranchHistory& hist);
1.1.1.5 root 232: void cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode);
1.1.1.4 root 233: void cmd_n_common(bool);
234: void cmd_s_common(bool);
235: void cmd_so_common(bool);
1.1.1.3 root 236: bool ParseVerbHex(const char *arg, uint32 *valp);
1.1 root 237: bool ParseAddr(const char *arg, uint32_t *addrp);
1.1.1.4 root 238: void SetNBreakpoint();
1.1 root 239:
1.1.1.5 root 240: static const HelpMessages HelpListMain;
241: static const HelpMessages HelpListBreakpoints;
1.1.1.4 root 242: static const HelpMessages HelpDetails;
1.1.1.5 root 243: void ShowHelpList(const HelpMessages& msgs);
1.1.1.4 root 244:
245: // 個別ヘルプメッセージを出力用に置換
246: std::string HelpConvert(const std::string& msg);
1.1.1.2 root 247:
248: // モニターを更新して表示
1.1.1.7 ! root 249: void ShowMonitor(Monitor& monitor);
1.1.1.2 root 250: // テキストスクリーンを表示
251: void ShowTextScreen(TextScreen& screen);
1.1 root 252:
1.1.1.4 root 253: DebuggerMD *md {}; // 機種依存部分
1.1 root 254:
1.1.1.4 root 255: Console *cons {}; // 入出力
256: const char *prompt {}; // プロンプト文字列
1.1 root 257: std::string cmdbuf {}; // 現在のコマンドライン
258: std::string last_cmdbuf {}; // 直前のコマンドライン
1.1.1.2 root 259: std::vector<std::string> args {};
1.1 root 260:
1.1.1.4 root 261: uint32 pc {};
1.1 root 262: std::vector<uint8> ir {}; // この後実行する命令のバイナリ列
1.1.1.2 root 263: std::array<breakpoint_t, MAX_BREAKPOINTS> bpoint {};
1.1.1.4 root 264: bool bc_enable {};
265: uint32 bc_addr {};
266: uint32 bi_inst {};
267: int bi_inst_bytes {};
268: int bi_need_bytes {};
1.1.1.3 root 269: int bv_vector = -1;
1.1.1.5 root 270: saddr_t d_last_addr {};
271: saddr_t m_last_addr {};
1.1.1.4 root 272: bool n_enable {};
273: uint32 n_breakaddr {};
274: uint32 n_count {};
275: bool s_enable {};
276: uint32 s_count {};
277: bool so_enable {};
278: bool t_enable {};
279: uint32 t_count {};
1.1 root 280:
281: // 一度VMを実行して再びプロンプトに来たら true
1.1.1.4 root 282: bool is_continued {};
283:
284: // プロンプトで表示するレジスタ群
285: std::vector<std::string> disp_regs {};
1.1 root 286:
1.1.1.6 root 287: // ブレークポイント到達メッセージ
288: // (コンソールが獲得できるまで保留しておくため)
289: std::string bpointmsg {};
290:
1.1.1.7 ! root 291: // ブレークポイントモニタ
! 292: DECLARE_MONITOR_CALLBACK(MonitorUpdateBpoint);
! 293: Monitor bpoint_monitor { this };
! 294:
! 295: // メモリダンプモニタ
! 296: DECLARE_MONITOR_CALLBACK(MonitorUpdateMemdump);
! 297:
1.1.1.2 root 298: static std::vector<cmddef_t> cmdtable;
1.1 root 299: };
300:
301: // デバッガの CPU 依存部分
302: class DebuggerMD
303: {
304: public:
1.1.1.5 root 305: DebuggerMD(Debugger *parent_, Debugger::Arch arch_) {
1.1.1.4 root 306: parent = parent_;
1.1.1.5 root 307: arch = arch_;
1.1 root 308: }
1.1.1.5 root 309: virtual ~DebuggerMD();
1.1 root 310:
311: // CPU のリクエストフラグに flag を立てる
312: virtual void ReqSet(uint32 flag) = 0;
313: // CPU のリクエストフラグから flag を落とす
314: virtual void ReqClr(uint32 flag) = 0;
315:
316: // 特権モードなら true を返す
317: virtual bool IsSuper() const = 0;
318: // MMU が有効なら true を返す
319: virtual bool MMUEnabled() const = 0;
320:
321: // アドレス変換をする。
322: // MMUEnabled() が true であることは呼び出し側が確認すること。
1.1.1.5 root 323: // lookup が true ならテーブルサーチまで行う。
1.1 root 324: // 変換できなければ (uint64)-1 を返す。
1.1.1.5 root 325: virtual uint64 TranslateAddr(saddr_t laddr, bool lookup) const = 0;
1.1 root 326:
327: // 現在の命令先頭アドレスを返す
328: virtual uint32 GetPC() const = 0;
329:
330: // ステップアウトを設定する
331: virtual void SetStepOut() = 0;
332: // ステップアウトなら true を返す
333: virtual bool IsStepOut() const = 0;
334:
1.1.1.4 root 335: // この命令がステップイン出来るなら true を返す (cmd_n 用)
1.1.1.5 root 336: virtual bool IsOpStepIn(DebuggerMemoryStream& mem) = 0;
1.1.1.4 root 337:
1.1 root 338: // name で示されるのレジスタの値を返す。
339: // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは
340: // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて
341: // よい。また m680x0 の SRP/CRP は下位32ビットでよい。
342: // name が正しくない場合は (uint64)-1 を返す。
343: virtual uint64 GetRegAddr(const char *name) const = 0;
344:
345: // 現在のレジスタセットを内部にバックアップする
346: virtual void BackupRegs() = 0;
347:
1.1.1.2 root 348: // レジスタ表示系のコマンドを実行。処理すれば true を返す。
349: virtual bool ShowRegister(Console *cons,
350: const std::vector<std::string>& args) = 0;
1.1.1.5 root 351: // レジスタ表示系コマンドのヘルプ一覧を取得
352: virtual const HelpMessages& GetHelpListReg() const = 0;
1.1.1.2 root 353: // レジスタ表示系コマンドのヘルプメッセージを取得
1.1.1.5 root 354: virtual const HelpMessages& GetHelpReg() const = 0;
1.1.1.2 root 355:
1.1.1.3 root 356: // ブランチ履歴・例外履歴(オブジェクト)を取得
357: virtual BranchHistory& GetBrHist() const = 0;
358: virtual BranchHistory& GetExHist() const = 0;
1.1 root 359:
360: // 直近の命令でアクセスした laddr が一致したら true を返す
361: // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する
362: virtual bool CheckLEA(uint32 laddr) = 0;
363:
364: // 逆アセンブル。
1.1.1.5 root 365: // mem.laddr の位置の命令を一つ逆アセンブルする。
1.1 root 366: // 成功すれば true を返し、失敗すれば(?) false を返す。
367: // 成功した場合 mnemonic に逆アセンブルした文字列が、
368: // bin にこの命令のバイナリ列が格納されている。
369: // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。
370: // bin はメモリイメージのバイト順で格納すること。
1.1.1.5 root 371: virtual bool Disassemble(DebuggerMemoryStream& mem,
1.1 root 372: std::string& mnemonic, std::vector<uint8>& bin) = 0;
373:
374: // 逆アセンブルをフォーマット。
375: // オフライン版は逆アセンブルウィンドウなど、
376: // オンライン版(Live) はデバッガプロンプトで表示するやつ。
377: virtual std::string FormatDisasm(const std::string& mnemonic,
378: const std::vector<uint8>& bin) = 0;
379: virtual std::string FormatDisasmLive(const std::string& mnemonic,
380: const std::vector<uint8>& bin) = 0;
381:
1.1.1.4 root 382: // 例外のベクタ番号から名前を取得。
383: virtual const char *GetExceptionName(int vector) const = 0;
384:
1.1.1.5 root 385: // 機種
386: Debugger::Arch arch {};
387:
1.1.1.3 root 388: // ベクタ番号の最大値 (+1)
1.1.1.4 root 389: int vector_max {};
390: // 最短の1命令のバイト数
391: uint inst_bytes {};
392: // 命令が固定長ならそのバイト数、可変長なら 0
393: uint inst_bytes_fixed {};
1.1.1.3 root 394:
1.1 root 395: protected:
1.1.1.4 root 396: Debugger *parent {}; // 親クラス
1.1 root 397: };
398:
399: #define NORM "\x1b[0m"
400: #define BOLD "\x1b[1m"
401: #define BOLDIF(n) ((n) ? BOLD : "")
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.