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

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

unix.superglobalmegacorp.com

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