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

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       root       14: 
                     15: #include "config.h"
                     16: 
                     17: #include "main.h"
                     18: #include "breakcond.h"
                     19: #include "configuration.h"
                     20: #include "debugui.h"
                     21: #include "debug_priv.h"
                     22: #include "debugcpu.h"
                     23: #include "evaluate.h"
                     24: #include "hatari-glue.h"
1.1.1.3   root       25: #include "history.h"
1.1       root       26: #include "log.h"
                     27: #include "m68000.h"
                     28: #include "memorySnapShot.h"
1.1.1.2   root       29: #include "profile.h"
1.1       root       30: #include "stMemory.h"
                     31: #include "str.h"
                     32: #include "symbols.h"
1.1.1.2   root       33: #include "68kDisass.h"
1.1.1.5   root       34: #include "console.h"
                     35: #include "options.h"
1.1.1.8 ! root       36: #include "vars.h"
1.1.1.5   root       37: 
1.1       root       38: 
                     39: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
                     40: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
                     41: 
                     42: static Uint32 disasm_addr;     /* disasm address */
                     43: static Uint32 memdump_addr;    /* memdump address */
                     44: 
1.1.1.2   root       45: static bool bCpuProfiling;     /* Whether CPU profiling is activated */
1.1       root       46: static int nCpuActiveCBs = 0;  /* Amount of active conditional breakpoints */
                     47: static int nCpuSteps = 0;      /* Amount of steps for CPU single-stepping */
                     48: 
                     49: 
                     50: /**
                     51:  * Load a binary file to a memory address.
                     52:  */
                     53: static int DebugCpu_LoadBin(int nArgc, char *psArgs[])
                     54: {
                     55:        FILE *fp;
                     56:        unsigned char c;
                     57:        Uint32 address;
                     58:        int i=0;
                     59: 
                     60:        if (nArgc < 3)
                     61:        {
1.1.1.6   root       62:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root       63:        }
                     64: 
                     65:        if (!Eval_Number(psArgs[2], &address))
                     66:        {
                     67:                fprintf(stderr, "Invalid address!\n");
                     68:                return DEBUGGER_CMDDONE;
                     69:        }
                     70: 
                     71:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
                     72:        {
                     73:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
                     74:                return DEBUGGER_CMDDONE;
                     75:        }
                     76: 
1.1.1.7   root       77:        /* TODO: more efficient would be to:
                     78:         * - check file size
                     79:         * - verify that it fits into valid memory area
                     80:         * - flush emulated CPU data cache
                     81:         * - read file contents directly into memory
                     82:         */
1.1       root       83:        c = fgetc(fp);
                     84:        while (!feof(fp))
                     85:        {
                     86:                i++;
                     87:                STMemory_WriteByte(address++, c);
                     88:                c = fgetc(fp);
                     89:        }
                     90:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
                     91:        fclose(fp);
                     92: 
                     93:        return DEBUGGER_CMDDONE;
                     94: }
                     95: 
                     96: 
                     97: /**
                     98:  * Dump memory from an address to a binary file.
                     99:  */
                    100: static int DebugCpu_SaveBin(int nArgc, char *psArgs[])
                    101: {
                    102:        FILE *fp;
                    103:        unsigned char c;
                    104:        Uint32 address;
                    105:        Uint32 bytes, i = 0;
                    106: 
                    107:        if (nArgc < 4)
                    108:        {
1.1.1.6   root      109:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      110:        }
                    111: 
                    112:        if (!Eval_Number(psArgs[2], &address))
                    113:        {
                    114:                fprintf(stderr, "  Invalid address!\n");
                    115:                return DEBUGGER_CMDDONE;
                    116:        }
                    117: 
                    118:        if (!Eval_Number(psArgs[3], &bytes))
                    119:        {
                    120:                fprintf(stderr, "  Invalid length!\n");
                    121:                return DEBUGGER_CMDDONE;
                    122:        }
                    123: 
                    124:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
                    125:        {
                    126:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
                    127:                return DEBUGGER_CMDDONE;
                    128:        }
                    129: 
                    130:        while (i < bytes)
                    131:        {
                    132:                c = STMemory_ReadByte(address++);
                    133:                fputc(c, fp);
                    134:                i++;
                    135:        }
                    136:        fclose(fp);
                    137:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
                    138: 
                    139:        return DEBUGGER_CMDDONE;
                    140: }
                    141: 
                    142: 
                    143: /**
1.1.1.2   root      144:  * Check whether given address matches any CPU symbol and whether
                    145:  * there's profiling information available for it.  If yes, show it.
1.1       root      146:  */
1.1.1.8 ! root      147: static void DebugCpu_ShowAddressInfo(Uint32 addr, FILE *fp)
1.1       root      148: {
1.1.1.4   root      149:        const char *symbol = Symbols_GetByCpuAddress(addr);
1.1       root      150:        if (symbol)
1.1.1.8 ! root      151:                fprintf(fp, "%s:\n", symbol);
1.1       root      152: }
                    153: 
                    154: /**
                    155:  * Dissassemble - arg = starting address, or PC.
                    156:  */
                    157: int DebugCpu_DisAsm(int nArgc, char *psArgs[])
                    158: {
                    159:        Uint32 disasm_upper = 0;
                    160:        int insts, max_insts;
                    161:        uaecptr nextpc;
                    162: 
                    163:        if (nArgc > 1)
                    164:        {
1.1.1.2   root      165:                switch (Eval_Range(psArgs[1], &disasm_addr, &disasm_upper, false))
1.1       root      166:                {
                    167:                case -1:
                    168:                        /* invalid value(s) */
                    169:                        return DEBUGGER_CMDDONE;
                    170:                case 0:
                    171:                        /* single value */
                    172:                        break;
                    173:                case 1:
                    174:                        /* range */
                    175:                        break;
                    176:                }
                    177:        }
                    178:        else
                    179:        {
                    180:                /* continue */
                    181:                if(!disasm_addr)
                    182:                        disasm_addr = M68000_GetPC();
                    183:        }
                    184: 
                    185:        /* limit is topmost address or instruction count */
                    186:        if (disasm_upper)
                    187:        {
                    188:                max_insts = INT_MAX;
                    189:        }
                    190:        else
                    191:        {
1.1.1.7   root      192:                disasm_upper = 0xFFFFFFFF;
1.1       root      193:                max_insts = ConfigureParams.Debugger.nDisasmLines;
                    194:        }
                    195: 
                    196:        /* output a range */
                    197:        for (insts = 0; insts < max_insts && disasm_addr < disasm_upper; insts++)
                    198:        {
1.1.1.8 ! root      199:                DebugCpu_ShowAddressInfo(disasm_addr, debugOutput);
1.1.1.5   root      200:                Disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
1.1       root      201:                disasm_addr = nextpc;
                    202:        }
                    203:        fflush(debugOutput);
                    204: 
                    205:        return DEBUGGER_CMDCONT;
                    206: }
                    207: 
                    208: 
                    209: /**
                    210:  * Readline match callback to list register names usable within debugger.
                    211:  * STATE = 0 -> different text from previous one.
                    212:  * Return next match or NULL if no matches.
                    213:  */
                    214: static char *DebugCpu_MatchRegister(const char *text, int state)
                    215: {
1.1.1.6   root      216:        static const char* regs[] = {
1.1       root      217:                "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
                    218:                "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
                    219:                "pc", "sr"
                    220:        };
1.1.1.8 ! root      221:        return DebugUI_MatchHelper(regs, ARRAY_SIZE(regs), text, state);
1.1       root      222: }
                    223: 
                    224: 
                    225: /**
1.1.1.5   root      226:  * Set address of the named 32-bit register to given argument.
1.1       root      227:  * Return register size in bits or zero for uknown register name.
                    228:  * Handles D0-7 data and A0-7 address registers, but not PC & SR
                    229:  * registers as they need to be accessed using UAE accessors.
                    230:  */
                    231: int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr)
                    232: {
                    233:        char r0, r1;
                    234:        if (!reg[0] || !reg[1] || reg[2])
                    235:                return 0;
                    236:        
1.1.1.6   root      237:        r0 = toupper((unsigned char)reg[0]);
                    238:        r1 = toupper((unsigned char)reg[1]);
1.1       root      239: 
                    240:        if (r0 == 'D')  /* Data regs? */
                    241:        {
                    242:                if (r1 >= '0' && r1 <= '7')
                    243:                {
                    244:                        *addr = &(Regs[REG_D0 + r1 - '0']);
                    245:                        return 32;
                    246:                }
                    247:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
                    248:                return 0;
                    249:        }
                    250:        if(r0 == 'A')  /* Address regs? */
                    251:        {
                    252:                if (r1 >= '0' && r1 <= '7')
                    253:                {
                    254:                        *addr = &(Regs[REG_A0 + r1 - '0']);
                    255:                        return 32;
                    256:                }
                    257:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
                    258:                return 0;
                    259:        }
                    260:        return 0;
                    261: }
                    262: 
                    263: 
                    264: /**
                    265:  * Dump or set CPU registers
                    266:  */
                    267: int DebugCpu_Register(int nArgc, char *psArgs[])
                    268: {
                    269:        char reg[3], *assign;
                    270:        Uint32 value;
                    271:        char *arg;
                    272: 
                    273:        /* If no parameter has been given, simply dump all registers */
                    274:        if (nArgc == 1)
                    275:        {
                    276:                uaecptr nextpc;
                    277:                /* use the UAE function instead */
1.1.1.7   root      278: #ifdef WINUAE_FOR_HATARI
                    279:                m68k_dumpstate_file(debugOutput, &nextpc);
                    280: #else
1.1       root      281:                m68k_dumpstate(debugOutput, &nextpc);
1.1.1.7   root      282: #endif
1.1       root      283:                fflush(debugOutput);
                    284:                return DEBUGGER_CMDDONE;
                    285:        }
                    286: 
                    287:        arg = psArgs[1];
                    288: 
                    289:        assign = strchr(arg, '=');
                    290:        if (!assign)
                    291:        {
                    292:                goto error_msg;
                    293:        }
                    294: 
                    295:        *assign++ = '\0';
                    296:        if (!Eval_Number(Str_Trim(assign), &value))
                    297:        {
                    298:                goto error_msg;
                    299:        }
                    300: 
                    301:        arg = Str_Trim(arg);
                    302:        if (strlen(arg) != 2)
                    303:        {
                    304:                goto error_msg;
                    305:        }
1.1.1.6   root      306:        reg[0] = toupper((unsigned char)arg[0]);
                    307:        reg[1] = toupper((unsigned char)arg[1]);
1.1       root      308:        reg[2] = '\0';
                    309:        
                    310:        /* set SR and update conditional flags for the UAE CPU core. */
                    311:        if (reg[0] == 'S' && reg[1] == 'R')
                    312:        {
                    313:                M68000_SetSR(value);
                    314:        }
                    315:        else if (reg[0] == 'P' && reg[1] == 'C')   /* set PC? */
                    316:        {
                    317:                M68000_SetPC(value);
                    318:        }
                    319:        else
                    320:        {
                    321:                Uint32 *regaddr;
                    322:                /* check&set data and address registers */
                    323:                if (DebugCpu_GetRegisterAddress(reg, &regaddr))
                    324:                {
                    325:                        *regaddr = value;
                    326:                }
                    327:                else
                    328:                {
                    329:                        goto error_msg;
                    330:                }
                    331:        }
                    332:        return DEBUGGER_CMDDONE;
                    333: 
                    334: error_msg:
                    335:        fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR.\n");
                    336:        return DEBUGGER_CMDDONE;
                    337: }
                    338: 
                    339: 
                    340: /**
1.1.1.2   root      341:  * CPU wrapper for BreakAddr_Command().
1.1       root      342:  */
                    343: static int DebugCpu_BreakAddr(int nArgc, char *psArgs[])
                    344: {
                    345:        BreakAddr_Command(psArgs[1], false);
                    346:        return DEBUGGER_CMDDONE;
                    347: }
                    348: 
                    349: /**
1.1.1.2   root      350:  * CPU wrapper for BreakCond_Command().
1.1       root      351:  */
                    352: static int DebugCpu_BreakCond(int nArgc, char *psArgs[])
                    353: {
                    354:        BreakCond_Command(psArgs[1], false);
                    355:        return DEBUGGER_CMDDONE;
                    356: }
                    357: 
