Annotation of hatari/src/debugui.c, revision 1.1.1.12

1.1       root        1: /*
1.1.1.6   root        2:   Hatari - debugui.c
1.1       root        3: 
1.1.1.4   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
1.1.1.6   root        7:   debugui.c - this is the code for the mini-debugger. When the pause button is
                      8:   pressed, the emulator is (hopefully) halted and this little CLI can be used
                      9:   (in the terminal box) for debugging tasks like memory and register dumps.
1.1       root       10: */
1.1.1.10  root       11: const char DebugUI_fileid[] = "Hatari debugui.c : " __DATE__ " " __TIME__;
1.1       root       12: 
                     13: #include <ctype.h>
1.1.1.8   root       14: #include <stdio.h>
                     15: 
                     16: #include "config.h"
                     17: 
                     18: #if HAVE_LIBREADLINE
                     19: #include <readline/readline.h>
                     20: #include <readline/history.h>
                     21: #endif
1.1       root       22: 
                     23: #include "main.h"
1.1.1.9   root       24: #include "change.h"
1.1       root       25: #include "configuration.h"
1.1.1.11  root       26: #include "memorySnapShot.h"
1.1.1.9   root       27: #include "file.h"
1.1       root       28: #include "reset.h"
                     29: #include "m68000.h"
1.1.1.9   root       30: #include "str.h"
1.1.1.3   root       31: #include "stMemory.h"
1.1       root       32: #include "sound.h"
                     33: #include "tos.h"
1.1.1.11  root       34: #include "options.h"
1.1.1.4   root       35: #include "debugui.h"
1.1.1.11  root       36: #include "breakcond.h"
1.1.1.8   root       37: #include "hatari-glue.h"
1.1.1.11  root       38: #include "screen.h"
                     39: #include "statusbar.h"
                     40: #include "video.h"
                     41: 
                     42: int bExceptionDebugging;
1.1       root       43: 
                     44: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
                     45: #define MEMDUMP_ROWS   4       /* memdump, number of rows */
1.1.1.2   root       46: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
1.1       root       47: #define DISASM_INSTS   5       /* disasm - number of instructions */
                     48: 
1.1.1.11  root       49: static Uint32 disasm_addr;        /* disasm address */
                     50: static Uint32 memdump_addr;       /* memdump address */
                     51: 
                     52: static Uint16 dsp_disasm_addr;    /* DSP disasm address */
                     53: static Uint16 dsp_memdump_addr;   /* DSP memdump address */
                     54: static char dsp_mem_space = 'P';  /* X, Y, P */
1.1.1.6   root       55: 
1.1.1.9   root       56: static FILE *debugOutput;
1.1.1.2   root       57: 
1.1.1.11  root       58: static Uint32 CpuBreakPoint[16];  /* 68k breakpoints */
                     59: static int nCpuActiveBPs = 0;     /* Amount of active breakpoints */
                     60: static int nCpuActiveCBs = 0;     /* Amount of active conditional breakpoints */
                     61: static int nCpuSteps = 0;         /* Amount of steps for CPU single-stepping */
                     62: 
                     63: static Uint16 DspBreakPoint[16];  /* DSP breakpoints */
                     64: static int nDspActiveBPs = 0;     /* Amount of active breakpoints */
                     65: static int nDspActiveCBs = 0;     /* Amount of active conditional breakpoints */
                     66: static int nDspSteps = 0;         /* Amount of steps for DSP single-stepping */
1.1.1.2   root       67: 
1.1.1.11  root       68: static int DebugUI_Help(int nArgc, char *psArgv[]);
                     69: static void DebugUI_PrintCmdHelp(const char *psCmd);
1.1.1.6   root       70: 
                     71: 
1.1.1.8   root       72: /**
1.1.1.11  root       73:  * Save/Restore snapshot of debugging session variables
1.1.1.8   root       74:  */
1.1.1.11  root       75: void DebugUI_MemorySnapShot_Capture(bool bSave)
1.1.1.6   root       76: {
1.1.1.11  root       77:        MemorySnapShot_Store(&disasm_addr, sizeof(disasm_addr));
                     78:        MemorySnapShot_Store(&memdump_addr, sizeof(memdump_addr));
                     79:        MemorySnapShot_Store(&dsp_disasm_addr, sizeof(dsp_disasm_addr));
                     80:        MemorySnapShot_Store(&dsp_memdump_addr, sizeof(dsp_memdump_addr));
                     81:        MemorySnapShot_Store(&dsp_mem_space, sizeof(dsp_mem_space));
                     82:        
                     83:        MemorySnapShot_Store(&CpuBreakPoint, sizeof(CpuBreakPoint));
                     84:        MemorySnapShot_Store(&nCpuActiveBPs, sizeof(nCpuActiveBPs));
                     85:        MemorySnapShot_Store(&nCpuActiveCBs, sizeof(nCpuActiveCBs));
                     86:        MemorySnapShot_Store(&DspBreakPoint, sizeof(DspBreakPoint));
                     87:        MemorySnapShot_Store(&nDspActiveBPs, sizeof(nDspActiveBPs));
                     88:        MemorySnapShot_Store(&nDspActiveCBs, sizeof(nDspActiveCBs));
                     89:        
                     90:        BreakCond_MemorySnapShot_Capture(bSave);
1.1.1.9   root       91: }
                     92: 
                     93: 
                     94: /**
                     95:  * Close a log file if open, and set it to default stream.
                     96:  */
                     97: static void DebugUI_SetLogDefault(void)
                     98: {
                     99:        if (debugOutput != stderr)
                    100:        {
                    101:                if (debugOutput)
                    102:                {
                    103:                        File_Close(debugOutput);
                    104:                        fprintf(stderr, "Debug log closed.\n");
                    105:                }
                    106:                debugOutput = stderr;
                    107:        }
1.1.1.2   root      108: }
                    109: 
1.1.1.6   root      110: 
1.1.1.11  root      111: /**
                    112:  * Open (or close) given log file.
                    113:  */
                    114: static int DebugUI_SetLogFile(int nArgc, char *psArgs[])
                    115: {
                    116:        File_Close(debugOutput);
                    117:        debugOutput = NULL;
                    118: 
                    119:        if (nArgc > 1)
                    120:                debugOutput = File_Open(psArgs[1], "w");
                    121: 
                    122:        if (debugOutput)
                    123:                fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]);
                    124:        else
                    125:                debugOutput = stderr;
                    126: 
                    127:        return DEBUGGER_CMDDONE;
                    128: }
                    129: 
                    130: 
1.1.1.8   root      131: /**
                    132:  * Load a binary file to a memory address.
                    133:  */
1.1.1.11  root      134: static int DebugUI_LoadBin(int nArgc, char *psArgs[])
1.1.1.6   root      135: {
                    136:        FILE *fp;
                    137:        unsigned char c;
1.1.1.11  root      138:        Uint32 address;
1.1.1.6   root      139:        int i=0;
                    140: 
1.1.1.11  root      141:        if (nArgc < 3)
                    142:        {
                    143:                DebugUI_PrintCmdHelp(psArgs[0]);
                    144:                return DEBUGGER_CMDDONE;
                    145:        }
                    146: 
                    147:        if (!Str_GetNumber(psArgs[2], &address))
1.1.1.6   root      148:        {
1.1.1.11  root      149:                fprintf(stderr, "Invalid address!\n");
                    150:                return DEBUGGER_CMDDONE;
1.1.1.6   root      151:        }
                    152:        address &= 0x00FFFFFF;
1.1.1.11  root      153: 
                    154:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
1.1.1.6   root      155:        {
1.1.1.11  root      156:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
                    157:                return DEBUGGER_CMDDONE;
1.1.1.6   root      158:        }
                    159: 
                    160:        c = fgetc(fp);
                    161:        while (!feof(fp))
                    162:        {
                    163:                i++;
                    164:                STMemory_WriteByte(address++, c);
                    165:                c = fgetc(fp);
                    166:        }
                    167:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
                    168:        fclose(fp);
1.1.1.11  root      169: 
                    170:        return DEBUGGER_CMDDONE;
1.1       root      171: }
                    172: 
