Annotation of hatari/src/debug/debugui.c, revision 1.1.1.9

1.1       root        1: /*
                      2:   Hatari - debugui.c
                      3: 
1.1.1.6   root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      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.
                     10: */
                     11: const char DebugUI_fileid[] = "Hatari debugui.c : " __DATE__ " " __TIME__;
                     12: 
                     13: #include <ctype.h>
                     14: #include <stdio.h>
                     15: #include <unistd.h>
                     16: 
                     17: #include "config.h"
                     18: 
                     19: #if HAVE_LIBREADLINE
                     20: #include <readline/readline.h>
                     21: #include <readline/history.h>
                     22: #endif
                     23: 
                     24: #include "main.h"
                     25: #include "change.h"
                     26: #include "configuration.h"
                     27: #include "file.h"
                     28: #include "log.h"
                     29: #include "m68000.h"
                     30: #include "memorySnapShot.h"
                     31: #include "options.h"
1.1.1.8   root       32: #include "reset.h"
1.1       root       33: #include "screen.h"
                     34: #include "statusbar.h"
                     35: #include "str.h"
                     36: 
                     37: #include "debug_priv.h"
                     38: #include "breakcond.h"
                     39: #include "debugcpu.h"
                     40: #include "debugdsp.h"
1.1.1.6   root       41: #include "68kDisass.h"
1.1       root       42: #include "debugInfo.h"
                     43: #include "debugui.h"
                     44: #include "evaluate.h"
1.1.1.3   root       45: #include "history.h"
1.1       root       46: #include "symbols.h"
1.1.1.9 ! root       47: #include "vars.h"
1.1       root       48: 
1.1.1.5   root       49: FILE *debugOutput;
1.1       root       50: 
                     51: static dbgcommand_t *debugCommand;
                     52: static int debugCommands;
                     53: 
                     54: /* stores last 'e' command result as hex, used for TAB-completion */
                     55: static char lastResult[10];
                     56: 
1.1.1.6   root       57: /* parse debugger commands from here on init */
1.1       root       58: static const char *parseFileName;
                     59: 
                     60: 
                     61: /**
                     62:  * Save/Restore snapshot of debugging session variables
                     63:  */
                     64: void DebugUI_MemorySnapShot_Capture(const char *path, bool bSave)
                     65: {
                     66:        char *filename;
                     67: 
                     68:        filename = malloc(strlen(path) + strlen(".debug") + 1);
                     69:        assert(filename);
                     70:        strcpy(filename, path);
                     71:        strcat(filename, ".debug");
                     72:        
                     73:        if (bSave)
                     74:        {
                     75:                /* save breakpoints as debugger input file */
                     76:                BreakCond_Save(filename);
                     77:        }
                     78:        else
                     79:        {
                     80:                /* remove current CPU and DSP breakpoints */
                     81:                BreakCond_Command("all", false);
                     82:                BreakCond_Command("all", true);
                     83: 
                     84:                if (File_Exists(filename))
                     85:                {
                     86:                        /* and parse back the saved breakpoints */
1.1.1.6   root       87:                        DebugUI_ParseFile(filename, true);
1.1       root       88:                }
                     89:        }
                     90:        free(filename);
                     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:        }
                    108: }
                    109: 
                    110: 
                    111: /**
                    112:  * Open (or close) given log file.
                    113:  */
                    114: static int DebugUI_SetLogFile(int nArgc, char *psArgs[])
                    115: {
1.1.1.9 ! root      116:        if (debugOutput != stderr)
        !           117:        {
        !           118:                fprintf(stderr, "Debug log closed.\n");
        !           119:                File_Close(debugOutput);
        !           120:        }
        !           121:        debugOutput = stderr;
1.1       root      122: 
                    123:        if (nArgc > 1)
1.1.1.9 ! root      124:        {
        !           125:                if ((debugOutput = File_Open(psArgs[1], "w")))
        !           126:                {
        !           127:                        fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]);
        !           128:                }
        !           129:                else
        !           130:                {
        !           131:                        fprintf(stderr, "Debug log '%s' opening FAILED.\n", psArgs[1]);
        !           132:                        debugOutput = stderr;
        !           133:                }
        !           134:        }
