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

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

unix.superglobalmegacorp.com

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