Annotation of hatari/src/debug/debugcpu.c, revision 1.1.1.10

1.1       root        1: /*
                      2:   Hatari - debugcpu.c
                      3: 
1.1.1.5   root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
                      7:   debugcpu.c - function needed for the CPU debugging tasks like memory
                      8:   and register dumps.
                      9: */
                     10: const char DebugCpu_fileid[] = "Hatari debugcpu.c : " __DATE__ " " __TIME__;
                     11: 
                     12: #include <stdio.h>
1.1.1.6   root       13: #include <ctype.h>
1.1.1.9   root       14: #include <limits.h>
1.1       root       15: 
                     16: #include "config.h"
                     17: 
                     18: #include "main.h"
                     19: #include "breakcond.h"
                     20: #include "configuration.h"
                     21: #include "debugui.h"
                     22: #include "debug_priv.h"
                     23: #include "debugcpu.h"
                     24: #include "evaluate.h"
                     25: #include "hatari-glue.h"
1.1.1.3   root       26: #include "history.h"
1.1       root       27: #include "log.h"
                     28: #include "m68000.h"
                     29: #include "memorySnapShot.h"
1.1.1.2   root       30: #include "profile.h"
1.1       root       31: #include "stMemory.h"
                     32: #include "str.h"
                     33: #include "symbols.h"
1.1.1.2   root       34: #include "68kDisass.h"
1.1.1.5   root       35: #include "console.h"
                     36: #include "options.h"
1.1.1.8   root       37: #include "vars.h"
1.1.1.5   root       38: 
1.1       root       39: 
                     40: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
                     41: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
                     42: 
                     43: static Uint32 disasm_addr;     /* disasm address */
                     44: static Uint32 memdump_addr;    /* memdump address */
1.1.1.10! root       45: static Uint32 fake_regs[8];    /* virtual debugger "registers" */
        !            46: static bool bFakeRegsUsed;     /* whether to show virtual regs */
