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