|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - debugui.c
1.1 root 3:
1.1.1.4 root 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:
1.1.1.6 root 7: debugui.c - this is the code for the mini-debugger. When the pause button is
8: pressed, the emulator is (hopefully) halted and this little CLI can be used
9: (in the terminal box) for debugging tasks like memory and register dumps.
1.1 root 10: */
1.1.1.10 root 11: const char DebugUI_fileid[] = "Hatari debugui.c : " __DATE__ " " __TIME__;
1.1 root 12:
13: #include <ctype.h>
1.1.1.8 root 14: #include <stdio.h>
15:
16: #include "config.h"
17:
18: #if HAVE_LIBREADLINE
19: #include <readline/readline.h>
20: #include <readline/history.h>
21: #endif
1.1 root 22:
23: #include "main.h"
1.1.1.9 root 24: #include "change.h"
1.1 root 25: #include "configuration.h"
1.1.1.11 root 26: #include "memorySnapShot.h"
1.1.1.9 root 27: #include "file.h"
1.1 root 28: #include "reset.h"
29: #include "m68000.h"
1.1.1.9 root 30: #include "str.h"
1.1.1.3 root 31: #include "stMemory.h"
1.1 root 32: #include "sound.h"
33: #include "tos.h"
1.1.1.11 root 34: #include "options.h"
1.1.1.4 root 35: #include "debugui.h"
1.1.1.11 root 36: #include "breakcond.h"
1.1.1.8 root 37: #include "hatari-glue.h"
1.1.1.11 root 38: #include "screen.h"
39: #include "statusbar.h"
40: #include "video.h"
41:
42: int bExceptionDebugging;
1.1 root 43:
44: #define MEMDUMP_COLS 16 /* memdump, number of bytes per row */
45: #define MEMDUMP_ROWS 4 /* memdump, number of rows */
1.1.1.2 root 46: #define NON_PRINT_CHAR '.' /* character to display for non-printables */
1.1 root 47: #define DISASM_INSTS 5 /* disasm - number of instructions */
48:
1.1.1.11 root 49: static Uint32 disasm_addr; /* disasm address */
50: static Uint32 memdump_addr; /* memdump address */
51:
52: static Uint16 dsp_disasm_addr; /* DSP disasm address */
53: static Uint16 dsp_memdump_addr; /* DSP memdump address */
54: static char dsp_mem_space = 'P'; /* X, Y, P */
1.1.1.6 root 55:
1.1.1.9 root 56: static FILE *debugOutput;
1.1.1.2 root 57:
1.1.1.11 root 58: static Uint32 CpuBreakPoint[16]; /* 68k breakpoints */
59: static int nCpuActiveBPs = 0; /* Amount of active breakpoints */
60: static int nCpuActiveCBs = 0; /* Amount of active conditional breakpoints */
61: static int nCpuSteps = 0; /* Amount of steps for CPU single-stepping */
62:
63: static Uint16 DspBreakPoint[16]; /* DSP breakpoints */
64: static int nDspActiveBPs = 0; /* Amount of active breakpoints */
65: static int nDspActiveCBs = 0; /* Amount of active conditional breakpoints */
66: static int nDspSteps = 0; /* Amount of steps for DSP single-stepping */
1.1.1.2 root 67:
1.1.1.11 root 68: static int DebugUI_Help(int nArgc, char *psArgv[]);
69: static void DebugUI_PrintCmdHelp(const char *psCmd);
1.1.1.6 root 70:
71:
1.1.1.8 root 72: /**
1.1.1.11 root 73: * Save/Restore snapshot of debugging session variables
1.1.1.8 root 74: */
1.1.1.11 root 75: void DebugUI_MemorySnapShot_Capture(bool bSave)
1.1.1.6 root 76: {
1.1.1.11 root 77: MemorySnapShot_Store(&disasm_addr, sizeof(disasm_addr));
78: MemorySnapShot_Store(&memdump_addr, sizeof(memdump_addr));
79: MemorySnapShot_Store(&dsp_disasm_addr, sizeof(dsp_disasm_addr));
80: MemorySnapShot_Store(&dsp_memdump_addr, sizeof(dsp_memdump_addr));
81: MemorySnapShot_Store(&dsp_mem_space, sizeof(dsp_mem_space));
82:
83: MemorySnapShot_Store(&CpuBreakPoint, sizeof(CpuBreakPoint));
84: MemorySnapShot_Store(&nCpuActiveBPs, sizeof(nCpuActiveBPs));
85: MemorySnapShot_Store(&nCpuActiveCBs, sizeof(nCpuActiveCBs));
86: MemorySnapShot_Store(&DspBreakPoint, sizeof(DspBreakPoint));
87: MemorySnapShot_Store(&nDspActiveBPs, sizeof(nDspActiveBPs));
88: MemorySnapShot_Store(&nDspActiveCBs, sizeof(nDspActiveCBs));
89:
90: BreakCond_MemorySnapShot_Capture(bSave);
1.1.1.9 root 91: }
92:
93:
94: /**
95: * Close a log file if open, and set it to default stream.
96: */
97: static void DebugUI_SetLogDefault(void)
98: {
99: if (debugOutput != stderr)
100: {
101: if (debugOutput)
102: {
103: File_Close(debugOutput);
104: fprintf(stderr, "Debug log closed.\n");
105: }
106: debugOutput = stderr;
107: }
1.1.1.2 root 108: }
109:
1.1.1.6 root 110:
1.1.1.11 root 111: /**
112: * Open (or close) given log file.
113: */
114: static int DebugUI_SetLogFile(int nArgc, char *psArgs[])
115: {
116: File_Close(debugOutput);
117: debugOutput = NULL;
118:
119: if (nArgc > 1)
120: debugOutput = File_Open(psArgs[1], "w");
121:
122: if (debugOutput)
123: fprintf(stderr, "Debug log '%s' opened.\n", psArgs[1]);
124: else
125: debugOutput = stderr;
126:
127: return DEBUGGER_CMDDONE;
128: }
129:
130:
1.1.1.8 root 131: /**
132: * Load a binary file to a memory address.
133: */
1.1.1.11 root 134: static int DebugUI_LoadBin(int nArgc, char *psArgs[])
1.1.1.6 root 135: {
136: FILE *fp;
137: unsigned char c;
1.1.1.11 root 138: Uint32 address;
1.1.1.6 root 139: int i=0;
140:
1.1.1.11 root 141: if (nArgc < 3)
142: {
143: DebugUI_PrintCmdHelp(psArgs[0]);
144: return DEBUGGER_CMDDONE;
145: }
146:
147: if (!Str_GetNumber(psArgs[2], &address))
1.1.1.6 root 148: {
1.1.1.11 root 149: fprintf(stderr, "Invalid address!\n");
150: return DEBUGGER_CMDDONE;
1.1.1.6 root 151: }
152: address &= 0x00FFFFFF;
1.1.1.11 root 153:
154: if ((fp = fopen(psArgs[1], "rb")) == NULL)
1.1.1.6 root 155: {
1.1.1.11 root 156: fprintf(stderr, "Cannot open file '%s'!\n", psArgs[1]);
157: return DEBUGGER_CMDDONE;
1.1.1.6 root 158: }
159:
160: c = fgetc(fp);
161: while (!feof(fp))
162: {
163: i++;
164: STMemory_WriteByte(address++, c);
165: c = fgetc(fp);
166: }
167: fprintf(stderr," Read 0x%x bytes.\n", i);
168: fclose(fp);
1.1.1.11 root 169:
170: return DEBUGGER_CMDDONE;
1.1 root 171: }
172:
1.1.1.6 root 173:
1.1.1.8 root 174: /**
175: * Dump memory from an address to a binary file.
176: */
1.1.1.11 root 177: static int DebugUI_SaveBin(int nArgc, char *psArgs[])
1.1.1.6 root 178: {
179: FILE *fp;
180: unsigned char c;
1.1.1.11 root 181: Uint32 address;
182: Uint32 bytes, i = 0;
1.1.1.6 root 183:
1.1.1.11 root 184: if (nArgc < 4)
1.1.1.6 root 185: {
1.1.1.11 root 186: DebugUI_PrintCmdHelp(psArgs[0]);
187: return DEBUGGER_CMDDONE;
188: }
189:
190: if (!Str_GetNumber(psArgs[2], &address))
191: {
192: fprintf(stderr, " Invalid address!\n");
193: return DEBUGGER_CMDDONE;
1.1.1.6 root 194: }
195: address &= 0x00FFFFFF;
1.1.1.11 root 196:
197: if (!Str_GetNumber(psArgs[3], &bytes))
1.1.1.6 root 198: {
1.1.1.11 root 199: fprintf(stderr, " Invalid length!\n");
200: return DEBUGGER_CMDDONE;
201: }
202:
203: if ((fp = fopen(psArgs[1], "wb")) == NULL)
204: {
205: fprintf(stderr," Cannot open file '%s'!\n", psArgs[1]);
206: return DEBUGGER_CMDDONE;
1.1.1.6 root 207: }
208:
209: while (i < bytes)
210: {
211: c = STMemory_ReadByte(address++);
212: fputc(c, fp);
213: i++;
214: }
215: fclose(fp);
1.1.1.11 root 216: fprintf(stderr, " Wrote 0x%x bytes.\n", bytes);
217:
218: return DEBUGGER_CMDDONE;
1.1 root 219: }
220:
1.1.1.6 root 221:
1.1.1.11 root 222: #if ENABLE_DSP_EMU
223:
224: #include "dsp.h"
225:
1.1.1.8 root 226: /**
1.1.1.11 root 227: * Command: Dump or set a DSP register
1.1.1.8 root 228: */
1.1.1.11 root 229: static int DebugUI_DspRegister(int nArgc, char *psArgs[])
1.1 root 230: {
1.1.1.11 root 231: int i;
232: char reg[4], *assign;
233: Uint32 value;
234: char *arg;
235:
236: if (!bDspEnabled)
237: {
238: printf("DSP isn't present or initialized.\n");
239: return DEBUGGER_CMDDONE;
240: }
241:
242: if (nArgc == 1)
243: {
244: /* No parameter - dump all registers */
245: DSP_DisasmRegisters();
246: return DEBUGGER_CMDDONE;
247: }
248:
249: arg = psArgs[1];
250: assign = strchr(arg, '=');
251: /* has '=' and reg name is max. 3 letters that fit to string */
252: if (!assign || assign - arg > 3+1)
253: goto error_msg;
254:
255: *assign++ = '\0';
256: if (!Str_GetNumber(assign, &value))
257: goto error_msg;
258:
259: for (i = 0; i < 3 && arg[i]; i++)
260: reg[i] = toupper(arg[i]);
261:
262: DSP_Disasm_SetRegister(reg, value);
263: return DEBUGGER_CMDDONE;
264:
265: error_msg:
266: fprintf(stderr,"\tError, usage: dr or dr xx=yyyy\n"
267: "\tWhere: xx=A0-A2, B0-B2, X0, X1, Y0, Y1, R0-R7,\n"
268: "\t N0-N7, M0-M7, LA, LC, PC, SR, SP, OMR, SSH, SSL\n"
269: "\tand yyyy is a hex value.\n");
270:
271: return DEBUGGER_CMDDONE;
1.1 root 272: }
273:
274:
1.1.1.8 root 275: /**
1.1.1.11 root 276: * DSP dissassemble - arg = starting address/range, or PC.
1.1.1.8 root 277: */
1.1.1.11 root 278: static int DebugUI_DspDisAsm(int nArgc, char *psArgs[])
1.1.1.6 root 279: {
1.1.1.11 root 280: Uint32 lower, upper;
281: Uint16 dsp_disasm_upper = 0;
1.1.1.6 root 282:
1.1.1.11 root 283: if (!bDspEnabled)
1.1.1.6 root 284: {
1.1.1.11 root 285: printf("DSP isn't present or initialized.\n");
286: return DEBUGGER_CMDDONE;
287: }
1.1.1.6 root 288:
1.1.1.11 root 289: if (nArgc > 1)
290: {
291: switch (Str_ParseRange(psArgs[1], &lower, &upper))
292: {
293: case -1:
294: /* invalid value(s) */
295: return DEBUGGER_CMDDONE;
296: case 0:
297: /* single value */
298: break;
299: case 1:
300: /* range */
301: if (upper > 0xFFFF)
302: {
303: fprintf(stderr,"Invalid address '%x'!\n", upper);
304: return DEBUGGER_CMDDONE;
305: }
306: dsp_disasm_upper = upper;
307: break;
308: }
309:
310: if (lower > 0xFFFF)
311: {
312: fprintf(stderr,"Invalid address '%x'!\n", lower);
313: return DEBUGGER_CMDDONE;
314: }
315: dsp_disasm_addr = lower;
316: }
317: else
318: {
319: /* continue */
320: if(!dsp_disasm_addr)
321: {
322: dsp_disasm_addr = DSP_GetPC();
323: }
324: }
325: if (!dsp_disasm_upper)
326: {
327: if ( dsp_disasm_addr < (0xFFFF - 8))
328: dsp_disasm_upper = dsp_disasm_addr + 8;
329: else
330: dsp_disasm_upper = 0xFFFF;
331: }
332: printf("DSP disasm %hx-%hx:\n", dsp_disasm_addr, dsp_disasm_upper);
333: dsp_disasm_addr = DSP_DisasmAddress(dsp_disasm_addr, dsp_disasm_upper);
1.1.1.6 root 334:
1.1.1.11 root 335: return DEBUGGER_CMDCONT;
336: }
337:
338:
339: /**
340: * Do a DSP memory dump, args = starting address or range.
341: * <x|y|p> <address>: dump from X, Y or P, starting from given address,
342: * e.g. "x 200" or "p 200-300"
343: */
344: static int DebugUI_DspMemDump(int nArgc, char *psArgs[])
345: {
346: Uint32 lower, upper;
347: Uint16 dsp_memdump_upper = 0;
348: char space;
349:
350: if (!bDspEnabled)
351: {
352: printf("DSP isn't present or initialized.\n");
353: return DEBUGGER_CMDDONE;
354: }
355: if (nArgc == 2)
356: {
357: fprintf(stderr,"Memory space or address/range missing\n");
358: return DEBUGGER_CMDDONE;
359: }
360:
361: if (nArgc == 3)
362: {
363: space = toupper(psArgs[1][0]);
364: switch (space)
365: {
366: case 'X':
367: case 'Y':
368: case 'P':
369: break;
370: default:
371: fprintf(stderr,"Invalid DSP address space '%c'!\n", space);
372: return DEBUGGER_CMDDONE;
373: }
374: switch (Str_ParseRange(psArgs[2], &lower, &upper))
375: {
376: case -1:
377: /* invalid value(s) */
378: return DEBUGGER_CMDDONE;
379: case 0:
380: /* single value */
381: break;
382: case 1:
383: /* range */
384: if (upper > 0xFFFF)
1.1.1.6 root 385: {
1.1.1.11 root 386: fprintf(stderr,"Invalid address '%x'!\n", upper);
387: return DEBUGGER_CMDDONE;
1.1.1.6 root 388: }
1.1.1.11 root 389: dsp_memdump_upper = upper;
390: break;
391: }
392: if (lower > 0xFFFF)
1.1.1.6 root 393: {
1.1.1.11 root 394: fprintf(stderr,"Invalid address '%x'!\n", lower);
395: return DEBUGGER_CMDDONE;
1.1.1.6 root 396: }
1.1.1.11 root 397: dsp_memdump_addr = lower;
398: dsp_mem_space = space;
399: } /* continue */
400:
401: if (!dsp_memdump_upper)
402: {
403: if ( dsp_memdump_addr < (0xFFFF - 7))
404: dsp_memdump_upper = dsp_memdump_addr + 7;
1.1.1.6 root 405: else
1.1.1.11 root 406: dsp_memdump_upper = 0xFFFF;
407: }
408:
409:
410: printf("DSP memdump from %hx in '%c' address space\n", dsp_memdump_addr, dsp_mem_space);
411: DSP_DisasmMemory(dsp_memdump_addr, dsp_memdump_upper, dsp_mem_space);
412: dsp_memdump_addr = dsp_memdump_upper + 1;
413:
414: return DEBUGGER_CMDCONT;
415: }
416:
417: /**
418: * Toggle or list DSP breakpoints.
419: */
420: static int DebugUI_DspBreakPoint(int nArgc, char *psArgs[])
421: {
422: int i;
423: Uint16 addr;
424: Uint32 BreakAddr;
425:
426: /* List breakpoints? */
427: if (nArgc == 1)
428: {
429: /* No arguments - so list available breakpoints */
430: if (!nDspActiveBPs)
431: {
432: fputs("No DSP breakpoints set.\n", stderr);
433: return DEBUGGER_CMDDONE;
434: }
435:
436: fputs("Currently active DSP breakpoints:\n", stderr);
437: for (i = 0; i < nDspActiveBPs; i++)
438: {
439: addr = DspBreakPoint[i];
440: DSP_DisasmAddress(addr, addr);
441: }
442:
443: return DEBUGGER_CMDDONE;
444: }
445:
446: /* Parse parameter as breakpoint value */
447: if (!Str_GetNumber(psArgs[1], &BreakAddr) || BreakAddr > 0xFFFF)
448: {
449: fputs("Not a valid value for a DSP breakpoint!\n", stderr);
450: return DEBUGGER_CMDDONE;
451: }
452:
453: /* Is the breakpoint already in the list? Then disable it! */
454: for (i = 0; i < nDspActiveBPs; i++)
455: {
456: if (BreakAddr == DspBreakPoint[i])
457: {
458: DspBreakPoint[i] = DspBreakPoint[nDspActiveBPs-1];
459: nDspActiveBPs -= 1;
460: fprintf(stderr, "DSP breakpoint at %x deleted.\n", BreakAddr);
461: return DEBUGGER_CMDDONE;
462: }
463: }
464:
465: /* Is there at least one free slot available? */
466: if (nDspActiveBPs == ARRAYSIZE(DspBreakPoint))
467: {
468: fputs("No more available free DSP breakpoints!\n", stderr);
469: return DEBUGGER_CMDDONE;
470: }
471:
472: /* Add new breakpoint */
473: DspBreakPoint[nDspActiveBPs] = BreakAddr;
474: nDspActiveBPs += 1;
475: fprintf(stderr, "DSP breakpoint added at %x.\n", BreakAddr);
476:
477: return DEBUGGER_CMDDONE;
478: }
479:
480: /**
481: * DSP wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END
482: */
483: static int DebugUI_BreakCondDsp(int nArgc, char *psArgs[])
484: {
485: BreakCond_Command((const char *)psArgs[1], true);
486: nDspActiveCBs = BreakCond_BreakPointCount(true);
487: return DEBUGGER_CMDDONE;
488: }
489:
490: /**
491: * Check if we hit a DSP breakpoint
492: */
493: static void DebugUI_CheckDspBreakpoints(void)
494: {
495: Uint16 pc = DSP_GetPC();
496: int i;
497:
498: for (i = 0; i < nDspActiveBPs; i++)
499: {
500: if (pc == DspBreakPoint[i])
501: {
502: fprintf(stderr, "\nDSP breakpoint at %x ...", pc);
503: DebugUI();
504: break;
505: }
506: }
507: }
508:
509:
510: /**
511: * This function is called after each DSP instruction when debugging is enabled.
512: */
513: void DebugUI_DspCheck(void)
514: {
515: if (nDspActiveBPs)
516: {
517: DebugUI_CheckDspBreakpoints();
518: }
519: if (nDspActiveCBs)
520: {
521: if (BreakCond_MatchDsp())
522: DebugUI();
523: }
524: if (nDspSteps)
525: {
526: nDspSteps -= 1;
527: if (nDspSteps == 0)
528: DebugUI();
529: }
530: }
531:
532: #endif /* ENABLE_DSP_EMU */
533:
534:
535:
536: /**
537: * Dissassemble - arg = starting address, or PC.
538: */
539: static int DebugUI_DisAsm(int nArgc, char *psArgs[])
540: {
541: Uint32 disasm_upper = 0;
542: uaecptr nextpc;
543:
544: if (nArgc > 1)
545: {
546: switch (Str_ParseRange(psArgs[1], &disasm_addr, &disasm_upper))
547: {
548: case -1:
549: /* invalid value(s) */
550: return DEBUGGER_CMDDONE;
551: case 0:
552: /* single value */
553: break;
554: case 1:
555: /* range */
1.1.1.6 root 556: disasm_upper &= 0x00FFFFFF;
1.1.1.11 root 557: break;
1.1.1.6 root 558: }
559: }
1.1.1.11 root 560: else
561: {
562: /* continue */
1.1.1.6 root 563: if(!disasm_addr)
1.1.1.8 root 564: disasm_addr = M68000_GetPC();
1.1.1.11 root 565: }
1.1.1.6 root 566: disasm_addr &= 0x00FFFFFF;
567:
568: /* output a single block. */
1.1.1.11 root 569: if (!disasm_upper)
1.1.1.6 root 570: {
1.1.1.9 root 571: m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, DISASM_INSTS);
1.1.1.6 root 572: disasm_addr = nextpc;
1.1.1.9 root 573: fflush(debugOutput);
1.1.1.11 root 574: return DEBUGGER_CMDCONT;
1.1.1.6 root 575: }
576:
577: /* output a range */
578: while (disasm_addr < disasm_upper)
579: {
1.1.1.9 root 580: m68k_disasm(debugOutput, (uaecptr)disasm_addr, &nextpc, 1);
1.1.1.6 root 581: disasm_addr = nextpc;
582: }
1.1.1.9 root 583: fflush(debugOutput);
1.1.1.11 root 584:
585: return DEBUGGER_CMDCONT;
1.1.1.2 root 586: }
587:
1.1.1.6 root 588:
1.1.1.8 root 589: /**
1.1.1.11 root 590: * Set address of the named register to given argument.
591: * Return register size in bits or zero for uknown register name.
592: * Handles D0-7 data and A0-7 address registers, but not PC & SR
593: * registers as they need to be accessed using UAE accessors.
1.1.1.8 root 594: */
1.1.1.11 root 595: int DebugUI_GetCpuRegisterAddress(const char *reg, Uint32 **addr)
1.1.1.6 root 596: {
1.1.1.11 root 597: char r0, r1;
598: if (!reg[0] || !reg[1] || reg[2])
599: return 0;
600:
601: r0 = toupper(reg[0]);
602: r1 = toupper(reg[1]);
603:
604: if (r0 == 'D') /* Data regs? */
1.1.1.6 root 605: {
1.1.1.11 root 606: if (r1 >= '0' && r1 <= '7')
1.1.1.6 root 607: {
1.1.1.11 root 608: *addr = &(Regs[REG_D0 + r1 - '0']);
609: return 32;
1.1.1.6 root 610: }
1.1.1.11 root 611: fprintf(stderr,"\tBad data register, valid values are 0-7\n");
612: return 0;
613: }
614: if(r0 == 'A') /* Address regs? */
615: {
616: if (r1 >= '0' && r1 <= '7')
617: {
618: *addr = &(Regs[REG_A0 + r1 - '0']);
619: return 32;
620: }
621: fprintf(stderr,"\tBad address register, valid values are 0-7\n");
622: return 0;
1.1.1.6 root 623: }
1.1.1.11 root 624: return 0;
625: }
626:
627:
628: /**
629: * Dump or set CPU registers
630: */
631: static int DebugUI_CpuRegister(int nArgc, char *psArgs[])
632: {
633: int i;
634: char reg[3], *assign;
635: Uint32 value;
636: char *arg;
637:
638: /* If no parameter has been given, simply dump all registers */
639: if (nArgc == 1)
640: {
641: uaecptr nextpc;
642: /* use the UAE function instead */
643: m68k_dumpstate(debugOutput, &nextpc);
644: fflush(debugOutput);
645: return DEBUGGER_CMDDONE;
646: }
647:
648: arg = psArgs[1];
1.1.1.6 root 649:
1.1.1.11 root 650: assign = strchr(arg, '=');
651: /* has '=' and reg name is max. 2 letters that fit to string */
652: if (!assign || assign - arg > 2+1)
1.1.1.6 root 653: {
654: fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR and yyyy is a hex value.\n");
1.1.1.11 root 655: return DEBUGGER_CMDDONE;
1.1.1.6 root 656: }
657:
1.1.1.11 root 658: *assign++ = '\0';
659: if (!Str_GetNumber(assign, &value))
1.1.1.6 root 660: {
661: fprintf(stderr,"\tError, usage: r or r xx=yyyy\n\tWhere: xx=A0-A7, D0-D7, PC or SR and yyyy is a hex value.\n");
1.1.1.11 root 662: return DEBUGGER_CMDDONE;
1.1.1.6 root 663: }
1.1.1.11 root 664:
665: for (i = 0; i < 2 && arg[i]; i++)
666: {
667: reg[i] = toupper(arg[i]);
668: }
669:
1.1.1.6 root 670: /* set SR and update conditional flags for the UAE CPU core. */
671: if (reg[0] == 'S' && reg[1] == 'R')
672: {
1.1.1.8 root 673: M68000_SetSR(value);
1.1.1.6 root 674: }
675: else if (reg[0] == 'P' && reg[1] == 'C') /* set PC? */
676: {
1.1.1.8 root 677: M68000_SetPC(value);
1.1.1.6 root 678: }
1.1.1.11 root 679: else
1.1.1.6 root 680: {
1.1.1.11 root 681: Uint32 *regaddr;
682: /* check&set data and address registers */
683: if (DebugUI_GetCpuRegisterAddress(reg, ®addr))
1.1.1.6 root 684: {
1.1.1.11 root 685: *regaddr = value;
686: }
687: else
688: {
689: fprintf(stderr, "\t Bad register!\n");
1.1.1.6 root 690: }
691: }
1.1.1.11 root 692: return DEBUGGER_CMDDONE;
693: }
694:
695:
696: /**
697: * Toggle or list CPU breakpoints.
698: */
699: static int DebugUI_CpuBreakPoint(int nArgc, char *psArgs[])
700: {
701: int i;
702: uaecptr nextpc;
703: Uint32 BreakAddr;
704:
705: /* List breakpoints? */
706: if (nArgc == 1)
1.1.1.6 root 707: {
1.1.1.11 root 708: /* No arguments - so list available breakpoints */
709: if (!nCpuActiveBPs)
1.1.1.6 root 710: {
1.1.1.11 root 711: fputs("No CPU breakpoints set.\n", stderr);
712: return DEBUGGER_CMDDONE;
713: }
1.1.1.6 root 714:
1.1.1.11 root 715: fputs("Currently active CPU breakpoints:\n", stderr);
716: for (i = 0; i < nCpuActiveBPs; i++)
717: {
718: m68k_disasm(stderr, (uaecptr)CpuBreakPoint[i], &nextpc, 1);
1.1.1.6 root 719: }
1.1.1.11 root 720:
721: return DEBUGGER_CMDDONE;
1.1.1.6 root 722: }
1.1.1.11 root 723:
724: /* Parse parameter as breakpoint value */
725: if (!Str_GetNumber(psArgs[1], &BreakAddr)
726: || (BreakAddr > STRamEnd && BreakAddr < 0xe00000)
727: || BreakAddr > 0xff0000)
1.1.1.6 root 728: {
1.1.1.11 root 729: fputs("Not a valid value for a CPU breakpoint!\n", stderr);
730: return DEBUGGER_CMDDONE;
1.1.1.6 root 731: }
1.1.1.11 root 732:
733: /* Is the breakpoint already in the list? Then disable it! */
734: for (i = 0; i < nCpuActiveBPs; i++)
735: {
736: if (BreakAddr == CpuBreakPoint[i])
737: {
738: CpuBreakPoint[i] = CpuBreakPoint[nCpuActiveBPs-1];
739: nCpuActiveBPs -= 1;
740: fprintf(stderr, "CPU breakpoint at %x deleted.\n", BreakAddr);
741: return DEBUGGER_CMDDONE;
742: }
743: }
744:
745: /* Is there at least one free slot available? */
746: if (nCpuActiveBPs == ARRAYSIZE(CpuBreakPoint))
747: {
748: fputs("No more available free CPU breakpoints!\n", stderr);
749: return DEBUGGER_CMDDONE;
750: }
751:
752: /* Add new breakpoint */
753: CpuBreakPoint[nCpuActiveBPs] = BreakAddr;
754: nCpuActiveBPs += 1;
755: fprintf(stderr, "CPU breakpoint added at %x.\n", BreakAddr);
756:
757: return DEBUGGER_CMDDONE;
1.1 root 758: }
759:
1.1.1.11 root 760: /**
761: * CPU wrapper for BreakCond_Command/BreakPointCount, returns DEBUGGER_END
762: */
763: static int DebugUI_BreakCondCpu(int nArgc, char *psArgs[])
764: {
765: BreakCond_Command((const char*)psArgs[1], false);
766: nCpuActiveCBs = BreakCond_BreakPointCount(false);
767: return DEBUGGER_CMDDONE;
768: }
1.1.1.6 root 769:
1.1.1.8 root 770: /**
771: * Do a memory dump, args = starting address.
772: */
1.1.1.11 root 773: static int DebugUI_MemDump(int nArgc, char *psArgs[])
1.1.1.6 root 774: {
775: int i,j;
776: char c;
1.1.1.11 root 777: Uint32 memdump_upper = 0;
1.1.1.2 root 778:
1.1.1.11 root 779: if (nArgc > 1)
1.1.1.6 root 780: {
1.1.1.11 root 781: switch (Str_ParseRange(psArgs[1], &memdump_addr, &memdump_upper))
1.1.1.6 root 782: {
1.1.1.11 root 783: case -1:
784: /* invalid value(s) */
785: return DEBUGGER_CMDDONE;
786: case 0:
787: /* single value */
788: break;
789: case 1:
790: /* range */
1.1.1.6 root 791: memdump_upper &= 0x00FFFFFF;
1.1.1.11 root 792: break;
1.1.1.6 root 793: }
794: } /* continue */
795: memdump_addr &= 0x00FFFFFF;
796:
1.1.1.11 root 797: if (!memdump_upper)
1.1.1.6 root 798: {
799: for (j=0;j<MEMDUMP_ROWS;j++)
800: {
1.1.1.11 root 801: fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
1.1.1.6 root 802: for (i = 0; i < MEMDUMP_COLS; i++) /* print hex data */
1.1.1.9 root 803: fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
804: fprintf(debugOutput, " "); /* print ASCII data */
1.1.1.6 root 805: for (i = 0; i < MEMDUMP_COLS; i++)
806: {
807: c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
1.1.1.8 root 808: if (!isprint((unsigned)c))
1.1.1.6 root 809: c = NON_PRINT_CHAR; /* non-printable as dots */
1.1.1.9 root 810: fprintf(debugOutput,"%c", c);
1.1.1.6 root 811: }
1.1.1.9 root 812: fprintf(debugOutput, "\n"); /* newline */
1.1.1.6 root 813: }
1.1.1.9 root 814: fflush(debugOutput);
1.1.1.11 root 815: return DEBUGGER_CMDCONT;
1.1.1.6 root 816: } /* not a range */
817:
818: while (memdump_addr < memdump_upper)
819: {
1.1.1.11 root 820: fprintf(debugOutput, "%6.6X: ", memdump_addr); /* print address */
1.1.1.6 root 821: for (i = 0; i < MEMDUMP_COLS; i++) /* print hex data */
1.1.1.9 root 822: fprintf(debugOutput, "%2.2x ", STMemory_ReadByte(memdump_addr++));
823: fprintf(debugOutput, " "); /* print ASCII data */
1.1.1.6 root 824: for (i = 0; i < MEMDUMP_COLS; i++)
825: {
826: c = STMemory_ReadByte(memdump_addr-MEMDUMP_COLS+i);
1.1.1.8 root 827: if(!isprint((unsigned)c))
1.1.1.6 root 828: c = NON_PRINT_CHAR; /* non-printable as dots */
1.1.1.9 root 829: fprintf(debugOutput,"%c", c);
1.1.1.6 root 830: }
1.1.1.9 root 831: fprintf(debugOutput, "\n"); /* newline */
1.1.1.6 root 832: } /* while */
1.1.1.9 root 833: fflush(debugOutput);
1.1.1.11 root 834:
835: return DEBUGGER_CMDCONT;
836: }
1.1 root 837:
1.1.1.6 root 838:
1.1.1.8 root 839: /**
1.1.1.11 root 840: * Command: Write to memory, arg = starting address, followed by bytes.
1.1.1.8 root 841: */
1.1.1.11 root 842: static int DebugUI_MemWrite(int nArgc, char *psArgs[])
1.1 root 843: {
1.1.1.11 root 844: int i, numBytes;
845: Uint32 write_addr, d;
846: unsigned char bytes[256]; /* store bytes */
1.1.1.6 root 847:
1.1.1.11 root 848: if (nArgc < 3)
849: {
850: DebugUI_PrintCmdHelp(psArgs[0]);
851: return DEBUGGER_CMDDONE;
852: }
1.1.1.6 root 853:
1.1.1.11 root 854: /* Read address */
855: if (!Str_GetNumber(psArgs[1], &write_addr))
1.1.1.6 root 856: {
857: fprintf(stderr, "Bad address!\n");
1.1.1.11 root 858: return DEBUGGER_CMDDONE;
1.1.1.6 root 859: }
860:
861: write_addr &= 0x00FFFFFF;
1.1.1.11 root 862: numBytes = 0;
1.1.1.6 root 863:
864: /* get bytes data */
1.1.1.11 root 865: for (i = 2; i < nArgc; i++)
1.1.1.6 root 866: {
1.1.1.11 root 867: if (!Str_GetNumber(psArgs[i], &d) || d > 255)
1.1.1.6 root 868: {
1.1.1.11 root 869: fprintf(stderr, "Bad byte argument: '%s'!\n", psArgs[i]);
870: return DEBUGGER_CMDDONE;
1.1.1.6 root 871: }
872:
1.1.1.11 root 873: bytes[numBytes] = d & 0x0FF;
1.1.1.6 root 874: numBytes++;
875: }
876:
877: /* write the data */
878: for (i = 0; i < numBytes; i++)
879: STMemory_WriteByte(write_addr + i, bytes[i]);
1.1 root 880:
1.1.1.11 root 881: return DEBUGGER_CMDDONE;
882: }
1.1.1.6 root 883:
1.1.1.8 root 884: /**
1.1.1.11 root 885: * Command: Show given value in bin/dec/hex number bases or change number base
1.1.1.8 root 886: */
1.1.1.11 root 887: static int DebugUI_ShowValue(int argc, char *argv[])
1.1 root 888: {
1.1.1.11 root 889: static const struct {
890: const char name[4];
891: int base;
892: } bases[] = {
893: { "bin", 2 },
894: { "dec", 10 },
895: { "hex", 16 }
896: };
897: bool one, ones;
898: Uint32 value;
899: int bit, i;
900:
901: if (argc < 2)
902: {
903: DebugUI_PrintCmdHelp(argv[0]);
904: return DEBUGGER_CMDDONE;
905: }
906:
907: for (i = 0; i < ARRAYSIZE(bases); i++)
908: {
909: if (strcasecmp(bases[i].name, argv[1]) == 0)
910: {
911: if (ConfigureParams.Log.nNumberBase != bases[i].base)
912: {
913: fprintf(stderr, "Switched default number base from %d to %d-based (%s) values\n",
914: ConfigureParams.Log.nNumberBase,
915: bases[i].base, bases[i].name);
916: ConfigureParams.Log.nNumberBase = bases[i].base;
917: } else {
918: fprintf(stderr, "Already in '%s' mode\n", bases[i].name);
919: }
920: return DEBUGGER_CMDDONE;
921: }
922: }
923:
924: if (!Str_GetNumber(argv[1], &value))
925: return DEBUGGER_CMDDONE;
926:
927: fprintf(stderr, "'%s' = %%", argv[1]);
928: ones = false;
929: for (bit = 31; bit >= 0; bit--)
930: {
931: one = value & (1<<bit);
932: if (one || ones)
933: {
934: fputc(one ? '1':'0', stderr);
935: ones = true;
936: }
937: }
938: if (!ones)
939: fputc('0', stderr);
940: fprintf(stderr, " (bin), #%u (dec), $%x (hex)\n", value, value);
941: return DEBUGGER_CMDDONE;
1.1 root 942: }
943:
1.1.1.9 root 944:
1.1.1.8 root 945: /**
1.1.1.11 root 946: * Command: Set options
1.1.1.8 root 947: */
1.1.1.11 root 948: static int DebugUI_SetOptions(int argc, char *argv[])
1.1.1.6 root 949: {
1.1.1.11 root 950: CNF_PARAMS current;
1.1.1.6 root 951:
1.1.1.11 root 952: /* get configuration changes */
953: current = ConfigureParams;
1.1 root 954:
1.1.1.11 root 955: /* Parse and apply options */
956: if (Opt_ParseParameters(argc, (const char**)argv))
1.1.1.6 root 957: {
1.1.1.11 root 958: ConfigureParams.Screen.bFullScreen = false;
959: Change_CopyChangedParamsToConfiguration(¤t, &ConfigureParams, false);
1.1.1.6 root 960: }
1.1.1.11 root 961: else
962: {
963: ConfigureParams = current;
964: }
965:
966: return DEBUGGER_CMDDONE;
967: }
968:
969:
970: /**
971: * Command: Continue emulation / single-stepping
972: */
973: static int DebugUI_Continue(int nArgc, char *psArgv[], bool bStepDsp)
974: {
975: const char *chip;
976: int steps = 0;
977:
978: if (nArgc > 1)
979: {
980: steps = atoi(psArgv[1]);
981: }
982: /* at most one should be active at the same time */
983: nDspSteps = 0;
984: nCpuSteps = 0;
985: if (steps <= 0)
986: {
1.1.1.12! root 987: fprintf(stderr,"Returning to emulation...\n");
1.1.1.11 root 988: return DEBUGGER_END;
989: }
990: if (bStepDsp)
991: {
992: nDspSteps = steps;
993: #if ENABLE_DSP_EMU
994: chip = "DSP";
995: #else
996: chip = "<NONE>";
997: #endif
998: } else {
999: nCpuSteps = steps;
1000: chip = "CPU";
1.1.1.9 root 1001: }
1.1.1.11 root 1002: fprintf(stderr,"Returning to emulation for %i %s instructions...\n", steps, chip);
1003: return DEBUGGER_END;
1004: }
1005:
1006: /**
1007: * Command: Continue emulation / single-stepping CPU wrapper
1008: */
1009: static int DebugUI_CpuContinue(int nArgc, char *psArgv[])
1010: {
1011: return DebugUI_Continue(nArgc, psArgv, false);
1012: }
1013: /**
1014: * Command: Continue emulation / single-stepping DSP wrapper
1015: */
1016: static int DebugUI_DspContinue(int nArgc, char *psArgv[])
1017: {
1018: return DebugUI_Continue(nArgc, psArgv, true);
1019: }
1.1.1.6 root 1020:
1.1.1.8 root 1021:
1.1.1.11 root 1022: /**
1023: * Command: Quit emulator
1024: */
1025: static int DebugUI_QuitEmu(int nArgc, char *psArgv[])
1026: {
1027: bQuitProgram = true;
1028: M68000_SetSpecial(SPCFLAG_BRK); /* Assure that CPU core shuts down */
1029: return DEBUGGER_END;
1030: }
1031:
1032:
1033: typedef struct
1034: {
1035: int (*pFunction)(int argc, char *argv[]);
1036: const char *sLongName;
1037: const char *sShortName;
1038: const char *sShortDesc;
1039: const char *sUsage;
1040: bool bNoParsing;
1041: } dbgcommand_t;
1042:
1043: dbgcommand_t commandtab[] =
1044: {
1045: #if ENABLE_DSP_EMU
1046: { DebugUI_DspBreakPoint, "dspaddress", "da",
1047: "toggle or list (traditional) DSP address breakpoints",
1048: "[address]\n"
1049: "\tToggle breakpoint at <address> or list all breakpoints when\n"
1050: "\tno address is given.",
1051: false },
1052: { DebugUI_BreakCondDsp, "dspbreak", "db",
1053: "set/remove/list DSP register/RAM condition breakpoints",
1054: "[help | all | <breakpoint index> | <breakpoint condition>]\n"
1055: "\tSet breakpoint with given condition, remove breakpoint with\n"
1056: "\tgiven index or list all breakpoints when no args are given.\n"
1057: "\t'help' outputs breakpoint condition syntax help, 'all' removes\n"
1058: "\tall conditional breakpoints",
1059: true },
1060: { DebugUI_DspDisAsm, "dspdisasm", "dd",
1061: "disassemble DSP code",
1062: "[address]\n"
1063: "\tDisassemble from DSP-PC, otherwise at given address.",
1064: false },
1065: { DebugUI_DspMemDump, "dspmemdump", "dm",
1066: "dump DSP memory",
1067: "<x|y|p> [address]\n"
1068: "\tdump DSP memory at address, or continue from previous address if not\n"
1069: "\tspecified.",
1070: false },
1071: { DebugUI_DspRegister, "dspreg", "dr",
1072: "read/write DSP registers",
1073: "[REG=value]"
1074: "\tSet or dump contents of DSP registers.",
1075: false },
1076: { DebugUI_DspContinue, "dspcont", "dc",
1077: "continue emulation / DSP single-stepping",
1078: "[steps]\n"
1079: "\tLeave debugger and continue emulation for <steps> DSP instructions\n"
1080: "\tor forever if no steps have been specified.",
1081: false },
1082: #endif
1083: { DebugUI_CpuBreakPoint, "address", "a",
1084: "toggle or list (traditional) CPU address breakpoints",
1085: "[address]\n"
1086: "\tToggle breakpoint at <address> or list all breakpoints when\n"
1087: "\tno address is given.",
1088: false },
1089: { DebugUI_BreakCondCpu, "breakpoint", "b",
1090: "set/remove/list register/RAM condition breakpoints",
1091: "[help | all | <breakpoint index> | <breakpoint condition>]\n"
1092: "\tSet breakpoint with given condition, remove breakpoint with\n"
1093: "\tgiven index or list all breakpoints when no args are given.\n"
1094: "\t'help' outputs breakpoint condition syntax help, 'all' removes\n"
1095: "\tall conditional breakpoints",
1096: true },
1097: { DebugUI_DisAsm, "disasm", "d",
1098: "disassemble from PC, or given address",
1099: "[address]\n"
1100: "\tIf no address is given, this command disassembles from the last\n"
1101: "\tposition or from current PC if no last postition is available.",
1102: false },
1103: { DebugUI_CpuRegister, "cpureg", "r",
1104: "dump register values or set register to value",
1105: "[REG=value]\n"
1106: "\tSet CPU register to value or dumps all register if no parameter\n"
1107: "\thas been specified.",
1108: false },
1109: { DebugUI_MemDump, "memdump", "m",
1110: "dump memory",
1111: "[address]\n"
1112: "\tdump memory at address or continue dump from previous address.",
1113: false },
1114: { DebugUI_MemWrite, "memwrite", "w",
1115: "write bytes to memory",
1116: "address byte1 [byte2 ...]\n"
1117: "\tWrite bytes to a memory address, bytes are space separated\n"
1118: "\thexadecimals.",
1119: false },
1120: { DebugUI_SetLogFile, "logfile", "f",
1121: "open or close log file",
1122: "[filename]\n"
1123: "\tOpen log file, no argument closes the log file. Output of\n"
1124: "\tregister & memory dumps and disassembly will be written to it.",
1125: false },
1126: { DebugUI_LoadBin, "loadbin", "l",
1127: "load a file into memory",
1128: "filename address\n"
1129: "\tLoad the file <filename> into memory starting at <address>.",
1130: false },
1131: { DebugUI_SaveBin, "savebin", "s",
1132: "save memory to a file",
1133: "filename address length\n"
1134: "\tSave the memory block at <address> with given <length> to\n"
1135: "\tthe file <filename>.",
1136: false },
1137: { DebugUI_SetOptions, "setopt", "o",
1138: "set Hatari command line options",
1139: "[command line parameters]\n"
1140: "\tSet options like command line parameters. For example to"
1141: "\tenable CPU disasm tracing: setopt --trace cpu_disasm",
1142: false },
1143: { DebugUI_ShowValue, "value", "v",
1144: "set number base / show value in other number bases",
1145: "<bin|dec|hex|value>\n"
1146: "\tHelper to change the default number base and to see given values\n"
1147: "\tin all the supported bin/dec/hex number bases.",
1148: false },
1149: { DebugUI_CpuContinue, "cont", "c",
1150: "continue emulation / CPU single-stepping",
1151: "[steps]\n"
1152: "\tLeave debugger and continue emulation for <steps> CPU instructions\n"
1153: "\tor forever if no steps have been specified.",
1154: false },
1155: { DebugUI_QuitEmu, "quit", "q",
1156: "quit emulator",
1157: "\n"
1158: "\tLeave debugger and quit emulator.",
1159: false },
1160: { DebugUI_Help, "help", "h",
1161: "print help",
1162: "[command]"
1163: "\tPrint help text for available commands.",
1164: false },
1165: };
1166:
1167:
1168: /**
1169: * Print help text for one command
1170: */
1171: static void DebugUI_PrintCmdHelp(const char *psCmd)
1172: {
1173: int i;
1174:
1175: /* Search the command ... */
1176: for (i = 0; i < ARRAYSIZE(commandtab); i++)
1.1.1.6 root 1177: {
1.1.1.11 root 1178: if (!strcmp(psCmd, commandtab[i].sLongName)
1179: || !strcmp(psCmd, commandtab[i].sShortName))
1180: {
1181: /* ... and print help text */
1182: fprintf(stderr, "'%s' or '%s' - %s\n",
1183: commandtab[i].sLongName, commandtab[i].sShortName,
1184: commandtab[i].sShortDesc);
1185: fprintf(stderr, "Usage: %s %s\n", commandtab[i].sShortName,
1186: commandtab[i].sUsage);
1187: return;
1.1.1.6 root 1188: }
1.1.1.11 root 1189: }
1.1.1.6 root 1190:
1.1.1.11 root 1191: fprintf(stderr, "Unknown command '%s'\n", psCmd);
1192: }
1.1.1.6 root 1193:
1194:
1.1.1.11 root 1195: /**
1196: * Command: Print debugger help screen.
1197: */
1198: static int DebugUI_Help(int nArgc, char *psArgs[])
1199: {
1200: int i;
1201:
1202: if (nArgc > 1)
1203: {
1204: DebugUI_PrintCmdHelp(psArgs[1]);
1205: return DEBUGGER_CMDDONE;
1206: }
1207:
1208: fputs("Available commands:\n", stderr);
1209: for (i = 0; i < ARRAYSIZE(commandtab); i++)
1210: {
1211: fprintf(stderr, " %12s (%2s) : %s\n", commandtab[i].sLongName,
1212: commandtab[i].sShortName, commandtab[i].sShortDesc);
1213: }
1214:
1215: fprintf(stderr,
1216: "If value is prefixed with '$', it's a hexadecimal, if with '#', it's\n"
1217: "a normal decimal, if with '%%', it's a binary decimal. Prefix can\n"
1218: "be skipped for numbers in the default number base (currently %d).\n"
1219: "Adresses may be given as a range like '$fc0000-$fc0100'.\n"
1220: "'h <command>' gives more help.\n", ConfigureParams.Log.nNumberBase);
1221: return DEBUGGER_CMDDONE;
1222: }
1223:
1224:
1225: /**
1226: * Parse debug command and execute it.
1227: */
1228: int DebugUI_ParseCommand(char *input)
1229: {
1230: char *psArgs[64];
1231: const char *delim;
1232: static char sLastCmd[80] = { '\0' };
1233: int nArgc, cmd = -1;
1234: int i, retval;
1.1.1.6 root 1235:
1.1.1.11 root 1236: psArgs[0] = strtok(input, " \t");
1237:
1238: if (psArgs[0] == NULL)
1239: {
1240: if (strlen(sLastCmd) > 0)
1241: psArgs[0] = sLastCmd;
1.1.1.8 root 1242: else
1.1.1.11 root 1243: return DEBUGGER_CMDDONE;
1244: }
1245:
1246: /* Search the command ... */
1247: for (i = 0; i < ARRAYSIZE(commandtab); i++)
1248: {
1249: if (!strcmp(psArgs[0], commandtab[i].sLongName)
1250: || !strcmp(psArgs[0], commandtab[i].sShortName))
1251: {
1252: cmd = i;
1253: break;
1254: }
1255: }
1256: if (cmd == -1)
1257: {
1258: fprintf(stderr, "Command '%s' not found.\n"
1259: "Use 'help' to view a list of available commands.\n",
1260: psArgs[0]);
1261: return DEBUGGER_CMDDONE;
1262: }
1263:
1264: if (commandtab[cmd].bNoParsing)
1265: delim = "";
1266: else
1267: delim = " \t";
1268:
1269: /* Separate arguments and put the pointers into psArgs */
1270: for (nArgc = 1; nArgc < ARRAYSIZE(psArgs); nArgc++)
1271: {
1272: psArgs[nArgc] = strtok(NULL, delim);
1273: if (psArgs[nArgc] == NULL)
1274: break;
1275: }
1.1.1.6 root 1276:
1.1.1.11 root 1277: if (!debugOutput) {
1278: /* make sure also calls from control.c work */
1279: DebugUI_SetLogDefault();
1.1.1.6 root 1280: }
1281:
1.1.1.11 root 1282: /* ... and execute the function */
1283: retval = commandtab[i].pFunction(nArgc, psArgs);
1284: /* Save commando string if it can be repeated */
1285: if (retval == DEBUGGER_CMDCONT)
1286: strncpy(sLastCmd, psArgs[0], sizeof(sLastCmd));
1287: else
1288: sLastCmd[0] = '\0';
1.1.1.9 root 1289: return retval;
1290: }
1291:
1.1.1.11 root 1292:
1.1.1.9 root 1293: /**
1.1.1.11 root 1294: * Read a command line from the keyboard and return a pointer to the string.
1295: * @return Pointer to the string which should be deallocated free()
1296: * after use. Returns NULL when error occured.
1.1.1.9 root 1297: */
1.1.1.11 root 1298: static char *DebugUI_GetCommand(void)
1.1.1.9 root 1299: {
1300: char *input;
1.1.1.8 root 1301:
1.1.1.9 root 1302: #if HAVE_LIBREADLINE
1303: input = readline("> ");
1304: if (!input)
1.1.1.11 root 1305: return NULL;
1.1.1.9 root 1306: if (input[0] != 0)
1307: add_history(input);
1308: #else
1309: fprintf(stderr, "> ");
1310: input = malloc(256);
1311: if (!input)
1.1.1.11 root 1312: return NULL;
1.1.1.9 root 1313: input[0] = '\0';
1.1.1.11 root 1314: if (fgets(input, 256, stdin) == NULL)
1315: {
1316: free(input);
1317: return NULL;
1318: }
1.1.1.9 root 1319: #endif
1.1.1.11 root 1320: input = Str_Trim(input);
1.1.1.9 root 1321:
1.1.1.11 root 1322: return input;
1323: }
1324:
1325:
1326: /**
1327: * Texts shown when entering the debugger on first and successive times
1328: */
1329: static void DebugUI_WelcomeText(void)
1330: {
1331: int hbl, fcycles, lcycles;
1332: static const char *welcome =
1333: "\n----------------------------------------------------------------------"
1334: "\nYou have entered debug mode. Type c to continue emulation, h for help.\n";
1335: if (welcome)
1336: {
1337: fputs(welcome, stderr);
1338: welcome = NULL;
1339: }
1340: Video_GetPosition(&fcycles, &hbl, &lcycles);
1341: fprintf(stderr, "\nCPU=$%x, VBL=%d, FrameCycles=%d, HBL=%d, LineCycles=%d, DSP=",
1342: M68000_GetPC(), nVBLs, fcycles, hbl, lcycles);
1343: if (bDspEnabled)
1344: fprintf(stderr, "$%x\n", DSP_GetPC());
1345: else
1346: fprintf(stderr, "N/A\n");
1.1 root 1347: }
1348:
1349:
1.1.1.8 root 1350: /**
1.1.1.11 root 1351: * Debugger user interface main function.
1.1.1.8 root 1352: */
1.1.1.4 root 1353: void DebugUI(void)
1.1 root 1354: {
1.1.1.11 root 1355: int cmdret;
1356:
1357: /* if you want disassembly or memdumping to start/continue from
1358: * specific address, you can set them here. If disassembly
1359: * address is zero, disassembling starts from PC.
1360: */
1361: #if ENABLE_DSP_EMU
1362: dsp_disasm_addr = 0;
1363: dsp_memdump_addr = 0;
1364: dsp_mem_space = 'P';
1365: #endif
1366: memdump_addr = 0;
1.1.1.6 root 1367: disasm_addr = 0;
1.1.1.2 root 1368:
1.1.1.11 root 1369: if (bInFullScreen)
1370: Screen_ReturnFromFullScreen();
1371:
1372: DebugUI_WelcomeText();
1373:
1374: /* override paused message so that user knows to look into console
1375: * on how to continue in case he invoked the debugger by accident.
1376: */
1377: Statusbar_AddMessage("Console Debugger", 100);
1378: Statusbar_Update(sdlscrn);
1379:
1380: do
1381: {
1382: char *psCmd;
1383:
1384: /* Read command from the keyboard */
1385: psCmd = DebugUI_GetCommand();
1386:
1387: if (psCmd)
1388: {
1389: /* Parse and execute the command string */
1390: cmdret = DebugUI_ParseCommand(psCmd);
1391: free(psCmd);
1392: }
1393: else
1394: {
1395: cmdret = DEBUGGER_END;
1396: }
1397: }
1398: while (cmdret != DEBUGGER_END);
1399:
1.1.1.9 root 1400: DebugUI_SetLogDefault();
1.1.1.11 root 1401:
1402: /* If "real-time" debugging like breakpoints has been set, we've
1403: * got to tell the CPU core to call us after each instruction! */
1404: if (nCpuActiveBPs || nCpuActiveCBs || nCpuSteps)
1405: M68000_SetSpecial(SPCFLAG_DEBUGGER);
1406: else
1407: M68000_UnsetSpecial(SPCFLAG_DEBUGGER);
1408: /* ...and DSP core */
1409: if (nDspActiveBPs || nDspActiveCBs || nDspSteps)
1410: DSP_SetDebugging(true);
1411: else
1412: DSP_SetDebugging(false);
1413: }
1414:
1415:
1416: /**
1417: * Check if we hit a CPU breakpoint
1418: */
1419: static void DebugUI_CheckCpuBreakpoints(void)
1420: {
1421: Uint32 pc = M68000_GetPC();
1422: int i;
1423:
1424: for (i = 0; i < nCpuActiveBPs; i++)
1425: {
1426: if (pc == CpuBreakPoint[i])
1427: {
1428: fprintf(stderr, "\nCPU breakpoint at %x ...", pc);
1429: DebugUI();
1430: break;
1431: }
1432: }
1433: }
1434:
1435:
1436: /**
1437: * This function is called after each CPU instruction when debugging is enabled.
1438: */
1439: void DebugUI_CpuCheck(void)
1440: {
1441: if (nCpuActiveBPs)
1442: {
1443: DebugUI_CheckCpuBreakpoints();
1444: }
1445: if (nCpuActiveCBs)
1446: {
1447: if (BreakCond_MatchCpu())
1448: DebugUI();
1449: }
1450: if (nCpuSteps)
1451: {
1452: nCpuSteps -= 1;
1453: if (nCpuSteps == 0)
1454: DebugUI();
1455: }
1.1 root 1456: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.