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