|
|
1.1 root 1: /*
2: Hatari - debuginfo.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: debuginfo.c - functions needed to show info about the atari HW & OS
8: components and "lock" that info to be shown on entering the debugger.
9: */
10: const char DebugInfo_fileid[] = "Hatari debuginfo.c : " __DATE__ " " __TIME__;
11:
12: #include <stdio.h>
13: #include <assert.h>
1.1.1.6 ! root 14: #include <ctype.h>
! 15:
1.1 root 16: #include "main.h"
1.1.1.4 root 17: #include "bios.h"
1.1.1.5 root 18: #include "blitter.h"
1.1 root 19: #include "configuration.h"
1.1.1.6 ! root 20: #include "crossbar.h"
1.1 root 21: #include "debugInfo.h"
22: #include "debugcpu.h"
23: #include "debugdsp.h"
24: #include "debugui.h"
1.1.1.5 root 25: #include "debug_priv.h"
1.1 root 26: #include "dsp.h"
27: #include "evaluate.h"
1.1.1.2 root 28: #include "file.h"
29: #include "gemdos.h"
1.1.1.3 root 30: #include "history.h"
1.1 root 31: #include "ioMem.h"
32: #include "m68000.h"
1.1.1.6 ! root 33: #include "psg.h"
1.1 root 34: #include "stMemory.h"
35: #include "tos.h"
1.1.1.2 root 36: #include "screen.h"
37: #include "vdi.h"
1.1 root 38: #include "video.h"
1.1.1.6 ! root 39: #include "videl.h"
1.1.1.4 root 40: #include "xbios.h"
1.1.1.6 ! root 41: #include "newcpu.h"
! 42: #include "68kDisass.h"
1.1 root 43:
44:
45: /* ------------------------------------------------------------------
46: * TOS information
47: */
48: #define OS_SYSBASE 0x4F2
49: #define OS_HEADER_SIZE 0x30
50:
51: #define COOKIE_JAR 0x5A0
52:
53: #define BASEPAGE_SIZE 0x100
54:
55: #define GEM_MAGIC 0x87654321
56: #define GEM_MUPB_SIZE 0xC
57:
58: #define RESET_MAGIC 0x31415926
59: #define RESET_VALID 0x426
60: #define RESET_VECTOR 0x42A
61:
62: #define COUNTRY_SPAIN 4
63:
1.1.1.2 root 64:
1.1 root 65: /**
1.1.1.5 root 66: * DebugInfo_GetSysbase: get and validate system base
67: * return on success sysbase address (+ set rombase), on failure return zero
1.1 root 68: */
1.1.1.5 root 69: static Uint32 DebugInfo_GetSysbase(Uint32 *rombase)
1.1 root 70: {
71: Uint32 sysbase = STMemory_ReadLong(OS_SYSBASE);
72:
73: if (!STMemory_ValidArea(sysbase, OS_HEADER_SIZE)) {
1.1.1.5 root 74: fprintf(stderr, "Invalid TOS sysbase RAM address (0x%x)!\n", sysbase);
1.1 root 75: return 0;
76: }
1.1.1.5 root 77: /* under TOS, sysbase = os_beg = TosAddress, but not under MiNT -> use os_beg */
78: *rombase = STMemory_ReadLong(sysbase+0x08);
79: if (!STMemory_ValidArea(*rombase, OS_HEADER_SIZE)) {
80: fprintf(stderr, "Invalid TOS sysbase ROM address (0x%x)!\n", *rombase);
81: return 0;
82: }
83: if (*rombase != TosAddress) {
84: fprintf(stderr, "os_beg (0x%x) != TOS address (0x%x), header in RAM not set up yet?\n",
85: *rombase, TosAddress);
1.1 root 86: return 0;
87: }
88: return sysbase;
89: }
90:
91: /**
1.1.1.5 root 92: * DebugInfo_CurrentBasepage: get and validate currently running program basepage.
93: * if given sysbase is zero, use system sysbase.
1.1 root 94: */
1.1.1.5 root 95: static Uint32 DebugInfo_CurrentBasepage(Uint32 sysbase)
1.1 root 96: {
1.1.1.5 root 97: Uint32 basepage;
1.1 root 98: Uint16 osversion, osconf;
99:
100: if (!sysbase) {
1.1.1.5 root 101: Uint32 rombase;
102: sysbase = DebugInfo_GetSysbase(&rombase);
103: if (!sysbase) {
104: return 0;
105: }
1.1 root 106: }
1.1.1.5 root 107: osversion = STMemory_ReadWord(sysbase+0x02);
1.1 root 108: if (osversion >= 0x0102) {
109: basepage = STMemory_ReadLong(sysbase+0x28);
110: } else {
111: osconf = STMemory_ReadWord(sysbase+0x1C);
112: if((osconf>>1) == COUNTRY_SPAIN) {
113: basepage = 0x873C;
114: } else {
115: basepage = 0x602C;
116: }
117: }
118: if (STMemory_ValidArea(basepage, 4)) {
119: return STMemory_ReadLong(basepage);
120: }
121: fprintf(stderr, "Pointer 0x%06x to basepage address is invalid!\n", basepage);
122: return 0;
123: }
124:
1.1.1.2 root 125:
126: /**
1.1.1.5 root 127: * GetBasepageValue: return basepage value at given offset in
1.1.1.2 root 128: * TOS process basepage or zero if that is missing/invalid.
129: */
1.1.1.5 root 130: static Uint32 GetBasepageValue(unsigned offset)
1.1.1.2 root 131: {
1.1.1.5 root 132: Uint32 basepage = DebugInfo_CurrentBasepage(0);
1.1.1.2 root 133: if (!basepage) {
134: return 0;
135: }
136: if (!STMemory_ValidArea(basepage, BASEPAGE_SIZE) ||
137: STMemory_ReadLong(basepage) != basepage) {
138: fprintf(stderr, "Basepage address 0x%06x is invalid!\n", basepage);
139: return 0;
140: }
141: return STMemory_ReadLong(basepage+offset);
142: }
143:
144: /**
145: * DebugInfo_GetTEXT: return current program TEXT segment address
146: * or zero if basepage missing/invalid. For virtual debugger variable.
147: */
148: Uint32 DebugInfo_GetTEXT(void)
149: {
1.1.1.5 root 150: return GetBasepageValue(0x08);
151: }
152: /**
153: * DebugInfo_GetTEXTEnd: return current program TEXT segment end address
154: * or zero if basepage missing/invalid. For virtual debugger variable.
155: */
156: Uint32 DebugInfo_GetTEXTEnd(void)
157: {
158: Uint32 addr = GetBasepageValue(0x08);
159: if (addr) {
160: return addr + GetBasepageValue(0x0C) - 1;
161: }
162: return 0;
1.1.1.2 root 163: }
164: /**
165: * DebugInfo_GetDATA: return current program DATA segment address
166: * or zero if basepage missing/invalid. For virtual debugger variable.
167: */
168: Uint32 DebugInfo_GetDATA(void)
169: {
1.1.1.5 root 170: return GetBasepageValue(0x010);
1.1.1.2 root 171: }
172: /**
173: * DebugInfo_GetBSS: return current program BSS segment address
174: * or zero if basepage missing/invalid. For virtual debugger variable.
175: */
176: Uint32 DebugInfo_GetBSS(void)
177: {
1.1.1.5 root 178: return GetBasepageValue(0x18);
1.1.1.2 root 179: }
180:
181:
1.1 root 182: /**
183: * DebugInfo_Basepage: show TOS process basepage information
184: * at given address.
185: */
186: static void DebugInfo_Basepage(Uint32 basepage)
187: {
188: Uint8 cmdlen;
189: Uint32 env;
190:
191: if (!basepage) {
192: /* default to current process basepage */
1.1.1.5 root 193: basepage = DebugInfo_CurrentBasepage(0);
1.1 root 194: if (!basepage) {
195: return;
196: }
197: }
198: fprintf(stderr, "Process basepage information:\n");
199: if (!STMemory_ValidArea(basepage, BASEPAGE_SIZE) ||
200: STMemory_ReadLong(basepage) != basepage) {
201: fprintf(stderr, "- address 0x%06x is invalid!\n", basepage);
202: return;
203: }
204: fprintf(stderr, "- TPA start : 0x%06x\n", STMemory_ReadLong(basepage));
205: fprintf(stderr, "- TPA end +1 : 0x%06x\n", STMemory_ReadLong(basepage+0x04));
206: fprintf(stderr, "- Text segment : 0x%06x\n", STMemory_ReadLong(basepage+0x08));
207: fprintf(stderr, "- Text size : 0x%x\n", STMemory_ReadLong(basepage+0x0C));
208: fprintf(stderr, "- Data segment : 0x%06x\n", STMemory_ReadLong(basepage+0x10));
209: fprintf(stderr, "- Data size : 0x%x\n", STMemory_ReadLong(basepage+0x14));
210: fprintf(stderr, "- BSS segment : 0x%06x\n", STMemory_ReadLong(basepage+0x18));
211: fprintf(stderr, "- BSS size : 0x%x\n", STMemory_ReadLong(basepage+0x1C));
212: fprintf(stderr, "- Process DTA : 0x%06x\n", STMemory_ReadLong(basepage+0x20));
213: fprintf(stderr, "- Parent basepage: 0x%06x\n", STMemory_ReadLong(basepage+0x24));
214:
215: env = STMemory_ReadLong(basepage+0x2C);
216: fprintf(stderr, "- Environment : 0x%06x\n", env);
217: if (STMemory_ValidArea(env, 4096)) {
218: Uint32 end = env + 4096;
219: while (env < end && *(STRam+env)) {
220: fprintf(stderr, "'%s'\n", STRam+env);
221: env += strlen((const char *)(STRam+env)) + 1;
222: }
223: }
224: cmdlen = STMemory_ReadByte(basepage+0x80);
225: fprintf(stderr, "- Command argslen: %d\n", cmdlen);
226: if (cmdlen) {
227: int offset = 0;
228: while (offset < cmdlen) {
229: fprintf(stderr, " '%s'", STRam+basepage+0x81+offset);
230: offset += strlen((const char *)(STRam+basepage+0x81+offset)) + 1;
231: }
232: fprintf(stderr, "\n");
233: }
234: }
235:
236: /**
1.1.1.5 root 237: * DebugInfo_PrintOSHeader: output OS Header information
1.1 root 238: */
1.1.1.5 root 239: static void DebugInfo_PrintOSHeader(Uint32 sysbase)
1.1 root 240: {
1.1.1.5 root 241: Uint32 gemblock, basepage;
1.1.1.2 root 242: Uint16 osversion, osconf, langbits;
243: const char *lang;
244: static const char langs[][3] = {
245: "us", "de", "fr", "uk", "es", "it", "se", "ch" /* fr */, "ch" /* de */,
246: "tr", "fi", "no", "dk", "sa", "nl", "cs", "hu"
247: };
1.1 root 248:
1.1.1.5 root 249: osversion = STMemory_ReadWord(sysbase+0x02);
1.1 root 250: fprintf(stderr, "OS base addr : 0x%06x\n", sysbase);
251: fprintf(stderr, "OS RAM end+1 : 0x%06x\n", STMemory_ReadLong(sysbase+0x0C));
252: fprintf(stderr, "TOS version : 0x%x\n", osversion);
253:
254: fprintf(stderr, "Reset handler: 0x%06x\n", STMemory_ReadLong(sysbase+0x04));
255: fprintf(stderr, "Reset vector : 0x%06x\n", STMemory_ReadLong(RESET_VECTOR));
256: fprintf(stderr, "Reset valid : 0x%x (valid=0x%x)\n", STMemory_ReadLong(RESET_VALID), RESET_MAGIC);
257:
258: gemblock = STMemory_ReadLong(sysbase+0x14);
259: fprintf(stderr, "GEM Memory Usage Parameter Block:\n");
260: if (STMemory_ValidArea(gemblock, GEM_MUPB_SIZE)) {
261: fprintf(stderr, "- Block addr : 0x%06x\n", gemblock);
262: fprintf(stderr, "- GEM magic : 0x%x (valid=0x%x)\n", STMemory_ReadLong(gemblock), GEM_MAGIC);
263: fprintf(stderr, "- GEM entry : 0x%06x\n", STMemory_ReadLong(gemblock+4));
264: fprintf(stderr, "- GEM end : 0x%06x\n", STMemory_ReadLong(gemblock+8));
265: } else {
266: fprintf(stderr, "- is at INVALID 0x%06x address.\n", gemblock);
267: }
268:
269: fprintf(stderr, "OS date : 0x%x\n", STMemory_ReadLong(sysbase+0x14));
270: fprintf(stderr, "OS DOS date : 0x%x\n", STMemory_ReadLong(sysbase+0x1E));
271:
272: osconf = STMemory_ReadWord(sysbase+0x1C);
1.1.1.2 root 273: langbits = osconf >> 1;
274: if (langbits == 127) {
275: lang = "all";
276: } else if (langbits < ARRAYSIZE(langs)) {
277: lang = langs[langbits];
278: } else {
279: lang = "unknown";
280: }
281: fprintf(stderr, "OS Conf bits : 0x%04x (%s, %s)\n", osconf, lang, osconf&1 ? "PAL":"NTSC");
1.1 root 282:
283: if (osversion >= 0x0102) {
1.1.1.2 root 284: /* last 3 OS header fields are only available as of TOS 1.02 */
1.1 root 285: fprintf(stderr, "Memory pool : 0x%06x\n", STMemory_ReadLong(sysbase+0x20));
286: fprintf(stderr, "Kbshift addr : 0x%06x\n", STMemory_ReadLong(sysbase+0x24));
287: } else {
1.1.1.2 root 288: /* TOS 1.0 */
289: fprintf(stderr, "Memory pool : 0x0056FA\n");
1.1 root 290: fprintf(stderr, "Kbshift addr : 0x000E1B\n");
291: }
1.1.1.5 root 292: basepage = DebugInfo_CurrentBasepage(sysbase);
1.1 root 293: if (basepage) {
294: fprintf(stderr, "Basepage : 0x%06x\n", basepage);
295: }
296: }
297:
1.1.1.5 root 298: /**
299: * DebugInfo_OSHeader: display TOS OS Header and RAM one
300: * if their addresses differ
301: */
302: static void DebugInfo_OSHeader(Uint32 dummy)
303: {
304: Uint32 sysbase, rombase;
305:
306: sysbase = DebugInfo_GetSysbase(&rombase);
307: if (!sysbase) {
308: return;
309: }
310: fprintf(stderr, "OS header information:\n");
311: DebugInfo_PrintOSHeader(sysbase);
312: if (sysbase != rombase) {
313: fprintf(stderr, "\nROM TOS OS header information:\n");
314: DebugInfo_PrintOSHeader(rombase);
315: return;
316: }
317: }
1.1 root 318:
1.1.1.2 root 319: /**
320: * DebugInfo_Cookiejar: display TOS Cookiejar content
321: */
322: static void DebugInfo_Cookiejar(Uint32 dummy)
323: {
324: int items;
325:
326: Uint32 jar = STMemory_ReadLong(COOKIE_JAR);
327: if (!jar) {
328: fprintf(stderr, "Cookiejar is empty.\n");
329: return;
330: }
331:
332: fprintf(stderr, "Cookiejar contents:\n");
333: items = 0;
334: while (STMemory_ValidArea(jar, 8) && STMemory_ReadLong(jar)) {
335: fprintf(stderr, "%c%c%c%c = 0x%08x\n",
336: STRam[jar], STRam[jar+1], STRam[jar+2], STRam[jar+3],
337: STMemory_ReadLong(jar+4));
338: jar += 8;
339: items++;
340: }
341: fprintf(stderr, "%d items at 0x%06x.\n", items, STMemory_ReadLong(COOKIE_JAR));
342: }
343:
344:
1.1 root 345: /* ------------------------------------------------------------------
346: * CPU and DSP information wrappers
347: */
348:
349: /**
350: * Helper to call debugcpu.c and debugdsp.c debugger commands
351: */
352: static void DebugInfo_CallCommand(int (*func)(int, char* []), const char *command, Uint32 arg)
353: {
354: char cmdbuffer[16], argbuffer[12];
355: char *argv[] = { cmdbuffer, NULL };
356: int argc = 1;
357:
358: assert(strlen(command) < sizeof(cmdbuffer));
359: strcpy(cmdbuffer, command);
360: if (arg) {
361: sprintf(argbuffer, "$%x", arg);
362: argv[argc++] = argbuffer;
363: }
364: func(argc, argv);
365: }
366:
367: static void DebugInfo_CpuRegister(Uint32 arg)
368: {
369: DebugInfo_CallCommand(DebugCpu_Register, "register", arg);
370: }
371: static void DebugInfo_CpuDisAsm(Uint32 arg)
372: {
373: DebugInfo_CallCommand(DebugCpu_DisAsm, "disasm", arg);
374: }
375: static void DebugInfo_CpuMemDump(Uint32 arg)
376: {
377: DebugInfo_CallCommand(DebugCpu_MemDump, "memdump", arg);
378: }
379:
380: #if ENABLE_DSP_EMU
381:
382: static void DebugInfo_DspRegister(Uint32 arg)
383: {
384: DebugInfo_CallCommand(DebugDsp_Register, "dspreg", arg);
385: }
386: static void DebugInfo_DspDisAsm(Uint32 arg)
387: {
388: DebugInfo_CallCommand(DebugDsp_DisAsm, "dspdisasm", arg);
389: }
390:
391: static void DebugInfo_DspMemDump(Uint32 arg)
392: {
393: char cmdbuf[] = "dspmemdump";
394: char addrbuf[6], spacebuf[2] = "X";
395: char *argv[] = { cmdbuf, spacebuf, addrbuf };
396: spacebuf[0] = (arg>>16)&0xff;
397: sprintf(addrbuf, "$%x", (Uint16)(arg&0xffff));
398: DebugDsp_MemDump(3, argv);
399: }
400:
401: /**
402: * Convert arguments to Uint32 arg suitable for DSP memdump callback
403: */
404: static Uint32 DebugInfo_DspMemArgs(int argc, char *argv[])
405: {
406: Uint32 value;
407: char space;
408: if (argc != 2) {
409: return 0;
410: }
1.1.1.6 ! root 411: space = toupper((unsigned char)argv[0][0]);
1.1 root 412: if ((space != 'X' && space != 'Y' && space != 'P') || argv[0][1]) {
413: fprintf(stderr, "ERROR: invalid DSP address space '%s'!\n", argv[0]);
414: return 0;
415: }
416: if (!Eval_Number(argv[1], &value) || value > 0xffff) {
417: fprintf(stderr, "ERROR: invalid DSP address '%s'!\n", argv[1]);
418: return 0;
419: }
420: return ((Uint32)space<<16) | value;
421: }
422:
423: #endif /* ENABLE_DSP_EMU */
424:
425:
426: static void DebugInfo_RegAddr(Uint32 arg)
427: {
428: bool forDsp;
429: char regname[3];
1.1.1.5 root 430: Uint32 *reg32, regvalue, mask;
1.1 root 431: char cmdbuf[12], addrbuf[6];
432: char *argv[] = { cmdbuf, addrbuf };
433:
434: regname[0] = (arg>>24)&0xff;
435: regname[1] = (arg>>16)&0xff;
436: regname[2] = '\0';
437:
1.1.1.5 root 438: if (DebugCpu_GetRegisterAddress(regname, ®32)) {
439: regvalue = *reg32;
1.1 root 440: mask = 0xffffffff;
441: forDsp = false;
442: } else {
1.1.1.5 root 443: int regsize = DSP_GetRegisterAddress(regname, ®32, &mask);
444: switch (regsize) {
445: /* currently regaddr supports only 32-bit Rx regs, but maybe later... */
446: case 16:
447: regvalue = *((Uint16*)reg32);
448: break;
449: case 32:
450: regvalue = *reg32;
451: break;
452: default:
1.1 root 453: fprintf(stderr, "ERROR: invalid address/data register '%s'!\n", regname);
454: return;
455: }
456: forDsp = true;
457: }
1.1.1.5 root 458: sprintf(addrbuf, "$%x", regvalue & mask);
1.1 root 459:
460: if ((arg & 0xff) == 'D') {
461: if (forDsp) {
462: #if ENABLE_DSP_EMU
1.1.1.5 root 463: strcpy(cmdbuf, "dd");
1.1 root 464: DebugDsp_DisAsm(2, argv);
465: #endif
466: } else {
1.1.1.5 root 467: strcpy(cmdbuf, "d");
1.1 root 468: DebugCpu_DisAsm(2, argv);
469: }
470: } else {
471: if (forDsp) {
472: #if ENABLE_DSP_EMU
1.1.1.5 root 473: /* use "Y" address space */
474: char cmd[] = "dm"; char space[] = "y";
475: char *dargv[] = { cmd, space, addrbuf };
476: DebugDsp_MemDump(3, dargv);
1.1 root 477: #endif
478: } else {
1.1.1.5 root 479: strcpy(cmdbuf, "m");
1.1 root 480: DebugCpu_MemDump(2, argv);
481: }
482: }
483: }
484:
485: /**
486: * Convert arguments to Uint32 arg suitable for RegAddr callback
487: */
488: static Uint32 DebugInfo_RegAddrArgs(int argc, char *argv[])
489: {
490: Uint32 value, *regaddr;
491: if (argc != 2) {
492: return 0;
493: }
494:
495: if (strcmp(argv[0], "disasm") == 0) {
496: value = 'D';
497: } else if (strcmp(argv[0], "memdump") == 0) {
498: value = 'M';
499: } else {
500: fprintf(stderr, "ERROR: regaddr operation can be only 'disasm' or 'memdump', not '%s'!\n", argv[0]);
501: return 0;
502: }
503:
504: if (strlen(argv[1]) != 2 ||
505: (!DebugCpu_GetRegisterAddress(argv[1], ®addr) &&
1.1.1.6 ! root 506: (toupper((unsigned char)argv[1][0]) != 'R'
! 507: || !isdigit((unsigned char)argv[1][1]) || argv[1][2]))) {
1.1 root 508: /* not CPU register or Rx DSP register */
509: fprintf(stderr, "ERROR: invalid address/data register '%s'!\n", argv[1]);
510: return 0;
511: }
512:
513: value |= argv[1][0] << 24;
514: value |= argv[1][1] << 16;
515: value &= 0xffff00ff;
516: return value;
517: }
518:
519:
520: /* ------------------------------------------------------------------
1.1.1.2 root 521: * wrappers for command to parse debugger input file
522: */
523:
524: /* file name to be given before calling the Parse function,
525: * needs to be set separately as it's a host pointer which
526: * can be 64-bit i.e. may not fit into Uint32.
527: */
528: static char *parse_filename;
529:
530: /**
531: * Parse and exec commands in the previously given debugger input file
532: */
533: static void DebugInfo_FileParse(Uint32 dummy)
534: {
535: if (parse_filename) {
1.1.1.5 root 536: DebugUI_ParseFile(parse_filename, true);
1.1.1.2 root 537: } else {
538: fputs("ERROR: debugger input file name to parse isn't set!\n", stderr);
539: }
540: }
541:
542: /**
543: * Set which input file to parse.
544: * Return true if file exists, false on error
545: */
546: static Uint32 DebugInfo_FileArgs(int argc, char *argv[])
547: {
548: if (argc != 1) {
549: return false;
550: }
551: if (!File_Exists(argv[0])) {
552: fprintf(stderr, "ERROR: given file '%s' doesn't exist!\n", argv[0]);
553: return false;
554: }
555: if (parse_filename) {
556: free(parse_filename);
557: }
558: parse_filename = strdup(argv[0]);
559: return true;
560: }
561:
562:
563: /* ------------------------------------------------------------------
1.1 root 564: * Debugger & readline TAB completion integration
565: */
566:
567: /**
568: * Default information on entering the debugger
569: */
570: static void DebugInfo_Default(Uint32 dummy)
571: {
572: int hbl, fcycles, lcycles;
1.1.1.6 ! root 573: uaecptr nextpc, pc = M68000_GetPC();
1.1 root 574: Video_GetPosition(&fcycles, &hbl, &lcycles);
1.1.1.6 ! root 575:
1.1 root 576: fprintf(stderr, "\nCPU=$%x, VBL=%d, FrameCycles=%d, HBL=%d, LineCycles=%d, DSP=",
1.1.1.6 ! root 577: pc, nVBLs, fcycles, hbl, lcycles);
1.1 root 578: if (bDspEnabled)
579: fprintf(stderr, "$%x\n", DSP_GetPC());
580: else
581: fprintf(stderr, "N/A\n");
1.1.1.6 ! root 582:
! 583: Disasm(stderr, pc, &nextpc, 1);
1.1 root 584: }
585:
586: static const struct {
1.1.1.2 root 587: /* if overlaps with other functionality, list only for lock command */
1.1 root 588: bool lock;
589: const char *name;
590: void (*func)(Uint32 arg);
591: /* convert args in argv into single Uint32 for func */
592: Uint32 (*args)(int argc, char *argv[]);
593: const char *info;
594: } infotable[] = {
1.1.1.2 root 595: { false,"aes", AES_Info, NULL, "Show AES vector contents (with <value>, show opcodes)" },
1.1.1.6 ! root 596: { false,"basepage", DebugInfo_Basepage, NULL, "Show program basepage contents at given <address>" },
1.1.1.4 root 597: { false,"bios", Bios_Info, NULL, "Show BIOS opcodes" },
1.1.1.6 ! root 598: { false,"blitter", Blitter_Info, NULL, "Show Blitter register contents" },
1.1.1.2 root 599: { false,"cookiejar", DebugInfo_Cookiejar, NULL, "Show TOS Cookiejar contents" },
1.1.1.6 ! root 600: { false,"crossbar", Crossbar_Info, NULL, "Show Falcon Crossbar register contents" },
1.1 root 601: { true, "default", DebugInfo_Default, NULL, "Show default debugger entry information" },
602: { true, "disasm", DebugInfo_CpuDisAsm, NULL, "Disasm CPU from PC or given <address>" },
603: #if ENABLE_DSP_EMU
1.1.1.5 root 604: { false, "dsp", DSP_Info, NULL, "Show misc. DSP core info (stack etc)" },
1.1 root 605: { true, "dspdisasm", DebugInfo_DspDisAsm, NULL, "Disasm DSP from given <address>" },
606: { true, "dspmemdump",DebugInfo_DspMemDump, DebugInfo_DspMemArgs, "Dump DSP memory from given <space> <address>" },
1.1.1.6 ! root 607: { true, "dspregs", DebugInfo_DspRegister,NULL, "Show DSP register contents" },
1.1 root 608: #endif
1.1.1.2 root 609: { true, "file", DebugInfo_FileParse, DebugInfo_FileArgs, "Parse commands from given debugger input <file>" },
1.1.1.6 ! root 610: { false,"gemdos", GemDOS_Info, NULL, "Show GEMDOS HDD emu information (with <value>, show opcodes)" },
1.1.1.3 root 611: { true, "history", History_Show, NULL, "Show history of last <count> instructions" },
1.1 root 612: { true, "memdump", DebugInfo_CpuMemDump, NULL, "Dump CPU memory from given <address>" },
1.1.1.6 ! root 613: { false,"osheader", DebugInfo_OSHeader, NULL, "Show TOS OS header contents" },
1.1 root 614: { true, "regaddr", DebugInfo_RegAddr, DebugInfo_RegAddrArgs, "Show <disasm|memdump> from CPU/DSP address pointed by <register>" },
1.1.1.6 ! root 615: { true, "registers", DebugInfo_CpuRegister,NULL, "Show CPU register contents" },
1.1.1.2 root 616: { false,"vdi", VDI_Info, NULL, "Show VDI vector contents (with <value>, show opcodes)" },
1.1.1.6 ! root 617: { false,"videl", Videl_Info, NULL, "Show Falcon Videl register contents" },
! 618: { false,"video", Video_Info, NULL, "Show Video information" },
! 619: { false,"xbios", XBios_Info, NULL, "Show XBIOS opcodes" },
! 620: { false,"ym", PSG_Info, NULL, "Show YM-2149 register contents" },
1.1 root 621: };
622:
1.1.1.5 root 623: static int LockedFunction = 6; /* index for the "default" function */
1.1 root 624: static Uint32 LockedArgument;
625:
626: /**
627: * Show selected debugger session information
628: * (when debugger is (again) entered)
629: */
630: void DebugInfo_ShowSessionInfo(void)
631: {
632: infotable[LockedFunction].func(LockedArgument);
633: }
634:
635:
636: /**
637: * Readline match callback for info subcommand name completion.
638: * STATE = 0 -> different text from previous one.
639: * Return next match or NULL if no matches.
640: */
641: static char *DebugInfo_Match(const char *text, int state, bool lock)
642: {
643: static int i, len;
644: const char *name;
645:
646: if (!state) {
647: /* first match */
648: len = strlen(text);
649: i = 0;
650: }
651: /* next match */
652: while (i++ < ARRAYSIZE(infotable)) {
653: if (!lock && infotable[i-1].lock) {
654: continue;
655: }
656: name = infotable[i-1].name;
657: if (strncmp(name, text, len) == 0)
658: return (strdup(name));
659: }
660: return NULL;
661: }
662: char *DebugInfo_MatchLock(const char *text, int state)
663: {
664: return DebugInfo_Match(text, state, true);
665: }
666: char *DebugInfo_MatchInfo(const char *text, int state)
667: {
668: return DebugInfo_Match(text, state, false);
669: }
670:
671:
672: /**
673: * Show requested command information.
674: */
675: int DebugInfo_Command(int nArgc, char *psArgs[])
676: {
677: Uint32 value;
678: const char *cmd;
679: bool ok, lock;
680: int i, sub;
681:
682: sub = -1;
683: if (nArgc > 1) {
684: cmd = psArgs[1];
685: /* which subcommand? */
686: for (i = 0; i < ARRAYSIZE(infotable); i++) {
687: if (strcmp(cmd, infotable[i].name) == 0) {
688: sub = i;
689: break;
690: }
691: }
692: }
693:
1.1.1.5 root 694: if (sub >= 0 && infotable[sub].args) {
1.1 root 695: /* value needs callback specific conversion */
696: value = infotable[sub].args(nArgc-2, psArgs+2);
697: ok = !!value;
698: } else {
699: if (nArgc > 2) {
700: /* value is normal number */
701: ok = Eval_Number(psArgs[2], &value);
702: } else {
703: value = 0;
704: ok = true;
705: }
706: }
707:
708: lock = (strcmp(psArgs[0], "lock") == 0);
709:
710: if (sub < 0 || !ok) {
711: /* no subcommand or something wrong with value, show info */
712: fprintf(stderr, "%s subcommands are:\n", psArgs[0]);
713: for (i = 0; i < ARRAYSIZE(infotable); i++) {
714: if (!lock && infotable[i].lock) {
715: continue;
716: }
717: fprintf(stderr, "- %s: %s\n",
718: infotable[i].name, infotable[i].info);
719: }
720: return DEBUGGER_CMDDONE;
721: }
722:
723: if (lock) {
724: /* lock given subcommand and value */
725: LockedFunction = sub;
726: LockedArgument = value;
727: fprintf(stderr, "Locked %s output.\n", psArgs[1]);
728: } else {
729: /* do actual work */
730: infotable[sub].func(value);
731: }
732: return DEBUGGER_CMDDONE;
733: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.