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

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2019 [email protected]
                      4: //
                      5: 
1.1.1.2 ! root        6: #include "console.h"
        !             7: #include "debugger_private.h"
        !             8: #include "debugger_m680x0.h"
        !             9: #include "debugger_m88xx0.h"
        !            10: #include "mainapp.h"
1.1       root       11: #include "mpu.h"
                     12: #include "mystring.h"
                     13: #include <csignal>
                     14: 
                     15: Debugger *gDebugger;
                     16: CVPrompt *gCVPrompt;
                     17: 
                     18: static void *debugger_run(void *);
                     19: 
                     20: // 初期化。
                     21: // この時点で VM が初期化されていること。
                     22: void
                     23: debugger_init()
                     24: {
                     25:        gDebugger = new Debugger();
                     26:        gDebugger->Init();
                     27: 
                     28:        gCVPrompt = new CVPrompt();
                     29: 
                     30:        // デバッガスレッド起動
                     31:        pthread_t th;
                     32:        pthread_create(&th, NULL, debugger_run, NULL);
                     33: }
                     34: 
                     35: // デバッガスレッドのエントリポイント
                     36: static void *
                     37: debugger_run(void *dummy)
                     38: {
                     39:        pthread_setname_np("Debugger");
                     40:        pthread_detach(pthread_self());
                     41: 
                     42:        gDebugger->ThreadRun();
                     43:        return NULL;
                     44: }
                     45: 
                     46: // コンストラクタ
                     47: Debugger::Debugger()
                     48: {
1.1.1.2 ! root       49:        if (gMPU680x0) {
        !            50:                md = new DebuggerMD_m680x0(this, gMPU680x0->GetCPU());
        !            51:        } else if (gMPU88xx0) {
        !            52:                md = new DebuggerMD_m88xx0(this, gMPU88xx0->GetCPU());
        !            53:        } else {
        !            54:                throw "unknown mpu";
        !            55:        }
1.1       root       56: }
                     57: 
                     58: // コマンドライン引数によって動作を決めるところ。
                     59: // 名前がこれでいいのかはあるけど。
                     60: void
                     61: Debugger::Init()
                     62: {
                     63:        // -d なら CPU 起動時点で停止してプロンプトを待つ
1.1.1.2 ! root       64:        if (gMainApp.debug_on_start) {
        !            65:                md->ReqSet(CPU_REQ_PROMPT);
1.1       root       66:        }
                     67: 
                     68:        // -b <addr> ならブレークポイント設定
1.1.1.2 ! root       69:        if (gMainApp.debug_breakaddr != 0xffffffff) {
        !            70:                md->ReqSet(CPU_REQ_TRACE);
        !            71:                AddBreakpoint(gMainApp.debug_breakaddr, false);
1.1       root       72:        }
                     73: 
                     74:        // どこでやるべか
                     75:        signal(SIGPIPE, SIG_IGN);
                     76: }
                     77: 
                     78: // デバッガスレッド
                     79: void
                     80: Debugger::ThreadRun()
                     81: {
                     82:        // XXX どこかでコンソールの選択とパラメータの取得
1.1.1.2 ! root       83:        if (gMainApp.debug_on_console) {
        !            84:                cons = new ConsoleStdio();
        !            85:        } else {
        !            86:                cons = new ConsoleTCP();
        !            87:        }
1.1       root       88:        if (cons->Init() == false) {
                     89:                return;
                     90:        }
                     91: 
                     92:        for (;;) {
                     93:                cons->Open();
1.1.1.2 ! root       94:                cons->InitEditLine("> ");
1.1       root       95:                cons->Print("This is debugger console\n");
                     96: 
                     97:                // 接続ごとに初期化する値
                     98:                // XXX もうちょっときれいにしたい
                     99:                d_last_addr = 0xffffffff;
                    100:                m_last_addr = 0xffffffff;
                    101:                n_enable = false;
                    102:                s_enable = false;
                    103:                t_enable = false;
                    104:                is_continued = true;
                    105: 
                    106:                // コンソールが繋がっている間がトレースオン
                    107:                // コンソールが繋がるとプロンプトになる
1.1.1.2 ! root      108:                md->ReqSet(CPU_REQ_TRACE | CPU_REQ_PROMPT);
1.1       root      109:                while (MainLoop() == true)
                    110:                        ;
                    111:                // コンソールを抜ける時はCPUの停止を解除。
1.1.1.2 ! root      112:                md->ReqClr(CPU_REQ_TRACE);
1.1       root      113:                gCVPrompt->NotifyRelease();
                    114: 
                    115:                cons->Close();
                    116:        }
                    117: 
                    118:        delete cons;
                    119: }
                    120: 
                    121: // プロンプト処理のメイン部分。
                    122: // false を返すとコンソールをクローズする。
                    123: bool
                    124: Debugger::MainLoop()
                    125: {
                    126:        // プロンプトが取れるのを待つ
1.1.1.2 ! root      127:        for (;;) {
        !           128:                bool is_prompt = gCVPrompt->WaitAcquire(200);
        !           129:                if (is_prompt) break;
        !           130: 
        !           131:                // コンソールを定期観測して、入力があればブレーク要求
        !           132:                if (cons->Poll()) {
        !           133:                        // この入力は drop してみる
        !           134:                        if (cons->Gets(cmdbuf) == false) {
        !           135:                                // EOF or Error
        !           136:                                cmd_q();
        !           137:                                return false;
        !           138:                        }
        !           139:                        md->ReqSet(CPU_REQ_PROMPT);
        !           140:                }
        !           141:        }
1.1       root      142: 
                    143:        // VM 実行からプロンプトに来たとき
                    144:        if (is_continued) {
                    145:                is_continued = false;
                    146: 
1.1.1.2 ! root      147:                pc = md->GetPC();
1.1       root      148:                d_last_addr = pc;
                    149:                // プロンプトに来た時に表示するいつものやつ
                    150:                cmd_minus();
                    151:        }
                    152: 
1.1.1.2 ! root      153:        cons->Prompt();
        !           154:        if (cons->Gets(cmdbuf) == false) {
        !           155:                // EOF or Error
        !           156:                cmd_q();
1.1       root      157:                return false;
                    158:        }
                    159: 
1.1.1.2 ! root      160:        string_rtrim(cmdbuf);
1.1       root      161: 
1.1.1.2 ! root      162:        if (!cmdbuf.empty()) {
1.1       root      163:                // コマンドが入力されれば次回のために保存
1.1.1.2 ! root      164:                last_cmdbuf = cmdbuf;
1.1       root      165:        } else {
                    166:                // 空行が入力されれば直前のコマンドをもう一度
                    167:                // 前行がなければ何もせずもう一度プロンプトを表示するかね
1.1.1.2 ! root      168:                if (last_cmdbuf.empty())
1.1       root      169:                        return true;
1.1.1.2 ! root      170:                cmdbuf = last_cmdbuf;
1.1       root      171:        }
                    172: 
                    173:        // 行を cmd, ac, av に分解
                    174:        cmddef_t *cmd = ParseCmd();
                    175: 
                    176:        // 前回の値が有効なのはコマンドが連続した時だけ
                    177: 
                    178:        // コマンド実行
                    179:        (this->*(cmd->func))();
1.1.1.2 ! root      180: 
        !           181:        // 終了コマンドによる終了処理
        !           182:        return (cmd->func != &Debugger::cmd_q);
1.1       root      183: }
                    184: 
                    185: // ブレークポイントとかを調べる。
                    186: // CPU_REQ_TRACE フラグが立っている間1命令ごとに呼び出される。
                    187: bool
                    188: debugger_check()
                    189: {
                    190:        return gDebugger->Check();
                    191: }
                    192: 
                    193: // デバッガ実行中なら命令開始前にメインルーチンから呼ばれる。
                    194: // プロンプトに降りるなら true を返す。
                    195: bool
                    196: Debugger::Check()
                    197: {
                    198:        if (t_enable) {
                    199:                t_count--;
                    200:                if (t_count == 0) {
                    201:                        t_enable = false;
                    202:                        return true;
                    203:                }
                    204:        }
                    205: 
                    206:        if (s_enable) {
                    207:                s_count--;
                    208:                if (s_count == 0) {
                    209:                        s_enable = false;
                    210:                        return true;
                    211:                }
                    212:        }
                    213: 
                    214:        // n による1命令実行のブレークポイントか
1.1.1.2 ! root      215:        if (n_enable && n_breakenable && n_breakaddr == md->GetPC()) {
1.1       root      216:                n_breakenable = false;
                    217:                return true;
                    218:        }
                    219: 
                    220:        // アドレス
                    221:        for (int i = 0; i < countof(bpoint); i++) {
                    222:                breakpoint_t *bp = &bpoint[i];
                    223:                if (bp->enable) {
1.1.1.2 ! root      224:                        if (bp->ismemory) {
        !           225:                                if (md->CheckLEA(bp->addr)) {
        !           226:                                        bp->count++;
        !           227:                                        return true;
        !           228:                                }
        !           229:                        } else {
        !           230:                                if (bp->addr == md->GetPC()) {
        !           231:                                        bp->count++;
        !           232:                                        return true;
        !           233:                                }
1.1       root      234:                        }
                    235:                }
                    236:        }
                    237: 
                    238:        // ステップアウト
                    239:        if (so_enable) {
1.1.1.2 ! root      240:                if (md->IsStepOut()) {
1.1       root      241:                        so_enable = false;
                    242:                        return true;
                    243:                }
                    244:        }
                    245: 
                    246:        // アドレス指定付き continue
                    247:        if (bc_enable) {
1.1.1.2 ! root      248:                if (bc_addr == md->GetPC()) {
1.1       root      249:                        bc_enable = false;
                    250:                        return true;
                    251:                }
                    252:        }
                    253: 
                    254:        return false;
                    255: }
                    256: 
                    257: // コマンド一覧。
