--- nono/debugger/debugger.h 2026/04/29 17:04:28 1.1 +++ nono/debugger/debugger.h 2026/04/29 17:05:49 1.1.1.13 @@ -1,12 +1,286 @@ // // nono -// Copyright (C) 2019 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt +// + +// +// デバッガ (外部用) // #pragma once -extern void debugger_init(); -extern bool debugger_check(); +#include "debugger_defs.h" +#include "bus.h" +#include "monitor.h" +#include "textscreen.h" +#include "thread.h" +#include +#include +#include + +class BranchHistory; +class HostCOMDevice; +class MemdumpMonitor; +class Syncer; +class VectorTable; + +class Debugger : public ThreadDevice +{ + using inherited = ThreadDevice; + friend class DebuggerMD_m680x0; + friend class DebuggerMD_m88xx0; + + private: + // リクエストフラグ + static const uint32 REQUEST_EXIT = 0x0001; // 終了 + static const uint32 REQUEST_RXCHAR = 0x0002; // 1文字受信 + static const uint32 REQUEST_ACCEPT = 0x0004; // 着信通知 + static const uint32 REQUEST_PROMPT = 0x0008; // プロンプト要求 + + // コマンド + enum CmdAct { + Stay, // デバッガプロンプトに留まる + Leave, // デバッガプロンプトを抜けて VM を実行する + Quit, // デバッガとの接続を終了する + }; + struct cmddef_t { + const char *name; + CmdAct (Debugger::*func)(); + }; + + // ブレークポイント種別 + enum BreakpointType { + Unused = 0, + Address, // このアドレスに来る直前 + Memory, // このアドレスをアクセスした直後 + Exception, // この例外を検出した直後 + Instruction, // この命令を実行する直前 + }; + + // ブレークポイント + struct breakpoint_t { + DebuggerMD *md {}; // CPU + BreakpointType type {}; // 種別 + // 種別ごとのパラメータ + union { + uint32 addr {}; // ターゲットアドレス (Address/Memory) + struct { + int vec1; // ベクタ番号 (開始) + int vec2; // ベクタ番号 (終了) + }; + struct { + uint32 inst; // 命令ワード + uint32 mask; // マスク + }; + }; + + uint32 matched {}; // 成立回数 (積算) + + // skip はユーザ指定値。ただし + // -1 なら常にスキップ、つまりブレークせずカウントのみ行う、 + // 0 ならスキップなし、つまり成立ごとにブレーク(これがデフォルト)、 + // n(>0) なら n 回の成立をスキップし、(n+1) 回目でブレークの意。 + int32 skip {}; // スキップ回数 (ユーザ指定値) + int32 skipremain {}; // 残りスキップ回数 (0 で成立) + }; + static const int MAX_BREAKPOINTS = 8; + + // ステップ実行種別 + enum StepType { + None, // なし + Count, // 命令数指定 + CountSkipSub, // 命令数指定 (サブルーチンをスキップ) + StepOut, // ステップアウト + Addr, // アドレス指定 + Time, // 時間指定 + }; + + public: + Debugger(); + ~Debugger() override; + + bool Create() override; + void SetLogLevel(int) override; + bool Init() override; + void ThreadRun() override; + void Terminate() override; + + void ExecMain() { Exec(md_mpu.get()); } + void ExecXP() { Exec(md_xp.get()); } + void NotifyExceptionMain(int vector); + void NotifyExceptionXP(int vector); + + // MPU トレースが必要なら true を返す + bool IsTrace() const; + + // FILE コールバック + int ReadFunc(char *, int); + int WriteFunc(const char *, int); + + private: + void Close(); + void RxCallback(uint32); + void AcceptCallback(uint32); + void Input(int); + void EnterPrompt(); + void LeavePrompt(bool trace); + void PrintPrompt(); + + void Exec(DebuggerMD *); + CmdAct Command(); + bool CheckAllBreakpoints(DebuggerMD *); + bool CheckBreakpointInst(breakpoint_t&); + void ParseCmdbuf(); + // コマンド名は大文字小文字を区別する関係でスネークスタイル。 + CmdAct cmd_b(); + CmdAct cmd_bi(); + CmdAct cmd_bm(); + CmdAct cmd_bv(); + CmdAct cmd_b_list(); + CmdAct cmd_b_set(BreakpointType); + CmdAct cmd_b_delete(); + CmdAct cmd_brhist(); + CmdAct cmd_bx(); + CmdAct cmd_c(); + CmdAct cmd_ct(); + CmdAct cmd_d(); + CmdAct cmd_D(); + CmdAct cmd_disp(); + CmdAct cmd_exhist(); + CmdAct cmd_h(); + CmdAct cmd_hb(); + CmdAct cmd_hr(); + CmdAct cmd_L(); + CmdAct cmd_m(); + CmdAct cmd_mpu(); + CmdAct cmd_M(); + CmdAct cmd_minus(); + CmdAct cmd_n(); + CmdAct cmd_nt(); + CmdAct cmd_q(); + CmdAct cmd_reset(); + CmdAct cmd_s(); + CmdAct cmd_st(); + CmdAct cmd_so(); + CmdAct cmd_sot(); + CmdAct cmd_show(); + CmdAct cmd_t(); + CmdAct cmd_xp(); + CmdAct cmd_z(); + + bool Check(DebuggerMD *); + bool ParseOptBreakAddr(const std::string&); + bool ParseOptBreakInst(const std::string&); + bool ParseOptBreakVector(const std::string&); + bool IsCPUStr(const std::string&) const; + DebuggerMD *ParseCPU(const std::string&) const; + int AddBreakInst(const std::string& cpustr, const std::string& inststr, + const std::string& skipstr, std::string *errstr); + int AddBreakVector(const std::string& cpustr, const std::string& vecstr, + const std::string& skipstr, std::string *errstr); + int AddBreakpoint(const breakpoint_t&); + void RecalcInstMask(); + bool GetAddr(busaddr *addr, bool); + CmdAct cmd_d_common(busaddr access_mode); + CmdAct cmd_hist_common(BranchHistory& hist); + CmdAct cmd_m_common(busaddr access_mode); + CmdAct cmd_n_common(bool); + CmdAct cmd_s_common(bool); + CmdAct cmd_so_common(bool); + bool ParseVector(DebuggerMD *, const char *arg, uint32 *valp); + bool ParseVerbHex(const char *arg, uint32 *valp); + bool ParseAddr(const char *arg, uint32_t *addrp); + bool ParseTime(const char *arg, uint64 *timep); + void SetNBreakpoint(); + void ChangeMD(DebuggerMD *); + void ResetStickyAddr(); + + static const HelpMessages HelpListMain; + static const HelpMessages HelpListBreakpoints; + static const HelpMessages HelpDetails; + CmdAct ShowHelpList(const HelpMessages& msgs); + + // 個別ヘルプメッセージを出力用に置換 + std::string HelpConvert(const std::string& msg); + + // モニタを更新して表示 + void ShowMonitor(Monitor *monitor); + // テキストスクリーンを表示 + void ShowTextScreen(TextScreen& screen); + + // 機種依存部分 + std::unique_ptr md_mpu /*{}*/; // メイン + std::unique_ptr md_xp /*{}*/; // XP + // 現行 + DebuggerMD *curmd {}; + + std::mutex mtx {}; + // このスレッドへのリクエスト + std::condition_variable cv_request {}; + uint32 request {}; + // コマンドモード(プロンプト)なら true + std::condition_variable cv_prompt {}; + bool prompt_released {}; + + bool is_prompt {}; + + // コンソール + std::unique_ptr hostcom /*{}*/; + FILE *cons {}; + + const char *prompt {}; // プロンプト文字列 + std::string cmdbuf {}; // 現在のコマンドライン + std::string last_cmdbuf {}; // 直前のコマンドライン + std::vector cmdargs {}; + + uint32 pc {}; + std::array bpoint {}; + uint32 bi_inst {}; + int bi_inst_bytes {}; + int bi_need_bytes {}; + uint64 ct_timespan {}; + busaddr d_last_addr {}; + busaddr m_last_addr {}; + StepType step_type {}; // ステップ実行種別 + DebuggerMD *step_md {}; // ステップ実行中の CPU + uint32 step_count {}; + uint64 step_addr {}; + uint64 step_time {}; + DebuggerMD *t_enable {}; + uint32 t_count {}; + + // 一度VMを実行して再びプロンプトに来たら true + bool is_continued {}; + + // MPU を一時停止するとき true (ワンショット) + bool is_pause {}; + + // プロンプトで表示するレジスタ群 + std::vector disp_regs {}; + + // ブレークポイント到達メッセージ + // (コンソールが獲得できるまで保留しておくため) + std::string bpointmsg {}; + + // ブレークポイントモニタ + DECLARE_MONITOR_CALLBACK(MonitorUpdateBpoint); + Monitor *bpoint_monitor {}; + + // 逆アセンブルとメモリダンプモニタ + std::array, MAX_MEMDUMP_MONITOR> + memdump_monitor /*{}*/; + std::array, MAX_XPMEMDUMP_MONITOR> + xpmemdump_monitor /*{}*/; + + // ベクタテーブル + std::unique_ptr pVectorTable /*{}*/; + + Syncer *syncer {}; + + static std::vector cmdtable; +}; -extern bool debug_on_start; -extern uint32 debug_breakaddr; +static inline Debugger *GetDebugger() { + return Object::GetObject(OBJ_DEBUGGER); +}