1.1.1.2   root      358: /**
                    359:  * CPU wrapper for Profile_Command().
                    360:  */
                    361: static int DebugCpu_Profile(int nArgc, char *psArgs[])
                    362: {
1.1.1.5   root      363:        return Profile_Command(nArgc, psArgs, false);
1.1.1.2   root      364: }
                    365: 
1.1       root      366: 
                    367: /**
                    368:  * Do a memory dump, args = starting address.
                    369:  */
                    370: int DebugCpu_MemDump(int nArgc, char *psArgs[])
                    371: {
                    372:        int i;
                    373:        char c;
                    374:        Uint32 memdump_upper = 0;
                    375: 
                    376:        if (nArgc > 1)
                    377:        {
1.1.1.2   root      378:                switch (Eval_Range(psArgs[1], &memdump_addr, &memdump_upper, false))
1.1       root      379:                {
                    380:                case -1:
                    381:                        /* invalid value(s) */
                    382:                        return DEBUGGER_CMDDONE;
                    383:                case 0:
                    384:                        /* single value */
                    385:                        break;
                    386:                case 1:
                    387:                        /* range */
                    388:                        break;
                    389:                }
                    390:        } /* continue */
                    391: 
                    392:        if (!memdump_upper)
                    393:        {
                    394:                memdump_upper = memdump_addr + MEMDUMP_COLS * ConfigureParams.Debugger.nMemdumpLines;
                    395:        }
                    396: 
                    397:        while (memdump_addr < memdump_upper)
                    398:        {
1.1.1.7   root      399:                fprintf(debugOutput, "%8.8X: ", memdump_addr);  /* print address */
1.1       root      400:                for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
                    401:                        fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    402:                fprintf(debugOutput, "  ");                     /* print ASCII data */
                    403:                for (i = 0; i < MEMDUMP_COLS; i++)
                    404:                {
                    405:                        c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
                    406:                        if(!isprint((unsigned)c))
                    407:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
                    408:                        fprintf(debugOutput,"%c", c);
                    409:                }
                    410:                fprintf(debugOutput, "\n");            /* newline */
                    411:        } /* while */
                    412:        fflush(debugOutput);
                    413: 
                    414:        return DEBUGGER_CMDCONT;
                    415: }
                    416: 
                    417: 
                    418: /**
                    419:  * Command: Write to memory, arg = starting address, followed by bytes.
                    420:  */
                    421: static int DebugCpu_MemWrite(int nArgc, char *psArgs[])
                    422: {
                    423:        int i, numBytes;
                    424:        Uint32 write_addr, d;
                    425:        unsigned char bytes[256]; /* store bytes */
                    426: 
                    427:        if (nArgc < 3)
                    428:        {
1.1.1.6   root      429:                return DebugUI_PrintCmdHelp(psArgs[0]);
1.1       root      430:        }
                    431: 
                    432:        /* Read address */
                    433:        if (!Eval_Number(psArgs[1], &write_addr))
                    434:        {
                    435:                fprintf(stderr, "Bad address!\n");
                    436:                return DEBUGGER_CMDDONE;
                    437:        }
                    438: 
                    439:        numBytes = 0;
                    440: 
                    441:        /* get bytes data */
                    442:        for (i = 2; i < nArgc; i++)
                    443:        {
                    444:                if (!Eval_Number(psArgs[i], &d) || d > 255)
                    445:                {
                    446:                        fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
                    447:                        return DEBUGGER_CMDDONE;
                    448:                }
                    449: 
                    450:                bytes[numBytes] = d & 0x0FF;
                    451:                numBytes++;
                    452:        }
                    453: 
                    454:        /* write the data */
                    455:        for (i = 0; i < numBytes; i++)
                    456:                STMemory_WriteByte(write_addr + i, bytes[i]);
                    457: 
                    458:        return DEBUGGER_CMDDONE;
                    459: }
                    460: 
                    461: 
                    462: /**
                    463:  * Command: Continue CPU emulation / single-stepping
                    464:  */
                    465: static int DebugCpu_Continue(int nArgc, char *psArgv[])
                    466: {
                    467:        int steps = 0;
                    468:        
                    469:        if (nArgc > 1)
                    470:        {
                    471:                steps = atoi(psArgv[1]);
                    472:        }
                    473:        if (steps <= 0)
                    474:        {
                    475:                nCpuSteps = 0;
                    476:                fprintf(stderr,"Returning to emulation...\n");
                    477:                return DEBUGGER_END;
                    478:        }
                    479:        nCpuSteps = steps;
                    480:        fprintf(stderr,"Returning to emulation for %i CPU instructions...\n", steps);
                    481:        return DEBUGGER_END;
                    482: }
                    483: 
