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

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

unix.superglobalmegacorp.com

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