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