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