|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2019 [email protected]
4: //
5:
1.1.1.2 ! root 6: #include "console.h"
! 7: #include "debugger_private.h"
! 8: #include "debugger_m680x0.h"
! 9: #include "debugger_m88xx0.h"
! 10: #include "mainapp.h"
1.1 root 11: #include "mpu.h"
12: #include "mystring.h"
13: #include <csignal>
14:
15: Debugger *gDebugger;
16: CVPrompt *gCVPrompt;
17:
18: static void *debugger_run(void *);
19:
20: // 初期化。
21: // この時点で VM が初期化されていること。
22: void
23: debugger_init()
24: {
25: gDebugger = new Debugger();
26: gDebugger->Init();
27:
28: gCVPrompt = new CVPrompt();
29:
30: // デバッガスレッド起動
31: pthread_t th;
32: pthread_create(&th, NULL, debugger_run, NULL);
33: }
34:
35: // デバッガスレッドのエントリポイント
36: static void *
37: debugger_run(void *dummy)
38: {
39: pthread_setname_np("Debugger");
40: pthread_detach(pthread_self());
41:
42: gDebugger->ThreadRun();
43: return NULL;
44: }
45:
46: // コンストラクタ
47: Debugger::Debugger()
48: {
1.1.1.2 ! root 49: if (gMPU680x0) {
! 50: md = new DebuggerMD_m680x0(this, gMPU680x0->GetCPU());
! 51: } else if (gMPU88xx0) {
! 52: md = new DebuggerMD_m88xx0(this, gMPU88xx0->GetCPU());
! 53: } else {
! 54: throw "unknown mpu";
! 55: }
1.1 root 56: }
57:
58: // コマンドライン引数によって動作を決めるところ。
59: // 名前がこれでいいのかはあるけど。
60: void
61: Debugger::Init()
62: {
63: // -d なら CPU 起動時点で停止してプロンプトを待つ
1.1.1.2 ! root 64: if (gMainApp.debug_on_start) {
! 65: md->ReqSet(CPU_REQ_PROMPT);
1.1 root 66: }
67:
68: // -b <addr> ならブレークポイント設定
1.1.1.2 ! root 69: if (gMainApp.debug_breakaddr != 0xffffffff) {
! 70: md->ReqSet(CPU_REQ_TRACE);
! 71: AddBreakpoint(gMainApp.debug_breakaddr, false);
1.1 root 72: }
73:
74: // どこでやるべか
75: signal(SIGPIPE, SIG_IGN);
76: }
77:
78: // デバッガスレッド
79: void
80: Debugger::ThreadRun()
81: {
82: // XXX どこかでコンソールの選択とパラメータの取得
1.1.1.2 ! root 83: if (gMainApp.debug_on_console) {
! 84: cons = new ConsoleStdio();
! 85: } else {
! 86: cons = new ConsoleTCP();
! 87: }
1.1 root 88: if (cons->Init() == false) {
89: return;
90: }
91:
92: for (;;) {
93: cons->Open();
1.1.1.2 ! root 94: cons->InitEditLine("> ");
1.1 root 95: cons->Print("This is debugger console\n");
96:
97: // 接続ごとに初期化する値
98: // XXX もうちょっときれいにしたい
99: d_last_addr = 0xffffffff;
100: m_last_addr = 0xffffffff;
101: n_enable = false;
102: s_enable = false;
103: t_enable = false;
104: is_continued = true;
105:
106: // コンソールが繋がっている間がトレースオン
107: // コンソールが繋がるとプロンプトになる
1.1.1.2 ! root 108: md->ReqSet(CPU_REQ_TRACE | CPU_REQ_PROMPT);
1.1 root 109: while (MainLoop() == true)
110: ;
111: // コンソールを抜ける時はCPUの停止を解除。
1.1.1.2 ! root 112: md->ReqClr(CPU_REQ_TRACE);
1.1 root 113: gCVPrompt->NotifyRelease();
114:
115: cons->Close();
116: }
117:
118: delete cons;
119: }
120:
121: // プロンプト処理のメイン部分。
122: // false を返すとコンソールをクローズする。
123: bool
124: Debugger::MainLoop()
125: {
126: // プロンプトが取れるのを待つ
1.1.1.2 ! root 127: for (;;) {
! 128: bool is_prompt = gCVPrompt->WaitAcquire(200);
! 129: if (is_prompt) break;
! 130:
! 131: // コンソールを定期観測して、入力があればブレーク要求
! 132: if (cons->Poll()) {
! 133: // この入力は drop してみる
! 134: if (cons->Gets(cmdbuf) == false) {
! 135: // EOF or Error
! 136: cmd_q();
! 137: return false;
! 138: }
! 139: md->ReqSet(CPU_REQ_PROMPT);
! 140: }
! 141: }
1.1 root 142:
143: // VM 実行からプロンプトに来たとき
144: if (is_continued) {
145: is_continued = false;
146:
1.1.1.2 ! root 147: pc = md->GetPC();
1.1 root 148: d_last_addr = pc;
149: // プロンプトに来た時に表示するいつものやつ
150: cmd_minus();
151: }
152:
1.1.1.2 ! root 153: cons->Prompt();
! 154: if (cons->Gets(cmdbuf) == false) {
! 155: // EOF or Error
! 156: cmd_q();
1.1 root 157: return false;
158: }
159:
1.1.1.2 ! root 160: string_rtrim(cmdbuf);
1.1 root 161:
1.1.1.2 ! root 162: if (!cmdbuf.empty()) {
1.1 root 163: // コマンドが入力されれば次回のために保存
1.1.1.2 ! root 164: last_cmdbuf = cmdbuf;
1.1 root 165: } else {
166: // 空行が入力されれば直前のコマンドをもう一度
167: // 前行がなければ何もせずもう一度プロンプトを表示するかね
1.1.1.2 ! root 168: if (last_cmdbuf.empty())
1.1 root 169: return true;
1.1.1.2 ! root 170: cmdbuf = last_cmdbuf;
1.1 root 171: }
172:
173: // 行を cmd, ac, av に分解
174: cmddef_t *cmd = ParseCmd();
175:
176: // 前回の値が有効なのはコマンドが連続した時だけ
177:
178: // コマンド実行
179: (this->*(cmd->func))();
1.1.1.2 ! root 180:
! 181: // 終了コマンドによる終了処理
! 182: return (cmd->func != &Debugger::cmd_q);
1.1 root 183: }
184:
185: // ブレークポイントとかを調べる。
186: // CPU_REQ_TRACE フラグが立っている間1命令ごとに呼び出される。
187: bool
188: debugger_check()
189: {
190: return gDebugger->Check();
191: }
192:
193: // デバッガ実行中なら命令開始前にメインルーチンから呼ばれる。
194: // プロンプトに降りるなら true を返す。
195: bool
196: Debugger::Check()
197: {
198: if (t_enable) {
199: t_count--;
200: if (t_count == 0) {
201: t_enable = false;
202: return true;
203: }
204: }
205:
206: if (s_enable) {
207: s_count--;
208: if (s_count == 0) {
209: s_enable = false;
210: return true;
211: }
212: }
213:
214: // n による1命令実行のブレークポイントか
1.1.1.2 ! root 215: if (n_enable && n_breakenable && n_breakaddr == md->GetPC()) {
1.1 root 216: n_breakenable = false;
217: return true;
218: }
219:
220: // アドレス
221: for (int i = 0; i < countof(bpoint); i++) {
222: breakpoint_t *bp = &bpoint[i];
223: if (bp->enable) {
1.1.1.2 ! root 224: if (bp->ismemory) {
! 225: if (md->CheckLEA(bp->addr)) {
! 226: bp->count++;
! 227: return true;
! 228: }
! 229: } else {
! 230: if (bp->addr == md->GetPC()) {
! 231: bp->count++;
! 232: return true;
! 233: }
1.1 root 234: }
235: }
236: }
237:
238: // ステップアウト
239: if (so_enable) {
1.1.1.2 ! root 240: if (md->IsStepOut()) {
1.1 root 241: so_enable = false;
242: return true;
243: }
244: }
245:
246: // アドレス指定付き continue
247: if (bc_enable) {
1.1.1.2 ! root 248: if (bc_addr == md->GetPC()) {
1.1 root 249: bc_enable = false;
250: return true;
251: }
252: }
253:
254: return false;
255: }
256:
257: // コマンド一覧。
1.1.1.2 ! root 258: // quit コマンドによるメインループ終了は MainLoop() 側で処理してある。
1.1 root 259: Debugger::cmddef_t Debugger::cmdtable[] = {
260: { "bx", &Debugger::cmd_bx, },
261: { "b", &Debugger::cmd_b, },
262: { "brhist", &Debugger::cmd_brhist },
263: { "c", &Debugger::cmd_c, },
264: { "d", &Debugger::cmd_d, },
265: { "dt", &Debugger::cmd_dt, },
266: { "D", &Debugger::cmd_D, },
267: { "h", &Debugger::cmd_h, },
268: { "L", &Debugger::cmd_L, },
269: { "m", &Debugger::cmd_m, },
270: { "mt", &Debugger::cmd_mt, },
271: { "M", &Debugger::cmd_M, },
272: { "n", &Debugger::cmd_n, },
1.1.1.2 ! root 273: { "q", &Debugger::cmd_q, },
! 274: { "quit", &Debugger::cmd_q, },
1.1 root 275: { "r", &Debugger::cmd_r, },
276: { "ra", &Debugger::cmd_ra, },
1.1.1.2 ! root 277: { "rc", &Debugger::cmd_rc, },
1.1 root 278: { "rf", &Debugger::cmd_rf, },
279: { "rm", &Debugger::cmd_rm, },
280: { "ro", &Debugger::cmd_ro, },
281: { "s", &Debugger::cmd_s, },
282: { "so", &Debugger::cmd_so, },
283: { "show", &Debugger::cmd_show, },
284: { "t", &Debugger::cmd_t, },
285: { "-", &Debugger::cmd_minus },
286: };
287: Debugger::cmddef_t Debugger::cmdtable_unknown = {
288: .name = "",
289: .func = &Debugger::cmd_unknown,
290: };
291:
292: // ヘルプ
293: void
294: Debugger::cmd_h()
295: {
296: if (ac == 1) {
297: // 引数なし
298: HelpMain();
299: return;
300: } else {
301: // 引数あり(今の所対応していない)
302: HelpMain();
303: return;
304: }
305: }
306:
307: void
308: Debugger::HelpMain()
309: {
310: cons->Print(" b ブレークポイント一覧表示\n");
311: cons->Print(" b #n ブレークポイント n を削除\n");
312: cons->Print(" b $<addr> メモリブレークポイント設定\n");
313: cons->Print(" b <addr> ブレークポイント設定\n");
314: cons->Print(" bx ブレークポイント全削除\n");
315: cons->Print(" brhist ブランチ履歴表示\n");
316: cons->Print(" c [<addr>] 実行再開(continue)\n");
317: cons->Print(" d [<addr> [<lines>] 逆アセンブル(論理、テーブルサーチなし)\n");
318: cons->Print(" dt [<addr> [<lines>] 逆アセンブル(論理、テーブルサーチあり)\n");
319: cons->Print(" D [<addr> [<lines>] 逆アセンブル(物理)\n");
320: cons->Print(" h ヘルプ(help)\n");
321: cons->Print(" L <name>=<lv> ログレベル設定\n");
322: cons->Print(" m [<addr> [<lines>] メモリダンプ(論理、テーブルサーチなし)\n");
323: cons->Print(" mt [<addr> [<lines>] メモリダンプ(論理、テーブルサーチあり)\n");
324: cons->Print(" M [<addr> [<lines>] メモリダンプ(物理)\n");
325: cons->Print(" n <cnt?:1> ステップ実行 (サブルーチンを飛ばす)\n");
326: cons->Print(" q quit\n");
1.1.1.2 ! root 327: cons->Print(" r 通常レジスタを表示\n");
! 328: cons->Print(" ra ATC を表示\n");
! 329: cons->Print(" rc 制御レジスタを表示 (m88xx0)\n");
! 330: cons->Print(" rf FPU レジスタを表示\n");
! 331: cons->Print(" rm MMU レジスタを表示\n");
! 332: cons->Print(" ro その他のレジスタを表示\n");
1.1 root 333: cons->Print(" so ステップアウト\n");
334: cons->Print(" show <monitor> モニター表示\n");
335: cons->Print(" t <cnt?:1> トレース実行\n");
336: }
337:
338: // 知らないコマンドを処理するというコマンド
339: void
340: Debugger::cmd_unknown()
341: {
342: cons->Print("%s: unknown command\n", av[0]);
343: }
344:
345: // cmdbuf を cmd, ac, av に分解する。
346: // コマンド(の1ワード目)が一致しなければ cmd_unknown を返し、
347: // 終了コマンドと一致したら NULL を返す。
348: Debugger::cmddef_t *
349: Debugger::ParseCmd()
350: {
1.1.1.2 ! root 351: char buf[cmdbuf.length() + 1];
1.1 root 352: char *p;
353: cmddef_t *cmd;
354:
1.1.1.2 ! root 355: strcpy(buf, cmdbuf.c_str());
! 356: p = buf;
1.1 root 357: ac = 0;
358: memset(&av, 0, sizeof(av));
359:
360: // 引数を空白で分解
361: for (; ac < countof(av); ) {
362: // 先頭の空白は取り除く
363: while (isspace((int)*p))
364: p++;
365: if (*p == '\0')
366: break;
367:
368: av[ac++] = p;
369: // 次の空白まで進める
370: for (; *p != '\0'; p++) {
371: if (isspace((int)*p))
372: break;
373: }
374: if (*p != '\0')
375: *p++ = '\0';
376: }
1.1.1.2 ! root 377: // buf はスコープを抜けると無効なので、
! 378: // コピーを取って挿げ替え
! 379: for (int i = 0; i < ac; i++) {
! 380: strav[i] = av[i];
! 381: av[i] = strav[i].c_str();
! 382: }
! 383: // デバッグ表示
! 384: if (0) {
! 385: for (int i = 0; i < ac; i++) {
! 386: printf("av[%d]=|%s|\n", i, av[i]);
! 387: }
! 388: }
1.1 root 389:
390: // コマンドを探す
391: for (int i = 0; i < countof(cmdtable); i++) {
392: cmd = &cmdtable[i];
393:
394: if (strcmp(av[0], cmd->name) == 0)
395: return cmd;
396: }
397:
398: // 見つからなければ cmd_unknown コマンドを実行。
399: return &cmdtable_unknown;
400: }
401:
402: //
403: // デバッガコマンド
404: //
405:
406: // ブレークポイント
407: void
408: Debugger::cmd_b()
409: {
410: // 引数なしなら一覧表示
411: if (ac < 2) {
412: return cmd_b_list();
413: }
414:
415: // 引数取得
416: if (av[1][0] == '#') {
417: // #<n> 形式なら、指定番号のブレークポイントを削除
418: int i = atoi(&av[1][1]);
419: if (i < 0 || i >= MAX_BREAKPOINTS) {
420: cons->Print("invaild break point number: #%d\n", i);
421: return;
422: }
423: breakpoint_t *bp = &bpoint[i];
424: if (bp->enable) {
425: cons->Print("%sbreakpoint #%d (%08x) removed\n",
426: bp->ismemory ? "memory " : "", i, bp->addr);
427: bp->enable = false;
428: } else {
429: cons->Print("breakpoint #%d not enabled\n", i);
430: }
431: return;
432: }
433:
434: bool ismemory;
435: uint32 addr;
436: if (av[1][0] == '$') {
437: // $<n> 形式ならメモリブレークポイント
438: ismemory = true;
439: addr = strtoul(&av[1][1], NULL, 16);
440: } else {
441: // そうでなければアドレス指定
442: ismemory = false;
443: addr = strtoul(av[1], NULL, 16);
444: }
445:
446: // すでにあればそのブレークポイントを削除
447: for (int i = 0; i < MAX_BREAKPOINTS; i++) {
448: breakpoint_t *bp = &bpoint[i];
449: if (bp->enable && bp->ismemory == ismemory && bp->addr == addr) {
450: bp->enable = false;
451: cons->Print("%sbreakpoint #%d (%08x) removed\n",
452: bp->ismemory ? "memory " : "", i, bp->addr);
453: return;
454: }
455: }
456:
457: // 空いてるところにセット
458: int bi = AddBreakpoint(addr, ismemory);
459: if (bi == -1) {
460: cons->Print("no free breakpoints!\n");
461: } else {
462: breakpoint_t *bp = &bpoint[bi];
463: cons->Print("%sbreakpoint #%d (%08x) added\n",
464: bp->ismemory ? "memory " : "", bi, bp->addr);
465: }
466: }
467:
468: // ブレークポイント一覧表示
469: void
470: Debugger::cmd_b_list()
471: {
472: int found = 0;
473:
474: for (int i = 0; i < MAX_BREAKPOINTS; i++) {
475: breakpoint_t *bp = &bpoint[i];
476: if (bp->enable) {
477: cons->Print(" #%d %s%08x %d\n",
478: i,
479: bp->ismemory ? "memory $" : "",
480: bp->addr, bp->count);
481: found = 1;
482: }
483: }
484: if (found == 0) {
485: cons->Print(" No breakpoints enabled\n");
486: }
487: }
488:
489: // ブレークポイント全削除
490: void
491: Debugger::cmd_bx()
492: {
493: for (int i = 0; i < MAX_BREAKPOINTS; i++) {
494: breakpoint_t *bp = &bpoint[i];
495: bp->enable = false;
496: }
497: cons->Print(" All breakpoints disabled\n");
498: }
499:
500: // ブレークポイントを設定。
501: // 設定できればその番号、できなければ -1 を返す
502: // TODO 重複の処理とか
503: int
504: Debugger::AddBreakpoint(uint32 addr, bool ismemory)
505: {
506: for (int i = 0; i < countof(bpoint); i++) {
507: breakpoint_t *bp = &bpoint[i];
508: if (!bp->enable) {
509: bp->enable = true;
510: bp->addr = addr;
511: bp->ismemory = ismemory;
512: bp->count = 0;
513: return i;
514: }
515: }
516: return -1;
517: }
518:
519: // ブランチ履歴表示
520: void
521: Debugger::cmd_brhist()
522: {
523: gMPUBrHist->MonitorUpdate();
524: ShowMonitor(gMPUBrHist->monitor);
525: }
526:
527: // 実行再開(continue): c [<addr>]
528: // <addr> 指定があれば <addr> まで実行。
529: void
530: Debugger::cmd_c()
531: {
532: if (ac > 1) {
533: // 引数があれば
534: if (!ParseAddr(av[1], &bc_addr)) {
535: return;
536: }
537: // 偶数番地に丸める
538: bc_addr &= 0xfffffffe;
539:
540: bc_enable = true;
541: }
542: Continue();
543: }
544:
545: // 実行再開
546: void
547: Debugger::Continue()
548: {
549: is_continued = true;
550:
551: // 今のレジスタセットを次回との差分のためにバックアップしておく
1.1.1.2 ! root 552: md->BackupRegs();
1.1 root 553:
554: gCVPrompt->NotifyRelease();
555: }
556:
557: // 引数などからアドレスを取得する共通ルーチン。
558: // 引数が1つ(以上)あれば av[1] をアドレスとしてパースする。
559: // なければ、lastaddr が指定されていればそれを使う。
1.1.1.2 ! root 560: // それもなければ現在の PC を使う。
1.1 root 561: bool
562: Debugger::GetAddr(uint32& addr, uint32& lastaddr)
563: {
564: if (ac > 1) {
565: // 1つ目の引数があれば、開始アドレス
566: if (ParseAddr(av[1], &addr) == false) {
567: return false;
568: }
569: // 偶数番地からに丸める
570: addr &= 0xfffffffe;
571: } else if (lastaddr != 0xffffffff) {
572: // 引数なしで前回値があれば前回の続き
573: addr = lastaddr;
574: } else {
575: // そうでなければ、今の PC
1.1.1.2 ! root 576: addr = md->GetPC();
1.1 root 577: }
578: return true;
579: }
580:
581: // 逆アセンブル: d [<addr> [<cnt>]] (論理、テーブルサーチなし)
582: void
583: Debugger::cmd_d()
584: {
585: cmd_d_common(MemdumpMode::Logical_atc);
586: }
587:
588: // 逆アセンブル: dt [<addr>] [<cnt>]] (論理、テーブルサーチあり)
589: void
590: Debugger::cmd_dt()
591: {
592: cmd_d_common(MemdumpMode::Logical_search);
593: }
594:
595: // 逆アセンブル: D [<addr> [<cnt>]] (物理)
596: void
597: Debugger::cmd_D()
598: {
599: cmd_d_common(MemdumpMode::Physical);
600: }
601:
602: // 逆アセンブル共通
603: void
604: Debugger::cmd_d_common(MemdumpMode mode)
605: {
606: uint32 addr;
1.1.1.2 ! root 607: saddr_t saddr;
1.1 root 608: int cnt;
609:
610: cnt = 10;
611:
612: // 開始アドレス
613: if (GetAddr(addr, d_last_addr) == false) {
614: return;
615: }
616: // 2つ目の引数があれば行数
617: if (ac > 2) {
618: cnt = strtol(av[2], NULL, 10);
619: }
620:
1.1.1.2 ! root 621: saddr.addr = addr;
! 622: saddr.super = md->IsSuper();
! 623:
! 624: // XXX そのうちなんとかする
! 625: if (mode == MemdumpMode::Logical_search) {
! 626: saddr.logical = true;
! 627: saddr.search = true;
! 628: } else if (mode == MemdumpMode::Logical_atc) {
! 629: saddr.logical = true;
! 630: }
! 631:
1.1 root 632: for (int i = 0; i < cnt; i++) {
1.1.1.2 ! root 633: std::string addrbuf;
! 634: std::string mnemonic;
! 635: std::string mnembuf;
! 636: std::vector<uint8> local_ir;
! 637:
! 638: if (FormatDumpAddr(saddr, addrbuf)) {
! 639: md->Disassemble(saddr, mnemonic, local_ir);
! 640: // オフライン用に整形
! 641: mnembuf = md->FormatDisasm(mnemonic, local_ir);
1.1 root 642: }
1.1.1.2 ! root 643: // アドレス変換でバスエラーが起きてもここは表示する
! 644: cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str());
! 645:
! 646: // 変換できなければここで終了
! 647: if (local_ir.size() == 0)
! 648: break;
! 649: saddr.addr += local_ir.size();
1.1 root 650: }
1.1.1.2 ! root 651:
! 652: d_last_addr = saddr.addr;
1.1 root 653: }
654:
655: // ログレベル設定: L <name> <level>
656: void
657: Debugger::cmd_L()
658: {
659: const char *name;
660: int level;
661:
662: if (ac < 3) {
663: cons->Print("L <name> <level>\n");
664: return;
665: }
666:
667: name = av[1];
668: level = atoi(av[2]);
669:
670: // 短縮形とかエイリアスとか
671: // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい
672: if (strcmp(name, "sch") == 0)
673: name = "scheduler";
674: if (strcmp(name, "scc") == 0)
675: name = "sio";
676:
677: // all はどうするか
678: std::string sname = name;
679: bool found = false;
680: for (auto& obj : gObjects) {
681: if (obj->logname == sname) {
682: obj->loglevel = level;
683: cons->Print("%s=%d\n", name, obj->loglevel);
684: found = true;
685: break;
686: }
687: }
688: // 見付からない場合はエラー
689: if (!found) {
690: cons->Print("%s: invalid logname\n", name);
691: }
692: }
693:
694: // メモリダンプ: m [<addr> [<cnt>]] (論理、テーブルサーチなし)
695: void
696: Debugger::cmd_m()
697: {
698: cmd_m_common(MemdumpMode::Logical_atc);
699: }
700:
701: // メモリダンプ: mt [<addr> [<cnt>]] (論理、テーブルサーチあり)
702: void
703: Debugger::cmd_mt()
704: {
705: cmd_m_common(MemdumpMode::Logical_search);
706: }
707:
708: // メモリダンプ: M [<addr> [<cnt>]] (物理)
709: void
710: Debugger::cmd_M()
711: {
712: cmd_m_common(MemdumpMode::Physical);
713: }
714:
715: // メモリダンプ共通
716: void
717: Debugger::cmd_m_common(MemdumpMode mode)
718: {
719: uint32 addr;
1.1.1.2 ! root 720: saddr_t saddr;
1.1 root 721: int cnt;
722:
723: cnt = 10;
724:
725: // 開始アドレス
726: if (GetAddr(addr, m_last_addr) == false) {
727: return;
728: }
729: // 2つ目の引数があれば行数
730: if (ac > 2) {
731: cnt = strtol(av[2], NULL, 10);
732: }
733:
1.1.1.2 ! root 734: saddr.addr = addr;
! 735: saddr.super = md->IsSuper();
! 736: // XXX
! 737: if (mode == MemdumpMode::Logical_search) {
! 738: saddr.logical = true;
! 739: saddr.search = true;
! 740: } else if (mode == MemdumpMode::Logical_atc) {
! 741: saddr.logical = true;
! 742: }
! 743:
1.1 root 744: for (int i = 0; i < cnt; i++) {
1.1.1.2 ! root 745: std::string addrbuf;
! 746: std::string dumpbuf;
! 747: std::string charbuf;
! 748:
! 749: if (FormatDumpAddr(saddr, addrbuf) == false) {
! 750: // アドレス変換でバスエラーならダンプもくそもない
! 751: cons->Print("%s\n", addrbuf.c_str());
! 752: // ここで終わる?
! 753: // XXX 16バイト先を試してみるとか?
! 754: break;
! 755: }
! 756:
! 757: for (int j = 0; j < 8; j++) {
! 758: uint64 paddr;
! 759: // もう一回アドレス変換するのやや冗長だが仕方ない
! 760: if (saddr.IsLogical() && md->MMUEnabled()) {
! 761: // アドレス変換
! 762: paddr = md->TranslateAddr(saddr);
! 763: if ((int64)paddr < 0) {
! 764: // バスエラーが起きたら改行して仕切り直し
! 765: break;
! 766: }
! 767: } else {
! 768: paddr = saddr.addr;
! 769: }
! 770:
! 771: for (int k = 0; k < 2; k++) {
! 772: uint64 b = vm_phys_peek_8(paddr + k);
! 773:
! 774: if ((int64)b < 0) {
! 775: dumpbuf += "--";
! 776: charbuf += " ";
! 777: } else {
! 778: uint32 c = (uint32)b;
! 779: dumpbuf += string_format("%02x", c);
! 780: charbuf += string_format("%c",
! 781: (0x20 <= c && c <= 0x7e) ? c : '.');
! 782: }
! 783: }
! 784: dumpbuf += " ";
! 785: saddr.addr += 2;
! 786: }
! 787: cons->Print("%-18s %-40s %s\n",
! 788: addrbuf.c_str(), dumpbuf.c_str(), charbuf.c_str());
1.1 root 789: }
1.1.1.2 ! root 790: m_last_addr = saddr.addr;
1.1 root 791: }
792:
793: // プロンプトに来た最初に表示するいつものやつを再表示する
794: void
795: Debugger::cmd_minus()
796: {
797: cmd_r();
798:
799: // 論理アクセス時、ATC ミスが分かったほうが便利だと思う
1.1.1.2 ! root 800: saddr_t laddr;
! 801: laddr.addr = pc;
! 802: laddr.super = md->IsSuper();
! 803: laddr.logical = true;
! 804: laddr.search = false;
! 805:
! 806: // 現在の PC の位置を逆アセンブル。ここで ir を更新。
! 807: std::string addrbuf;
! 808: std::string mnemonic;
! 809: std::string mnembuf;
! 810: ir.clear();
! 811: // アドレスを表示用に
! 812: if (FormatDumpAddr(laddr, addrbuf)) {
! 813: md->Disassemble(laddr, mnemonic, ir);
! 814: // ライブ表示用に整形
! 815: mnembuf = md->FormatDisasmLive(mnemonic, ir);
! 816: }
! 817: cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str());
! 818:
! 819: // XXX m88k?
! 820: nextpc = pc + ir.size();
1.1 root 821: }
822:
823: // ステップ実行: n[<count>?=1] (サブルーチンを飛ばす)
824: void
825: Debugger::cmd_n()
826: {
827: if (ac > 1) {
828: int count;
829: count = strtol(av[1], NULL, 10);
830: if (count < 1) {
831: cons->Print(" invalid step count: %d\n", count);
832: return;
833: }
834:
835: n_count = count;
836: } else {
837: n_count = 1;
838: }
839: n_enable = true;
840: SetNBreakpoint();
841: Continue();
842: }
843:
844: // n コマンド用のサブルーチンを飛ばすブレークポイントを設定。
845: // 戻り値は、プロンプトをスキップするなら true。
846: bool
847: Debugger::SetNBreakpoint()
848: {
849: // n コマンドは、通常はブレークポイントを次の命令に仕掛けながら
850: // 実行するが、いくつかの命令ではブレークポイントではなく、
851: // 命令トレース (t コマンド) のように動作させる。
852: // トレース動作する命令は以下の通り。
853: // Bcc, BRA
854: // JMP
855: // RTD, RTR, RTS
856: // RTE
857: // FBcc
858: // FDBcc (2ワード目無視)
859: // (RTM は 68020 専用なので対応しない)
860: #define IsBcc(x) ((((x) & 0xf000) == 0x6000) && (((x) & 0xff00) != 0x6100))
861: #define IsJMP(x) (((x) & 0xffc0) == 0x4ec0)
862: #define IsRTD(x) (((x) & 0xffff) == 0x4e74)
863: #define IsRTE(x) (((x) & 0xffff) == 0x4e73)
864: #define IsRTR(x) (((x) & 0xffff) == 0x4e77)
865: #define IsRTS(x) (((x) & 0xffff) == 0x4e75)
866: #define IsFBcc(x) (((x) & 0xf180) == 0xf080)
867: #define IsFDBcc(x) (((x) & 0xf1f8) == 0xf048)
868:
869: uint16 op;
870:
871: // XXX この辺統一的にしたほうがいい
872: // XXX logical peek のような気がする
1.1.1.2 ! root 873: op = (((uint16)vm_phys_peek_8(pc)) << 8)
! 874: | vm_phys_peek_8(pc + 1);
1.1 root 875:
876: if (IsBcc(op)
877: || IsJMP(op)
878: || IsRTD(op)
879: || IsRTE(op)
880: || IsRTR(op)
881: || IsRTS(op)
882: || IsFBcc(op)
883: || IsFDBcc(op)
884: ) {
885: n_breakenable = false;
886: s_enable = true;
887: s_count = 1;
888: return false;
889: } else {
890: n_breakenable = true;
891: n_breakaddr = nextpc;
892: return true;
893: }
894: }
895:
1.1.1.2 ! root 896: // デバッガ終了コマンド
! 897: void
! 898: Debugger::cmd_q()
! 899: {
! 900: cons->Print("quit debugger console.\n");
! 901:
! 902: // XXX: このフラグでいいのかとか exit でいいのかとか
! 903: if (gMainApp.debug_on_console) {
! 904: // コンソールモードのときはプログラムも終了
! 905: exit(0);
! 906: }
! 907: }
! 908:
1.1 root 909: // レジスタ表示
910: // rf: FPU レジスタを表示
911: // rm: MMU レジスタを表示
912: // r<それ以外>: 通常レジスタを表示?
913: void
914: Debugger::cmd_r()
915: {
916: if (ac > 1) {
917: int arg = av[1][0];
918: switch (arg) {
919: case 'a':
920: ShowMonitor(gMPUATC->monitor);
921: return;
1.1.1.2 ! root 922: case 'c':
! 923: md->ShowRegCtrl(cons);
! 924: return;
1.1 root 925: case 'f':
1.1.1.2 ! root 926: md->ShowRegFPU(cons);
1.1 root 927: return;
928: case 'm':
1.1.1.2 ! root 929: md->ShowRegMMU(cons);
1.1 root 930: return;
931: case 'o':
1.1.1.2 ! root 932: md->ShowRegOther(cons);
1.1 root 933: return;
934: }
935: }
1.1.1.2 ! root 936: md->ShowRegMain(cons);
1.1 root 937: }
938:
939: // ショートカット
940: void
941: Debugger::cmd_ra()
942: {
1.1.1.2 ! root 943: md->ShowRegATC(cons);
! 944: }
! 945: void
! 946: Debugger::cmd_rc()
! 947: {
! 948: md->ShowRegCtrl(cons);
1.1 root 949: }
950: void
951: Debugger::cmd_rf()
952: {
1.1.1.2 ! root 953: md->ShowRegFPU(cons);
1.1 root 954: }
955: void
956: Debugger::cmd_rm()
957: {
1.1.1.2 ! root 958: md->ShowRegMMU(cons);
1.1 root 959: }
960: void
961: Debugger::cmd_ro()
962: {
1.1.1.2 ! root 963: md->ShowRegOther(cons);
1.1 root 964: }
965:
966: // モニター表示
967: void
968: Debugger::cmd_show()
969: {
970: if (ac != 2) {
971: cons->Print("usage: show <monitor>\n");
972: for (auto& d : gObjects) {
973: if (d->logname != "?") {
974: cons->Print(" %s\n", d->logname.c_str());
975: }
976: }
977: return;
978: }
979:
980: std::string name(av[1]);
981: for (auto& d : gObjects) {
982: if (d->logname == name) {
983: // ここで更新して..
984: if (d->MonitorUpdate()) {
985: // 表示
986: ShowMonitor(d->monitor);
987: } else {
988: // モニターがない場合
989: cons->Print("show: %s has no monitor\n", av[1]);
990: }
991: return;
992: }
993: }
994: // 一致しない
995: cons->Print("show: no such objects\n");
996: }
997:
998: // モニタースクリーンを表示。
999: void
1000: Debugger::ShowMonitor(TextScreen& monitor)
1001: {
1002: char sbuf[1024]; // 適当
1003:
1004: // monitor 内部バッファから ShiftJIS バッファを作成。
1005: // その際属性もエスケープシーケンスで再現する。
1006: int col = monitor.GetCol();
1007: int row = monitor.GetRow();
1008: const uint16 *src = monitor.GetBuf();
1009:
1010: for (int y = 0; y < row; y++) {
1011: int sy = y * col;
1012: int sx;
1013: uint attr;
1014: char *d;
1015:
1016: memset(sbuf, 0, sizeof(sbuf));
1017: d = sbuf;
1018: attr = TA::Normal;
1019: for (sx = 0; sx < col; sx++) {
1020: uint a = src[sy + sx] & 0xff00;
1021: uint ch = src[sy + sx] & 0x00ff;
1022:
1023: // 属性の変わり目
1024: if (attr != a) {
1025: switch (a) {
1026: case TA::Normal:
1027: case TA::Off:
1028: *d++ = 0x1b;
1029: *d++ = '[';
1030: *d++ = 'm';
1031: break;
1032: case TA::On:
1033: *d++ = 0x1b;
1034: *d++ = '[';
1035: *d++ = '7';
1036: *d++ = 'm';
1037: break;
1038: case TA::Disable:
1039: *d++ = 0x1b;
1040: *d++ = '[';
1041: *d++ = '2';
1042: *d++ = 'm';
1043: break;
1044: case TA::Em:
1045: *d++ = 0x1b;
1046: *d++ = '[';
1047: *d++ = '1';
1048: *d++ = 'm';
1049: break;
1050: }
1051: attr = a;
1052: }
1053: *d++ = ch;
1054: }
1055: *d = '\0';
1056:
1057: // XXX 日本語が使われてれば UTF-8 にしないといけないはず
1058:
1059: cons->Print("%s\n", sbuf);
1060: }
1061: }
1062:
1063: // ステップ実行: s[<count>?:1]
1064: void
1065: Debugger::cmd_s()
1066: {
1067: if (ac > 1) {
1068: int count;
1069: count = strtol(av[1], NULL, 10);
1070: if (count < 1) {
1071: cons->Print(" invalid step count: %d\n", count);
1072: return;
1073: }
1074:
1075: s_count = count;
1076: } else {
1077: s_count = 1;
1078: }
1079: s_enable = true;
1080: Continue();
1081: }
1082:
1083: // ステップアウト
1084: void
1085: Debugger::cmd_so()
1086: {
1087: so_enable = true;
1.1.1.2 ! root 1088: md->SetStepOut();
1.1 root 1089: Continue();
1090: }
1091:
1092: // トレース実行: t[<count>?:1]
1093: // レジスタを表示しながら実行する
1094: void
1095: Debugger::cmd_t()
1096: {
1097: if (ac > 1) {
1098: int count;
1099: count = strtol(av[1], NULL, 10);
1100: if (count < 1) {
1101: cons->Print(" invalid trace count: %d\n", count);
1102: return;
1103: }
1104: t_count = count;
1105: } else {
1106: t_count = 1;
1107: }
1108: t_enable = true;
1109: Continue();
1110: }
1111:
1112: // 引数で示されるアドレスを返す。
1113: // '%' で始まればレジスタ。
1114: // そうでなければ16進数値。
1115: // アドレスが正しく取得できればアドレスを addr に格納し真を返す。
1116: // そうでなければエラーメッセージを表示して偽を返す。
1117: bool
1118: Debugger::ParseAddr(const char *arg, uint32_t *addrp)
1119: {
1120: uint32_t addr;
1121: char *end;
1122:
1123: if (arg[0] == '%') {
1.1.1.2 ! root 1124: // '%' から始まればレジスタ
! 1125: uint64 r;
! 1126: r = md->GetRegAddr(arg + 1);
! 1127: if ((int64)r < 0) {
! 1128: #if 0 // not yet
1.1 root 1129: cons->Print("valid register name are: %s%s\n",
1130: "%d0-%d7,%a0-%a7,%sp,%usp,%isp,%pc",
1131: ",%msp,%vbr,%srp,%crp");
1.1.1.2 ! root 1132: #endif
! 1133: cons->Print("invalid register name\n");
1.1 root 1134: return false;
1135: }
1.1.1.2 ! root 1136: addr = (uint32)r;
1.1 root 1137: } else {
1138: /* そうでなければ番地指定 */
1139: errno = 0;
1140: addr = strtoul(arg, &end, 16);
1141: if (arg[0] == '\0' || end[0] != '\0') {
1142: cons->Print("invalid address: '%s'\n", arg);
1143: return false;
1144: }
1145: if (errno == ERANGE) {
1146: cons->Print("out of range: %s\n", arg);
1147: return false;
1148: }
1149: }
1150:
1151: *addrp = addr;
1152: return true;
1153: }
1154:
1.1.1.2 ! root 1155: // (論理、物理)アドレスを表示用に整形。
! 1156: // 逆アセンブル表示、メモリダンプ表示等で共通。
! 1157: // アドレス変換でバスエラーが起きたら false を返す (この場合も str は有効)。
! 1158: // 末尾を空白パディングはしていないので必要なら "%-18s" 等して使うこと。
! 1159: // 123456789012345678
! 1160: // "00112233:44556677:"
1.1 root 1161: bool
1.1.1.2 ! root 1162: Debugger::FormatDumpAddr(saddr_t laddr, std::string& str)
1.1 root 1163: {
1.1.1.2 ! root 1164: bool rv = true;
1.1 root 1165:
1.1.1.2 ! root 1166: // laddr は常に表示
! 1167: str = string_format("%08x", laddr.addr);
1.1 root 1168:
1.1.1.2 ! root 1169: if (laddr.IsLogical() && md->MMUEnabled()) {
! 1170: // アドレス変換してみる
! 1171: uint64 paddr = md->TranslateAddr(laddr);
! 1172: if ((int64)paddr < 0) {
! 1173: // MMU 時点でバスエラー
! 1174: str += ":BusErr";
! 1175: rv = false;
! 1176: } else if (paddr == laddr.addr) {
! 1177: // PA==VA
! 1178: str += "=PA";
1.1 root 1179: } else {
1.1.1.2 ! root 1180: // PA!=VA
! 1181: str += string_format(":%08x:", (uint32)paddr);
1.1 root 1182: }
1.1.1.2 ! root 1183: } else {
! 1184: // 物理アクセス
! 1185: str += ":";
1.1 root 1186: }
1187:
1.1.1.2 ! root 1188: return rv;
1.1 root 1189: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.