1.1.1.5   root      484: /**
                    485:  * Command: Single-step CPU
                    486:  */
                    487: static int DebugCpu_Step(int nArgc, char *psArgv[])
                    488: {
                    489:        nCpuSteps = 1;
                    490:        return DEBUGGER_END;
                    491: }
                    492: 
1.1.1.6   root      493: 
                    494: /**
                    495:  * Readline match callback to list next command opcode types.
                    496:  * STATE = 0 -> different text from previous one.
                    497:  * Return next match or NULL if no matches.
                    498:  */
                    499: static char *DebugCpu_MatchNext(const char *text, int state)
                    500: {
                    501:        static const char* ntypes[] = {
                    502:                "branch", "exception", "exreturn", "return", "subcall", "subreturn"
                    503:        };
1.1.1.8 ! root      504:        return DebugUI_MatchHelper(ntypes, ARRAY_SIZE(ntypes), text, state);
1.1.1.6   root      505: }
                    506: 
1.1.1.5   root      507: /**
                    508:  * Command: Step CPU, but proceed through subroutines
                    509:  * Does this by temporary conditional breakpoint
                    510:  */
                    511: static int DebugCpu_Next(int nArgc, char *psArgv[])
                    512: {
1.1.1.6   root      513:        char command[40];
                    514:        if (nArgc > 1)
                    515:        {
                    516:                int optype;
                    517:                if(strcmp(psArgv[1], "branch") == 0)
                    518:                        optype = CALL_BRANCH;
                    519:                else if(strcmp(psArgv[1], "exception") == 0)
                    520:                        optype = CALL_EXCEPTION;
                    521:                else if(strcmp(psArgv[1], "exreturn") == 0)
                    522:                        optype = CALL_EXCRETURN;
                    523:                else if(strcmp(psArgv[1], "subcall") == 0)
                    524:                        optype = CALL_SUBROUTINE;
                    525:                else if (strcmp(psArgv[1], "subreturn") == 0)
                    526:                        optype = CALL_SUBRETURN;
                    527:                else if (strcmp(psArgv[1], "return") == 0)
                    528:                        optype = CALL_SUBRETURN | CALL_EXCRETURN;
                    529:                else
                    530:                {
                    531:                        fprintf(stderr, "Unrecognized opcode type given!\n");
                    532:                        return DEBUGGER_CMDDONE;
                    533:                }
                    534:                sprintf(command, "CpuOpcodeType & $%x > 0 :once :quiet\n", optype);
                    535:        }
                    536:        else
                    537:        {
                    538:                Uint32 optype, nextpc;
                    539: 
                    540:                optype = DebugCpu_OpcodeType();
1.1.1.8 ! root      541:                /* should this instruction be stepped normally, or is it
        !           542:                 * - subroutine call
        !           543:                 * - exception
        !           544:                 * - loop branch backwards
        !           545:                 */
        !           546:                if (optype == CALL_SUBROUTINE ||
        !           547:                    optype == CALL_EXCEPTION ||
        !           548:                    (optype == CALL_BRANCH &&
        !           549:                     (STMemory_ReadWord(M68000_GetPC()) & 0xf0f8) == 0x50c8 &&
        !           550:                     (Sint16)STMemory_ReadWord(M68000_GetPC()+SIZE_WORD) < 0))
        !           551:                {
        !           552:                        nextpc = Disasm_GetNextPC(M68000_GetPC());
        !           553:                        sprintf(command, "pc=$%x :once :quiet\n", nextpc);
        !           554:                }
        !           555:                else
1.1.1.6   root      556:                {
                    557:                        nCpuSteps = 1;
                    558:                        return DEBUGGER_END;
                    559:                }
                    560:        }
                    561:        /* use breakpoint, not steps */
                    562:        if (BreakCond_Command(command, false))
                    563:        {
                    564:                nCpuSteps = 0;
1.1.1.5   root      565:                return DEBUGGER_END;
                    566:        }
                    567:        return DEBUGGER_CMDDONE;
                    568: }
                    569: 