1.1.1.6   root      173: 
1.1.1.8   root      174: /**
                    175:  * Dump memory from an address to a binary file.
                    176:  */
1.1.1.11  root      177: static int DebugUI_SaveBin(int nArgc, char *psArgs[])
1.1.1.6   root      178: {
                    179:        FILE *fp;
                    180:        unsigned char c;
1.1.1.11  root      181:        Uint32 address;
                    182:        Uint32 bytes, i = 0;
1.1.1.6   root      183: 
1.1.1.11  root      184:        if (nArgc < 4)
1.1.1.6   root      185:        {
1.1.1.11  root      186:                DebugUI_PrintCmdHelp(psArgs[0]);
                    187:                return DEBUGGER_CMDDONE;
                    188:        }
                    189: 
                    190:        if (!Str_GetNumber(psArgs[2], &address))
                    191:        {
                    192:                fprintf(stderr, "  Invalid address!\n");
                    193:                return DEBUGGER_CMDDONE;
1.1.1.6   root      194:        }
                    195:        address &= 0x00FFFFFF;
1.1.1.11  root      196: 
                    197:        if (!Str_GetNumber(psArgs[3], &bytes))
1.1.1.6   root      198:        {
1.1.1.11  root      199:                fprintf(stderr, "  Invalid length!\n");
                    200:                return DEBUGGER_CMDDONE;
                    201:        }
                    202: 
                    203:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
                    204:        {
                    205:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
                    206:                return DEBUGGER_CMDDONE;
1.1.1.6   root      207:        }
                    208: 
                    209:        while (i < bytes)
                    210:        {
                    211:                c = STMemory_ReadByte(address++);
                    212:                fputc(c, fp);
                    213:                i++;
                    214:        }
                    215:        fclose(fp);
1.1.1.11  root      216:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
                    217: 
                    218:        return DEBUGGER_CMDDONE;
1.1       root      219: }
                    220: 
1.1.1.6   root      221: 
1.1.1.11  root      222: #if ENABLE_DSP_EMU
                    223: 
                    224: #include "dsp.h"
                    225: 
1.1.1.8   root      226: /**
1.1.1.11  root      227:  * Command: Dump or set a DSP register
1.1.1.8   root      228:  */
1.1.1.11  root      229: static int DebugUI_DspRegister(int nArgc, char *psArgs[])
1.1       root      230: {
1.1.1.11  root      231:        int i;
                    232:        char reg[4], *assign;
                    233:        Uint32 value;
                    234:        char *arg;
                    235: 
                    236:        if (!bDspEnabled)
                    237:        {
                    238:                printf("DSP isn't present or initialized.\n");
                    239:                return DEBUGGER_CMDDONE;
                    240:        }
                    241: 
                    242:        if (nArgc == 1)
                    243:        {
                    244:                /* No parameter - dump all registers */
                    245:                DSP_DisasmRegisters();
                    246:                return DEBUGGER_CMDDONE;
                    247:        }
                    248: 
                    249:        arg = psArgs[1];
                    250:        assign = strchr(arg, '=');
                    251:        /* has '=' and reg name is max. 3 letters that fit to string */
                    252:        if (!assign || assign - arg > 3+1)
                    253:                goto error_msg;
                    254: 
                    255:        *assign++ = '\0';
                    256:        if (!Str_GetNumber(assign, &value))
                    257:                goto error_msg;
                    258: 
                    259:        for (i = 0; i < 3 && arg[i]; i++)
                    260:                reg[i] = toupper(arg[i]);
                    261: 
                    262:        DSP_Disasm_SetRegister(reg, value);
                    263:        return DEBUGGER_CMDDONE;
                    264: 
                    265:        error_msg:
                    266:        fprintf(stderr,"\tError, usage: dr or dr xx=yyyy\n"
                    267:                "\tWhere: xx=A0-A2, B0-B2, X0, X1, Y0, Y1, R0-R7,\n"
                    268:                "\t       N0-N7, M0-M7, LA, LC, PC, SR, SP, OMR, SSH, SSL\n"
                    269:                "\tand yyyy is a hex value.\n");
                    270: 
                    271:        return DEBUGGER_CMDDONE;
1.1       root      272: }
                    273: 
                    274: 