1.1       root       47: 
1.1.1.2   root       48: static bool bCpuProfiling;     /* Whether CPU profiling is activated */
1.1       root       49: static int nCpuActiveCBs = 0;  /* Amount of active conditional breakpoints */
                     50: static int nCpuSteps = 0;      /* Amount of steps for CPU single-stepping */
                     51: 
                     52: 
                     53: /**
                     54:  * Load a binary file to a memory address.
                     55:  */
                     56: static int DebugCpu_LoadBin(int nArgc, char *psArgs[])
                     57: {
                     58:        FILE *fp;
                     59:        unsigned char c;
                     60:        Uint32 address;
                     61:        int i=0;
                     62: 
                     63:        if (nArgc < 3)
                     64:        {
1.1.1.6   root       65:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root       66:        }
                     67: 
                     68:        if (!Eval_Number(psArgs[2], &address))
                     69:        {
                     70:                fprintf(stderr, "Invalid address!\n");
                     71:                return DEBUGGER_CMDDONE;
                     72:        }
                     73: 
                     74:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
                     75:        {
                     76:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
                     77:                return DEBUGGER_CMDDONE;
                     78:        }
                     79: 
1.1.1.7   root       80:        /* TODO: more efficient would be to:
                     81:         * - check file size
                     82:         * - verify that it fits into valid memory area
                     83:         * - flush emulated CPU data cache
                     84:         * - read file contents directly into memory
                     85:         */
1.1       root       86:        c = fgetc(fp);
                     87:        while (!feof(fp))
                     88:        {
                     89:                i++;
                     90:                STMemory_WriteByte(address++, c);
                     91:                c = fgetc(fp);
                     92:        }
                     93:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
                     94:        fclose(fp);
                     95: 
                     96:        return DEBUGGER_CMDDONE;
                     97: }
                     98: 
                     99: 
                    100: /**
                    101:  * Dump memory from an address to a binary file.
                    102:  */
                    103: static int DebugCpu_SaveBin(int nArgc, char *psArgs[])
                    104: {
                    105:        FILE *fp;
                    106:        unsigned char c;
                    107:        Uint32 address;
                    108:        Uint32 bytes, i = 0;
                    109: 
                    110:        if (nArgc < 4)
                    111:        {
1.1.1.6   root      112:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      113:        }
                    114: 
                    115:        if (!Eval_Number(psArgs[2], &address))
                    116:        {
                    117:                fprintf(stderr, "  Invalid address!\n");
                    118:                return DEBUGGER_CMDDONE;
                    119:        }
                    120: 
                    121:        if (!Eval_Number(psArgs[3], &bytes))
                    122:        {
                    123:                fprintf(stderr, "  Invalid length!\n");
                    124:                return DEBUGGER_CMDDONE;
                    125:        }
                    126: 
                    127:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
                    128:        {
                    129:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
                    130:                return DEBUGGER_CMDDONE;
                    131:        }
                    132: 
                    133:        while (i < bytes)
                    134:        {
                    135:                c = STMemory_ReadByte(address++);
                    136:                fputc(c, fp);
                    137:                i++;
                    138:        }
                    139:        fclose(fp);
                    140:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
                    141: 
                    142:        return DEBUGGER_CMDDONE;
                    143: }
                    144: 
                    145: 
                    146: /**
1.1.1.2   root      147:  * Check whether given address matches any CPU symbol and whether
                    148:  * there's profiling information available for it.  If yes, show it.
1.1.1.9   root      149:  * 
                    150:  * @return true if symbol was shown, false otherwise
1.1       root      151:  */
1.1.1.9   root      152: static bool DebugCpu_ShowAddressInfo(Uint32 addr, FILE *fp)
1.1       root      153: {
1.1.1.9   root      154:        const char *symbol = Symbols_GetByCpuAddress(addr, SYMTYPE_ALL);
1.1       root      155:        if (symbol)
1.1.1.9   root      156:        {
1.1.1.8   root      157:                fprintf(fp, "%s:\n", symbol);
1.1.1.9   root      158:                return true;
                    159:        }
                    160:        return false;
1.1       root      161: }
                    162: 
                    163: /**
                    164:  * Dissassemble - arg = starting address, or PC.
                    165:  */
                    166: int DebugCpu_DisAsm(int nArgc, char *psArgs[])
                    167: {
                    168:        Uint32 disasm_upper = 0;
1.1.1.9   root      169:        int shown, lines = INT_MAX;
1.1       root      170:        uaecptr nextpc;
                    171: 
                    172:        if (nArgc > 1)
                    173:        {
1.1.1.2   root      174:                switch (Eval_Range(psArgs[1], &disasm_addr, &disasm_upper, false))
1.1       root      175:                {
                    176:                case -1:
                    177:                        /* invalid value(s) */
                    178:                        return DEBUGGER_CMDDONE;
                    179:                case 0:
                    180:                        /* single value */
                    181:                        break;
                    182:                case 1:
                    183:                        /* range */
                    184:                        break;
                    185:                }
                    186:        }
                    187:        else
                    188:        {
                    189:                /* continue */
                    190:                if(!disasm_addr)
                    191:                        disasm_addr = M68000_GetPC();
                    192:        }
                    193: 
                    194:        /* limit is topmost address or instruction count */
1.1.1.9   root      195:        if (!disasm_upper)
1.1       root      196:        {
1.1.1.7   root      197:                disasm_upper = 0xFFFFFFFF;
1.1.1.9   root      198:                lines = DebugUI_GetPageLines(ConfigureParams.Debugger.nDisasmLines, 8);
1.1       root      199:        }
                    200: 
                    201:        /* output a range */
1.1.1.9   root      202:        for (shown = 0; shown < lines && disasm_addr < disasm_upper; shown++)
1.1       root      203:        {
1.1.1.9   root      204:                if (DebugCpu_ShowAddressInfo(disasm_addr, debugOutput))
                    205:                        shown++;
1.1.1.5   root      206:                Disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
1.1       root      207:                disasm_addr = nextpc;
                    208:        }
                    209:        fflush(debugOutput);
                    210: 
                    211:        return DEBUGGER_CMDCONT;
                    212: }
                    213: 
                    214: 
                    215: /**
                    216:  * Readline match callback to list register names usable within debugger.
                    217:  * STATE = 0 -> different text from previous one.
                    218:  * Return next match or NULL if no matches.
                    219:  */
                    220: static char *DebugCpu_MatchRegister(const char *text, int state)
                    221: {
1.1.1.10! root      222:        static const char* regs_000[] = {
1.1       root      223:                "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
                    224:                "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
1.1.1.10! root      225:                "isp", "usp",
        !           226:                "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"
1.1       root      227:        };
1.1.1.10! root      228:        static const char* regs_020[] = {
        !           229:                "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
        !           230:                "caar", "cacr",
        !           231:                "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
        !           232:                "dfc", "isp", "msp", "pc", "sfc", "sr", "usp",
        !           233:                "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
        !           234:                "vbr"
        !           235:        };
        !           236:        if (ConfigureParams.System.nCpuLevel < 2)
        !           237:                return DebugUI_MatchHelper(regs_000, ARRAY_SIZE(regs_000), text, state);
        !           238:        else
        !           239:                return DebugUI_MatchHelper(regs_020, ARRAY_SIZE(regs_020), text, state);
1.1       root      240: }
                    241: 
                    242: 
                    243: /**
1.1.1.5   root      244:  * Set address of the named 32-bit register to given argument.
1.1.1.10! root      245:  * Handles V0-7 fake registers, D0-7 data, A0-7 address and several
        !           246:  * special registers except for PC & SR registers because they need
        !           247:  * to be accessed using UAE accessors.
        !           248:  *
        !           249:  * Return register size in bits or zero for unknown register name.
1.1       root      250:  */
                    251: int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr)
                    252: {
1.1.1.10! root      253:        char r0;
        !           254:        int r1;
        !           255: 
        !           256:        if (!reg[0] || !reg[1])
1.1       root      257:                return 0;
1.1.1.10! root      258: 
        !           259:        /* 3-4 letter reg? */
        !           260:        if (reg[2])
        !           261:        {
        !           262:                if (strcasecmp(reg, "ISP") == 0)
        !           263:                {
        !           264:                        *addr = &regs.isp;
        !           265:                        return 32;
        !           266:                }
        !           267:                if (strcasecmp(reg, "USP") == 0)
        !           268:                {
        !           269:                        *addr = &regs.usp;
        !           270:                        return 32;
        !           271:                }
        !           272:                if (ConfigureParams.System.nCpuLevel >= 2)
        !           273:                {
        !           274:                        static const struct {
        !           275:                                const char name[5];
        !           276:                                Uint32 *addr;
        !           277:                        } reg_020[] = {
        !           278:                                { "CAAR", &regs.caar },
        !           279:                                { "CACR", &regs.cacr },
        !           280:                                { "DFC", &regs.dfc },
        !           281:                                { "MSP", &regs.msp },
        !           282:                                { "SFC", &regs.sfc },
        !           283:                                { "VBR", &regs.vbr }
        !           284:                        };
        !           285:                        for (int i = 0; i < ARRAY_SIZE(reg_020); i++)
        !           286:                        {
        !           287:                                if (strcasecmp(reg, reg_020[i].name) == 0)
        !           288:                                {
        !           289:                                        *addr = reg_020[i].addr;
        !           290:                                        return 32;
        !           291:                                }
        !           292:                        }
        !           293:                }
        !           294:                return 0;
        !           295:        }
        !           296: 
        !           297:        /* 2-letter reg */
1.1.1.6   root      298:        r0 = toupper((unsigned char)reg[0]);
1.1.1.10! root      299:        r1 = toupper((unsigned char)reg[1]) - '0';
1.1       root      300: 
                    301:        if (r0 == 'D')  /* Data regs? */
                    302:        {
1.1.1.10! root      303:                if (r1 >= 0 && r1 <= 7)
1.1       root      304:                {
1.1.1.10! root      305:                        *addr = &(regs.regs[REG_D0 + r1]);
1.1       root      306:                        return 32;
                    307:                }
                    308:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
                    309:                return 0;
                    310:        }
                    311:        if(r0 == 'A')  /* Address regs? */
                    312:        {
1.1.1.10! root      313:                if (r1 >= 0 && r1 <= 7)
1.1       root      314:                {
1.1.1.10! root      315:                        *addr = &(regs.regs[REG_A0 + r1]);
1.1       root      316:                        return 32;
                    317:                }
                    318:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
                    319:                return 0;
                    320:        }
1.1.1.10! root      321:        if(r0 == 'V')  /* Virtual regs? */
        !           322:        {
        !           323:                if (r1 >= 0 && r1 < ARRAY_SIZE(fake_regs))
        !           324:                {
        !           325:                        *addr = &fake_regs[r1];
        !           326:                        bFakeRegsUsed = true;
        !           327:                        return 32;
        !           328:                }
        !           329:                fprintf(stderr,"\tBad virtual register, valid values are 0-7\n");
        !           330:                return 0;
        !           331:        }
1.1       root      332:        return 0;
                    333: }
                    334: 
                    335: 
                    336: /**
                    337:  * Dump or set CPU registers
                    338:  */
                    339: int DebugCpu_Register(int nArgc, char *psArgs[])
                    340: {
1.1.1.10! root      341:        char *arg, *assign;
1.1       root      342:        Uint32 value;
                    343: 
                    344:        /* If no parameter has been given, simply dump all registers */
                    345:        if (nArgc == 1)
                    346:        {
                    347:                uaecptr nextpc;
1.1.1.10! root      348:                int idx;
        !           349: 
1.1       root      350:                /* use the UAE function instead */
1.1.1.7   root      351: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root      352:                m68k_dumpstate_file(debugOutput, &nextpc, 0xffffffff);
1.1.1.7   root      353: #else
1.1       root      354:                m68k_dumpstate(debugOutput, &nextpc);
1.1.1.7   root      355: #endif
1.1       root      356:                fflush(debugOutput);
1.1.1.10! root      357:                if (!bFakeRegsUsed)
        !           358:                        return DEBUGGER_CMDDONE;
        !           359: 
        !           360:                fputs("Virtual registers:\n", debugOutput);
        !           361:                for (idx = 0; idx < ARRAY_SIZE(fake_regs); idx++)
        !           362:                {
        !           363:                        if (idx && idx % 4 == 0)
        !           364:                                fputs("\n", debugOutput);
        !           365:                        fprintf(debugOutput, "  V%c %08x",
        !           366:                                '0' + idx, fake_regs[idx]);
        !           367:                }
        !           368:                fputs("\n", debugOutput);
        !           369:                fflush(debugOutput);
1.1       root      370:                return DEBUGGER_CMDDONE;
                    371:        }
                    372: 
                    373:        arg = psArgs[1];
                    374: 
                    375:        assign = strchr(arg, '=');
                    376:        if (!assign)
                    377:        {
                    378:                goto error_msg;
                    379:        }
                    380: 
                    381:        *assign++ = '\0';
                    382:        if (!Eval_Number(Str_Trim(assign), &value))
                    383:        {
                    384:                goto error_msg;
                    385:        }
                    386: 
                    387:        arg = Str_Trim(arg);
1.1.1.10! root      388:        if (strlen(arg) < 2)
1.1       root      389:        {
                    390:                goto error_msg;
                    391:        }
                    392:        
                    393:        /* set SR and update conditional flags for the UAE CPU core. */
1.1.1.10! root      394:        if (strcasecmp("SR", arg) == 0)
1.1       root      395:        {
                    396:                M68000_SetSR(value);
                    397:        }
1.1.1.10! root      398:        else if (strcasecmp("PC", arg) == 0)  /* set PC */
1.1       root      399:        {
                    400:                M68000_SetPC(value);
                    401:        }
                    402:        else
                    403:        {
                    404:                Uint32 *regaddr;
                    405:                /* check&set data and address registers */
1.1.1.10! root      406:                if (DebugCpu_GetRegisterAddress(arg, &regaddr))
1.1       root      407:                {
                    408:                        *regaddr = value;
                    409:                }
                    410:                else
                    411:                {
                    412:                        goto error_msg;
                    413:                }
                    414:        }
                    415:        return DEBUGGER_CMDDONE;
                    416: 
                    417: error_msg:
1.1.1.10! root      418:        fprintf(stderr,"\tError, usage: r or r xx=yyyy\n"
        !           419:                "\tWhere: xx=A0-A7, D0-D7, PC, SR, ISP, USP\n"
        !           420:                "\t020+: CAAR, CACR, DFC, SFC, MSP, VBR\n"
        !           421:                "\tor V0-V7 (virtual).\n");
1.1       root      422:        return DEBUGGER_CMDDONE;
                    423: }
                    424: 
                    425: 
                    426: /**
1.1.1.2   root      427:  * CPU wrapper for BreakAddr_Command().
1.1       root      428:  */
                    429: static int DebugCpu_BreakAddr(int nArgc, char *psArgs[])
                    430: {
                    431:        BreakAddr_Command(psArgs[1], false);
                    432:        return DEBUGGER_CMDDONE;
                    433: }
                    434: 
                    435: /**
1.1.1.2   root      436:  * CPU wrapper for BreakCond_Command().
1.1       root      437:  */
                    438: static int DebugCpu_BreakCond(int nArgc, char *psArgs[])
                    439: {
                    440:        BreakCond_Command(psArgs[1], false);
                    441:        return DEBUGGER_CMDDONE;
                    442: }
                    443: 