1.1.1.2 ! root      258: // quit コマンドによるメインループ終了は MainLoop() 側で処理してある。
1.1       root      259: Debugger::cmddef_t Debugger::cmdtable[] = {
                    260:        { "bx",         &Debugger::cmd_bx, },
                    261:        { "b",          &Debugger::cmd_b, },
                    262:        { "brhist",     &Debugger::cmd_brhist },
                    263:        { "c",          &Debugger::cmd_c, },
                    264:        { "d",          &Debugger::cmd_d, },
                    265:        { "dt",         &Debugger::cmd_dt, },
                    266:        { "D",          &Debugger::cmd_D, },
                    267:        { "h",          &Debugger::cmd_h, },
                    268:        { "L",          &Debugger::cmd_L, },
                    269:        { "m",          &Debugger::cmd_m, },
                    270:        { "mt",         &Debugger::cmd_mt, },
                    271:        { "M",          &Debugger::cmd_M, },
                    272:        { "n",          &Debugger::cmd_n, },
1.1.1.2 ! root      273:        { "q",          &Debugger::cmd_q, },
        !           274:        { "quit",       &Debugger::cmd_q, },
1.1       root      275:        { "r",          &Debugger::cmd_r, },
                    276:        { "ra",         &Debugger::cmd_ra, },
1.1.1.2 ! root      277:        { "rc",         &Debugger::cmd_rc, },
1.1       root      278:        { "rf",         &Debugger::cmd_rf, },
                    279:        { "rm",         &Debugger::cmd_rm, },
                    280:        { "ro",         &Debugger::cmd_ro, },
                    281:        { "s",          &Debugger::cmd_s, },
                    282:        { "so",         &Debugger::cmd_so, },
                    283:        { "show",       &Debugger::cmd_show, },
                    284:        { "t",          &Debugger::cmd_t, },
                    285:        { "-",          &Debugger::cmd_minus },
                    286: };
                    287: Debugger::cmddef_t Debugger::cmdtable_unknown = {
                    288:        .name = "",
                    289:        .func = &Debugger::cmd_unknown,
                    290: };
                    291: 
                    292: // ヘルプ
                    293: void
                    294: Debugger::cmd_h()
                    295: {
                    296:        if (ac == 1) {
                    297:                // 引数なし
                    298:                HelpMain();
                    299:                return;
                    300:        } else {
                    301:                // 引数あり(今の所対応していない)
                    302:                HelpMain();
                    303:                return;
                    304:        }
                    305: }
                    306: 
                    307: void
                    308: Debugger::HelpMain()
                    309: {
                    310:        cons->Print(" b         ブレークポイント一覧表示\n");
                    311:        cons->Print(" b #n      ブレークポイント n を削除\n");
                    312:        cons->Print(" b $<addr> メモリブレークポイント設定\n");
                    313:        cons->Print(" b <addr>  ブレークポイント設定\n");
                    314:        cons->Print(" bx        ブレークポイント全削除\n");
                    315:        cons->Print(" brhist    ブランチ履歴表示\n");
                    316:        cons->Print(" c [<addr>] 実行再開(continue)\n");
                    317:        cons->Print(" d  [<addr> [<lines>]  逆アセンブル(論理、テーブルサーチなし)\n");
                    318:        cons->Print(" dt [<addr> [<lines>]  逆アセンブル(論理、テーブルサーチあり)\n");
                    319:        cons->Print(" D  [<addr> [<lines>]  逆アセンブル(物理)\n");
                    320:        cons->Print(" h         ヘルプ(help)\n");
                    321:        cons->Print(" L <name>=<lv> ログレベル設定\n");
                    322:        cons->Print(" m  [<addr> [<lines>]  メモリダンプ(論理、テーブルサーチなし)\n");
                    323:        cons->Print(" mt [<addr> [<lines>]  メモリダンプ(論理、テーブルサーチあり)\n");
                    324:        cons->Print(" M  [<addr> [<lines>]  メモリダンプ(物理)\n");
                    325:        cons->Print(" n <cnt?:1> ステップ実行 (サブルーチンを飛ばす)\n");
                    326:        cons->Print(" q         quit\n");
1.1.1.2 ! root      327:        cons->Print(" r         通常レジスタを表示\n");
        !           328:        cons->Print(" ra        ATC を表示\n");
        !           329:        cons->Print(" rc        制御レジスタを表示 (m88xx0)\n");
        !           330:        cons->Print(" rf        FPU レジスタを表示\n");
        !           331:        cons->Print(" rm        MMU レジスタを表示\n");
        !           332:        cons->Print(" ro        その他のレジスタを表示\n");
1.1       root      333:        cons->Print(" so                ステップアウト\n");
                    334:        cons->Print(" show <monitor> モニター表示\n");
                    335:        cons->Print(" t <cnt?:1> トレース実行\n");
                    336: }
                    337: 
                    338: // 知らないコマンドを処理するというコマンド
                    339: void
                    340: Debugger::cmd_unknown()
                    341: {
                    342:        cons->Print("%s: unknown command\n", av[0]);
                    343: }
                    344: 
                    345: // cmdbuf を cmd, ac, av に分解する。
                    346: // コマンド(の1ワード目)が一致しなければ cmd_unknown を返し、
                    347: // 終了コマンドと一致したら NULL を返す。
                    348: Debugger::cmddef_t *
                    349: Debugger::ParseCmd()
                    350: {
1.1.1.2 ! root      351:        char buf[cmdbuf.length() + 1];
1.1       root      352:        char *p;
                    353:        cmddef_t *cmd;
                    354: 
1.1.1.2 ! root      355:        strcpy(buf, cmdbuf.c_str());
        !           356:        p = buf;
1.1       root      357:        ac = 0;
                    358:        memset(&av, 0, sizeof(av));
                    359: 
                    360:        // 引数を空白で分解
                    361:        for (; ac < countof(av); ) {
                    362:                // 先頭の空白は取り除く
                    363:                while (isspace((int)*p))
                    364:                        p++;
                    365:                if (*p == '\0')
                    366:                        break;
                    367: 
                    368:                av[ac++] = p;
                    369:                // 次の空白まで進める
                    370:                for (; *p != '\0'; p++) {
                    371:                        if (isspace((int)*p))
                    372:                                break;
                    373:                }
                    374:                if (*p != '\0')
                    375:                        *p++ = '\0';
                    376:        }
1.1.1.2 ! root      377:        // buf はスコープを抜けると無効なので、
        !           378:        // コピーを取って挿げ替え
        !           379:        for (int i = 0; i < ac; i++) {
        !           380:                strav[i] = av[i];
        !           381:                av[i] = strav[i].c_str();
        !           382:        }
        !           383:        // デバッグ表示
        !           384:        if (0) {
        !           385:                for (int i = 0; i < ac; i++) {
        !           386:                        printf("av[%d]=|%s|\n", i, av[i]);
        !           387:                }
        !           388:        }
1.1       root      389: 
                    390:        // コマンドを探す
                    391:        for (int i = 0; i < countof(cmdtable); i++) {
                    392:                cmd = &cmdtable[i];
                    393: 
                    394:                if (strcmp(av[0], cmd->name) == 0)
                    395:                        return cmd;
                    396:        }
                    397: 
                    398:        // 見つからなければ cmd_unknown コマンドを実行。
                    399:        return &cmdtable_unknown;
                    400: }
                    401: 
                    402: //
                    403: // デバッガコマンド
                    404: //
                    405: 
                    406: // ブレークポイント
                    407: void
                    408: Debugger::cmd_b()
                    409: {
                    410:        // 引数なしなら一覧表示
                    411:        if (ac < 2) {
                    412:                return cmd_b_list();
                    413:        }
                    414: 
                    415:        // 引数取得
                    416:        if (av[1][0] == '#') {
                    417:                // #<n> 形式なら、指定番号のブレークポイントを削除
                    418:                int i = atoi(&av[1][1]);
                    419:                if (i < 0 || i >= MAX_BREAKPOINTS) {
                    420:                        cons->Print("invaild break point number: #%d\n", i);
                    421:                        return;
                    422:                }
                    423:                breakpoint_t *bp = &bpoint[i];
                    424:                if (bp->enable) {
                    425:                        cons->Print("%sbreakpoint #%d (%08x) removed\n",
                    426:                                bp->ismemory ? "memory " : "", i, bp->addr);
                    427:                        bp->enable = false;
                    428:                } else {
                    429:                        cons->Print("breakpoint #%d not enabled\n", i);
                    430:                }
                    431:                return;
                    432:        }
                    433: 
                    434:        bool ismemory;
                    435:        uint32 addr;
                    436:        if (av[1][0] == '$') {
                    437:                // $<n> 形式ならメモリブレークポイント
                    438:                ismemory = true;
                    439:                addr = strtoul(&av[1][1], NULL, 16);
                    440:        } else {
                    441:                // そうでなければアドレス指定
                    442:                ismemory = false;
                    443:                addr = strtoul(av[1], NULL, 16);
                    444:        }
                    445: 
                    446:        // すでにあればそのブレークポイントを削除
                    447:        for (int i = 0; i < MAX_BREAKPOINTS; i++) {
                    448:                breakpoint_t *bp = &bpoint[i];
                    449:                if (bp->enable && bp->ismemory == ismemory && bp->addr == addr) {
                    450:                        bp->enable = false;
                    451:                        cons->Print("%sbreakpoint #%d (%08x) removed\n",
                    452:                                bp->ismemory ? "memory " : "", i, bp->addr);
                    453:                        return;
                    454:                }
                    455:        }
                    456: 
                    457:        // 空いてるところにセット
                    458:        int bi = AddBreakpoint(addr, ismemory);
                    459:        if (bi == -1) {
                    460:                cons->Print("no free breakpoints!\n");
                    461:        } else {
                    462:                breakpoint_t *bp = &bpoint[bi];
                    463:                cons->Print("%sbreakpoint #%d (%08x) added\n",
                    464:                        bp->ismemory ? "memory " : "", bi, bp->addr);
                    465:        }
                    466: }
                    467: 
                    468: // ブレークポイント一覧表示
                    469: void
                    470: Debugger::cmd_b_list()
                    471: {
                    472:        int found = 0;
                    473: 
                    474:        for (int i = 0; i < MAX_BREAKPOINTS; i++) {
                    475:                breakpoint_t *bp = &bpoint[i];
                    476:                if (bp->enable) {
                    477:                        cons->Print(" #%d %s%08x %d\n",
                    478:                                i,
                    479:                                bp->ismemory ? "memory $" : "",
                    480:                                bp->addr, bp->count);
                    481:                        found = 1;
                    482:                }
                    483:        }
                    484:        if (found == 0) {
                    485:                cons->Print(" No breakpoints enabled\n");
                    486:        }
                    487: }
                    488: 
                    489: // ブレークポイント全削除
                    490: void
                    491: Debugger::cmd_bx()
                    492: {
                    493:        for (int i = 0; i < MAX_BREAKPOINTS; i++) {
                    494:                breakpoint_t *bp = &bpoint[i];
                    495:                bp->enable = false;
                    496:        }
                    497:        cons->Print(" All breakpoints disabled\n");
                    498: }
                    499: 
                    500: // ブレークポイントを設定。
                    501: // 設定できればその番号、できなければ -1 を返す
                    502: // TODO 重複の処理とか
                    503: int
                    504: Debugger::AddBreakpoint(uint32 addr, bool ismemory)
                    505: {
                    506:        for (int i = 0; i < countof(bpoint); i++) {
                    507:                breakpoint_t *bp = &bpoint[i];
                    508:                if (!bp->enable) {
                    509:                        bp->enable = true;
                    510:                        bp->addr = addr;
                    511:                        bp->ismemory = ismemory;
                    512:                        bp->count = 0;
                    513:                        return i;
                    514:                }
                    515:        }
                    516:        return -1;
                    517: }
                    518: 
                    519: // ブランチ履歴表示
                    520: void
                    521: Debugger::cmd_brhist()
                    522: {
                    523:        gMPUBrHist->MonitorUpdate();
                    524:        ShowMonitor(gMPUBrHist->monitor);
                    525: }
                    526: 
                    527: // 実行再開(continue): c [<addr>]
                    528: // <addr> 指定があれば <addr> まで実行。
                    529: void
                    530: Debugger::cmd_c()
                    531: {
                    532:        if (ac > 1) {
                    533:                // 引数があれば
                    534:                if (!ParseAddr(av[1], &bc_addr)) {
                    535:                        return;
                    536:                }
                    537:                // 偶数番地に丸める
                    538:                bc_addr &= 0xfffffffe;
                    539: 
                    540:                bc_enable = true;
                    541:        }
                    542:        Continue();
                    543: }
                    544: 
                    545: // 実行再開
                    546: void
                    547: Debugger::Continue()
                    548: {
                    549:        is_continued = true;
                    550: 
                    551:        // 今のレジスタセットを次回との差分のためにバックアップしておく
1.1.1.2 ! root      552:        md->BackupRegs();
1.1       root      553: 
                    554:        gCVPrompt->NotifyRelease();
                    555: }
                    556: 
                    557: // 引数などからアドレスを取得する共通ルーチン。
                    558: // 引数が1つ(以上)あれば av[1] をアドレスとしてパースする。
                    559: // なければ、lastaddr が指定されていればそれを使う。
