Annotation of previous/src/debug/debugui.c, revision 1.1.1.4

1.1       root        1: /*
                      2:   Hatari - debugui.c
                      3: 
                      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: 
                      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 "screen.h"
                     31: #include "statusbar.h"
                     32: #include "str.h"
                     33: 
                     34: #include "debug_priv.h"
                     35: #include "breakcond.h"
                     36: #include "debugcpu.h"
                     37: #include "debugInfo.h"
                     38: #include "debugui.h"
                     39: #include "evaluate.h"
                     40: #include "symbols.h"
                     41: 
                     42: int bExceptionDebugging;
                     43: 
1.1.1.3   root       44: FILE *debugOutput = NULL;
1.1       root       45: 
                     46: static dbgcommand_t *debugCommand;
                     47: static int debugCommands;
                     48: 
                     49: /* stores last 'e' command result as hex, used for TAB-completion */
                     50: static char lastResult[10];
                     51: 
                     52: static const char *parseFileName;
                     53: 
                     54: 
                     55: /**
                     56:  * Save/Restore snapshot of debugging session variables
                     57:  */
                     58: void DebugUI_MemorySnapShot_Capture(const char *path, bool bSave)
                     59: {
                     60:        char *filename;
                     61: 
                     62:        filename = malloc(strlen(path) + strlen(".debug") + 1);
                     63:        assert(filename);
                     64:        strcpy(filename, path);
                     65:        strcat(filename, ".debug");
                     66:        
                     67:        if (bSave)
                     68:        {
                     69:                /* save breakpoints as debugger input file */
                     70:                BreakCond_Save(filename);
                     71:        }
                     72:        else
                     73:        {
                     74:                /* remove current CPU and DSP breakpoints */
                     75:                BreakCond_Command("all", false);
                     76:                BreakCond_Command("all", true);
                     77: 
                     78:                if (File_Exists(filename))
                     79:                {
                     80:                        /* and parse back the saved breakpoints */
                     81:                        DebugUI_ParseFile(filename);
                     82:                }
                     83:        }
                     84:        free(filename);
                     85: }
                     86: 
                     87: 
                     88: /**
                     89:  * Close a log file if open, and set it to default stream.
                     90:  */
                     91: static void DebugUI_SetLogDefault(void)
                     92: {
                     93:        if (debugOutput != stderr)
                     94:        {
                     95:                if (debugOutput)
                     96:                {
                     97:                        File_Close(debugOutput);
                     98:                        fprintf(stderr, "Debug log closed.\n");
                     99:                }
                    100:                debugOutput = stderr;
                    101:        }
                    102: }
                    103: 
                    104: 
                    105: /**
                    106:  * Open (or close) given log file.
                    107:  */
                    108: static int DebugUI_SetLogFile(int nArgc, char *psArgs[])
                    109: {
                    110:        File_Close(debugOutput);
                    111:        debugOutput = NULL;
                    112: 
                    113:        if (nArgc > 1)
                    114:                debugOutput = File_Open(psArgs[1], "w");
                    115: 
                    116:        if (debugOutput)
                    117:                fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]);
                    118:        else
                    119:                debugOutput = stderr;
                    120: 
                    121:        return DEBUGGER_CMDDONE;
                    122: }
                    123: 
                    124: 
                    125: /**
                    126:  * Helper to print given value in all supported number bases
                    127:  */
                    128: static void DebugUI_PrintValue(Uint32 value)
                    129: {
                    130:        bool one, ones;
                    131:        int bit;
                    132: 
                    133:        fputs("= %", stderr);
                    134:        ones = false;
                    135:        for (bit = 31; bit >= 0; bit--)
                    136:        {
                    137:                one = value & (1<<bit);
                    138:                if (one || ones)
                    139:                {
                    140:                        fputc(one ? '1':'0', stderr);
                    141:                        ones = true;
                    142:                }
                    143:        }
                    144:        if (!ones)
                    145:                fputc('0', stderr);
                    146:        if (value & 0x80000000)
                    147:                fprintf(stderr, " (bin), #%u/%d (dec), $%x (hex)\n", value, (int)value, value);
                    148:        else
                    149:                fprintf(stderr, " (bin), #%u (dec), $%x (hex)\n", value, value);
                    150: 
                    151:        sprintf(lastResult, "%x", value);
                    152: }
                    153: 
                    154: 
                    155: /**
                    156:  * Commmand: Evaluate an expression with CPU reg and symbol parsing.
                    157:  */
                    158: static int DebugUI_Evaluate(int nArgc, char *psArgs[])
                    159: {
                    160:        const char *errstr, *expression = (const char *)psArgs[1];
                    161:        Uint32 result;
                    162:        int offset;
                    163: 
                    164:        if (nArgc < 2)
                    165:        {
                    166:                DebugUI_PrintCmdHelp(psArgs[0]);
                    167:                return DEBUGGER_CMDDONE;
                    168:        }
                    169: 
                    170:        errstr = Eval_Expression(expression, &result, &offset, false);
                    171:        if (errstr)
                    172:                fprintf(stderr, "ERROR in the expression:\n'%s'\n%*c-%s\n",
                    173:                        expression, offset+3, '^', errstr);
                    174:        else
                    175:                DebugUI_PrintValue(result);
                    176:        return DEBUGGER_CMDDONE;
                    177: }
                    178: 
                    179: 
                    180: /**
                    181:  * Check whether given string is a two letter command starting with 'd'
                    182:  * or a long command starting with "dsp". String should be trimmed.
                    183:  * Return true if given string is command for DSP, false otherwise.
                    184:  */
                    185: static bool DebugUI_IsForDsp(const char *cmd)
                    186: {
                    187:        return ((cmd[0] == 'd' && cmd[1] && !cmd[2])
                    188:                || strncmp(cmd, "dsp", 3) == 0);
                    189: }
                    190: 
                    191: /**
                    192:  * Evaluate everything include within "" and replace them with the result.
1.1.1.2   root      193:  * Caller needs to free the returned string separately if its address
                    194:  * doesn't match the given input string.
1.1       root      195:  * 
1.1.1.2   root      196:  * Return string with expressions (potentially) expanded, or
                    197:  * NULL when there's an error in the expression.
1.1       root      198:  */
                    199: static char *DebugUI_EvaluateExpressions(char *input)
                    200: {
1.1.1.2   root      201:        int offset, count, diff, inputlen;
                    202:     char *end, *start, *initial;
1.1       root      203:        const char *errstr;
                    204:        char valuestr[12];
                    205:        Uint32 value;
                    206:        bool fordsp;
                    207: 
                    208:        /* input is split later on, need to save len here */
                    209:        fordsp = DebugUI_IsForDsp(input);
                    210:        inputlen = strlen(input);
1.1.1.2   root      211:        initial = start = input;
1.1       root      212:        
                    213:        while ((start = strchr(start, '"')))
                    214:        {
                    215:                end = strchr(start+1, '"');
                    216:                if (!end)
                    217:                {
                    218:                        fprintf(stderr, "ERROR: matching '\"' missing from '%s'!\n", start);
                    219:                        return NULL;
                    220:                }
                    221:                
                    222:                if (end == start+1)
                    223:                {
                    224:                        /* empty expression */
                    225:                        memmove(start, start+2, strlen(start+2)+1);
                    226:                        continue;
                    227:                }
                    228: 
                    229:                *end = '\0';
                    230:                errstr = Eval_Expression(start+1, &value, &offset, fordsp);
                    231:                if (errstr) {
                    232:                        *end = '"';
                    233:                        fprintf(stderr, "Expression ERROR:\n'%s'\n%*c-%s\n",
                    234:                                input, (int)(start-input)+offset+3, '^', errstr);
                    235:                        return NULL;
                    236:                }
                    237:                end++;
                    238:                
                    239:                count = sprintf(valuestr, "$%x", value);
                    240:                fprintf(stderr, "- \"%s\" -> %s\n", start+1, valuestr);
                    241: 
                    242:                diff = end-start;
                    243:                if (count < diff)
                    244:                {
                    245:                        memcpy(start, valuestr, count);
                    246:                        start += count;
                    247:                        memmove(start, end, strlen(end) + 1);
                    248:                } else {
                    249:                        /* value won't fit to expression, expand string */
                    250:                        char *tmp;
                    251:                        inputlen += count-diff+1;
                    252:                        tmp = malloc(inputlen+1);
                    253:                        if (!tmp)
                    254:                        {
                    255:                                perror("ERROR: Input string alloc failed\n");
                    256:                                return NULL;
                    257:                        }
                    258: 
                    259:                        memcpy(tmp, input, start-input);
                    260:                        start = tmp+(start-input);
                    261:                        memcpy(start, valuestr, count);
                    262:                        start += count;
                    263:                        memcpy(start, end, strlen(end) + 1);
                    264: 
1.1.1.2   root      265:             if (input != initial)
                    266:                 free(input);
                    267:             input = tmp;
1.1       root      268:                }
                    269:        }
                    270:        /* no (more) expressions to evaluate */
                    271:        return input;
                    272: }
                    273: 
                    274: /**
                    275:  * Command: Set command line and debugger options
                    276:  */
                    277: static int DebugUI_SetOptions(int argc, char *argv[])
                    278: {
                    279:        CNF_PARAMS current;
                    280:        static const struct {
                    281:                const char name[4];
                    282:                int base;
                    283:        } bases[] = {
                    284:                { "bin", 2 },
                    285:                { "dec", 10 },
                    286:                { "hex", 16 }
                    287:        };
                    288:        const char *arg;
                    289:        int i;
                    290:        
                    291:        if (argc < 2)
                    292:        {
                    293:                DebugUI_PrintCmdHelp(argv[0]);
                    294:                return DEBUGGER_CMDDONE;
                    295:        }
                    296:        arg = argv[1];
                    297:        
                    298:        for (i = 0; i < ARRAYSIZE(bases); i++)
                    299:        {
                    300:                if (strcasecmp(bases[i].name, arg) == 0)
                    301:                {
                    302:                        if (ConfigureParams.Debugger.nNumberBase != bases[i].base)
                    303:                        {
                    304:                                fprintf(stderr, "Switched default number base from %d to %d-based (%s) values.\n",
                    305:                                        ConfigureParams.Debugger.nNumberBase,
                    306:                                        bases[i].base, bases[i].name);
                    307:                                ConfigureParams.Debugger.nNumberBase = bases[i].base;
                    308:                        } else {
                    309:                                fprintf(stderr, "Already in '%s' mode.\n", bases[i].name);
                    310:                        }
                    311:                        return DEBUGGER_CMDDONE;
                    312:                }
                    313:        }
                    314: 
                    315:        /* get configuration changes */
                    316:        current = ConfigureParams;
1.1.1.4 ! root      317: #if 0
1.1       root      318:        /* Parse and apply options */
1.1.1.2   root      319:        if (Opt_ParseParameters(argc, (const char * const *)argv))
1.1       root      320:        {
                    321:                ConfigureParams.Screen.bFullScreen = false;
                    322:                Change_CopyChangedParamsToConfiguration(&current, &ConfigureParams, false);
                    323:        }
                    324:        else
1.1.1.4 ! root      325: #endif
1.1       root      326:        {
                    327:                ConfigureParams = current;
                    328:        }
                    329: 
                    330:        return DEBUGGER_CMDDONE;
                    331: }
                    332: 
                    333: 
                    334: /**
                    335:  * Command: Set tracing
                    336:  */
                    337: static int DebugUI_SetTracing(int argc, char *argv[])
                    338: {
                    339:        const char *errstr;
                    340:        if (argc != 2)
                    341:        {
                    342:                DebugUI_PrintCmdHelp(argv[0]);
                    343:                return DEBUGGER_CMDDONE;
                    344:        }
                    345:        errstr = Log_SetTraceOptions(argv[1]);
                    346:        if (errstr && errstr[0])
                    347:                fprintf(stderr, "ERROR: %s\n", errstr);
                    348: 
                    349:        return DEBUGGER_CMDDONE;
                    350: }
                    351: 
                    352: 
                    353: /**
                    354:  * Command: Change Hatari work directory
                    355:  */
                    356: static int DebugUI_ChangeDir(int argc, char *argv[])
                    357: {
                    358:        if (argc == 2)
                    359:        {
                    360:                if (chdir(argv[1]) == 0)
                    361:                        return DEBUGGER_CMDDONE;
                    362:                perror("ERROR");
                    363:        }
                    364:        DebugUI_PrintCmdHelp(argv[0]);
                    365:        return DEBUGGER_CMDDONE;
                    366: }
                    367: 
                    368: 
                    369: /**
                    370:  * Command: Read debugger commands from a file
                    371:  */
                    372: static int DebugUI_CommandsFromFile(int argc, char *argv[])
                    373: {
                    374:        if (argc == 2)
                    375:                DebugUI_ParseFile(argv[1]);
                    376:        else
                    377:                DebugUI_PrintCmdHelp(argv[0]);
                    378:        return DEBUGGER_CMDDONE;
                    379: }
                    380: 
                    381: 
                    382: /**
                    383:  * Command: Quit emulator
                    384:  */
                    385: static int DebugUI_QuitEmu(int nArgc, char *psArgv[])
                    386: {
                    387:        bQuitProgram = true;
                    388:        M68000_SetSpecial(SPCFLAG_BRK);   /* Assure that CPU core shuts down */
                    389:        return DEBUGGER_END;
                    390: }
                    391: 
                    392: 
                    393: /**
                    394:  * Print help text for one command
                    395:  */
                    396: void DebugUI_PrintCmdHelp(const char *psCmd)
                    397: {
                    398:        dbgcommand_t *cmd;
                    399:        int i;
                    400: 
                    401:        /* Search the command ... */
                    402:        for (cmd = debugCommand, i = 0; i < debugCommands; i++, cmd++)
                    403:        {
                    404:                if (!debugCommand[i].pFunction)
                    405:                        continue;
                    406:                if ((*(cmd->sShortName) && !strcmp(psCmd, cmd->sShortName))
                    407:                    || !strcmp(psCmd, cmd->sLongName))
                    408:                {
                    409:                        bool bShort = *(cmd->sShortName);
                    410:                        /* ... and print help text */
                    411:                        if (bShort)
                    412:                        {
                    413:                                fprintf(stderr, "'%s' or '%s' - %s\n",
                    414:                                        cmd->sLongName,
                    415:                                        cmd->sShortName,
                    416:                                        cmd->sShortDesc);
                    417:                        }
                    418:                        else
                    419:                        {
                    420:                                fprintf(stderr, "'%s' - %s\n",
                    421:                                        cmd->sLongName,
                    422:                                        cmd->sShortDesc);
                    423:                        }
                    424:                        fprintf(stderr, "Usage:  %s %s\n",
                    425:                                bShort ? cmd->sShortName : cmd->sLongName,
                    426:                                cmd->sUsage);
                    427:                        return;
                    428:                }
                    429:        }
                    430: 
                    431:        fprintf(stderr, "Unknown command '%s'\n", psCmd);
                    432: }
                    433: 
                    434: 
                    435: /**
                    436:  * Command: Print debugger help screen.
                    437:  */
                    438: static int DebugUI_Help(int nArgc, char *psArgs[])
                    439: {
                    440:        int i;
                    441: 
                    442:        if (nArgc > 1)
                    443:        {
                    444:                DebugUI_PrintCmdHelp(psArgs[1]);
                    445:                return DEBUGGER_CMDDONE;
                    446:        }
                    447: 
                    448:        for (i = 0; i < debugCommands; i++)
                    449:        {
                    450:                if (!debugCommand[i].pFunction)
                    451:                {
                    452:                        fprintf(stderr, "\n%s:\n", debugCommand[i].sLongName);
                    453:                        continue;
                    454:                }
                    455:                fprintf(stderr, " %12s (%2s) : %s\n", debugCommand[i].sLongName,
                    456:                        debugCommand[i].sShortName, debugCommand[i].sShortDesc);
                    457:        }
                    458: 
                    459:        fprintf(stderr,
                    460:                "\n"
                    461:                "If value is prefixed with '$', it's a hexadecimal, if with '#', it's\n"
                    462:                "a normal decimal, if with '%%', it's a binary decimal. Prefix can\n"
                    463:                "be skipped for numbers in the default number base (currently %d).\n"
                    464:                "\n"
                    465:                "Any expression given in quotes (within \"\"), will be evaluated\n"
                    466:                "before given to the debugger command.  Any register and symbol\n"
                    467:                "names in the expression are replaced by their values.\n"
                    468:                "\n"
                    469:                "Note that address ranges like '$fc0000-$fc0100' should have no\n"
                    470:                "spaces between the range numbers.\n"
                    471:                "\n"
                    472:                "'help <command>' gives more help.\n", ConfigureParams.Debugger.nNumberBase);
                    473:        return DEBUGGER_CMDDONE;
                    474: }
                    475: 
                    476: 
                    477: /**
                    478:  * Parse debug command and execute it.
                    479:  */