1.1       root      135:        return DEBUGGER_CMDDONE;
                    136: }
                    137: 
                    138: 
                    139: /**
                    140:  * Helper to print given value in all supported number bases
                    141:  */
                    142: static void DebugUI_PrintValue(Uint32 value)
                    143: {
                    144:        bool one, ones;
                    145:        int bit;
                    146: 
                    147:        fputs("= %", stderr);
                    148:        ones = false;
                    149:        for (bit = 31; bit >= 0; bit--)
                    150:        {
                    151:                one = value & (1<<bit);
                    152:                if (one || ones)
                    153:                {
                    154:                        fputc(one ? '1':'0', stderr);
                    155:                        ones = true;
                    156:                }
                    157:        }
                    158:        if (!ones)
                    159:                fputc('0', stderr);
                    160:        if (value & 0x80000000)
                    161:                fprintf(stderr, " (bin), #%u/%d (dec), $%x (hex)\n", value, (int)value, value);
                    162:        else
                    163:                fprintf(stderr, " (bin), #%u (dec), $%x (hex)\n", value, value);
                    164: 
                    165:        sprintf(lastResult, "%x", value);
                    166: }
                    167: 
                    168: 
                    169: /**
                    170:  * Commmand: Evaluate an expression with CPU reg and symbol parsing.
                    171:  */
                    172: static int DebugUI_Evaluate(int nArgc, char *psArgs[])
                    173: {
                    174:        const char *errstr, *expression = (const char *)psArgs[1];
                    175:        Uint32 result;
                    176:        int offset;
                    177: 
                    178:        if (nArgc < 2)
                    179:        {
1.1.1.7   root      180:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      181:        }
                    182: 
                    183:        errstr = Eval_Expression(expression, &result, &offset, false);
                    184:        if (errstr)
                    185:                fprintf(stderr, "ERROR in the expression:\n'%s'\n%*c-%s\n",
                    186:                        expression, offset+3, '^', errstr);
                    187:        else
                    188:                DebugUI_PrintValue(result);
                    189:        return DEBUGGER_CMDDONE;
                    190: }
                    191: 
                    192: 
                    193: /**
                    194:  * Check whether given string is a two letter command starting with 'd'
                    195:  * or a long command starting with "dsp". String should be trimmed.
                    196:  * Return true if given string is command for DSP, false otherwise.
                    197:  */
                    198: static bool DebugUI_IsForDsp(const char *cmd)
                    199: {
1.1.1.7   root      200:        return ((cmd[0] == 'd' && isalpha((unsigned char)cmd[1])
                    201:                               && !isalpha((unsigned char)cmd[2]))
                    202:                || strncmp(cmd, "dsp", 3) == 0);
1.1       root      203: }
                    204: 
                    205: /**
1.1.1.6   root      206:  * Evaluate everything include within single or double quotes ("" or '')
                    207:  * and replace them with the result.
                    208:  * Caller needs to free the returned string separately.
1.1       root      209:  * 
1.1.1.6   root      210:  * Return new string with expressions (potentially) expanded, or
1.1.1.2   root      211:  * NULL when there's an error in the expression.
1.1       root      212:  */
1.1.1.6   root      213: static char *DebugUI_EvaluateExpressions(const char *initial)
1.1       root      214: {
                    215:        int offset, count, diff, inputlen;
1.1.1.6   root      216:        char *end, *start, *input;
1.1       root      217:        const char *errstr;
                    218:        char valuestr[12];
                    219:        Uint32 value;
                    220:        bool fordsp;
                    221: 
                    222:        /* input is split later on, need to save len here */
1.1.1.6   root      223:        input = strdup(initial);
                    224:        if (!input)
                    225:        {
                    226:                perror("ERROR: Input string alloc failed\n");
                    227:                return NULL;
                    228:        }
1.1       root      229:        fordsp = DebugUI_IsForDsp(input);
                    230:        inputlen = strlen(input);
1.1.1.6   root      231:        start = input;
                    232: 
                    233:        while ((count = strcspn(start, "\"'")) && *(start+count))
1.1       root      234:        {
1.1.1.6   root      235:                start += count;
                    236:                end = strchr(start+1, *start);
1.1       root      237:                if (!end)
                    238:                {
1.1.1.6   root      239:                        fprintf(stderr, "ERROR: matching '%c' missing from '%s'!\n", *start, start);
1.1.1.7   root      240:                        free(input);
1.1       root      241:                        return NULL;
                    242:                }
                    243:                
                    244:                if (end == start+1)
                    245:                {
                    246:                        /* empty expression */
                    247:                        memmove(start, start+2, strlen(start+2)+1);
                    248:                        continue;
                    249:                }
                    250: 
                    251:                *end = '\0';
                    252:                errstr = Eval_Expression(start+1, &value, &offset, fordsp);
                    253:                if (errstr) {
1.1.1.6   root      254:                        *end = *start; /* restore expression mark */
1.1       root      255:                        fprintf(stderr, "Expression ERROR:\n'%s'\n%*c-%s\n",
                    256:                                input, (int)(start-input)+offset+3, '^', errstr);
1.1.1.7   root      257:                        free(input);
1.1       root      258:                        return NULL;
                    259:                }
                    260:                end++;
1.1.1.6   root      261: 
1.1       root      262:                count = sprintf(valuestr, "$%x", value);
1.1.1.6   root      263:                fprintf(stderr, "- '%s' -> %s\n", start+1, valuestr);
1.1       root      264: 
                    265:                diff = end-start;
                    266:                if (count < diff)
                    267:                {
                    268:                        memcpy(start, valuestr, count);
                    269:                        start += count;
                    270:                        memmove(start, end, strlen(end) + 1);
                    271:                } else {
                    272:                        /* value won't fit to expression, expand string */
                    273:                        char *tmp;
                    274:                        inputlen += count-diff+1;
                    275:                        tmp = malloc(inputlen+1);
                    276:                        if (!tmp)
                    277:                        {
                    278:                                perror("ERROR: Input string alloc failed\n");
1.1.1.7   root      279:                                free(input);
1.1       root      280:                                return NULL;
                    281:                        }
                    282: 
                    283:                        memcpy(tmp, input, start-input);
                    284:                        start = tmp+(start-input);
                    285:                        memcpy(start, valuestr, count);
                    286:                        start += count;
                    287:                        memcpy(start, end, strlen(end) + 1);
                    288: 
1.1.1.6   root      289:                        free(input);
1.1       root      290:                        input = tmp;
                    291:                }
                    292:        }
                    293:        /* no (more) expressions to evaluate */
                    294:        return input;
                    295: }
                    296: 
                    297: 
                    298: /**
                    299:  * Command: Store and restore emulation state
                    300:  */
                    301: static int DebugUI_DoMemorySnap(int argc, char *argv[])
                    302: {
                    303:        const char *file;
                    304: 
                    305:        if (argc > 1)
                    306:                file = argv[1];
                    307:        else
                    308:                file = ConfigureParams.Memory.szMemoryCaptureFileName;
                    309: 
                    310:        if (strcmp(argv[0], "stateload") == 0)
                    311:                MemorySnapShot_Restore(file, true);
                    312:        else
                    313:                MemorySnapShot_Capture(file, true);
                    314: 
                    315:        return DEBUGGER_CMDDONE;
                    316: }
                    317: 
                    318: 
                    319: /**
                    320:  * Command: Set command line and debugger options
                    321:  */
                    322: static int DebugUI_SetOptions(int argc, char *argv[])
                    323: {
                    324:        CNF_PARAMS current;
                    325:        static const struct {
                    326:                const char name[4];
                    327:                int base;
                    328:        } bases[] = {
                    329:                { "bin", 2 },
                    330:                { "dec", 10 },
                    331:                { "hex", 16 }
                    332:        };
                    333:        const char *arg;
                    334:        int i;
                    335:        
                    336:        if (argc < 2)
                    337:        {
1.1.1.7   root      338:                return DebugUI_PrintCmdHelp(argv[0]);
1.1       root      339:        }
                    340:        arg = argv[1];
1.1.1.6   root      341: 
1.1.1.9 ! root      342:        for (i = 0; i < ARRAY_SIZE(bases); i++)
1.1       root      343:        {
                    344:                if (strcasecmp(bases[i].name, arg) == 0)
                    345:                {
                    346:                        if (ConfigureParams.Debugger.nNumberBase != bases[i].base)
                    347:                        {
                    348:                                fprintf(stderr, "Switched default number base from %d to %d-based (%s) values.\n",
                    349:                                        ConfigureParams.Debugger.nNumberBase,
                    350:                                        bases[i].base, bases[i].name);
                    351:                                ConfigureParams.Debugger.nNumberBase = bases[i].base;
                    352:                        } else {
                    353:                                fprintf(stderr, "Already in '%s' mode.\n", bases[i].name);
                    354:                        }
                    355:                        return DEBUGGER_CMDDONE;
                    356:                }
                    357:        }
                    358: 
                    359:        /* get configuration changes */
                    360:        current = ConfigureParams;
                    361: 
                    362:        /* Parse and apply options */
1.1.1.2   root      363:        if (Opt_ParseParameters(argc, (const char * const *)argv))
1.1       root      364:        {
                    365:                ConfigureParams.Screen.bFullScreen = false;
                    366:                Change_CopyChangedParamsToConfiguration(&current, &ConfigureParams, false);
                    367:        }
                    368:        else
                    369:        {
                    370:                ConfigureParams = current;
                    371:        }
                    372: 
                    373:        return DEBUGGER_CMDDONE;
                    374: }
                    375: 
                    376: 
                    377: /**
                    378:  * Command: Set tracing
                    379:  */
                    380: static int DebugUI_SetTracing(int argc, char *argv[])
                    381: {
                    382:        const char *errstr;
                    383:        if (argc != 2)
                    384:        {
1.1.1.7   root      385:                return DebugUI_PrintCmdHelp(argv[0]);
1.1       root      386:        }
                    387:        errstr = Log_SetTraceOptions(argv[1]);
                    388:        if (errstr && errstr[0])
                    389:                fprintf(stderr, "ERROR: %s\n", errstr);
                    390: 
                    391:        return DEBUGGER_CMDDONE;
                    392: }
                    393: 
                    394: 
                    395: /**
                    396:  * Command: Change Hatari work directory
                    397:  */
                    398: static int DebugUI_ChangeDir(int argc, char *argv[])
                    399: {
                    400:        if (argc == 2)
                    401:        {
                    402:                if (chdir(argv[1]) == 0)
                    403:                        return DEBUGGER_CMDDONE;
                    404:                perror("ERROR");
                    405:        }
1.1.1.7   root      406:        return DebugUI_PrintCmdHelp(argv[0]);
                    407: }
                    408: 
                    409: /**
                    410:  * Command: Rename file
                    411:  */
                    412: static int DebugUI_Rename(int argc, char *argv[])
                    413: {
                    414:        if (argc == 3)
                    415:        {
                    416:                if (rename(argv[1], argv[2]) == 0)
                    417:                        return DEBUGGER_CMDDONE;
                    418:                perror("ERROR");
                    419:        }
                    420:        return DebugUI_PrintCmdHelp(argv[0]);
1.1       root      421: }
                    422: 
                    423: 
                    424: /**
1.1.1.8   root      425:  * Command: Reset emulation
                    426:  */
                    427: static char *DebugUI_MatchReset(const char *text, int state)
                    428: {
                    429:        static const char* types[] = {  "cold", "hard", "soft", "warm" };
1.1.1.9 ! root      430:        return DebugUI_MatchHelper(types, ARRAY_SIZE(types), text, state);
1.1.1.8   root      431: }
                    432: static int DebugUI_Reset(int argc, char *argv[])
                    433: {
                    434:        if (argc != 2)
                    435:                return DebugUI_PrintCmdHelp(argv[0]);
                    436: 
                    437:        if (strcmp(argv[1], "soft") == 0 || strcmp(argv[1], "warm") == 0)
                    438:                Reset_Warm();
                    439:        else if (strcmp(argv[1], "cold") == 0 || strcmp(argv[1], "hard") == 0)
                    440:                Reset_Cold();
                    441:        else
                    442:                return DebugUI_PrintCmdHelp(argv[0]);
                    443:        return DEBUGGER_END;
                    444: }
                    445: 
                    446: 
                    447: /**
1.1       root      448:  * Command: Read debugger commands from a file
                    449:  */
                    450: static int DebugUI_CommandsFromFile(int argc, char *argv[])
                    451: {
                    452:        if (argc == 2)
1.1.1.6   root      453:                DebugUI_ParseFile(argv[1], true);
1.1       root      454:        else
                    455:                DebugUI_PrintCmdHelp(argv[0]);
                    456:        return DEBUGGER_CMDDONE;
                    457: }
                    458: 
                    459: 
                    460: /**
                    461:  * Command: Quit emulator
                    462:  */
                    463: static int DebugUI_QuitEmu(int nArgc, char *psArgv[])
                    464: {
1.1.1.7   root      465:        int exitval;
                    466: 
                    467:        if (nArgc > 2)
                    468:                return DebugUI_PrintCmdHelp(psArgv[0]);
                    469: 
                    470:        if (nArgc == 2)
                    471:                exitval = atoi(psArgv[1]);
                    472:        else
                    473:                exitval = 0;
                    474: 
                    475:        ConfigureParams.Log.bConfirmQuit = false;
                    476:        Main_RequestQuit(exitval);
1.1       root      477:        return DEBUGGER_END;
                    478: }
                    479: 
                    480: 
                    481: /**
                    482:  * Print help text for one command
                    483:  */
