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