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