--- nono/debugger/debugger.cpp 2026/04/29 17:05:20 1.1.1.14 +++ nono/debugger/debugger.cpp 2026/04/29 17:05:54 1.1.1.21 @@ -36,6 +36,8 @@ #include "debugger_hd64180.h" #include "debugger_m680x0.h" #include "debugger_m88xx0.h" +#include "ascii_ctype.h" +#include "event.h" #include "hostcom.h" #include "mainapp.h" #include "memdump.h" @@ -63,13 +65,13 @@ Debugger::Debugger() pVectorTable.reset(new VectorTable(gMainApp.GetVMType())); // ブレークポイントモニタ - bpoint_monitor.func = ToMonitorCallback(&Debugger::MonitorUpdateBpoint); - bpoint_monitor.SetSize(60, 9); - bpoint_monitor.Regist(ID_MONITOR_BREAKPOINT); + bpoint_monitor = gMonitorManager->Regist(ID_MONITOR_BREAKPOINT, this); + bpoint_monitor->func = ToMonitorCallback(&Debugger::MonitorUpdateBpoint); + bpoint_monitor->SetSize(59, 9); // メモリダンプモニタ for (int i = 0, end = memdump_monitor.size(); i < end; i++) { - int objid = OBJ_MPU_MEMDUMP(i); + uint objid = OBJ_MPU_MEMDUMP(i); int monid = ID_MONITOR_MEMDUMP(i); memdump_monitor[i].reset(new MemdumpMonitor(objid, monid)); } @@ -77,7 +79,7 @@ Debugger::Debugger() if (gMainApp.Has(VMCap::LUNA)) { // XP 空間のメモリダンプモニタ for (int i = 0, end = xpmemdump_monitor.size(); i < end; i++) { - int objid = OBJ_XP_MEMDUMP(i); + uint objid = OBJ_XP_MEMDUMP(i); int monid = ID_MONITOR_XPMEMDUMP(i); xpmemdump_monitor[i].reset(new MemdumpMonitor(objid, monid)); } @@ -92,7 +94,7 @@ Debugger::~Debugger() Close(); if ((bool)hostcom) { - hostcom->SetRxCallback(NULL); + hostcom->ResetRxCallback(); hostcom->SetAcceptCallback(NULL); } @@ -103,12 +105,15 @@ bool Debugger::Create() { // ホストドライバを作成 - hostcom.reset(new HostCOMDevice(this, "Debugger")); + try { + hostcom.reset(new HostCOMDevice(this, -1, "Debugger")); + } catch (...) { } if ((bool)hostcom == false) { + warnx("Failed to initialize HostCOMDevice at %s", __method__); return false; } - hostcom->SetRxCallback(ToDeviceCallback(&Debugger::RxCallback)); + hostcom->SetRxCallback(ToDeviceCallback(&Debugger::RxCallback), 0); hostcom->SetAcceptCallback(ToDeviceCallback(&Debugger::AcceptCallback)); return true; @@ -136,14 +141,28 @@ Debugger::Init() syncer = GetSyncer(); - if (gMainApp.Has(VMCap::M88K)) { - md_mpu.reset(new DebuggerMD_m88xx0(this)); - } else { - md_mpu.reset(new DebuggerMD_m680x0(this)); + try { + if (gMainApp.Has(VMCap::M88K)) { + md_mpu.reset(new DebuggerMD_m88xx0(this)); + } else { + md_mpu.reset(new DebuggerMD_m680x0(this)); + } + } catch (...) { } + if ((bool)md_mpu == false) { + warnx("Failed to initialize md_mpu at %s", __method__); + return false; } + if (gMainApp.Has(VMCap::LUNA)) { - md_xp.reset(new DebuggerMD_hd64180(this)); + try { + md_xp.reset(new DebuggerMD_hd64180(this)); + } catch (...) { } + if ((bool)md_xp == false) { + warnx("Failed to initialize md_xp at %s", __method__); + return false; + } } + // とりあえずメインプロセッサに固定 curmd = md_mpu.get(); @@ -169,50 +188,37 @@ Debugger::Init() } // -b [,][,] ならブレークポイント設定 - for (auto& str : gMainApp.debug_breakaddr) { - breakpoint_t bp; - std::string cpustr; - std::string addrstr; - std::string skipstr; - - // "," で分離 - auto arr = string_split(str, ','); - if (arr.size() < 2) { - // 1個ならアドレス (0 ってことはないはずだが) - addrstr = arr[0]; - } else if (arr.size() == 2) { - // 2個なら cpu か skip のどちらかが省略。 - // 1つ目が16進数っぽいかどうかで判定する。 - char *end; - strtoul(arr[0].c_str(), &end, 16); - if (end == &arr[0][0]) { - cpustr = arr[0]; - addrstr = arr[1]; - } else { - addrstr = arr[0]; - skipstr = arr[1]; - } - } else if (arr.size() == 3) { - cpustr = arr[0]; - addrstr = arr[1]; - skipstr = arr[2]; - } else { - warnx("\"%s\": Invalid breakpoint", str.c_str()); + for (const auto& str : gMainApp.debug_breakaddr) { + if (ParseOptBreakAddr(str) == false) { + return false; + } + } + + // --bi [,][:][,] で命令ブレークポイント設定。 + for (auto& str : gMainApp.debug_breakinst) { + if (ParseOptBreakInst(str) == false) { return false; } + } - // を取り出す - if (!ParseAddr(addrstr.c_str(), &bp.addr)) { - warnx("\"%s\": Invalid breakpoint address", str.c_str()); + // --bv [,][-][,] でベクタブレークポイント設定。 + for (auto& str : gMainApp.debug_breakvec) { + if (ParseOptBreakVector(str) == false) { return false; } - // を取り出す - if (skipstr.empty() == false) { - bp.skip = atoi(skipstr.c_str()); - } - // 登録 - bp.type = BreakpointType::Address; - AddBreakpoint(bp, cpustr); + } + + // --bi-exg なら命令ブレークポイントを設定 + // (CPU のチェックはしていない) + if (gMainApp.debug_breakinst_exg) { + breakpoint_t bp; + bp.type = BreakpointType::Instruction; + bp.inst = 0xcf4f0000; + bp.mask = 0xffff0000; + bp.md = curmd; + AddBreakpoint(bp); + // 今登録されている命令ブレークの必要命令長を再計算 + RecalcInstMask(); } // 入出力を FILE で扱う @@ -229,6 +235,8 @@ Debugger::Init() void Debugger::ThreadRun() { + SetThreadAffinityHint(AffinityClass::Light); + // disp_regs の初期値設定。 // 再接続でも継続してていいような気がするのでループ外で初期化。 disp_regs.clear(); @@ -309,7 +317,7 @@ Debugger::Close() void Debugger::Terminate() { - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQUEST_EXIT; cv_request.notify_one(); } @@ -318,14 +326,16 @@ Debugger::Terminate() static int readfunc(void *cookie, char *buf, int bufsize) { - return ((Debugger *)cookie)->ReadFunc(buf, bufsize); + auto debugger = reinterpret_cast(cookie); + return debugger->ReadFunc(buf, bufsize); } // funopen の write コールバック static int writefunc(void *cookie, const char *buf, int len) { - return ((Debugger *)cookie)->WriteFunc(buf, len); + auto debugger = reinterpret_cast(cookie); + return debugger->WriteFunc(buf, len); } // funopen の read コールバックの本体 @@ -382,20 +392,20 @@ Debugger::WriteFunc(const char *buf, int // ホストからの1文字受信通知 (HostCOM スレッドから呼ばれる) void -Debugger::RxCallback() +Debugger::RxCallback(uint32 arg) { // デバッガスレッドに通知 - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQUEST_RXCHAR; cv_request.notify_one(); } // ホストからの着信通知 (HostCOM スレッドから呼ばれる) void -Debugger::AcceptCallback() +Debugger::AcceptCallback(uint32 dummy) { // デバッガスレッドに通知 - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); request |= REQUEST_ACCEPT; cv_request.notify_one(); } @@ -457,7 +467,7 @@ Debugger::Input(int c) case CmdAct::Quit: // アプリケーション自体を終了 LeavePrompt(false); - UIMessage::Post(UIMessage::APPEXIT); + gMainApp.GetUIMessage()->Post(UIMessage::APPEXIT); } } else if (c < ' ' || c == 0x07f) { // 他のコントロールコードはとりあえず無視 @@ -505,7 +515,7 @@ Debugger::LeavePrompt(bool trace) // 最後に VM スレッドで待機している Exec() を起こす { - std::unique_lock lock(mtx); + std::lock_guard lock(mtx); prompt_released = true; cv_prompt.notify_one(); } @@ -537,7 +547,7 @@ Debugger::Command() last_cmdbuf = cmdbuf; } - // 行を args に分解 + // 行を cmdargs に分解 ParseCmdbuf(); cmdbuf.clear(); @@ -545,7 +555,7 @@ Debugger::Command() // コマンドをテーブルから探す auto it = std::find_if(cmdtable.begin(), cmdtable.end(), - [=](auto x) { return strcmp(args[0].c_str(), x.name) == 0; }); + [=](auto x) { return strcmp(cmdargs[0].c_str(), x.name) == 0; }); if (it != cmdtable.end()) { auto cmd = *it; @@ -554,16 +564,16 @@ Debugger::Command() } // (コマンドテーブルになくて) "r" から始まっていればレジスタ表示系 - if (args[0][0] == 'r') { + if (cmdargs[0][0] == 'r') { // ShowRegister() は処理したら true を返す。 // "r" 系コマンドはすべて Stay。 - if (curmd->ShowRegister(cons, args)) { + if (curmd->ShowRegister(cons, cmdargs)) { return CmdAct::Stay; } } // 知らないコマンドも Stay 相当。 - fprintf(cons, "%s: unknown command\n", args[0].c_str()); + fprintf(cons, "%s: Unknown command.\n", cmdargs[0].c_str()); // この行は次回空エンターで再発行しないでいい。 last_cmdbuf.clear(); return CmdAct::Stay; @@ -857,7 +867,7 @@ Debugger::CheckAllBreakpoints(DebuggerMD // この時点ではまだコンソールを取得していない可能性があるので // (-D なしで起動した場合とか)、表示せず用意するだけ。 // コンソールが取得できたところで表示する。 - bpointmsg += string_format("breakpoint #%d (%s) reached\n", + bpointmsg += string_format("Breakpoint #%d (%s) reached.\n", i, desc.c_str()); } @@ -873,8 +883,10 @@ Debugger::CheckBreakpointInst(breakpoint // bi_inst_bytes が読み込んだバイト数(bi_inst の左からの有効バイト数)。 // bi_need_bytes が現在のブレークポイントで読み込む必要のあるバイト数。 - saddr_t laddr(bp.md->GetPC(), bp.md->IsSuper()); - DebuggerMemoryStream mem(bp.md, laddr, MMULookupMode::True); + busaddr laddr = busaddr(bp.md->GetPC()) + | BusAddr::Fetch + | busaddr::SU(bp.md->IsSuper()); + DebuggerMemoryStream mem(bp.md, laddr); // 必要なバイト数に達するまで読み足す bi_inst = 0; @@ -928,7 +940,6 @@ Debugger::NotifyExceptionXP(int vector) { "c", &Debugger::cmd_c, }, { "ct", &Debugger::cmd_ct, }, { "d", &Debugger::cmd_d, }, - { "dt", &Debugger::cmd_dt, }, { "D", &Debugger::cmd_D, }, { "disp", &Debugger::cmd_disp, }, { "exhist", &Debugger::cmd_exhist, }, @@ -938,7 +949,6 @@ Debugger::NotifyExceptionXP(int vector) { "help", &Debugger::cmd_h, }, { "L", &Debugger::cmd_L, }, { "m", &Debugger::cmd_m, }, - { "mt", &Debugger::cmd_mt, }, { "M", &Debugger::cmd_M, }, { "mpu", &Debugger::cmd_mpu, }, { "n", &Debugger::cmd_n, }, @@ -963,14 +973,14 @@ Debugger::NotifyExceptionXP(int vector) Debugger::CmdAct Debugger::cmd_h() { - if (args.size() < 2) { + if (cmdargs.size() < 2) { // 引数なしなら一覧表示。 ShowHelpList(HelpListMain); return CmdAct::Stay; } // 引数があれば個別の詳細 - const std::string cmd1 = args[1]; + const std::string cmd1 = cmdargs[1]; // curmd の MD 分も併せて検索するため、ローカルに map を作成する。 // value のほうは実体コピーは不要なのでポインタ。 @@ -985,7 +995,7 @@ Debugger::cmd_h() // 検索 const auto it1 = helpmap.find(cmd1); if (it1 == helpmap.end()) { - fprintf(cons, "invalid command name: %s\n", cmd1.c_str()); + fprintf(cons, "Invalid command name: %s\n", cmd1.c_str()); return CmdAct::Stay; } const auto& msg1 = *(it1->second); @@ -1002,7 +1012,7 @@ Debugger::cmd_h() // 再検索 (こっちは見付からないはずはない) const auto it2 = helpmap.find(cmd2); if (it2 == helpmap.end()) { - fprintf(cons, "Warning: '%s' in '%s' not found\n", + fprintf(cons, "Warning: '%s' in '%s' not found.\n", msg1.c_str(), cmd1.c_str()); return CmdAct::Stay; } @@ -1173,11 +1183,12 @@ Debugger::HelpDetails = { { "bv", R"**( Command: bv [,][-] [] - Sets an exception breakpoint on . must be specified in hex. - ranges from 0 to ff (255 in decimal) on m68k, and 0 to 1ff (511 - in decimal) on m88k. If is specified, it matches the range - from to (including themselves). - For example, "bv 1-1ff" on m88k means all exceptions but reset. + Sets an exception breakpoint on . accepts hexadecimal + number if prefixed with "$" or "0x", or decimal number if no prefix. + ranges from 0 to 255 on m68k, and 0 to 511 on m88k. + If is specified, it matches the range from to + (including themselves). For example, "bv 1-$1ff" on m88k means all + exceptions but reset. If is omitted, the current cpu is used. XXX skipcount @@ -1220,12 +1231,11 @@ Debugger::HelpDetails = { { "d", R"**( Command: D
] [] Command: d [[:]
] [] - Command: dt [[:]
] [] Shows disassemble. The first form ("D") interprets
as a physical address. - The second and third form ("d", "dt") interprets
as a logical - address if the address translation is enabled. Normally,
is + The second form ("d") interprets
as a logical address + if the address translation is enabled. Normally,
is interpreted in the current privilege and current address space. You can change it by modifier. On m68k, can be specified either by function code number directly @@ -1236,11 +1246,7 @@ Debugger::HelpDetails = { modifier ('s' or 'u', same as above) and following CMMU identifiers: 'd' .. Data CMMU 'i' or 'p' .. Instruction CMMU Or CMMU can also be identified by CMMU number (like '6' or '7'). - - "d" only looks up in ATC (on m68k) or in BATC/PATC (on m88k). - "dt" will simulate to search the page table in addition to that. )**" }, - { "dt", "=d" }, { "D", "=d" }, //----- @@ -1290,12 +1296,11 @@ Debugger::HelpDetails = { { "m", R"**( Command: M
] [] Command: m [[:]
] [] - Command: mt [[:]
] [] Shows memory dump. The first form ("M") interprets
as a physical address. - The second and third form ("m", "mt") interprets
as a logical - address if the address translation is enabled. Normally,
is + The second form ("m") interprets
as a logical address + if the address translation is enabled. Normally,
is interpreted in the current privilege and current address space. You can change it by modifier. On m68k, can be specified either by function code number directly @@ -1306,11 +1311,7 @@ Debugger::HelpDetails = { modifier ('s' or 'u', same as above) and following CMMU identifiers: 'd' .. Data CMMU 'i' or 'p' .. Instruction CMMU Or CMMU can also be identified by CMMU number (like '6' or '7'). - - "m" only looks up in ATC (on m68k) or in BATC/PATC (on m88k). - "mt" will simulate to search the page table in addition to that. )**" }, - { "mt", "=m" }, { "M", "=m" }, //----- @@ -1394,7 +1395,7 @@ Debugger::HelpDetails = { )**" }, }; -// cmdbuf を args... に分解する。 +// cmdbuf を cmdargs... に分解する。 void Debugger::ParseCmdbuf() { @@ -1402,13 +1403,13 @@ Debugger::ParseCmdbuf() int start; pos = 0; - args.clear(); + cmdargs.clear(); // 引数を空白で分解 for (;;) { // 先頭の空白はスキップ for (; cmdbuf[pos] != '\0'; pos++) { - if (!isspace((unsigned int)cmdbuf[pos])) + if (!is_ascii_space(cmdbuf[pos])) break; } if (cmdbuf[pos] == '\0') @@ -1417,15 +1418,15 @@ Debugger::ParseCmdbuf() // 終わりを探す start = pos; for (; cmdbuf[pos] != '\0'; pos++) { - if (isspace((unsigned int)cmdbuf[pos])) + if (is_ascii_space(cmdbuf[pos])) break; } - args.push_back(cmdbuf.substr(start, pos - start)); + cmdargs.push_back(cmdbuf.substr(start, pos - start)); } // デバッグ表示 if (0) { - for (int i = 0 ; i < args.size(); i++) { - printf("args[%d]=|%s|\n", i, args[i].c_str()); + for (int i = 0 ; i < cmdargs.size(); i++) { + printf("cmdargs[%d]=|%s|\n", i, cmdargs[i].c_str()); } } } @@ -1442,12 +1443,12 @@ Debugger::CmdAct Debugger::cmd_b() { // 引数なしなら一覧表示 - if (args.size() < 2) { + if (cmdargs.size() < 2) { return cmd_b_list(); } // 引数取得 - if (args[1][0] == '#') { + if (cmdargs[1][0] == '#') { // # 形式なら、指定番号のブレークポイントを削除 cmd_b_delete(); return CmdAct::Stay; @@ -1463,13 +1464,14 @@ Debugger::cmd_bm() { // XXX m88k のみ未サポート if (curmd->arch != CPUArch::M88xx0) { - fprintf(cons, "bm not supported yet on m68k\n"); + fprintf(cons, "bm: Not supported yet on m68k.\n"); return CmdAct::Stay; } return cmd_b_set(BreakpointType::Memory); } // type が違うだけの各種ブレークポイント設定の共通部分。 +// すぐ下の ParseOptBreakAddr() と限りなく似ている。 Debugger::CmdAct Debugger::cmd_b_set(BreakpointType type) { @@ -1477,63 +1479,132 @@ Debugger::cmd_b_set(BreakpointType type) std::string cpustr; std::string addrstr; - if (args.size() < 2) { - fprintf(cons, "usage: %s [,] []\n", - args[0].c_str()); + if (cmdargs.size() < 2) { + fprintf(cons, "Usage: %s [,] []\n", + cmdargs[0].c_str()); return CmdAct::Stay; } // まず CPU を分離 - auto pos = args[1].find(','); + auto pos = cmdargs[1].find(','); if (pos == std::string::npos) { // CPU 指定なし - addrstr = args[1]; + addrstr = cmdargs[1]; } else { // CPU 指定あり - cpustr = args[1].substr(0, pos); - addrstr = args[1].substr(pos + 1); + cpustr = cmdargs[1].substr(0, pos); + addrstr = cmdargs[1].substr(pos + 1); } + // CPU + bp.md = ParseCPU(cpustr); + if (bp.md == NULL) { + fprintf(cons, "Invalid CPU Name.\n"); + return CmdAct::Stay; + } // アドレス if (!ParseAddr(addrstr.c_str(), &bp.addr)) { return CmdAct::Stay; } // あればスキップカウント - if (args.size() > 2) { - bp.skip = atoi(args[2].c_str()); + if (cmdargs.size() > 2) { + bp.skip = atoi(cmdargs[2].c_str()); } // 空いてるところにセット // (よく似たエントリがあっても干渉しない) bp.type = type; - int bi = AddBreakpoint(bp, cpustr); + int bi = AddBreakpoint(bp); if (bi == -1) { - fprintf(cons, "no free breakpoints\n"); + fprintf(cons, "Breakpoints full.\n"); } else { - fprintf(cons, "breakpoint #%d added\n", bi); + fprintf(cons, "Breakpoint #%d added.\n", bi); } return CmdAct::Stay; } +// コマンドラインオプション -b(--b) の引数 str からのブレークポイント(アドレス) +// を登録する。 +// 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。 +// すぐ上の cmd_b_set() と限りなく似ている。 +bool +Debugger::ParseOptBreakAddr(const std::string& str) +{ + breakpoint_t bp; + std::string cpustr; + std::string addrstr; + std::string skipstr; + + // "," で分離。 + auto args = string_split(str, ','); + if (args.size() == 1) { + // 1個ならアドレスのみ。 + addrstr = args[0]; + } else if (args.size() == 2) { + // 2個なら cpu か skip のどちらかが省略されている…。 + // 先頭が CPU 文字列かどうかで判定する。 + if (IsCPUStr(args[0])) { + cpustr = args[0]; + addrstr = args[1]; + } else { + addrstr = args[0]; + skipstr = args[1]; + } + } else if (args.size() == 3) { + cpustr = args[0]; + addrstr = args[1]; + skipstr = args[2]; + } else { + warnx("--b \"%s\": Syntax error.", str.c_str()); + return false; + } + + // を取り出す。 + bp.md = ParseCPU(cpustr); + if (bp.md == NULL) { + warnx("--b \"%s\": Invalid CPU Name.", str.c_str()); + return false; + } + + // を取り出す。 + if (ParseVerbHex(addrstr.c_str(), &bp.addr) == false) { + warnx("--b \"%s\": Invalid address.", str.c_str()); + return false; + } + + // を取り出す。 + if (skipstr.empty() == false) { + bp.skip = atoi(skipstr.c_str()); + } + + // 登録。 + bp.type = BreakpointType::Address; + if (AddBreakpoint(bp) < 0) { + warnx("--b \"%s\": Breakpoints full.", str.c_str()); + return false; + } + return true; +} + // ブレークポイント個別削除 // (引数の先頭が '#' なことを判定したところで呼ばれる) // b # Debugger::CmdAct Debugger::cmd_b_delete() { - int n = atoi(&args[1][1]); + int n = atoi(&cmdargs[1][1]); if (n < 0 || n >= bpoint.size()) { - fprintf(cons, "invalid breakpoint number: #%d\n", n); + fprintf(cons, "Invalid breakpoint number: %d\n", n); return CmdAct::Stay; } auto& bp = bpoint[n]; if (bp.type == BreakpointType::Unused) { - fprintf(cons, "invalid breakpoint number: #%d\n", n); + fprintf(cons, "Breakpoint #%d already removed.\n", n); return CmdAct::Stay; } - fprintf(cons, "breakpoint #%d removed\n", n); + fprintf(cons, "Breakpoint #%d removed.\n", n); bp.type = BreakpointType::Unused; // 今登録されている命令ブレークの必要命令長を再計算 RecalcInstMask(); @@ -1545,153 +1616,344 @@ Debugger::cmd_b_delete() Debugger::CmdAct Debugger::cmd_bi() { - breakpoint_t bp; std::string cpustr; - std::string argstr; std::string inststr; - std::string maskstr; - int instlen; - int masklen; + std::string skipstr; + std::string errstr; - if (args.size() < 2) { - fprintf(cons, "usage: bi [:] []\n"); + if (cmdargs.size() < 2) { + fprintf(cons, "Usage: bi [:] []\n"); return CmdAct::Stay; } // CPU をまず分離 - auto pos = args[1].find(','); + auto pos = cmdargs[1].find(','); if (pos == std::string::npos) { // CPU 指定なし - argstr = args[1]; + inststr = cmdargs[1]; } else { // CPU 指定あり - cpustr = args[1].substr(0, pos); - argstr = args[1].substr(pos + 1); + cpustr = cmdargs[1].substr(0, pos); + inststr = cmdargs[1].substr(pos + 1); } - pos = argstr.find(':'); - if (pos == std::string::npos) { - // マスク指定なし - inststr = argstr; - instlen = inststr.size(); + // あればスキップカウント + if (cmdargs.size() > 2) { + skipstr = cmdargs[2]; + } + + // 命令ブレークポイントを登録。 + int bi = AddBreakInst(cpustr, inststr, skipstr, &errstr); + if (errstr.empty() == false) { + fprintf(cons, "%s\n", errstr.c_str()); + return CmdAct::Stay; + } + fprintf(cons, "Breakpoint #%d added.\n", bi); + return CmdAct::Stay; +} + +// --bi オプションの引数 str から命令ブレークポイントを登録する。 +// 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。 +bool +Debugger::ParseOptBreakInst(const std::string& str) +{ + std::string cpustr; + std::string inststr; + std::string skipstr; + std::string errstr; + + // "," で分離。 + auto args = string_split(str, ','); + if (args.size() == 1) { + // 1個なら命令のみ。 + inststr = args[0]; + } else if (args.size() == 2) { + // 2個なら cpu か skip のどちらかが省略されている…。 + // 先頭が CPU 文字列かどうかで判定する。 + if (IsCPUStr(args[0])) { + cpustr = args[0]; + inststr = args[1]; + } else { + inststr = args[0]; + skipstr = args[1]; + } + } else if (args.size() == 3) { + cpustr = args[0]; + inststr = args[1]; + skipstr = args[2]; + } else { + warnx("--bi \"%s\": Syntax error.", str.c_str()); + return false; + } + + // 命令ブレークポイントを登録。 + AddBreakInst(cpustr, inststr, skipstr, &errstr); + if (errstr.empty() == false) { + warnx("--bi \"%s\": %s", str.c_str(), errstr.c_str()); + return false; + } + return true; +} + +// 命令ブレークポイントを登録する。cmd_bi と --bi の後半の共通部分。 +// 成功すれば *errstr は empty でブレークポイント番号(>=0)を返す。 +// 失敗すれば *errstr をセットして -1 を返す。 +int +Debugger::AddBreakInst(const std::string& cpustr, const std::string& argstr, + const std::string& skipstr, std::string *errstr) +{ + DebuggerMD *md; + breakpoint_t bp; + std::string inststr; + std::string maskstr; + int instlen; + int masklen; + + // CPU 部チェック + md = ParseCPU(cpustr); + if (md == NULL) { + *errstr = std::string("Invalid CPU Name."); + return CmdAct::Stay; + } + bp.md = md; + + // 命令部。 + // ニーモニックが指定できたら便利。 + inststr = md->ParseInst(argstr); + if (inststr.empty() == false) { masklen = -1; } else { - // マスク指定あり - inststr = argstr.substr(0, pos); - instlen = inststr.size(); - maskstr = argstr.substr(pos + 1); - masklen = maskstr.size(); + auto pos = argstr.find(':'); + if (pos == std::string::npos) { + // マスク指定なし。 + inststr = argstr; + masklen = -1; + } else { + // マスク指定あり。 + inststr = argstr.substr(0, pos); + maskstr = argstr.substr(pos + 1); + masklen = maskstr.size(); + } } + instlen = inststr.size(); - // 命令部チェック if (ParseVerbHex(inststr.c_str(), &bp.inst) == false) { - fprintf(cons, "%s: invalid instruction value\n", argstr.c_str()); - return CmdAct::Stay; + *errstr = string_format("Invalid instruction: %s", argstr.c_str()); + return -1; } - if (instlen % (curmd->inst_bytes * 2) != 0) { - fprintf(cons, "%s: invalid instruction length\n", argstr.c_str()); - return CmdAct::Stay; + if (instlen % (md->inst_bytes * 2) != 0) { + *errstr = string_format("Invalid instruction length: %s", + argstr.c_str()); + return -1; } // マスク部チェック bp.mask = 0xffffffff; if (masklen != -1) { if (ParseVerbHex(maskstr.c_str(), &bp.mask) == false) { - fprintf(cons, "%s: invalid mask value\n", argstr.c_str()); - return CmdAct::Stay; + *errstr = string_format("Invalid mask value: %s", argstr.c_str()); + return -1; } if (masklen != instlen) { - fprintf(cons, "%s: inst:mask must be the same length\n", - argstr.c_str()); - return CmdAct::Stay; + *errstr = std::string(": must be the same length"); + return -1; } } // 8バイト未満なら左詰め。 - if (curmd->inst_bytes < 4 && instlen < 8) { + if (md->inst_bytes < 4 && instlen < 8) { bp.inst <<= 32 - instlen * 4; bp.mask <<= 32 - instlen * 4; } - // あればスキップカウント - bp.skip = 0; - if (args.size() > 2) { - bp.skip = atoi(args[2].c_str()); + // を取り出す。 + if (skipstr.empty() == false) { + bp.skip = atoi(skipstr.c_str()); } // 空いてるところにセット bp.type = BreakpointType::Instruction; - int bi = AddBreakpoint(bp, cpustr); - if (bi == -1) { - fprintf(cons, "no free breakpoints\n"); - } else { - fprintf(cons, "breakpoint #%d added\n", bi); + int bi = AddBreakpoint(bp); + if (bi < 0) { + *errstr = std::string("Breakpoints full."); + return bi; } - // 今登録されている命令ブレークの必要命令長を再計算 + // 今登録されている命令ブレークの必要命令長を再計算。 RecalcInstMask(); - return CmdAct::Stay; + + return bi; } -// 例外ブレークポイントの設定 +// 例外ブレークポイントの設定。 // bv [,][-] [] Debugger::CmdAct Debugger::cmd_bv() { - breakpoint_t bp; - std::string argstr; std::string cpustr; - DebuggerMD *md; + std::string vecstr; + std::string skipstr; + std::string errstr; - if (args.size() < 2) { - fprintf(cons, "usage: bv [,][-] []\n"); + if (cmdargs.size() < 2) { + fprintf(cons, "Usage: bv [,][-] []\n"); return CmdAct::Stay; } // CPU をまず分離 - auto pos = args[1].find(','); + auto pos = cmdargs[1].find(','); if (pos == std::string::npos) { // CPU 指定なし - argstr = args[1]; + vecstr = cmdargs[1]; } else { // CPU 指定あり - cpustr = args[1].substr(0, pos); - argstr = args[1].substr(pos + 1); + cpustr = cmdargs[1].substr(0, pos); + vecstr = cmdargs[1].substr(pos + 1); } - // ベクタ名解釈のために必要 + + if (cmdargs.size() > 2) { + skipstr = cmdargs[2]; + } + + // ベクタブレークポイントを登録。 + int bi = AddBreakVector(cpustr, vecstr, skipstr, &errstr); + if (errstr.empty() == false) { + fprintf(cons, "%s\n", errstr.c_str()); + return CmdAct::Stay; + } + fprintf(cons, "Breakpoint #%d added.\n", bi); + + // この CPU 側に、すでに来ている例外をクリア。 + // ブレークポイント設定の有無に関わらず例外が起きたら CPU 側から常に + // 通知されている。これをクリアするのは CheckAllBreakpoints() で、これは + // 命令間(命令前)に呼ばれるやつ、なのでこうなる。 + // 1. 例外が起きると md->bv_vector がセットされる + // 2. 例外ブレークポイントを設定していないとこれがクリアされない + // 3. bv コマンドで例外ブレークを新たに設定すると、次の命令境界で + // 1.のベクタが反応してしまう。 + // 命令ごととかにクリアしてもいいかも知れないが、ここでブレークポイントを + // 設定したのだから、それ以前の事象には反応すべきでない、という意味では + // ここでもいいか? + + // bp.md は AddBreakpoint() で bpoint 登録時にセットされるので + // インデックスから bp をもう一度読み込む。 + auto bp = bpoint[bi]; + bp.md->bv_vector = -1; + + return CmdAct::Stay; +} + +// --bv オプションの引数 str からベクタブレークポイントを登録する。 +// 成功すれば true を返す。失敗すればエラーメッセージを表示して false を返す。 +bool +Debugger::ParseOptBreakVector(const std::string& str) +{ + std::string cpustr; + std::string vecstr; + std::string skipstr; + std::string errstr; + + // "," で分離。 + auto args = string_split(str, ','); + if (args.size() == 1) { + // 1個ならベクタのみ。 + vecstr = args[0]; + } else if (args.size() == 2) { + // 2個なら cpu か skip のどちらかが省略されている…。 + // 先頭が CPU 文字列かどうかで判定する。 + if (IsCPUStr(args[0])) { + cpustr = args[0]; + vecstr = args[1]; + } else { + vecstr = args[0]; + skipstr = args[1]; + } + } else if (args.size() == 3) { + cpustr = args[0]; + vecstr = args[1]; + skipstr = args[2]; + } else { + warnx("--bv \"%s\": Syntax error.", str.c_str()); + return false; + } + + // ベクタブレークポイントを登録。 + AddBreakVector(cpustr, vecstr, skipstr, &errstr); + if (errstr.empty() == false) { + warnx("--bv \"%s\": %s", str.c_str(), errstr.c_str()); + return false; + } + return true; +} + +// ベクタブレークポイントを登録する。cmd_bv と --bv の後半の共通部分。 +// 成功すれば *errstr は empty でブレークポイント番号(>=0)を返す。 +// 失敗すれば *errstr をセットして -1 を返す。 +int +Debugger::AddBreakVector(const std::string& cpustr, const std::string& vecstr, + const std::string& skipstr, std::string *errstr) +{ + uint32 maxvector; + breakpoint_t bp; + DebuggerMD *md; + + // CPU 部。ベクタ解釈にも使う。 md = ParseCPU(cpustr); + if (md == NULL) { + *errstr = std::string("Invalid CPU Name."); + return CmdAct::Stay; + } + bp.md = md; - pos = argstr.find('-'); + // ベクタ数 (最大値) を取得。 + if (md->arch == CPUArch::HD64180) { + // XXX あってる? + maxvector = 256; + } else { + maxvector = pVectorTable->Size(); + } + + // ベクタを取り出す。 + auto pos = vecstr.find('-'); if (pos == std::string::npos) { // ベクタ番号が1つなら vec1, vec2 を同値にしておく。 - if (ParseVector(md, argstr.c_str(), (uint32 *)&bp.vec1) == false) { - fprintf(cons, "%s: invalid vector number\n", argstr.c_str()); - return CmdAct::Stay; + if (ParseVector(md, vecstr.c_str(), (uint32 *)&bp.vec1) == false) { + *errstr = string_format("Invalid vector number: %s", + vecstr.c_str()); + return -1; } bp.vec2 = bp.vec1; } else { // ベクタ番号(範囲指定 [vec1, vec2]) - std::string str1 = argstr.substr(0, pos); - std::string str2 = argstr.substr(pos + 1); + std::string vec1 = vecstr.substr(0, pos); + std::string vec2 = vecstr.substr(pos + 1); - if (ParseVector(md, str1.c_str(), (uint32 *)&bp.vec1) == false) { - fprintf(cons, "%s: invalid first vector number\n", argstr.c_str()); - return CmdAct::Stay; + // "-vec2" なら vec1 = 0、 + // "vec1-" なら vec2 は最大値 (機種による)、とする。 + + if (vec1.empty()) { + bp.vec1 = 0; + } else if (ParseVector(md, vec1.c_str(), (uint32 *)&bp.vec1) == false) { + *errstr = string_format("Invalid first vector number: %s", + vecstr.c_str()); + return -1; } - if (ParseVector(md, str2.c_str(), (uint32 *)&bp.vec2) == false) { - fprintf(cons, "%s: invalid last vector number\n", argstr.c_str()); - return CmdAct::Stay; + if (vec2.empty()) { + bp.vec2 = maxvector - 1; + } else if (ParseVector(md, vec2.c_str(), (uint32 *)&bp.vec2) == false) { + *errstr = string_format("Invalid last vector number: %s", + vecstr.c_str()); + return -1; } } // 範囲チェック - auto vectortable = pVectorTable.get(); - if (bp.vec1 < 0 || bp.vec1 >= vectortable->Size()) { - fprintf(cons, "$%x: invalid vector number\n", bp.vec1); - return CmdAct::Stay; - } - if (bp.vec2 < 0 || bp.vec2 >= vectortable->Size()) { - fprintf(cons, "$%x: invalid last vector number\n", bp.vec2); - return CmdAct::Stay; + if (bp.vec1 < 0 || bp.vec1 >= maxvector) { + *errstr = string_format("Out of range: $%x", bp.vec1); + return -1; + } + if (bp.vec2 < 0 || bp.vec2 >= maxvector) { + *errstr = string_format("Out of range: $%x", bp.vec2); + return -1; } // 大小が逆なら入れ替える? @@ -1702,51 +1964,55 @@ Debugger::cmd_bv() bp.vec2 = tmp; } - // あればスキップカウント - bp.skip = 0; - if (args.size() > 2) { - bp.skip = atoi(args[2].c_str()); + // を取り出す。 + if (skipstr.empty() == false) { + bp.skip = atoi(skipstr.c_str()); } // 空いてるところにセット bp.type = BreakpointType::Exception; - int bi = AddBreakpoint(bp, cpustr); - if (bi == -1) { - fprintf(cons, "no free breakpoints\n"); - } else { - fprintf(cons, "breakpoint #%d added\n", bi); + int bi = AddBreakpoint(bp); + if (bi < 0) { + *errstr = std::string("Breakpoints full."); } - - // この CPU 側に、すでに来ている例外をクリア。 - // ブレークポイント設定の有無に関わらず例外が起きたら CPU 側から常に - // 通知されている。これをクリアするのは CheckAllBreakpoints() で、これは - // 命令間(命令前)に呼ばれるやつ、なのでこうなる。 - // 1. 例外が起きると md->bv_vector がセットされる - // 2. 例外ブレークポイントを設定していないとこれがクリアされない - // 3. bv コマンドで例外ブレークを新たに設定すると、次の命令境界で - // 1.のベクタが反応してしまう。 - // 命令ごととかにクリアしてもいいかも知れないが、ここでブレークポイントを - // 設定したのだから、それ以前の事象には反応すべきでない、という意味では - // ここでもいいか? - - // bp.md は AddBreakpoint() で bpoint 登録時にセットされるので - // インデックスから bp をもう一度読み込む。 - bp = bpoint[bi]; - bp.md->bv_vector = -1; - - return CmdAct::Stay; + return bi; } // ベクタ名かベクタ番号をパースする。 +// ベクタ番号は10進数で表記されることが多いので、10進/16進どちらも対応する。 +// - "$" か "0x" から始まれば16進数。 +// - それ以外で [0-9] から始まれば10進数。"0" プレフィックスを8進数にはしない。 +// - それ以外ならベクタ名とみなす。 bool Debugger::ParseVector(DebuggerMD *md, const char *arg, uint32 *valp) { - // 数値変換出来るか。 - if (ParseVerbHex(arg, valp)) { + assert(arg); + + if (arg[0] == '$') { + // 1文字目以降が16進数。 + return ParseVerbHex(arg + 1, valp); + } + if (strncmp(arg, "0x", 2) == 0) { + // 2文字目以降が16進数。 + return ParseVerbHex(arg + 2, valp); + } + if ('0' <= arg[0] && arg[0] <= '9') { + // 先頭から10進数。 + uint32 val; + char *end; + errno = 0; + val = strtoul(arg, &end, 10); + if (*end != '\0') { + return false; + } + if (errno == ERANGE) { + return false; + } + *valp = val; return true; } - // 出来なければ、機種ごとにベクタ名と比較する。 + // 数値に出来なければ、機種ごとにベクタ名と比較する。 if (md->arch == CPUArch::HD64180) { static std::vector table = { "trap", @@ -1790,15 +2056,15 @@ Debugger::MonitorUpdateBpoint(Monitor *, { // 0 1 2 3 4 5 6 // 0123456789012345678901234567890123456789012345678901234567890 - // No CPU Type Parameter Matched Skip - // #0 xp addr $01234567 123456789 123456789/123456789 - // #1 main inst 00000000/00000000 - // #2 main excp $00-$00 + // No CPU Type Parameter Matched Skip + // #0 xp addr $01234567 123456789 123456789/123456789 + // #1 mpu inst 00000000:00000000 + // #2 mpu excp $00-$00 monitor.Clear(); - monitor.Print(0, 0, "No CPU Type Parameter"); - monitor.Print(31, 0, "Matched"); - monitor.Print(42, 0, "Skip"); + monitor.Print(0, 0, "No CPU Type Parameter"); + monitor.Print(30, 0, "Matched"); + monitor.Print(41, 0, "Skip"); for (int i = 0; i < bpoint.size(); i++) { const auto& bp = bpoint[i]; @@ -1806,64 +2072,69 @@ Debugger::MonitorUpdateBpoint(Monitor *, monitor.Print(0, y, "#%d", i); - // 種別ごとの表示 - switch (bp.type) { - case BreakpointType::Unused: + if (bp.type == BreakpointType::Unused) { continue; + } + monitor.Print(3, y, "%s", bp.md ? bp.md->GetName().c_str() : "?"); + // 種別ごとの表示 + switch (bp.type) { case BreakpointType::Address: - monitor.Print(3, y, "%-4s addr $%08x", - bp.md->GetName().c_str(), bp.addr); + monitor.Print(7, y, "addr $%08x", bp.addr); break; + case BreakpointType::Memory: - monitor.Print(3, y, "%-4s mem $%08x", - bp.md->GetName().c_str(), bp.addr); + monitor.Print(7, y, "mem $%08x", bp.addr); break; case BreakpointType::Exception: - monitor.Print(3, y, "%-4s excp $%02x", - bp.md->GetName().c_str(), bp.vec1); + { + uint vd; // ベクタの桁数 + if (bp.md->arch == CPUArch::M88xx0) { + vd = 3; + } else { + vd = 2; + } + monitor.Print(7, y, "excp $%0*x", vd, bp.vec1); if (bp.vec2 != bp.vec1) { - monitor.Print(16, y, "-$%02x", bp.vec2); + monitor.Print(13 + vd, y, "-$%0*x", vd, bp.vec2); } break; + } case BreakpointType::Instruction: - monitor.Print(3, y, "%-4s inst", bp.md->GetName().c_str()); - if (bp.md->inst_bytes == 4) { - if (bp.mask == 0xffffffff) { - monitor.Print(13, y, "%08x", bp.inst); - } else { - monitor.Print(13, y, "%08x:%08x", bp.inst, bp.mask); - } - } else { - if (bp.mask == 0xffffffff) { - monitor.Print(13, y, "%08x", bp.inst); - } else if (((bp.inst | bp.mask) & 0x0000ffff) != 0) { - monitor.Print(13, y, "%08x:%08x", bp.inst, bp.mask); - } else if (bp.mask == 0xffff0000) { - monitor.Print(13, y, "%04x", bp.inst >> 16); - } else { - monitor.Print(13, y, "%04x:%04x", - bp.inst >> 16, bp.mask >> 16); + monitor.Puts(7, y, "inst"); + for (int n = bp.md->inst_bytes; n <= 4; n += bp.md->inst_bytes) { + // 左詰め n バイト分のマスク。 + int bits = (4 - n) * 8; + uint imask = 0xffffffffU << bits; + // n が 4 だと ~imask の式は使えないが無条件で入る。 + if (n == 4 || ((bp.inst | bp.mask) & ~imask) == 0) { + if (bp.mask == imask) { + monitor.Print(12, y, "%0*x", n * 2, (bp.inst >> bits)); + } else { + monitor.Print(12, y, "%0*x:%0*x", + n * 2, (bp.inst >> bits), + n * 2, (bp.mask >> bits)); + } + break; } } break; default: - monitor.Print(3, y, "%-4s type=%d", - (bp.md ? bp.md->GetName().c_str() : "?"), (int)bp.type); + monitor.Print(7, y, "type=%d", (int)bp.type); continue; } // マッチ回数 - monitor.Print(31, y, "%d", bp.matched); + monitor.Print(30, y, "%d", bp.matched); // スキップ if (bp.skip < 0) { - monitor.Print(42, y, "forever"); + monitor.Print(41, y, "forever"); } else if (bp.skip > 0) { - monitor.Print(42, y, "%d / %d", (bp.skip - bp.skipremain), bp.skip); + monitor.Print(41, y, "%d / %d", (bp.skip - bp.skipremain), bp.skip); } } } @@ -1875,7 +2146,7 @@ Debugger::cmd_bx() for (auto& bp : bpoint) { bp.type = BreakpointType::Unused; } - fprintf(cons, " All breakpoints disabled\n"); + fprintf(cons, "All breakpoints are removed.\n"); // 今登録されている命令ブレークの必要命令長を再計算 RecalcInstMask(); @@ -1883,6 +2154,19 @@ Debugger::cmd_bx() return CmdAct::Stay; } +// CPU 文字列なら true を返す。 +bool +Debugger::IsCPUStr(const std::string& cpustr) const +{ + if (cpustr.empty()) { + return false; + } + if (ParseCPU(cpustr) == NULL) { + return false; + } + return true; +} + // CPU 文字列から対応する MD を返す。 // 一致しなければ NULL を返す。 DebuggerMD * @@ -1892,26 +2176,27 @@ Debugger::ParseCPU(const std::string& cp return curmd; } else if (cpustr == "xp") { return md_xp.get(); - } else if (cpustr == "main") { + } else if (cpustr == "mpu") { return md_mpu.get(); } return NULL; } // ブレークポイントを設定。 -// new_bp のうち cpu, matched, skipremain はこちらで初期化する。 -// それ以外を埋めてから呼ぶこと。 +// new_bp のうち matched, skipremain はこちらで初期化する。 +// それ以外の type、md と type ごとに必要なパラメータを埋めてから呼ぶこと。 // 設定できればその番号、できなければ -1 を返す。 int -Debugger::AddBreakpoint(const breakpoint_t& new_bp, const std::string& cpustr) +Debugger::AddBreakpoint(const breakpoint_t& new_bp) { - DebuggerMD *md = ParseCPU(cpustr); - for (int i = 0; i < bpoint.size(); i++) { auto& bp = bpoint[i]; if (bp.type == BreakpointType::Unused) { bp = new_bp; - bp.md = md; + // 本当は assert レベルだが、とは言えここで死なれるとつらいので。 + if (bp.md == NULL) { + bp.md = curmd; + } bp.matched = 0; if (bp.skip > 0) { bp.skipremain = bp.skip; @@ -1986,8 +2271,8 @@ Debugger::cmd_hist_common(BranchHistory& // 向きは bottom_to_top = true が新しいほうを下とする方向。 int maxlines = 20; bool bottom_to_top = true; - if (args.size() > 1) { - maxlines = atoi(args[1].c_str()); + if (cmdargs.size() > 1) { + maxlines = atoi(cmdargs[1].c_str()); if (maxlines < 0) { bottom_to_top = false; maxlines = -maxlines; @@ -2007,10 +2292,9 @@ Debugger::cmd_hist_common(BranchHistory& int lines = std::min(used, maxlines) + 1; // MonitorUpdate() は TextScreen 高さに合わせて出力してくれる。 - auto& histmon = hist.monitor; - auto size = histmon.GetSize(); + auto *histmon = hist.monitor; TextScreen screen; - screen.Init(size.width, lines); + screen.Init(histmon->GetCol(), lines); // コンソールでは下が新しいの順のほうがいい if (bottom_to_top) { @@ -2018,7 +2302,7 @@ Debugger::cmd_hist_common(BranchHistory& } // 表示 - MONITOR_UPDATE(histmon, screen); + histmon->Update(screen); ShowTextScreen(screen); return CmdAct::Stay; @@ -2029,10 +2313,10 @@ Debugger::cmd_hist_common(BranchHistory& Debugger::CmdAct Debugger::cmd_c() { - if (args.size() > 1) { + if (cmdargs.size() > 1) { // 引数があれば uint32 addr; - if (!ParseAddr(args[1].c_str(), &addr)) { + if (!ParseAddr(cmdargs[1].c_str(), &addr)) { return CmdAct::Stay; } step_type = StepType::Addr; @@ -2048,14 +2332,14 @@ Debugger::cmd_c() Debugger::CmdAct Debugger::cmd_ct() { - if (args.size() > 1) { + if (cmdargs.size() > 1) { // 引数があれば - if (!ParseTime(args[1].c_str(), &ct_timespan)) { + if (!ParseTime(cmdargs[1].c_str(), &ct_timespan)) { return CmdAct::Stay; } } if (ct_timespan == 0) { - fprintf(cons, "time must be specified\n"); + fprintf(cons, "Time must be specified.\n"); return CmdAct::Stay; } step_type = StepType::Time; @@ -2069,14 +2353,14 @@ Debugger::cmd_ct() // // 引数がなければ sa->addr には書き込まずに true で帰る (ので、呼び出し側が // 事前に適切なデフォルト値をセットしておくと、それがそのまま使われる)。 -// 引数が1つ(以上)あれば args[1] をアドレスとしてパースする。 +// 引数が1つ(以上)あれば cmdargs[1] をアドレスとしてパースする。 // アドレスには空間修飾子を前置可能、省略の場合はいずれも現在値を使う。 // エラーならメッセージを表示して false を返す。 // sa は in/out パラメータ。 bool -Debugger::GetAddr(saddr_t *sa, bool default_data) +Debugger::GetAddr(busaddr *sa, bool default_data) { - if (args.size() < 2) { + if (cmdargs.size() < 2) { // 引数なしなら、呼び出し側が sa にセットした前回値をそのまま使う。 return true; } @@ -2084,7 +2368,7 @@ Debugger::GetAddr(saddr_t *sa, bool defa // 引数ありならパースする。アドレスが明示的に指定されたので、 // ここから先の省略箇所は前回値ではなくデフォルト値で補完する。 - std::string& str = args[1]; + std::string& str = cmdargs[1]; uint32 addr; // ':' があればその前はアドレス空間修飾子 @@ -2129,7 +2413,8 @@ Debugger::GetAddr(saddr_t *sa, bool defa } // 有効な値は 1,2,5,6 のみ if (num == 0 || num == 3 || num == 4 || num == 7) { - fprintf(cons, "%c: invalid address space\n", ch); + fprintf(cons, "Invalid function code %d.\n", num); + return false; } mod_num = num; mod_super = mod_num >> 2; // FC2 @@ -2146,14 +2431,14 @@ Debugger::GetAddr(saddr_t *sa, bool defa fprintf(cons, "not yet\n"); } } else { - fprintf(cons, "%c: unknown address space modifier\n", ch); + fprintf(cons, "Unknown address space modifier: %c\n", ch); return false; } continue; error: - fprintf(cons, "%s: address space modifier '%c' conflicts\n", - mod.c_str(), ch); + fprintf(cons, "Address space modifiers conflict: \"%s\"\n", + mod.c_str()); return false; } @@ -2173,8 +2458,7 @@ Debugger::GetAddr(saddr_t *sa, bool defa // "6" -> Data (CPU#0) // "7" -> Program (CPU#0) if (mod_num < 6) { - fprintf(cons, "%d: CMMU#%d not installed\n", - mod_num, mod_num); + fprintf(cons, "CMMU %d not installed.\n", mod_num); return false; } mod_prog = mod_num - 6; @@ -2191,15 +2475,15 @@ Debugger::GetAddr(saddr_t *sa, bool defa if (mod_prog < 0) { mod_prog = !default_data; } - sa->SetSuper(mod_super); - sa->SetData(!mod_prog); + sa->ChangeSuper(mod_super); + sa->ChangeData(!mod_prog); // アドレス if (ParseAddr(str.c_str() + addrpos, &addr) == false) { return false; } // 命令境界に丸める - sa->SetAddr(addr & ~(curmd->inst_bytes - 1)); + sa->ChangeAddr(addr & ~(curmd->inst_bytes - 1)); return true; } @@ -2240,11 +2524,13 @@ Debugger::cmd_z() } else { // 可変長なら逆アセンブルしてみるしか。 - saddr_t laddr(curmd->GetPC(), curmd->IsSuper()); - DebuggerMemoryStream mem(curmd, laddr, MMULookupMode::True); + busaddr laddr = busaddr(curmd->GetPC()) + | BusAddr::Fetch + | busaddr::SU(curmd->IsSuper()); + DebuggerMemoryStream mem(curmd, laddr); // XXX 失敗したらどうすべ curmd->Disassemble(mem); - step_addr = (uint32)mem.laddr; + step_addr = mem.laddr.Addr(); } step_type = StepType::Addr; step_md = curmd; @@ -2257,7 +2543,7 @@ Debugger::ChangeMD(DebuggerMD *newmd) { if (newmd != curmd) { curmd = newmd; - fprintf(cons, "Target cpu switched to '%s'\n", + fprintf(cons, "Target cpu is switched to '%s'.\n", curmd->GetName().c_str()); } } @@ -2267,67 +2553,61 @@ void Debugger::ResetStickyAddr() { pc = curmd->GetPC(); - m_last_addr.Set(pc, curmd->IsSuper(), true); - d_last_addr.Set(pc, curmd->IsSuper(), false); + m_last_addr = busaddr(pc) | BusAddr::Read | busaddr::SU(curmd->IsSuper()); + d_last_addr = busaddr(pc) | BusAddr::Fetch | busaddr::SU(curmd->IsSuper()); } -// 逆アセンブル: d [[SU:] []] (論理、テーブルサーチなし) +// 逆アセンブル: d [[SU:] []] (論理) Debugger::CmdAct Debugger::cmd_d() { - return cmd_d_common(MemoryMode::Logical, MMULookupMode::False); -} - -// 逆アセンブル: dt [[SU:]] []] (論理、テーブルサーチあり) -Debugger::CmdAct -Debugger::cmd_dt() -{ - return cmd_d_common(MemoryMode::Logical, MMULookupMode::True); + return cmd_d_common(BusAddr::Logical); } // 逆アセンブル: D [ []] (物理) Debugger::CmdAct Debugger::cmd_D() { - return cmd_d_common(MemoryMode::Physical, MMULookupMode::None); + return cmd_d_common(BusAddr::Physical); } // 逆アセンブル共通 Debugger::CmdAct -Debugger::cmd_d_common(MemoryMode access_mode, MMULookupMode lookup_mode) +Debugger::cmd_d_common(busaddr access_mode) { - saddr_t saddr; + busaddr saddr; int row; row = 10; - // 開始アドレス + // 開始アドレス。S/U は GetAddr() がセットする。 saddr = d_last_addr; if (GetAddr(&saddr, false) == false) { return CmdAct::Stay; } + + // 論理アドレス/物理アドレスはコマンドによって決まる。 + saddr |= access_mode; + // 2つ目の引数があれば行数 - if (args.size() > 2) { - row = strtol(args[2].c_str(), NULL, 10); + if (cmdargs.size() > 2) { + row = strtol(cmdargs[2].c_str(), NULL, 10); } // アドレス幅を制限 (XP用) (ここ?) uint64 mask; - if (access_mode == MemoryMode::Logical) { - mask = (1ULL << curmd->GetLASize()) - 1; - } else { + if (saddr.IsPhysical()) { mask = (1ULL << curmd->GetPASize()) - 1; + } else { + mask = (1ULL << curmd->GetLASize()) - 1; } - saddr = (uint32)saddr & (uint32)mask; + saddr &= (uint32)mask; Memdump disasm(curmd, curmd->arch); disasm.SetAddr(saddr); - disasm.SetAccessMode(access_mode); - disasm.SetLookupMode(lookup_mode); disasm.Print(cons, row); - // アドレスと Super/User 状態を次回継続用に保存 - // (Super/Data はコマンドで都度指定なので気にしなくていい) + // アドレスを次回継続用に保存 d_last_addr = disasm.GetAddr(); return CmdAct::Stay; @@ -2339,7 +2619,7 @@ Debugger::cmd_d_common(MemoryMode access Debugger::CmdAct Debugger::cmd_disp() { - if (args.size() < 2) { + if (cmdargs.size() < 2) { // 表示 bool first = true; for (const auto& r : disp_regs) { @@ -2354,7 +2634,7 @@ Debugger::cmd_disp() char buf[256]; char *p; char *last; - strlcpy(buf, args[1].c_str(), sizeof(buf)); + strlcpy(buf, cmdargs[1].c_str(), sizeof(buf)); disp_regs.clear(); for (p = strtok_r(buf, ",", &last); p; p = strtok_r(NULL, ",", &last)) { disp_regs.push_back(std::string(p)); @@ -2369,8 +2649,8 @@ Debugger::cmd_disp() Debugger::CmdAct Debugger::cmd_L() { - if (args.size() < 2) { - fprintf(cons, "L [=][,[=]]...\n"); + if (cmdargs.size() < 2) { + fprintf(cons, "Usage: L [=][,[=]]...\n"); return CmdAct::Stay; } @@ -2378,11 +2658,11 @@ Debugger::cmd_L() // help が混ざる場合の "L foo=1,help" と "L foo=1 help" を同じ動作に // するため。 std::string str; - for (int i = 1, ac = args.size(); i < ac; i++) { + for (int i = 1, ac = cmdargs.size(); i < ac; i++) { if (str.empty() == false) { str += ','; } - str += args[i]; + str += cmdargs[i]; } // で、再分解 @@ -2409,64 +2689,58 @@ Debugger::cmd_L() return CmdAct::Stay; } -// メモリダンプ: m [ []] (論理、テーブルサーチなし) +// メモリダンプ: m [ []] (論理) Debugger::CmdAct Debugger::cmd_m() { - return cmd_m_common(MemoryMode::Logical, MMULookupMode::False); -} - -// メモリダンプ: mt [ []] (論理、テーブルサーチあり) -Debugger::CmdAct -Debugger::cmd_mt() -{ - return cmd_m_common(MemoryMode::Logical, MMULookupMode::True); + return cmd_m_common(BusAddr::Logical); } // メモリダンプ: M [ []] (物理) Debugger::CmdAct Debugger::cmd_M() { - return cmd_m_common(MemoryMode::Physical, MMULookupMode::None); + return cmd_m_common(BusAddr::Physical); } // メモリダンプ共通 Debugger::CmdAct -Debugger::cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode) +Debugger::cmd_m_common(busaddr access_mode) { - saddr_t saddr; + busaddr saddr; int row; row = 8; - // 開始アドレス + // 開始アドレス。S/U は GetAddr() がセットする。 saddr = m_last_addr; if (GetAddr(&saddr, true) == false) { return CmdAct::Stay; } + + // 論理アドレス/物理アドレスはコマンドによって決まる。 + saddr |= access_mode; + // 2つ目の引数があれば行数 - if (args.size() > 2) { - row = strtol(args[2].c_str(), NULL, 10); + if (cmdargs.size() > 2) { + row = strtol(cmdargs[2].c_str(), NULL, 10); } // アドレス幅を制限 (XP用) (ここ?) uint64 mask; - if (access_mode == MemoryMode::Logical) { - mask = (1ULL << curmd->GetLASize()) - 1; - } else { + if (saddr.IsPhysical()) { mask = (1ULL << curmd->GetPASize()) - 1; + } else { + mask = (1ULL << curmd->GetLASize()) - 1; } - saddr = (uint32)saddr & (uint32)mask; + saddr &= (uint32)mask; Memdump memdump(curmd); memdump.SetAddr(saddr); - memdump.SetAccessMode(access_mode); - memdump.SetLookupMode(lookup_mode); memdump.SetFormat(Memdump::Word); memdump.Print(cons, row); // アドレスを次回継続用に保存 - // (Super/Data はコマンドで都度指定なので気にしなくていい) m_last_addr = memdump.GetAddr(); return CmdAct::Stay; @@ -2490,9 +2764,10 @@ Debugger::cmd_minus() std::string addrbuf; std::string textbuf; - // 論理アクセス時、ATC ミスが分かったほうが便利だと思うので lookup なし - saddr_t laddr(pc, curmd->IsSuper()); - DebuggerMemoryStream mem(curmd, laddr, MMULookupMode::False); + busaddr laddr = busaddr(pc) + | BusAddr::Fetch + | busaddr::SU(curmd->IsSuper()); + DebuggerMemoryStream mem(curmd, laddr); // アドレス if (mem.FormatAddr(addrbuf) == false) { fprintf(cons, "%s\n", addrbuf.c_str()); @@ -2527,11 +2802,11 @@ Debugger::cmd_n_common(bool trace) { t_enable = trace ? curmd : NULL; - if (args.size() > 1) { + if (cmdargs.size() > 1) { int count; - count = strtol(args[1].c_str(), NULL, 10); + count = strtol(cmdargs[1].c_str(), NULL, 10); if (count < 1) { - fprintf(cons, " invalid step count: %d\n", count); + fprintf(cons, "Invalid step count: %d\n", count); return CmdAct::Stay; } @@ -2552,15 +2827,17 @@ Debugger::cmd_n_common(bool trace) void Debugger::SetNBreakpoint() { - saddr_t laddr(curmd->GetPC(), curmd->IsSuper()); - DebuggerMemoryStream mem(curmd, laddr, MMULookupMode::True); + busaddr laddr = busaddr(curmd->GetPC()) + | BusAddr::Fetch + | busaddr::SU(curmd->IsSuper()); + DebuggerMemoryStream mem(curmd, laddr); // 命令がサブルーチンやトラップなどステップインできる命令か。 if (curmd->IsOpStepIn(mem)) { // この次の命令にブレークをかける if (curmd->inst_bytes_fixed != 0) { // 固定長命令 - step_addr = (uint32)mem.laddr; + step_addr = mem.laddr.Addr(); } else { // 可変長なら逆アセンブルしてみるしか。 // 表示用文字列は作る必要ないけど、処理分けるのも手間だし @@ -2570,7 +2847,7 @@ Debugger::SetNBreakpoint() mem.ResetAddr(curmd->GetPC()); // XXX 失敗したらどうすべ curmd->Disassemble(mem); - step_addr = (uint32)mem.laddr; + step_addr = mem.laddr.Addr(); } } else { // そうでなければ1命令進める。 @@ -2582,7 +2859,7 @@ Debugger::SetNBreakpoint() Debugger::CmdAct Debugger::cmd_q() { - fprintf(cons, "quit debugger console.\n"); + fprintf(cons, "Quit debugger console.\n"); return CmdAct::Quit; } @@ -2598,31 +2875,31 @@ Debugger::cmd_reset() Debugger::CmdAct Debugger::cmd_show() { - if (args.size() != 2) { - std::vector list; + if (cmdargs.size() != 2) { + std::vector list; // 登録されているモニタだけを列挙 // (登録されていてもサブウィンドウの ID を持っているものは除外) for (const auto mon : gMonitorManager->GetList()) { - int id = mon->GetId(); + uint id = mon->GetId(); if (id <= ID_MONITOR_END) { list.push_back(id); } } // 一覧を表示 - std::string msg = MonitorManager::MakeListString(list); - fprintf(cons, "usage: show \n"); - fprintf(cons, "%s", msg.c_str()); + fprintf(cons, "Usage: show \n"); + std::vector names = gMonitorManager->MakeListString(list); + MainApp::ShowHelpList(cons, names); return CmdAct::Stay; } std::vector candidates; std::vector cand_names; - std::string name = args[1]; + std::string name = cmdargs[1]; for (auto mon : gMonitorManager->GetList()) { - int id = mon->GetId(); + uint id = mon->GetId(); const auto& aliases = gMonitorManager->GetAliases(id); bool matched = false; @@ -2643,10 +2920,10 @@ Debugger::cmd_show() if (candidates.empty()) { // 一致しない - fprintf(cons, "unknown monitor name: \"%s\"\n", name.c_str()); + fprintf(cons, "Unknown monitor name: \"%s\"\n", name.c_str()); } else if (candidates.size() == 1) { // 確定した - Monitor& mon = *(candidates[0]); + Monitor *mon = candidates[0]; ShowMonitor(mon); } else { // 候補が複数あった @@ -2655,7 +2932,7 @@ Debugger::cmd_show() candstr += ' '; candstr += cname; } - fprintf(cons, "ambiguous monitor name \"%s\": candidates are%s\n", + fprintf(cons, "Ambiguous monitor name \"%s\". Candidates are:%s\n", name.c_str(), candstr.c_str()); } @@ -2664,15 +2941,15 @@ Debugger::cmd_show() // モニタを更新して表示。 void -Debugger::ShowMonitor(Monitor& monitor) +Debugger::ShowMonitor(Monitor *monitor) { // モニタを更新 TextScreen ts; - auto size = monitor.GetSize(); + auto size = monitor->GetSize(); ts.Init(size.width, size.height); - MONITOR_UPDATE(monitor, ts); + monitor->Update(ts); ShowTextScreen(ts); } @@ -2772,11 +3049,11 @@ Debugger::cmd_s_common(bool trace) { t_enable = trace ? curmd : NULL; - if (args.size() > 1) { + if (cmdargs.size() > 1) { int count; - count = strtol(args[1].c_str(), NULL, 10); + count = strtol(cmdargs[1].c_str(), NULL, 10); if (count < 1) { - fprintf(cons, " invalid step count: %d\n", count); + fprintf(cons, "Invalid step count: %d\n", count); return CmdAct::Stay; } @@ -2854,38 +3131,31 @@ Debugger::ParseVerbHex(const char *arg, bool Debugger::ParseAddr(const char *arg, uint32 *addrp) { - uint32 addr; + uint64 addr; char *end; if (arg[0] == '%') { // '%' から始まればレジスタ - uint64 r; - r = curmd->GetRegAddr(arg + 1); - if ((int64)r < 0) { -#if 0 // not yet - fprintf(cons, "valid register name are: %s%s\n", - "%d0-%d7,%a0-%a7,%sp,%usp,%isp,%pc", - ",%msp,%vbr,%srp,%crp"); -#endif - fprintf(cons, "invalid register name\n"); + addr = curmd->GetRegAddr(arg + 1); + if ((int64)addr < 0) { + fprintf(cons, "Invalid register name.\n"); return false; } - addr = (uint32)r; } else { /* そうでなければ番地指定 */ errno = 0; addr = strtoul(arg, &end, 16); - if (arg[0] == '\0' || end[0] != '\0') { - fprintf(cons, "invalid address: '%s'\n", arg); + if (end == arg || *end != '\0') { + fprintf(cons, "Invalid address: '%s'\n", arg); return false; } - if (errno == ERANGE) { - fprintf(cons, "out of range: %s\n", arg); + if (addr > 0xffffffff) { + fprintf(cons, "Out of range: %s\n", arg); return false; } } - *addrp = addr; + *addrp = (uint32)addr; return true; } @@ -2900,11 +3170,11 @@ Debugger::ParseTime(const char *arg, uin errno = 0; f = strtod(arg, &end); if (end == arg) { - fprintf(cons, "invalid time: %s\n", arg); + fprintf(cons, "Invalid time: %s\n", arg); return false; } if (errno == ERANGE || f < 0 || std::isinf(f) || std::isnan(f)) { - fprintf(cons, "out of range: %s\n", arg); + fprintf(cons, "Out of range: %s\n", arg); return false; } @@ -2919,7 +3189,7 @@ Debugger::ParseTime(const char *arg, uin } else if (strcmp(end, "sec") == 0 || strcmp(end, "_sec") == 0) { t = f * 1_sec; } else { - fprintf(cons, "unknown time suffix: %s\n", arg); + fprintf(cons, "Unknown time suffix: %s\n", end); return false; }