|
|
1.1 root 1: /*
2: Hatari - debuginfo.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
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>
14: #include "main.h"
15: #include "configuration.h"
16: #include "debugInfo.h"
17: #include "debugcpu.h"
18: #include "debugui.h"
19: #include "evaluate.h"
1.1.1.2 ! root 20: #include "file.h"
1.1 root 21: #include "ioMem.h"
22: #include "m68000.h"
23: #include "nextMemory.h"
1.1.1.2 ! root 24: #include "screen.h"
1.1 root 25: #include "video.h"
26:
27:
28: /* ------------------------------------------------------------------
29: * TOS information
30: */
31: #define OS_SYSBASE 0x4F2
32: #define OS_HEADER_SIZE 0x30
33:
34: #define COOKIE_JAR 0x5A0
35:
36: #define BASEPAGE_SIZE 0x100
37:
38: #define GEM_MAGIC 0x87654321
39: #define GEM_MUPB_SIZE 0xC
40:
41: #define RESET_MAGIC 0x31415926
42: #define RESET_VALID 0x426
43: #define RESET_VECTOR 0x42A
44:
45: #define COUNTRY_SPAIN 4
46:
47: /**
48: * DebugInfo_GetSysbase: set osversion to given argument.
49: * return sysbase address on success and zero on failure.
50: */
51: static Uint32 DebugInfo_GetSysbase(Uint16 *osversion)
52: {
53: return 00;
54: }
55:
56: /**
57: * DebugInfo_CurrentBasepage: get currently running TOS program basepage
58: */
59: static Uint32 DebugInfo_CurrentBasepage(void)
60: {
61: return 0;
62: }
63:
64: /**
1.1.1.2 ! root 65: * GetSegmentAddress: return segment address at given offset in
! 66: * TOS process basepage or zero if that is missing/invalid.
! 67: */
! 68: static Uint32 GetSegmentAddress(unsigned offset)
! 69: {
! 70: Uint32 basepage = DebugInfo_CurrentBasepage();
! 71: if (!basepage) {
! 72: return 0;
! 73: }
! 74: if (!NEXTMemory_ValidArea(basepage, BASEPAGE_SIZE) ||
! 75: NEXTMemory_ReadLong(basepage) != basepage) {
! 76: fprintf(stderr, "Basepage address 0x%06x is invalid!\n", basepage);
! 77: return 0;
! 78: }
! 79: return NEXTMemory_ReadLong(basepage+offset);
! 80: }
! 81:
! 82: /**
! 83: * DebugInfo_GetTEXT: return current program TEXT segment address
! 84: * or zero if basepage missing/invalid. For virtual debugger variable.
! 85: */
! 86: Uint32 DebugInfo_GetTEXT(void)
! 87: {
! 88: return GetSegmentAddress(0x08);
! 89: }
! 90: /**
! 91: * DebugInfo_GetDATA: return current program DATA segment address
! 92: * or zero if basepage missing/invalid. For virtual debugger variable.
! 93: */
! 94: Uint32 DebugInfo_GetDATA(void)
! 95: {
! 96: return GetSegmentAddress(0x010);
! 97: }
! 98: /**
! 99: * DebugInfo_GetBSS: return current program BSS segment address
! 100: * or zero if basepage missing/invalid. For virtual debugger variable.
! 101: */
! 102: Uint32 DebugInfo_GetBSS(void)
! 103: {
! 104: return GetSegmentAddress(0x18);
! 105: }
! 106:
! 107: /**
1.1 root 108: * DebugInfo_Basepage: show TOS process basepage information
109: * at given address.
110: */
111: static void DebugInfo_Basepage(Uint32 basepage)
112: {
113: }
114:
115: /**
116: * DebugInfo_OSHeader: display TOS OS Header
117: */
118: static void DebugInfo_OSHeader(Uint32 dummy)
119: {
120: }
121:
122:
123: /* ------------------------------------------------------------------
124: * Next HW information
125: */
126:
127: /**
128: * DebugInfo_Rtc : display the Videl registers values.
129: */
130: static void DebugInfo_Rtc(Uint32 dummy)
131: {
132: Screen_Draw();
133: fprintf(stdout,"%s",get_rtc_ram_info());
134: }
135:
136: /**
137: * DebugInfo_Crossbar : display the Crossbar registers values.
138: */
139: static void DebugInfo_Crossbar(Uint32 dummy)
140: {
141: }
142:
143:
144: /* ------------------------------------------------------------------
145: * CPU and DSP information wrappers
146: */
147:
148: /**
149: * Helper to call debugcpu.c and debugdsp.c debugger commands
150: */
151: static void DebugInfo_CallCommand(int (*func)(int, char* []), const char *command, Uint32 arg)
152: {
153: char cmdbuffer[16], argbuffer[12];
154: char *argv[] = { cmdbuffer, NULL };
155: int argc = 1;
156:
157: assert(strlen(command) < sizeof(cmdbuffer));
158: strcpy(cmdbuffer, command);
159: if (arg) {
160: sprintf(argbuffer, "$%x", arg);
161: argv[argc++] = argbuffer;
162: }
163: func(argc, argv);
164: }
165:
166: static void DebugInfo_CpuRegister(Uint32 arg)
167: {
168: DebugInfo_CallCommand(DebugCpu_Register, "register", arg);
169: }
170: static void DebugInfo_CpuDisAsm(Uint32 arg)
171: {
172: DebugInfo_CallCommand(DebugCpu_DisAsm, "disasm", arg);
173: }
174: static void DebugInfo_CpuMemDump(Uint32 arg)
175: {
176: DebugInfo_CallCommand(DebugCpu_MemDump, "memdump", arg);
177: }
178:
179: #if ENABLE_DSP_EMU
180:
181: static void DebugInfo_DspRegister(Uint32 arg)
182: {
183: }
184: static void DebugInfo_DspDisAsm(Uint32 arg)
185: {
186: }
187:
188: static void DebugInfo_DspMemDump(Uint32 arg)
189: {
190: }
191:
192: /**
193: * Convert arguments to Uint32 arg suitable for DSP memdump callback
194: */
195: static Uint32 DebugInfo_DspMemArgs(int argc, char *argv[])
196: {
197: Uint32 value;
198: char space;
199: if (argc != 2) {
200: return 0;
201: }
202: space = toupper(argv[0][0]);
203: if ((space != 'X' && space != 'Y' && space != 'P') || argv[0][1]) {
204: fprintf(stderr, "ERROR: invalid DSP address space '%s'!\n", argv[0]);
205: return 0;
206: }
207: if (!Eval_Number(argv[1], &value) || value > 0xffff) {
208: fprintf(stderr, "ERROR: invalid DSP address '%s'!\n", argv[1]);
209: return 0;
210: }
211: return ((Uint32)space<<16) | value;
212: }
213:
214: #endif /* ENABLE_DSP_EMU */
215:
216:
217: static void DebugInfo_RegAddr(Uint32 arg)
218: {
219: }
220:
221: /**
222: * Convert arguments to Uint32 arg suitable for RegAddr callback
223: */
224: static Uint32 DebugInfo_RegAddrArgs(int argc, char *argv[])
225: {
226: Uint32 value, *regaddr;
227: if (argc != 2) {
228: return 0;
229: }
230:
231: if (strcmp(argv[0], "disasm") == 0) {
232: value = 'D';
233: } else if (strcmp(argv[0], "memdump") == 0) {
234: value = 'M';
235: } else {
236: fprintf(stderr, "ERROR: regaddr operation can be only 'disasm' or 'memdump', not '%s'!\n", argv[0]);
237: return 0;
238: }
239:
240: if (strlen(argv[1]) != 2 ||
241: (!DebugCpu_GetRegisterAddress(argv[1], ®addr) &&
242: (toupper(argv[1][0]) != 'R' || !isdigit(argv[1][1]) || argv[1][2]))) {
243: /* not CPU register or Rx DSP register */
244: fprintf(stderr, "ERROR: invalid address/data register '%s'!\n", argv[1]);
245: return 0;
246: }
247:
248: value |= argv[1][0] << 24;
249: value |= argv[1][1] << 16;
250: value &= 0xffff00ff;
251: return value;
252: }
253:
254:
255: /* ------------------------------------------------------------------
1.1.1.2 ! root 256: * wrappers for command to parse debugger input file
! 257: */
! 258:
! 259: /* file name to be given before calling the Parse function,
! 260: * needs to be set separately as it's a host pointer which
! 261: * can be 64-bit i.e. may not fit into Uint32.
! 262: */
! 263: static char *parse_filename;
! 264:
! 265: /**
! 266: * Parse and exec commands in the previously given debugger input file
! 267: */
! 268: static void DebugInfo_FileParse(Uint32 dummy)
! 269: {
! 270: if (parse_filename) {
! 271: DebugUI_ParseFile(parse_filename);
! 272: } else {
! 273: fputs("ERROR: debugger input file name to parse isn't set!\n", stderr);
! 274: }
! 275: }
! 276:
! 277: /**
! 278: * Set which input file to parse.
! 279: * Return true if file exists, false on error
! 280: */
! 281: static Uint32 DebugInfo_FileArgs(int argc, char *argv[])
! 282: {
! 283: if (argc != 1) {
! 284: return false;
! 285: }
! 286: if (!File_Exists(argv[0])) {
! 287: fprintf(stderr, "ERROR: given file '%s' doesn't exist!\n", argv[0]);
! 288: return false;
! 289: }
! 290: if (parse_filename) {
! 291: free(parse_filename);
! 292: }
! 293: parse_filename = strdup(argv[0]);
! 294: return true;
! 295: }
! 296:
! 297: /* ------------------------------------------------------------------
1.1 root 298: * Debugger & readline TAB completion integration
299: */
300:
301: /**
302: * Default information on entering the debugger
303: */
304: static void DebugInfo_Default(Uint32 dummy)
305: {
306: int hbl, fcycles, lcycles;
307: Video_GetPosition(&fcycles, &hbl, &lcycles);
308: fprintf(stderr, "\nCPU=$%x, VBL=%d, FrameCycles=%d, HBL=%d, LineCycles=%d, DSP=",
309: M68000_GetPC(), 0, fcycles, hbl, lcycles);
310: fprintf(stderr, "N/A\n");
311: }
312:
313: static const struct {
1.1.1.2 ! root 314: /* if overlaps with other functionality, list only for lock command */
1.1 root 315: bool lock;
316: const char *name;
317: void (*func)(Uint32 arg);
318: /* convert args in argv into single Uint32 for func */
319: Uint32 (*args)(int argc, char *argv[]);
320: const char *info;
321: } infotable[] = {
1.1.1.2 ! root 322: // { false,"aes", AES_Info, NULL, "Show AES vector contents (with <value>, show opcodes)" },
1.1 root 323: { false,"basepage", DebugInfo_Basepage, NULL, "Show program basepage info at given <address>" },
1.1.1.2 ! root 324: // { false,"cookiejar", DebugInfo_Cookiejar, NULL, "Show TOS Cookiejar contents" },
1.1 root 325: { false,"crossbar", DebugInfo_Crossbar, NULL, "Show Falcon crossbar HW register values" },
326: { true, "default", DebugInfo_Default, NULL, "Show default debugger entry information" },
327: { true, "disasm", DebugInfo_CpuDisAsm, NULL, "Disasm CPU from PC or given <address>" },
328: #if ENABLE_DSP_EMU
329: { true, "dspdisasm", DebugInfo_DspDisAsm, NULL, "Disasm DSP from given <address>" },
330: { true, "dspmemdump",DebugInfo_DspMemDump, DebugInfo_DspMemArgs, "Dump DSP memory from given <space> <address>" },
1.1.1.2 ! root 331: { true, "dspregs", DebugInfo_DspRegister,NULL, "Show DSP registers values" },
1.1 root 332: #endif
1.1.1.2 ! root 333: { true, "file", DebugInfo_FileParse, DebugInfo_FileArgs, "Parse commands from given debugger input <file>" },
! 334: // { false,"gemdos", GemDOS_Info, NULL, "Show GEMDOS HDD emu info (with <value>, show opcodes)" },
1.1 root 335: { true, "memdump", DebugInfo_CpuMemDump, NULL, "Dump CPU memory from given <address>" },
336: { false,"osheader", DebugInfo_OSHeader, NULL, "Show TOS OS header information" },
337: { true, "regaddr", DebugInfo_RegAddr, DebugInfo_RegAddrArgs, "Show <disasm|memdump> from CPU/DSP address pointed by <register>" },
1.1.1.2 ! root 338: { true, "registers", DebugInfo_CpuRegister,NULL, "Show CPU registers values" },
! 339: // { false,"video", DebugInfo_Video, NULL, "Show Video related values" },
1.1 root 340: { false,"rtc", DebugInfo_Rtc, NULL, "Show Next's RTC registers" }
341: };
342:
1.1.1.2 ! root 343: static int LockedFunction = 4; /* index for the "default" function */
1.1 root 344: static Uint32 LockedArgument;
345:
346: /**
347: * Show selected debugger session information
348: * (when debugger is (again) entered)
349: */
350: void DebugInfo_ShowSessionInfo(void)
351: {
352: infotable[LockedFunction].func(LockedArgument);
353: }
354:
355:
356: /**
357: * Readline match callback for info subcommand name completion.
358: * STATE = 0 -> different text from previous one.
359: * Return next match or NULL if no matches.
360: */
361: static char *DebugInfo_Match(const char *text, int state, bool lock)
362: {
363: static int i, len;
364: const char *name;
365:
366: if (!state) {
367: /* first match */
368: len = strlen(text);
369: i = 0;
370: }
371: /* next match */
372: while (i++ < ARRAYSIZE(infotable)) {
373: if (!lock && infotable[i-1].lock) {
374: continue;
375: }
376: name = infotable[i-1].name;
377: if (strncmp(name, text, len) == 0)
378: return (strdup(name));
379: }
380: return NULL;
381: }
382: char *DebugInfo_MatchLock(const char *text, int state)
383: {
384: return DebugInfo_Match(text, state, true);
385: }
386: char *DebugInfo_MatchInfo(const char *text, int state)
387: {
388: return DebugInfo_Match(text, state, false);
389: }
390:
391:
392: /**
393: * Show requested command information.
394: */
395: int DebugInfo_Command(int nArgc, char *psArgs[])
396: {
397: Uint32 value;
398: const char *cmd;
399: bool ok, lock;
400: int i, sub;
401:
402: sub = -1;
403: if (nArgc > 1) {
404: cmd = psArgs[1];
405: /* which subcommand? */
406: for (i = 0; i < ARRAYSIZE(infotable); i++) {
407: if (strcmp(cmd, infotable[i].name) == 0) {
408: sub = i;
409: break;
410: }
411: }
412: }
413:
414: if (infotable[sub].args) {
415: /* value needs callback specific conversion */
416: value = infotable[sub].args(nArgc-2, psArgs+2);
417: ok = !!value;
418: } else {
419: if (nArgc > 2) {
420: /* value is normal number */
421: ok = Eval_Number(psArgs[2], &value);
422: } else {
423: value = 0;
424: ok = true;
425: }
426: }
427:
428: lock = (strcmp(psArgs[0], "lock") == 0);
429:
430: if (sub < 0 || !ok) {
431: /* no subcommand or something wrong with value, show info */
432: fprintf(stderr, "%s subcommands are:\n", psArgs[0]);
433: for (i = 0; i < ARRAYSIZE(infotable); i++) {
434: if (!lock && infotable[i].lock) {
435: continue;
436: }
437: fprintf(stderr, "- %s: %s\n",
438: infotable[i].name, infotable[i].info);
439: }
440: return DEBUGGER_CMDDONE;
441: }
442:
443: if (lock) {
444: /* lock given subcommand and value */
445: LockedFunction = sub;
446: LockedArgument = value;
447: fprintf(stderr, "Locked %s output.\n", psArgs[1]);
448: } else {
449: /* do actual work */
450: infotable[sub].func(value);
451: }
452: return DEBUGGER_CMDDONE;
453: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.