1.1.1.6   root      570: /* helper to get instruction type */
                    571: Uint32 DebugCpu_OpcodeType(void)
                    572: {
                    573:        /* cannot use OpcodeFamily like profiler does,
                    574:         * as that's for previous instructions
                    575:         */
                    576:        Uint16 opcode = STMemory_ReadWord(M68000_GetPC());
                    577: 
                    578:        if (opcode == 0x4e74 ||                 /* RTD */
                    579:            opcode == 0x4e75 ||                 /* RTS */
                    580:            opcode == 0x4e77)                   /* RTR */
                    581:                return CALL_SUBRETURN;
                    582: 
                    583:        if (opcode == 0x4e73)                   /* RTE */
                    584:                return CALL_EXCRETURN;
                    585: 
                    586:        /* NOTE: BSR needs to be matched before BRA/BCC! */
                    587:        if ((opcode & 0xff00) == 0x6100 ||      /* BSR */
                    588:            (opcode & 0xffc0) == 0x4e80)        /* JSR */
                    589:                return CALL_SUBROUTINE;
                    590: 
                    591:        /* TODO: ftrapcc, chk2? */
                    592:        if (opcode == 0x4e72 ||                 /* STOP */
                    593:            opcode == 0x4afc ||                 /* ILLEGAL */
                    594:            opcode == 0x4e76 ||                 /* TRAPV */
                    595:            (opcode & 0xfff0) == 0x4e40 ||      /* TRAP */
                    596:            (opcode & 0xf1c0) == 0x4180 ||      /* CHK */
                    597:            (opcode & 0xfff8) == 0x4848)        /* BKPT */
                    598:                return CALL_EXCEPTION;
                    599: 
                    600:        /* TODO: fbcc, fdbcc */
                    601:        if ((opcode & 0xf000) == 0x6000 ||      /* BRA / BCC */
                    602:            (opcode & 0xffc0) == 0x4ec0 ||      /* JMP */
1.1.1.7   root      603:            (opcode & 0xf0f8) == 0x50c8)        /* DBCC */
1.1.1.6   root      604:                return CALL_BRANCH;
                    605: 
                    606:        return CALL_UNKNOWN;
                    607: }
                    608: 
                    609: 
                    610: /**
                    611:  * CPU instructions since continuing emulation
                    612:  */
                    613: static Uint32 nCpuInstructions;
                    614: Uint32 DebugCpu_InstrCount(void)
                    615: {
                    616:        return nCpuInstructions;
                    617: }
