--- nono/debugger/debugger.cpp 2026/04/29 17:04:30 1.1.1.2 +++ nono/debugger/debugger.cpp 2026/04/29 17:04:33 1.1.1.3 @@ -1,6 +1,7 @@ // // nono -// Copyright (C) 2019 isaki@NetBSD.org +// Copyright (C) 2020 nono project +// Licensed under nono-license.txt // #include "console.h" @@ -8,11 +9,12 @@ #include "debugger_m680x0.h" #include "debugger_m88xx0.h" #include "mainapp.h" -#include "mpu.h" #include "mystring.h" +#include "mythread.h" +#include #include -Debugger *gDebugger; +static Debugger *gDebugger; CVPrompt *gCVPrompt; static void *debugger_run(void *); @@ -36,7 +38,7 @@ debugger_init() static void * debugger_run(void *dummy) { - pthread_setname_np("Debugger"); + PTHREAD_SETNAME("Debugger"); pthread_detach(pthread_self()); gDebugger->ThreadRun(); @@ -66,9 +68,9 @@ Debugger::Init() } // -b ならブレークポイント設定 - if (gMainApp.debug_breakaddr != 0xffffffff) { + for (auto& b : gMainApp.debug_breakaddr) { md->ReqSet(CPU_REQ_TRACE); - AddBreakpoint(gMainApp.debug_breakaddr, false); + AddBreakpoint(b, false); } // どこでやるべか @@ -86,47 +88,135 @@ Debugger::ThreadRun() cons = new ConsoleTCP(); } if (cons->Init() == false) { + delete cons; return; } for (;;) { - cons->Open(); + // 着信待ち + if (Accept() == false) { + break; + } + cons->InitEditLine("> "); - cons->Print("This is debugger console\n"); - // 接続ごとに初期化する値 - // XXX もうちょっときれいにしたい - d_last_addr = 0xffffffff; - m_last_addr = 0xffffffff; - n_enable = false; - s_enable = false; - t_enable = false; - is_continued = true; - - // コンソールが繋がっている間がトレースオン - // コンソールが繋がるとプロンプトになる - md->ReqSet(CPU_REQ_TRACE | CPU_REQ_PROMPT); - while (MainLoop() == true) - ; - // コンソールを抜ける時はCPUの停止を解除。 + // デバッガプロンプトにいる間はトレースオン + md->ReqSet(CPU_REQ_TRACE); + + bool first = true; + for (;;) { + // 接続後の1回目だけ実行するもの。 + if (first) { + first = false; + + // greeting はプロンプトが取れる前にもう表示したい。 + // 何らかの事故でプロンプトが取れなくても、ここまでは接続 + // できてることが分かるように。 + cons->Print("This is debugger console\n"); + + // 接続ごとに初期化する値 + // XXX もうちょっときれいにしたい + d_last_addr = 0xffffffff; + m_last_addr = 0xffffffff; + n_enable = false; + s_enable = false; + t_enable = false; + } + + // プロンプトが取れるのを待つ + if (AcquirePrompt() == false) { + break; + } + + // プロンプトに来た時に表示するいつものやつ + pc = md->GetPC(); + d_last_addr = pc; + cmd_minus(); + + // コマンド処理のメインループ + auto action = MainLoop(); + + // 次回との差分のため、今のレジスタセットをバックアップ + md->BackupRegs(); + + // メインループから戻ったということは Leave か Quit なので + // どちらにしても、ここでプロンプトを手放す。 + gCVPrompt->NotifyRelease(); + + // quit ならここでループを1段抜ける + if (action == CommandAction::Quit) { + break; + } + } + + // デバッガを抜けるのでトレースオフ md->ReqClr(CPU_REQ_TRACE); - gCVPrompt->NotifyRelease(); cons->Close(); + if (gMainApp.debug_on_console) { + break; + } } delete cons; } -// プロンプト処理のメイン部分。 -// false を返すとコンソールをクローズする。 +// コンソールに接続されるのを待つ。 +// うーん、なんだこれ。 +// +// +--- debug_on_console (-D オプション) +// | +- debug_on_start (-d オプション) +// | | 動作 +// 0 0 TCP、Accept で待機。 +// 0 1 TCP、Accpet で待機。 +// 1 0 stdio、起動時にプロンプトで止まらない -> キー入力待ち。 +// 1 1 stdio、起動時にプロンプトで止まる。 bool -Debugger::MainLoop() +Debugger::Accept() +{ + if (gMainApp.debug_on_console == false) { + // TCP なら accept が成功するのを待つ + cons->Accept(); + } else { + if (gMainApp.debug_on_start == false) { + // stdio、起動時にプロンプトで止まらない。 + // この場合キー入力かブレークポイントなどで止まった時点で + // プロンプトを出したいのでちょっと面倒なことに。 + for (;;) { + bool is_prompt = gCVPrompt->WaitAcquire(200); + if (is_prompt) { + break; + } + + int r = cons->Poll(200); + if (r < 0) { + cmd_q(); + return false; + } + if (r > 0) { + break; + } + } + } else { + // stdio、起動時にプロンプトで止まる。 + // この場合は無条件に成功でよい。 + } + } + + return true; +} + +// プロンプトが取れるのを待つ +// 失敗すれば false を返す +bool +Debugger::AcquirePrompt() { - // プロンプトが取れるのを待つ + md->ReqSet(CPU_REQ_PROMPT); + for (;;) { bool is_prompt = gCVPrompt->WaitAcquire(200); - if (is_prompt) break; + if (is_prompt) + break; // コンソールを定期観測して、入力があればブレーク要求 if (cons->Poll()) { @@ -139,47 +229,71 @@ Debugger::MainLoop() md->ReqSet(CPU_REQ_PROMPT); } } + return true; +} - // VM 実行からプロンプトに来たとき - if (is_continued) { - is_continued = false; - - pc = md->GetPC(); - d_last_addr = pc; - // プロンプトに来た時に表示するいつものやつ - cmd_minus(); - } - - cons->Prompt(); - if (cons->Gets(cmdbuf) == false) { - // EOF or Error - cmd_q(); - return false; - } - - string_rtrim(cmdbuf); - - if (!cmdbuf.empty()) { - // コマンドが入力されれば次回のために保存 - last_cmdbuf = cmdbuf; - } else { - // 空行が入力されれば直前のコマンドをもう一度 - // 前行がなければ何もせずもう一度プロンプトを表示するかね - if (last_cmdbuf.empty()) - return true; - cmdbuf = last_cmdbuf; - } +// コマンド処理のメインループ。 +// コマンドが Stay ならこの中で処理を継続。 +// コマンドが Leave か Quit ならその値を持って戻る (呼び出し側で処理する)。 +Debugger::CommandAction +Debugger::MainLoop() +{ + for (;;) { + cons->Prompt(); + if (cons->Gets(cmdbuf) == false) { + // EOF or Error + return CommandAction::Quit; + } - // 行を cmd, ac, av に分解 - cmddef_t *cmd = ParseCmd(); + string_rtrim(cmdbuf); - // 前回の値が有効なのはコマンドが連続した時だけ + if (!cmdbuf.empty()) { + // コマンドが入力されれば次回のために保存 + last_cmdbuf = cmdbuf; + } else { + // 空行が入力されれば直前のコマンドをもう一度 + // 前行がなければ何もせずもう一度プロンプトを表示するかね + if (last_cmdbuf.empty()) + continue; + cmdbuf = last_cmdbuf; + } + + // 行を args に分解 + ParseCmdbuf(); + + // 前回の値が有効なのはコマンドが連続した時だけ + + // コマンドをテーブルから探す + auto it = std::find_if(cmdtable.begin(), cmdtable.end(), + [=](auto x) { return strcmp(args[0].c_str(), x.name) == 0; }); + if (it != cmdtable.end()) { + auto cmd = *it; + + // 見付かれば実行 + (this->*(cmd.func))(); + + // Stay なら引き続きコマンド処理 + if (cmd.action == CommandAction::Stay) { + continue; + } + // それ以外ならメインループ終了 + return cmd.action; + } - // コマンド実行 - (this->*(cmd->func))(); + // (コマンドテーブルになくて) "r" から始まっていればレジスタ表示系 + if (args[0][0] == 'r') { + // ShowRegister() は処理したら true を返す。 + // "r" 系コマンドはすべて Stay。 + if (md->ShowRegister(cons, args)) { + continue; + } + } - // 終了コマンドによる終了処理 - return (cmd->func != &Debugger::cmd_q); + // 知らないコマンドも Stay 相当。 + cons->Print("%s: unknown command\n", args[0].c_str()); + continue; + } + __unreachable(); } // ブレークポイントとかを調べる。 @@ -218,17 +332,16 @@ Debugger::Check() } // アドレス - for (int i = 0; i < countof(bpoint); i++) { - breakpoint_t *bp = &bpoint[i]; - if (bp->enable) { - if (bp->ismemory) { - if (md->CheckLEA(bp->addr)) { - bp->count++; + for (auto& bp : bpoint) { + if (bp.enable) { + if (bp.ismemory) { + if (md->CheckLEA(bp.addr)) { + bp.count++; return true; } } else { - if (bp->addr == md->GetPC()) { - bp->count++; + if (bp.addr == md->GetPC()) { + bp.count++; return true; } } @@ -255,148 +368,113 @@ Debugger::Check() } // コマンド一覧。 -// quit コマンドによるメインループ終了は MainLoop() 側で処理してある。 -Debugger::cmddef_t Debugger::cmdtable[] = { - { "bx", &Debugger::cmd_bx, }, - { "b", &Debugger::cmd_b, }, - { "brhist", &Debugger::cmd_brhist }, - { "c", &Debugger::cmd_c, }, - { "d", &Debugger::cmd_d, }, - { "dt", &Debugger::cmd_dt, }, - { "D", &Debugger::cmd_D, }, - { "h", &Debugger::cmd_h, }, - { "L", &Debugger::cmd_L, }, - { "m", &Debugger::cmd_m, }, - { "mt", &Debugger::cmd_mt, }, - { "M", &Debugger::cmd_M, }, - { "n", &Debugger::cmd_n, }, - { "q", &Debugger::cmd_q, }, - { "quit", &Debugger::cmd_q, }, - { "r", &Debugger::cmd_r, }, - { "ra", &Debugger::cmd_ra, }, - { "rc", &Debugger::cmd_rc, }, - { "rf", &Debugger::cmd_rf, }, - { "rm", &Debugger::cmd_rm, }, - { "ro", &Debugger::cmd_ro, }, - { "s", &Debugger::cmd_s, }, - { "so", &Debugger::cmd_so, }, - { "show", &Debugger::cmd_show, }, - { "t", &Debugger::cmd_t, }, - { "-", &Debugger::cmd_minus }, -}; -Debugger::cmddef_t Debugger::cmdtable_unknown = { - .name = "", - .func = &Debugger::cmd_unknown, +// "r" から始まるレジスタ表示系コマンドはコード中で別処理してある。 +/*static*/ std::vector Debugger::cmdtable = { + { "bx", &Debugger::cmd_bx, Debugger::CommandAction::Stay }, + { "b", &Debugger::cmd_b, Debugger::CommandAction::Stay }, + { "brhist", &Debugger::cmd_brhist, Debugger::CommandAction::Stay }, + { "c", &Debugger::cmd_c, Debugger::CommandAction::Leave }, + { "d", &Debugger::cmd_d, Debugger::CommandAction::Stay }, + { "dt", &Debugger::cmd_dt, Debugger::CommandAction::Stay }, + { "D", &Debugger::cmd_D, Debugger::CommandAction::Stay }, + { "h", &Debugger::cmd_h, Debugger::CommandAction::Stay }, + { "help", &Debugger::cmd_h, Debugger::CommandAction::Stay }, + { "L", &Debugger::cmd_L, Debugger::CommandAction::Stay }, + { "m", &Debugger::cmd_m, Debugger::CommandAction::Stay }, + { "mt", &Debugger::cmd_mt, Debugger::CommandAction::Stay }, + { "M", &Debugger::cmd_M, Debugger::CommandAction::Stay }, + { "n", &Debugger::cmd_n, Debugger::CommandAction::Leave }, + { "q", &Debugger::cmd_q, Debugger::CommandAction::Quit }, + { "quit", &Debugger::cmd_q, Debugger::CommandAction::Quit }, + { "s", &Debugger::cmd_s, Debugger::CommandAction::Leave }, + { "so", &Debugger::cmd_so, Debugger::CommandAction::Leave }, + { "show", &Debugger::cmd_show, Debugger::CommandAction::Stay }, + { "t", &Debugger::cmd_t, Debugger::CommandAction::Leave }, + { "-", &Debugger::cmd_minus, Debugger::CommandAction::Stay }, }; // ヘルプ void Debugger::cmd_h() { - if (ac == 1) { - // 引数なし - HelpMain(); - return; - } else { - // 引数あり(今の所対応していない) - HelpMain(); - return; + if (args.size() > 1) { + if (args[1] == "r") { + Help(md->GetRegisterHelp()); + return; + } + } + // 引数なしか、あっても対応してないやつなら通常ヘルプを表示 + Help(HelpMsgMain); + return; +} + +/*static*/ const HelpMessages +Debugger::HelpMsgMain = { + { "b", "ブレークポイント一覧表示" }, + { "b #n", "ブレークポイント n を削除" }, + { "b $", "メモリブレークポイント設定" }, + { "b ", "ブレークポイント設定" }, + { "bx", "ブレークポイント全削除" }, + { "brhist []", "ブランチ履歴表示" }, + { "c []", "実行再開(continue)" }, + { "d [ []", "逆アセンブル(論理、テーブルサーチなし)" }, + { "dt [ []", "逆アセンブル(論理、テーブルサーチあり)" }, + { "D [ []", "逆アセンブル(物理)" }, + { "h", "ヘルプ(help)" }, + { "L =", "ログレベル設定" }, + { "m [ []", "メモリダンプ(論理、テーブルサーチなし)" }, + { "mt [ []", "メモリダンプ(論理、テーブルサーチあり)" }, + { "M [ []", "メモリダンプ(物理)" }, + { "n ", "ステップ実行 (サブルーチンを飛ばす)" }, + { "q", "quit" }, + { "r*", "各種レジスタを表示 (see \"help r\")" }, + { "so", "ステップアウト" }, + { "show ", "モニター表示" }, + { "t ", "トレース実行" }, +}; + +void +Debugger::Help(HelpMessages msgs) +{ + for (const auto& pair : msgs) { + cons->Print(" %-23s %s\n", pair.first.c_str(), pair.second.c_str()); } } +// cmdbuf を args... に分解する。 void -Debugger::HelpMain() +Debugger::ParseCmdbuf() { - cons->Print(" b ブレークポイント一覧表示\n"); - cons->Print(" b #n ブレークポイント n を削除\n"); - cons->Print(" b $ メモリブレークポイント設定\n"); - cons->Print(" b ブレークポイント設定\n"); - cons->Print(" bx ブレークポイント全削除\n"); - cons->Print(" brhist ブランチ履歴表示\n"); - cons->Print(" c [] 実行再開(continue)\n"); - cons->Print(" d [ [] 逆アセンブル(論理、テーブルサーチなし)\n"); - cons->Print(" dt [ [] 逆アセンブル(論理、テーブルサーチあり)\n"); - cons->Print(" D [ [] 逆アセンブル(物理)\n"); - cons->Print(" h ヘルプ(help)\n"); - cons->Print(" L = ログレベル設定\n"); - cons->Print(" m [ [] メモリダンプ(論理、テーブルサーチなし)\n"); - cons->Print(" mt [ [] メモリダンプ(論理、テーブルサーチあり)\n"); - cons->Print(" M [ [] メモリダンプ(物理)\n"); - cons->Print(" n ステップ実行 (サブルーチンを飛ばす)\n"); - cons->Print(" q quit\n"); - cons->Print(" r 通常レジスタを表示\n"); - cons->Print(" ra ATC を表示\n"); - cons->Print(" rc 制御レジスタを表示 (m88xx0)\n"); - cons->Print(" rf FPU レジスタを表示\n"); - cons->Print(" rm MMU レジスタを表示\n"); - cons->Print(" ro その他のレジスタを表示\n"); - cons->Print(" so ステップアウト\n"); - cons->Print(" show モニター表示\n"); - cons->Print(" t トレース実行\n"); -} - -// 知らないコマンドを処理するというコマンド -void -Debugger::cmd_unknown() -{ - cons->Print("%s: unknown command\n", av[0]); -} - -// cmdbuf を cmd, ac, av に分解する。 -// コマンド(の1ワード目)が一致しなければ cmd_unknown を返し、 -// 終了コマンドと一致したら NULL を返す。 -Debugger::cmddef_t * -Debugger::ParseCmd() -{ - char buf[cmdbuf.length() + 1]; - char *p; - cmddef_t *cmd; - - strcpy(buf, cmdbuf.c_str()); - p = buf; - ac = 0; - memset(&av, 0, sizeof(av)); + int pos; + int start; + + pos = 0; + args.clear(); // 引数を空白で分解 - for (; ac < countof(av); ) { - // 先頭の空白は取り除く - while (isspace((int)*p)) - p++; - if (*p == '\0') + for (;;) { + // 先頭の空白はスキップ + for (; cmdbuf[pos] != '\0'; pos++) { + if (!isspace((unsigned int)cmdbuf[pos])) + break; + } + if (cmdbuf[pos] == '\0') break; - av[ac++] = p; - // 次の空白まで進める - for (; *p != '\0'; p++) { - if (isspace((int)*p)) + // 終わりを探す + start = pos; + for (; cmdbuf[pos] != '\0'; pos++) { + if (isspace((unsigned int)cmdbuf[pos])) break; } - if (*p != '\0') - *p++ = '\0'; - } - // buf はスコープを抜けると無効なので、 - // コピーを取って挿げ替え - for (int i = 0; i < ac; i++) { - strav[i] = av[i]; - av[i] = strav[i].c_str(); + args.push_back(cmdbuf.substr(start, pos - start)); } // デバッグ表示 if (0) { - for (int i = 0; i < ac; i++) { - printf("av[%d]=|%s|\n", i, av[i]); + for (int i = 0 ; i < args.size(); i++) { + printf("args[%d]=|%s|\n", i, args[i].c_str()); } } - - // コマンドを探す - for (int i = 0; i < countof(cmdtable); i++) { - cmd = &cmdtable[i]; - - if (strcmp(av[0], cmd->name) == 0) - return cmd; - } - - // 見つからなければ cmd_unknown コマンドを実行。 - return &cmdtable_unknown; } // @@ -408,23 +486,23 @@ void Debugger::cmd_b() { // 引数なしなら一覧表示 - if (ac < 2) { + if (args.size() < 2) { return cmd_b_list(); } // 引数取得 - if (av[1][0] == '#') { + if (args[1][0] == '#') { // # 形式なら、指定番号のブレークポイントを削除 - int i = atoi(&av[1][1]); - if (i < 0 || i >= MAX_BREAKPOINTS) { + int i = atoi(&args[1][1]); + if (i < 0 || i >= bpoint.size()) { cons->Print("invaild break point number: #%d\n", i); return; } - breakpoint_t *bp = &bpoint[i]; - if (bp->enable) { + auto& bp = bpoint[i]; + if (bp.enable) { cons->Print("%sbreakpoint #%d (%08x) removed\n", - bp->ismemory ? "memory " : "", i, bp->addr); - bp->enable = false; + bp.ismemory ? "memory " : "", i, bp.addr); + bp.enable = false; } else { cons->Print("breakpoint #%d not enabled\n", i); } @@ -433,23 +511,27 @@ Debugger::cmd_b() bool ismemory; uint32 addr; - if (av[1][0] == '$') { + bool rv; + if (args[1][0] == '$') { // $ 形式ならメモリブレークポイント ismemory = true; - addr = strtoul(&av[1][1], NULL, 16); + rv = ParseAddr(&args[1][1], &addr); } else { // そうでなければアドレス指定 ismemory = false; - addr = strtoul(av[1], NULL, 16); + rv = ParseAddr(&args[1][0], &addr); + } + if (rv == false) { + return; } // すでにあればそのブレークポイントを削除 - for (int i = 0; i < MAX_BREAKPOINTS; i++) { - breakpoint_t *bp = &bpoint[i]; - if (bp->enable && bp->ismemory == ismemory && bp->addr == addr) { - bp->enable = false; + for (int i = 0; i < bpoint.size(); i++) { + auto& bp = bpoint[i]; + if (bp.enable && bp.ismemory == ismemory && bp.addr == addr) { + bp.enable = false; cons->Print("%sbreakpoint #%d (%08x) removed\n", - bp->ismemory ? "memory " : "", i, bp->addr); + bp.ismemory ? "memory " : "", i, bp.addr); return; } } @@ -459,9 +541,9 @@ Debugger::cmd_b() if (bi == -1) { cons->Print("no free breakpoints!\n"); } else { - breakpoint_t *bp = &bpoint[bi]; + auto& bp = bpoint[bi]; cons->Print("%sbreakpoint #%d (%08x) added\n", - bp->ismemory ? "memory " : "", bi, bp->addr); + bp.ismemory ? "memory " : "", bi, bp.addr); } } @@ -471,13 +553,13 @@ Debugger::cmd_b_list() { int found = 0; - for (int i = 0; i < MAX_BREAKPOINTS; i++) { - breakpoint_t *bp = &bpoint[i]; - if (bp->enable) { + for (int i = 0; i < bpoint.size(); i++) { + auto& bp = bpoint[i]; + if (bp.enable) { cons->Print(" #%d %s%08x %d\n", i, - bp->ismemory ? "memory $" : "", - bp->addr, bp->count); + bp.ismemory ? "memory $" : "", + bp.addr, bp.count); found = 1; } } @@ -490,9 +572,8 @@ Debugger::cmd_b_list() void Debugger::cmd_bx() { - for (int i = 0; i < MAX_BREAKPOINTS; i++) { - breakpoint_t *bp = &bpoint[i]; - bp->enable = false; + for (auto& bp : bpoint) { + bp.enable = false; } cons->Print(" All breakpoints disabled\n"); } @@ -503,13 +584,13 @@ Debugger::cmd_bx() int Debugger::AddBreakpoint(uint32 addr, bool ismemory) { - for (int i = 0; i < countof(bpoint); i++) { - breakpoint_t *bp = &bpoint[i]; - if (!bp->enable) { - bp->enable = true; - bp->addr = addr; - bp->ismemory = ismemory; - bp->count = 0; + for (int i = 0; i < bpoint.size(); i++) { + auto& bp = bpoint[i]; + if (!bp.enable) { + bp.enable = true; + bp.addr = addr; + bp.ismemory = ismemory; + bp.count = 0; return i; } } @@ -520,8 +601,28 @@ Debugger::AddBreakpoint(uint32 addr, boo void Debugger::cmd_brhist() { - gMPUBrHist->MonitorUpdate(); - ShowMonitor(gMPUBrHist->monitor); + int n = 20; + + if (args.size() > 1) { + n = atoi(args[1].c_str()); + if (n <= 0) n = 1; + if (n > 255) n = 256; + } + // コンソールでは古い順に表示。最下行が最新。 + auto& bh = (BranchHistory&)md->GetBrHist(); + uint8 t = bh.top; + + t = t - n; + for (int i = 0; i < n; i++) { + auto& e = bh.entry[++t]; + if (e.count == 0) continue; + cons->Print("%03d:%08x->%08x", n - i - 1, e.from, e.to); + if (e.count > 1) { + cons->Print(" x %u\n", e.count); + } else { + cons->Print("\n"); + } + } } // 実行再開(continue): c [] @@ -529,9 +630,9 @@ Debugger::cmd_brhist() void Debugger::cmd_c() { - if (ac > 1) { + if (args.size() > 1) { // 引数があれば - if (!ParseAddr(av[1], &bc_addr)) { + if (!ParseAddr(args[1].c_str(), &bc_addr)) { return; } // 偶数番地に丸める @@ -539,31 +640,18 @@ Debugger::cmd_c() bc_enable = true; } - Continue(); -} - -// 実行再開 -void -Debugger::Continue() -{ - is_continued = true; - - // 今のレジスタセットを次回との差分のためにバックアップしておく - md->BackupRegs(); - - gCVPrompt->NotifyRelease(); } // 引数などからアドレスを取得する共通ルーチン。 -// 引数が1つ(以上)あれば av[1] をアドレスとしてパースする。 +// 引数が1つ(以上)あれば args[1] をアドレスとしてパースする。 // なければ、lastaddr が指定されていればそれを使う。 // それもなければ現在の PC を使う。 bool Debugger::GetAddr(uint32& addr, uint32& lastaddr) { - if (ac > 1) { + if (args.size() > 1) { // 1つ目の引数があれば、開始アドレス - if (ParseAddr(av[1], &addr) == false) { + if (ParseAddr(args[1].c_str(), &addr) == false) { return false; } // 偶数番地からに丸める @@ -614,8 +702,8 @@ Debugger::cmd_d_common(MemdumpMode mode) return; } // 2つ目の引数があれば行数 - if (ac > 2) { - cnt = strtol(av[2], NULL, 10); + if (args.size() > 2) { + cnt = strtol(args[2].c_str(), NULL, 10); } saddr.addr = addr; @@ -659,13 +747,13 @@ Debugger::cmd_L() const char *name; int level; - if (ac < 3) { + if (args.size() < 3) { cons->Print("L \n"); return; } - name = av[1]; - level = atoi(av[2]); + name = args[1].c_str(); + level = atoi(args[2].c_str()); // 短縮形とかエイリアスとか // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい @@ -674,6 +762,7 @@ Debugger::cmd_L() if (strcmp(name, "scc") == 0) name = "sio"; + // 複数のオブジェクトが同じ logname を持ってもよい (CMMUとか)。 // all はどうするか std::string sname = name; bool found = false; @@ -682,7 +771,6 @@ Debugger::cmd_L() obj->loglevel = level; cons->Print("%s=%d\n", name, obj->loglevel); found = true; - break; } } // 見付からない場合はエラー @@ -727,8 +815,8 @@ Debugger::cmd_m_common(MemdumpMode mode) return; } // 2つ目の引数があれば行数 - if (ac > 2) { - cnt = strtol(av[2], NULL, 10); + if (args.size() > 2) { + cnt = strtol(args[2].c_str(), NULL, 10); } saddr.addr = addr; @@ -794,7 +882,9 @@ Debugger::cmd_m_common(MemdumpMode mode) void Debugger::cmd_minus() { - cmd_r(); + // 通常レジスタを表示 + std::vector tmpargs {{ "r" }}; + md->ShowRegister(cons, tmpargs); // 論理アクセス時、ATC ミスが分かったほうが便利だと思う saddr_t laddr; @@ -824,9 +914,9 @@ Debugger::cmd_minus() void Debugger::cmd_n() { - if (ac > 1) { + if (args.size() > 1) { int count; - count = strtol(av[1], NULL, 10); + count = strtol(args[1].c_str(), NULL, 10); if (count < 1) { cons->Print(" invalid step count: %d\n", count); return; @@ -838,7 +928,6 @@ Debugger::cmd_n() } n_enable = true; SetNBreakpoint(); - Continue(); } // n コマンド用のサブルーチンを飛ばすブレークポイントを設定。 @@ -898,76 +987,13 @@ void Debugger::cmd_q() { cons->Print("quit debugger console.\n"); - - // XXX: このフラグでいいのかとか exit でいいのかとか - if (gMainApp.debug_on_console) { - // コンソールモードのときはプログラムも終了 - exit(0); - } -} - -// レジスタ表示 -// rf: FPU レジスタを表示 -// rm: MMU レジスタを表示 -// r<それ以外>: 通常レジスタを表示? -void -Debugger::cmd_r() -{ - if (ac > 1) { - int arg = av[1][0]; - switch (arg) { - case 'a': - ShowMonitor(gMPUATC->monitor); - return; - case 'c': - md->ShowRegCtrl(cons); - return; - case 'f': - md->ShowRegFPU(cons); - return; - case 'm': - md->ShowRegMMU(cons); - return; - case 'o': - md->ShowRegOther(cons); - return; - } - } - md->ShowRegMain(cons); -} - -// ショートカット -void -Debugger::cmd_ra() -{ - md->ShowRegATC(cons); -} -void -Debugger::cmd_rc() -{ - md->ShowRegCtrl(cons); -} -void -Debugger::cmd_rf() -{ - md->ShowRegFPU(cons); -} -void -Debugger::cmd_rm() -{ - md->ShowRegMMU(cons); -} -void -Debugger::cmd_ro() -{ - md->ShowRegOther(cons); } // モニター表示 void Debugger::cmd_show() { - if (ac != 2) { + if (args.size() != 2) { cons->Print("usage: show \n"); for (auto& d : gObjects) { if (d->logname != "?") { @@ -977,17 +1003,10 @@ Debugger::cmd_show() return; } - std::string name(av[1]); + std::string name = args[1]; for (auto& d : gObjects) { if (d->logname == name) { - // ここで更新して.. - if (d->MonitorUpdate()) { - // 表示 - ShowMonitor(d->monitor); - } else { - // モニターがない場合 - cons->Print("show: %s has no monitor\n", av[1]); - } + ShowMonitor(*d); return; } } @@ -995,9 +1014,21 @@ Debugger::cmd_show() cons->Print("show: no such objects\n"); } -// モニタースクリーンを表示。 +// モニターを更新して表示。 +void +Debugger::ShowMonitor(Object& obj) +{ + // モニタを更新 + if (obj.MonitorUpdate() == false) { + cons->Print("show: no monitor\n"); + return; + } + ShowTextScreen(obj.monitor); +} + +// テキストスクリーンを表示。 void -Debugger::ShowMonitor(TextScreen& monitor) +Debugger::ShowTextScreen(TextScreen& monitor) { char sbuf[1024]; // 適当 @@ -1052,6 +1083,12 @@ Debugger::ShowMonitor(TextScreen& monito } *d++ = ch; } + // 行の終わりで一旦属性を戻しておく + if (attr != TA::Normal) { + *d++ = 0x1b; + *d++ = '['; + *d++ = 'm'; + } *d = '\0'; // XXX 日本語が使われてれば UTF-8 にしないといけないはず @@ -1064,9 +1101,9 @@ Debugger::ShowMonitor(TextScreen& monito void Debugger::cmd_s() { - if (ac > 1) { + if (args.size() > 1) { int count; - count = strtol(av[1], NULL, 10); + count = strtol(args[1].c_str(), NULL, 10); if (count < 1) { cons->Print(" invalid step count: %d\n", count); return; @@ -1077,7 +1114,6 @@ Debugger::cmd_s() s_count = 1; } s_enable = true; - Continue(); } // ステップアウト @@ -1086,7 +1122,6 @@ Debugger::cmd_so() { so_enable = true; md->SetStepOut(); - Continue(); } // トレース実行: t[?:1] @@ -1094,9 +1129,9 @@ Debugger::cmd_so() void Debugger::cmd_t() { - if (ac > 1) { + if (args.size() > 1) { int count; - count = strtol(av[1], NULL, 10); + count = strtol(args[1].c_str(), NULL, 10); if (count < 1) { cons->Print(" invalid trace count: %d\n", count); return; @@ -1106,7 +1141,6 @@ Debugger::cmd_t() t_count = 1; } t_enable = true; - Continue(); } // 引数で示されるアドレスを返す。