1.1.1.7   root      484: int DebugUI_PrintCmdHelp(const char *psCmd)
1.1       root      485: {
                    486:        dbgcommand_t *cmd;
                    487:        int i;
                    488: 
                    489:        /* Search the command ... */
                    490:        for (cmd = debugCommand, i = 0; i < debugCommands; i++, cmd++)
                    491:        {
                    492:                if (!debugCommand[i].pFunction)
                    493:                        continue;
                    494:                if ((*(cmd->sShortName) && !strcmp(psCmd, cmd->sShortName))
                    495:                    || !strcmp(psCmd, cmd->sLongName))
                    496:                {
                    497:                        bool bShort = *(cmd->sShortName);
                    498:                        /* ... and print help text */
                    499:                        if (bShort)
                    500:                        {
                    501:                                fprintf(stderr, "'%s' or '%s' - %s\n",
                    502:                                        cmd->sLongName,
                    503:                                        cmd->sShortName,
                    504:                                        cmd->sShortDesc);
                    505:                        }
                    506:                        else
                    507:                        {
                    508:                                fprintf(stderr, "'%s' - %s\n",
                    509:                                        cmd->sLongName,
                    510:                                        cmd->sShortDesc);
                    511:                        }
                    512:                        fprintf(stderr, "Usage:  %s %s\n",
                    513:                                bShort ? cmd->sShortName : cmd->sLongName,
                    514:                                cmd->sUsage);
1.1.1.7   root      515:                        return DEBUGGER_CMDDONE;
1.1       root      516:                }
                    517:        }
                    518: 
                    519:        fprintf(stderr, "Unknown command '%s'\n", psCmd);
1.1.1.7   root      520:        return DEBUGGER_CMDDONE;
1.1       root      521: }
                    522: 
                    523: 
                    524: /**
                    525:  * Command: Print debugger help screen.
                    526:  */
                    527: static int DebugUI_Help(int nArgc, char *psArgs[])
                    528: {
                    529:        int i;
                    530: 
                    531:        if (nArgc > 1)
                    532:        {
1.1.1.7   root      533:                return DebugUI_PrintCmdHelp(psArgs[1]);
1.1       root      534:        }
                    535: 
                    536:        for (i = 0; i < debugCommands; i++)
                    537:        {
                    538:                if (!debugCommand[i].pFunction)
                    539:                {
                    540:                        fprintf(stderr, "\n%s:\n", debugCommand[i].sLongName);
                    541:                        continue;
                    542:                }
                    543:                fprintf(stderr, " %12s (%2s) : %s\n", debugCommand[i].sLongName,
                    544:                        debugCommand[i].sShortName, debugCommand[i].sShortDesc);
                    545:        }
                    546: 
                    547:        fprintf(stderr,
                    548:                "\n"
                    549:                "If value is prefixed with '$', it's a hexadecimal, if with '#', it's\n"
                    550:                "a normal decimal, if with '%%', it's a binary decimal. Prefix can\n"
                    551:                "be skipped for numbers in the default number base (currently %d).\n"
                    552:                "\n"
                    553:                "Any expression given in quotes (within \"\"), will be evaluated\n"
                    554:                "before given to the debugger command.  Any register and symbol\n"
                    555:                "names in the expression are replaced by their values.\n"
                    556:                "\n"
                    557:                "Note that address ranges like '$fc0000-$fc0100' should have no\n"
                    558:                "spaces between the range numbers.\n"
                    559:                "\n"
                    560:                "'help <command>' gives more help.\n", ConfigureParams.Debugger.nNumberBase);
                    561:        return DEBUGGER_CMDDONE;
                    562: }
                    563: 
                    564: 
                    565: /**
                    566:  * Parse debug command and execute it.
                    567:  */