1.1.1.2   root      444: /**
                    445:  * CPU wrapper for Profile_Command().
                    446:  */
                    447: static int DebugCpu_Profile(int nArgc, char *psArgs[])
                    448: {
1.1.1.5   root      449:        return Profile_Command(nArgc, psArgs, false);
1.1.1.2   root      450: }
                    451: 
1.1       root      452: 
                    453: /**
                    454:  * Do a memory dump, args = starting address.
                    455:  */
                    456: int DebugCpu_MemDump(int nArgc, char *psArgs[])
                    457: {
1.1.1.10! root      458:        char c, mode;
        !           459:        int i, arg, size;
        !           460:        Uint32 value, memdump_upper = 0;
        !           461: 
        !           462:        arg = 1;
        !           463:        mode = 0;
        !           464:        size = 1;
1.1       root      465:        if (nArgc > 1)
1.1.1.10! root      466:                mode = tolower(psArgs[arg][0]);
        !           467: 
        !           468:        if (!mode || isdigit(psArgs[arg][0]) || psArgs[arg][1])
        !           469:        {
        !           470:                /* no args, single digit or multiple chars -> default mode */
        !           471:                mode = 'b';
        !           472:        }
        !           473:        else if (mode == 'b')
        !           474:        {
        !           475:                arg += 1;
        !           476:        }
        !           477:        else if (mode == 'w')
        !           478:        {
        !           479:                arg += 1;
        !           480:                size = 2;
        !           481:        }
        !           482:        else if (mode == 'l')
        !           483:        {
        !           484:                arg += 1;
        !           485:                size = 4;
        !           486:        }
        !           487:        else
        !           488:        {
        !           489:                fprintf(stderr, "Invalid width mode (not b|w|l)!\n");
        !           490:                return DEBUGGER_CMDDONE;
        !           491:        }
        !           492: 
        !           493:        if (nArgc > arg)
1.1       root      494:        {
1.1.1.10! root      495:                switch (Eval_Range(psArgs[arg], &memdump_addr, &memdump_upper, false))
1.1       root      496:                {
                    497:                case -1:
                    498:                        /* invalid value(s) */
                    499:                        return DEBUGGER_CMDDONE;
                    500:                case 0:
                    501:                        /* single value */
                    502:                        break;
                    503:                case 1:
                    504:                        /* range */
                    505:                        break;
                    506:                }
1.1.1.10! root      507:                arg++;
        !           508: 
        !           509:                if (nArgc > arg)
        !           510:                {
        !           511:                        int count = atoi(psArgs[arg]);
        !           512:                        if (!count)
        !           513:                        {
        !           514:                                fprintf(stderr, "Invalid count %d!\n", count);
        !           515:                                return DEBUGGER_CMDDONE;
        !           516:                        }
        !           517:                        memdump_upper = memdump_addr + count * size;
        !           518:                }
        !           519:        }
1.1       root      520: 
                    521:        if (!memdump_upper)
                    522:        {
1.1.1.9   root      523:                int lines = DebugUI_GetPageLines(ConfigureParams.Debugger.nMemdumpLines, 8);
                    524:                memdump_upper = memdump_addr + MEMDUMP_COLS * lines;
1.1       root      525:        }
                    526: 
                    527:        while (memdump_addr < memdump_upper)
                    528:        {
1.1.1.10! root      529:                fprintf(debugOutput, "%08X: ", memdump_addr);
        !           530:                
        !           531:                /* print HEX data */
        !           532:                for (i = 0; i < MEMDUMP_COLS/size; i++)
        !           533:                {
        !           534:                        switch (mode)
        !           535:                        {
        !           536:                        case 'l':
        !           537:                                value = STMemory_ReadLong(memdump_addr);
        !           538:                                break;
        !           539:                        case 'w':
        !           540:                                value = STMemory_ReadWord(memdump_addr);
        !           541:                                break;
        !           542:                        case 'b':
        !           543:                        default:
        !           544:                                value = STMemory_ReadByte(memdump_addr);
        !           545:                                break;
        !           546:                        }
        !           547:                        fprintf(debugOutput, "%0*x ", 2*size, value);
        !           548:                        memdump_addr += size;
        !           549:                }
        !           550: 
        !           551:                /* print ASCII data */
        !           552:                fprintf(debugOutput, "  ");
1.1       root      553:                for (i = 0; i < MEMDUMP_COLS; i++)
                    554:                {
                    555:                        c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
                    556:                        if(!isprint((unsigned)c))
                    557:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
                    558:                        fprintf(debugOutput,"%c", c);
                    559:                }
1.1.1.10! root      560:                fprintf(debugOutput, "\n");
        !           561:        }
1.1       root      562:        fflush(debugOutput);
                    563: 
                    564:        return DEBUGGER_CMDCONT;
                    565: }
                    566: 
                    567: 
                    568: /**
1.1.1.10! root      569:  * Command: Write to memory, optional arg for value lenghts,
        !           570:  * followed by starting address and the values.
1.1       root      571:  */
                    572: static int DebugCpu_MemWrite(int nArgc, char *psArgs[])
                    573: {
1.1.1.10! root      574:        int i, arg, values, max_values;
1.1       root      575:        Uint32 write_addr, d;
1.1.1.10! root      576:        union {
        !           577:                Uint8  bytes[256];
        !           578:                Uint16 words[128];
        !           579:                Uint32 longs[64];
        !           580:        } store;
        !           581:        char mode;
1.1       root      582: 
                    583:        if (nArgc < 3)
                    584:        {
1.1.1.6   root      585:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      586:        }
                    587: 
1.1.1.10! root      588:        arg = 1;
        !           589:        mode = tolower(psArgs[arg][0]);
        !           590:        max_values = ARRAY_SIZE(store.bytes);
        !           591: 
        !           592:        if (!mode || isdigit(psArgs[arg][0]) || psArgs[arg][1])
        !           593:        {
        !           594:                /* no args, single digit or multiple chars -> default mode */
        !           595:                mode = 'b';
        !           596:        }
        !           597:        else if (mode == 'b')
        !           598:        {
        !           599:                arg += 1;
        !           600:        }
        !           601:        else if (mode == 'w')
        !           602:        {
        !           603:                max_values = ARRAY_SIZE(store.words);
        !           604:                arg += 1;
        !           605:        }
        !           606:        else if (mode == 'l')
        !           607:        {
        !           608:                max_values = ARRAY_SIZE(store.longs);
        !           609:                arg += 1;
        !           610:        }
        !           611:        else
        !           612:        {
        !           613:                fprintf(stderr, "Invalid width mode (not b|w|l)!\n");
        !           614:                return DEBUGGER_CMDDONE;
        !           615:        }
1.1       root      616:        /* Read address */
1.1.1.10! root      617:        if (!Eval_Number(psArgs[arg++], &write_addr))
1.1       root      618:        {
                    619:                fprintf(stderr, "Bad address!\n");
                    620:                return DEBUGGER_CMDDONE;
                    621:        }
                    622: 
1.1.1.10! root      623:        if (nArgc - arg > max_values)
        !           624:        {
        !           625:                fprintf(stderr, "Too many values (%d) given for mode '%c' (max %d)!\n",
        !           626:                       nArgc - arg, mode, max_values);
        !           627:                return DEBUGGER_CMDDONE;
        !           628:        }
1.1       root      629: 
1.1.1.10! root      630:        /* get the data */
        !           631:        values = 0;
        !           632:        for (i = arg; i < nArgc; i++)
1.1       root      633:        {
1.1.1.10! root      634:                if (!Eval_Number(psArgs[i], &d))
1.1       root      635:                {
1.1.1.10! root      636:                        fprintf(stderr, "Bad value '%s'!\n", psArgs[i]);
1.1       root      637:                        return DEBUGGER_CMDDONE;
                    638:                }
1.1.1.10! root      639:                switch(mode)
        !           640:                {
        !           641:                case 'b':
        !           642:                        if (d > 0xff)
        !           643:                        {
        !           644:                                fprintf(stderr, "Illegal byte argument: 0x%x!\n", d);
        !           645:                                return DEBUGGER_CMDDONE;
        !           646:                        }
        !           647:                        store.bytes[values] = (Uint8)d;
        !           648:                        break;
        !           649:                case 'w':
        !           650:                        if (d > 0xffff)
        !           651:                        {
        !           652:                                fprintf(stderr, "Illegal word argument: 0x%x!\n", d);
        !           653:                                return DEBUGGER_CMDDONE;
        !           654:                        }
        !           655:                        store.words[values] = (Uint16)d;
        !           656:                        break;
        !           657:                case 'l':
        !           658:                        store.longs[values] = d;
        !           659:                        break;
        !           660:                }
        !           661:                values++;
1.1       root      662:        }
                    663: 
                    664:        /* write the data */
1.1.1.10! root      665:        for (i = 0; i < values; i++)
        !           666:        {
        !           667:                switch(mode)
        !           668:                {
        !           669:                case 'b':
        !           670:                        STMemory_WriteByte(write_addr + i, store.bytes[i]);
        !           671:                        break;
        !           672:                case 'w':
        !           673:                        STMemory_WriteWord(write_addr + i*2, store.words[i]);
        !           674:                        break;
        !           675:                case 'l':
        !           676:                        STMemory_WriteLong(write_addr + i*4, store.longs[i]);
        !           677:                        break;
        !           678:                }
        !           679:        }
        !           680:        if (values > 1)
        !           681:        {
        !           682:                fprintf(stderr, "Wrote %d '%c' values starting from 0x%x.\n",
        !           683:                        values, mode, write_addr);
        !           684:        }
1.1       root      685:        return DEBUGGER_CMDDONE;
                    686: }
                    687: 
                    688: 
                    689: /**
                    690:  * Command: Continue CPU emulation / single-stepping
                    691:  */
                    692: static int DebugCpu_Continue(int nArgc, char *psArgv[])
                    693: {
                    694:        int steps = 0;
                    695:        
                    696:        if (nArgc > 1)
                    697:        {
                    698:                steps = atoi(psArgv[1]);
                    699:        }
                    700:        if (steps <= 0)
                    701:        {
                    702:                nCpuSteps = 0;
                    703:                fprintf(stderr,"Returning to emulation...\n");
                    704:                return DEBUGGER_END;
                    705:        }
                    706:        nCpuSteps = steps;
                    707:        fprintf(stderr,"Returning to emulation for %i CPU instructions...\n", steps);
                    708:        return DEBUGGER_END;
                    709: }
                    710: 