1.1.1.2   root      480: static int DebugUI_ParseCommand(const char *input_orig)
1.1       root      481: {
1.1.1.2   root      482:        char *psArgs[64], *input;
1.1       root      483:        const char *delim;
                    484:        static char sLastCmd[80] = { '\0' };
                    485:        int nArgc, cmd = -1;
                    486:        int i, retval;
                    487: 
1.1.1.2   root      488:     input = strdup(input_orig);
1.1       root      489:        psArgs[0] = strtok(input, " \t");
                    490: 
                    491:        if (psArgs[0] == NULL)
                    492:        {
                    493:                if (strlen(sLastCmd) > 0)
                    494:                        psArgs[0] = sLastCmd;
                    495:                else
1.1.1.2   root      496:         {
                    497:             free(input);
                    498:             return DEBUGGER_CMDDONE;
                    499:         }
1.1       root      500:        }
                    501: 
                    502:        /* Search the command ... */
                    503:        for (i = 0; i < debugCommands; i++)
                    504:        {
                    505:                if (!debugCommand[i].pFunction)
                    506:                        continue;
                    507:                if (!strcmp(psArgs[0], debugCommand[i].sShortName) ||
                    508:                    !strcmp(psArgs[0], debugCommand[i].sLongName))
                    509:                {
                    510:                        cmd = i;
                    511:                        break;
                    512:                }
                    513:        }
                    514:        if (cmd == -1)
                    515:        {
                    516:                fprintf(stderr, "Command '%s' not found.\n"
                    517:                        "Use 'help' to view a list of available commands.\n",
                    518:                        psArgs[0]);
1.1.1.2   root      519:         free(input);
1.1       root      520:                return DEBUGGER_CMDDONE;
                    521:        }
                    522: 
                    523:        if (debugCommand[cmd].bNoParsing)
                    524:                delim = "";
                    525:        else
                    526:                delim = " \t";
                    527: 
                    528:        /* Separate arguments and put the pointers into psArgs */
                    529:        for (nArgc = 1; nArgc < ARRAYSIZE(psArgs); nArgc++)
                    530:        {
                    531:                psArgs[nArgc] = strtok(NULL, delim);
                    532:                if (psArgs[nArgc] == NULL)
                    533:                        break;
                    534:        }
                    535: 
                    536:        if (!debugOutput) {
                    537:                /* make sure also calls from control.c work */
                    538:                DebugUI_SetLogDefault();
                    539:        }
                    540: 
                    541:        /* ... and execute the function */
                    542:        retval = debugCommand[i].pFunction(nArgc, psArgs);
                    543:        /* Save commando string if it can be repeated */
                    544:        if (retval == DEBUGGER_CMDCONT)
                    545:                strncpy(sLastCmd, psArgs[0], sizeof(sLastCmd));
                    546:        else
                    547:                sLastCmd[0] = '\0';
1.1.1.2   root      548:     free(input);
1.1       root      549:        return retval;
                    550: }
                    551: 
                    552: 
                    553: /* See "info:readline" e.g. in Konqueror for readline usage. */
                    554: 
                    555: /**
                    556:  * Readline match callback for long command name completion.
                    557:  * STATE = 0 -> different text from previous one.
                    558:  * Return next match or NULL if no matches.
                    559:  */
                    560: static char *DebugUI_MatchCommand(const char *text, int state)
                    561: {
                    562:        static int i, len;
                    563:        const char *name;
                    564:        
                    565:        if (!state)
                    566:        {
                    567:                /* first match */
                    568:                len = strlen(text);
                    569:                i = 0;
                    570:        }
                    571:        /* next match */
                    572:        while (i < debugCommands)
                    573:        {
                    574:                name = debugCommand[i].sLongName;
                    575:                if (debugCommand[i++].pFunction &&
                    576:                    strncmp(name, text, len) == 0)
                    577:                        return (strdup(name));
                    578:        }
                    579:        return NULL;
                    580: }
                    581: 
                    582: 
                    583: #if HAVE_LIBREADLINE
                    584: /**
                    585:  * Readline match callback returning last result.
                    586:  */
                    587: static char *DebugUI_MatchLast(const char *text, int state)
                    588: {
                    589:        if (state)
                    590:                return NULL;
                    591:        return strdup(lastResult);
                    592: }
                    593: 
                    594: /**
                    595:  * Readline completion callback. Returns matches.
                    596:  */
                    597: static char **DebugUI_Completion(const char *text, int a, int b)
                    598: {
                    599:        int i, cmd, quotes, end, start = 0;
                    600:        char *str, buf[32];
                    601:        size_t len;
                    602: 
                    603:        /* check where's the first word (ignore white space) */
                    604:        while (start < rl_point && isspace(rl_line_buffer[start]))
                    605:                start++;
                    606:        end = start;
                    607:        while (end < rl_point && !isspace(rl_line_buffer[end]))
                    608:                end++;
                    609: 
                    610:        if (end >= rl_point)
                    611:                /* first word on line */
                    612:                return rl_completion_matches(text, DebugUI_MatchCommand);
                    613:        
                    614:        /* complete '$' with last result? */
                    615:        if (lastResult[0] && rl_line_buffer[rl_point-1] == '$')
                    616:                return rl_completion_matches(text, DebugUI_MatchLast);
                    617: 
                    618:        /* check which command args are to be completed */
                    619:        len = end - start;
                    620:        if (len >= sizeof(buf))
                    621:                len = sizeof(buf)-1;
                    622:        memcpy(buf, &(rl_line_buffer[start]), len);
                    623:        buf[len] = '\0';
                    624: 
                    625:        /* expression completion needed (= open quote)? */
                    626:        str = strchr(&(rl_line_buffer[end]), '"');
                    627:        quotes = 0;
                    628:        while (str)
                    629:        {
                    630:                quotes++;
                    631:                str = strchr(str+1, '"');
                    632:        }
                    633:        if (quotes & 1)
                    634:        {
                    635:                if (DebugUI_IsForDsp(buf))
                    636:                        return rl_completion_matches(text, Symbols_MatchDspAddress);
                    637:                return rl_completion_matches(text, Symbols_MatchCpuAddress);
                    638:        }
                    639: 
                    640:        /* do command argument completion */
                    641:        cmd = -1;
                    642:        for (i = 0; i < debugCommands; i++)
                    643:        {
                    644:                if (!debugCommand[i].pFunction)
                    645:                        continue;
                    646:                if (!strcmp(buf, debugCommand[i].sShortName) ||
                    647:                    !strcmp(buf, debugCommand[i].sLongName))
                    648:                {
                    649:                        cmd = i;
                    650:                        break;
                    651:                }
                    652:        }
                    653:        if (cmd < 0)
                    654:        {
                    655:                rl_attempted_completion_over = true;
                    656:                return NULL;
                    657:        }
                    658:        if (debugCommand[cmd].pMatch)
                    659:                return rl_completion_matches(text, debugCommand[cmd].pMatch);
                    660:        else
                    661:                return rl_completion_matches(text, rl_filename_completion_function);
                    662: }
                    663: 
                    664: 
                    665: /**
                    666:  * Read a command line from the keyboard and return a pointer to the string.
1.1.1.2   root      667:  * Only string returned by this function can be given for it as argument!
                    668:  * The string will be stored into command history buffer.
                    669:  * @return     Pointer to the string which should be deallocated after
                    670:  *              use or given back to this function for re-use/history.
                    671:  *              Returns NULL when error occured.
1.1       root      672:  */
1.1.1.2   root      673: static char *DebugUI_GetCommand(char *input)
1.1       root      674: {
                    675:        /* Allow conditional parsing of the ~/.inputrc file. */
                    676:        rl_readline_name = "Hatari";
                    677:        
                    678:        /* Tell the completer that we want a crack first. */
                    679:        rl_attempted_completion_function = DebugUI_Completion;
                    680: 
1.1.1.2   root      681:     if (input && *input)
                    682:     {
                    683:         HIST_ENTRY *hist = previous_history();
                    684:         /* don't store successive duplicate entries */
                    685:         if (!hist || !hist->line || strcmp(hist->line, input) != 0)
                    686:             add_history(input);
                    687:         free(input);
                    688:     }
1.1       root      689: 
1.1.1.2   root      690:        return Str_Trim(readline("> "));
1.1       root      691: }
                    692: 
                    693: #else /* !HAVE_LIBREADLINE */
                    694: 
                    695: /**
                    696:  * Read a command line from the keyboard and return a pointer to the string.
1.1.1.2   root      697:  * Only string returned by this function can be given for it as argument!
                    698:  * @return     Pointer to the string which should be deallocated after
                    699:  *              use or given back to this function for re-use.
                    700:  *              Returns NULL when error occured.
1.1       root      701:  */
1.1.1.2   root      702: static char *DebugUI_GetCommand(char *input)
1.1       root      703: {
                    704:        fprintf(stderr, "> ");
                    705:        if (!input)
1.1.1.2   root      706:     {
                    707:         input = malloc(256);
                    708:         assert(input);
                    709:     }
1.1       root      710:        input[0] = '\0';
                    711:        if (fgets(input, 256, stdin) == NULL)
                    712:        {
                    713:                free(input);
                    714:                return NULL;
                    715:        }
                    716:        return Str_Trim(input);
                    717: }
                    718: 
                    719: #endif /* !HAVE_LIBREADLINE */
                    720: 
                    721: 
                    722: static const dbgcommand_t uicommand[] =
                    723: {
                    724:        { NULL, NULL, "Generic commands", NULL, NULL, NULL, false },
                    725:        /* NULL as match function will complete file names */
                    726:        { DebugUI_ChangeDir, NULL,
                    727:          "cd", "",
                    728:          "change directory",
                    729:          "<directory>\n"
                    730:          "\tChange Hatari work directory.",
                    731:          false },
                    732:        { DebugUI_Evaluate, Symbols_MatchCpuAddress,
                    733:          "evaluate", "e",
                    734:          "evaluate an expression",
                    735:          "<expression>\n"
                    736:          "\tEvaluate an expression and show the result.  Expression can\n"
                    737:          "\tinclude CPU register and symbol names, those are replaced\n"
                    738:          "\tby their values. Supported operators in expressions are,\n"
                    739:          "\tin the decending order of precedence:\n"
                    740:          "\t\t(), +, -, ~, *, /, +, -, >>, <<, ^, &, |\n"
1.1.1.2   root      741:       "\tParenthesis will fetch a _long_ value from the address\n"
                    742:       "\tto what the value inside it evaluates to. Prefixes can be\n"
                    743:       "\tused only in start of line or parenthesis.\n"
1.1       root      744:          "\tFor example:\n"
1.1.1.2   root      745:          "\t\t~%101 & $f0f0f ^ (d0 + 0x21)\n"
1.1       root      746:          "\tResult value is shown as binary, decimal and hexadecimal.\n"
                    747:          "\tAfter this, '$' will TAB-complete to last result value.",
                    748:          true },
                    749:        { DebugUI_Help, DebugUI_MatchCommand,
                    750:          "help", "h",
                    751:          "print help",
                    752:          "[command]\n"
                    753:          "\tPrint help text for available commands.",
                    754:          false },
                    755:        { DebugInfo_Command, DebugInfo_MatchInfo,
                    756:          "info", "i",
                    757:          "show machine/OS information",
                    758:          "[subject [arg]]\n"
                    759:          "\tPrint information on requested subject or list them if\n"
                    760:          "\tno subject given.",
                    761:          false },
                    762:        { DebugInfo_Command, DebugInfo_MatchLock,
                    763:          "lock", "",
1.1.1.2   root      764:       "specify information to show on entering the debugger",
                    765:       "[subject [args]]\n"
                    766:       "\tLock what information should be shown every time debugger\n"
                    767:       "\tis entered, or list available options if no subject's given.",
1.1       root      768:          false },
                    769:        { DebugUI_SetLogFile, NULL,
                    770:          "logfile", "f",
                    771:          "open or close log file",
                    772:          "[filename]\n"
                    773:          "\tOpen log file, no argument closes the log file. Output of\n"
                    774:          "\tregister & memory dumps and disassembly will be written to it.",
                    775:          false },
                    776:        { DebugUI_CommandsFromFile, NULL,
                    777:          "parse", "p",
                    778:          "get debugger commands from file",
                    779:          "[filename]\n"
                    780:          "\tRead debugger commands from given file and do them.",
                    781:          false },
1.1.1.4 ! root      782:        { DebugUI_SetOptions, NULL /* Opt_MatchOption */,
1.1       root      783:          "setopt", "o",
                    784:          "set Hatari command line and debugger options",
                    785:          "[<bin|dec|hex>|<command line options>]\n"
                    786:          "\tSet Hatari options. For example to enable exception catching,\n"
                    787:          "\tuse following command line option: 'setopt --debug'. Special\n"
                    788:          "\t'bin', 'dec' and 'hex' arguments change the default number base\n"
                    789:          "\tused in debugger.",
                    790:          false },
                    791:        { DebugUI_SetTracing, Log_MatchTrace,
                    792:          "trace", "t",
                    793:          "select Hatari tracing settings",
                    794:          "[set1,set2...]\n"
1.1.1.2   root      795:       "\tSelect Hatari tracing settings. 'help' shows all the available\n"
                    796:       "\tsettings.  For example, to enable CPU disassembly and VBL\n"
1.1.1.3   root      797:       "\ttracing, use:\n\t\ttrace cpu_disasm",
1.1       root      798:          false },
                    799:        { DebugUI_QuitEmu, NULL,
                    800:          "quit", "q",
                    801:          "quit emulator",
                    802:          "\n"
                    803:          "\tLeave debugger and quit emulator.",
                    804:          false }
                    805: };
                    806: 
                    807: 
                    808: /**
                    809:  * Debugger user interface initialization.
                    810:  */
                    811: void DebugUI_Init(void)
                    812: {
1.1.1.3   root      813:     const dbgcommand_t *cpucmd;
                    814:     int cpucmds;
1.1       root      815: 
1.1.1.4 ! root      816:     if(!(debugOutput)){
        !           817:         debugOutput = stderr;          
        !           818:        } 
1.1.1.3   root      819:         
1.1       root      820:        /* already intialized? */
                    821:        if (debugCommands)
                    822:                return;
                    823: 
                    824:        /* if you want disassembly or memdumping to start/continue from
                    825:         * specific address, you can set them in these functions.
                    826:         */
                    827: //     dspcmds = DebugDsp_Init(&dspcmd);
                    828:        cpucmds = DebugCpu_Init(&cpucmd);
                    829: 
                    830:        /* on first time copy the command structures to a single table */
                    831:        debugCommands = ARRAYSIZE(uicommand);
                    832:        debugCommand = malloc(sizeof(dbgcommand_t) * (cpucmds + debugCommands));
                    833:        assert(debugCommand);
                    834:        
                    835:        memcpy(debugCommand, uicommand, sizeof(dbgcommand_t) * debugCommands);
                    836:        memcpy(&debugCommand[debugCommands], cpucmd, sizeof(dbgcommand_t) * cpucmds);
                    837:        debugCommands += cpucmds;
                    838: //     memcpy(&debugCommand[debugCommands], dspcmd, sizeof(dbgcommand_t) * dspcmds);
                    839: //     debugCommands += dspcmds;
                    840: 
                    841:        if (parseFileName)
                    842:                DebugUI_ParseFile(parseFileName);
                    843: }
                    844: 
                    845: 
                    846: /**
1.1.1.2   root      847:  * Set debugger commands file during Hatari startup before things
                    848:  * needed by the debugger are initialized so that it can be parsed
                    849:  * when debugger itself gets initialized.
1.1       root      850:  * Return true if file exists, false otherwise.
                    851:  */
                    852: bool DebugUI_SetParseFile(const char *path)
                    853: {
                    854:        if (File_Exists(path))
                    855:        {
                    856:                parseFileName = path;
                    857:                return true;
                    858:        }
1.1.1.3   root      859:        //fprintf(stderr, "ERROR: debugger input file '%s' missing.\n", path);
1.1       root      860:        return false;
                    861: }
                    862: 
                    863: 
                    864: /**
                    865:  * Debugger user interface main function.
                    866:  */
                    867: void DebugUI(void)
                    868: {
                    869:        int cmdret, alertLevel;
1.1.1.2   root      870:        char *expCmd, *psCmd = NULL;
1.1       root      871:        static const char *welcome =
                    872:                "\n----------------------------------------------------------------------"
                    873:                "\nYou have entered debug mode. Type c to continue emulation, h for help.\n";
                    874:        
                    875:        if (bInFullScreen)
                    876:                Screen_ReturnFromFullScreen();
                    877: 
                    878:        DebugUI_Init();
                    879: 
                    880:        if (welcome)
                    881:        {
                    882:                fputs(welcome, stderr);
                    883:                welcome = NULL;
                    884:        }
                    885:        DebugCpu_InitSession();
                    886: //     DebugDsp_InitSession();
                    887:        DebugInfo_ShowSessionInfo();
                    888: 
                    889:        /* override paused message so that user knows to look into console
                    890:         * on how to continue in case he invoked the debugger by accident.
                    891:         */
1.1.1.3   root      892:        Statusbar_AddMessage("M68K Console Debugger", 100);
1.1       root      893:        Statusbar_Update(sdlscrn);
                    894: 
                    895:        /* disable normal GUI alerts while on console */
                    896:        alertLevel = Log_SetAlertLevel(LOG_FATAL);
                    897: 
                    898:        cmdret = DEBUGGER_CMDDONE;
                    899:        do
                    900:        {
1.1.1.2   root      901:         /* Read command from the keyboard and give previous
                    902:          * command for freeing / adding to history
                    903:          */
                    904:         psCmd = DebugUI_GetCommand(psCmd);
1.1       root      905:                if (!psCmd)
                    906:                        break;
                    907: 
1.1.1.2   root      908:         /* returns new string if expressions needed expanding! */
                    909:         if (!(expCmd = DebugUI_EvaluateExpressions(psCmd)))
1.1       root      910:                        continue;
                    911: 
                    912:                /* Parse and execute the command string */
1.1.1.2   root      913:         cmdret = DebugUI_ParseCommand(expCmd);
                    914:         if (expCmd != psCmd)
                    915:             free(expCmd);
1.1       root      916:        }
                    917:        while (cmdret != DEBUGGER_END);
1.1.1.2   root      918:     
                    919:     /* free (and ignore) exit command */
1.1.1.4 ! root      920:     if (psCmd) {
        !           921:        free(psCmd);            
        !           922:        }
        !           923:  
1.1       root      924:        Log_SetAlertLevel(alertLevel);
                    925:        DebugUI_SetLogDefault();
                    926: 
                    927:        DebugCpu_SetDebugging();
                    928: }
                    929: 
                    930: 
                    931: /**
                    932:  * Read debugger commands from a file.
                    933:  * return false for error, true for success.
                    934:  */