1.1.1.2   root      568: static int DebugUI_ParseCommand(const char *input_orig)
1.1       root      569: {
1.1.1.2   root      570:        char *psArgs[64], *input;
1.1       root      571:        const char *delim;
                    572:        static char sLastCmd[80] = { '\0' };
                    573:        int nArgc, cmd = -1;
                    574:        int i, retval;
                    575: 
1.1.1.2   root      576:        input = strdup(input_orig);
1.1       root      577:        psArgs[0] = strtok(input, " \t");
                    578: 
                    579:        if (psArgs[0] == NULL)
                    580:        {
                    581:                if (strlen(sLastCmd) > 0)
                    582:                        psArgs[0] = sLastCmd;
                    583:                else
1.1.1.2   root      584:                {
                    585:                        free(input);
1.1       root      586:                        return DEBUGGER_CMDDONE;
1.1.1.2   root      587:                }
1.1       root      588:        }
                    589: 
                    590:        /* Search the command ... */
                    591:        for (i = 0; i < debugCommands; i++)
                    592:        {
                    593:                if (!debugCommand[i].pFunction)
                    594:                        continue;
                    595:                if (!strcmp(psArgs[0], debugCommand[i].sShortName) ||
                    596:                    !strcmp(psArgs[0], debugCommand[i].sLongName))
                    597:                {
                    598:                        cmd = i;
                    599:                        break;
                    600:                }
                    601:        }
                    602:        if (cmd == -1)
                    603:        {
                    604:                fprintf(stderr, "Command '%s' not found.\n"
                    605:                        "Use 'help' to view a list of available commands.\n",
                    606:                        psArgs[0]);
1.1.1.2   root      607:                free(input);
1.1       root      608:                return DEBUGGER_CMDDONE;
                    609:        }
                    610: 
                    611:        if (debugCommand[cmd].bNoParsing)
                    612:                delim = "";
                    613:        else
                    614:                delim = " \t";
                    615: 
                    616:        /* Separate arguments and put the pointers into psArgs */
1.1.1.9 ! root      617:        for (nArgc = 1; nArgc < ARRAY_SIZE(psArgs); nArgc++)
1.1       root      618:        {
                    619:                psArgs[nArgc] = strtok(NULL, delim);
                    620:                if (psArgs[nArgc] == NULL)
                    621:                        break;
                    622:        }
                    623: 
                    624:        /* ... and execute the function */
                    625:        retval = debugCommand[i].pFunction(nArgc, psArgs);
                    626:        /* Save commando string if it can be repeated */
                    627:        if (retval == DEBUGGER_CMDCONT)
1.1.1.7   root      628:        {
                    629:                if (psArgs[0] != sLastCmd)
1.1.1.8   root      630:                        strlcpy(sLastCmd, psArgs[0], sizeof(sLastCmd));
1.1.1.7   root      631:        }
1.1       root      632:        else
                    633:                sLastCmd[0] = '\0';
1.1.1.2   root      634:        free(input);
1.1       root      635:        return retval;
                    636: }
                    637: 
                    638: 
                    639: /* See "info:readline" e.g. in Konqueror for readline usage. */
                    640: 
                    641: /**
1.1.1.7   root      642:  * Generic readline match callback helper.
                    643:  * STATE = 0 -> different text from previous one.
                    644:  * Return next match or NULL if no matches.
                    645:  */
                    646: char *DebugUI_MatchHelper(const char **strings, int items, const char *text, int state)
                    647: {
                    648:        static int i, len;
                    649:        
                    650:        if (!state)
                    651:        {
                    652:                /* first match */
                    653:                len = strlen(text);
                    654:                i = 0;
                    655:        }
                    656:        /* next match */
                    657:        while (i < items) {
                    658:                if (strncasecmp(strings[i++], text, len) == 0)
                    659:                        return (strdup(strings[i-1]));
                    660:        }
                    661:        return NULL;
                    662: }
                    663: 
                    664: /**
1.1       root      665:  * Readline match callback for long command name completion.
                    666:  * STATE = 0 -> different text from previous one.
                    667:  * Return next match or NULL if no matches.
                    668:  */
                    669: static char *DebugUI_MatchCommand(const char *text, int state)
                    670: {
                    671:        static int i, len;
                    672:        const char *name;
                    673:        
                    674:        if (!state)
                    675:        {
                    676:                /* first match */
                    677:                len = strlen(text);
                    678:                i = 0;
                    679:        }
                    680:        /* next match */
                    681:        while (i < debugCommands)
                    682:        {
                    683:                name = debugCommand[i].sLongName;
                    684:                if (debugCommand[i++].pFunction &&
                    685:                    strncmp(name, text, len) == 0)
                    686:                        return (strdup(name));
                    687:        }
                    688:        return NULL;
                    689: }
                    690: 
                    691: 
                    692: #if HAVE_LIBREADLINE
                    693: /**
                    694:  * Readline match callback returning last result.
                    695:  */
                    696: static char *DebugUI_MatchLast(const char *text, int state)
                    697: {
                    698:        if (state)
                    699:                return NULL;
                    700:        return strdup(lastResult);
                    701: }
                    702: 
                    703: /**
                    704:  * Readline completion callback. Returns matches.
                    705:  */
                    706: static char **DebugUI_Completion(const char *text, int a, int b)
                    707: {
                    708:        int i, cmd, quotes, end, start = 0;
                    709:        char *str, buf[32];
                    710:        size_t len;
                    711: 
                    712:        /* check where's the first word (ignore white space) */
1.1.1.7   root      713:        while (start < rl_point && isspace((unsigned char)rl_line_buffer[start]))
1.1       root      714:                start++;
                    715:        end = start;
1.1.1.7   root      716:        while (end < rl_point && !isspace((unsigned char)rl_line_buffer[end]))
1.1       root      717:                end++;
                    718: 
                    719:        if (end >= rl_point)
                    720:                /* first word on line */
                    721:                return rl_completion_matches(text, DebugUI_MatchCommand);
                    722:        
                    723:        /* complete '$' with last result? */
                    724:        if (lastResult[0] && rl_line_buffer[rl_point-1] == '$')
                    725:                return rl_completion_matches(text, DebugUI_MatchLast);
                    726: 
                    727:        /* check which command args are to be completed */
                    728:        len = end - start;
                    729:        if (len >= sizeof(buf))
                    730:                len = sizeof(buf)-1;
                    731:        memcpy(buf, &(rl_line_buffer[start]), len);
                    732:        buf[len] = '\0';
                    733: 
                    734:        /* expression completion needed (= open quote)? */
                    735:        str = strchr(&(rl_line_buffer[end]), '"');
                    736:        quotes = 0;
                    737:        while (str)
                    738:        {
                    739:                quotes++;
                    740:                str = strchr(str+1, '"');
                    741:        }
                    742:        if (quotes & 1)
                    743:        {
                    744:                if (DebugUI_IsForDsp(buf))
                    745:                        return rl_completion_matches(text, Symbols_MatchDspAddress);
                    746:                return rl_completion_matches(text, Symbols_MatchCpuAddress);
                    747:        }
                    748: 
                    749:        /* do command argument completion */
                    750:        cmd = -1;
                    751:        for (i = 0; i < debugCommands; i++)
                    752:        {
                    753:                if (!debugCommand[i].pFunction)
                    754:                        continue;
                    755:                if (!strcmp(buf, debugCommand[i].sShortName) ||
                    756:                    !strcmp(buf, debugCommand[i].sLongName))
                    757:                {
                    758:                        cmd = i;
                    759:                        break;
                    760:                }
                    761:        }
                    762:        if (cmd < 0)
                    763:        {
                    764:                rl_attempted_completion_over = true;
                    765:                return NULL;
                    766:        }
                    767:        if (debugCommand[cmd].pMatch)
                    768:                return rl_completion_matches(text, debugCommand[cmd].pMatch);
                    769:        else
                    770:                return rl_completion_matches(text, rl_filename_completion_function);
                    771: }
                    772: 
