File:  [Isaki's NoNo m68k/m88k emulator] / nono / debugger / debugger.h
Revision 1.1.1.14 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:58 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// デバッガ (外部用)
//

#pragma once

#include "debugger_defs.h"
#include "bus.h"
#include "monitor.h"
#include "textscreen.h"
#include "thread.h"
#include <array>
#include <condition_variable>
#include <mutex>

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;	// マスク
				int instbytes;	// 命令バイト数
			};
		};

		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()); }

	// 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 QuitPrompt();
	void LeavePrompt(bool trace);
	void PrintPrompt();

	void Exec(DebuggerMD *);
	CmdAct Command();
	bool CheckAllBreakpoints(DebuggerMD *);
	uint64 ReadBreakpointInst(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_pe();
	CmdAct cmd_pf();
	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&);
	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<DebuggerMD> md_mpu /*{}*/;	// メイン
	std::unique_ptr<DebuggerMD> 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<HostCOMDevice> hostcom /*{}*/;
	FILE *cons {};

	const char *prompt {};		// プロンプト文字列
	std::string cmdbuf {};		// 現在のコマンドライン
	std::string last_cmdbuf {};	// 直前のコマンドライン
	std::vector<std::string> cmdargs {};

	uint32 pc {};
	std::array<breakpoint_t, MAX_BREAKPOINTS> bpoint {};
	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<std::string> disp_regs {};

	// ブレークポイント到達メッセージ
	// (コンソールが獲得できるまで保留しておくため)
	std::string bpointmsg {};

	// ブレークポイントモニタ
	DECLARE_MONITOR_SCREEN(MonitorScreenBpoint);
	Monitor *bpoint_monitor {};

	// 逆アセンブルとメモリダンプモニタ
	std::array<std::unique_ptr<MemdumpMonitor>, MAX_MEMDUMP_MONITOR>
		memdump_monitor /*{}*/;
	std::array<std::unique_ptr<MemdumpMonitor>, MAX_XPMEMDUMP_MONITOR>
		xpmemdump_monitor /*{}*/;

	// ベクタテーブル
	std::unique_ptr<VectorTable> pVectorTable /*{}*/;

	Syncer *syncer {};

	static std::vector<cmddef_t> cmdtable;
};

inline Debugger *GetDebugger() {
	return Object::GetObject<Debugger>(OBJ_DEBUGGER);
}

unix.superglobalmegacorp.com

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