1.1.1.2 ! root      560: // それもなければ現在の PC を使う。
1.1       root      561: bool
                    562: Debugger::GetAddr(uint32& addr, uint32& lastaddr)
                    563: {
                    564:        if (ac > 1) {
                    565:                // 1つ目の引数があれば、開始アドレス
                    566:                if (ParseAddr(av[1], &addr) == false) {
                    567:                        return false;
                    568:                }
                    569:                // 偶数番地からに丸める
                    570:                addr &= 0xfffffffe;
                    571:        } else if (lastaddr != 0xffffffff) {
                    572:                // 引数なしで前回値があれば前回の続き
                    573:                addr = lastaddr;
                    574:        } else {
                    575:                // そうでなければ、今の PC
1.1.1.2 ! root      576:                addr = md->GetPC();
1.1       root      577:        }
                    578:        return true;
                    579: }
                    580: 
                    581: // 逆アセンブル: d [<addr> [<cnt>]] (論理、テーブルサーチなし)
                    582: void
                    583: Debugger::cmd_d()
                    584: {
                    585:        cmd_d_common(MemdumpMode::Logical_atc);
                    586: }
                    587: 
                    588: // 逆アセンブル: dt [<addr>] [<cnt>]] (論理、テーブルサーチあり)
                    589: void
                    590: Debugger::cmd_dt()
                    591: {
                    592:        cmd_d_common(MemdumpMode::Logical_search);
                    593: }
                    594: 
                    595: // 逆アセンブル: D [<addr> [<cnt>]] (物理)
                    596: void
                    597: Debugger::cmd_D()
                    598: {
                    599:        cmd_d_common(MemdumpMode::Physical);
                    600: }
                    601: 
                    602: // 逆アセンブル共通
                    603: void
                    604: Debugger::cmd_d_common(MemdumpMode mode)
                    605: {
                    606:        uint32 addr;
1.1.1.2 ! root      607:        saddr_t saddr;
1.1       root      608:        int cnt;
                    609: 
                    610:        cnt = 10;
                    611: 
                    612:        // 開始アドレス
                    613:        if (GetAddr(addr, d_last_addr) == false) {
                    614:                return;
                    615:        }
                    616:        // 2つ目の引数があれば行数
                    617:        if (ac > 2) {
                    618:                cnt = strtol(av[2], NULL, 10);
                    619:        }
                    620: 
1.1.1.2 ! root      621:        saddr.addr  = addr;
        !           622:        saddr.super = md->IsSuper();
        !           623: 
        !           624:        // XXX そのうちなんとかする
        !           625:        if (mode == MemdumpMode::Logical_search) {
        !           626:                saddr.logical = true;
        !           627:                saddr.search = true;
        !           628:        } else if (mode == MemdumpMode::Logical_atc) {
        !           629:                saddr.logical = true;
        !           630:        }
        !           631: 
1.1       root      632:        for (int i = 0; i < cnt; i++) {
1.1.1.2 ! root      633:                std::string addrbuf;
        !           634:                std::string mnemonic;
        !           635:                std::string mnembuf;
        !           636:                std::vector<uint8> local_ir;
        !           637: 
        !           638:                if (FormatDumpAddr(saddr, addrbuf)) {
        !           639:                        md->Disassemble(saddr, mnemonic, local_ir);
        !           640:                        // オフライン用に整形
        !           641:                        mnembuf = md->FormatDisasm(mnemonic, local_ir);
1.1       root      642:                }
1.1.1.2 ! root      643:                // アドレス変換でバスエラーが起きてもここは表示する
        !           644:                cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str());
        !           645: 
        !           646:                // 変換できなければここで終了
        !           647:                if (local_ir.size() == 0)
        !           648:                        break;
        !           649:                saddr.addr += local_ir.size();
1.1       root      650:        }
1.1.1.2 ! root      651: 
        !           652:        d_last_addr = saddr.addr;