1.1.1.6   root      773: /**
                    774:  * Add non-repeated command to readline history
                    775:  * and free the given string
                    776:  */
1.1.1.7   root      777: static void DebugUI_FreeCommand(char *input)
1.1.1.6   root      778: {
                    779:        if (input && *input)
                    780:        {
                    781:                HIST_ENTRY *hist = history_get(history_length);
                    782:                /* don't store duplicate successive entries */
                    783:                if (!hist || !hist->line || strcmp(hist->line, input) != 0)
                    784:                {
                    785:                        add_history(input);
                    786:                }
                    787:                free(input);
                    788:        }
                    789: }
1.1       root      790: 
                    791: /**
                    792:  * Read a command line from the keyboard and return a pointer to the string.
1.1.1.2   root      793:  * Only string returned by this function can be given for it as argument!
                    794:  * The string will be stored into command history buffer.
1.1.1.6   root      795:  * @return     Pointer to the string which should be given back to this
                    796:  *              function or DebugUI_FreeCommand() for re-use/history.
                    797:  *              Returns NULL when error occurred.
1.1       root      798:  */
1.1.1.2   root      799: static char *DebugUI_GetCommand(char *input)
1.1       root      800: {
                    801:        /* Allow conditional parsing of the ~/.inputrc file. */
                    802:        rl_readline_name = "Hatari";
                    803:        
                    804:        /* Tell the completer that we want a crack first. */
                    805:        rl_attempted_completion_function = DebugUI_Completion;
1.1.1.7   root      806:        DebugUI_FreeCommand(input);
1.1.1.2   root      807:        return Str_Trim(readline("> "));
1.1       root      808: }
                    809: 
                    810: #else /* !HAVE_LIBREADLINE */
                    811: 
                    812: /**
1.1.1.6   root      813:  * Free Command input string
                    814:  */
