|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.2 root 7: #include "console.h"
8: #include "debugger_private.h"
9: #include "debugger_m680x0.h"
10: #include "debugger_m88xx0.h"
11: #include "mainapp.h"
1.1.1.3 root 12: #include "mythread.h"
1.1.1.7 root 13: #include "scheduler.h"
1.1.1.3 root 14: #include <algorithm>
1.1 root 15: #include <csignal>
16:
1.1.1.3 root 17: static Debugger *gDebugger;
1.1.1.4 root 18: BreakpointMonitor *gBreakpointMonitor;
1.1 root 19: CVPrompt *gCVPrompt;
20:
21: static void *debugger_run(void *);
22:
23: // 初期化。
24: // この時点で VM が初期化されていること。
25: void
26: debugger_init()
27: {
28: gDebugger = new Debugger();
29: gDebugger->Init();
30:
1.1.1.4 root 31: gBreakpointMonitor = new BreakpointMonitor();
1.1 root 32: gCVPrompt = new CVPrompt();
33:
34: // デバッガスレッド起動
35: pthread_t th;
36: pthread_create(&th, NULL, debugger_run, NULL);
37: }
38:
39: // デバッガスレッドのエントリポイント
40: static void *
41: debugger_run(void *dummy)
42: {
1.1.1.3 root 43: PTHREAD_SETNAME("Debugger");
1.1 root 44: pthread_detach(pthread_self());
45:
46: gDebugger->ThreadRun();
47: return NULL;
48: }
49:
50: // コンストラクタ
51: Debugger::Debugger()
52: {
1.1.1.2 root 53: if (gMPU680x0) {
54: md = new DebuggerMD_m680x0(this, gMPU680x0->GetCPU());
55: } else if (gMPU88xx0) {
56: md = new DebuggerMD_m88xx0(this, gMPU88xx0->GetCPU());
57: } else {
58: throw "unknown mpu";
59: }
1.1 root 60: }
61:
62: // コマンドライン引数によって動作を決めるところ。
63: // 名前がこれでいいのかはあるけど。
64: void
65: Debugger::Init()
66: {
67: // -d なら CPU 起動時点で停止してプロンプトを待つ
1.1.1.2 root 68: if (gMainApp.debug_on_start) {
69: md->ReqSet(CPU_REQ_PROMPT);
1.1 root 70: }
71:
72: // -b <addr> ならブレークポイント設定
1.1.1.4 root 73: for (auto& str : gMainApp.debug_breakaddr) {
74: breakpoint_t bp;
75:
1.1.1.2 root 76: md->ReqSet(CPU_REQ_TRACE);
1.1.1.4 root 77:
78: // <addr>,<skip> で分離できたら <skip> を取り出す
79: int pos = str.find(',');
80: if (pos != std::string::npos) {
81: std::string skipstr = str.substr(pos + 1);
82: bp.skip = atoi(skipstr.c_str());
83:
84: // XXX これ出来るんだっけ?
85: str[pos] = '\0';
86: }
87: // そしてどちらにしても <addr> を取り出す
88: if (!ParseAddr(str.c_str(), &bp.addr)) {
89: warnx("\"%s\": Invalid breakpoint address", str.c_str());
90: return;
91: }
92: // 登録
93: bp.type = BreakpointType::Address;
94: AddBreakpoint(bp);
1.1 root 95: }
96:
97: // どこでやるべか
98: signal(SIGPIPE, SIG_IGN);
99: }
100:
101: // デバッガスレッド
102: void
103: Debugger::ThreadRun()
104: {
105: // XXX どこかでコンソールの選択とパラメータの取得
1.1.1.2 root 106: if (gMainApp.debug_on_console) {
107: cons = new ConsoleStdio();
108: } else {
109: cons = new ConsoleTCP();
110: }
1.1 root 111: if (cons->Init() == false) {
1.1.1.3 root 112: delete cons;
1.1 root 113: return;
114: }
115:
1.1.1.5 root 116: // disp_regs の初期値設定。
117: // 再接続でも継続してていいような気がするのでループ外で初期化。
118: disp_regs.clear();
119: disp_regs.push_back("r");
120:
1.1 root 121: for (;;) {
1.1.1.3 root 122: // 着信待ち
123: if (Accept() == false) {
124: break;
125: }
126:
1.1.1.2 root 127: cons->InitEditLine("> ");
1.1 root 128:
1.1.1.3 root 129: // デバッガプロンプトにいる間はトレースオン
130: md->ReqSet(CPU_REQ_TRACE);
131:
132: bool first = true;
133: for (;;) {
134: // 接続後の1回目だけ実行するもの。
135: if (first) {
136: first = false;
137:
138: // greeting はプロンプトが取れる前にもう表示したい。
139: // 何らかの事故でプロンプトが取れなくても、ここまでは接続
140: // できてることが分かるように。
141: cons->Print("This is debugger console\n");
142:
143: // 接続ごとに初期化する値
144: n_enable = false;
145: s_enable = false;
1.1.1.5 root 146: t_enable = true;
1.1.1.3 root 147: }
148:
149: // プロンプトが取れるのを待つ
150: if (AcquirePrompt() == false) {
151: break;
152: }
153:
1.1.1.8 ! root 154: // 実時間を停止
! 155: gRealtime.Stop();
! 156:
1.1.1.6 root 157: // d/m をいきなり引数なしで実行した時のため、現在地にしておく。
1.1.1.3 root 158: pc = md->GetPC();
1.1.1.6 root 159: m_last_addr.Set(pc, md->IsSuper(), true);
160: d_last_addr.Set(pc, md->IsSuper(), false);
161: // プロンプトに来た時に表示するいつものやつ
1.1.1.3 root 162: cmd_minus();
163:
164: // コマンド処理のメインループ
165: auto action = MainLoop();
166:
167: // 次回との差分のため、今のレジスタセットをバックアップ
168: md->BackupRegs();
169:
1.1.1.8 ! root 170: // 実時間を再開
! 171: gRealtime.Start();
! 172:
1.1.1.3 root 173: // メインループから戻ったということは Leave か Quit なので
174: // どちらにしても、ここでプロンプトを手放す。
175: gCVPrompt->NotifyRelease();
176:
177: // quit ならここでループを1段抜ける
178: if (action == CommandAction::Quit) {
179: break;
180: }
181: }
182:
183: // デバッガを抜けるのでトレースオフ
1.1.1.2 root 184: md->ReqClr(CPU_REQ_TRACE);
1.1 root 185:
186: cons->Close();
1.1.1.3 root 187: if (gMainApp.debug_on_console) {
188: break;
189: }
1.1 root 190: }
191:
192: delete cons;
193: }
194:
1.1.1.3 root 195: // コンソールに接続されるのを待つ。
196: // うーん、なんだこれ。
197: //
198: // +--- debug_on_console (-D オプション)
199: // | +- debug_on_start (-d オプション)
200: // | | 動作
201: // 0 0 TCP、Accept で待機。
202: // 0 1 TCP、Accpet で待機。
203: // 1 0 stdio、起動時にプロンプトで止まらない -> キー入力待ち。
204: // 1 1 stdio、起動時にプロンプトで止まる。
1.1 root 205: bool
1.1.1.3 root 206: Debugger::Accept()
207: {
208: if (gMainApp.debug_on_console == false) {
209: // TCP なら accept が成功するのを待つ
210: cons->Accept();
211: } else {
212: if (gMainApp.debug_on_start == false) {
213: // stdio、起動時にプロンプトで止まらない。
214: // この場合キー入力かブレークポイントなどで止まった時点で
215: // プロンプトを出したいのでちょっと面倒なことに。
216: for (;;) {
217: bool is_prompt = gCVPrompt->WaitAcquire(200);
218: if (is_prompt) {
219: break;
220: }
221:
222: int r = cons->Poll(200);
223: if (r < 0) {
224: cmd_q();
225: return false;
226: }
227: if (r > 0) {
228: break;
229: }
230: }
231: } else {
232: // stdio、起動時にプロンプトで止まる。
233: // この場合は無条件に成功でよい。
234: }
235: }
236:
237: return true;
238: }
239:
240: // プロンプトが取れるのを待つ
241: // 失敗すれば false を返す
242: bool
243: Debugger::AcquirePrompt()
1.1 root 244: {
1.1.1.3 root 245: md->ReqSet(CPU_REQ_PROMPT);
246:
1.1.1.2 root 247: for (;;) {
248: bool is_prompt = gCVPrompt->WaitAcquire(200);
1.1.1.3 root 249: if (is_prompt)
250: break;
1.1.1.2 root 251:
252: // コンソールを定期観測して、入力があればブレーク要求
253: if (cons->Poll()) {
254: // この入力は drop してみる
255: if (cons->Gets(cmdbuf) == false) {
256: // EOF or Error
257: cmd_q();
258: return false;
259: }
260: md->ReqSet(CPU_REQ_PROMPT);
261: }
262: }
1.1.1.3 root 263: return true;
264: }
1.1 root 265:
1.1.1.3 root 266: // コマンド処理のメインループ。
267: // コマンドが Stay ならこの中で処理を継続。
268: // コマンドが Leave か Quit ならその値を持って戻る (呼び出し側で処理する)。
269: Debugger::CommandAction
270: Debugger::MainLoop()
271: {
272: for (;;) {
1.1.1.7 root 273: // ブレークポイント到達メッセージがあればここで表示
274: if (bpointmsg.empty() == false) {
275: cons->Print("%s", bpointmsg.c_str());
276: bpointmsg.clear();
277: }
278:
1.1.1.3 root 279: cons->Prompt();
280: if (cons->Gets(cmdbuf) == false) {
281: // EOF or Error
282: return CommandAction::Quit;
283: }
1.1 root 284:
1.1.1.3 root 285: string_rtrim(cmdbuf);
1.1 root 286:
1.1.1.3 root 287: if (!cmdbuf.empty()) {
288: // コマンドが入力されれば次回のために保存
289: last_cmdbuf = cmdbuf;
290: } else {
291: // 空行が入力されれば直前のコマンドをもう一度
292: // 前行がなければ何もせずもう一度プロンプトを表示するかね
293: if (last_cmdbuf.empty())
294: continue;
295: cmdbuf = last_cmdbuf;
296: }
297:
298: // 行を args に分解
299: ParseCmdbuf();
300:
301: // 前回の値が有効なのはコマンドが連続した時だけ
302:
303: // コマンドをテーブルから探す
304: auto it = std::find_if(cmdtable.begin(), cmdtable.end(),
305: [=](auto x) { return strcmp(args[0].c_str(), x.name) == 0; });
306: if (it != cmdtable.end()) {
307: auto cmd = *it;
308:
309: // 見付かれば実行
310: (this->*(cmd.func))();
311:
312: // Stay なら引き続きコマンド処理
313: if (cmd.action == CommandAction::Stay) {
314: continue;
315: }
316: // それ以外ならメインループ終了
317: return cmd.action;
318: }
1.1 root 319:
1.1.1.3 root 320: // (コマンドテーブルになくて) "r" から始まっていればレジスタ表示系
321: if (args[0][0] == 'r') {
322: // ShowRegister() は処理したら true を返す。
323: // "r" 系コマンドはすべて Stay。
324: if (md->ShowRegister(cons, args)) {
325: continue;
326: }
327: }
1.1.1.2 root 328:
1.1.1.3 root 329: // 知らないコマンドも Stay 相当。
330: cons->Print("%s: unknown command\n", args[0].c_str());
331: continue;
332: }
333: __unreachable();
1.1 root 334: }
335:
336: // ブレークポイントとかを調べる。
337: // CPU_REQ_TRACE フラグが立っている間1命令ごとに呼び出される。
338: bool
339: debugger_check()
340: {
341: return gDebugger->Check();
342: }
343:
344: // デバッガ実行中なら命令開始前にメインルーチンから呼ばれる。
345: // プロンプトに降りるなら true を返す。
346: bool
347: Debugger::Check()
348: {
1.1.1.5 root 349: bool is_break = false;
350:
351: // ブレークポイントは他のチェックとは併用になるので先に調べる。
352: if (CheckAllBreakpoints()) {
353: is_break = true;
354: }
355: // アドレス指定付き continue もブレークポイントと似た動作なのでこっち。
356: // XXX ブレークポイントとして実装するかどうか
357: if (bc_enable) {
358: if (bc_addr == md->GetPC()) {
359: bc_enable = false;
360: is_break = true;
1.1 root 361: }
362: }
363:
1.1.1.5 root 364: // XXX 残りは排他動作のはず
365:
366: // いずれの場合も、ステップ実行が終了条件にマッチしたら、ブレークポイント
367: // の成否に関わらず true を返せばいい。
368: // 終了条件が来ないうちに先にブレークポイントに到達した場合でも、ブレーク
369: // ポイントによりプロンプトに降りるわけなので、実行中のステップ実行を
370: // キャンセルする。この場合もブレークポイント側が true なので true を
371: // 返せばよい。
372:
373: // t (トレース表示) が enable なら、終了条件にマッチしなくてもここで
374: // レジスタを表示。終了条件にマッチする場合に表示するとプロンプトで
375: // もう一回表示されて二重になってしまうので注意。
376:
377: if (s_enable) { // ステップ実行が..
1.1 root 378: s_count--;
1.1.1.5 root 379: if (s_count == 0) { // 成立
380: s_enable = false;
381: return true;
382: } else if (is_break) { // 非成立だがブレークが成立
1.1 root 383: s_enable = false;
384: return true;
1.1.1.5 root 385: } else if (t_enable) { // どちらも非成立で trace on
386: cmd_minus();
1.1 root 387: }
388:
1.1.1.5 root 389: } else if (so_enable) { // ステップアウトが..
390: if (md->IsStepOut()) { // 成立
1.1 root 391: so_enable = false;
392: return true;
1.1.1.5 root 393: } else if (is_break) { // 非成立だがブレークが成立
394: so_enable = false;
395: return true;
396: } else if (t_enable) { // どちらも非成立で trace on
397: cmd_minus();
1.1 root 398: }
399:
1.1.1.5 root 400: } else if (n_enable) { // 次命令まで実行が..
401: if (n_breakaddr != 0xffffffff) {
402: // ステップインをスキップ中
403: if (n_breakaddr == md->GetPC()) {
404: n_count--;
405: }
406: } else {
407: // 1命令実行
408: n_count--;
409: }
410: if (n_count == 0) { // 成立
411: n_enable = false;
412: return true;
413: } else if (is_break) { // 非成立だがブレークが成立
414: n_enable = false;
1.1 root 415: return true;
416: }
1.1.1.5 root 417: if (t_enable) { // どちらも非成立で trace on
418: cmd_minus();
419: }
420:
421: // スキップ中でなければ、ステップインが起きるか都度調べる。
422: // すでにスキップ中なら到達するまでは何もしない。
423: if (n_breakaddr == 0xffffffff) {
424: SetNBreakpoint();
425: }
1.1 root 426: }
427:
1.1.1.5 root 428: // ステップ実行系がなければブレークポイントの成否だけ
429: return is_break;
1.1 root 430: }
431:
1.1.1.4 root 432: // ブレークポイントがどれかでも成立するかを調べる。
433: // 1つ以上成立してブレークするなら true を返す。
434: // 1つも成立しておらずブレークしないなら false を返す。
1.1.1.7 root 435: // このルーチン内では Console があることを期待してはいけない (プロンプトが
436: // ない時でも呼ばれるので)。
1.1.1.4 root 437: bool
438: Debugger::CheckAllBreakpoints()
439: {
440: bool is_break = false;
441:
442: // 命令ごとにクリアする
443: bi_inst = 0;
444: bi_inst_bytes = 0;
445:
446: // 1つの条件でマッチしても(そこでブレークすること自体は確定するのだが)
447: // 残りの他の条件も成立すればカウントを進める必要があるため、
448: // 全部処理した上でどれか一つでもブレークしたかで判断する必要がある。
1.1.1.5 root 449: for (int i = 0, end = bpoint.size(); i < end; i++) {
450: auto& bp = bpoint[i];
451:
1.1.1.4 root 452: switch (bp.type) {
453: case BreakpointType::Address:
454: if (bp.addr != md->GetPC()) {
455: continue;
456: }
457: break;
458:
459: case BreakpointType::Memory:
460: if (!md->CheckLEA(bp.addr)) {
461: continue;
462: }
463: break;
464:
465: case BreakpointType::Exception:
466: if (bv_vector >= 0) {
467: if (bp.vec1 <= bv_vector && bv_vector <= bp.vec2) {
468: break;
469: }
470: }
471: continue;
472:
473: case BreakpointType::Instruction:
474: if (CheckBreakpointInst(bp) == false) {
475: continue;
476: }
477: break;
478:
479: default:
480: continue;
481: }
482:
483: // 条件は成立したのでカウントとスキップ
484: bp.matched++;
485:
486: // skip == -1 は常にブレークしない (カウントするだけ)
487: if (bp.skip < 0) {
488: continue;
489: }
490:
491: // skip が 1 以上なら、remain を減算
492: if (bp.skip > 0 && --bp.skipremain > 0) {
493: continue;
494: }
495:
496: // ブレーク成立
497: is_break = true;
1.1.1.5 root 498:
499: std::string desc;
500: switch (bp.type) {
501: case BreakpointType::Address:
502: desc = string_format("addr $%08x", bp.addr);
503: break;
504: case BreakpointType::Memory:
505: desc = string_format("mem $%08x", bp.addr);
506: break;
507: case BreakpointType::Exception:
508: {
509: desc = string_format("excp $%02x", bv_vector);
510: const char *name = md->GetExceptionName(bv_vector);
511: if (name != NULL && name[0] != '\0') {
512: desc += string_format(" \"%s\"", name);
513: }
514: break;
515: }
516: case BreakpointType::Instruction:
517: desc = string_format("inst %0*x",
518: bi_inst_bytes * 2,
519: bi_inst >> ((4 - bi_inst_bytes) * 8));
520: break;
521: default:
522: assert(false);
523: break;
524: }
1.1.1.7 root 525:
526: // 到達メッセージを作成。
527: // この時点ではまだコンソールを取得していない可能性があるので
528: // (-D なしで起動した場合とか)、表示せず用意するだけ。
529: // コンソールが取得できたところで表示する。
530: bpointmsg += string_format("breakpoint #%d (%s) reached\n",
531: i, desc.c_str());
1.1.1.4 root 532: }
533:
534: // 例外通知は通過ごとに常に下ろしておく
535: bv_vector = -1;
536:
537: // ブレークポイントが1つでも成立したかどうかを返す
538: return is_break;
539: }
540:
541: // 命令ブレークポイントが成立するか調べる。
542: bool
543: Debugger::CheckBreakpointInst(breakpoint_t& bp)
544: {
545: // uint32 bi_inst が現在の PC 位置の命令データ (左詰め)
546: // bi_inst_bytes が読み込んだバイト数(bi_inst の左からの有効バイト数)。
547: // bi_need_bytes が現在のブレークポイントで読み込む必要のあるバイト数。
548:
1.1.1.6 root 549: saddr_t laddr(md->GetPC(), md->IsSuper());
550: DebuggerMemoryStream mem(md, laddr);
1.1.1.5 root 551:
1.1.1.4 root 552: // 必要なバイト数に達するまで読み足す
1.1.1.5 root 553: bi_inst = 0;
1.1.1.4 root 554: while (bi_inst_bytes < bi_need_bytes) {
1.1.1.6 root 555: uint64 data = mem.FetchInst();
1.1.1.5 root 556: if ((int64)data < 0) {
557: return false;
1.1.1.4 root 558: }
559:
1.1.1.5 root 560: bi_inst <<= md->inst_bytes * 8;
561: bi_inst |= data;
562: bi_inst_bytes += md->inst_bytes;
1.1.1.4 root 563: }
1.1.1.5 root 564:
1.1.1.4 root 565: // 左詰めにする
566: bi_inst <<= (4 - bi_inst_bytes) * 8;
567:
568: // 必要なバイト数取得できたので比較
569: if ((bi_inst & bp.mask) == bp.inst) {
570: return true;
571: }
572: return false;
573: }
574:
575: // 例外通知 (MPU からの連絡用)
576: void
1.1.1.5 root 577: debugger_notify_exception(int vector)
1.1.1.4 root 578: {
579: gDebugger->NotifyException(vector);
580: }
581:
582: // 例外通知 (本体)
583: void
584: Debugger::NotifyException(int vector)
585: {
586: bv_vector = vector;
587: }
588:
1.1 root 589: // コマンド一覧。
1.1.1.3 root 590: // "r" から始まるレジスタ表示系コマンドはコード中で別処理してある。
591: /*static*/ std::vector<Debugger::cmddef_t> Debugger::cmdtable = {
1.1.1.4 root 592: { "bi", &Debugger::cmd_bi, Debugger::CommandAction::Stay },
593: { "bm", &Debugger::cmd_bm, Debugger::CommandAction::Stay },
594: { "bv", &Debugger::cmd_bv, Debugger::CommandAction::Stay },
1.1.1.3 root 595: { "bx", &Debugger::cmd_bx, Debugger::CommandAction::Stay },
596: { "b", &Debugger::cmd_b, Debugger::CommandAction::Stay },
597: { "brhist", &Debugger::cmd_brhist, Debugger::CommandAction::Stay },
598: { "c", &Debugger::cmd_c, Debugger::CommandAction::Leave },
599: { "d", &Debugger::cmd_d, Debugger::CommandAction::Stay },
600: { "dt", &Debugger::cmd_dt, Debugger::CommandAction::Stay },
601: { "D", &Debugger::cmd_D, Debugger::CommandAction::Stay },
1.1.1.5 root 602: { "disp", &Debugger::cmd_disp, Debugger::CommandAction::Stay },
1.1.1.4 root 603: { "exhist", &Debugger::cmd_exhist, Debugger::CommandAction::Stay },
1.1.1.5 root 604: { "hb", &Debugger::cmd_hb, Debugger::CommandAction::Stay },
605: { "hr", &Debugger::cmd_hr, Debugger::CommandAction::Stay },
1.1.1.3 root 606: { "h", &Debugger::cmd_h, Debugger::CommandAction::Stay },
607: { "help", &Debugger::cmd_h, Debugger::CommandAction::Stay },
608: { "L", &Debugger::cmd_L, Debugger::CommandAction::Stay },
609: { "m", &Debugger::cmd_m, Debugger::CommandAction::Stay },
610: { "mt", &Debugger::cmd_mt, Debugger::CommandAction::Stay },
611: { "M", &Debugger::cmd_M, Debugger::CommandAction::Stay },
612: { "n", &Debugger::cmd_n, Debugger::CommandAction::Leave },
1.1.1.5 root 613: { "nt", &Debugger::cmd_nt, Debugger::CommandAction::Leave },
1.1.1.3 root 614: { "q", &Debugger::cmd_q, Debugger::CommandAction::Quit },
615: { "quit", &Debugger::cmd_q, Debugger::CommandAction::Quit },
1.1.1.5 root 616: { "reset", &Debugger::cmd_reset, Debugger::CommandAction::Leave },
1.1.1.3 root 617: { "s", &Debugger::cmd_s, Debugger::CommandAction::Leave },
1.1.1.5 root 618: { "st", &Debugger::cmd_st, Debugger::CommandAction::Leave },
1.1.1.3 root 619: { "so", &Debugger::cmd_so, Debugger::CommandAction::Leave },
1.1.1.5 root 620: { "sot", &Debugger::cmd_sot, Debugger::CommandAction::Leave },
1.1.1.3 root 621: { "show", &Debugger::cmd_show, Debugger::CommandAction::Stay },
622: { "t", &Debugger::cmd_t, Debugger::CommandAction::Leave },
623: { "-", &Debugger::cmd_minus, Debugger::CommandAction::Stay },
1.1 root 624: };
625:
626: // ヘルプ
1.1.1.5 root 627: // h : 一覧を表示
628: // h <cmd> : 単独コマンドの詳細を表示
1.1 root 629: void
630: Debugger::cmd_h()
631: {
1.1.1.5 root 632: if (args.size() < 2) {
633: // 引数なしなら一覧表示。
1.1.1.6 root 634: ShowHelpList(HelpListMain);
1.1.1.5 root 635: return;
1.1.1.3 root 636: }
1.1.1.5 root 637:
638: // 引数があれば個別の詳細
639: bool try_again = false;
640: std::string cmd = args[1];
641: do {
1.1.1.6 root 642: // レジスタ系のヘルプを MD から取得して、ローカル変数で足す
643: auto details = HelpDetails;
644: for (const auto& dict : md->GetHelpReg()) {
645: details.push_back(dict);
646: }
1.1.1.5 root 647:
1.1.1.6 root 648: // そこから検索
649: for (const auto& dict : details) {
1.1.1.5 root 650: if (cmd == dict.first) {
651: const auto& desc = dict.second;
652: if (desc[0] == '=') {
653: // "=<cmd>" 形式なら <cmd> を探しなおす。
654: // 別名で同じヘルプを指すシンボリックリンクみたいなもの。
655: cmd = desc.substr(1);
656: try_again = true;
657: break;
658: }
659: // そうでなければこれを表示して終了
660: std::string disp = HelpConvert(dict.second);
661: cons->Print("%s", disp.c_str());
662: return;
663: }
664: }
665: } while (try_again);
666: cons->Print("invalid command name: %s\n", args[1].c_str());
1.1.1.3 root 667: }
668:
1.1.1.5 root 669: // hb : ブレークポイント系コマンドの一覧を表示
670: // こいつだけ結構占めるので別階層。
671: void
672: Debugger::cmd_hb()
673: {
1.1.1.6 root 674: ShowHelpList(HelpListBreakpoints);
1.1.1.5 root 675: }
676:
677: // hr : レジスタ表示系コマンドの一覧を表示
678: // CPU ごとに違うので。
679: void
680: Debugger::cmd_hr()
681: {
1.1.1.6 root 682: ShowHelpList(md->GetHelpListReg());
1.1.1.5 root 683: }
1.1.1.3 root 684:
1.1.1.6 root 685: // ヘルプ一覧を表示。
1.1.1.3 root 686: void
1.1.1.6 root 687: Debugger::ShowHelpList(const HelpMessages& msgs)
1.1.1.3 root 688: {
1.1.1.5 root 689: cons->Print("Type \"help <cmd>\" for indivisual details.\n");
1.1.1.3 root 690: for (const auto& pair : msgs) {
1.1.1.5 root 691: cons->Print(" %-16s %s\n", pair.first.c_str(), pair.second.c_str());
1.1 root 692: }
693: }
694:
1.1.1.5 root 695: // 個別ヘルプメッセージを出力用に置換。
696: // 1. 行頭の連続する改行 (通常は1つのはず) を取り除く。
697: // 2. 末尾の連続するタブ (通常は1つのはず) を取り除く。
698: // 3. (各行頭の) タブを空白4つに置換する。
699: std::string
700: Debugger::HelpConvert(const std::string& src)
701: {
702: int start = 0;
703: int len = src.size();
704:
705: // 末尾の連続するタブをカウント
706: while (src[len - 1] == '\t') {
707: len--;
708: }
709: // 先頭の連続する改行をカウント
710: while (src[start] == '\n') {
711: start++;
712: len--;
713: }
714: std::string stripped = src.substr(start, len);
715:
716: // 面倒なので行頭に関わらず全タブを置換
717: const char *c_stripped = stripped.c_str();
718: std::string dst;
719: for (const char *s = c_stripped; *s; s++) {
720: if (*s == '\t') {
721: dst.append(" ");
722: } else {
723: dst.append(1, *s);
724: }
725: }
726: return dst;
727: }
728:
729: /*static*/ const HelpMessages
1.1.1.6 root 730: Debugger::HelpListMain = {
1.1.1.5 root 731: { "b*", "Set/show Breakpoints (Type \"hb\" for details)" },
732: { "brhist", "Show branch history" },
733: { "c", "Continue" },
734: { "d/dt/D", "Disassemble" },
735: { "disp", "Set register group to show" },
736: { "exhist", "Show exception history" },
737: { "help", "Show this message" },
738: { "L", "Set log level" },
739: { "m/mt/M", "Memory dump" },
740: { "n/nt", "Step until next instruction (Skip subroutines)" },
741: { "quit", "Quit" },
742: { "r*", "Show registers (Type \"hr\" for details)" },
743: { "reset", "Reset the VM" },
744: { "s/st", "Step an instruction (Step in)" },
745: { "so", "Step out" },
746: { "show", "Show monitor" },
747: };
748:
749: /*static*/ const HelpMessages
1.1.1.6 root 750: Debugger::HelpListBreakpoints = {
1.1.1.5 root 751: { "b", "Show all breakpoints" },
752: { "b arg..","Set/Delete breakpoint" },
753: { "bm", "Set memory breakpoint" },
754: { "bi", "Set instruction breakpoint" },
755: { "bv", "Set exception breakpoint" },
756: { "bx", "Delete all breakpoints" },
757: };
758:
759: // 各コマンドの詳細。"コマンド名" => "説明文" の形式。
760: // 説明文は C+11 の生文字リテラル機能を使って R"**( )**" で囲む。
761: // 1つのエントリは
762: // { "cmdname", R"**(
763: // <tab>cmdname [argument...]
764: //
765: // <tab>Description...
766: // <tab>)**" },
767: // のようになる。説明文本文はインデント1つ(TAB 幅 4) で字下げした状態で
768: // 80桁以内に収めること。出力の際にタブを空白4つに置き換えることでソース上
769: // での見た目と実際の出力とを揃えてある。
770: // またソースコード上の見栄えの問題として、文字列の開始記号、終了記号を本文
771: // とは別の行に書いているため、オブジェクトとしての文字列には先頭に改行、
772: // 末尾にタブが余計に入っているが、これは表示の際にコードで取り除く。
773: //
774: // 説明文の書き方は、まずコマンド書式を1行ずつ書く。
775: // コマンド書式と本文との間は1行あける。
776: /*static*/ const HelpMessages
777: Debugger::HelpDetails = {
778: //-----
779: { "b", R"**(
780: Command: b
781: Command: b <address> [<skipcount>]
782: Command: b #n
783:
784: The first form (with no arguments) shows all breakpoints.
785: The second form sets a new breakpoint on <address>.
786: XXX skipcount
787: If <skipcount> is -1, it will never match. It's useful to count the
788: number of times you have passed this address.
789: The third form deletes a breakpoint specified by number.
790: )**" },
791:
792: //-----
793: { "bm", R"**(
794: Command: bm <address> [<skipcount>]
795:
796: Sets a memory breakpoint on <address>.
797: XXX skipcount
798: If <skipcount> is -1, it will never match. It's useful to count the
799: number of times you have passed this address.
800: )**" },
801:
802: //-----
803: { "bi", R"**(
804: Command: bi <inst>[:<mask>] [<skipcount>]
805:
806: Sets an instruction breakpoint. <inst> must be 16 bits or 32 bits on
807: m68k and must be 32 bits on m88k. <mask> can specify the mask. Its
808: length must be the same as <inst>. If the <mask> is ommited, all bits
809: of <inst> is used to compare.
810: For example,
811: "bi 4e75" on m68k will stop at 'rts' instruction.
812: "bi 70004e4f:fff0ffff" on m68k will stop at any of 'IOCS #0'..'IOCS #15'.
813:
814: XXX skipcount
815: If <skipcount> is -1, it will never match. It's useful to count the
816: number of times you have passed this address.
817: )**" },
818:
819: //-----
820: { "bv", R"**(
821: Command: bv <vector>[-<vector2>] [<skipcount>]
822:
823: Sets an exception breakpoint. <vector> must be specified in hex.
824: <vector> ranges from 0 to ff (255 in decimal) on m68k, and 0 to 1ff (511
825: in decimal) on m88k. If <vector2> is specified, it matches the range
826: from <vector> to <vector2> (including themselves).
827: For example, "bv 1-1ff" on m88k means all exceptions but reset.
828: XXX skipcount
829: If <skipcount> is -1, it will never match. It's useful to count the
830: number of times you have passed this address.
831: )**" },
832:
833: //-----
834: { "bx", R"**(
835: Command: bx
836:
837: Deletes all breakpoints.
838: )**" },
839:
840: //-----
841: { "brhist", R"**(
842: Command: brhist [<maxlines>]
843:
844: Show branch history. <maxlines> specifies the maximum number of lines
845: to display. If <maxlines> is negative value, sort in reverse order.
846: )**" },
847:
848: //-----
849: { "c", R"**(
850: Command: c [<address>]
851:
852: Continue (until <address> if specified).
853: )**" },
854:
855: //-----
856: { "d", R"**(
857: Command: D <address>] [<lines>]
1.1.1.6 root 858: Command: d [[<space>:]<address>] [<lines>]
859: Command: dt [[<space>:]<address>] [<lines>]
1.1.1.5 root 860:
861: Shows disassemble.
862: The first form ("D") interprets <address> as a physical address.
863: The second and third form ("d", "dt") interprets <address> as a logical
1.1.1.7 root 864: address if the address translation is enabled. Normally, <address> is
1.1.1.6 root 865: interpreted in the current privilege and current address space. You can
866: change it by <space> modifier.
867: On m68k, <space> can be specified either by function code number directly
868: ('1', '2', '5', and '6) or by one or more following modifiers:
869: 's' .. Supervisor mode 'u' .. User mode
870: 'd' .. Data space 'p' or 'i' .. Program space
871: On m88k, <space> can be specified by using combination of privilege
872: modifier ('s' or 'u', same as above) and following CMMU identifiers:
873: 'd' .. Data CMMU 'i' or 'p' .. Instruction CMMU
874: Or CMMU can also be identified by CMMU number (like '6' or '7').
875:
1.1.1.5 root 876: "d" only looks up in ATC (on m68k) or in BATC/PATC (on m88k).
877: "dt" will simulate to search the page table in addition to that.
878: )**" },
879: { "dt", "=d" },
880: { "D", "=d" },
881:
882: //-----
883: { "disp", R"**(
884: Command: disp <register...>
885:
886: Sets the registers list to be shown in the trace.
887: <registers...> is comma-separated list and each of which is a command
888: name that shows registers. See "hr".
889: The default is "r" and thus it only shows general registers in the trace.
890: For example, if you set "disp r,rf", it will show general registers and
891: FPU registers in every trace.
892: )**" },
893:
894: //-----
895: { "exhist", R"**(
896: Command: exhist [<maxlines>]
897:
898: Show exception history. <maxlines> specifies the maximum number of lines
899: to display. If <maxlines> is negative value, sort in reverse order.
900: )**" },
901:
902: //-----
903: { "help", R"**(
904: Command: help [<command>]
905: Command: hb
906: Command: hr
907:
908: The "help" command without arguments shows the list of commands.
909: The "help" command with an argument shows <command>'s detailed help.
910: "h" is a synonym of "help".
911: The "hb" command shows the list of breakpoint-related commands.
912: The "hr" command shows the list of register-related commands.
913: )**" },
914: { "h", "=help" },
915: { "hb", "=help" },
916: { "hr", "=help" },
917:
918: //-----
919: { "L", R"**(
920: Command: L <name> <level>
921:
922: Set loglevel. XXX To be written...
923: )**" },
924:
925: //-----
926: { "m", R"**(
927: Command: M <address>] [<lines>]
1.1.1.6 root 928: Command: m [[<space>:]<address>] [<lines>]
929: Command: mt [[<space>:]<address>] [<lines>]
1.1.1.5 root 930:
931: Shows memory dump.
932: The first form ("M") interprets <address> as a physical address.
933: The second and third form ("m", "mt") interprets <address> as a logical
934: address if the address translation is enabled. Normally, <address> is
1.1.1.6 root 935: interpreted in the current privilege and current address space. You can
936: change it by <space> modifier.
937: On m68k, <space> can be specified either by function code number directly
938: ('1', '2', '5', and '6) or by one or more following modifiers:
939: 's' .. Supervisor mode 'u' .. User mode
940: 'd' .. Data space 'p' or 'i' .. Program space
941: On m88k, <space> can be specified by using combination of privilege
942: modifier ('s' or 'u', same as above) and following CMMU identifiers:
943: 'd' .. Data CMMU 'i' or 'p' .. Instruction CMMU
944: Or CMMU can also be identified by CMMU number (like '6' or '7').
945:
1.1.1.5 root 946: "m" only looks up in ATC (on m68k) or in BATC/PATC (on m88k).
947: "mt" will simulate to search the page table in addition to that.
948: )**" },
949: { "mt", "=m" },
950: { "M", "=m" },
951:
952: //-----
953: { "n", R"**(
954: Command: n [<count>]
955: Command: nt [<count>]
956:
957: Step one (or <count>) instructions. Unlike "s" command, "n" skips
958: subroutine.
959: If "t" is suffixed, it shows a trace for each instruction (including
960: while skipping).
961: )**" },
962: { "nt", "=n" },
963:
964: //-----
965: { "quit", R"**(
966: Command: quit (or q)
967:
968: Quit the debugger console. This continues the execution, as same as "c".
969: )**" },
970: { "q", "=quit" },
971:
972: //-----
973: { "reset", R"**(
974: Command: reset
975:
976: Reset the VM. Currently this does the hardware reset.
977: )**" },
978:
979: //-----
980: { "s", R"**(
981: Command: s [<count>]
982: Command: st [<count>]
983:
984: Step one (or <count>) instructions. Unlike "n" command, "s" steps in
985: subroutine.
986: If "t" is suffixed, it shows a trace for each instruction.
987:
988: "t" command is a synonym of "st" for backward compatibility.
989: )**" },
990: { "st", "=s" },
991:
992: //-----
993: { "so", R"**(
994: Command: so
995: Command: sot
996:
997: Step out this sub routine.
998: If "t" is suffixed, it shows a trace for each instruction.
999: )**" },
1000:
1001: //-----
1002: { "show", R"**(
1003: Command: show <monitor>
1004:
1005: Shows the specified monitor.
1006: )**" },
1007:
1008: //-----
1009: { "t", "=s" },
1010: };
1011:
1.1.1.3 root 1012: // cmdbuf を args... に分解する。
1.1 root 1013: void
1.1.1.3 root 1014: Debugger::ParseCmdbuf()
1.1 root 1015: {
1.1.1.3 root 1016: int pos;
1017: int start;
1018:
1019: pos = 0;
1020: args.clear();
1.1 root 1021:
1022: // 引数を空白で分解
1.1.1.3 root 1023: for (;;) {
1024: // 先頭の空白はスキップ
1025: for (; cmdbuf[pos] != '\0'; pos++) {
1026: if (!isspace((unsigned int)cmdbuf[pos]))
1027: break;
1028: }
1029: if (cmdbuf[pos] == '\0')
1.1 root 1030: break;
1031:
1.1.1.3 root 1032: // 終わりを探す
1033: start = pos;
1034: for (; cmdbuf[pos] != '\0'; pos++) {
1035: if (isspace((unsigned int)cmdbuf[pos]))
1.1 root 1036: break;
1037: }
1.1.1.3 root 1038: args.push_back(cmdbuf.substr(start, pos - start));
1.1.1.2 root 1039: }
1040: // デバッグ表示
1041: if (0) {
1.1.1.3 root 1042: for (int i = 0 ; i < args.size(); i++) {
1043: printf("args[%d]=|%s|\n", i, args[i].c_str());
1.1.1.2 root 1044: }
1045: }
1.1 root 1046: }
1047:
1048: //
1049: // デバッガコマンド
1050: //
1051:
1052: // ブレークポイント
1.1.1.4 root 1053: // b ... 一覧表示
1054: // b #n ... #n を削除
1055: // b <addr> [<skip>] ... 設定
1.1 root 1056: void
1057: Debugger::cmd_b()
1058: {
1059: // 引数なしなら一覧表示
1.1.1.3 root 1060: if (args.size() < 2) {
1.1 root 1061: return cmd_b_list();
1062: }
1063:
1064: // 引数取得
1.1.1.3 root 1065: if (args[1][0] == '#') {
1.1 root 1066: // #<n> 形式なら、指定番号のブレークポイントを削除
1.1.1.3 root 1067: int i = atoi(&args[1][1]);
1068: if (i < 0 || i >= bpoint.size()) {
1.1.1.4 root 1069: cons->Print("invaild breakpoint number: #%d\n", i);
1.1 root 1070: return;
1071: }
1.1.1.3 root 1072: auto& bp = bpoint[i];
1.1.1.4 root 1073: if (bp.type == BreakpointType::Unused) {
1074: cons->Print("invalid breakpoint number: #%d\n", i);
1075: return;
1.1 root 1076: }
1.1.1.4 root 1077: cons->Print("breakpoint #%d (%08x) removed\n",
1078: i, bp.addr);
1079: bp.type = BreakpointType::Unused;
1080: // 今登録されている命令ブレークの必要命令長を再計算
1081: RecalcInstMask();
1.1 root 1082: return;
1083: }
1084:
1.1.1.4 root 1085: return cmd_b_set(BreakpointType::Address);
1086: }
1087:
1088: // メモリブレークポイントの設定
1089: // bm <addr> [<skip>]
1090: void
1091: Debugger::cmd_bm()
1092: {
1093: // XXX m68k では未サポート
1.1.1.6 root 1094: if (md->arch == Arch::M680x0) {
1.1.1.4 root 1095: cons->Print("bm not supported yet on m68k\n");
1096: return;
1097: }
1098: cmd_b_set(BreakpointType::Memory);
1099: }
1100:
1101: // type が違うだけの各種ブレークポイント設定の共通部分。
1102: void
1103: Debugger::cmd_b_set(BreakpointType type)
1104: {
1105: breakpoint_t bp;
1106:
1107: if (args.size() < 2) {
1108: cons->Print("usage: %s <addr> [<skipcount>]\n", args[0].c_str());
1109: return;
1110: }
1111:
1112: // アドレス
1113: if (!ParseAddr(args[1].c_str(), &bp.addr)) {
1114: return;
1115: }
1116: // あればスキップカウント
1117: if (args.size() > 2) {
1118: bp.skip = atoi(args[2].c_str());
1119: }
1120:
1121: // 空いてるところにセット
1122: // (よく似たエントリがあっても干渉しない)
1123: bp.type = type;
1124: int bi = AddBreakpoint(bp);
1125: if (bi == -1) {
1126: cons->Print("no free breakpoints\n");
1.1 root 1127: } else {
1.1.1.4 root 1128: cons->Print("breakpoint #%d added\n", bi);
1.1.1.3 root 1129: }
1.1.1.4 root 1130: }
1131:
1132: // 命令ブレークポイントの設定
1133: // bi <insn>[:<mask>] [<skip>]
1134: void
1135: Debugger::cmd_bi()
1136: {
1137: breakpoint_t bp;
1138: std::string inststr;
1139: std::string maskstr;
1140: int instlen;
1141: int masklen;
1142:
1143: if (args.size() < 2) {
1144: cons->Print("usage: bi <inst>[:<mask>] [<skipcount>]\n");
1.1.1.3 root 1145: return;
1.1 root 1146: }
1147:
1.1.1.4 root 1148: // 引数をまず分離
1149: auto pos = args[1].find(':');
1150: if (pos == std::string::npos) {
1151: // マスク指定なし
1152: inststr = args[1];
1153: instlen = inststr.size();
1154: masklen = -1;
1155: } else {
1156: // マスク指定あり
1157: inststr = args[1].substr(0, pos);
1158: instlen = inststr.size();
1159: maskstr = args[1].substr(pos + 1);
1160: masklen = maskstr.size();
1161: }
1162:
1163: // 命令部チェック
1164: if (ParseVerbHex(inststr.c_str(), &bp.inst) == false) {
1165: cons->Print("%s: invalid instruction value\n", args[1].c_str());
1166: return;
1167: }
1.1.1.5 root 1168: if (instlen % (md->inst_bytes * 2) != 0) {
1.1.1.4 root 1169: cons->Print("%s: invalid instruction length\n", args[1].c_str());
1170: return;
1171: }
1172:
1173: // マスク部チェック
1174: bp.mask = 0xffffffff;
1175: if (masklen != -1) {
1176: if (ParseVerbHex(maskstr.c_str(), &bp.mask) == false) {
1177: cons->Print("%s: invalid mask value\n", args[1].c_str());
1178: return;
1179: }
1180: if (masklen != instlen) {
1181: cons->Print("%s: inst:mask must be the same length\n",
1182: args[1].c_str());
1.1 root 1183: return;
1184: }
1185: }
1.1.1.4 root 1186: // 8バイト未満なら左詰め。
1.1.1.5 root 1187: if (md->inst_bytes < 4 && instlen < 8) {
1.1.1.4 root 1188: bp.inst <<= 32 - instlen * 4;
1189: bp.mask <<= 32 - instlen * 4;
1190: }
1191:
1192: // あればスキップカウント
1193: bp.skip = 0;
1194: if (args.size() > 2) {
1195: bp.skip = atoi(args[2].c_str());
1196: }
1197:
1198: // 空いてるところにセット
1199: bp.type = BreakpointType::Instruction;
1200: int bi = AddBreakpoint(bp);
1201: if (bi == -1) {
1202: cons->Print("no free breakpoints\n");
1203: } else {
1204: cons->Print("breakpoint #%d added\n", bi);
1205: }
1206:
1207: // 今登録されている命令ブレークの必要命令長を再計算
1208: RecalcInstMask();
1209: }
1210:
1211: // 例外ブレークポイントの設定
1212: // bv <vector_number>[-<end_number>] [<skip>]
1213: void
1214: Debugger::cmd_bv()
1215: {
1216: breakpoint_t bp;
1217:
1218: if (args.size() < 2) {
1219: cons->Print("usage: be <vec#>[-<end#>] [<skipcount>]\n");
1220: return;
1221: }
1222:
1223: auto pos = args[1].find('-');
1224: if (pos == std::string::npos) {
1225: // ベクタ番号が1つなら vec1, vec2 を同値にしておく。
1226: if (ParseVerbHex(args[1].c_str(), (uint32 *)&bp.vec1) == false) {
1227: cons->Print("%s: invalid vector number\n", args[1].c_str());
1228: return;
1229: }
1230: bp.vec2 = bp.vec1;
1231: } else {
1232: // ベクタ番号(範囲指定 [vec1, vec2])
1233: std::string str1 = args[1].substr(0, pos);
1234: std::string str2 = args[1].substr(pos + 1);
1235:
1236: if (ParseVerbHex(str1.c_str(), (uint32 *)&bp.vec1) == false) {
1237: cons->Print("%s: invalid first vector number\n", args[1].c_str());
1238: return;
1239: }
1240: if (ParseVerbHex(str2.c_str(), (uint32 *)&bp.vec2) == false) {
1241: cons->Print("%s: invalid last vector number\n", args[1].c_str());
1242: return;
1243: }
1244: }
1245:
1246: // 範囲チェック
1247: if (bp.vec1 < 0 || bp.vec1 >= md->vector_max) {
1248: cons->Print("$%x: invalid vector number\n", bp.vec1);
1249: return;
1250: }
1251: if (bp.vec2 < 0 || bp.vec2 >= md->vector_max) {
1252: cons->Print("$%x: invalid last vector number\n", bp.vec2);
1253: return;
1254: }
1255:
1256: // 大小が逆なら入れ替える?
1257: if (bp.vec1 > bp.vec2) {
1258: int tmp;
1259: tmp = bp.vec1;
1260: bp.vec1 = bp.vec2;
1261: bp.vec2 = tmp;
1262: }
1263:
1264: // あればスキップカウント
1265: bp.skip = 0;
1266: if (args.size() > 2) {
1267: bp.skip = atoi(args[2].c_str());
1268: }
1.1 root 1269:
1270: // 空いてるところにセット
1.1.1.4 root 1271: bp.type = BreakpointType::Exception;
1272: int bi = AddBreakpoint(bp);
1.1 root 1273: if (bi == -1) {
1.1.1.4 root 1274: cons->Print("no free breakpoints\n");
1.1 root 1275: } else {
1.1.1.4 root 1276: cons->Print("breakpoint #%d added\n", bi);
1.1 root 1277: }
1.1.1.5 root 1278:
1279: // すでに来ている例外をクリア。
1280: // ブレークポイント設定の有無に関わらず例外が起きたら CPU 側から常に
1281: // 通知されている。これをクリアするのは CheckAllBreakpoints() で、これは
1282: // 命令間(命令前)に呼ばれるやつ、なのでこうなる。
1283: // 1. 例外が起きると bv_vector がセットされる
1284: // 2. 例外ブレークポイントを設定していないとこれがクリアされない
1285: // 3. bv コマンドで例外ブレークを新たに設定すると、次の命令境界で
1286: // 1.のベクタが反応してしまう。
1287: // 命令ごととかにクリアしてもいいかも知れないが、ここでブレークポイントを
1288: // 設定したのだから、それ以前の事象には反応すべきでない、という意味では
1289: // ここでもいいか?
1290: bv_vector = -1;
1.1 root 1291: }
1292:
1293: // ブレークポイント一覧表示
1294: void
1295: Debugger::cmd_b_list()
1296: {
1.1.1.4 root 1297: ShowMonitor(*gBreakpointMonitor);
1298: }
1299:
1300: // ブレークポイント一覧 (モニタ)
1301: void
1302: Debugger::MonitorBreakpoint(TextScreen& monitor)
1303: {
1304: // 0 1 2 3 4 5 6
1305: // 0123456789012345678901234567890123456789012345678901234567890
1306: // No Type Parameter Matched Skip
1307: // #0 addr $01234567 123456789 123456789/123456789
1308: // #1 inst 00000000/00000000
1309: // #2 excp $00-$00
1310:
1311: monitor.Clear();
1312: monitor.Print(0, 0, "No Type Parameter");
1313: monitor.Print(26, 0, "Matched");
1314: monitor.Print(37, 0, "Skip");
1.1 root 1315:
1.1.1.3 root 1316: for (int i = 0; i < bpoint.size(); i++) {
1.1.1.4 root 1317: const auto& bp = bpoint[i];
1318: int y = i + 1;
1319:
1320: monitor.Print(0, y, "#%d", i);
1321:
1322: // 種別ごとの表示
1323: switch (bp.type) {
1324: case BreakpointType::Unused:
1325: continue;
1326:
1327: case BreakpointType::Address:
1328: monitor.Print(3, y, "addr $%08x", bp.addr);
1329: break;
1330: case BreakpointType::Memory:
1331: monitor.Print(3, y, "mem $%08x", bp.addr);
1332: break;
1333:
1334: case BreakpointType::Exception:
1335: monitor.Print(3, y, "excp $%02x", bp.vec1);
1336: if (bp.vec2 != bp.vec1) {
1337: monitor.Print(11, y, "-$%02x", bp.vec2);
1338: }
1339: break;
1340:
1341: case BreakpointType::Instruction:
1342: monitor.Print(3, y, "inst");
1.1.1.5 root 1343: if (md->inst_bytes == 4) {
1.1.1.4 root 1344: if (bp.mask == 0xffffffff) {
1345: monitor.Print(8, y, "%08x", bp.inst);
1346: } else {
1347: monitor.Print(8, y, "%08x:%08x", bp.inst, bp.mask);
1348: }
1349: } else {
1350: if (bp.mask == 0xffffffff) {
1351: monitor.Print(8, y, "%08x", bp.inst);
1352: } else if (((bp.inst | bp.mask) & 0x0000ffff) != 0) {
1353: monitor.Print(8, y, "%08x:%08x", bp.inst, bp.mask);
1354: } else if (bp.mask == 0xffff0000) {
1355: monitor.Print(8, y, "%04x", bp.inst >> 16);
1356: } else {
1357: monitor.Print(8, y, "%04x:%04x",
1358: bp.inst >> 16, bp.mask >> 16);
1359: }
1360: }
1361: break;
1362:
1363: default:
1364: monitor.Print(3, y, "type=%d", (int)bp.type);
1365: continue;
1366: }
1367:
1368: // マッチ回数
1369: monitor.Print(26, y, "%d", bp.matched);
1370:
1371: // スキップ
1372: if (bp.skip < 0) {
1373: monitor.Print(37, y, "forever");
1374: } else if (bp.skip > 0) {
1375: monitor.Print(37, y, "%d / %d", (bp.skip - bp.skipremain), bp.skip);
1.1 root 1376: }
1377: }
1378: }
1379:
1380: // ブレークポイント全削除
1381: void
1382: Debugger::cmd_bx()
1383: {
1.1.1.3 root 1384: for (auto& bp : bpoint) {
1.1.1.4 root 1385: bp.type = BreakpointType::Unused;
1.1 root 1386: }
1387: cons->Print(" All breakpoints disabled\n");
1.1.1.4 root 1388:
1389: // 今登録されている命令ブレークの必要命令長を再計算
1390: RecalcInstMask();
1.1 root 1391: }
1392:
1393: // ブレークポイントを設定。
1.1.1.4 root 1394: // new_bp のうち matched, skipremain はこちらで初期化する。
1395: // それ以外を埋めてから呼ぶこと。
1396: // 設定できればその番号、できなければ -1 を返す。
1.1 root 1397: int
1.1.1.4 root 1398: Debugger::AddBreakpoint(const breakpoint_t& new_bp)
1.1 root 1399: {
1.1.1.3 root 1400: for (int i = 0; i < bpoint.size(); i++) {
1401: auto& bp = bpoint[i];
1.1.1.4 root 1402: if (bp.type == BreakpointType::Unused) {
1403: bp = new_bp;
1404: bp.matched = 0;
1405: if (bp.skip > 0) {
1406: bp.skipremain = bp.skip;
1407: } else {
1408: bp.skipremain = 0;
1409: }
1410:
1.1 root 1411: return i;
1412: }
1413: }
1414: return -1;
1415: }
1416:
1.1.1.4 root 1417: // すべての命令ブレークのマスクのうち最長のものを再計算する。
1418: // 命令ブレークポイントの追加/削除のたびに呼び出すこと。
1419: void
1420: Debugger::RecalcInstMask()
1421: {
1422: uint32 mask;
1423: bi_need_bytes = 0;
1424:
1425: // 登録されている命令ブレークの最長マスクを求める
1426: mask = 0;
1427: for (const auto& bp : bpoint) {
1428: if (bp.type == BreakpointType::Instruction) {
1429: mask |= bp.mask;
1430: }
1431: }
1432:
1433: // mask の Number of Trailing Zero を求める。
1434: // (x & -x) で x の最も下の立ってるビットだけを立てる、
1435: // (x & -x) -1 でそれより下の全ビットを立てる、
1436: // それを popcount で数えるので、$fffffff0 なら ntz = 4 になる。
1437: int ntz = __builtin_popcount((mask & -(int32)mask) - 1);
1438: // 上位側から数えたマスクに必要なビット数
1439: int mlen = 32 - ntz;
1440: // 命令語単位に切り上げる
1.1.1.5 root 1441: mlen = roundup(mlen, md->inst_bytes * 8);
1.1.1.4 root 1442: // バイト数に変換
1443: mlen /= 8;
1444:
1445: if (mlen > bi_need_bytes) {
1446: bi_need_bytes = mlen;
1447: }
1448: }
1449:
1450: // ブランチ履歴、例外履歴表示
1451: // brhist [<maxlines>]
1452: // exhist [<maxlines>]
1453: // <maxlines> は表示する最大エントリ数。
1454: // コンソールではデフォルトで下を新しいの順とする。<maxlines> を負数にすると
1455: // (行数は絶対値して) 並び順を逆にしてモニタウィンドウと同じ上を新しいの順に
1456: // する。
1.1 root 1457: void
1458: Debugger::cmd_brhist()
1459: {
1.1.1.4 root 1460: cmd_hist_common(md->GetBrHist(), 0);
1461: }
1462: void
1463: Debugger::cmd_exhist()
1464: {
1465: cmd_hist_common(md->GetExHist(), BranchHistory::ExHist);
1466: }
1.1.1.3 root 1467:
1.1.1.4 root 1468: // ブランチ履歴、例外履歴表示の共通部分。
1469: void
1470: Debugger::cmd_hist_common(BranchHistory& hist, uint64 flag)
1471: {
1472: // 表示最大行数(と向き)
1473: // 向きは bottom_to_top = true が新しいほうを下とする方向。
1474: int maxlines = 20;
1475: bool bottom_to_top = true;
1.1.1.3 root 1476: if (args.size() > 1) {
1.1.1.4 root 1477: maxlines = atoi(args[1].c_str());
1478: if (maxlines < 0) {
1479: bottom_to_top = false;
1480: maxlines = -maxlines;
1.1.1.3 root 1481: }
1.1.1.4 root 1482:
1483: if (maxlines < 1)
1484: maxlines = 1;
1485: if (maxlines > 256)
1486: maxlines = 256;
1487: }
1488:
1489: // コンソールでは空エントリの行は表示したくないので、
1490: // 先にエントリ数を調べる。
1491: int used = hist.GetUsed();
1492:
1493: // 表示行数 + 1行はヘッダ分
1494: int lines = std::min(used, maxlines) + 1;
1495:
1496: // MonitorUpdate() は TextScreen 高さに合わせて出力してくれる。
1497: auto size = hist.GetMonitorSize();
1498: TextScreen tscr;
1499: tscr.Init(size.width, lines);
1500:
1501: // コンソールでは下が新しいの順のほうがいい
1502: if (bottom_to_top) {
1503: flag |= BranchHistory::BottomToTop;
1.1.1.3 root 1504: }
1.1.1.4 root 1505: tscr.userdata = flag;
1506:
1507: // 表示
1508: hist.MonitorUpdate(tscr);
1509: ShowTextScreen(tscr);
1.1 root 1510: }
1511:
1512: // 実行再開(continue): c [<addr>]
1513: // <addr> 指定があれば <addr> まで実行。
1514: void
1515: Debugger::cmd_c()
1516: {
1.1.1.3 root 1517: if (args.size() > 1) {
1.1 root 1518: // 引数があれば
1.1.1.3 root 1519: if (!ParseAddr(args[1].c_str(), &bc_addr)) {
1.1 root 1520: return;
1521: }
1522: // 偶数番地に丸める
1523: bc_addr &= 0xfffffffe;
1524:
1525: bc_enable = true;
1526: }
1527: }
1528:
1.1.1.5 root 1529: // 引数などからアドレスを取得するごった煮共通ルーチン。
1530: //
1.1.1.6 root 1531: // 引数がなければ sa->addr には書き込まずに true で帰る (ので、呼び出し側が
1532: // 事前に適切なデフォルト値をセットしておくと、それがそのまま使われる)。
1.1.1.3 root 1533: // 引数が1つ(以上)あれば args[1] をアドレスとしてパースする。
1.1.1.6 root 1534: // アドレスには空間修飾子を前置可能、省略の場合はいずれも現在値を使う。
1535: // エラーならメッセージを表示して false を返す。
1.1.1.5 root 1536: // sa は in/out パラメータ。
1.1 root 1537: bool
1.1.1.6 root 1538: Debugger::GetAddr(saddr_t *sa, bool default_data)
1.1 root 1539: {
1.1.1.5 root 1540: if (args.size() < 2) {
1.1.1.6 root 1541: // 引数なしなら、呼び出し側が sa にセットした前回値をそのまま使う。
1.1.1.5 root 1542: return true;
1543: }
1544:
1.1.1.6 root 1545: // 引数ありならパースする。アドレスが明示的に指定されたので、
1546: // ここから先の省略箇所は前回値ではなくデフォルト値で補完する。
1547:
1.1.1.5 root 1548: std::string& str = args[1];
1549: uint32 addr;
1550:
1.1.1.6 root 1551: // ':' があればその前はアドレス空間修飾子
1552: int mod_super = -1; // 'u'/'s'
1553: int mod_prog = -1; // 'd'/'p' or 'd'/'i'
1554: int mod_num = -1; // '0'..'7'
1555: auto addrpos = str.find(':');
1556: if (addrpos == std::string::npos) {
1557: // なければ先頭からアドレス
1558: addrpos = 0;
1559: } else {
1560: // ':' が途中にあれば、その前が修飾子。
1561: // ':' が先頭なら修飾子が空文字列という扱いでいいか。
1562: std::string mod = str.substr(0, addrpos);
1563: addrpos++;
1564: for (auto ch : mod) {
1565: if (ch == 'u') {
1566: if (mod_super == 1)
1567: goto error;
1568: mod_super = 0;
1569: } else if (ch == 's') {
1570: if (mod_super == 0)
1571: goto error;
1572: mod_super = 1;
1573: } else if (ch == 'd') {
1574: if (mod_prog == 1)
1575: goto error;
1576: mod_prog = 0;
1577: } else if (ch == 'p' || ch == 'i') {
1578: // m68k では 'P'rogram space、m88k では 'I'nstruction CMMU…
1579: if (mod_prog == 0)
1580: goto error;
1581: mod_prog = 1;
1582: } else if ('0' <= ch && ch <= '7') {
1583: int num = ch - '0';
1584: if (md->arch == Arch::M680x0) {
1585: // m68k では FC 指定は Super/User 指定を含んでおり、
1586: // 値指定は他の修飾子とは同時に指定できない。
1587: if (mod_super >= 0 || mod_prog >= 0 ||
1588: (mod_num >= 0 && mod_num != num)) {
1589: goto error;
1590: }
1591: // 有効な値は 1,2,5,6 のみ
1592: if (num == 0 || num == 3 || num == 4 || num == 7) {
1593: cons->Print("%c: invalid address space\n", ch);
1594: }
1595: mod_num = num;
1596: mod_super = mod_num >> 2; // FC2
1597: mod_prog = (mod_num & 3) - 1; // FC1,FC0
1598: } else if (md->arch == Arch::M88xx0) {
1599: // m88k では CMMU 指定と、Super/User 指定は独立。
1600: if (mod_prog >= 0 ||
1601: (mod_num >= 0 && mod_num != num)) {
1602: goto error;
1603: }
1604: mod_num = num;
1605: mod_prog = (mod_num & 1); // CMMU7 が Inst
1606: }
1607: } else {
1608: cons->Print("%c: unknown address space modifier\n", ch);
1609: return false;
1610: }
1611: continue;
1612:
1613: error:
1614: cons->Print("%s: address space modifier '%c' conflicts\n",
1615: mod.c_str(), ch);
1616: return false;
1617: }
1618:
1619: // 数値指定を機種ごとに読み替える
1620: if (mod_num >= 0) {
1621: if (md->arch == Arch::M680x0) {
1622: // m68k なら値指定で全部確定する
1623: // "1:" -> User/Data
1624: // "2:" -> User/Program
1625: // "5:" -> Super/Data
1626: // "6:" -> Super/Program
1627: mod_super = (mod_num & 4) ? true : false;
1628: mod_prog = (mod_num & 3) - 1;
1629: } else if (md->arch == Arch::M88xx0) {
1630: // m88k では mod_num を CMMU ID とする(?)。
1631: // XXX まだ CPU は1つしかないので雑に処理。
1632: // "6" -> Data (CPU#0)
1633: // "7" -> Program (CPU#0)
1634: if (mod_num < 6) {
1635: cons->Print("%d: CMMU#%d not installed\n",
1636: mod_num, mod_num);
1637: return false;
1638: }
1639: mod_prog = mod_num - 6;
1640: }
1641: }
1.1 root 1642: }
1.1.1.5 root 1643:
1.1.1.6 root 1644: // アドレス空間修飾子のうち省略箇所はデフォルト状態で補完
1645: // - 's'/'u' いずれもなければ現在値。
1646: // - 'd'/'p'/'i' いずれもなければ、d/m コマンドごとに自然なほう。
1647: if (mod_super < 0) {
1648: mod_super = md->IsSuper();
1649: }
1650: if (mod_prog < 0) {
1651: mod_prog = !default_data;
1652: }
1653: sa->SetSuper(mod_super);
1654: sa->SetData(!mod_prog);
1655:
1.1.1.5 root 1656: // アドレス
1657: if (ParseAddr(str.c_str() + addrpos, &addr) == false) {
1658: return false;
1659: }
1.1.1.7 root 1660: // 命令境界に丸める
1661: sa->SetAddr(addr & ~(md->inst_bytes - 1));
1.1.1.5 root 1662:
1.1 root 1663: return true;
1664: }
1665:
1.1.1.5 root 1666: // 逆アセンブル: d [[SU:]<addr> [<cnt>]] (論理、テーブルサーチなし)
1.1 root 1667: void
1668: Debugger::cmd_d()
1669: {
1.1.1.6 root 1670: cmd_d_common(MemoryMode::Logical, MMULookupMode::False);
1.1 root 1671: }
1672:
1.1.1.5 root 1673: // 逆アセンブル: dt [[SU:]<addr>] [<cnt>]] (論理、テーブルサーチあり)
1.1 root 1674: void
1675: Debugger::cmd_dt()
1676: {
1.1.1.6 root 1677: cmd_d_common(MemoryMode::Logical, MMULookupMode::True);
1.1 root 1678: }
1679:
1680: // 逆アセンブル: D [<addr> [<cnt>]] (物理)
1681: void
1682: Debugger::cmd_D()
1683: {
1.1.1.6 root 1684: cmd_d_common(MemoryMode::Physical, MMULookupMode::None);
1.1 root 1685: }
1686:
1687: // 逆アセンブル共通
1688: void
1.1.1.6 root 1689: Debugger::cmd_d_common(MemoryMode access_mode, MMULookupMode lookup_mode)
1.1 root 1690: {
1.1.1.2 root 1691: saddr_t saddr;
1.1 root 1692: int cnt;
1693:
1694: cnt = 10;
1695:
1696: // 開始アドレス
1.1.1.6 root 1697: saddr = d_last_addr;
1698: if (GetAddr(&saddr, false) == false) {
1.1 root 1699: return;
1700: }
1701: // 2つ目の引数があれば行数
1.1.1.3 root 1702: if (args.size() > 2) {
1703: cnt = strtol(args[2].c_str(), NULL, 10);
1.1 root 1704: }
1705:
1.1.1.6 root 1706: DebuggerMemoryStream mem(md, saddr, access_mode, lookup_mode);
1.1.1.2 root 1707:
1.1 root 1708: for (int i = 0; i < cnt; i++) {
1.1.1.2 root 1709: std::string addrbuf;
1710: std::string mnemonic;
1711: std::string mnembuf;
1712: std::vector<uint8> local_ir;
1713:
1.1.1.6 root 1714: // アドレス
1715: if (mem.FormatAddr(addrbuf) == false) {
1716: // アドレス変換でバスエラーならここで終了
1717: cons->Print("%s\n", addrbuf.c_str());
1718: break;
1.1 root 1719: }
1.1.1.6 root 1720:
1721: // 逆アセンブル
1722: md->Disassemble(mem, mnemonic, local_ir);
1723: // オフライン用に整形
1724: mnembuf = md->FormatDisasm(mnemonic, local_ir);
1725:
1.1.1.2 root 1726: cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str());
1727:
1728: // 変換できなければここで終了
1729: if (local_ir.size() == 0)
1730: break;
1.1 root 1731: }
1.1.1.2 root 1732:
1.1.1.6 root 1733: // アドレスと Super/User 状態を次回継続用に保存
1734: d_last_addr = mem.laddr;
1.1 root 1735: }
1736:
1.1.1.5 root 1737: // 表示レジスタ選択
1738: // disp 現在の内容を表示
1739: // disp <regs>... 設定
1740: void
1741: Debugger::cmd_disp()
1742: {
1743: if (args.size() < 2) {
1744: // 表示
1745: bool first = true;
1746: for (const auto& r : disp_regs) {
1747: cons->Print("%s%s", (first ? "" : ","), r.c_str());
1748: first = false;
1749: }
1750: cons->Print("\n");
1751: return;
1752: }
1753:
1754: // 設定 (引数を分解する)
1755: char buf[256];
1756: char *p;
1757: char *last;
1758: strlcpy(buf, args[1].c_str(), sizeof(buf));
1759: disp_regs.clear();
1760: for (p = strtok_r(buf, ",", &last); p; p = strtok_r(NULL, ",", &last)) {
1761: disp_regs.push_back(std::string(p));
1762: }
1763:
1764: // XXX チェック
1765: }
1766:
1.1 root 1767: // ログレベル設定: L <name> <level>
1768: void
1769: Debugger::cmd_L()
1770: {
1771: const char *name;
1772: int level;
1773:
1.1.1.3 root 1774: if (args.size() < 3) {
1.1 root 1775: cons->Print("L <name> <level>\n");
1776: return;
1777: }
1778:
1.1.1.3 root 1779: name = args[1].c_str();
1780: level = atoi(args[2].c_str());
1.1 root 1781:
1782: // 短縮形とかエイリアスとか
1783: // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい
1784: if (strcmp(name, "sch") == 0)
1785: name = "scheduler";
1786: if (strcmp(name, "scc") == 0)
1787: name = "sio";
1788:
1.1.1.3 root 1789: // 複数のオブジェクトが同じ logname を持ってもよい (CMMUとか)。
1.1 root 1790: // all はどうするか
1791: std::string sname = name;
1792: bool found = false;
1793: for (auto& obj : gObjects) {
1794: if (obj->logname == sname) {
1795: obj->loglevel = level;
1796: cons->Print("%s=%d\n", name, obj->loglevel);
1797: found = true;
1798: }
1799: }
1800: // 見付からない場合はエラー
1801: if (!found) {
1802: cons->Print("%s: invalid logname\n", name);
1803: }
1804: }
1805:
1806: // メモリダンプ: m [<addr> [<cnt>]] (論理、テーブルサーチなし)
1807: void
1808: Debugger::cmd_m()
1809: {
1.1.1.6 root 1810: cmd_m_common(MemoryMode::Logical, MMULookupMode::False);
1.1 root 1811: }
1812:
1813: // メモリダンプ: mt [<addr> [<cnt>]] (論理、テーブルサーチあり)
1814: void
1815: Debugger::cmd_mt()
1816: {
1.1.1.6 root 1817: cmd_m_common(MemoryMode::Logical, MMULookupMode::True);
1.1 root 1818: }
1819:
1820: // メモリダンプ: M [<addr> [<cnt>]] (物理)
1821: void
1822: Debugger::cmd_M()
1823: {
1.1.1.6 root 1824: cmd_m_common(MemoryMode::Physical, MMULookupMode::None);
1.1 root 1825: }
1826:
1827: // メモリダンプ共通
1828: void
1.1.1.6 root 1829: Debugger::cmd_m_common(MemoryMode access_mode, MMULookupMode lookup_mode)
1.1 root 1830: {
1.1.1.2 root 1831: saddr_t saddr;
1.1 root 1832: int cnt;
1833:
1834: cnt = 10;
1835:
1836: // 開始アドレス
1.1.1.6 root 1837: saddr = m_last_addr;
1838: if (GetAddr(&saddr, true) == false) {
1.1 root 1839: return;
1840: }
1841: // 2つ目の引数があれば行数
1.1.1.3 root 1842: if (args.size() > 2) {
1843: cnt = strtol(args[2].c_str(), NULL, 10);
1.1 root 1844: }
1845:
1.1.1.6 root 1846: DebuggerMemoryStream mem(md, saddr, access_mode, lookup_mode);
1.1.1.2 root 1847:
1.1 root 1848: for (int i = 0; i < cnt; i++) {
1.1.1.2 root 1849: std::string addrbuf;
1850: std::string dumpbuf;
1851: std::string charbuf;
1852:
1.1.1.6 root 1853: // アドレス
1854: if (mem.FormatAddr(addrbuf) == false) {
1855: // アドレス変換でバスエラーならここで終了
1.1.1.2 root 1856: cons->Print("%s\n", addrbuf.c_str());
1857: break;
1858: }
1859:
1860: for (int j = 0; j < 8; j++) {
1861: for (int k = 0; k < 2; k++) {
1.1.1.6 root 1862: uint64 b = mem.Fetch8();
1.1.1.2 root 1863:
1864: if ((int64)b < 0) {
1865: dumpbuf += "--";
1866: charbuf += " ";
1867: } else {
1868: uint32 c = (uint32)b;
1869: dumpbuf += string_format("%02x", c);
1870: charbuf += string_format("%c",
1871: (0x20 <= c && c <= 0x7e) ? c : '.');
1872: }
1873: }
1874: dumpbuf += " ";
1875: }
1.1.1.6 root 1876:
1.1.1.2 root 1877: cons->Print("%-18s %-40s %s\n",
1878: addrbuf.c_str(), dumpbuf.c_str(), charbuf.c_str());
1.1 root 1879: }
1.1.1.6 root 1880:
1881: // アドレスと Super/User 状態を次回継続用に保存
1882: m_last_addr = mem.laddr;
1.1 root 1883: }
1884:
1885: // プロンプトに来た最初に表示するいつものやつを再表示する
1886: void
1887: Debugger::cmd_minus()
1888: {
1.1.1.5 root 1889: // 指定のレジスタ群を表示
1890: // disp_regs はレジスタ群のリスト { "r", "rf" } のような感じ。
1891: // 一方 ShowRegisters() の第2引数は1つのコマンドラインを空白で区切った
1892: // 文字列リスト { arg[0], arg[1], .. }。型が同じで意味が違うので注意。
1893: for (const auto& reg : disp_regs) {
1894: std::vector<std::string> tmpargs;
1895: tmpargs.push_back(reg);
1896: md->ShowRegister(cons, tmpargs);
1897: }
1.1 root 1898:
1.1.1.2 root 1899: // 現在の PC の位置を逆アセンブル。ここで ir を更新。
1900: std::string addrbuf;
1901: std::string mnemonic;
1902: std::string mnembuf;
1903: ir.clear();
1.1.1.6 root 1904:
1905: // 論理アクセス時、ATC ミスが分かったほうが便利だと思うので lookup なし
1906: saddr_t laddr(pc, md->IsSuper());
1907: DebuggerMemoryStream mem(md, laddr);
1908: // アドレス
1909: if (mem.FormatAddr(addrbuf) == false) {
1910: cons->Print("%s\n", addrbuf.c_str());
1911: return;
1.1.1.2 root 1912: }
1.1.1.6 root 1913: // 逆アセンブル
1914: md->Disassemble(mem, mnemonic, ir);
1915: // ライブ表示用に整形
1916: mnembuf = md->FormatDisasmLive(mnemonic, ir);
1917:
1.1.1.2 root 1918: cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str());
1.1 root 1919: }
1920:
1.1.1.5 root 1921: // サブルーチンとループを飛ばしながら count 命令ステップ実行
1922: // n [<count>?:1] (途中レジスタを表示しない)
1.1 root 1923: void
1924: Debugger::cmd_n()
1925: {
1.1.1.5 root 1926: cmd_n_common(false);
1927: }
1928:
1929: // サブルーチンとループを飛ばしながら count 命令ステップ実行
1930: // nt [<count>?:1] (1命令ずつレジスタを表示する)
1931: void
1932: Debugger::cmd_nt()
1933: {
1934: cmd_n_common(true);
1935: }
1936:
1937: // n と nt の共通部分
1938: void
1939: Debugger::cmd_n_common(bool trace)
1940: {
1941: t_enable = trace;
1942:
1.1.1.3 root 1943: if (args.size() > 1) {
1.1 root 1944: int count;
1.1.1.3 root 1945: count = strtol(args[1].c_str(), NULL, 10);
1.1 root 1946: if (count < 1) {
1947: cons->Print(" invalid step count: %d\n", count);
1948: return;
1949: }
1950:
1951: n_count = count;
1952: } else {
1953: n_count = 1;
1954: }
1955: n_enable = true;
1956: SetNBreakpoint();
1957: }
1958:
1.1.1.5 root 1959: // n コマンド用のブレークポイントを設定する。
1960: // この命令語によって仕掛けるブレークポイントが変わるので、都度都度
1961: // 呼び出すこと。
1962: void
1.1 root 1963: Debugger::SetNBreakpoint()
1964: {
1.1.1.6 root 1965: saddr_t laddr(md->GetPC(), md->IsSuper());
1966: DebuggerMemoryStream mem(md, laddr);
1.1.1.5 root 1967:
1.1.1.6 root 1968: // 命令がサブルーチンやトラップなどステップインできる命令か。
1969: if (md->IsOpStepIn(mem)) {
1.1.1.5 root 1970: // この次の命令にブレークをかける
1971: if (md->inst_bytes_fixed != 0) {
1972: // 固定長命令
1.1.1.6 root 1973: n_breakaddr = (uint32)mem.laddr;
1.1.1.5 root 1974: } else {
1975: // 可変長なら逆アセンブルしてみるしか
1976: std::string mnemonic;
1977: std::vector<uint8> v;
1978: // XXX 失敗したらどうすべ
1.1.1.6 root 1979: mem.ResetAddr(md->GetPC());
1980: md->Disassemble(mem, mnemonic, v);
1981: n_breakaddr = (uint32)mem.laddr;
1.1.1.5 root 1982: }
1.1 root 1983: } else {
1.1.1.5 root 1984: // そうでなければ1命令進める。
1985: // 0xffffffff は常にアドレスとして不正なのでこれをフラグに使う。
1986: n_breakaddr = 0xffffffff;
1.1 root 1987: }
1988: }
1989:
1.1.1.2 root 1990: // デバッガ終了コマンド
1991: void
1992: Debugger::cmd_q()
1993: {
1994: cons->Print("quit debugger console.\n");
1.1 root 1995: }
1996:
1.1.1.5 root 1997: // VM リセット
1998: void
1999: Debugger::cmd_reset()
2000: {
2001: gScheduler->RequestResetHard();
2002: }
2003:
1.1 root 2004: // モニター表示
2005: void
2006: Debugger::cmd_show()
2007: {
1.1.1.3 root 2008: if (args.size() != 2) {
1.1 root 2009: cons->Print("usage: show <monitor>\n");
2010: for (auto& d : gObjects) {
2011: if (d->logname != "?") {
2012: cons->Print(" %s\n", d->logname.c_str());
2013: }
2014: }
2015: return;
2016: }
2017:
1.1.1.3 root 2018: std::string name = args[1];
1.1 root 2019: for (auto& d : gObjects) {
2020: if (d->logname == name) {
1.1.1.3 root 2021: ShowMonitor(*d);
1.1 root 2022: return;
2023: }
2024: }
2025: // 一致しない
2026: cons->Print("show: no such objects\n");
2027: }
2028:
1.1.1.3 root 2029: // モニターを更新して表示。
2030: void
1.1.1.4 root 2031: Debugger::ShowMonitor(IMonitor& monitor)
1.1.1.3 root 2032: {
2033: // モニタを更新
1.1.1.4 root 2034: TextScreen ts;
2035:
2036: auto size = monitor.GetMonitorSize();
2037: ts.Init(size.width, size.height);
2038:
2039: monitor.MonitorUpdate(ts);
2040: ShowTextScreen(ts);
1.1.1.3 root 2041: }
2042:
2043: // テキストスクリーンを表示。
1.1 root 2044: void
1.1.1.3 root 2045: Debugger::ShowTextScreen(TextScreen& monitor)
1.1 root 2046: {
2047: char sbuf[1024]; // 適当
2048:
2049: // monitor 内部バッファから ShiftJIS バッファを作成。
2050: // その際属性もエスケープシーケンスで再現する。
2051: int col = monitor.GetCol();
2052: int row = monitor.GetRow();
1.1.1.8 ! root 2053: const std::vector<uint16>& src = monitor.GetBuf();
1.1 root 2054:
2055: for (int y = 0; y < row; y++) {
2056: int sy = y * col;
2057: int sx;
2058: uint attr;
2059: char *d;
2060:
2061: memset(sbuf, 0, sizeof(sbuf));
2062: d = sbuf;
2063: attr = TA::Normal;
2064: for (sx = 0; sx < col; sx++) {
2065: uint a = src[sy + sx] & 0xff00;
2066: uint ch = src[sy + sx] & 0x00ff;
2067:
2068: // 属性の変わり目
2069: if (attr != a) {
2070: switch (a) {
2071: case TA::Normal:
2072: case TA::Off:
2073: *d++ = 0x1b;
2074: *d++ = '[';
2075: *d++ = 'm';
2076: break;
2077: case TA::On:
2078: *d++ = 0x1b;
2079: *d++ = '[';
2080: *d++ = '7';
2081: *d++ = 'm';
2082: break;
2083: case TA::Disable:
2084: *d++ = 0x1b;
2085: *d++ = '[';
2086: *d++ = '2';
2087: *d++ = 'm';
2088: break;
2089: case TA::Em:
2090: *d++ = 0x1b;
2091: *d++ = '[';
2092: *d++ = '1';
2093: *d++ = 'm';
2094: break;
2095: }
2096: attr = a;
2097: }
2098: *d++ = ch;
2099: }
1.1.1.3 root 2100: // 行の終わりで一旦属性を戻しておく
2101: if (attr != TA::Normal) {
2102: *d++ = 0x1b;
2103: *d++ = '[';
2104: *d++ = 'm';
2105: }
1.1 root 2106: *d = '\0';
2107:
2108: // XXX 日本語が使われてれば UTF-8 にしないといけないはず
2109:
2110: cons->Print("%s\n", sbuf);
2111: }
2112: }
2113:
1.1.1.5 root 2114: // ステップ実行
2115: // s [<count>?:1] (途中レジスタを表示しない)
1.1 root 2116: void
2117: Debugger::cmd_s()
2118: {
1.1.1.5 root 2119: cmd_s_common(false);
2120: }
2121:
2122: // ステップ実行
2123: // st [<count>?:1] (命令ごとにレジスタを表示する)
2124: void
2125: Debugger::cmd_st()
2126: {
2127: cmd_s_common(true);
2128: }
2129:
2130: // ステップ実行共通部分
2131: void
2132: Debugger::cmd_s_common(bool trace)
2133: {
2134: t_enable = trace;
2135:
1.1.1.3 root 2136: if (args.size() > 1) {
1.1 root 2137: int count;
1.1.1.3 root 2138: count = strtol(args[1].c_str(), NULL, 10);
1.1 root 2139: if (count < 1) {
2140: cons->Print(" invalid step count: %d\n", count);
2141: return;
2142: }
2143:
2144: s_count = count;
2145: } else {
2146: s_count = 1;
2147: }
2148: s_enable = true;
2149: }
2150:
1.1.1.5 root 2151: // ステップアウト (途中レジスタを表示しない)
1.1 root 2152: void
2153: Debugger::cmd_so()
2154: {
1.1.1.5 root 2155: cmd_so_common(false);
2156: }
2157:
2158: // ステップアウト (命令ごとにレジスタを表示する)
2159: void
2160: Debugger::cmd_sot()
2161: {
2162: cmd_so_common(true);
2163: }
2164:
2165: // ステップアウトの共通部分
2166: void
2167: Debugger::cmd_so_common(bool trace)
2168: {
2169: t_enable = trace;
2170:
1.1 root 2171: so_enable = true;
1.1.1.2 root 2172: md->SetStepOut();
1.1 root 2173: }
2174:
1.1.1.5 root 2175: // t は st の省略形。互換のため。
1.1 root 2176: void
2177: Debugger::cmd_t()
2178: {
1.1.1.5 root 2179: cmd_st();
1.1 root 2180: }
2181:
1.1.1.4 root 2182: // 引数で示されるプレフィックスなしの16進数値を返す。
2183: // 正しく変換できれば値を valp に格納して true を返す。
2184: // そうでなければ false を返す。
2185: bool
2186: Debugger::ParseVerbHex(const char *arg, uint32 *valp)
2187: {
2188: uint32 val;
2189: char *end;
2190:
2191: errno = 0;
2192: val = strtoul(arg, &end, 16);
2193: if (arg[0] == '\0' || end[0] != '\0') {
2194: return false;
2195: }
2196: if (errno == ERANGE) {
2197: return false;
2198: }
2199:
2200: *valp = val;
2201: return true;
2202: }
2203:
1.1 root 2204: // 引数で示されるアドレスを返す。
2205: // '%' で始まればレジスタ。
2206: // そうでなければ16進数値。
2207: // アドレスが正しく取得できればアドレスを addr に格納し真を返す。
2208: // そうでなければエラーメッセージを表示して偽を返す。
2209: bool
1.1.1.4 root 2210: Debugger::ParseAddr(const char *arg, uint32 *addrp)
1.1 root 2211: {
1.1.1.4 root 2212: uint32 addr;
1.1 root 2213: char *end;
2214:
2215: if (arg[0] == '%') {
1.1.1.2 root 2216: // '%' から始まればレジスタ
2217: uint64 r;
2218: r = md->GetRegAddr(arg + 1);
2219: if ((int64)r < 0) {
2220: #if 0 // not yet
1.1 root 2221: cons->Print("valid register name are: %s%s\n",
2222: "%d0-%d7,%a0-%a7,%sp,%usp,%isp,%pc",
2223: ",%msp,%vbr,%srp,%crp");
1.1.1.2 root 2224: #endif
2225: cons->Print("invalid register name\n");
1.1 root 2226: return false;
2227: }
1.1.1.2 root 2228: addr = (uint32)r;
1.1 root 2229: } else {
2230: /* そうでなければ番地指定 */
2231: errno = 0;
2232: addr = strtoul(arg, &end, 16);
2233: if (arg[0] == '\0' || end[0] != '\0') {
2234: cons->Print("invalid address: '%s'\n", arg);
2235: return false;
2236: }
2237: if (errno == ERANGE) {
2238: cons->Print("out of range: %s\n", arg);
2239: return false;
2240: }
2241: }
2242:
2243: *addrp = addr;
2244: return true;
2245: }
2246:
1.1.1.4 root 2247:
2248: //
1.1.1.5 root 2249: // MD
2250: //
2251:
1.1.1.6 root 2252: // デストラクタ
2253: DebuggerMD::~DebuggerMD()
2254: {
1.1.1.5 root 2255: }
2256:
2257:
2258: //
1.1.1.4 root 2259: // ブレークポイントモニター
2260: //
2261:
2262: // コンストラクタ
2263: BreakpointMonitor::BreakpointMonitor()
2264: {
2265: monitor_size = nnSize(55, 9);
2266: }
2267:
2268: void
2269: BreakpointMonitor::MonitorUpdate(TextScreen& monitor)
2270: {
2271: gDebugger->MonitorBreakpoint(monitor);
2272: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.