|
|
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.1.10! root 228: // コマンド
! 229: enum CmdAct {
1.1.1.2 root 230: Stay, // デバッガプロンプトに留まる
231: Leave, // デバッガプロンプトを抜けて VM を実行する
232: Quit, // デバッガとの接続を終了する
233: };
1.1.1.9 root 234: struct cmddef_t {
1.1 root 235: const char *name;
1.1.1.10! root 236: CmdAct (Debugger::*func)();
1.1.1.9 root 237: };
1.1 root 238:
1.1.1.3 root 239: // ブレークポイント種別
240: enum BreakpointType {
241: Unused = 0,
242: Address, // このアドレスに来る直前
243: Memory, // このアドレスをアクセスした直後
244: Exception, // この例外を検出した直後
245: Instruction, // この命令を実行する直前
246: };
247:
1.1 root 248: // ブレークポイント
1.1.1.9 root 249: struct breakpoint_t {
1.1.1.3 root 250: BreakpointType type {}; // 種別
251: // 種別ごとのパラメータ
252: union {
253: uint32 addr {}; // ターゲットアドレス (Address/Memory)
254: struct {
255: int vec1; // ベクタ番号 (開始)
256: int vec2; // ベクタ番号 (終了)
257: };
258: struct {
259: uint32 inst; // 命令ワード
260: uint32 mask; // マスク
261: };
262: };
263:
264: uint32 matched {}; // 成立回数 (積算)
265:
266: // skip はユーザ指定値。ただし
267: // -1 なら常にスキップ、つまりブレークせずカウントのみ行う、
268: // 0 ならスキップなし、つまり成立ごとにブレーク(これがデフォルト)、
269: // n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。
270: int32 skip {}; // スキップ回数 (ユーザ指定値)
271: int32 skipremain {}; // 残りスキップ回数 (0 で成立)
1.1.1.9 root 272: };
1.1 root 273: static const int MAX_BREAKPOINTS = 8;
274:
275: public:
276: Debugger();
1.1.1.9 root 277: ~Debugger() override;
1.1 root 278:
1.1.1.9 root 279: void SetLogLevel(int) override;
280: bool Create() override;
281: bool Init() override;
282: void ThreadRun() override;
283: void Terminate() override;
284:
285: void Exec();
1.1.1.3 root 286: void NotifyException(int vector);
287:
1.1.1.9 root 288: // MPU トレースが必要なら true を返す
289: bool IsTrace() const;
290:
291: // FILE コールバック
292: int ReadFunc(char *, int);
293: int WriteFunc(const char *, int);
294:
1.1.1.7 root 295: // メモリダンプモニタ
296: // GUI 用 (show コマンドでも見れるけど)
1.1.1.9 root 297: std::array<Monitor, MAX_MEMDUMP_MONITOR> memdump_monitor {};
1.1.1.7 root 298:
299: // m/M コマンド用のメモリダンプモニタ
300: Monitor m_monitor { this };
1.1 root 301:
302: private:
1.1.1.9 root 303: void Close();
304: void RxCallback();
305: void AcceptCallback();
306: void Input(int);
307: void EnterPrompt();
308: void LeavePrompt();
309: void PrintPrompt();
310:
1.1.1.10! root 311: CmdAct Command();
1.1.1.3 root 312: bool CheckAllBreakpoints();
313: bool CheckBreakpointInst(breakpoint_t&);
1.1.1.2 root 314: void ParseCmdbuf();
1.1 root 315: // コマンド名は大文字小文字を区別する関係でスネークスタイル。
1.1.1.10! root 316: CmdAct cmd_b();
! 317: CmdAct cmd_bi();
! 318: CmdAct cmd_bm();
! 319: CmdAct cmd_bv();
! 320: CmdAct cmd_b_list();
! 321: CmdAct cmd_b_set(BreakpointType);
! 322: CmdAct cmd_b_delete();
! 323: CmdAct cmd_brhist();
! 324: CmdAct cmd_bx();
! 325: CmdAct cmd_c();
! 326: CmdAct cmd_ct();
! 327: CmdAct cmd_d();
! 328: CmdAct cmd_dt();
! 329: CmdAct cmd_D();
! 330: CmdAct cmd_disp();
! 331: CmdAct cmd_exhist();
! 332: CmdAct cmd_h();
! 333: CmdAct cmd_hb();
! 334: CmdAct cmd_hr();
! 335: CmdAct cmd_L();
! 336: CmdAct cmd_m();
! 337: CmdAct cmd_mt();
! 338: CmdAct cmd_M();
! 339: CmdAct cmd_minus();
! 340: CmdAct cmd_n();
! 341: CmdAct cmd_nt();
! 342: CmdAct cmd_q();
! 343: CmdAct cmd_reset();
! 344: CmdAct cmd_s();
! 345: CmdAct cmd_st();
! 346: CmdAct cmd_so();
! 347: CmdAct cmd_sot();
! 348: CmdAct cmd_show();
! 349: CmdAct cmd_t();
1.1 root 350:
1.1.1.9 root 351: bool Check();
1.1.1.3 root 352: int AddBreakpoint(const breakpoint_t&);
353: void RecalcInstMask();
1.1.1.5 root 354: bool GetAddr(saddr_t *addr, bool);
1.1.1.10! root 355: CmdAct cmd_d_common(MemoryMode access_mode, MMULookupMode lookup_mode);
! 356: CmdAct cmd_hist_common(BranchHistory& hist);
! 357: CmdAct cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode);
! 358: CmdAct cmd_n_common(bool);
! 359: CmdAct cmd_s_common(bool);
! 360: CmdAct cmd_so_common(bool);
1.1.1.3 root 361: bool ParseVerbHex(const char *arg, uint32 *valp);
1.1 root 362: bool ParseAddr(const char *arg, uint32_t *addrp);
1.1.1.10! root 363: bool ParseTime(const char *arg, uint64 *timep);
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.10! root 369: CmdAct 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.10! root 409: bool ct_enable {};
! 410: uint64 ct_end_time {};
! 411: uint64 ct_timespan {};
1.1.1.5 root 412: saddr_t d_last_addr {};
413: saddr_t m_last_addr {};
1.1.1.4 root 414: bool n_enable {};
415: uint32 n_breakaddr {};
416: uint32 n_count {};
417: bool s_enable {};
418: uint32 s_count {};
419: bool so_enable {};
420: bool t_enable {};
421: uint32 t_count {};
1.1 root 422:
423: // 一度VMを実行して再びプロンプトに来たら true
1.1.1.4 root 424: bool is_continued {};
425:
1.1.1.9 root 426: // MPU を一時停止するとき true (ワンショット)
427: bool is_pause {};
428:
1.1.1.4 root 429: // プロンプトで表示するレジスタ群
430: std::vector<std::string> disp_regs {};
1.1 root 431:
1.1.1.6 root 432: // ブレークポイント到達メッセージ
433: // (コンソールが獲得できるまで保留しておくため)
434: std::string bpointmsg {};
435:
1.1.1.7 root 436: // ブレークポイントモニタ
437: DECLARE_MONITOR_CALLBACK(MonitorUpdateBpoint);
438: Monitor bpoint_monitor { this };
439:
440: // メモリダンプモニタ
441: DECLARE_MONITOR_CALLBACK(MonitorUpdateMemdump);
442:
1.1.1.9 root 443: // ベクタテーブル
444: std::unique_ptr<VectorTable> pVectorTable /*{}*/;
445:
1.1.1.2 root 446: static std::vector<cmddef_t> cmdtable;
1.1 root 447: };
448:
1.1.1.9 root 449: extern Debugger *gDebugger;
1.1 root 450:
451: #define NORM "\x1b[0m"
452: #define BOLD "\x1b[1m"
453: #define BOLDIF(n) ((n) ? BOLD : "")
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.