1.1.1.8   root      275: /**
1.1.1.11  root      276:  * DSP dissassemble - arg = starting address/range, or PC.
1.1.1.8   root      277:  */
1.1.1.11  root      278: static int DebugUI_DspDisAsm(int nArgc, char *psArgs[])
1.1.1.6   root      279: {
1.1.1.11  root      280:        Uint32 lower, upper;
                    281:        Uint16 dsp_disasm_upper = 0;
1.1.1.6   root      282: 
1.1.1.11  root      283:        if (!bDspEnabled)
1.1.1.6   root      284:        {
1.1.1.11  root      285:                printf("DSP isn't present or initialized.\n");
                    286:                return DEBUGGER_CMDDONE;
                    287:        }
1.1.1.6   root      288: 
1.1.1.11  root      289:        if (nArgc > 1)
                    290:        {
                    291:                switch (Str_ParseRange(psArgs[1], &lower, &upper))
                    292:                {
                    293:                        case -1:
                    294:                                /* invalid value(s) */
                    295:                                return DEBUGGER_CMDDONE;
                    296:                        case 0:
                    297:                                /* single value */
                    298:                                break;
                    299:                        case 1:
                    300:                                /* range */
                    301:                                if (upper > 0xFFFF)
                    302:                                {
                    303:                                        fprintf(stderr,"Invalid address '%x'!\n", upper);
                    304:                                        return DEBUGGER_CMDDONE;
                    305:                                }
                    306:                                dsp_disasm_upper = upper;
                    307:                                break;
                    308:                }
                    309: 
                    310:                if (lower > 0xFFFF)
                    311:                {
                    312:                        fprintf(stderr,"Invalid address '%x'!\n", lower);
                    313:                        return DEBUGGER_CMDDONE;
                    314:                }
                    315:                dsp_disasm_addr = lower;
                    316:        }
                    317:        else
                    318:        {
                    319:                /* continue */
                    320:                if(!dsp_disasm_addr)
                    321:                {
                    322:                        dsp_disasm_addr = DSP_GetPC();
                    323:                }
                    324:        }
                    325:        if (!dsp_disasm_upper)
                    326:        {
                    327:                if ( dsp_disasm_addr < (0xFFFF - 8))
                    328:                        dsp_disasm_upper = dsp_disasm_addr + 8;
                    329:                else
                    330:                        dsp_disasm_upper = 0xFFFF;
                    331:        }
                    332:        printf("DSP disasm %hx-%hx:\n", dsp_disasm_addr, dsp_disasm_upper);
                    333:        dsp_disasm_addr = DSP_DisasmAddress(dsp_disasm_addr, dsp_disasm_upper);
1.1.1.6   root      334: 
1.1.1.11  root      335:        return DEBUGGER_CMDCONT;
                    336: }
                    337: 
                    338: 
                    339: /**
                    340:  * Do a DSP memory dump, args = starting address or range.
                    341:  * <x|y|p> <address>: dump from X, Y or P, starting from given address,
                    342:  * e.g. "x 200" or "p 200-300"
                    343:  */
                    344: static int DebugUI_DspMemDump(int nArgc, char *psArgs[])
                    345: {
                    346:        Uint32 lower, upper;
                    347:        Uint16 dsp_memdump_upper = 0;
                    348:        char space;
                    349: 
                    350:        if (!bDspEnabled)
                    351:        {
                    352:                printf("DSP isn't present or initialized.\n");
                    353:                return DEBUGGER_CMDDONE;
                    354:        }
                    355:        if (nArgc == 2)
                    356:        {
                    357:                fprintf(stderr,"Memory space or address/range missing\n");
                    358:                return DEBUGGER_CMDDONE;
                    359:        }
                    360: 
                    361:        if (nArgc == 3)
                    362:        {
                    363:                space = toupper(psArgs[1][0]);
                    364:                switch (space)
                    365:                {
                    366:                case 'X':
                    367:                case 'Y':
                    368:                case 'P':
                    369:                        break;
                    370:                default:
                    371:                        fprintf(stderr,"Invalid DSP address space '%c'!\n", space);
                    372:                        return DEBUGGER_CMDDONE;
                    373:                }
                    374:                switch (Str_ParseRange(psArgs[2], &lower, &upper))
                    375:                {
                    376:                case -1:
                    377:                        /* invalid value(s) */
                    378:                        return DEBUGGER_CMDDONE;
                    379:                case 0:
                    380:                        /* single value */
                    381:                        break;
                    382:                case 1:
                    383:                        /* range */
                    384:                        if (upper > 0xFFFF)
1.1.1.6   root      385:                        {
1.1.1.11  root      386:                                fprintf(stderr,"Invalid address '%x'!\n", upper);
                    387:                                return DEBUGGER_CMDDONE;
1.1.1.6   root      388:                        }
1.1.1.11  root      389:                        dsp_memdump_upper = upper;
                    390:                        break;
                    391:                }
                    392:                if (lower > 0xFFFF)
1.1.1.6   root      393:                {
1.1.1.11  root      394:                        fprintf(stderr,"Invalid address '%x'!\n", lower);
                    395:                        return DEBUGGER_CMDDONE;
1.1.1.6   root      396:                }
1.1.1.11  root      397:                dsp_memdump_addr = lower;
                    398:                dsp_mem_space = space;
                    399:        } /* continue */
                    400: 
                    401:        if (!dsp_memdump_upper)
                    402:        {
                    403:                if ( dsp_memdump_addr < (0xFFFF - 7))
                    404:                        dsp_memdump_upper = dsp_memdump_addr + 7;
1.1.1.6   root      405:                else
1.1.1.11  root      406:                        dsp_memdump_upper = 0xFFFF;
                    407:        }
                    408: 
                    409: 
                    410:        printf("DSP memdump from %hx in '%c' address space\n", dsp_memdump_addr, dsp_mem_space);
                    411:        DSP_DisasmMemory(dsp_memdump_addr, dsp_memdump_upper, dsp_mem_space);
                    412:        dsp_memdump_addr = dsp_memdump_upper + 1;
                    413: 
                    414:        return DEBUGGER_CMDCONT;
                    415: }
                    416: 
                    417: /**
                    418:  * Toggle or list DSP breakpoints.
                    419:  */
                    420: static int DebugUI_DspBreakPoint(int nArgc, char *psArgs[])
                    421: {
                    422:        int i;
                    423:        Uint16 addr;
                    424:        Uint32 BreakAddr;
                    425: 
                    426:        /* List breakpoints? */
                    427:        if (nArgc == 1)
                    428:        {
                    429:                /* No arguments - so list available breakpoints */
                    430:                if (!nDspActiveBPs)
                    431:                {
                    432:                        fputs("No DSP breakpoints set.\n", stderr);
                    433:                        return DEBUGGER_CMDDONE;
                    434:                }
                    435: 
                    436:                fputs("Currently active DSP breakpoints:\n", stderr);
                    437:                for (i = 0; i < nDspActiveBPs; i++)
                    438:                {
                    439:                        addr = DspBreakPoint[i];
                    440:                        DSP_DisasmAddress(addr, addr);
                    441:                }
                    442: 
                    443:                return DEBUGGER_CMDDONE;
                    444:        }
                    445: 
                    446:        /* Parse parameter as breakpoint value */
                    447:        if (!Str_GetNumber(psArgs[1], &BreakAddr) || BreakAddr > 0xFFFF)
                    448:        {
                    449:                fputs("Not a valid value for a DSP breakpoint!\n", stderr);
                    450:                return DEBUGGER_CMDDONE;
                    451:        }
                    452: 
                    453:        /* Is the breakpoint already in the list? Then disable it! */
                    454:        for (i = 0; i < nDspActiveBPs; i++)
                    455:        {
                    456:                if (BreakAddr == DspBreakPoint[i])
                    457:                {
                    458:                        DspBreakPoint[i] = DspBreakPoint[nDspActiveBPs-1];
                    459:                        nDspActiveBPs -= 1;
                    460:                        fprintf(stderr, "DSP breakpoint at %x deleted.\n", BreakAddr);
                    461:                        return DEBUGGER_CMDDONE;
                    462:                }
                    463:        }
                    464: 
                    465:        /* Is there at least one free slot available? */
                    466:        if (nDspActiveBPs == ARRAYSIZE(DspBreakPoint))
                    467:        {
                    468:                fputs("No more available free DSP breakpoints!\n", stderr);
                    469:                return DEBUGGER_CMDDONE;
                    470:        }
                    471: 
                    472:        /* Add new breakpoint */
                    473:        DspBreakPoint[nDspActiveBPs] = BreakAddr;
                    474:        nDspActiveBPs += 1;
                    475:        fprintf(stderr, "DSP breakpoint added at %x.\n", BreakAddr);
                    476: 
                    477:        return DEBUGGER_CMDDONE;
                    478: }
                    479: 
                    480: /**
                    481:  * DSP wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END
                    482:  */
                    483: static int DebugUI_BreakCondDsp(int nArgc, char *psArgs[])
                    484: {
                    485:        BreakCond_Command((const char *)psArgs[1], true);
                    486:        nDspActiveCBs = BreakCond_BreakPointCount(true);
                    487:        return DEBUGGER_CMDDONE;
                    488: }
                    489: 
                    490: /**
                    491:  * Check if we hit a DSP breakpoint
                    492:  */
                    493: static void DebugUI_CheckDspBreakpoints(void)
                    494: {
                    495:        Uint16 pc = DSP_GetPC();
                    496:        int i;
                    497: 
                    498:        for (i = 0; i < nDspActiveBPs; i++)
                    499:        {
                    500:                if (pc == DspBreakPoint[i])
                    501:                {
                    502:                        fprintf(stderr, "\nDSP breakpoint at %x ...", pc);
                    503:                        DebugUI();
                    504:                        break;
                    505:                }
                    506:        }
                    507: }
                    508: 
                    509: 
                    510: /**
                    511:  * This function is called after each DSP instruction when debugging is enabled.
                    512:  */
                    513: void DebugUI_DspCheck(void)
                    514: {
                    515:        if (nDspActiveBPs)
                    516:        {
                    517:                DebugUI_CheckDspBreakpoints();
                    518:        }
                    519:        if (nDspActiveCBs)
                    520:        {
                    521:                if (BreakCond_MatchDsp())
                    522:                        DebugUI();
                    523:        }
                    524:        if (nDspSteps)
                    525:        {
                    526:                nDspSteps -= 1;
                    527:                if (nDspSteps == 0)
                    528:                        DebugUI();
                    529:        }
                    530: }
                    531: 
                    532: #endif /* ENABLE_DSP_EMU */
                    533: 
                    534: 
                    535: 
                    536: /**
                    537:  * Dissassemble - arg = starting address, or PC.
                    538:  */
                    539: static int DebugUI_DisAsm(int nArgc, char *psArgs[])
                    540: {
                    541:        Uint32 disasm_upper = 0;
                    542:        uaecptr nextpc;
                    543: 
                    544:        if (nArgc > 1)
                    545:        {
                    546:                switch (Str_ParseRange(psArgs[1], &disasm_addr, &disasm_upper))
                    547:                {
                    548:                case -1:
                    549:                        /* invalid value(s) */
                    550:                        return DEBUGGER_CMDDONE;
                    551:                case 0:
                    552:                        /* single value */
                    553:                        break;
                    554:                case 1:
                    555:                        /* range */
1.1.1.6   root      556:                        disasm_upper &= 0x00FFFFFF;
1.1.1.11  root      557:                        break;
1.1.1.6   root      558:                }
                    559:        }
1.1.1.11  root      560:        else
                    561:        {
                    562:                /* continue */
1.1.1.6   root      563:                if(!disasm_addr)
1.1.1.8   root      564:                        disasm_addr = M68000_GetPC();
1.1.1.11  root      565:        }
1.1.1.6   root      566:        disasm_addr &= 0x00FFFFFF;
                    567: 
                    568:        /* output a single block. */
1.1.1.11  root      569:        if (!disasm_upper)
1.1.1.6   root      570:        {
1.1.1.9   root      571:                m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, DISASM_INSTS);
1.1.1.6   root      572:                disasm_addr = nextpc;
1.1.1.9   root      573:                fflush(debugOutput);
1.1.1.11  root      574:                return DEBUGGER_CMDCONT;
1.1.1.6   root      575:        }
                    576: 
                    577:        /* output a range */
                    578:        while (disasm_addr < disasm_upper)
                    579:        {
1.1.1.9   root      580:                m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
1.1.1.6   root      581:                disasm_addr = nextpc;
                    582:        }
