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

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

unix.superglobalmegacorp.com

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