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