1.1.1.7   root      815: static void DebugUI_FreeCommand(char *input)
1.1.1.6   root      816: {
1.1.1.9 ! root      817:        free(input);
1.1.1.6   root      818: }
                    819: 
                    820: /**
1.1       root      821:  * Read a command line from the keyboard and return a pointer to the string.
1.1.1.2   root      822:  * Only string returned by this function can be given for it as argument!
1.1.1.6   root      823:  * @return     Pointer to the string which should be given back to this
                    824:  *              function or DebugUI_FreeCommand() for re-use/freeing.
                    825:  *              Returns NULL when error occurred.
1.1       root      826:  */
1.1.1.2   root      827: static char *DebugUI_GetCommand(char *input)
1.1       root      828: {
                    829:        fprintf(stderr, "> ");
                    830:        if (!input)
1.1.1.2   root      831:        {
                    832:                input = malloc(256);
                    833:                assert(input);
                    834:        }
1.1       root      835:        input[0] = '\0';
                    836:        if (fgets(input, 256, stdin) == NULL)
                    837:        {
                    838:                free(input);
                    839:                return NULL;
                    840:        }
                    841:        return Str_Trim(input);
                    842: }
                    843: 
                    844: #endif /* !HAVE_LIBREADLINE */
                    845: 
                    846: 
                    847: static const dbgcommand_t uicommand[] =
                    848: {
                    849:        { NULL, NULL, "Generic commands", NULL, NULL, NULL, false },
                    850:        /* NULL as match function will complete file names */
                    851:        { DebugUI_ChangeDir, NULL,
                    852:          "cd", "",
                    853:          "change directory",
                    854:          "<directory>\n"
                    855:          "\tChange Hatari work directory.",
                    856:          false },
1.1.1.9 ! root      857:        { DebugUI_Evaluate, Vars_MatchCpuVariable,
1.1       root      858:          "evaluate", "e",
                    859:          "evaluate an expression",
                    860:          "<expression>\n"
                    861:          "\tEvaluate an expression and show the result.  Expression can\n"
1.1.1.9 ! root      862:          "\tinclude CPU register & symbol and Hatari variable names.\n"
        !           863:          "\tThose are replaced by their values. Supported operators in\n"
        !           864:          "\texpressions are, in the decending order of precedence:\n"
1.1       root      865:          "\t\t(), +, -, ~, *, /, +, -, >>, <<, ^, &, |\n"
1.1.1.2   root      866:          "\tParenthesis will fetch a _long_ value from the address\n"
                    867:          "\tto what the value inside it evaluates to. Prefixes can be\n"
                    868:          "\tused only in start of line or parenthesis.\n"
1.1       root      869:          "\tFor example:\n"
1.1.1.2   root      870:          "\t\t~%101 & $f0f0f ^ (d0 + 0x21)\n"
1.1       root      871:          "\tResult value is shown as binary, decimal and hexadecimal.\n"
                    872:          "\tAfter this, '$' will TAB-complete to last result value.",
                    873:          true },
                    874:        { DebugUI_Help, DebugUI_MatchCommand,
                    875:          "help", "h",
                    876:          "print help",
                    877:          "[command]\n"
                    878:          "\tPrint help text for available commands.",
                    879:          false },
1.1.1.7   root      880:        { History_Parse, History_Match,
1.1.1.3   root      881:          "history", "hi",
1.1.1.6   root      882:          "show last CPU/DSP PC values & executed instructions",
1.1.1.8   root      883:          "cpu|dsp|on|off|<count> [limit]|save <file>\n"
1.1.1.7   root      884:          "\t'cpu' and 'dsp' enable instruction history tracking for just given\n"
                    885:          "\tprocessor, 'on' tracks them both, 'off' will disable history.\n"
                    886:          "\tOptional 'limit' will set how many past instructions are tracked.\n"
                    887:          "\tGiving just count will show (at max) given number of last saved PC\n"
                    888:          "\tvalues and instructions currently at corresponding RAM addresses.",
1.1.1.3   root      889:          false },
1.1       root      890:        { DebugInfo_Command, DebugInfo_MatchInfo,
                    891:          "info", "i",
                    892:          "show machine/OS information",
                    893:          "[subject [arg]]\n"
                    894:          "\tPrint information on requested subject or list them if\n"
                    895:          "\tno subject given.",
                    896:          false },
                    897:        { DebugInfo_Command, DebugInfo_MatchLock,
                    898:          "lock", "",
1.1.1.2   root      899:          "specify information to show on entering the debugger",
1.1       root      900:          "[subject [args]]\n"
1.1.1.2   root      901:          "\tLock what information should be shown every time debugger\n"
                    902:          "\tis entered, or list available options if no subject's given.",
1.1       root      903:          false },
                    904:        { DebugUI_SetLogFile, NULL,
                    905:          "logfile", "f",
                    906:          "open or close log file",
                    907:          "[filename]\n"
                    908:          "\tOpen log file, no argument closes the log file. Output of\n"
                    909:          "\tregister & memory dumps and disassembly will be written to it.",
                    910:          false },
                    911:        { DebugUI_CommandsFromFile, NULL,
                    912:          "parse", "p",
                    913:          "get debugger commands from file",
                    914:          "[filename]\n"
                    915:          "\tRead debugger commands from given file and do them.",
                    916:          false },
1.1.1.7   root      917:        { DebugUI_Rename, NULL,
                    918:          "rename", "",
                    919:          "rename given file",
                    920:          "old new\n"
                    921:          "\tRenames file with 'old' name to 'new'.",
                    922:          false },
1.1.1.8   root      923:        { DebugUI_Reset, DebugUI_MatchReset,
                    924:          "reset", "",
                    925:          "reset emulation",
                    926:          "<soft|hard>\n",
                    927:          false },
1.1       root      928:        { DebugUI_SetOptions, Opt_MatchOption,
                    929:          "setopt", "o",
                    930:          "set Hatari command line and debugger options",
1.1.1.6   root      931:          "[bin|dec|hex|<command line options>]\n"
1.1.1.8   root      932:          "\tSpecial 'bin', 'dec' and 'hex' arguments change the default\n"
                    933:          "\tnumber base used in debugger.  <TAB> lists available command\n"
                    934:          "\tline options, 'setopt --help' their descriptions.",
1.1       root      935:          false },
                    936:        { DebugUI_DoMemorySnap, NULL,
                    937:          "stateload", "",
                    938:          "restore emulation state",
                    939:          "[filename]\n"
                    940:          "\tRestore emulation snapshot from default or given file",
                    941:          false },
                    942:        { DebugUI_DoMemorySnap, NULL,
                    943:          "statesave", "",
                    944:          "save emulation state",
                    945:          "[filename]\n"
                    946:          "\tSave emulation snapshot to default or given file",
                    947:          false },
                    948:        { DebugUI_SetTracing, Log_MatchTrace,
                    949:          "trace", "t",
                    950:          "select Hatari tracing settings",
                    951:          "[set1,set2...]\n"
1.1.1.2   root      952:          "\tSelect Hatari tracing settings. 'help' shows all the available\n"
                    953:          "\tsettings.  For example, to enable CPU disassembly and VBL\n"
                    954:          "\ttracing, use:\n\t\ttrace cpu_disasm,video_hbl",
1.1       root      955:          false },
1.1.1.9 ! root      956:        { Vars_List, NULL,
        !           957:          "variables", "v",
        !           958:          "List builtin symbols / variables",
        !           959:          "\n"
        !           960:          "\tList Hatari debugger builtin symbols / variables and their values.\n"
        !           961:          "\tThey're accepted by breakpoints and evaluate command.",
        !           962:          false },
1.1       root      963:        { DebugUI_QuitEmu, NULL,
                    964:          "quit", "q",
                    965:          "quit emulator",
1.1.1.7   root      966:          "[exit value]\n"
                    967:          "\tLeave debugger and quit emulator with given exit value.",
1.1       root      968:          false }
                    969: };
                    970: 
                    971: 
                    972: /**
                    973:  * Debugger user interface initialization.
                    974:  */
                    975: void DebugUI_Init(void)
                    976: {
                    977:        const dbgcommand_t *cpucmd, *dspcmd;
                    978:        int cpucmds, dspcmds;
                    979: 
                    980:        /* already intialized? */
                    981:        if (debugCommands)
                    982:                return;
                    983: 
1.1.1.9 ! root      984:        if (!debugOutput)
        !           985:                DebugUI_SetLogDefault();
        !           986: 
1.1       root      987:        /* if you want disassembly or memdumping to start/continue from
                    988:         * specific address, you can set them in these functions.
                    989:         */
                    990:        dspcmds = DebugDsp_Init(&dspcmd);
                    991:        cpucmds = DebugCpu_Init(&cpucmd);
                    992: 
                    993:        /* on first time copy the command structures to a single table */
1.1.1.9 ! root      994:        debugCommands = ARRAY_SIZE(uicommand);
1.1       root      995:        debugCommand = malloc(sizeof(dbgcommand_t) * (dspcmds + cpucmds + debugCommands));
                    996:        assert(debugCommand);
                    997:        
                    998:        memcpy(debugCommand, uicommand, sizeof(dbgcommand_t) * debugCommands);
                    999:        memcpy(&debugCommand[debugCommands], cpucmd, sizeof(dbgcommand_t) * cpucmds);
                   1000:        debugCommands += cpucmds;
                   1001:        memcpy(&debugCommand[debugCommands], dspcmd, sizeof(dbgcommand_t) * dspcmds);
                   1002:        debugCommands += dspcmds;
                   1003: 
                   1004:        if (parseFileName)
1.1.1.6   root     1005:                DebugUI_ParseFile(parseFileName, true);
1.1       root     1006: }
                   1007: 
                   1008: 
                   1009: /**
1.1.1.2   root     1010:  * Set debugger commands file during Hatari startup before things
                   1011:  * needed by the debugger are initialized so that it can be parsed
                   1012:  * when debugger itself gets initialized.
1.1       root     1013:  * Return true if file exists, false otherwise.
                   1014:  */
                   1015: bool DebugUI_SetParseFile(const char *path)
                   1016: {
                   1017:        if (File_Exists(path))
                   1018:        {
                   1019:                parseFileName = path;
                   1020:                return true;
                   1021:        }
                   1022:        fprintf(stderr, "ERROR: debugger input file '%s' missing.\n", path);
                   1023:        return false;
                   1024: }
                   1025: 
                   1026: 
                   1027: /**
                   1028:  * Debugger user interface main function.
                   1029:  */
