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

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

unix.superglobalmegacorp.com

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