|
|
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.1.8 ! root 200: void cmd_b_delete();
1.1 root 201: void cmd_brhist();
202: void cmd_bx();
203: void cmd_c();
204: void cmd_d();
205: void cmd_dt();
206: void cmd_D();
1.1.1.4 root 207: void cmd_disp();
1.1.1.3 root 208: void cmd_exhist();
1.1 root 209: void cmd_h();
1.1.1.4 root 210: void cmd_hb();
211: void cmd_hr();
1.1 root 212: void cmd_L();
213: void cmd_m();
214: void cmd_mt();
215: void cmd_M();
216: void cmd_minus();
217: void cmd_n();
1.1.1.4 root 218: void cmd_nt();
1.1 root 219: void cmd_q();
1.1.1.4 root 220: void cmd_reset();
1.1 root 221: void cmd_s();
1.1.1.4 root 222: void cmd_st();
1.1 root 223: void cmd_so();
1.1.1.4 root 224: void cmd_sot();
1.1 root 225: void cmd_show();
226: void cmd_t();
227:
1.1.1.3 root 228: int AddBreakpoint(const breakpoint_t&);
229: void RecalcInstMask();
1.1.1.5 root 230: bool GetAddr(saddr_t *addr, bool);
231: void cmd_d_common(MemoryMode access_mode, MMULookupMode lookup_mode);
1.1.1.7 root 232: void cmd_hist_common(BranchHistory& hist);
1.1.1.5 root 233: void cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode);
1.1.1.4 root 234: void cmd_n_common(bool);
235: void cmd_s_common(bool);
236: void cmd_so_common(bool);
1.1.1.3 root 237: bool ParseVerbHex(const char *arg, uint32 *valp);
1.1 root 238: bool ParseAddr(const char *arg, uint32_t *addrp);
1.1.1.4 root 239: void SetNBreakpoint();
1.1 root 240:
1.1.1.5 root 241: static const HelpMessages HelpListMain;
242: static const HelpMessages HelpListBreakpoints;
1.1.1.4 root 243: static const HelpMessages HelpDetails;
1.1.1.5 root 244: void ShowHelpList(const HelpMessages& msgs);
1.1.1.4 root 245:
246: // 個別ヘルプメッセージを出力用に置換
247: std::string HelpConvert(const std::string& msg);
1.1.1.2 root 248:
249: // モニターを更新して表示
1.1.1.7 root 250: void ShowMonitor(Monitor& monitor);
1.1.1.2 root 251: // テキストスクリーンを表示
252: void ShowTextScreen(TextScreen& screen);
1.1 root 253:
1.1.1.4 root 254: DebuggerMD *md {}; // 機種依存部分
1.1 root 255:
1.1.1.4 root 256: Console *cons {}; // 入出力
257: const char *prompt {}; // プロンプト文字列
1.1 root 258: std::string cmdbuf {}; // 現在のコマンドライン
259: std::string last_cmdbuf {}; // 直前のコマンドライン
1.1.1.2 root 260: std::vector<std::string> args {};
1.1 root 261:
1.1.1.4 root 262: uint32 pc {};
1.1 root 263: std::vector<uint8> ir {}; // この後実行する命令のバイナリ列
1.1.1.2 root 264: std::array<breakpoint_t, MAX_BREAKPOINTS> bpoint {};
1.1.1.4 root 265: bool bc_enable {};
266: uint32 bc_addr {};
267: uint32 bi_inst {};
268: int bi_inst_bytes {};
269: int bi_need_bytes {};
1.1.1.3 root 270: int bv_vector = -1;
1.1.1.5 root 271: saddr_t d_last_addr {};
272: saddr_t m_last_addr {};
1.1.1.4 root 273: bool n_enable {};
274: uint32 n_breakaddr {};
275: uint32 n_count {};
276: bool s_enable {};
277: uint32 s_count {};
278: bool so_enable {};
279: bool t_enable {};
280: uint32 t_count {};
1.1 root 281:
282: // 一度VMを実行して再びプロンプトに来たら true
1.1.1.4 root 283: bool is_continued {};
284:
285: // プロンプトで表示するレジスタ群
286: std::vector<std::string> disp_regs {};
1.1 root 287:
1.1.1.6 root 288: // ブレークポイント到達メッセージ
289: // (コンソールが獲得できるまで保留しておくため)
290: std::string bpointmsg {};
291:
1.1.1.7 root 292: // ブレークポイントモニタ
293: DECLARE_MONITOR_CALLBACK(MonitorUpdateBpoint);
294: Monitor bpoint_monitor { this };
295:
296: // メモリダンプモニタ
297: DECLARE_MONITOR_CALLBACK(MonitorUpdateMemdump);
298:
1.1.1.2 root 299: static std::vector<cmddef_t> cmdtable;
1.1 root 300: };
301:
302: // デバッガの CPU 依存部分
303: class DebuggerMD
304: {
305: public:
1.1.1.5 root 306: DebuggerMD(Debugger *parent_, Debugger::Arch arch_) {
1.1.1.4 root 307: parent = parent_;
1.1.1.5 root 308: arch = arch_;
1.1 root 309: }
1.1.1.5 root 310: virtual ~DebuggerMD();
1.1 root 311:
312: // CPU のリクエストフラグに flag を立てる
313: virtual void ReqSet(uint32 flag) = 0;
314: // CPU のリクエストフラグから flag を落とす
315: virtual void ReqClr(uint32 flag) = 0;
316:
317: // 特権モードなら true を返す
318: virtual bool IsSuper() const = 0;
319: // MMU が有効なら true を返す
320: virtual bool MMUEnabled() const = 0;
321:
322: // アドレス変換をする。
323: // MMUEnabled() が true であることは呼び出し側が確認すること。
1.1.1.5 root 324: // lookup が true ならテーブルサーチまで行う。
1.1 root 325: // 変換できなければ (uint64)-1 を返す。
1.1.1.5 root 326: virtual uint64 TranslateAddr(saddr_t laddr, bool lookup) const = 0;
1.1 root 327:
328: // 現在の命令先頭アドレスを返す
329: virtual uint32 GetPC() const = 0;
330:
331: // ステップアウトを設定する
332: virtual void SetStepOut() = 0;
333: // ステップアウトなら true を返す
334: virtual bool IsStepOut() const = 0;
335:
1.1.1.4 root 336: // この命令がステップイン出来るなら true を返す (cmd_n 用)
1.1.1.5 root 337: virtual bool IsOpStepIn(DebuggerMemoryStream& mem) = 0;
1.1.1.4 root 338:
1.1 root 339: // name で示されるのレジスタの値を返す。
340: // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは
341: // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて
342: // よい。また m680x0 の SRP/CRP は下位32ビットでよい。
343: // name が正しくない場合は (uint64)-1 を返す。
344: virtual uint64 GetRegAddr(const char *name) const = 0;
345:
346: // 現在のレジスタセットを内部にバックアップする
347: virtual void BackupRegs() = 0;
348:
1.1.1.2 root 349: // レジスタ表示系のコマンドを実行。処理すれば true を返す。
350: virtual bool ShowRegister(Console *cons,
351: const std::vector<std::string>& args) = 0;
1.1.1.5 root 352: // レジスタ表示系コマンドのヘルプ一覧を取得
353: virtual const HelpMessages& GetHelpListReg() const = 0;
1.1.1.2 root 354: // レジスタ表示系コマンドのヘルプメッセージを取得
1.1.1.5 root 355: virtual const HelpMessages& GetHelpReg() const = 0;
1.1.1.2 root 356:
1.1.1.3 root 357: // ブランチ履歴・例外履歴(オブジェクト)を取得
358: virtual BranchHistory& GetBrHist() const = 0;
359: virtual BranchHistory& GetExHist() const = 0;
1.1 root 360:
361: // 直近の命令でアクセスした laddr が一致したら true を返す
362: // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する
363: virtual bool CheckLEA(uint32 laddr) = 0;
364:
365: // 逆アセンブル。
1.1.1.5 root 366: // mem.laddr の位置の命令を一つ逆アセンブルする。
1.1 root 367: // 成功すれば true を返し、失敗すれば(?) false を返す。
368: // 成功した場合 mnemonic に逆アセンブルした文字列が、
369: // bin にこの命令のバイナリ列が格納されている。
370: // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。
371: // bin はメモリイメージのバイト順で格納すること。
1.1.1.5 root 372: virtual bool Disassemble(DebuggerMemoryStream& mem,
1.1 root 373: std::string& mnemonic, std::vector<uint8>& bin) = 0;
374:
375: // 逆アセンブルをフォーマット。
376: // オフライン版は逆アセンブルウィンドウなど、
377: // オンライン版(Live) はデバッガプロンプトで表示するやつ。
378: virtual std::string FormatDisasm(const std::string& mnemonic,
379: const std::vector<uint8>& bin) = 0;
380: virtual std::string FormatDisasmLive(const std::string& mnemonic,
381: const std::vector<uint8>& bin) = 0;
382:
1.1.1.4 root 383: // 例外のベクタ番号から名前を取得。
384: virtual const char *GetExceptionName(int vector) const = 0;
385:
1.1.1.5 root 386: // 機種
387: Debugger::Arch arch {};
388:
1.1.1.3 root 389: // ベクタ番号の最大値 (+1)
1.1.1.4 root 390: int vector_max {};
391: // 最短の1命令のバイト数
392: uint inst_bytes {};
393: // 命令が固定長ならそのバイト数、可変長なら 0
394: uint inst_bytes_fixed {};
1.1.1.3 root 395:
1.1 root 396: protected:
1.1.1.4 root 397: Debugger *parent {}; // 親クラス
1.1 root 398: };
399:
400: #define NORM "\x1b[0m"
401: #define BOLD "\x1b[1m"
402: #define BOLDIF(n) ((n) ? BOLD : "")
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.