|
|
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.2 root 281: static std::vector<cmddef_t> cmdtable;
1.1 root 282: };
283:
284: // デバッガの CPU 依存部分
285: class DebuggerMD
286: {
287: public:
1.1.1.5 ! root 288: DebuggerMD(Debugger *parent_, Debugger::Arch arch_) {
1.1.1.4 root 289: parent = parent_;
1.1.1.5 ! root 290: arch = arch_;
1.1 root 291: }
1.1.1.5 ! root 292: virtual ~DebuggerMD();
1.1 root 293:
294: // CPU のリクエストフラグに flag を立てる
295: virtual void ReqSet(uint32 flag) = 0;
296: // CPU のリクエストフラグから flag を落とす
297: virtual void ReqClr(uint32 flag) = 0;
298:
299: // 特権モードなら true を返す
300: virtual bool IsSuper() const = 0;
301: // MMU が有効なら true を返す
302: virtual bool MMUEnabled() const = 0;
303:
304: // アドレス変換をする。
305: // MMUEnabled() が true であることは呼び出し側が確認すること。
1.1.1.5 ! root 306: // lookup が true ならテーブルサーチまで行う。
1.1 root 307: // 変換できなければ (uint64)-1 を返す。
1.1.1.5 ! root 308: virtual uint64 TranslateAddr(saddr_t laddr, bool lookup) const = 0;
1.1 root 309:
310: // 現在の命令先頭アドレスを返す
311: virtual uint32 GetPC() const = 0;
312:
313: // ステップアウトを設定する
314: virtual void SetStepOut() = 0;
315: // ステップアウトなら true を返す
316: virtual bool IsStepOut() const = 0;
317:
1.1.1.4 root 318: // この命令がステップイン出来るなら true を返す (cmd_n 用)
1.1.1.5 ! root 319: virtual bool IsOpStepIn(DebuggerMemoryStream& mem) = 0;
1.1.1.4 root 320:
1.1 root 321: // name で示されるのレジスタの値を返す。
322: // メモリダンプで指定するケースを想定しているので、明らかにアドレスでは
323: // ないレジスタは含まなくてよい (m680x0 の SR など)。ただし Dn は含めて
324: // よい。また m680x0 の SRP/CRP は下位32ビットでよい。
325: // name が正しくない場合は (uint64)-1 を返す。
326: virtual uint64 GetRegAddr(const char *name) const = 0;
327:
328: // 現在のレジスタセットを内部にバックアップする
329: virtual void BackupRegs() = 0;
330:
1.1.1.2 root 331: // レジスタ表示系のコマンドを実行。処理すれば true を返す。
332: virtual bool ShowRegister(Console *cons,
333: const std::vector<std::string>& args) = 0;
1.1.1.5 ! root 334: // レジスタ表示系コマンドのヘルプ一覧を取得
! 335: virtual const HelpMessages& GetHelpListReg() const = 0;
1.1.1.2 root 336: // レジスタ表示系コマンドのヘルプメッセージを取得
1.1.1.5 ! root 337: virtual const HelpMessages& GetHelpReg() const = 0;
1.1.1.2 root 338:
1.1.1.3 root 339: // ブランチ履歴・例外履歴(オブジェクト)を取得
340: virtual BranchHistory& GetBrHist() const = 0;
341: virtual BranchHistory& GetExHist() const = 0;
1.1 root 342:
343: // 直近の命令でアクセスした laddr が一致したら true を返す
344: // 1 命令で複数にアクセスする場合を考慮して、md 側で判断する
345: virtual bool CheckLEA(uint32 laddr) = 0;
346:
347: // 逆アセンブル。
1.1.1.5 ! root 348: // mem.laddr の位置の命令を一つ逆アセンブルする。
1.1 root 349: // 成功すれば true を返し、失敗すれば(?) false を返す。
350: // 成功した場合 mnemonic に逆アセンブルした文字列が、
351: // bin にこの命令のバイナリ列が格納されている。
352: // mnemonic は単純に命令部分のみ、16進ダンプや付随情報は含まない。
353: // bin はメモリイメージのバイト順で格納すること。
1.1.1.5 ! root 354: virtual bool Disassemble(DebuggerMemoryStream& mem,
1.1 root 355: std::string& mnemonic, std::vector<uint8>& bin) = 0;
356:
357: // 逆アセンブルをフォーマット。
358: // オフライン版は逆アセンブルウィンドウなど、
359: // オンライン版(Live) はデバッガプロンプトで表示するやつ。
360: virtual std::string FormatDisasm(const std::string& mnemonic,
361: const std::vector<uint8>& bin) = 0;
362: virtual std::string FormatDisasmLive(const std::string& mnemonic,
363: const std::vector<uint8>& bin) = 0;
364:
1.1.1.4 root 365: // 例外のベクタ番号から名前を取得。
366: virtual const char *GetExceptionName(int vector) const = 0;
367:
1.1.1.5 ! root 368: // 機種
! 369: Debugger::Arch arch {};
! 370:
1.1.1.3 root 371: // ベクタ番号の最大値 (+1)
1.1.1.4 root 372: int vector_max {};
373: // 最短の1命令のバイト数
374: uint inst_bytes {};
375: // 命令が固定長ならそのバイト数、可変長なら 0
376: uint inst_bytes_fixed {};
1.1.1.3 root 377:
1.1 root 378: protected:
1.1.1.4 root 379: Debugger *parent {}; // 親クラス
1.1 root 380: };
381:
382: #define NORM "\x1b[0m"
383: #define BOLD "\x1b[1m"
384: #define BOLDIF(n) ((n) ? BOLD : "")
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.