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