1.1.1.5   root      711: /**
                    712:  * Command: Single-step CPU
                    713:  */
                    714: static int DebugCpu_Step(int nArgc, char *psArgv[])
                    715: {
                    716:        nCpuSteps = 1;
                    717:        return DEBUGGER_END;
                    718: }
                    719: 
1.1.1.6   root      720: 
                    721: /**
                    722:  * Readline match callback to list next command opcode types.
                    723:  * STATE = 0 -> different text from previous one.
                    724:  * Return next match or NULL if no matches.
                    725:  */
                    726: static char *DebugCpu_MatchNext(const char *text, int state)
                    727: {
                    728:        static const char* ntypes[] = {
                    729:                "branch", "exception", "exreturn", "return", "subcall", "subreturn"
                    730:        };
1.1.1.8   root      731:        return DebugUI_MatchHelper(ntypes, ARRAY_SIZE(ntypes), text, state);
1.1.1.6   root      732: }
                    733: 
1.1.1.5   root      734: /**
                    735:  * Command: Step CPU, but proceed through subroutines
                    736:  * Does this by temporary conditional breakpoint
                    737:  */
                    738: static int DebugCpu_Next(int nArgc, char *psArgv[])
                    739: {
1.1.1.6   root      740:        char command[40];
                    741:        if (nArgc > 1)
                    742:        {
                    743:                int optype;
                    744:                if(strcmp(psArgv[1], "branch") == 0)
                    745:                        optype = CALL_BRANCH;
                    746:                else if(strcmp(psArgv[1], "exception") == 0)
                    747:                        optype = CALL_EXCEPTION;
                    748:                else if(strcmp(psArgv[1], "exreturn") == 0)
                    749:                        optype = CALL_EXCRETURN;
                    750:                else if(strcmp(psArgv[1], "subcall") == 0)
                    751:                        optype = CALL_SUBROUTINE;
                    752:                else if (strcmp(psArgv[1], "subreturn") == 0)
                    753:                        optype = CALL_SUBRETURN;
                    754:                else if (strcmp(psArgv[1], "return") == 0)
                    755:                        optype = CALL_SUBRETURN | CALL_EXCRETURN;
                    756:                else
                    757:                {
                    758:                        fprintf(stderr, "Unrecognized opcode type given!\n");
                    759:                        return DEBUGGER_CMDDONE;
                    760:                }
                    761:                sprintf(command, "CpuOpcodeType & $%x > 0 :once :quiet\n", optype);
                    762:        }
                    763:        else
                    764:        {
                    765:                Uint32 optype, nextpc;
                    766: 
                    767:                optype = DebugCpu_OpcodeType();
1.1.1.8   root      768:                /* should this instruction be stepped normally, or is it
                    769:                 * - subroutine call
                    770:                 * - exception
                    771:                 * - loop branch backwards
                    772:                 */
                    773:                if (optype == CALL_SUBROUTINE ||
                    774:                    optype == CALL_EXCEPTION ||
                    775:                    (optype == CALL_BRANCH &&
                    776:                     (STMemory_ReadWord(M68000_GetPC()) & 0xf0f8) == 0x50c8 &&
                    777:                     (Sint16)STMemory_ReadWord(M68000_GetPC()+SIZE_WORD) < 0))
                    778:                {
                    779:                        nextpc = Disasm_GetNextPC(M68000_GetPC());
                    780:                        sprintf(command, "pc=$%x :once :quiet\n", nextpc);
                    781:                }
                    782:                else
1.1.1.6   root      783:                {
                    784:                        nCpuSteps = 1;
                    785:                        return DEBUGGER_END;
                    786:                }
                    787:        }
                    788:        /* use breakpoint, not steps */
                    789:        if (BreakCond_Command(command, false))
                    790:        {
                    791:                nCpuSteps = 0;
1.1.1.5   root      792:                return DEBUGGER_END;
                    793:        }
                    794:        return DEBUGGER_CMDDONE;
                    795: }
                    796: 
