|
|
1.1 root 1: /*
2: Hatari
3:
4: debugui.c - this is the code for the mini-debugger, when the pause button is pressed,
5: the emulator is (hopefully) halted and this little CLI can be used (in the terminal
6: box) for debugging tasks like memory and register dumps
7:
8: (Personal note: Writing this reminded me how much I dislike writing syntax parsers,
9: especially with languages with weak string-handling, like C. Also,
10: please have oversight with any ugly code: This was written at 4 a.m. /Sven )
11: */
12:
13: #include <ctype.h>
14:
15: #include "main.h"
16: #include "configuration.h"
17: #include "decode.h"
18: #include "gemdos.h"
19: #include "intercept.h"
20: #include "reset.h"
21: #include "m68000.h"
22: #include "memorySnapShot.h"
23: #include "screen.h"
24: #include "sound.h"
25: #include "timer.h"
26: #include "tos.h"
27: #include "video.h"
28:
29: #include "uae-cpu/hatari-glue.h"
30:
31:
32: #define DEBUG_QUIT 0
33: #define DEBUG_CMD 1
34:
35: #define MEMDUMP_COLS 16 /* memdump, number of bytes per row */
36: #define MEMDUMP_ROWS 4 /* memdump, number of rows */
37: #define DISASM_INSTS 5 /* disasm - number of instructions */
38:
39: BOOL bMemDump; /* has memdump been called? */
40: unsigned long memdump_addr; /* memdump address */
41: unsigned long disasm_addr; /* disasm address */
42:
43: /* convert string to lowercase */
44: void string_tolower(char *str)
45: {
46: int i=0;
47: while(str[i] != '\0'){
48: if(isupper(str[i])) str[i] = tolower(str[i]);
49: i++;
50: }
51: }
52:
53: /* truncate string at first unprintable char (e.g. newline) */
54: void string_trunc(char *str){
55: int i=0;
56: while(str[i] != '\0'){
57: if(!isprint(str[i])) str[i] = '\0';
58: i++;
59: }
60: }
61:
62: /* check if string is valid hex number. */
63: BOOL isHex(char *str)
64: {
65: int i=0;
66: while(str[i] != '\0' && str[i] != ' '){
67: if(!isxdigit(str[i]))return(FALSE);
68: i++;
69: }
70: return(TRUE);
71: }
72:
73: /*-----------------------------------------------------------------------*/
74: /*
75: Load a binary file to a memory address.
76: */
77: void DebugUI_LoadBin(char *args){
78: FILE *fp;
79: unsigned char c;
80: char dummy[100];
81: char filename[200];
82: unsigned long address;
83: int i=0;
84:
85: if(sscanf(args, "%s%s%lx", dummy, filename, &address) != 3){
86: fprintf(stderr, "Invalid arguments!\n");
87: return;
88: }
89: address &= 0x00FFFFFF;
90: if((fp = fopen(filename, "rb")) == NULL){
91: fprintf(stderr,"Cannot open file!\n");
92: }
93:
94: c = fgetc(fp);
95: while(!feof(fp)){
96: i++;
97: STMemory_WriteByte(address++, c);
98: c = fgetc(fp);
99: }
100: fprintf(stderr," Read 0x%x bytes.\n", i);
101: fclose(fp);
102: }
103:
104: /*-----------------------------------------------------------------------*/
105: /*
106: Dump memory from an address to a binary file.
107: */
108: void DebugUI_SaveBin(char *args){
109: FILE *fp;
110: unsigned char c;
111: char filename[200];
112: char dummy[100];
113: unsigned long address;
114: unsigned long bytes;
115: int i=0;
116:
117: if(sscanf(args, "%s%s%lx%lx", dummy, filename, &address, &bytes) != 4){
118: fprintf(stderr, " Invalid arguments!");
119: return;
120: }
121: address &= 0x00FFFFFF;
122: if((fp = fopen(filename, "wb")) == NULL){
123: fprintf(stderr," Cannot open file!\n");
124: }
125:
126: while(i < bytes){
127: c = STMemory_ReadByte(address++);
128: fputc(c, fp);
129: i++;
130: }
131: fclose(fp);
132: fprintf(stderr, " Wrote 0x%x bytes.\n", bytes);
133: }
134:
135: /*-----------------------------------------------------------------------*/
136: /*
137: Do a register dump.
138: */
139: void DebugUI_RegDump()
140: {
141: int i;
142:
143: fprintf(stderr, "D0 = $%8.8lx\tA0 = $%8.8lx\n", Regs[REG_D0], Regs[REG_A0]);
144: fprintf(stderr, "D1 = $%8.8lx\tA1 = $%8.8lx\n", Regs[REG_D1], Regs[REG_A1]);
145: fprintf(stderr, "D2 = $%8.8lx\tA2 = $%8.8lx\n", Regs[REG_D2], Regs[REG_A2]);
146: fprintf(stderr, "D3 = $%8.8lx\tA3 = $%8.8lx\n", Regs[REG_D3], Regs[REG_A3]);
147: fprintf(stderr, "D4 = $%8.8lx\tA4 = $%8.8lx\n", Regs[REG_D4], Regs[REG_A4]);
148: fprintf(stderr, "D5 = $%8.8lx\tA5 = $%8.8lx\n", Regs[REG_D5], Regs[REG_A5]);
149: fprintf(stderr, "D6 = $%8.8lx\tA6 = $%8.8lx\n", Regs[REG_D6], Regs[REG_A6]);
150: fprintf(stderr, "D7 = $%8.8lx\tA7 = $%8.8lx\n", Regs[REG_D7], Regs[REG_A7]);
151: fprintf(stderr, "PC = $%8.8lx\tSR = %%", m68k_getpc());
152: /* Rather obfuscated way of printing SR in binary */
153: for(i=0;i<8;i++)fprintf(stderr, "%i", (SR & (1 << (15-i)))?1:0);
154: fprintf(stderr," "); /* space between bytes */
155: for(i=8;i<16;i++)fprintf(stderr, "%i", (SR & (1 << (15-i)))?1:0);
156: fprintf(stderr,"\n");
157: }
158:
159:
160: /*-----------------------------------------------------------------------*/
161: /*
162: Dissassemble - arg = starting address, or PC.
163: */
164: void DebugUI_DisAsm(char *arg, BOOL cont)
165: {
166: int i;
167: uaecptr nextpc;
168:
169: if(cont != TRUE){
170: if(!isHex(arg)) {
171: fprintf(stderr,"Invalid address!\n");
172: return;
173: }
174: i = sscanf(arg, "%lx", &disasm_addr);
175:
176: if(i == 0){
177: fprintf(stderr,"Invalid address!\n");
178: return;
179: }
180: } else
181: if(!disasm_addr) disasm_addr = m68k_getpc();
182:
183: disasm_addr &= 0x00FFFFFF;
184:
185: m68k_disasm(stderr, (uaecptr)disasm_addr, &nextpc, 5);
186: disasm_addr = nextpc;
187: }
188:
189: /*-----------------------------------------------------------------------*/
190: /*
191: Do a memory dump, args = starting address.
192: */
193: void DebugUI_MemDump(char *arg, BOOL cont)
194: {
195: int i,j;
196:
197: if(cont != TRUE){
198: if(!isHex(arg)) {
199: bMemDump = FALSE;
200: fprintf(stderr,"Invalid address!\n");
201: return;
202: }
203: i = sscanf(arg, "%lx", &memdump_addr);
204:
205: if(i == 0){
206: bMemDump = FALSE;
207: fprintf(stderr,"Invalid address!\n");
208: return;
209: }
210: }
211:
212: memdump_addr &= 0x00FFFFFF;
213: bMemDump = TRUE;
214:
215: fprintf(stderr, "%6.6X: ", memdump_addr);
216: for(j=0;j<MEMDUMP_ROWS-1;j++){
217: for(i=0;i<MEMDUMP_COLS;i++)
218: fprintf(stderr, "%2.2x ",STMemory_ReadByte(memdump_addr++));
219: fprintf(stderr, "\n%6.6X: ", memdump_addr);
220: }
221: for(i=0;i<MEMDUMP_COLS;i++)
222: fprintf(stderr, "%2.2x ",STMemory_ReadByte(memdump_addr++));
223: fprintf(stderr,"\n");
224: }
225:
226: /*-----------------------------------------------------------------------*/
227: /*
228: Do a memory write, arg = starting address, followed by bytes.
229: */
230: void DebugUI_MemWrite(char *addr_str, char *arg)
231: {
232: int i, j, numBytes;
233: long write_addr;
234: unsigned char bytes[300]; /* store bytes */
235: char temp[15];
236: int d;
237:
238: numBytes = 0;
239: i = 0;
240:
241: string_trunc(arg);
242: while(arg[i] == ' ')i++; /* skip spaces */
243: while(arg[i] != ' ')i++; /* skip command */
244: while(arg[i] == ' ')i++; /* skip spaces */
245:
246: j = 0;
247: while(isxdigit(arg[i]) && j < 14) /* get address */
248: temp[j++] = arg[i++];
249: temp[j] = '\0';
250: j = sscanf(temp, "%x", &write_addr);
251:
252: /* if next char is not valid, or it's not a valid address */
253: if((arg[i] != '\0' && arg[i] != ' ') || (j == 0)){
254: fprintf(stderr, "Bad address!\n");
255: return;
256: }
257:
258: write_addr &= 0x00FFFFFF;
259:
260: while(arg[i] == ' ')i++; /* skip spaces */
261:
262: /* get bytes data */
263: while(arg[i] != '\0'){
264: j = 0;
265: while(isxdigit(arg[i]) && j < 14) /* get byte */
266: temp[j++] = arg[i++];
267: temp[j] = '\0';
268:
269: /* if next char is not a null or a space - it's not valid. */
270: if(arg[i] != '\0' && arg[i] != ' '){
271: fprintf(stderr, "Bad byte argument: %c\n", arg[i]);
272: return;
273: }
274:
275: if(temp[0] != '\0')
276: if(sscanf(temp,"%x", &d) != 1){
277: fprintf(stderr, "Bad byte argument!\n");
278: return;
279: }
280:
281: bytes[numBytes] = (d&0x0FF);
282: numBytes++;
283: while(arg[i] == ' ')i++; /* skip any spaces */
284: }
285:
286: /* write the data */
287: for(i=0;i<numBytes;i++)
288: STMemory_WriteByte(write_addr + i, bytes[i]);
289: }
290:
291: /*-----------------------------------------------------------------------*/
292: /*
293: Help!
294: */
295: void DebugUI_Help()
296: {
297: fprintf(stderr,"---- debug mode commands ----\n");
298: fprintf(stderr," d [address]- disassemble from PC, or given address. \n");
299: fprintf(stderr," r - dump register values \n");
300: fprintf(stderr," m [address] - dump memory at address, \n\tm alone continues from previous address.\n");
301: fprintf(stderr," w address bytes - write bytes to a memory address, bytes are space separated. \n");
302: fprintf(stderr," l filename address - load a file into memory starting at address. \n");
303: fprintf(stderr," s filename address length - dump length bytes from memory to a file. \n");
304: fprintf(stderr," q - return to emulation\n");
305: fprintf(stderr,"-----------------------------\n");
306: fprintf(stderr,"\n");
307: }
308:
309: /*-----------------------------------------------------------------------*/
310: /*
311: Get a UI command, return it.
312: */
313: int DebugUI_Getcommand()
314: {
315: char temp[255];
316: char command[255], arg[255];
317: int i;
318: fprintf(stderr,"> ");
319: temp[0] = '\0';
320: fgets(temp, 255, stdin);
321:
322: i = sscanf(temp, "%s%s", command, arg);
323: string_tolower(command);
324:
325: if(i == 0){
326: fprintf(stderr," Unknown command.\n");
327: return(DEBUG_CMD);
328: }
329:
330: switch(command[0]){
331: case 'q':
332: return(DEBUG_QUIT);
333: break;
334:
335: case 'h':
336: case '?':
337: DebugUI_Help(); /* get help */
338: return(DEBUG_CMD);
339: break;
340:
341: case 'd':
342: if(i < 2) /* no arg? */
343: DebugUI_DisAsm(arg, TRUE); /* No arg - disassemble at PC */
344: else DebugUI_DisAsm(arg, FALSE); /* disasm at address. */
345: break;
346:
347: case 'm':
348: if(i < 2){ /* no arg? */
349: if(bMemDump == FALSE){
350: fprintf(stderr," Usage: m address\n");
351: return(DEBUG_CMD);
352: }
353: DebugUI_MemDump(arg, TRUE); /* No arg - continue memdump */
354: } else DebugUI_MemDump(arg, FALSE); /* new memdump */
355: break;
356:
357: case 'w':
358: if(i < 2){ /* no arg? */
359: fprintf(stderr," Usage: w address bytes\n");
360: return(DEBUG_CMD);
361: }
362: DebugUI_MemWrite(arg, temp);
363: break;
364:
365: case 'r':
366: DebugUI_RegDump();
367: break;
368:
369: case 'l':
370: if(i < 2){ /* no arg? */
371: fprintf(stderr," Usage: l filename address\n");
372: return(DEBUG_CMD);
373: }
374: DebugUI_LoadBin(temp);
375: break;
376:
377: case 's':
378: if(i < 2){ /* no arg? */
379: fprintf(stderr," Usage: s filename address bytes\n");
380: return(DEBUG_CMD);
381: }
382: DebugUI_SaveBin(temp);
383: break;
384:
385: default:
386: fprintf(stderr," Unknown command: '%s'\n", command);
387: break;
388: }
389:
390: return(DEBUG_CMD);
391: }
392:
393:
394: /*-----------------------------------------------------------------------*/
395: /*
396: Debug UI
397: */
398: void DebugUI()
399: {
400: bMemDump = FALSE;
401: disasm_addr = 0;
402: fprintf(stderr,"\nYou have entered debug mode. Type q to quit, h for help. \n------------------------------\n");
403: while(DebugUI_Getcommand() != DEBUG_QUIT);
404: fprintf(stderr,"Returning to emulation...\n------------------------------\n\n");
405: }
406:
407:
408:
409:
410:
411:
412:
413:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.