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

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

unix.superglobalmegacorp.com

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