1.1.1.6   root      797: /* helper to get instruction type */
                    798: Uint32 DebugCpu_OpcodeType(void)
                    799: {
                    800:        /* cannot use OpcodeFamily like profiler does,
                    801:         * as that's for previous instructions
                    802:         */
                    803:        Uint16 opcode = STMemory_ReadWord(M68000_GetPC());
                    804: 
                    805:        if (opcode == 0x4e74 ||                 /* RTD */
                    806:            opcode == 0x4e75 ||                 /* RTS */
                    807:            opcode == 0x4e77)                   /* RTR */
                    808:                return CALL_SUBRETURN;
                    809: 
                    810:        if (opcode == 0x4e73)                   /* RTE */
                    811:                return CALL_EXCRETURN;
                    812: 
                    813:        /* NOTE: BSR needs to be matched before BRA/BCC! */
                    814:        if ((opcode & 0xff00) == 0x6100 ||      /* BSR */
                    815:            (opcode & 0xffc0) == 0x4e80)        /* JSR */
                    816:                return CALL_SUBROUTINE;
                    817: 
                    818:        /* TODO: ftrapcc, chk2? */
                    819:        if (opcode == 0x4e72 ||                 /* STOP */
                    820:            opcode == 0x4afc ||                 /* ILLEGAL */
                    821:            opcode == 0x4e76 ||                 /* TRAPV */
                    822:            (opcode & 0xfff0) == 0x4e40 ||      /* TRAP */
                    823:            (opcode & 0xf1c0) == 0x4180 ||      /* CHK */
                    824:            (opcode & 0xfff8) == 0x4848)        /* BKPT */
                    825:                return CALL_EXCEPTION;
                    826: 
                    827:        /* TODO: fbcc, fdbcc */
                    828:        if ((opcode & 0xf000) == 0x6000 ||      /* BRA / BCC */
                    829:            (opcode & 0xffc0) == 0x4ec0 ||      /* JMP */
1.1.1.7   root      830:            (opcode & 0xf0f8) == 0x50c8)        /* DBCC */
1.1.1.6   root      831:                return CALL_BRANCH;
                    832: 
                    833:        return CALL_UNKNOWN;
                    834: }
                    835: 
                    836: 
                    837: /**
                    838:  * CPU instructions since continuing emulation
                    839:  */
                    840: static Uint32 nCpuInstructions;
                    841: Uint32 DebugCpu_InstrCount(void)
                    842: {
                    843:        return nCpuInstructions;
                    844: }
