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

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

unix.superglobalmegacorp.com

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