1.1       root      653: }
                    654: 
                    655: // ログレベル設定: L <name> <level>
                    656: void
                    657: Debugger::cmd_L()
                    658: {
                    659:        const char *name;
                    660:        int level;
                    661: 
                    662:        if (ac < 3) {
                    663:                cons->Print("L <name> <level>\n");
                    664:                return;
                    665:        }
                    666: 
                    667:        name = av[1];
                    668:        level = atoi(av[2]);
                    669: 
                    670:        // 短縮形とかエイリアスとか
                    671:        // lib/mainapp.cpp に同じものがあるのでどうにかしたほうがいい
                    672:        if (strcmp(name, "sch") == 0)
                    673:                name = "scheduler";
                    674:        if (strcmp(name, "scc") == 0)
                    675:                name = "sio";
                    676: 
                    677:        // all はどうするか
                    678:        std::string sname = name;
                    679:        bool found = false;
                    680:        for (auto& obj : gObjects) {
                    681:                if (obj->logname == sname) {
                    682:                        obj->loglevel = level;
                    683:                        cons->Print("%s=%d\n", name, obj->loglevel);
                    684:                        found = true;
                    685:                        break;
                    686:                }
                    687:        }
                    688:        // 見付からない場合はエラー
                    689:        if (!found) {
                    690:                cons->Print("%s: invalid logname\n", name);
                    691:        }
                    692: }
                    693: 
                    694: // メモリダンプ: m [<addr> [<cnt>]] (論理、テーブルサーチなし)
                    695: void
                    696: Debugger::cmd_m()
                    697: {
                    698:        cmd_m_common(MemdumpMode::Logical_atc);
                    699: }
                    700: 
                    701: // メモリダンプ: mt [<addr> [<cnt>]] (論理、テーブルサーチあり)
                    702: void
                    703: Debugger::cmd_mt()
                    704: {
                    705:        cmd_m_common(MemdumpMode::Logical_search);
                    706: }
                    707: 
                    708: // メモリダンプ: M [<addr> [<cnt>]] (物理)
                    709: void
                    710: Debugger::cmd_M()
                    711: {
                    712:        cmd_m_common(MemdumpMode::Physical);
                    713: }
                    714: 
                    715: // メモリダンプ共通
                    716: void
                    717: Debugger::cmd_m_common(MemdumpMode mode)
                    718: {
                    719:        uint32 addr;
1.1.1.2 ! root      720:        saddr_t saddr;
1.1       root      721:        int cnt;
                    722: 
                    723:        cnt = 10;
                    724: 
                    725:        // 開始アドレス
                    726:        if (GetAddr(addr, m_last_addr) == false) {
                    727:                return;
                    728:        }
                    729:        // 2つ目の引数があれば行数
                    730:        if (ac > 2) {
                    731:                cnt = strtol(av[2], NULL, 10);
                    732:        }
                    733: 
1.1.1.2 ! root      734:        saddr.addr  = addr;
        !           735:        saddr.super = md->IsSuper();
        !           736:        // XXX
        !           737:        if (mode == MemdumpMode::Logical_search) {
        !           738:                saddr.logical = true;
        !           739:                saddr.search = true;
        !           740:        } else if (mode == MemdumpMode::Logical_atc) {
        !           741:                saddr.logical = true;
        !           742:        }
        !           743: 
1.1       root      744:        for (int i = 0; i < cnt; i++) {
1.1.1.2 ! root      745:                std::string addrbuf;
        !           746:                std::string dumpbuf;
        !           747:                std::string charbuf;
        !           748: 
        !           749:                if (FormatDumpAddr(saddr, addrbuf) == false) {
        !           750:                        // アドレス変換でバスエラーならダンプもくそもない
        !           751:                        cons->Print("%s\n", addrbuf.c_str());
        !           752:                        // ここで終わる?
        !           753:                        // XXX 16バイト先を試してみるとか?
        !           754:                        break;
        !           755:                }
        !           756: 
        !           757:                for (int j = 0; j < 8; j++) {
        !           758:                        uint64 paddr;
        !           759:                        // もう一回アドレス変換するのやや冗長だが仕方ない
        !           760:                        if (saddr.IsLogical() && md->MMUEnabled()) {
        !           761:                                // アドレス変換
        !           762:                                paddr = md->TranslateAddr(saddr);
        !           763:                                if ((int64)paddr < 0) {
        !           764:                                        // バスエラーが起きたら改行して仕切り直し
        !           765:                                        break;
        !           766:                                }
        !           767:                        } else {
        !           768:                                paddr = saddr.addr;
        !           769:                        }
        !           770: 
        !           771:                        for (int k = 0; k < 2; k++) {
        !           772:                                uint64 b = vm_phys_peek_8(paddr + k);
        !           773: 
        !           774:                                if ((int64)b < 0) {
        !           775:                                        dumpbuf += "--";
        !           776:                                        charbuf += " ";
        !           777:                                } else {
        !           778:                                        uint32 c = (uint32)b;
        !           779:                                        dumpbuf += string_format("%02x", c);
        !           780:                                        charbuf += string_format("%c",
        !           781:                                                (0x20 <= c && c <= 0x7e) ? c : '.');
        !           782:                                }
        !           783:                        }
        !           784:                        dumpbuf += " ";
        !           785:                        saddr.addr += 2;
        !           786:                }
        !           787:                cons->Print("%-18s %-40s %s\n",
        !           788:                        addrbuf.c_str(), dumpbuf.c_str(), charbuf.c_str());
1.1       root      789:        }
1.1.1.2 ! root      790:        m_last_addr = saddr.addr;
1.1       root      791: }
                    792: 
                    793: // プロンプトに来た最初に表示するいつものやつを再表示する
                    794: void
                    795: Debugger::cmd_minus()
                    796: {
                    797:        cmd_r();
                    798: 
                    799:        // 論理アクセス時、ATC ミスが分かったほうが便利だと思う
1.1.1.2 ! root      800:        saddr_t laddr;
        !           801:        laddr.addr  = pc;
        !           802:        laddr.super = md->IsSuper();
        !           803:        laddr.logical = true;
        !           804:        laddr.search = false;
        !           805: 
        !           806:        // 現在の PC の位置を逆アセンブル。ここで ir を更新。
        !           807:        std::string addrbuf;
        !           808:        std::string mnemonic;
        !           809:        std::string mnembuf;
        !           810:        ir.clear();
        !           811:        // アドレスを表示用に
        !           812:        if (FormatDumpAddr(laddr, addrbuf)) {
        !           813:                md->Disassemble(laddr, mnemonic, ir);
        !           814:                // ライブ表示用に整形
        !           815:                mnembuf = md->FormatDisasmLive(mnemonic, ir);
        !           816:        }
        !           817:        cons->Print("%-18s %s\n", addrbuf.c_str(), mnembuf.c_str());
        !           818: 
        !           819:        // XXX m88k?
        !           820:        nextpc = pc + ir.size();
1.1       root      821: }
                    822: 
                    823: // ステップ実行: n[<count>?=1] (サブルーチンを飛ばす)
                    824: void
                    825: Debugger::cmd_n()
                    826: {
                    827:        if (ac > 1) {
                    828:                int count;
                    829:                count = strtol(av[1], NULL, 10);
                    830:                if (count < 1) {
                    831:                        cons->Print(" invalid step count: %d\n", count);
                    832:                        return;
                    833:                }
                    834: 
                    835:                n_count = count;
                    836:        } else {
                    837:                n_count = 1;
                    838:        }
                    839:        n_enable = true;
                    840:        SetNBreakpoint();
                    841:        Continue();
                    842: }
                    843: 
                    844: // n コマンド用のサブルーチンを飛ばすブレークポイントを設定。
                    845: // 戻り値は、プロンプトをスキップするなら true。
                    846: bool
                    847: Debugger::SetNBreakpoint()
                    848: {
                    849:        // n コマンドは、通常はブレークポイントを次の命令に仕掛けながら
                    850:        // 実行するが、いくつかの命令ではブレークポイントではなく、
                    851:        // 命令トレース (t コマンド) のように動作させる。
                    852:        // トレース動作する命令は以下の通り。
                    853:        //  Bcc, BRA
                    854:        //  JMP
                    855:        //  RTD, RTR, RTS
                    856:        //  RTE
                    857:        //  FBcc
                    858:        //  FDBcc (2ワード目無視)
                    859:        //  (RTM は 68020 専用なので対応しない)
                    860: #define IsBcc(x)       ((((x) & 0xf000) == 0x6000) && (((x) & 0xff00) != 0x6100))
                    861: #define IsJMP(x)       (((x) & 0xffc0) == 0x4ec0)
                    862: #define IsRTD(x)       (((x) & 0xffff) == 0x4e74)
                    863: #define IsRTE(x)       (((x) & 0xffff) == 0x4e73)
                    864: #define IsRTR(x)       (((x) & 0xffff) == 0x4e77)
                    865: #define IsRTS(x)       (((x) & 0xffff) == 0x4e75)
                    866: #define IsFBcc(x)      (((x) & 0xf180) == 0xf080)
                    867: #define IsFDBcc(x)     (((x) & 0xf1f8) == 0xf048)
                    868: 
                    869:        uint16 op;
                    870: 
                    871:        // XXX この辺統一的にしたほうがいい
                    872:        // XXX logical peek のような気がする
1.1.1.2 ! root      873:        op = (((uint16)vm_phys_peek_8(pc)) << 8)
        !           874:           | vm_phys_peek_8(pc + 1);
1.1       root      875: 
                    876:        if (IsBcc(op)
                    877:         || IsJMP(op)
                    878:         || IsRTD(op)
                    879:         || IsRTE(op)
                    880:         || IsRTR(op)
                    881:         || IsRTS(op)
                    882:         || IsFBcc(op)
                    883:         || IsFDBcc(op)
                    884:        ) {
                    885:                n_breakenable = false;
                    886:                s_enable = true;
                    887:                s_count = 1;
                    888:                return false;
                    889:        } else {
                    890:                n_breakenable = true;
                    891:                n_breakaddr = nextpc;
                    892:                return true;
                    893:        }
                    894: }
                    895: 