1.1.1.3   root     1030: void DebugUI(debug_reason_t reason)
1.1       root     1031: {
                   1032:        int cmdret, alertLevel;
1.1.1.2   root     1033:        char *expCmd, *psCmd = NULL;
1.1       root     1034:        static const char *welcome =
                   1035:                "\n----------------------------------------------------------------------"
                   1036:                "\nYou have entered debug mode. Type c to continue emulation, h for help.\n";
1.1.1.8   root     1037:        static bool recursing;
                   1038: 
                   1039:        if (recursing)
                   1040:        {
                   1041:                fprintf(stderr, "WARNING: recursive call to DebugUI (through profiler debug option?)!\n");
                   1042:                recursing = false;
                   1043:                return;
                   1044:        }
                   1045:        recursing = true;
1.1.1.3   root     1046: 
                   1047:        History_Mark(reason);
                   1048: 
1.1       root     1049:        if (bInFullScreen)
                   1050:                Screen_ReturnFromFullScreen();
                   1051: 
1.1.1.7   root     1052:        /* Make sure mouse isn't grabbed regardless of where
                   1053:         * this is invoked from.  E.g. returning from fullscreen
                   1054:         * enables grab if that was enabled on windowed mode.
                   1055:         */
                   1056:        SDL_WM_GrabInput(SDL_GRAB_OFF);
                   1057: 
1.1       root     1058:        DebugUI_Init();
                   1059: 
                   1060:        if (welcome)
                   1061:        {
                   1062:                fputs(welcome, stderr);
                   1063:                welcome = NULL;
                   1064:        }
                   1065:        DebugCpu_InitSession();
                   1066:        DebugDsp_InitSession();
1.1.1.7   root     1067:        Symbols_LoadCurrentProgram();
1.1       root     1068:        DebugInfo_ShowSessionInfo();
                   1069: 
                   1070:        /* override paused message so that user knows to look into console
                   1071:         * on how to continue in case he invoked the debugger by accident.
                   1072:         */
                   1073:        Statusbar_AddMessage("Console Debugger", 100);
1.1.1.7   root     1074:        Statusbar_Update(sdlscrn, true);
1.1       root     1075: 
                   1076:        /* disable normal GUI alerts while on console */
                   1077:        alertLevel = Log_SetAlertLevel(LOG_FATAL);
                   1078: 
                   1079:        cmdret = DEBUGGER_CMDDONE;
                   1080:        do
                   1081:        {
1.1.1.2   root     1082:                /* Read command from the keyboard and give previous
                   1083:                 * command for freeing / adding to history
                   1084:                 */
                   1085:                psCmd = DebugUI_GetCommand(psCmd);
1.1       root     1086:                if (!psCmd)
                   1087:                        break;
                   1088: 
1.1.1.6   root     1089:                /* returns new expression expanded string */
1.1.1.2   root     1090:                if (!(expCmd = DebugUI_EvaluateExpressions(psCmd)))
1.1       root     1091:                        continue;
                   1092: 
                   1093:                /* Parse and execute the command string */
1.1.1.2   root     1094:                cmdret = DebugUI_ParseCommand(expCmd);
1.1.1.6   root     1095:                free(expCmd);
1.1       root     1096:        }
                   1097:        while (cmdret != DEBUGGER_END);
                   1098: 
1.1.1.6   root     1099:        /* free exit command */
1.1.1.7   root     1100:        DebugUI_FreeCommand(psCmd);
1.1.1.2   root     1101: 
1.1       root     1102:        Log_SetAlertLevel(alertLevel);
                   1103: 
                   1104:        DebugCpu_SetDebugging();
                   1105:        DebugDsp_SetDebugging();
1.1.1.8   root     1106: 
                   1107:        recursing = false;
1.1       root     1108: }
                   1109: 
                   1110: 
                   1111: /**
1.1.1.6   root     1112:  * Read debugger commands from a file.  If 'reinit' is set
                   1113:  * (as it normally should), reinitialize breakpoints etc.
                   1114:  * afterwards. return false for error, true for success.
1.1       root     1115:  */
1.1.1.6   root     1116: bool DebugUI_ParseFile(const char *path, bool reinit)
1.1       root     1117: {
1.1.1.2   root     1118:        char *olddir, *dir, *cmd, *input, *expanded, *slash;
1.1       root     1119:        FILE *fp;
                   1120: 
                   1121:        fprintf(stderr, "Reading debugger commands from '%s'...\n", path);
                   1122:        if (!(fp = fopen(path, "r")))
                   1123:        {
                   1124:                perror("ERROR");
                   1125:                return false;
                   1126:        }
                   1127: 
                   1128:        /* change to directory where the debugger file resides */
1.1.1.2   root     1129:        olddir = NULL;
1.1       root     1130:        dir = strdup(path);
                   1131:        slash = strrchr(dir, PATHSEP);
                   1132:        if (slash)
                   1133:        {
1.1.1.2   root     1134:                olddir = malloc(FILENAME_MAX);
                   1135:                if (olddir)
                   1136:                {
                   1137:                        if (!getcwd(olddir, FILENAME_MAX))
                   1138:                                strcpy(olddir, ".");
                   1139:                }
1.1       root     1140:                *slash = '\0';
1.1.1.2   root     1141:                if (chdir(dir) != 0)
1.1       root     1142:                {
                   1143:                        perror("ERROR");
1.1.1.9 ! root     1144:                        free(olddir);
1.1       root     1145:                        free(dir);
1.1.1.6   root     1146:                        fclose(fp);
1.1       root     1147:                        return false;
                   1148:                }
1.1.1.2   root     1149:                fprintf(stderr, "Changed to input file dir '%s'.\n", dir);
1.1       root     1150:        }
                   1151:        free(dir);
                   1152: 
                   1153:        input = NULL;
                   1154:        for (;;)
                   1155:        {
                   1156:                if (!input)
                   1157:                {
                   1158:                        input = malloc(256);
                   1159:                        assert(input);
                   1160:                }
                   1161:                if (!fgets(input, 256, fp))
                   1162:                        break;
                   1163: 
1.1.1.2   root     1164:                /* ignore empty and comment lines */
                   1165:                cmd = Str_Trim(input);
                   1166:                if (!*cmd || *cmd == '#')
1.1       root     1167:                        continue;
                   1168: 
1.1.1.2   root     1169:                /* returns new string if input needed expanding! */
                   1170:                expanded = DebugUI_EvaluateExpressions(input);
                   1171:                if (!expanded)
                   1172:                        continue;
                   1173: 
                   1174:                cmd = Str_Trim(expanded);
                   1175:                fprintf(stderr, "> %s\n", cmd);
                   1176:                DebugUI_ParseCommand(cmd);
1.1.1.6   root     1177:                free(expanded);
1.1       root     1178:        }
                   1179: 
                   1180:        free(input);
1.1.1.6   root     1181:        fclose(fp);
                   1182: 
1.1.1.2   root     1183:        if (olddir)
                   1184:        {
                   1185:                if (chdir(olddir) != 0)
                   1186:                        perror("ERROR");
                   1187:                else
                   1188:                        fprintf(stderr, "Changed back to '%s' dir.\n", olddir);
                   1189:                free(olddir);
                   1190:        }
1.1       root     1191: 
1.1.1.6   root     1192:        if (reinit)
                   1193:        {
                   1194:                DebugCpu_SetDebugging();
                   1195:                DebugDsp_SetDebugging();
                   1196:        }
1.1       root     1197:        return true;
                   1198: }
                   1199: 
                   1200: 
                   1201: /**
1.1.1.6   root     1202:  * Remote/parallel debugger line usage API.
1.1       root     1203:  * Return false for failed command, true for success.
                   1204:  */
