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