1.1.1.2 ! root      896: // デバッガ終了コマンド
        !           897: void
        !           898: Debugger::cmd_q()
        !           899: {
        !           900:        cons->Print("quit debugger console.\n");
        !           901: 
        !           902:        // XXX: このフラグでいいのかとか exit でいいのかとか
        !           903:        if (gMainApp.debug_on_console) {
        !           904:                // コンソールモードのときはプログラムも終了
        !           905:                exit(0);
        !           906:        }
        !           907: }
        !           908: 
1.1       root      909: // レジスタ表示
                    910: // rf: FPU レジスタを表示
                    911: // rm: MMU レジスタを表示
                    912: // r<それ以外>: 通常レジスタを表示?
                    913: void
                    914: Debugger::cmd_r()
                    915: {
                    916:        if (ac > 1) {
                    917:                int arg = av[1][0];
                    918:                switch (arg) {
                    919:                 case 'a':
                    920:                        ShowMonitor(gMPUATC->monitor);
                    921:                        return;
1.1.1.2 ! root      922:                 case 'c':
        !           923:                        md->ShowRegCtrl(cons);
        !           924:                        return;
1.1       root      925:                 case 'f':
1.1.1.2 ! root      926:                        md->ShowRegFPU(cons);
1.1       root      927:                        return;
                    928:                 case 'm':
1.1.1.2 ! root      929:                        md->ShowRegMMU(cons);
1.1       root      930:                        return;
                    931:                 case 'o':
1.1.1.2 ! root      932:                        md->ShowRegOther(cons);
1.1       root      933:                        return;
                    934:                }
                    935:        }
1.1.1.2 ! root      936:        md->ShowRegMain(cons);
1.1       root      937: }
                    938: 
                    939: // ショートカット
                    940: void
                    941: Debugger::cmd_ra()
                    942: {
1.1.1.2 ! root      943:        md->ShowRegATC(cons);
        !           944: }
        !           945: void
        !           946: Debugger::cmd_rc()
        !           947: {
        !           948:        md->ShowRegCtrl(cons);
1.1       root      949: }
                    950: void
                    951: Debugger::cmd_rf()
                    952: {
1.1.1.2 ! root      953:        md->ShowRegFPU(cons);
1.1       root      954: }
                    955: void
                    956: Debugger::cmd_rm()
                    957: {
1.1.1.2 ! root      958:        md->ShowRegMMU(cons);
1.1       root      959: }
                    960: void
                    961: Debugger::cmd_ro()
                    962: {
1.1.1.2 ! root      963:        md->ShowRegOther(cons);
1.1       root      964: }
                    965: 
                    966: // モニター表示
                    967: void
                    968: Debugger::cmd_show()
                    969: {
                    970:        if (ac != 2) {
                    971:                cons->Print("usage: show <monitor>\n");
                    972:                for (auto& d : gObjects) {
                    973:                        if (d->logname != "?") {
                    974:                                cons->Print(" %s\n", d->logname.c_str());
                    975:                        }
                    976:                }
                    977:                return;
                    978:        }
                    979: 
                    980:        std::string name(av[1]);
                    981:        for (auto& d : gObjects) {
                    982:                if (d->logname == name) {
                    983:                        // ここで更新して..
                    984:                        if (d->MonitorUpdate()) {
                    985:                                // 表示
                    986:                                ShowMonitor(d->monitor);
                    987:                        } else {
                    988:                                // モニターがない場合
                    989:                                cons->Print("show: %s has no monitor\n", av[1]);
                    990:                        }
                    991:                        return;
                    992:                }
                    993:        }
                    994:        // 一致しない
                    995:        cons->Print("show: no such objects\n");
                    996: }
                    997: 
                    998: // モニタースクリーンを表示。
                    999: void
                   1000: Debugger::ShowMonitor(TextScreen& monitor)
                   1001: {
                   1002:        char sbuf[1024];        // 適当
                   1003: 
                   1004:        // monitor 内部バッファから ShiftJIS バッファを作成。
                   1005:        // その際属性もエスケープシーケンスで再現する。
                   1006:        int col = monitor.GetCol();
                   1007:        int row = monitor.GetRow();
                   1008:        const uint16 *src = monitor.GetBuf();
                   1009: 
                   1010:        for (int y = 0; y < row; y++) {
                   1011:                int sy = y * col;
                   1012:                int sx;
                   1013:                uint attr;
                   1014:                char *d;
                   1015: 
                   1016:                memset(sbuf, 0, sizeof(sbuf));
                   1017:                d = sbuf;
                   1018:                attr = TA::Normal;
                   1019:                for (sx = 0; sx < col; sx++) {
                   1020:                        uint a  = src[sy + sx] & 0xff00;
                   1021:                        uint ch = src[sy + sx] & 0x00ff;
                   1022: 
                   1023:                        // 属性の変わり目
                   1024:                        if (attr != a) {
                   1025:                                switch (a) {
                   1026:                                 case TA::Normal:
                   1027:                                 case TA::Off:
                   1028:                                        *d++ = 0x1b;
                   1029:                                        *d++ = '[';
                   1030:                                        *d++ = 'm';
                   1031:                                        break;
                   1032:                                 case TA::On:
                   1033:                                        *d++ = 0x1b;
                   1034:                                        *d++ = '[';
                   1035:                                        *d++ = '7';
                   1036:                                        *d++ = 'm';
                   1037:                                        break;
                   1038:                                 case TA::Disable:
                   1039:                                        *d++ = 0x1b;
                   1040:                                        *d++ = '[';
                   1041:                                        *d++ = '2';
                   1042:                                        *d++ = 'm';
                   1043:                                        break;
                   1044:                                 case TA::Em:
                   1045:                                        *d++ = 0x1b;
                   1046:                                        *d++ = '[';
                   1047:                                        *d++ = '1';
                   1048:                                        *d++ = 'm';
                   1049:                                        break;
                   1050:                                }
                   1051:                                attr = a;
                   1052:                        }
                   1053:                        *d++ = ch;
                   1054:                }
                   1055:                *d = '\0';
                   1056: 
                   1057:                // XXX 日本語が使われてれば UTF-8 にしないといけないはず
                   1058: 
                   1059:                cons->Print("%s\n", sbuf);
                   1060:        }
                   1061: }
                   1062: 
                   1063: // ステップ実行: s[<count>?:1]
                   1064: void
                   1065: Debugger::cmd_s()
                   1066: {
                   1067:        if (ac > 1) {
                   1068:                int count;
                   1069:                count = strtol(av[1], NULL, 10);
                   1070:                if (count < 1) {
                   1071:                        cons->Print(" invalid step count: %d\n", count);
                   1072:                        return;
                   1073:                }
                   1074: 
                   1075:                s_count = count;
                   1076:        } else {
                   1077:                s_count = 1;
                   1078:        }
                   1079:        s_enable = true;
                   1080:        Continue();
                   1081: }
                   1082: 
                   1083: // ステップアウト
                   1084: void
                   1085: Debugger::cmd_so()
                   1086: {
                   1087:        so_enable = true;
1.1.1.2 ! root     1088:        md->SetStepOut();
1.1       root     1089:        Continue();
                   1090: }
                   1091: 
                   1092: // トレース実行: t[<count>?:1]
                   1093: // レジスタを表示しながら実行する
                   1094: void
                   1095: Debugger::cmd_t()
                   1096: {
                   1097:        if (ac > 1) {
                   1098:                int count;
                   1099:                count = strtol(av[1], NULL, 10);
                   1100:                if (count < 1) {
                   1101:                        cons->Print(" invalid trace count: %d\n", count);
                   1102:                        return;
                   1103:                }
                   1104:                t_count = count;
                   1105:        } else {
                   1106:                t_count = 1;
                   1107:        }
                   1108:        t_enable = true;
                   1109:        Continue();
                   1110: }
                   1111: 
                   1112: // 引数で示されるアドレスを返す。
                   1113: // '%' で始まればレジスタ。
                   1114: // そうでなければ16進数値。
                   1115: // アドレスが正しく取得できればアドレスを addr に格納し真を返す。
                   1116: // そうでなければエラーメッセージを表示して偽を返す。
                   1117: bool
                   1118: Debugger::ParseAddr(const char *arg, uint32_t *addrp)
                   1119: {
                   1120:        uint32_t addr;
                   1121:        char *end;
                   1122: 
                   1123:        if (arg[0] == '%') {
1.1.1.2 ! root     1124:                // '%' から始まればレジスタ
        !          1125:                uint64 r;
        !          1126:                r = md->GetRegAddr(arg + 1);
        !          1127:                if ((int64)r < 0) {
        !          1128: #if 0 // not yet
1.1       root     1129:                        cons->Print("valid register name are: %s%s\n",
                   1130:                                "%d0-%d7,%a0-%a7,%sp,%usp,%isp,%pc",
                   1131:                                ",%msp,%vbr,%srp,%crp");
1.1.1.2 ! root     1132: #endif
        !          1133:                        cons->Print("invalid register name\n");
1.1       root     1134:                        return false;
                   1135:                }
1.1.1.2 ! root     1136:                addr = (uint32)r;
1.1       root     1137:        } else {
                   1138:                /* そうでなければ番地指定 */
                   1139:                errno = 0;
                   1140:                addr = strtoul(arg, &end, 16);
                   1141:                if (arg[0] == '\0' || end[0] != '\0') {
                   1142:                        cons->Print("invalid address: '%s'\n", arg);
                   1143:                        return false;
                   1144:                }
                   1145:                if (errno == ERANGE) {
                   1146:                        cons->Print("out of range: %s\n", arg);
                   1147:                        return false;
                   1148:                }
                   1149:        }
                   1150: 
                   1151:        *addrp = addr;
                   1152:        return true;
                   1153: }
                   1154: 
