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

1.1       root        1: /*
                      2:   Hatari - debugcpu.c
                      3: 
                      4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
                      6: 
                      7:   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>
                     13: 
                     14: #include "config.h"
                     15: 
                     16: #include "main.h"
                     17: #include "breakcond.h"
                     18: #include "configuration.h"
                     19: #include "debugui.h"
                     20: #include "debug_priv.h"
                     21: #include "debugcpu.h"
                     22: #include "evaluate.h"
                     23: #include "hatari-glue.h"
                     24: #include "log.h"
                     25: #include "m68000.h"
                     26: #include "memorySnapShot.h"
                     27: #include "stMemory.h"
                     28: #include "str.h"
                     29: #include "symbols.h"
                     30: 
                     31: #define MEMDUMP_COLS   16      /* memdump, number of bytes per row */
                     32: #define NON_PRINT_CHAR '.'     /* character to display for non-printables */
                     33: 
                     34: static Uint32 disasm_addr;     /* disasm address */
                     35: static Uint32 memdump_addr;    /* memdump address */
                     36: 
                     37: static int nCpuActiveCBs = 0;  /* Amount of active conditional breakpoints */
                     38: static int nCpuSteps = 0;      /* Amount of steps for CPU single-stepping */
                     39: 
                     40: 
                     41: /**
                     42:  * Load a binary file to a memory address.
                     43:  */
                     44: static int DebugCpu_LoadBin(int nArgc, char *psArgs[])
                     45: {
                     46:        FILE *fp;
                     47:        unsigned char c;
                     48:        Uint32 address;
                     49:        int i=0;
                     50: 
                     51:        if (nArgc < 3)
                     52:        {
                     53:                DebugUI_PrintCmdHelp(psArgs[0]);
                     54:                return DEBUGGER_CMDDONE;
                     55:        }
                     56: 
                     57:        if (!Eval_Number(psArgs[2], &address))
                     58:        {
                     59:                fprintf(stderr, "Invalid address!\n");
                     60:                return DEBUGGER_CMDDONE;
                     61:        }
                     62:        address &= 0x00FFFFFF;
                     63: 
                     64:        if ((fp = fopen(psArgs[1], "rb")) == NULL)
                     65:        {
                     66:                fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
                     67:                return DEBUGGER_CMDDONE;
                     68:        }
                     69: 
                     70:        c = fgetc(fp);
                     71:        while (!feof(fp))
                     72:        {
                     73:                i++;
                     74:                STMemory_WriteByte(address++, c);
                     75:                c = fgetc(fp);
                     76:        }
                     77:        fprintf(stderr,"  Read 0x%x bytes.\n", i);
                     78:        fclose(fp);
                     79: 
                     80:        return DEBUGGER_CMDDONE;
                     81: }
                     82: 
                     83: 
                     84: /**
                     85:  * Dump memory from an address to a binary file.
                     86:  */
                     87: static int DebugCpu_SaveBin(int nArgc, char *psArgs[])
                     88: {
                     89:        FILE *fp;
                     90:        unsigned char c;
                     91:        Uint32 address;
                     92:        Uint32 bytes, i = 0;
                     93: 
                     94:        if (nArgc < 4)
                     95:        {
                     96:                DebugUI_PrintCmdHelp(psArgs[0]);
                     97:                return DEBUGGER_CMDDONE;
                     98:        }
                     99: 
                    100:        if (!Eval_Number(psArgs[2], &address))
                    101:        {
                    102:                fprintf(stderr, "  Invalid address!\n");
                    103:                return DEBUGGER_CMDDONE;
                    104:        }
                    105:        address &= 0x00FFFFFF;
                    106: 
                    107:        if (!Eval_Number(psArgs[3], &bytes))
                    108:        {
                    109:                fprintf(stderr, "  Invalid length!\n");
                    110:                return DEBUGGER_CMDDONE;
                    111:        }
                    112: 
                    113:        if ((fp = fopen(psArgs[1], "wb")) == NULL)
                    114:        {
                    115:                fprintf(stderr,"  Cannot open file '%s'!\n", psArgs[1]);
                    116:                return DEBUGGER_CMDDONE;
                    117:        }
                    118: 
                    119:        while (i < bytes)
                    120:        {
                    121:                c = STMemory_ReadByte(address++);
                    122:                fputc(c, fp);
                    123:                i++;
                    124:        }
                    125:        fclose(fp);
                    126:        fprintf(stderr, "  Wrote 0x%x bytes.\n", bytes);
                    127: 
                    128:        return DEBUGGER_CMDDONE;
                    129: }
                    130: 
                    131: 
                    132: /**
                    133:  * Check whether given address matches any CPU symbol, if yes,
                    134:  * show the symbol information.
                    135:  */
                    136: static void DebugCpu_ShowMatchedSymbol(Uint32 addr)
                    137: {
                    138:        const char *symbol = Symbols_GetByCpuAddress(addr);
                    139:        if (symbol)
                    140:                fprintf(debugOutput, "%s:\n", symbol);
                    141: }
                    142: 
                    143: /**
                    144:  * Dissassemble - arg = starting address, or PC.
                    145:  */
                    146: int DebugCpu_DisAsm(int nArgc, char *psArgs[])
                    147: {
                    148:        Uint32 disasm_upper = 0;
                    149:        int insts, max_insts;
                    150:        uaecptr nextpc;
                    151: 
                    152:        if (nArgc > 1)
                    153:        {
                    154:                switch (Eval_Range(psArgs[1], &disasm_addr, &disasm_upper))
                    155:                {
                    156:                case -1:
                    157:                        /* invalid value(s) */
                    158:                        return DEBUGGER_CMDDONE;
                    159:                case 0:
                    160:                        /* single value */
                    161:                        break;
                    162:                case 1:
                    163:                        /* range */
                    164:                        disasm_upper &= 0x00FFFFFF;
                    165:                        break;
                    166:                }
                    167:        }
                    168:        else
                    169:        {
                    170:                /* continue */
                    171:                if(!disasm_addr)
                    172:                        disasm_addr = M68000_GetPC();
                    173:        }
                    174:        disasm_addr &= 0x00FFFFFF;
                    175: 
                    176:        /* limit is topmost address or instruction count */
                    177:        if (disasm_upper)
                    178:        {
                    179:                max_insts = INT_MAX;
                    180:        }
                    181:        else
                    182:        {
                    183:                disasm_upper = 0x00FFFFFF;
                    184:                max_insts = ConfigureParams.Debugger.nDisasmLines;
                    185:        }
                    186: 
                    187:        /* output a range */
                    188:        for (insts = 0; insts < max_insts && disasm_addr < disasm_upper; insts++)
                    189:        {
                    190:                DebugCpu_ShowMatchedSymbol(disasm_addr);
                    191:                m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
                    192:                disasm_addr = nextpc;
                    193:        }
                    194:        fflush(debugOutput);
                    195: 
                    196:        return DEBUGGER_CMDCONT;
                    197: }
                    198: 
                    199: 
                    200: /**
                    201:  * Readline match callback to list register names usable within debugger.
                    202:  * STATE = 0 -> different text from previous one.
                    203:  * Return next match or NULL if no matches.
                    204:  */
                    205: static char *DebugCpu_MatchRegister(const char *text, int state)
                    206: {
                    207:        static const char regs[][3] = {
                    208:                "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
                    209:                "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
                    210:                "pc", "sr"
                    211:        };
                    212:        static int i, len;
                    213:        
                    214:        if (!state)
                    215:        {
                    216:                /* first match */
                    217:                i = 0;
                    218:                len = strlen(text);
                    219:                if (len > 2)
                    220:                        return NULL;
                    221:        }
                    222:        /* next match */
                    223:        while (i < ARRAYSIZE(regs)) {
                    224:                if (strncasecmp(regs[i++], text, len) == 0)
                    225:                        return (strdup(regs[i-1]));
                    226:        }
                    227:        return NULL;
                    228: }
                    229: 
                    230: 
                    231: /**
                    232:  * Set address of the named register to given argument.
                    233:  * Return register size in bits or zero for uknown register name.
                    234:  * Handles D0-7 data and A0-7 address registers, but not PC & SR
                    235:  * registers as they need to be accessed using UAE accessors.
                    236:  */
                    237: int DebugCpu_GetRegisterAddress(const char *reg, Uint32 **addr)
                    238: {
                    239:        char r0, r1;
                    240:        if (!reg[0] || !reg[1] || reg[2])
                    241:                return 0;
                    242:        
                    243:        r0 = toupper(reg[0]);
                    244:        r1 = toupper(reg[1]);
                    245: 
                    246:        if (r0 == 'D')  /* Data regs? */
                    247:        {
                    248:                if (r1 >= '0' && r1 <= '7')
                    249:                {
                    250:                        *addr = &(Regs[REG_D0 + r1 - '0']);
                    251:                        return 32;
                    252:                }
                    253:                fprintf(stderr,"\tBad data register, valid values are 0-7\n");
                    254:                return 0;
                    255:        }
                    256:        if(r0 == 'A')  /* Address regs? */
                    257:        {
                    258:                if (r1 >= '0' && r1 <= '7')
                    259:                {
                    260:                        *addr = &(Regs[REG_A0 + r1 - '0']);
                    261:                        return 32;
                    262:                }
                    263:                fprintf(stderr,"\tBad address register, valid values are 0-7\n");
                    264:                return 0;
                    265:        }
                    266:        return 0;
                    267: }
                    268: 
                    269: 
                    270: /**
                    271:  * Dump or set CPU registers
                    272:  */
                    273: int DebugCpu_Register(int nArgc, char *psArgs[])
                    274: {
                    275:        char reg[3], *assign;
                    276:        Uint32 value;
                    277:        char *arg;
                    278: 
                    279:        /* If no parameter has been given, simply dump all registers */
                    280:        if (nArgc == 1)
                    281:        {
                    282:                uaecptr nextpc;
                    283:                /* use the UAE function instead */
                    284:                m68k_dumpstate(debugOutput, &nextpc);
                    285:                fflush(debugOutput);
                    286:                return DEBUGGER_CMDDONE;
                    287:        }
                    288: 
                    289:        arg = psArgs[1];
                    290: 
                    291:        assign = strchr(arg, '=');
                    292:        if (!assign)
                    293:        {
                    294:                goto error_msg;
                    295:        }
                    296: 
                    297:        *assign++ = '\0';
                    298:        if (!Eval_Number(Str_Trim(assign), &value))
                    299:        {
                    300:                goto error_msg;
                    301:        }
                    302: 
                    303:        arg = Str_Trim(arg);
                    304:        if (strlen(arg) != 2)
                    305:        {
                    306:                goto error_msg;
                    307:        }
                    308:        reg[0] = toupper(arg[0]);
                    309:        reg[1] = toupper(arg[1]);
                    310:        reg[2] = '\0';
                    311:        
                    312:        /* set SR and update conditional flags for the UAE CPU core. */
                    313:        if (reg[0] == 'S' && reg[1] == 'R')
                    314:        {
                    315:                M68000_SetSR(value);
                    316:        }
                    317:        else if (reg[0] == 'P' && reg[1] == 'C')   /* set PC? */
                    318:        {
                    319:                M68000_SetPC(value);
                    320:        }
                    321:        else
                    322:        {
                    323:                Uint32 *regaddr;
                    324:                /* check&set data and address registers */
                    325:                if (DebugCpu_GetRegisterAddress(reg, &regaddr))
                    326:                {
                    327:                        *regaddr = value;
                    328:                }
                    329:                else
                    330:                {
                    331:                        goto error_msg;
                    332:                }
                    333:        }
                    334:        return DEBUGGER_CMDDONE;
                    335: 
                    336: error_msg:
                    337:        fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR.\n");
                    338:        return DEBUGGER_CMDDONE;
                    339: }
                    340: 
                    341: 
                    342: /**
                    343:  * CPU wrapper for BreakAddr_Command/BreakPointCount.
                    344:  */
                    345: static int DebugCpu_BreakAddr(int nArgc, char *psArgs[])
                    346: {
                    347:        BreakAddr_Command(psArgs[1], false);
                    348:        return DEBUGGER_CMDDONE;
                    349: }
                    350: 
                    351: /**
                    352:  * CPU wrapper for BreakCond_Command/BreakPointCount.
                    353:  */
                    354: static int DebugCpu_BreakCond(int nArgc, char *psArgs[])
                    355: {
                    356:        BreakCond_Command(psArgs[1], false);
                    357:        return DEBUGGER_CMDDONE;
                    358: }
                    359: 
                    360: 
                    361: /**
                    362:  * Do a memory dump, args = starting address.
                    363:  */
                    364: int DebugCpu_MemDump(int nArgc, char *psArgs[])
                    365: {
                    366:        int i;
                    367:        char c;
                    368:        Uint32 memdump_upper = 0;
                    369: 
                    370:        if (nArgc > 1)
                    371:        {
                    372:                switch (Eval_Range(psArgs[1], &memdump_addr, &memdump_upper))
                    373:                {
                    374:                case -1:
                    375:                        /* invalid value(s) */
                    376:                        return DEBUGGER_CMDDONE;
                    377:                case 0:
                    378:                        /* single value */
                    379:                        break;
                    380:                case 1:
                    381:                        /* range */
                    382:                        break;
                    383:                }
                    384:        } /* continue */
                    385:        memdump_addr &= 0x00FFFFFF;
                    386: 
                    387:        if (!memdump_upper)
                    388:        {
                    389:                memdump_upper = memdump_addr + MEMDUMP_COLS * ConfigureParams.Debugger.nMemdumpLines;
                    390:        }
                    391:        memdump_upper &= 0x00FFFFFF;
                    392: 
                    393:        while (memdump_addr < memdump_upper)
                    394:        {
                    395:                fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
                    396:                for (i = 0; i < MEMDUMP_COLS; i++)               /* print hex data */
                    397:                        fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
                    398:                fprintf(debugOutput, "  ");                     /* print ASCII data */
                    399:                for (i = 0; i < MEMDUMP_COLS; i++)
                    400:                {
                    401:                        c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
                    402:                        if(!isprint((unsigned)c))
                    403:                                c = NON_PRINT_CHAR;             /* non-printable as dots */
                    404:                        fprintf(debugOutput,"%c", c);
                    405:                }
                    406:                fprintf(debugOutput, "\n");            /* newline */
                    407:        } /* while */
                    408:        fflush(debugOutput);
                    409: 
                    410:        return DEBUGGER_CMDCONT;
                    411: }
                    412: 
                    413: 
                    414: /**
                    415:  * Command: Write to memory, arg = starting address, followed by bytes.
                    416:  */
                    417: static int DebugCpu_MemWrite(int nArgc, char *psArgs[])
                    418: {
                    419:        int i, numBytes;
                    420:        Uint32 write_addr, d;
                    421:        unsigned char bytes[256]; /* store bytes */
                    422: 
                    423:        if (nArgc < 3)
                    424:        {
                    425:                DebugUI_PrintCmdHelp(psArgs[0]);
                    426:                return DEBUGGER_CMDDONE;
                    427:        }
                    428: 
                    429:        /* Read address */
                    430:        if (!Eval_Number(psArgs[1], &write_addr))
                    431:        {
                    432:                fprintf(stderr, "Bad address!\n");
                    433:                return DEBUGGER_CMDDONE;
                    434:        }
                    435: 
                    436:        write_addr &= 0x00FFFFFF;
                    437:        numBytes = 0;
                    438: 
                    439:        /* get bytes data */
                    440:        for (i = 2; i < nArgc; i++)
                    441:        {
                    442:                if (!Eval_Number(psArgs[i], &d) || d > 255)
                    443:                {
                    444:                        fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
                    445:                        return DEBUGGER_CMDDONE;
                    446:                }
                    447: 
                    448:                bytes[numBytes] = d & 0x0FF;
                    449:                numBytes++;
                    450:        }
                    451: 
                    452:        /* write the data */
                    453:        for (i = 0; i < numBytes; i++)
                    454:                STMemory_WriteByte(write_addr + i, bytes[i]);
                    455: 
                    456:        return DEBUGGER_CMDDONE;
                    457: }
                    458: 
                    459: 
                    460: /**
                    461:  * Command: Continue CPU emulation / single-stepping
                    462:  */
                    463: static int DebugCpu_Continue(int nArgc, char *psArgv[])
                    464: {
                    465:        int steps = 0;
                    466:        
                    467:        if (nArgc > 1)
                    468:        {
                    469:                steps = atoi(psArgv[1]);
                    470:        }
                    471:        if (steps <= 0)
                    472:        {
                    473:                nCpuSteps = 0;
                    474:                fprintf(stderr,"Returning to emulation...\n");
                    475:                return DEBUGGER_END;
                    476:        }
                    477:        nCpuSteps = steps;
                    478:        fprintf(stderr,"Returning to emulation for %i CPU instructions...\n", steps);
                    479:        return DEBUGGER_END;
                    480: }
                    481: 
                    482: 
                    483: /**
                    484:  * This function is called after each CPU instruction when debugging is enabled.
                    485:  */
                    486: void DebugCpu_Check(void)
                    487: {
                    488:        if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
                    489:        {
                    490:                DebugCpu_ShowMatchedSymbol(M68000_GetPC());
                    491:        }
                    492:        if (nCpuActiveCBs)
                    493:        {
                    494:                if (BreakCond_MatchCpu())
                    495:                        DebugUI();
                    496:        }
                    497:        if (nCpuSteps)
                    498:        {
                    499:                nCpuSteps -= 1;
                    500:                if (nCpuSteps == 0)
                    501:                        DebugUI();
                    502:        }
                    503: }
                    504: 
                    505: /**
                    506:  * Should be called before returning back emulation to tell the CPU core
                    507:  * to call us after each instruction if "real-time" debugging like
                    508:  * breakpoints has been set.
                    509:  */
                    510: void DebugCpu_SetDebugging(void)
                    511: {
                    512:        nCpuActiveCBs = BreakCond_BreakPointCount(false);
                    513:        if (nCpuActiveCBs || nCpuSteps)
                    514:                M68000_SetSpecial(SPCFLAG_DEBUGGER);
                    515:        else
                    516:                M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
                    517: }
                    518: 
                    519: 
                    520: static const dbgcommand_t cpucommands[] =
                    521: {
                    522:        { NULL, NULL, "CPU commands", NULL, NULL, NULL, false },
                    523:        /* NULL as match function will complete file names */
                    524:        { DebugCpu_BreakAddr, Symbols_MatchCpuCodeAddress,
                    525:          "address", "a",
                    526:          "set CPU PC address breakpoints",
                    527:          BreakAddr_Description,
                    528:          true  },
                    529:        { DebugCpu_BreakCond, BreakCond_MatchCpuVariable,
                    530:          "breakpoint", "b",
                    531:          "set/remove/list conditional CPU breakpoints",
                    532:          BreakCond_Description,
                    533:          true },
                    534:        { DebugCpu_DisAsm, Symbols_MatchCpuCodeAddress,
                    535:          "disasm", "d",
                    536:          "disassemble from PC, or given address",
                    537:          "[<start address>[-<end address>]]\n"
                    538:          "\tIf no address is given, this command disassembles from the last\n"
                    539:          "\tposition or from current PC if no last position is available.",
                    540:          false },
                    541:        { DebugCpu_Register, DebugCpu_MatchRegister,
                    542:          "cpureg", "r",
                    543:          "dump register values or set register to value",
                    544:          "[REG=value]\n"
                    545:          "\tSet CPU register to value or dumps all register if no parameter\n"
                    546:          "\thas been specified.",
                    547:          true },
                    548:        { DebugCpu_MemDump, Symbols_MatchCpuDataAddress,
                    549:          "memdump", "m",
                    550:          "dump memory",
                    551:          "[<start address>[-<end address>]]\n"
                    552:          "\tdump memory at address or continue dump from previous address.",
                    553:          false },
                    554:        { DebugCpu_MemWrite, Symbols_MatchCpuAddress,
                    555:          "memwrite", "w",
                    556:          "write bytes to memory",
                    557:          "address byte1 [byte2 ...]\n"
                    558:          "\tWrite bytes to a memory address, bytes are space separated\n"
                    559:          "\thexadecimals.",
                    560:          false },
                    561:        { DebugCpu_LoadBin, NULL,
                    562:          "loadbin", "l",
                    563:          "load a file into memory",
                    564:          "filename address\n"
                    565:          "\tLoad the file <filename> into memory starting at <address>.",
                    566:          false },
                    567:        { DebugCpu_SaveBin, NULL,
                    568:          "savebin", "s",
                    569:          "save memory to a file",
                    570:          "filename address length\n"
                    571:          "\tSave the memory block at <address> with given <length> to\n"
                    572:          "\tthe file <filename>.",
                    573:          false },
                    574:        { Symbols_Command, NULL,
                    575:          "symbols", "",
                    576:          "load CPU symbols & their addresses",
                    577:          Symbols_Description,
                    578:          false },
                    579:        { DebugCpu_Continue, NULL,
                    580:          "cont", "c",
                    581:          "continue emulation / CPU single-stepping",
                    582:          "[steps]\n"
                    583:          "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
                    584:          "\tor forever if no steps have been specified.",
                    585:          false }
                    586: };
                    587: 
                    588: 
                    589: /**
                    590:  * Should be called when debugger is first entered to initialize
                    591:  * CPU debugging variables.
                    592:  * 
                    593:  * if you want disassembly or memdumping to start/continue from
                    594:  * specific address, you can set them here.  If disassembly
                    595:  * address is zero, disassembling starts from PC.
                    596:  * 
                    597:  * returns number of CPU commands and pointer to array of them.
                    598:  */
                    599: int DebugCpu_Init(const dbgcommand_t **table)
                    600: {
                    601:        memdump_addr = 0;
                    602:        disasm_addr = 0;
                    603:        
                    604:        *table = cpucommands;
                    605:        return ARRAYSIZE(cpucommands);
                    606: }
                    607: 
                    608: /**
                    609:  * Should be called when debugger is re-entered to reset
                    610:  * relevant CPU debugging variables.
                    611:  */
                    612: void DebugCpu_InitSession(void)
                    613: {
                    614:        disasm_addr = M68000_GetPC();
                    615: }

unix.superglobalmegacorp.com

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