1.1.1.9   root      583:        fflush(debugOutput);
1.1.1.11  root      584: 
                    585:        return DEBUGGER_CMDCONT;
1.1.1.2   root      586: }
                    587: 
1.1.1.6   root      588: 
1.1.1.8   root      589: /**
1.1.1.11  root      590:  * Set address of the named register to given argument.
                    591:  * Return register size in bits or zero for uknown register name.
                    592:  * Handles D0-7 data and A0-7 address registers, but not PC & SR
                    593:  * registers as they need to be accessed using UAE accessors.
1.1.1.8   root      594:  */
1.1.1.11  root      595: int DebugUI_GetCpuRegisterAddress(const char *reg, Uint32 **addr)
1.1.1.6   root      596: {
1.1.1.11  root      597:        char r0, r1;
                    598:        if (!reg[0] || !reg[1] || reg[2])
                    599:                return 0;
                    600:        
                    601:        r0 = toupper(reg[0]);
                    602:        r1 = toupper(reg[1]);
                    603: 
                    604:        if (r0 == 'D')  /* Data regs? */
1.1.1.6   root      605:        {
1.1.1.11  root      606:                if (r1 >= '0' && r1 <= '7')
1.1.1.6   root      607:                {
1.1.1.11  root      608:                        *addr = &(Regs[REG_D0 + r1 - '0']);
                    609:                        return 32;
1.1.1.6   root      610:                }
1.1.1.11  root      611:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
                    612:                return 0;
                    613:        }
                    614:        if(r0 == 'A')  /* Address regs? */
                    615:        {
                    616:                if (r1 >= '0' && r1 <= '7')
                    617:                {
                    618:                        *addr = &(Regs[REG_A0 + r1 - '0']);
                    619:                        return 32;
                    620:                }
                    621:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
                    622:                return 0;
1.1.1.6   root      623:        }
1.1.1.11  root      624:        return 0;
                    625: }
                    626: 
                    627: 
                    628: /**
                    629:  * Dump or set CPU registers
                    630:  */
                    631: static int DebugUI_CpuRegister(int nArgc, char *psArgs[])
                    632: {
                    633:        int i;
                    634:        char reg[3], *assign;
                    635:        Uint32 value;
                    636:        char *arg;
                    637: 
                    638:        /* If no parameter has been given, simply dump all registers */
                    639:        if (nArgc == 1)
                    640:        {
                    641:                uaecptr nextpc;
                    642:                /* use the UAE function instead */
                    643:                m68k_dumpstate(debugOutput, &nextpc);
                    644:                fflush(debugOutput);
                    645:                return DEBUGGER_CMDDONE;
                    646:        }
                    647: 
                    648:        arg =  psArgs[1];
1.1.1.6   root      649: 
1.1.1.11  root      650:        assign = strchr(arg, '=');
                    651:        /* has '=' and reg name is max. 2 letters that fit to string */
                    652:        if (!assign || assign - arg > 2+1)
1.1.1.6   root      653:        {
                    654:                fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR and yyyy is a hex value.\n");
1.1.1.11  root      655:                return DEBUGGER_CMDDONE;
1.1.1.6   root      656:        }
                    657: 
1.1.1.11  root      658:        *assign++ = '\0';
                    659:        if (!Str_GetNumber(assign, &value))
1.1.1.6   root      660:        {
                    661:                fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR and yyyy is a hex value.\n");
1.1.1.11  root      662:                return DEBUGGER_CMDDONE;
1.1.1.6   root      663:        }
1.1.1.11  root      664:        
                    665:        for (i = 0; i < 2 && arg[i]; i++)
                    666:        {
                    667:                reg[i] = toupper(arg[i]);
                    668:        }
                    669:        
1.1.1.6   root      670:        /* set SR and update conditional flags for the UAE CPU core. */
                    671:        if (reg[0] == 'S' && reg[1] == 'R')
                    672:        {
1.1.1.8   root      673:                M68000_SetSR(value);
1.1.1.6   root      674:        }
                    675:        else if (reg[0] == 'P' && reg[1] == 'C')   /* set PC? */
                    676:        {
1.1.1.8   root      677:                M68000_SetPC(value);
1.1.1.6   root      678:        }
1.1.1.11  root      679:        else
1.1.1.6   root      680:        {
1.1.1.11  root      681:                Uint32 *regaddr;
                    682:                /* check&set data and address registers */
                    683:                if (DebugUI_GetCpuRegisterAddress(reg, &regaddr))
1.1.1.6   root      684:                {
1.1.1.11  root      685:                        *regaddr = value;
                    686:                }
                    687:                else
                    688:                {
                    689:                        fprintf(stderr, "\t Bad register!\n");
1.1.1.6   root      690:                }
                    691:        }
1.1.1.11  root      692:        return DEBUGGER_CMDDONE;
                    693: }
                    694: 
                    695: 
                    696: /**
                    697:  * Toggle or list CPU breakpoints.
                    698:  */
                    699: static int DebugUI_CpuBreakPoint(int nArgc, char *psArgs[])
                    700: {
                    701:        int i;
                    702:        uaecptr nextpc;
                    703:        Uint32 BreakAddr;
                    704: 
                    705:        /* List breakpoints? */
                    706:        if (nArgc == 1)
1.1.1.6   root      707:        {
1.1.1.11  root      708:                /* No arguments - so list available breakpoints */
                    709:                if (!nCpuActiveBPs)
1.1.1.6   root      710:                {
1.1.1.11  root      711:                        fputs("No CPU breakpoints set.\n", stderr);
                    712:                        return DEBUGGER_CMDDONE;
                    713:                }
1.1.1.6   root      714: 
1.1.1.11  root      715:                fputs("Currently active CPU breakpoints:\n", stderr);
                    716:                for (i = 0; i < nCpuActiveBPs; i++)
                    717:                {
                    718:                        m68k_disasm(stderr, (uaecptr)CpuBreakPoint[i], &nextpc, 1);
1.1.1.6   root      719:                }
1.1.1.11  root      720: 
                    721:                return DEBUGGER_CMDDONE;
1.1.1.6   root      722:        }
1.1.1.11  root      723: 
                    724:        /* Parse parameter as breakpoint value */
                    725:        if (!Str_GetNumber(psArgs[1], &BreakAddr)
                    726:            || (BreakAddr > STRamEnd && BreakAddr < 0xe00000)
                    727:            || BreakAddr > 0xff0000)
1.1.1.6   root      728:        {
1.1.1.11  root      729:                fputs("Not a valid value for a CPU breakpoint!\n", stderr);
                    730:                return DEBUGGER_CMDDONE;
1.1.1.6   root      731:        }
1.1.1.11  root      732: 
                    733:        /* Is the breakpoint already in the list? Then disable it! */
                    734:        for (i = 0; i < nCpuActiveBPs; i++)
                    735:        {
                    736:                if (BreakAddr == CpuBreakPoint[i])
                    737:                {
                    738:                        CpuBreakPoint[i] = CpuBreakPoint[nCpuActiveBPs-1];
                    739:                        nCpuActiveBPs -= 1;
                    740:                        fprintf(stderr, "CPU breakpoint at %x deleted.\n", BreakAddr);
                    741:                        return DEBUGGER_CMDDONE;
                    742:                }
                    743:        }
                    744: 
                    745:        /* Is there at least one free slot available? */
                    746:        if (nCpuActiveBPs == ARRAYSIZE(CpuBreakPoint))
                    747:        {
                    748:                fputs("No more available free CPU breakpoints!\n", stderr);
                    749:                return DEBUGGER_CMDDONE;
                    750:        }
                    751: 
                    752:        /* Add new breakpoint */
                    753:        CpuBreakPoint[nCpuActiveBPs] = BreakAddr;
                    754:        nCpuActiveBPs += 1;
                    755:        fprintf(stderr, "CPU breakpoint added at %x.\n", BreakAddr);
                    756: 
                    757:        return DEBUGGER_CMDDONE;
1.1       root      758: }
                    759: 
