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