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

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

unix.superglobalmegacorp.com

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