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

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

unix.superglobalmegacorp.com

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