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