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