1.1       root      618: 
                    619: /**
                    620:  * This function is called after each CPU instruction when debugging is enabled.
                    621:  */
                    622: void DebugCpu_Check(void)
                    623: {
1.1.1.6   root      624:        nCpuInstructions++;
1.1.1.2   root      625:        if (bCpuProfiling)
                    626:        {
                    627:                Profile_CpuUpdate();
                    628:        }
1.1.1.4   root      629:        if (LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS)))
1.1       root      630:        {
1.1.1.8 ! root      631:                DebugCpu_ShowAddressInfo(M68000_GetPC(), TraceFile);
1.1       root      632:        }
                    633:        if (nCpuActiveCBs)
                    634:        {
                    635:                if (BreakCond_MatchCpu())
1.1.1.5   root      636:                {
1.1.1.3   root      637:                        DebugUI(REASON_CPU_BREAKPOINT);
1.1.1.5   root      638:                        /* make sure we don't decrease step count
                    639:                         * below, before even even getting out of here
                    640:                         */
                    641:                        if (nCpuSteps)
                    642:                                nCpuSteps++;
                    643:                }
1.1       root      644:        }
                    645:        if (nCpuSteps)
                    646:        {
1.1.1.5   root      647:                nCpuSteps--;
1.1       root      648:                if (nCpuSteps == 0)
1.1.1.3   root      649:                        DebugUI(REASON_CPU_STEPS);
                    650:        }