1.1.1.11  root      760: /**
                    761:  * CPU wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END
                    762:  */
                    763: static int DebugUI_BreakCondCpu(int nArgc, char *psArgs[])
                    764: {
                    765:        BreakCond_Command((const char*)psArgs[1], false);
                    766:        nCpuActiveCBs = BreakCond_BreakPointCount(false);
                    767:        return DEBUGGER_CMDDONE;
                    768: }
1.1.1.6   root      769: 
1.1.1.8   root      770: /**
                    771:  * Do a memory dump, args = starting address.
                    772:  */
1.1.1.11  root      773: static int DebugUI_MemDump(int nArgc, char *psArgs[])
1.1.1.6   root      774: {
                    775:        int i,j;
                    776:        char c;
1.1.1.11  root      777:        Uint32 memdump_upper = 0;
1.1.1.2   root      778: 
1.1.1.11  root      779:        if (nArgc > 1)
1.1.1.6   root      780:        {
1.1.1.11  root      781:                switch (Str_ParseRange(psArgs[1], &memdump_addr, &memdump_upper))
1.1.1.6   root      782:                {
1.1.1.11  root      783:                case -1:
                    784:                        /* invalid value(s) */
                    785:                        return DEBUGGER_CMDDONE;
                    786:                case 0:
                    787:                        /* single value */
                    788:                        break;
                    789:                case 1:
                    790:                        /* range */
1.1.1.6   root      791:                        memdump_upper &= 0x00FFFFFF;
1.1.1.11  root      792:                        break;
1.1.1.6   root      793:                }
                    794:        } /* continue */
                    795:        memdump_addr &= 0x00FFFFFF;
                    796: 
1.1.1.11  root      797:        if (!memdump_upper)
1.1.1.6   root      798:        {
                    799:                for (j=0;j<MEMDUMP_ROWS;j++)
                    800:                {
1.1.1.11  root      801:                        fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
1.1.1.6   root      802:                        for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
1.1.1.9   root      803:                                fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    804:                        fprintf(debugOutput, "  ");                     /* print ASCII data */
1.1.1.6   root      805:                        for (i = 0; i < MEMDUMP_COLS; i++)
                    806:                        {
                    807:                                c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
1.1.1.8   root      808:                                if (!isprint((unsigned)c))
1.1.1.6   root      809:                                        c = NON_PRINT_CHAR;         /* non-printable as dots */
1.1.1.9   root      810:                                fprintf(debugOutput,"%c", c);
1.1.1.6   root      811:                        }
1.1.1.9   root      812:                        fprintf(debugOutput, "\n");        /* newline */
1.1.1.6   root      813:                }
1.1.1.9   root      814:                fflush(debugOutput);
1.1.1.11  root      815:                return DEBUGGER_CMDCONT;
1.1.1.6   root      816:        } /* not a range */
                    817: 
                    818:        while (memdump_addr < memdump_upper)
                    819:        {
1.1.1.11  root      820:                fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
1.1.1.6   root      821:                for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
1.1.1.9   root      822:                        fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    823:                fprintf(debugOutput, "  ");                     /* print ASCII data */
1.1.1.6   root      824:                for (i = 0; i < MEMDUMP_COLS; i++)
                    825:                {
                    826:                        c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
1.1.1.8   root      827:                        if(!isprint((unsigned)c))
1.1.1.6   root      828:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
1.1.1.9   root      829:                        fprintf(debugOutput,"%c", c);
1.1.1.6   root      830:                }
1.1.1.9   root      831:                fprintf(debugOutput, "\n");            /* newline */
1.1.1.6   root      832:        } /* while */
1.1.1.9   root      833:        fflush(debugOutput);
1.1.1.11  root      834: 
                    835:        return DEBUGGER_CMDCONT;
                    836: }
1.1       root      837: 
1.1.1.6   root      838: 
1.1.1.8   root      839: /**
1.1.1.11  root      840:  * Command: Write to memory, arg = starting address, followed by bytes.
1.1.1.8   root      841:  */
1.1.1.11  root      842: static int DebugUI_MemWrite(int nArgc, char *psArgs[])
1.1       root      843: {
1.1.1.11  root      844:        int i, numBytes;
                    845:        Uint32 write_addr, d;
                    846:        unsigned char bytes[256]; /* store bytes */
1.1.1.6   root      847: 
1.1.1.11  root      848:        if (nArgc < 3)
                    849:        {
                    850:                DebugUI_PrintCmdHelp(psArgs[0]);
                    851:                return DEBUGGER_CMDDONE;
                    852:        }
1.1.1.6   root      853: 
1.1.1.11  root      854:        /* Read address */
                    855:        if (!Str_GetNumber(psArgs[1], &write_addr))
1.1.1.6   root      856:        {
                    857:                fprintf(stderr, "Bad address!\n");
1.1.1.11  root      858:                return DEBUGGER_CMDDONE;
1.1.1.6   root      859:        }
                    860: 
                    861:        write_addr &= 0x00FFFFFF;
1.1.1.11  root      862:        numBytes = 0;
1.1.1.6   root      863: 
                    864:        /* get bytes data */
1.1.1.11  root      865:        for (i = 2; i < nArgc; i++)
1.1.1.6   root      866:        {
1.1.1.11  root      867:                if (!Str_GetNumber(psArgs[i], &d) || d > 255)
1.1.1.6   root      868:                {
1.1.1.11  root      869:                        fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
                    870:                        return DEBUGGER_CMDDONE;
1.1.1.6   root      871:                }
                    872: 
1.1.1.11  root      873:                bytes[numBytes] = d & 0x0FF;
1.1.1.6   root      874:                numBytes++;
                    875:        }
                    876: 
                    877:        /* write the data */
                    878:        for (i = 0; i < numBytes; i++)
                    879:                STMemory_WriteByte(write_addr + i, bytes[i]);
1.1       root      880: 
1.1.1.11  root      881:        return DEBUGGER_CMDDONE;
                    882: }
1.1.1.6   root      883: 
1.1.1.8   root      884: /**
1.1.1.11  root      885:  * Command: Show given value in bin/dec/hex number bases or change number base
1.1.1.8   root      886:  */
1.1.1.11  root      887: static int DebugUI_ShowValue(int argc, char *argv[])
1.1       root      888: {
1.1.1.11  root      889:        static const struct {
                    890:                const char name[4];
                    891:                int base;
                    892:        } bases[] = {
                    893:                { "bin", 2 },
                    894:                { "dec", 10 },
                    895:                { "hex", 16 }
                    896:        };
                    897:        bool one, ones;
                    898:        Uint32 value;
                    899:        int bit, i;
                    900:        
                    901:        if (argc < 2)
                    902:        {
                    903:                DebugUI_PrintCmdHelp(argv[0]);
                    904:                return DEBUGGER_CMDDONE;
                    905:        }
                    906:        
                    907:        for (i = 0; i < ARRAYSIZE(bases); i++)
                    908:        {
                    909:                if (strcasecmp(bases[i].name, argv[1]) == 0)
                    910:                {
                    911:                        if (ConfigureParams.Log.nNumberBase != bases[i].base)
                    912:                        {
                    913:                                fprintf(stderr, "Switched default number base from %d to %d-based (%s) values\n",
                    914:                                        ConfigureParams.Log.nNumberBase,
                    915:                                        bases[i].base, bases[i].name);
                    916:                                ConfigureParams.Log.nNumberBase = bases[i].base;
                    917:                        } else {
                    918:                                fprintf(stderr, "Already in '%s' mode\n", bases[i].name);
                    919:                        }
                    920:                        return DEBUGGER_CMDDONE;
                    921:                }
                    922:        }
                    923:        
                    924:        if (!Str_GetNumber(argv[1], &value))
                    925:                return DEBUGGER_CMDDONE;
                    926: 
                    927:        fprintf(stderr, "'%s' = %%", argv[1]);
                    928:        ones = false;
                    929:        for (bit = 31; bit >= 0; bit--)
                    930:        {
                    931:                one = value & (1<<bit);
                    932:                if (one || ones)
                    933:                {
                    934:                        fputc(one ? '1':'0', stderr);
                    935:                        ones = true;
                    936:                }
                    937:        }
                    938:        if (!ones)
                    939:                fputc('0', stderr);
                    940:        fprintf(stderr, " (bin), #%u (dec), $%x (hex)\n", value, value);
                    941:        return DEBUGGER_CMDDONE;
1.1       root      942: }
                    943: 
