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