1.1.1.5   root      651:        if (History_TrackCpu())
1.1.1.3   root      652:        {
                    653:                History_AddCpu();
1.1       root      654:        }
1.1.1.5   root      655:        if (ConOutDevice != CONOUT_DEVICE_NONE)
                    656:        {
                    657:                Console_Check();
                    658:        }
1.1       root      659: }
                    660: 
                    661: /**
                    662:  * Should be called before returning back emulation to tell the CPU core
                    663:  * to call us after each instruction if "real-time" debugging like
                    664:  * breakpoints has been set.
                    665:  */
                    666: void DebugCpu_SetDebugging(void)
                    667: {
1.1.1.2   root      668:        bCpuProfiling = Profile_CpuStart();
1.1.1.7   root      669:        nCpuActiveCBs = BreakCond_CpuBreakPointCount();
1.1.1.2   root      670: 
1.1.1.5   root      671:        if (nCpuActiveCBs || nCpuSteps || bCpuProfiling || History_TrackCpu()
                    672:            || LOG_TRACE_LEVEL((TRACE_CPU_DISASM|TRACE_CPU_SYMBOLS))
                    673:            || ConOutDevice != CONOUT_DEVICE_NONE)
1.1.1.6   root      674:        {
1.1       root      675:                M68000_SetSpecial(SPCFLAG_DEBUGGER);
1.1.1.6   root      676:                nCpuInstructions = 0;
                    677:        }       
1.1       root      678:        else
                    679:                M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
                    680: }
                    681: 
                    682: 
                    683: static const dbgcommand_t cpucommands[] =
                    684: {
                    685:        { NULL, NULL, "CPU commands", NULL, NULL, NULL, false },
                    686:        /* NULL as match function will complete file names */
                    687:        { DebugCpu_BreakAddr, Symbols_MatchCpuCodeAddress,
                    688:          "address", "a",
                    689:          "set CPU PC address breakpoints",
                    690:          BreakAddr_Description,
                    691:          true  },
1.1.1.8 ! root      692:        { DebugCpu_BreakCond, Vars_MatchCpuVariable,
1.1       root      693:          "breakpoint", "b",
                    694:          "set/remove/list conditional CPU breakpoints",
                    695:          BreakCond_Description,
                    696:          true },
                    697:        { DebugCpu_DisAsm, Symbols_MatchCpuCodeAddress,
                    698:          "disasm", "d",
                    699:          "disassemble from PC, or given address",
                    700:          "[<start address>[-<end address>]]\n"
                    701:          "\tIf no address is given, this command disassembles from the last\n"
                    702:          "\tposition or from current PC if no last position is available.",
                    703:          false },
1.1.1.2   root      704:        { DebugCpu_Profile, Profile_Match,
                    705:          "profile", "",
                    706:          "profile CPU code",
                    707:          Profile_Description,
                    708:          false },
1.1       root      709:        { DebugCpu_Register, DebugCpu_MatchRegister,
                    710:          "cpureg", "r",
                    711:          "dump register values or set register to value",
                    712:          "[REG=value]\n"
                    713:          "\tSet CPU register to value or dumps all register if no parameter\n"
                    714:          "\thas been specified.",
                    715:          true },
                    716:        { DebugCpu_MemDump, Symbols_MatchCpuDataAddress,
                    717:          "memdump", "m",
                    718:          "dump memory",
                    719:          "[<start address>[-<end address>]]\n"
                    720:          "\tdump memory at address or continue dump from previous address.",
                    721:          false },
                    722:        { DebugCpu_MemWrite, Symbols_MatchCpuAddress,
                    723:          "memwrite", "w",
                    724:          "write bytes to memory",
                    725:          "address byte1 [byte2 ...]\n"
                    726:          "\tWrite bytes to a memory address, bytes are space separated\n"
1.1.1.5   root      727:          "\tvalues in current number base.",
1.1       root      728:          false },
                    729:        { DebugCpu_LoadBin, NULL,
                    730:          "loadbin", "l",
                    731:          "load a file into memory",
                    732:          "filename address\n"
                    733:          "\tLoad the file <filename> into memory starting at <address>.",
                    734:          false },
                    735:        { DebugCpu_SaveBin, NULL,
1.1.1.5   root      736:          "savebin", "",
1.1       root      737:          "save memory to a file",
                    738:          "filename address length\n"
                    739:          "\tSave the memory block at <address> with given <length> to\n"
                    740:          "\tthe file <filename>.",
                    741:          false },
1.1.1.6   root      742:        { Symbols_Command, Symbols_MatchCommand,
1.1       root      743:          "symbols", "",
                    744:          "load CPU symbols & their addresses",
                    745:          Symbols_Description,
                    746:          false },
1.1.1.5   root      747:        { DebugCpu_Step, NULL,
                    748:          "step", "s",
                    749:          "single-step CPU",
                    750:          "\n"
                    751:          "\tExecute next CPU instruction (equals 'c 1')",
                    752:          false },
1.1.1.6   root      753:        { DebugCpu_Next, DebugCpu_MatchNext,
1.1.1.5   root      754:          "next", "n",
1.1.1.6   root      755:          "step CPU through subroutine calls / to given instruction type",
                    756:          "[instruction type]\n"
                    757:          "\tSame as 'step' command if there are no subroutine calls.\n"
                    758:           "\tWhen there are, those calls are treated as one instruction.\n"
                    759:          "\tIf argument is given, continues until instruction of given\n"
                    760:          "\ttype is encountered.",
1.1.1.5   root      761:          false },
1.1       root      762:        { DebugCpu_Continue, NULL,
                    763:          "cont", "c",
                    764:          "continue emulation / CPU single-stepping",
                    765:          "[steps]\n"
                    766:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
                    767:          "\tor forever if no steps have been specified.",
                    768:          false }
                    769: };
                    770: 
                    771: 
                    772: /**
                    773:  * Should be called when debugger is first entered to initialize
                    774:  * CPU debugging variables.
                    775:  * 
                    776:  * if you want disassembly or memdumping to start/continue from
                    777:  * specific address, you can set them here.  If disassembly
                    778:  * address is zero, disassembling starts from PC.
                    779:  * 
                    780:  * returns number of CPU commands and pointer to array of them.
                    781:  */
                    782: int DebugCpu_Init(const dbgcommand_t **table)
                    783: {
                    784:        memdump_addr = 0;
                    785:        disasm_addr = 0;
                    786:        
                    787:        *table = cpucommands;
1.1.1.8 ! root      788:        return ARRAY_SIZE(cpucommands);
1.1       root      789: }
                    790: 
                    791: /**
                    792:  * Should be called when debugger is re-entered to reset
                    793:  * relevant CPU debugging variables.
                    794:  */
                    795: void DebugCpu_InitSession(void)
                    796: {
                    797:        disasm_addr = M68000_GetPC();
1.1.1.2   root      798:        Profile_CpuStop();
1.1       root      799: }

unix.superglobalmegacorp.com

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