1.1.1.9   root      944: 
1.1.1.8   root      945: /**
1.1.1.11  root      946:  * Command: Set options
1.1.1.8   root      947:  */
1.1.1.11  root      948: static int DebugUI_SetOptions(int argc, char *argv[])
1.1.1.6   root      949: {
1.1.1.11  root      950:        CNF_PARAMS current;
1.1.1.6   root      951: 
1.1.1.11  root      952:        /* get configuration changes */
                    953:        current = ConfigureParams;
1.1       root      954: 
1.1.1.11  root      955:        /* Parse and apply options */
                    956:        if (Opt_ParseParameters(argc, (const char**)argv))
1.1.1.6   root      957:        {
1.1.1.11  root      958:                ConfigureParams.Screen.bFullScreen = false;
                    959:                Change_CopyChangedParamsToConfiguration(&current, &ConfigureParams, false);
1.1.1.6   root      960:        }
1.1.1.11  root      961:        else
                    962:        {
                    963:                ConfigureParams = current;
                    964:        }
                    965: 
                    966:        return DEBUGGER_CMDDONE;
                    967: }
                    968: 
                    969: 
                    970: /**
                    971:  * Command: Continue emulation / single-stepping
                    972:  */
                    973: static int DebugUI_Continue(int nArgc, char *psArgv[], bool bStepDsp)
                    974: {
                    975:        const char *chip;
                    976:        int steps = 0;
                    977:        
                    978:        if (nArgc > 1)
                    979:        {
                    980:                steps = atoi(psArgv[1]);
                    981:        }
                    982:        /* at most one should be active at the same time */
                    983:        nDspSteps = 0;
                    984:        nCpuSteps = 0;
                    985:        if (steps <= 0)
                    986:        {
1.1.1.12! root      987:                fprintf(stderr,"Returning to emulation...\n");
1.1.1.11  root      988:                return DEBUGGER_END;
                    989:        }
                    990:        if (bStepDsp)
                    991:        {
                    992:                nDspSteps = steps;
                    993: #if ENABLE_DSP_EMU
                    994:                chip = "DSP";
                    995: #else
                    996:                chip = "<NONE>";
                    997: #endif
                    998:        } else {
                    999:                nCpuSteps = steps;
                   1000:                chip = "CPU";
1.1.1.9   root     1001:        }
1.1.1.11  root     1002:        fprintf(stderr,"Returning to emulation for %i %s instructions...\n", steps, chip);
                   1003:        return DEBUGGER_END;
                   1004: }
                   1005: 
                   1006: /**
                   1007:  * Command: Continue emulation / single-stepping CPU wrapper
                   1008:  */
                   1009: static int DebugUI_CpuContinue(int nArgc, char *psArgv[])
                   1010: {
                   1011:        return DebugUI_Continue(nArgc, psArgv, false);
                   1012: }
                   1013: /**
                   1014:  * Command: Continue emulation / single-stepping DSP wrapper
                   1015:  */
                   1016: static int DebugUI_DspContinue(int nArgc, char *psArgv[])
                   1017: {
                   1018:        return DebugUI_Continue(nArgc, psArgv, true);
                   1019: }
