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

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

unix.superglobalmegacorp.com

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