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