|
|
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>
1.1.1.3 ! root 14: #include <ctype.h>
1.1 root 15: #include "main.h"
16: #include "configuration.h"
17: #include "debugInfo.h"
18: #include "debugcpu.h"
19: #include "debugui.h"
20: #include "evaluate.h"
1.1.1.2 root 21: #include "file.h"
1.1 root 22: #include "ioMem.h"
23: #include "m68000.h"
24: #include "nextMemory.h"
1.1.1.2 root 25: #include "screen.h"
1.1 root 26: #include "video.h"
27:
28: /* ------------------------------------------------------------------
29: * Next HW information
30: */
31:
1.1.1.3 ! root 32: char* get_rtc_ram_info(void);
! 33:
1.1 root 34: /**
35: * DebugInfo_Rtc : display the Videl registers values.
36: */
1.1.1.3 ! root 37: static void DebugInfo_Rtc(Uint32 dummy) {
! 38: Update_StatusBar();
1.1 root 39: fprintf(stdout,"%s",get_rtc_ram_info());
40: }
41:
42: /* ------------------------------------------------------------------
43: * CPU and DSP information wrappers
44: */
45:
46: /**
47: * Helper to call debugcpu.c and debugdsp.c debugger commands
48: */
49: static void DebugInfo_CallCommand(int (*func)(int, char* []), const char *command, Uint32 arg)
50: {
51: char cmdbuffer[16], argbuffer[12];
52: char *argv[] = { cmdbuffer, NULL };
53: int argc = 1;
54:
55: assert(strlen(command) < sizeof(cmdbuffer));
56: strcpy(cmdbuffer, command);
57: if (arg) {
58: sprintf(argbuffer, "$%x", arg);
59: argv[argc++] = argbuffer;
60: }
61: func(argc, argv);
62: }
63:
64: static void DebugInfo_CpuRegister(Uint32 arg)
65: {
66: DebugInfo_CallCommand(DebugCpu_Register, "register", arg);
67: }
68: static void DebugInfo_CpuDisAsm(Uint32 arg)
69: {
70: DebugInfo_CallCommand(DebugCpu_DisAsm, "disasm", arg);
71: }
72: static void DebugInfo_CpuMemDump(Uint32 arg)
73: {
74: DebugInfo_CallCommand(DebugCpu_MemDump, "memdump", arg);
75: }
76:
77: #if ENABLE_DSP_EMU
78:
79: static void DebugInfo_DspRegister(Uint32 arg)
80: {
81: }
82: static void DebugInfo_DspDisAsm(Uint32 arg)
83: {
84: }
85:
86: static void DebugInfo_DspMemDump(Uint32 arg)
87: {
88: }
89:
90: /**
91: * Convert arguments to Uint32 arg suitable for DSP memdump callback
92: */
93: static Uint32 DebugInfo_DspMemArgs(int argc, char *argv[])
94: {
95: Uint32 value;
96: char space;
97: if (argc != 2) {
98: return 0;
99: }
100: space = toupper(argv[0][0]);
101: if ((space != 'X' && space != 'Y' && space != 'P') || argv[0][1]) {
102: fprintf(stderr, "ERROR: invalid DSP address space '%s'!\n", argv[0]);
103: return 0;
104: }
105: if (!Eval_Number(argv[1], &value) || value > 0xffff) {
106: fprintf(stderr, "ERROR: invalid DSP address '%s'!\n", argv[1]);
107: return 0;
108: }
109: return ((Uint32)space<<16) | value;
110: }
111:
112: #endif /* ENABLE_DSP_EMU */
113:
114:
115: static void DebugInfo_RegAddr(Uint32 arg)
116: {
117: }
118:
119: /**
120: * Convert arguments to Uint32 arg suitable for RegAddr callback
121: */
122: static Uint32 DebugInfo_RegAddrArgs(int argc, char *argv[])
123: {
124: Uint32 value, *regaddr;
125: if (argc != 2) {
126: return 0;
127: }
128:
129: if (strcmp(argv[0], "disasm") == 0) {
130: value = 'D';
131: } else if (strcmp(argv[0], "memdump") == 0) {
132: value = 'M';
133: } else {
134: fprintf(stderr, "ERROR: regaddr operation can be only 'disasm' or 'memdump', not '%s'!\n", argv[0]);
135: return 0;
136: }
137:
138: if (strlen(argv[1]) != 2 ||
139: (!DebugCpu_GetRegisterAddress(argv[1], ®addr) &&
140: (toupper(argv[1][0]) != 'R' || !isdigit(argv[1][1]) || argv[1][2]))) {
141: /* not CPU register or Rx DSP register */
142: fprintf(stderr, "ERROR: invalid address/data register '%s'!\n", argv[1]);
143: return 0;
144: }
145:
146: value |= argv[1][0] << 24;
147: value |= argv[1][1] << 16;
148: value &= 0xffff00ff;
149: return value;
150: }
151:
152:
153: /* ------------------------------------------------------------------
1.1.1.2 root 154: * wrappers for command to parse debugger input file
155: */
156:
157: /* file name to be given before calling the Parse function,
158: * needs to be set separately as it's a host pointer which
159: * can be 64-bit i.e. may not fit into Uint32.
160: */
161: static char *parse_filename;
162:
163: /**
164: * Parse and exec commands in the previously given debugger input file
165: */
166: static void DebugInfo_FileParse(Uint32 dummy)
167: {
168: if (parse_filename) {
169: DebugUI_ParseFile(parse_filename);
170: } else {
1.1.1.3 ! root 171: // fputs("ERROR: debugger input file name to parse isn't set!\n", stderr);
1.1.1.2 root 172: }
173: }
174:
175: /**
176: * Set which input file to parse.
177: * Return true if file exists, false on error
178: */
179: static Uint32 DebugInfo_FileArgs(int argc, char *argv[])
180: {
181: if (argc != 1) {
182: return false;
183: }
184: if (!File_Exists(argv[0])) {
185: fprintf(stderr, "ERROR: given file '%s' doesn't exist!\n", argv[0]);
186: return false;
187: }
188: if (parse_filename) {
189: free(parse_filename);
190: }
191: parse_filename = strdup(argv[0]);
192: return true;
193: }
194:
195: /* ------------------------------------------------------------------
1.1 root 196: * Debugger & readline TAB completion integration
197: */
198:
199: /**
200: * Default information on entering the debugger
201: */
202: static void DebugInfo_Default(Uint32 dummy)
203: {
1.1.1.3 ! root 204: fprintf(stderr, "\nCPU=$%x, DSP=",
! 205: M68000_GetPC());
1.1 root 206: fprintf(stderr, "N/A\n");
207: }
208:
209: static const struct {
1.1.1.2 root 210: /* if overlaps with other functionality, list only for lock command */
1.1 root 211: bool lock;
212: const char *name;
213: void (*func)(Uint32 arg);
214: /* convert args in argv into single Uint32 for func */
215: Uint32 (*args)(int argc, char *argv[]);
216: const char *info;
217: } infotable[] = {
218: { true, "default", DebugInfo_Default, NULL, "Show default debugger entry information" },
219: { true, "disasm", DebugInfo_CpuDisAsm, NULL, "Disasm CPU from PC or given <address>" },
220: #if ENABLE_DSP_EMU
221: { true, "dspdisasm", DebugInfo_DspDisAsm, NULL, "Disasm DSP from given <address>" },
222: { true, "dspmemdump",DebugInfo_DspMemDump, DebugInfo_DspMemArgs, "Dump DSP memory from given <space> <address>" },
1.1.1.2 root 223: { true, "dspregs", DebugInfo_DspRegister,NULL, "Show DSP registers values" },
1.1 root 224: #endif
1.1.1.2 root 225: { true, "file", DebugInfo_FileParse, DebugInfo_FileArgs, "Parse commands from given debugger input <file>" },
1.1 root 226: { true, "memdump", DebugInfo_CpuMemDump, NULL, "Dump CPU memory from given <address>" },
227: { true, "regaddr", DebugInfo_RegAddr, DebugInfo_RegAddrArgs, "Show <disasm|memdump> from CPU/DSP address pointed by <register>" },
1.1.1.2 root 228: { true, "registers", DebugInfo_CpuRegister,NULL, "Show CPU registers values" },
1.1 root 229: { false,"rtc", DebugInfo_Rtc, NULL, "Show Next's RTC registers" }
230: };
231:
1.1.1.2 root 232: static int LockedFunction = 4; /* index for the "default" function */
1.1 root 233: static Uint32 LockedArgument;
234:
235: /**
236: * Show selected debugger session information
237: * (when debugger is (again) entered)
238: */
239: void DebugInfo_ShowSessionInfo(void)
240: {
241: infotable[LockedFunction].func(LockedArgument);
242: }
243:
244:
245: /**
246: * Readline match callback for info subcommand name completion.
247: * STATE = 0 -> different text from previous one.
248: * Return next match or NULL if no matches.
249: */
250: static char *DebugInfo_Match(const char *text, int state, bool lock)
251: {
252: static int i, len;
253: const char *name;
254:
255: if (!state) {
256: /* first match */
257: len = strlen(text);
258: i = 0;
259: }
260: /* next match */
261: while (i++ < ARRAYSIZE(infotable)) {
262: if (!lock && infotable[i-1].lock) {
263: continue;
264: }
265: name = infotable[i-1].name;
266: if (strncmp(name, text, len) == 0)
267: return (strdup(name));
268: }
269: return NULL;
270: }
271: char *DebugInfo_MatchLock(const char *text, int state)
272: {
273: return DebugInfo_Match(text, state, true);
274: }
275: char *DebugInfo_MatchInfo(const char *text, int state)
276: {
277: return DebugInfo_Match(text, state, false);
278: }
279:
280:
281: /**
282: * Show requested command information.
283: */
284: int DebugInfo_Command(int nArgc, char *psArgs[])
285: {
286: Uint32 value;
287: const char *cmd;
288: bool ok, lock;
289: int i, sub;
290:
291: sub = -1;
292: if (nArgc > 1) {
293: cmd = psArgs[1];
294: /* which subcommand? */
295: for (i = 0; i < ARRAYSIZE(infotable); i++) {
296: if (strcmp(cmd, infotable[i].name) == 0) {
297: sub = i;
298: break;
299: }
300: }
301: }
302:
303: if (infotable[sub].args) {
304: /* value needs callback specific conversion */
305: value = infotable[sub].args(nArgc-2, psArgs+2);
306: ok = !!value;
307: } else {
308: if (nArgc > 2) {
309: /* value is normal number */
310: ok = Eval_Number(psArgs[2], &value);
311: } else {
312: value = 0;
313: ok = true;
314: }
315: }
316:
317: lock = (strcmp(psArgs[0], "lock") == 0);
318:
319: if (sub < 0 || !ok) {
320: /* no subcommand or something wrong with value, show info */
321: fprintf(stderr, "%s subcommands are:\n", psArgs[0]);
322: for (i = 0; i < ARRAYSIZE(infotable); i++) {
323: if (!lock && infotable[i].lock) {
324: continue;
325: }
326: fprintf(stderr, "- %s: %s\n",
327: infotable[i].name, infotable[i].info);
328: }
329: return DEBUGGER_CMDDONE;
330: }
331:
332: if (lock) {
333: /* lock given subcommand and value */
334: LockedFunction = sub;
335: LockedArgument = value;
336: fprintf(stderr, "Locked %s output.\n", psArgs[1]);
337: } else {
338: /* do actual work */
339: infotable[sub].func(value);
340: }
341: return DEBUGGER_CMDDONE;
342: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.