Annotation of nono/debugger/debugger.cpp, revision 1.1.1.20

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.