1.1.1.2 ! root     1155: // (論理、物理)アドレスを表示用に整形。
        !          1156: // 逆アセンブル表示、メモリダンプ表示等で共通。
        !          1157: // アドレス変換でバスエラーが起きたら false を返す (この場合も str は有効)。
        !          1158: // 末尾を空白パディングはしていないので必要なら "%-18s" 等して使うこと。
        !          1159: //  123456789012345678
        !          1160: // "00112233:44556677:"
1.1       root     1161: bool
1.1.1.2 ! root     1162: Debugger::FormatDumpAddr(saddr_t laddr, std::string& str)
1.1       root     1163: {
1.1.1.2 ! root     1164:        bool rv = true;
1.1       root     1165: 
1.1.1.2 ! root     1166:        // laddr は常に表示
        !          1167:        str = string_format("%08x", laddr.addr);
1.1       root     1168: 
1.1.1.2 ! root     1169:        if (laddr.IsLogical() && md->MMUEnabled()) {
        !          1170:                // アドレス変換してみる
        !          1171:                uint64 paddr = md->TranslateAddr(laddr);
        !          1172:                if ((int64)paddr < 0) {
        !          1173:                        // MMU 時点でバスエラー
        !          1174:                        str += ":BusErr";
        !          1175:                        rv = false;
        !          1176:                } else if (paddr == laddr.addr) {
        !          1177:                        // PA==VA
        !          1178:                        str += "=PA";
1.1       root     1179:                } else {
1.1.1.2 ! root     1180:                        // PA!=VA
        !          1181:                        str += string_format(":%08x:", (uint32)paddr);
1.1       root     1182:                }
1.1.1.2 ! root     1183:        } else {
        !          1184:                // 物理アクセス
        !          1185:                str += ":";
1.1       root     1186:        }
                   1187: 
1.1.1.2 ! root     1188:        return rv;
1.1       root     1189: }

unix.superglobalmegacorp.com

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