--- nono/debugger/debugger.cpp 2026/04/29 17:04:51 1.1.1.8 +++ nono/debugger/debugger.cpp 2026/04/29 17:04:56 1.1.1.10 @@ -9,28 +9,32 @@ #include "debugger_m680x0.h" #include "debugger_m88xx0.h" #include "mainapp.h" +#include "mystring.h" #include "mythread.h" #include "scheduler.h" #include #include static Debugger *gDebugger; -BreakpointMonitor *gBreakpointMonitor; CVPrompt *gCVPrompt; static void *debugger_run(void *); -// 初期化。 +// 作成 (MainApp::Init1 から呼ばれる) +void +debugger_create() +{ + gDebugger = new Debugger(); + gCVPrompt = new CVPrompt(); +} + +// 初期化 (MainApp::Init2 から呼ばれる) // この時点で VM が初期化されていること。 void debugger_init() { - gDebugger = new Debugger(); gDebugger->Init(); - gBreakpointMonitor = new BreakpointMonitor(); - gCVPrompt = new CVPrompt(); - // デバッガスレッド起動 pthread_t th; pthread_create(&th, NULL, debugger_run, NULL); @@ -47,8 +51,17 @@ debugger_run(void *dummy) return NULL; } +// メモリダンプモニタを外部から取得 +Monitor& +debugger_memdump_monitor(int n) +{ + assert(n < MAX_MEMDUMP_MONITOR); + return gDebugger->memdump_monitor[n]; +} + // コンストラクタ Debugger::Debugger() + : inherited("Debugger") { if (gMPU680x0) { md = new DebuggerMD_m680x0(this, gMPU680x0->GetCPU()); @@ -57,6 +70,23 @@ Debugger::Debugger() } else { throw "unknown mpu"; } + + // ブレークポイントモニター + bpoint_monitor.func = (MonitorCallback_t)&Debugger::MonitorUpdateBpoint; + bpoint_monitor.SetSize(55, 9); + bpoint_monitor.Regist(ID_MONITOR_BREAKPOINT); + + // メモリダンプモニター + for (int i = 0, end = memdump_monitor.size(); i < end; i++) { + auto& mon = memdump_monitor[i]; + mon.obj = this; + mon.func = (MonitorCallback_t)&Debugger::MonitorUpdateMemdump; + mon.SetSize(76, 16); + mon.Regist(ID_MONITOR_MEMDUMP(i)); + } + // m/M コマンド用。こっちは Regist 不要 + m_monitor.func = (MonitorCallback_t)&Debugger::MonitorUpdateMemdump; + m_monitor.SetSize(76, 16); } // コマンドライン引数によって動作を決めるところ。 @@ -917,7 +947,7 @@ Debugger::HelpDetails = { //----- { "L", R"**( - Command: L + Command: L [=][,=[]]... Set loglevel. XXX To be written... )**" }, @@ -1064,21 +1094,7 @@ Debugger::cmd_b() // 引数取得 if (args[1][0] == '#') { // # 形式なら、指定番号のブレークポイントを削除 - int i = atoi(&args[1][1]); - if (i < 0 || i >= bpoint.size()) { - cons->Print("invaild breakpoint number: #%d\n", i); - return; - } - auto& bp = bpoint[i]; - if (bp.type == BreakpointType::Unused) { - cons->Print("invalid breakpoint number: #%d\n", i); - return; - } - cons->Print("breakpoint #%d (%08x) removed\n", - i, bp.addr); - bp.type = BreakpointType::Unused; - // 今登録されている命令ブレークの必要命令長を再計算 - RecalcInstMask(); + cmd_b_delete(); return; } @@ -1129,6 +1145,30 @@ Debugger::cmd_b_set(BreakpointType type) } } +// ブレークポイント個別削除 +// (引数の先頭が '#' なことを判定したところで呼ばれる) +// b # +void +Debugger::cmd_b_delete() +{ + int n = atoi(&args[1][1]); + if (n < 0 || n >= bpoint.size()) { + cons->Print("invalid breakpoint number: #%d\n", n); + return; + } + + auto& bp = bpoint[n]; + if (bp.type == BreakpointType::Unused) { + cons->Print("invalid breakpoint number: #%d\n", n); + return; + } + + cons->Print("breakpoint #%d removed\n", n); + bp.type = BreakpointType::Unused; + // 今登録されている命令ブレークの必要命令長を再計算 + RecalcInstMask(); +} + // 命令ブレークポイントの設定 // bi [:] [] void @@ -1294,12 +1334,12 @@ Debugger::cmd_bv() void Debugger::cmd_b_list() { - ShowMonitor(*gBreakpointMonitor); + ShowMonitor(bpoint_monitor); } // ブレークポイント一覧 (モニタ) void -Debugger::MonitorBreakpoint(TextScreen& monitor) +Debugger::MonitorUpdateBpoint(Monitor *, TextScreen& monitor) { // 0 1 2 3 4 5 6 // 0123456789012345678901234567890123456789012345678901234567890 @@ -1457,17 +1497,17 @@ Debugger::RecalcInstMask() void Debugger::cmd_brhist() { - cmd_hist_common(md->GetBrHist(), 0); + cmd_hist_common(md->GetBrHist()); } void Debugger::cmd_exhist() { - cmd_hist_common(md->GetExHist(), BranchHistory::ExHist); + cmd_hist_common(md->GetExHist()); } // ブランチ履歴、例外履歴表示の共通部分。 void -Debugger::cmd_hist_common(BranchHistory& hist, uint64 flag) +Debugger::cmd_hist_common(BranchHistory& hist) { // 表示最大行数(と向き) // 向きは bottom_to_top = true が新しいほうを下とする方向。 @@ -1494,19 +1534,19 @@ Debugger::cmd_hist_common(BranchHistory& int lines = std::min(used, maxlines) + 1; // MonitorUpdate() は TextScreen 高さに合わせて出力してくれる。 - auto size = hist.GetMonitorSize(); - TextScreen tscr; - tscr.Init(size.width, lines); + auto& histmon = hist.monitor; + auto size = histmon.GetSize(); + TextScreen screen; + screen.Init(size.width, lines); // コンソールでは下が新しいの順のほうがいい if (bottom_to_top) { - flag |= BranchHistory::BottomToTop; + screen.userdata |= BranchHistory::BottomToTop; } - tscr.userdata = flag; // 表示 - hist.MonitorUpdate(tscr); - ShowTextScreen(tscr); + MONITOR_UPDATE(histmon, screen); + ShowTextScreen(screen); } // 実行再開(continue): c [] @@ -1764,42 +1804,45 @@ Debugger::cmd_disp() // XXX チェック } -// ログレベル設定: L +// ログレベル設定: L [=][...] void Debugger::cmd_L() { - const char *name; - int level; - - if (args.size() < 3) { - cons->Print("L \n"); + if (args.size() < 2) { + cons->Print("L [=][,[=]]...\n"); return; } - name = args[1].c_str(); - level = atoi(args[2].c_str()); - - // 短縮形とかエイリアスとか - // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい - if (strcmp(name, "sch") == 0) - name = "scheduler"; - if (strcmp(name, "scc") == 0) - name = "sio"; - - // 複数のオブジェクトが同じ logname を持ってもよい (CMMUとか)。 - // all はどうするか - std::string sname = name; - bool found = false; - for (auto& obj : gObjects) { - if (obj->logname == sname) { - obj->loglevel = level; - cons->Print("%s=%d\n", name, obj->loglevel); - found = true; - } - } - // 見付からない場合はエラー - if (!found) { - cons->Print("%s: invalid logname\n", name); + // 一旦全部つなげる。 + // help が混ざる場合の "L foo=1,help" と "L foo=1 help" を同じ動作に + // するため。 + std::string str; + for (int i = 1, ac = args.size(); i < ac; i++) { + if (str.empty() == false) { + str += ','; + } + str += args[i]; + } + + // で、再分解 + std::vector items = string_split(str, ','); + + // "help" があれば一覧を表示 + for (const auto& item : items) { + if (item == "help") { + std::vector list = MainApp::GetLogNames(); + for (const auto& name : list) { + cons->Print(" %s\n", name.c_str()); + } + return; + } + } + + // ログレベルを設定 + std::string errmsg; + if (MainApp::SetLogopt(items, &errmsg) == false) { + cons->Print("%s\n", errmsg.c_str()); + return; } } @@ -1829,9 +1872,9 @@ void Debugger::cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode) { saddr_t saddr; - int cnt; + int row; - cnt = 10; + row = 8; // 開始アドレス saddr = m_last_addr; @@ -1840,20 +1883,76 @@ Debugger::cmd_m_common(MemoryMode access } // 2つ目の引数があれば行数 if (args.size() > 2) { - cnt = strtol(args[2].c_str(), NULL, 10); + row = strtol(args[2].c_str(), NULL, 10); + } + + // userdata を作成 + uint64 userdata = saddr.GetAddr(); + if (saddr.IsSuper() == false) { + userdata |= (1ULL << 32); } + if (saddr.IsData()) { + userdata |= (1ULL << 33); + } + if (access_mode == MemoryMode::Logical) { + userdata |= (1ULL << 34); + } + if (lookup_mode == MMULookupMode::True) { + userdata |= (1ULL << 35); + } + // CLI では毎回次を表示していってほしい + userdata |= (1ULL << 36); + TextScreen screen; + screen.Init(m_monitor.GetSize().width, row); + screen.userdata = userdata; + + MONITOR_UPDATE(m_monitor, screen); + ShowTextScreen(screen); + + // アドレスを次回継続用に保存 (Super/Data は維持) + m_last_addr = (uint32)screen.userdata; +} + +// メモリダンプモニタ +// +// userdata の下位32bit はアドレス。上位は各種フラグ。 +// +// ..| b36 | b35 | b34 | b33 | b32 | b31 .. b0 +// userdata | A | T | L | D | U | address +// | | | | +---- 1:User 0:Supervisor space +// | | | +---------- 1:Data, 0:Instruction space +// | | +---------------- 1:Logical, 0:Physical +// | +---------------------- 1:Table Lookup, 0:ATC Only +// +---------------------------- 1:Auto increment mode +void +Debugger::MonitorUpdateMemdump(Monitor *, TextScreen& screen) +{ + uint32 laddr = (uint32)screen.userdata; + bool user = (screen.userdata >> 32) & 1; + bool data = (screen.userdata >> 33) & 1; + MemoryMode access_mode = ((screen.userdata >> 34) & 1) + ? MemoryMode::Logical : MemoryMode::Physical; + MMULookupMode lookup_mode = ((screen.userdata >> 35) & 1) + ? MMULookupMode::True : MMULookupMode::None; + bool autoinc = ((screen.userdata >> 36) & 1); + + saddr_t saddr(laddr, !user, data); DebuggerMemoryStream mem(md, saddr, access_mode, lookup_mode); - for (int i = 0; i < cnt; i++) { + screen.Clear(); + + int row = screen.GetRow(); + for (int y = 0; y < row; y++) { std::string addrbuf; std::string dumpbuf; std::string charbuf; // アドレス - if (mem.FormatAddr(addrbuf) == false) { + bool ok = mem.FormatAddr(addrbuf); + screen.Print(0, y, "%s", addrbuf.c_str()); + if (ok == false) { // アドレス変換でバスエラーならここで終了 - cons->Print("%s\n", addrbuf.c_str()); break; } @@ -1863,7 +1962,7 @@ Debugger::cmd_m_common(MemoryMode access if ((int64)b < 0) { dumpbuf += "--"; - charbuf += " "; + charbuf += ' '; } else { uint32 c = (uint32)b; dumpbuf += string_format("%02x", c); @@ -1871,15 +1970,20 @@ Debugger::cmd_m_common(MemoryMode access (0x20 <= c && c <= 0x7e) ? c : '.'); } } - dumpbuf += " "; + dumpbuf += ' '; } - cons->Print("%-18s %-40s %s\n", - addrbuf.c_str(), dumpbuf.c_str(), charbuf.c_str()); + screen.Print(19, y, "%s", dumpbuf.c_str()); + screen.Print(60, y, "%s", charbuf.c_str()); } - // アドレスと Super/User 状態を次回継続用に保存 - m_last_addr = mem.laddr; + // 次回継続用に書き戻す + if (autoinc) { + union64 udata; + udata.q = screen.userdata; + udata.l = mem.laddr.GetAddr(); + screen.userdata = udata.q; + } } // プロンプトに来た最初に表示するいつものやつを再表示する @@ -2006,37 +2110,78 @@ void Debugger::cmd_show() { if (args.size() != 2) { - cons->Print("usage: show \n"); - for (auto& d : gObjects) { - if (d->logname != "?") { - cons->Print(" %s\n", d->logname.c_str()); + std::vector list; + + // 登録されているモニターだけを列挙 + // (登録されていてもサブウィンドウの ID を持っているものは除外) + for (const auto mon : gMonitorManager.GetList()) { + int id = mon->GetId(); + if (id <= ID_MONITOR_END) { + list.push_back(id); } } + + // 一覧を表示 + std::string msg = MonitorManager::MakeListString(list); + cons->Print("usage: show \n"); + cons->Print("%s", msg.c_str()); return; } + std::vector candidates; + std::vector cand_names; std::string name = args[1]; - for (auto& d : gObjects) { - if (d->logname == name) { - ShowMonitor(*d); - return; + + for (auto mon : gMonitorManager.GetList()) { + int id = mon->GetId(); + const auto& aliases = gMonitorManager.GetAliases(id); + + bool matched = false; + for (const auto& alias : aliases) { + // 部分一致したら名前はすべて覚えておく + if (starts_with_ignorecase(alias, name)) { + cand_names.push_back(alias); + matched = true; + } + } + + // 同じモニタで別名が複数回部分一致しても、 + // モニタのほうは1回として数える + if (matched) { + candidates.push_back(mon); } } - // 一致しない - cons->Print("show: no such objects\n"); + + if (candidates.empty()) { + // 一致しない + cons->Print("unknown monitor name: \"%s\"\n", name.c_str()); + } else if (candidates.size() == 1) { + // 確定した + Monitor& mon = *(candidates[0]); + ShowMonitor(mon); + } else { + // 候補が複数あった + std::string candstr; + for (const auto& cname : cand_names) { + candstr += ' '; + candstr += cname; + } + cons->Print("ambiguous monitor name \"%s\": candidates are%s\n", + name.c_str(), candstr.c_str()); + } } // モニターを更新して表示。 void -Debugger::ShowMonitor(IMonitor& monitor) +Debugger::ShowMonitor(Monitor& monitor) { // モニタを更新 TextScreen ts; - auto size = monitor.GetMonitorSize(); + auto size = monitor.GetSize(); ts.Init(size.width, size.height); - monitor.MonitorUpdate(ts); + MONITOR_UPDATE(monitor, ts); ShowTextScreen(ts); } @@ -2253,20 +2398,3 @@ Debugger::ParseAddr(const char *arg, uin DebuggerMD::~DebuggerMD() { } - - -// -// ブレークポイントモニター -// - -// コンストラクタ -BreakpointMonitor::BreakpointMonitor() -{ - monitor_size = nnSize(55, 9); -} - -void -BreakpointMonitor::MonitorUpdate(TextScreen& monitor) -{ - gDebugger->MonitorBreakpoint(monitor); -}