1.1.1.6   root     1205: bool DebugUI_ParseLine(const char *input)
1.1       root     1206: {
1.1.1.6   root     1207:        char *expanded;
                   1208:        int ret = 0;
1.1       root     1209: 
                   1210:        DebugUI_Init();
                   1211: 
1.1.1.6   root     1212:        /* returns new string if input needed expanding! */
                   1213:        expanded = DebugUI_EvaluateExpressions(input);
                   1214:        if (expanded)
                   1215:        {
                   1216:                fprintf(stderr, "> %s\n", expanded);
                   1217:                ret = DebugUI_ParseCommand(expanded);
                   1218:                free(expanded);
1.1       root     1219: 
1.1.1.6   root     1220:                DebugCpu_SetDebugging();
                   1221:                DebugDsp_SetDebugging();
                   1222:        }
1.1       root     1223:        return (ret == DEBUGGER_CMDDONE);
                   1224: }
1.1.1.7   root     1225: 
                   1226: /**
                   1227:  * Debugger invocation based on exception
                   1228:  */
                   1229: void DebugUI_Exceptions(int nr, long pc)
                   1230: {
                   1231:        static struct {
                   1232:                int flag;
                   1233:                const char *name;
                   1234:        } ex[] = {
                   1235:                { EXCEPT_BUS,       "Bus error" },              /* 2 */
                   1236:                { EXCEPT_ADDRESS,   "Address error" },          /* 3 */
                   1237:                { EXCEPT_ILLEGAL,   "Illegal instruction" },    /* 4 */
                   1238:                { EXCEPT_ZERODIV,   "Div by zero" },            /* 5 */
                   1239:                { EXCEPT_CHK,       "CHK" },                    /* 6 */
                   1240:                { EXCEPT_TRAPV,     "TRAPV" },                  /* 7 */
1.1.1.9 ! root     1241:                { EXCEPT_PRIVILEGE, "Privilege violation" },    /* 8 */
        !          1242:                { EXCEPT_TRACE,     "Trace" }                   /* 9 */
1.1.1.7   root     1243:        };
                   1244:        nr -= 2;
1.1.1.9 ! root     1245:        if (nr < 0  || nr >= ARRAY_SIZE(ex))
1.1.1.7   root     1246:                return;
                   1247:        if (!(ExceptionDebugMask & ex[nr].flag))
                   1248:                return;
                   1249:        fprintf(stderr,"%s exception at 0x%lx!\n", ex[nr].name, pc);
                   1250:        DebugUI(REASON_CPU_EXCEPTION);
                   1251: }

unix.superglobalmegacorp.com

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