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

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

unix.superglobalmegacorp.com

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