1.1       root      845: 
                    846: /**
                    847:  * This function is called after each CPU instruction when debugging is enabled.
                    848:  */
                    849: void DebugCpu_Check(void)
                    850: {
1.1.1.6   root      851:        nCpuInstructions++;
1.1.1.2   root      852:        if (bCpuProfiling)
                    853:        {
                    854:                Profile_CpuUpdate();
                    855:        }
1.1.1.4   root      856:        if (LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS)))
1.1       root      857:        {
1.1.1.8   root      858:                DebugCpu_ShowAddressInfo(M68000_GetPC(), TraceFile);
1.1       root      859:        }
1.1.1.9   root      860:        if (LOG_TRACE_LEVEL(TRACE_CPU_REGS))
                    861:        {
                    862:                uaecptr nextpc;
                    863: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root      864:                m68k_dumpstate_file(TraceFile, &nextpc, 0xffffffff);
1.1.1.9   root      865: #else
                    866:                m68k_dumpstate(TraceFile, &nextpc);
                    867: #endif
                    868:        }
1.1       root      869:        if (nCpuActiveCBs)
                    870:        {
                    871:                if (BreakCond_MatchCpu())
1.1.1.5   root      872:                {
1.1.1.3   root      873:                        DebugUI(REASON_CPU_BREAKPOINT);
1.1.1.5   root      874:                        /* make sure we don't decrease step count
                    875:                         * below, before even even getting out of here
                    876:                         */
                    877:                        if (nCpuSteps)
                    878:                                nCpuSteps++;
                    879:                }
1.1       root      880:        }
                    881:        if (nCpuSteps)
                    882:        {
1.1.1.5   root      883:                nCpuSteps--;
1.1       root      884:                if (nCpuSteps == 0)
1.1.1.3   root      885:                        DebugUI(REASON_CPU_STEPS);
                    886:        }