1.1.1.2   root      935: bool DebugUI_ParseFile(const char *path)
1.1       root      936: {
1.1.1.2   root      937:        char *olddir, *dir, *cmd, *input, *expanded, *slash;
1.1       root      938:        FILE *fp;
                    939: 
                    940:        fprintf(stderr, "Reading debugger commands from '%s'...\n", path);
                    941:        if (!(fp = fopen(path, "r")))
                    942:        {
                    943:                perror("ERROR");
                    944:                return false;
                    945:        }
                    946: 
                    947:        /* change to directory where the debugger file resides */
1.1.1.2   root      948:     olddir = NULL;
1.1       root      949:        dir = strdup(path);
                    950:        slash = strrchr(dir, PATHSEP);
                    951:        if (slash)
                    952:        {
1.1.1.2   root      953:         olddir = malloc(FILENAME_MAX);
                    954:         if (olddir)
                    955:         {
                    956:             if (!getcwd(olddir, FILENAME_MAX))
                    957:                 strcpy(olddir, ".");
                    958:         }
1.1       root      959:                *slash = '\0';
1.1.1.2   root      960:                if (chdir(dir) != 0)
1.1       root      961:                {
                    962:                        perror("ERROR");
1.1.1.2   root      963:             if (olddir)
                    964:                 free(olddir);
1.1       root      965:                        free(dir);
                    966:                        return false;
                    967:                }
1.1.1.2   root      968:         fprintf(stderr, "Changed to input file dir '%s'.\n", dir);
1.1       root      969:        }
                    970:        free(dir);
                    971: 
                    972:        input = NULL;
                    973:        for (;;)
                    974:        {
                    975:                if (!input)
                    976:                {
                    977:                        input = malloc(256);
                    978:                        assert(input);
                    979:                }
                    980:                if (!fgets(input, 256, fp))
                    981:                        break;
                    982: 
1.1.1.2   root      983:         /* ignore empty and comment lines */
                    984:         cmd = Str_Trim(input);
                    985:         if (!*cmd || *cmd == '#')
1.1       root      986:                        continue;
                    987: 
1.1.1.2   root      988:         /* returns new string if input needed expanding! */
                    989:         expanded = DebugUI_EvaluateExpressions(input);
                    990:         if (!expanded)
                    991:             continue;
                    992: 
                    993:         cmd = Str_Trim(expanded);
                    994:         fprintf(stderr, "> %s\n", cmd);
                    995:         DebugUI_ParseCommand(cmd);
                    996:         if (expanded != input)
                    997:             free(expanded);
1.1       root      998:        }
                    999: 
                   1000:        free(input);
1.1.1.2   root     1001:     if (olddir)
                   1002:     {
                   1003:         if (chdir(olddir) != 0)
                   1004:             perror("ERROR");
                   1005:         else
                   1006:             fprintf(stderr, "Changed back to '%s' dir.\n", olddir);
                   1007:         free(olddir);
                   1008:     }
1.1       root     1009: 
                   1010:        DebugCpu_SetDebugging();
                   1011: //     DebugDsp_SetDebugging();
                   1012:        return true;
                   1013: }
                   1014: 
                   1015: 
                   1016: /**
                   1017:  * Remote/parallel debugger usage API.
                   1018:  * Return false for failed command, true for success.
                   1019:  */
                   1020: bool DebugUI_RemoteParse(char *input)
                   1021: {
                   1022:        int ret;
                   1023: 
                   1024:        DebugUI_Init();
                   1025:        
                   1026:        ret = DebugUI_ParseCommand(input);
                   1027: 
                   1028:        DebugCpu_SetDebugging();
                   1029: //     DebugDsp_SetDebugging();
                   1030: 
                   1031:        return (ret == DEBUGGER_CMDDONE);
                   1032: }

unix.superglobalmegacorp.com

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