Annotation of nono/debugger/debugger_private.h, revision 1.1.1.9

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 : "")

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.