1.1.1.6   root     1020: 
1.1.1.8   root     1021: 
1.1.1.11  root     1022: /**
                   1023:  * Command: Quit emulator
                   1024:  */
                   1025: static int DebugUI_QuitEmu(int nArgc, char *psArgv[])
                   1026: {
                   1027:        bQuitProgram = true;
                   1028:        M68000_SetSpecial(SPCFLAG_BRK);   /* Assure that CPU core shuts down */
                   1029:        return DEBUGGER_END;
                   1030: }
                   1031: 
                   1032: 
                   1033: typedef struct
                   1034: {
                   1035:        int (*pFunction)(int argc, char *argv[]);
                   1036:        const char *sLongName;
                   1037:        const char *sShortName;
                   1038:        const char *sShortDesc;
                   1039:        const char *sUsage;
                   1040:        bool bNoParsing;
                   1041: } dbgcommand_t;
                   1042: 
                   1043: dbgcommand_t commandtab[] =
                   1044: {
                   1045: #if ENABLE_DSP_EMU
                   1046:        { DebugUI_DspBreakPoint, "dspaddress", "da",
                   1047:          "toggle or list (traditional) DSP address breakpoints",
                   1048:          "[address]\n"
                   1049:          "\tToggle breakpoint at <address> or list all breakpoints when\n"
                   1050:          "\tno address is given.",
                   1051:          false },
                   1052:        { DebugUI_BreakCondDsp, "dspbreak", "db",
                   1053:          "set/remove/list DSP register/RAM condition breakpoints",
                   1054:          "[help | all | <breakpoint index> | <breakpoint condition>]\n"
                   1055:          "\tSet breakpoint with given condition, remove breakpoint with\n"
                   1056:          "\tgiven index or list all breakpoints when no args are given.\n"
                   1057:          "\t'help' outputs breakpoint condition syntax help, 'all' removes\n"
                   1058:          "\tall conditional breakpoints",
                   1059:          true },
                   1060:        { DebugUI_DspDisAsm, "dspdisasm", "dd",
                   1061:          "disassemble DSP code",
                   1062:          "[address]\n"
                   1063:          "\tDisassemble from DSP-PC, otherwise at given address.",
                   1064:          false },
                   1065:        { DebugUI_DspMemDump, "dspmemdump", "dm",
                   1066:          "dump DSP memory",
                   1067:          "<x|y|p> [address]\n"
                   1068:          "\tdump DSP memory at address, or continue from previous address if not\n"
                   1069:          "\tspecified.",
                   1070:          false },
                   1071:        { DebugUI_DspRegister, "dspreg", "dr",
                   1072:          "read/write DSP registers",
                   1073:          "[REG=value]"
                   1074:          "\tSet or dump contents of DSP registers.",
                   1075:          false },
                   1076:        { DebugUI_DspContinue, "dspcont", "dc",
                   1077:          "continue emulation / DSP single-stepping",
                   1078:          "[steps]\n"
                   1079:          "\tLeave debugger and continue emulation for <steps> DSP instructions\n"
                   1080:          "\tor forever if no steps have been specified.",
                   1081:          false },
                   1082: #endif
                   1083:        { DebugUI_CpuBreakPoint, "address", "a",
                   1084:          "toggle or list (traditional) CPU address breakpoints",
                   1085:          "[address]\n"
                   1086:          "\tToggle breakpoint at <address> or list all breakpoints when\n"
                   1087:          "\tno address is given.",
                   1088:          false },
                   1089:        { DebugUI_BreakCondCpu, "breakpoint", "b",
                   1090:          "set/remove/list register/RAM condition breakpoints",
                   1091:          "[help | all | <breakpoint index> | <breakpoint condition>]\n"
                   1092:          "\tSet breakpoint with given condition, remove breakpoint with\n"
                   1093:          "\tgiven index or list all breakpoints when no args are given.\n"
                   1094:          "\t'help' outputs breakpoint condition syntax help, 'all' removes\n"
                   1095:          "\tall conditional breakpoints",
                   1096:          true },
                   1097:        { DebugUI_DisAsm, "disasm", "d",
                   1098:          "disassemble from PC, or given address",
                   1099:          "[address]\n"
                   1100:          "\tIf no address is given, this command disassembles from the last\n"
                   1101:          "\tposition or from current PC if no last postition is available.",
                   1102:          false },
                   1103:        { DebugUI_CpuRegister, "cpureg", "r",
                   1104:          "dump register values or set register to value",
                   1105:          "[REG=value]\n"
                   1106:          "\tSet CPU register to value or dumps all register if no parameter\n"
                   1107:          "\thas been specified.",
                   1108:          false },
                   1109:        { DebugUI_MemDump, "memdump", "m",
                   1110:          "dump memory",
                   1111:          "[address]\n"
                   1112:          "\tdump memory at address or continue dump from previous address.",
                   1113:          false },
                   1114:        { DebugUI_MemWrite, "memwrite", "w",
                   1115:          "write bytes to memory",
                   1116:          "address byte1 [byte2 ...]\n"
                   1117:          "\tWrite bytes to a memory address, bytes are space separated\n"
                   1118:          "\thexadecimals.",
                   1119:          false },
                   1120:        { DebugUI_SetLogFile, "logfile", "f",
                   1121:          "open or close log file",
                   1122:          "[filename]\n"
                   1123:          "\tOpen log file, no argument closes the log file. Output of\n"
                   1124:          "\tregister & memory dumps and disassembly will be written to it.",
                   1125:          false },
                   1126:        { DebugUI_LoadBin, "loadbin", "l",
                   1127:          "load a file into memory",
                   1128:          "filename address\n"
                   1129:          "\tLoad the file <filename> into memory starting at <address>.",
                   1130:          false },
                   1131:        { DebugUI_SaveBin, "savebin", "s",
                   1132:          "save memory to a file",
                   1133:          "filename address length\n"
                   1134:          "\tSave the memory block at <address> with given <length> to\n"
                   1135:          "\tthe file <filename>.",
                   1136:          false },
                   1137:        { DebugUI_SetOptions, "setopt", "o",
                   1138:          "set Hatari command line options",
                   1139:          "[command line parameters]\n"
                   1140:          "\tSet options like command line parameters. For example to"
                   1141:          "\tenable CPU disasm tracing:  setopt --trace cpu_disasm",
                   1142:          false },
                   1143:        { DebugUI_ShowValue, "value", "v",
                   1144:          "set number base / show value in other number bases",
                   1145:          "<bin|dec|hex|value>\n"
                   1146:          "\tHelper to change the default number base and to see given values\n"
                   1147:          "\tin all the supported bin/dec/hex number bases.",
                   1148:          false },
                   1149:        { DebugUI_CpuContinue, "cont", "c",
                   1150:          "continue emulation / CPU single-stepping",
                   1151:          "[steps]\n"
                   1152:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
                   1153:          "\tor forever if no steps have been specified.",
                   1154:          false },
                   1155:        { DebugUI_QuitEmu, "quit", "q",
                   1156:          "quit emulator",
                   1157:          "\n"
                   1158:          "\tLeave debugger and quit emulator.",
                   1159:          false },
                   1160:        { DebugUI_Help, "help", "h",
                   1161:          "print help",
                   1162:          "[command]"
                   1163:          "\tPrint help text for available commands.",
                   1164:          false },
                   1165: };
                   1166: 
                   1167: 
                   1168: /**
                   1169:  * Print help text for one command
                   1170:  */
                   1171: static void DebugUI_PrintCmdHelp(const char *psCmd)
                   1172: {
                   1173:        int i;
                   1174: 
                   1175:        /* Search the command ... */
                   1176:        for (i = 0; i < ARRAYSIZE(commandtab); i++)
1.1.1.6   root     1177:        {
1.1.1.11  root     1178:                if (!strcmp(psCmd, commandtab[i].sLongName)
                   1179:                    || !strcmp(psCmd, commandtab[i].sShortName))
                   1180:                {
                   1181:                        /* ... and print help text */
                   1182:                        fprintf(stderr, "'%s' or '%s' - %s\n",
                   1183:                                commandtab[i].sLongName, commandtab[i].sShortName,
                   1184:                                commandtab[i].sShortDesc);
                   1185:                        fprintf(stderr, "Usage:  %s %s\n", commandtab[i].sShortName,
                   1186:                                commandtab[i].sUsage);
                   1187:                        return;
1.1.1.6   root     1188:                }
1.1.1.11  root     1189:        }
1.1.1.6   root     1190: 
1.1.1.11  root     1191:        fprintf(stderr, "Unknown command '%s'\n", psCmd);
                   1192: }
1.1.1.6   root     1193: 
                   1194: 
1.1.1.11  root     1195: /**
                   1196:  * Command: Print debugger help screen.
                   1197:  */
                   1198: static int DebugUI_Help(int nArgc, char *psArgs[])
                   1199: {
                   1200:        int i;
                   1201: 
                   1202:        if (nArgc > 1)
                   1203:        {
                   1204:                DebugUI_PrintCmdHelp(psArgs[1]);
                   1205:                return DEBUGGER_CMDDONE;
                   1206:        }
                   1207: 
                   1208:        fputs("Available commands:\n", stderr);
                   1209:        for (i = 0; i < ARRAYSIZE(commandtab); i++)
                   1210:        {
                   1211:                fprintf(stderr, " %12s (%2s) : %s\n", commandtab[i].sLongName,
                   1212:                        commandtab[i].sShortName, commandtab[i].sShortDesc);
                   1213:        }
                   1214: 
                   1215:        fprintf(stderr,
                   1216:                "If value is prefixed with '$', it's a hexadecimal, if with '#', it's\n"
                   1217:                "a normal decimal, if with '%%', it's a binary decimal. Prefix can\n"
                   1218:                "be skipped for numbers in the default number base (currently %d).\n"
                   1219:                "Adresses may be given as a range like '$fc0000-$fc0100'.\n"
                   1220:                "'h <command>' gives more help.\n", ConfigureParams.Log.nNumberBase);
                   1221:        return DEBUGGER_CMDDONE;
                   1222: }
                   1223: 
                   1224: 
                   1225: /**
                   1226:  * Parse debug command and execute it.
                   1227:  */
                   1228: int DebugUI_ParseCommand(char *input)
                   1229: {
                   1230:        char *psArgs[64];
                   1231:        const char *delim;
                   1232:        static char sLastCmd[80] = { '\0' };
                   1233:        int nArgc, cmd = -1;
                   1234:        int i, retval;
1.1.1.6   root     1235: 
1.1.1.11  root     1236:        psArgs[0] = strtok(input, " \t");
                   1237: 
                   1238:        if (psArgs[0] == NULL)
                   1239:        {
                   1240:                if (strlen(sLastCmd) > 0)
                   1241:                        psArgs[0] = sLastCmd;
1.1.1.8   root     1242:                else
1.1.1.11  root     1243:                        return DEBUGGER_CMDDONE;
                   1244:        }
                   1245: 
                   1246:        /* Search the command ... */
                   1247:        for (i = 0; i < ARRAYSIZE(commandtab); i++)
                   1248:        {
                   1249:                if (!strcmp(psArgs[0], commandtab[i].sLongName)
                   1250:                    || !strcmp(psArgs[0], commandtab[i].sShortName))
                   1251:                {
                   1252:                        cmd = i;
                   1253:                        break;
                   1254:                }
                   1255:        }
                   1256:        if (cmd == -1)
                   1257:        {
                   1258:                fprintf(stderr, "Command '%s' not found.\n"
                   1259:                        "Use 'help' to view a list of available commands.\n",
                   1260:                        psArgs[0]);
                   1261:                return DEBUGGER_CMDDONE;
                   1262:        }
                   1263: 
                   1264:        if (commandtab[cmd].bNoParsing)
                   1265:                delim = "";
                   1266:        else
                   1267:                delim = " \t";
                   1268: 
                   1269:        /* Separate arguments and put the pointers into psArgs */
                   1270:        for (nArgc = 1; nArgc < ARRAYSIZE(psArgs); nArgc++)
                   1271:        {
                   1272:                psArgs[nArgc] = strtok(NULL, delim);
                   1273:                if (psArgs[nArgc] == NULL)
                   1274:                        break;
                   1275:        }
1.1.1.6   root     1276: 
1.1.1.11  root     1277:        if (!debugOutput) {
                   1278:                /* make sure also calls from control.c work */
                   1279:                DebugUI_SetLogDefault();
1.1.1.6   root     1280:        }
                   1281: 
1.1.1.11  root     1282:        /* ... and execute the function */
                   1283:        retval = commandtab[i].pFunction(nArgc, psArgs);
                   1284:        /* Save commando string if it can be repeated */
                   1285:        if (retval == DEBUGGER_CMDCONT)
                   1286:                strncpy(sLastCmd, psArgs[0], sizeof(sLastCmd));
                   1287:        else
                   1288:                sLastCmd[0] = '\0';
1.1.1.9   root     1289:        return retval;
                   1290: }
                   1291: 
