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

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

unix.superglobalmegacorp.com

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