1.1.1.5   root      887:        if (History_TrackCpu())
1.1.1.3   root      888:        {
                    889:                History_AddCpu();
1.1       root      890:        }
1.1.1.5   root      891:        if (ConOutDevice != CONOUT_DEVICE_NONE)
                    892:        {
                    893:                Console_Check();
                    894:        }
1.1       root      895: }
                    896: 
                    897: /**
                    898:  * Should be called before returning back emulation to tell the CPU core
                    899:  * to call us after each instruction if "real-time" debugging like
                    900:  * breakpoints has been set.
                    901:  */
                    902: void DebugCpu_SetDebugging(void)
                    903: {
1.1.1.2   root      904:        bCpuProfiling = Profile_CpuStart();
1.1.1.7   root      905:        nCpuActiveCBs = BreakCond_CpuBreakPointCount();
1.1.1.2   root      906: 
1.1.1.5   root      907:        if (nCpuActiveCBs || nCpuSteps || bCpuProfiling || History_TrackCpu()
1.1.1.9   root      908:            || LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS|TRACE_CPU_REGS))
1.1.1.5   root      909:            || ConOutDevice != CONOUT_DEVICE_NONE)
1.1.1.6   root      910:        {
1.1.1.10! root      911:                M68000_SetDebugger(true);
1.1.1.6   root      912:                nCpuInstructions = 0;
                    913:        }       