1.1.1.11  root     1292: 
1.1.1.9   root     1293: /**
1.1.1.11  root     1294:  * Read a command line from the keyboard and return a pointer to the string.
                   1295:  * @return     Pointer to the string which should be deallocated free()
                   1296:  *              after use. Returns NULL when error occured.
1.1.1.9   root     1297:  */
1.1.1.11  root     1298: static char *DebugUI_GetCommand(void)
1.1.1.9   root     1299: {
                   1300:        char *input;
1.1.1.8   root     1301: 
1.1.1.9   root     1302: #if HAVE_LIBREADLINE
                   1303:        input = readline("> ");
                   1304:        if (!input)
1.1.1.11  root     1305:                return NULL;
1.1.1.9   root     1306:        if (input[0] != 0)
                   1307:                add_history(input);
                   1308: #else
                   1309:        fprintf(stderr, "> ");
                   1310:        input = malloc(256);
                   1311:        if (!input)
1.1.1.11  root     1312:                return NULL;
1.1.1.9   root     1313:        input[0] = '\0';
1.1.1.11  root     1314:        if (fgets(input, 256, stdin) == NULL)
                   1315:        {
                   1316:                free(input);
                   1317:                return NULL;
                   1318:        }
1.1.1.9   root     1319: #endif
1.1.1.11  root     1320:        input = Str_Trim(input);
1.1.1.9   root     1321: 
1.1.1.11  root     1322:        return input;
                   1323: }
                   1324: 
                   1325: 
                   1326: /**
                   1327:  * Texts shown when entering the debugger on first and successive times
                   1328:  */
                   1329: static void DebugUI_WelcomeText(void)
                   1330: {
                   1331:        int hbl, fcycles, lcycles;
                   1332:        static const char *welcome =
                   1333:                "\n----------------------------------------------------------------------"
                   1334:                "\nYou have entered debug mode. Type c to continue emulation, h for help.\n";
                   1335:        if (welcome)
                   1336:        {
                   1337:                fputs(welcome, stderr);
                   1338:                welcome = NULL;
                   1339:        }
                   1340:        Video_GetPosition(&fcycles, &hbl, &lcycles);
                   1341:        fprintf(stderr, "\nCPU=$%x, VBL=%d, FrameCycles=%d, HBL=%d, LineCycles=%d, DSP=",
                   1342:                M68000_GetPC(), nVBLs, fcycles, hbl, lcycles);
                   1343:        if (bDspEnabled)
                   1344:                fprintf(stderr, "$%x\n", DSP_GetPC());
                   1345:        else
                   1346:                fprintf(stderr, "N/A\n");
1.1       root     1347: }
                   1348: 
                   1349: 
1.1.1.8   root     1350: /**
1.1.1.11  root     1351:  * Debugger user interface main function.
1.1.1.8   root     1352:  */
1.1.1.4   root     1353: void DebugUI(void)
1.1       root     1354: {
1.1.1.11  root     1355:        int cmdret;
                   1356: 
                   1357:        /* if you want disassembly or memdumping to start/continue from
                   1358:         * specific address, you can set them here.  If disassembly
                   1359:         * address is zero, disassembling starts from PC.
                   1360:         */
                   1361: #if ENABLE_DSP_EMU
                   1362:        dsp_disasm_addr = 0;
                   1363:        dsp_memdump_addr = 0;
                   1364:        dsp_mem_space = 'P';
                   1365: #endif
                   1366:        memdump_addr = 0;
1.1.1.6   root     1367:        disasm_addr = 0;
1.1.1.2   root     1368: 
1.1.1.11  root     1369:        if (bInFullScreen)
                   1370:                Screen_ReturnFromFullScreen();
                   1371: 
                   1372:        DebugUI_WelcomeText();
                   1373:        
                   1374:        /* override paused message so that user knows to look into console
                   1375:         * on how to continue in case he invoked the debugger by accident.
                   1376:         */
                   1377:        Statusbar_AddMessage("Console Debugger", 100);
                   1378:        Statusbar_Update(sdlscrn);
                   1379: 
                   1380:        do
                   1381:        {
                   1382:                char *psCmd;
                   1383: 
                   1384:                /* Read command from the keyboard */
                   1385:                psCmd = DebugUI_GetCommand();
                   1386: 
                   1387:                if (psCmd)
                   1388:                {
                   1389:                        /* Parse and execute the command string */
                   1390:                        cmdret = DebugUI_ParseCommand(psCmd);
                   1391:                        free(psCmd);
                   1392:                }
                   1393:                else
                   1394:                {
                   1395:                        cmdret = DEBUGGER_END;
                   1396:                }
                   1397:        }
                   1398:        while (cmdret != DEBUGGER_END);
                   1399: 
1.1.1.9   root     1400:        DebugUI_SetLogDefault();
1.1.1.11  root     1401: 
                   1402:        /* If "real-time" debugging like breakpoints has been set, we've
                   1403:         * got to tell the CPU core to call us after each instruction! */
                   1404:        if (nCpuActiveBPs || nCpuActiveCBs || nCpuSteps)
                   1405:                M68000_SetSpecial(SPCFLAG_DEBUGGER);
                   1406:        else
                   1407:                M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
                   1408:        /* ...and DSP core */
                   1409:        if (nDspActiveBPs || nDspActiveCBs || nDspSteps)
                   1410:                DSP_SetDebugging(true);
                   1411:        else
                   1412:                DSP_SetDebugging(false);
                   1413: }
                   1414: 
                   1415: 
                   1416: /**
                   1417:  * Check if we hit a CPU breakpoint
                   1418:  */
                   1419: static void DebugUI_CheckCpuBreakpoints(void)
                   1420: {
                   1421:        Uint32 pc = M68000_GetPC();
                   1422:        int i;
                   1423: 
                   1424:        for (i = 0; i < nCpuActiveBPs; i++)
                   1425:        {
                   1426:                if (pc == CpuBreakPoint[i])
                   1427:                {
                   1428:                        fprintf(stderr, "\nCPU breakpoint at %x ...", pc);
                   1429:                        DebugUI();
                   1430:                        break;
                   1431:                }
                   1432:        }
                   1433: }
                   1434: 
                   1435: 
                   1436: /**
                   1437:  * This function is called after each CPU instruction when debugging is enabled.
                   1438:  */
                   1439: void DebugUI_CpuCheck(void)
                   1440: {
                   1441:        if (nCpuActiveBPs)
                   1442:        {
                   1443:                DebugUI_CheckCpuBreakpoints();
                   1444:        }
                   1445:        if (nCpuActiveCBs)
                   1446:        {
                   1447:                if (BreakCond_MatchCpu())
                   1448:                        DebugUI();
                   1449:        }
                   1450:        if (nCpuSteps)
                   1451:        {
                   1452:                nCpuSteps -= 1;
                   1453:                if (nCpuSteps == 0)
                   1454:                        DebugUI();
                   1455:        }
1.1       root     1456: }

unix.superglobalmegacorp.com

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