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