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