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

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

unix.superglobalmegacorp.com

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