1.1       root      914:        else
1.1.1.10! root      915:                M68000_SetDebugger(false);
1.1       root      916: }
                    917: 
                    918: 
                    919: static const dbgcommand_t cpucommands[] =
                    920: {
                    921:        { NULL, NULL, "CPU commands", NULL, NULL, NULL, false },
                    922:        /* NULL as match function will complete file names */
                    923:        { DebugCpu_BreakAddr, Symbols_MatchCpuCodeAddress,
                    924:          "address", "a",
                    925:          "set CPU PC address breakpoints",
                    926:          BreakAddr_Description,
                    927:          true  },
1.1.1.8   root      928:        { DebugCpu_BreakCond, Vars_MatchCpuVariable,
1.1       root      929:          "breakpoint", "b",
                    930:          "set/remove/list conditional CPU breakpoints",
                    931:          BreakCond_Description,
                    932:          true },
                    933:        { DebugCpu_DisAsm, Symbols_MatchCpuCodeAddress,
                    934:          "disasm", "d",
                    935:          "disassemble from PC, or given address",
                    936:          "[<start address>[-<end address>]]\n"
                    937:          "\tIf no address is given, this command disassembles from the last\n"
                    938:          "\tposition or from current PC if no last position is available.",
                    939:          false },
1.1.1.2   root      940:        { DebugCpu_Profile, Profile_Match,
                    941:          "profile", "",
                    942:          "profile CPU code",
                    943:          Profile_Description,
                    944:          false },
1.1       root      945:        { DebugCpu_Register, DebugCpu_MatchRegister,
                    946:          "cpureg", "r",
                    947:          "dump register values or set register to value",
                    948:          "[REG=value]\n"
                    949:          "\tSet CPU register to value or dumps all register if no parameter\n"
                    950:          "\thas been specified.",
                    951:          true },
                    952:        { DebugCpu_MemDump, Symbols_MatchCpuDataAddress,
                    953:          "memdump", "m",
                    954:          "dump memory",
1.1.1.10! root      955:          "[b|w|l] [<start address>[-<end address>| <count>]]\n"
        !           956:          "\tdump memory at address or continue dump from previous address.\n"
        !           957:          "\tBy default memory output is done as bytes, with 'w' or 'l'\n"
        !           958:          "\toption, it will be done as words/longs instead.  Output amount\n"
        !           959:          "\tcan be given either as a count or an address range.",
1.1       root      960:          false },
                    961:        { DebugCpu_MemWrite, Symbols_MatchCpuAddress,
                    962:          "memwrite", "w",
1.1.1.10! root      963:          "write bytes/words/longs to memory",
        !           964:          "[b|w|l] address value1 [value2 ...]\n"
        !           965:          "\tWrite space separate values (in current number base) to given\n"
        !           966:          "\tmemory address. By default writes are done as bytes, with\n"
        !           967:          "\t'w' or 'l' option they will be done as words/longs instead",
1.1       root      968:          false },
                    969:        { DebugCpu_LoadBin, NULL,
                    970:          "loadbin", "l",
                    971:          "load a file into memory",
                    972:          "filename address\n"
                    973:          "\tLoad the file <filename> into memory starting at <address>.",
                    974:          false },
                    975:        { DebugCpu_SaveBin, NULL,
1.1.1.5   root      976:          "savebin", "",
1.1       root      977:          "save memory to a file",
                    978:          "filename address length\n"
                    979:          "\tSave the memory block at <address> with given <length> to\n"
                    980:          "\tthe file <filename>.",
                    981:          false },
1.1.1.6   root      982:        { Symbols_Command, Symbols_MatchCommand,
1.1       root      983:          "symbols", "",
                    984:          "load CPU symbols & their addresses",
                    985:          Symbols_Description,
                    986:          false },
1.1.1.5   root      987:        { DebugCpu_Step, NULL,
                    988:          "step", "s",
                    989:          "single-step CPU",
                    990:          "\n"
                    991:          "\tExecute next CPU instruction (equals 'c 1')",
                    992:          false },
1.1.1.6   root      993:        { DebugCpu_Next, DebugCpu_MatchNext,
1.1.1.5   root      994:          "next", "n",
1.1.1.6   root      995:          "step CPU through subroutine calls / to given instruction type",
                    996:          "[instruction type]\n"
                    997:          "\tSame as 'step' command if there are no subroutine calls.\n"
                    998:           "\tWhen there are, those calls are treated as one instruction.\n"
                    999:          "\tIf argument is given, continues until instruction of given\n"
                   1000:          "\ttype is encountered.",
1.1.1.5   root     1001:          false },
1.1       root     1002:        { DebugCpu_Continue, NULL,
                   1003:          "cont", "c",
                   1004:          "continue emulation / CPU single-stepping",
                   1005:          "[steps]\n"
                   1006:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
                   1007:          "\tor forever if no steps have been specified.",
                   1008:          false }
                   1009: };
                   1010: 
                   1011: 
                   1012: /**
                   1013:  * Should be called when debugger is first entered to initialize
                   1014:  * CPU debugging variables.
                   1015:  * 
                   1016:  * if you want disassembly or memdumping to start/continue from
                   1017:  * specific address, you can set them here.  If disassembly
                   1018:  * address is zero, disassembling starts from PC.
                   1019:  * 
                   1020:  * returns number of CPU commands and pointer to array of them.
                   1021:  */
                   1022: int DebugCpu_Init(const dbgcommand_t **table)
                   1023: {
                   1024:        memdump_addr = 0;
                   1025:        disasm_addr = 0;
                   1026:        
                   1027:        *table = cpucommands;
1.1.1.8   root     1028:        return ARRAY_SIZE(cpucommands);
1.1       root     1029: }
                   1030: 
                   1031: /**
                   1032:  * Should be called when debugger is re-entered to reset
                   1033:  * relevant CPU debugging variables.
                   1034:  */
                   1035: void DebugCpu_InitSession(void)
                   1036: {
                   1037:        disasm_addr = M68000_GetPC();
1.1.1.2   root     1038:        Profile_CpuStop();
1.1       root     1039: }

unix.superglobalmegacorp.com

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