Mercurial > vba-linux
comparison src/sdl/debugger.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. | |
2 // Copyright (C) 1999-2003 Forgotten | |
3 // Copyright (C) 2004 Forgotten and the VBA development team | |
4 | |
5 // This program is free software; you can redistribute it and/or modify | |
6 // it under the terms of the GNU General Public License as published by | |
7 // the Free Software Foundation; either version 2, or(at your option) | |
8 // any later version. | |
9 // | |
10 // This program is distributed in the hope that it will be useful, | |
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 // GNU General Public License for more details. | |
14 // | |
15 // You should have received a copy of the GNU General Public License | |
16 // along with this program; if not, write to the Free Software Foundation, | |
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | |
19 extern "C" { | |
20 #include <stdio.h> | |
21 #include <stdlib.h> | |
22 } // FIXME: should use c++ headers instead | |
23 | |
24 #include <string.h> | |
25 | |
26 #include "Port.h" | |
27 #include "gba/GBA.h" | |
28 #include "gba/GBAGlobals.h" | |
29 #include "gba/GBACheats.h" | |
30 #include "gba/armdis.h" | |
31 #include "gba/elf.h" | |
32 #include "common/System.h" | |
33 #include "exprNode.h" | |
34 | |
35 extern bool debugger; | |
36 extern int emulating; | |
37 | |
38 extern struct EmulatedSystem theEmulator; | |
39 | |
40 #define debuggerReadMemory(addr) \ | |
41 READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) | |
42 | |
43 #define debuggerReadHalfWord(addr) \ | |
44 READ16LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask])) | |
45 | |
46 #define debuggerReadByte(addr) \ | |
47 map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] | |
48 | |
49 #define debuggerWriteMemory(addr, value) \ | |
50 WRITE32LE(&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], value) | |
51 | |
52 #define debuggerWriteHalfWord(addr, value) \ | |
53 WRITE16LE(&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], value) | |
54 | |
55 #define debuggerWriteByte(addr, value) \ | |
56 map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] = (value) | |
57 | |
58 struct breakpointInfo { | |
59 u32 address; | |
60 u32 value; | |
61 int size; | |
62 }; | |
63 | |
64 struct DebuggerCommand { | |
65 const char *name; | |
66 void (*function)(int,char **); | |
67 const char *help; | |
68 const char *syntax; | |
69 }; | |
70 | |
71 void debuggerContinueAfterBreakpoint(); | |
72 | |
73 void debuggerHelp(int,char **); | |
74 void debuggerNext(int,char **); | |
75 void debuggerContinue(int, char **); | |
76 void debuggerRegisters(int, char **); | |
77 void debuggerBreak(int, char **); | |
78 void debuggerBreakDelete(int, char **); | |
79 void debuggerBreakList(int, char **); | |
80 void debuggerBreakArm(int, char **); | |
81 void debuggerBreakWriteClear(int, char **); | |
82 void debuggerBreakThumb(int, char **); | |
83 void debuggerBreakWrite(int, char **); | |
84 void debuggerDebug(int, char **); | |
85 void debuggerDisassemble(int, char **); | |
86 void debuggerDisassembleArm(int, char **); | |
87 void debuggerDisassembleThumb(int, char **); | |
88 void debuggerEditByte(int, char **); | |
89 void debuggerEditHalfWord(int, char **); | |
90 void debuggerEdit(int, char **); | |
91 void debuggerIo(int, char **); | |
92 void debuggerLocals(int, char **); | |
93 void debuggerMemoryByte(int, char **); | |
94 void debuggerMemoryHalfWord(int, char **); | |
95 void debuggerMemory(int, char **); | |
96 void debuggerPrint(int, char **); | |
97 void debuggerQuit(int, char **); | |
98 void debuggerSetRadix(int, char **); | |
99 void debuggerSymbols(int, char **); | |
100 void debuggerVerbose(int, char **); | |
101 void debuggerWhere(int, char **); | |
102 | |
103 DebuggerCommand debuggerCommands[] = { | |
104 { "?", debuggerHelp, "Shows this help information. Type ? <command> for command help", "[<command>]" }, | |
105 { "ba", debuggerBreakArm, "Adds an ARM breakpoint", "<address>" }, | |
106 { "bd", debuggerBreakDelete,"Deletes a breakpoint", "<number>" }, | |
107 { "bl", debuggerBreakList, "Lists breakpoints" }, | |
108 { "bpw", debuggerBreakWrite, "Break on write", "<address> <size>" }, | |
109 { "bpwc", debuggerBreakWriteClear, "Clear break on write", NULL }, | |
110 { "break", debuggerBreak, "Adds a breakpoint on the given function", "<function>|<line>|<file:line>" }, | |
111 { "bt", debuggerBreakThumb, "Adds a THUMB breakpoint", "<address>" }, | |
112 { "c", debuggerContinue, "Continues execution" , NULL }, | |
113 { "d", debuggerDisassemble, "Disassembles instructions", "[<address> [<number>]]" }, | |
114 { "da", debuggerDisassembleArm, "Disassembles ARM instructions", "[<address> [<number>]]" }, | |
115 { "dt", debuggerDisassembleThumb, "Disassembles THUMB instructions", "[<address> [<number>]]" }, | |
116 { "eb", debuggerEditByte, "Modify memory location (byte)", "<address> <hex value>" }, | |
117 { "eh", debuggerEditHalfWord,"Modify memory location (half-word)","<address> <hex value>" }, | |
118 { "ew", debuggerEdit, "Modify memory location (word)", "<address> <hex value" }, | |
119 { "h", debuggerHelp, "Shows this help information. Type h <command> for command help", "[<command>]" }, | |
120 { "io", debuggerIo, "Show I/O registers status", "[video|video2|dma|timer|misc]" }, | |
121 { "locals", debuggerLocals, "Shows local variables", NULL }, | |
122 { "mb", debuggerMemoryByte, "Shows memory contents (bytes)", "<address>" }, | |
123 { "mh", debuggerMemoryHalfWord, "Shows memory contents (half-words)", "<address>"}, | |
124 { "mw", debuggerMemory, "Shows memory contents (words)", "<address>" }, | |
125 { "n", debuggerNext, "Executes the next instruction", "[<count>]" }, | |
126 { "print", debuggerPrint, "Print the value of a expression (if known)", "[/x|/o|/d] <expression>" }, | |
127 { "q", debuggerQuit, "Quits the emulator", NULL }, | |
128 { "r", debuggerRegisters, "Shows ARM registers", NULL }, | |
129 { "radix", debuggerSetRadix, "Sets the print radix", "<radix>" }, | |
130 { "symbols", debuggerSymbols, "List symbols", "[<symbol>]" }, | |
131 #ifndef FINAL_VERSION | |
132 { "trace", debuggerDebug, "Sets the trace level", "<value>" }, | |
133 #endif | |
134 #ifdef DEV_VERSION | |
135 { "verbose", debuggerVerbose, "Change verbose setting", "<value>" }, | |
136 #endif | |
137 { "where", debuggerWhere, "Shows call chain", NULL }, | |
138 { NULL, NULL, NULL, NULL} // end marker | |
139 }; | |
140 | |
141 breakpointInfo debuggerBreakpointList[100]; | |
142 | |
143 int debuggerNumOfBreakpoints = 0; | |
144 bool debuggerAtBreakpoint = false; | |
145 int debuggerBreakpointNumber = 0; | |
146 int debuggerRadix = 0; | |
147 | |
148 void debuggerApplyBreakpoint(u32 address, int num, int size) | |
149 { | |
150 if(size) | |
151 debuggerWriteMemory(address, (u32)(0xe1200070 | | |
152 (num & 0xf) | | |
153 ((num<<4)&0xf0))); | |
154 else | |
155 debuggerWriteHalfWord(address, | |
156 (u16)(0xbe00 | num)); | |
157 } | |
158 | |
159 void debuggerDisableBreakpoints() | |
160 { | |
161 for(int i = 0; i < debuggerNumOfBreakpoints; i++) { | |
162 if(debuggerBreakpointList[i].size) | |
163 debuggerWriteMemory(debuggerBreakpointList[i].address, | |
164 debuggerBreakpointList[i].value); | |
165 else | |
166 debuggerWriteHalfWord(debuggerBreakpointList[i].address, | |
167 debuggerBreakpointList[i].value); | |
168 } | |
169 } | |
170 | |
171 void debuggerEnableBreakpoints(bool skipPC) | |
172 { | |
173 for(int i = 0; i < debuggerNumOfBreakpoints; i++) { | |
174 if(debuggerBreakpointList[i].address == armNextPC && skipPC) | |
175 continue; | |
176 | |
177 debuggerApplyBreakpoint(debuggerBreakpointList[i].address, | |
178 i, | |
179 debuggerBreakpointList[i].size); | |
180 } | |
181 } | |
182 | |
183 void debuggerUsage(const char *cmd) | |
184 { | |
185 for(int i = 0; ; i++) { | |
186 if(debuggerCommands[i].name) { | |
187 if(!strcmp(debuggerCommands[i].name, cmd)) { | |
188 printf("%s %s\t%s\n", | |
189 debuggerCommands[i].name, | |
190 debuggerCommands[i].syntax ? debuggerCommands[i].syntax : "", | |
191 debuggerCommands[i].help); | |
192 break; | |
193 } | |
194 } else { | |
195 printf("Unrecognized command '%s'.", cmd); | |
196 break; | |
197 } | |
198 } | |
199 } | |
200 | |
201 void debuggerPrintBaseType(Type *t, u32 value, u32 location, | |
202 LocationType type, | |
203 int bitSize, int bitOffset) | |
204 { | |
205 if(bitSize) { | |
206 if(bitOffset) | |
207 value >>= ((t->size*8)-bitOffset-bitSize); | |
208 value &= (1 << bitSize)-1; | |
209 } else { | |
210 if(t->size == 2) | |
211 value &= 0xFFFF; | |
212 else if(t->size == 1) | |
213 value &= 0xFF; | |
214 } | |
215 | |
216 if(t->size == 8) { | |
217 u64 value = 0; | |
218 if(type == LOCATION_memory) { | |
219 value = debuggerReadMemory(location) | | |
220 ((u64)debuggerReadMemory(location+4)<<32); | |
221 } else if(type == LOCATION_register) { | |
222 value = reg[location].I | ((u64)reg[location+1].I << 32); | |
223 } | |
224 switch(t->encoding) { | |
225 case DW_ATE_signed: | |
226 switch(debuggerRadix) { | |
227 case 0: | |
228 printf("%lld", value); | |
229 break; | |
230 case 1: | |
231 printf("0x%llx", value); | |
232 break; | |
233 case 2: | |
234 printf("0%llo", value); | |
235 break; | |
236 } | |
237 break; | |
238 case DW_ATE_unsigned: | |
239 switch(debuggerRadix) { | |
240 case 0: | |
241 printf("%llu", value); | |
242 break; | |
243 case 1: | |
244 printf("0x%llx", value); | |
245 break; | |
246 case 2: | |
247 printf("0%llo", value); | |
248 break; | |
249 } | |
250 break; | |
251 default: | |
252 printf("Unknowing 64-bit encoding\n"); | |
253 } | |
254 return; | |
255 } | |
256 | |
257 switch(t->encoding) { | |
258 case DW_ATE_boolean: | |
259 if(value) | |
260 printf("true"); | |
261 else | |
262 printf("false"); | |
263 break; | |
264 case DW_ATE_signed: | |
265 switch(debuggerRadix) { | |
266 case 0: | |
267 printf("%d", value); | |
268 break; | |
269 case 1: | |
270 printf("0x%x", value); | |
271 break; | |
272 case 2: | |
273 printf("0%o", value); | |
274 break; | |
275 } | |
276 break; | |
277 case DW_ATE_unsigned: | |
278 case DW_ATE_unsigned_char: | |
279 switch(debuggerRadix) { | |
280 case 0: | |
281 printf("%u", value); | |
282 break; | |
283 case 1: | |
284 printf("0x%x", value); | |
285 break; | |
286 case 2: | |
287 printf("0%o", value); | |
288 break; | |
289 } | |
290 break; | |
291 default: | |
292 printf("UNKNOWN BASE %d %08x", t->encoding, value); | |
293 } | |
294 } | |
295 | |
296 char *debuggerPrintType(Type *t) | |
297 { | |
298 char buffer[1024]; | |
299 static char buffer2[1024]; | |
300 | |
301 if(t->type == TYPE_pointer) { | |
302 if(t->pointer) | |
303 strcpy(buffer, debuggerPrintType(t->pointer)); | |
304 else | |
305 strcpy(buffer, "void"); | |
306 sprintf(buffer2, "%s *", buffer); | |
307 return buffer2; | |
308 } else if(t->type == TYPE_reference) { | |
309 strcpy(buffer, debuggerPrintType(t->pointer)); | |
310 sprintf(buffer2, "%s &", buffer); | |
311 return buffer2; | |
312 } | |
313 return t->name; | |
314 } | |
315 | |
316 void debuggerPrintValueInternal(Function *, Type *, ELFBlock *, int, int, u32); | |
317 void debuggerPrintValueInternal(Function *f, Type *t, | |
318 int bitSize, int bitOffset, | |
319 u32 objLocation, LocationType type); | |
320 | |
321 u32 debuggerGetValue(u32 location, LocationType type) | |
322 { | |
323 switch(type) { | |
324 case LOCATION_memory: | |
325 return debuggerReadMemory(location); | |
326 case LOCATION_register: | |
327 return reg[location].I; | |
328 case LOCATION_value: | |
329 return location; | |
330 } | |
331 return 0; | |
332 } | |
333 | |
334 void debuggerPrintPointer(Type *t, u32 value) | |
335 { | |
336 printf("(%s)0x%08x", debuggerPrintType(t), value); | |
337 } | |
338 | |
339 void debuggerPrintReference(Type *t, u32 value) | |
340 { | |
341 printf("(%s)0x%08x", debuggerPrintType(t), value); | |
342 } | |
343 | |
344 void debuggerPrintFunction(Type *t, u32 value) | |
345 { | |
346 printf("(%s)0x%08x", debuggerPrintType(t), value); | |
347 } | |
348 | |
349 void debuggerPrintArray(Type *t, u32 value) | |
350 { | |
351 // todo | |
352 printf("(%s[])0x%08x", debuggerPrintType(t->array->type), value); | |
353 } | |
354 | |
355 void debuggerPrintMember(Function *f, | |
356 Member *m, | |
357 u32 objLocation, | |
358 u32 location) | |
359 { | |
360 int bitSize = m->bitSize; | |
361 if(bitSize) { | |
362 u32 value = 0; | |
363 int off = m->bitOffset; | |
364 int size = m->byteSize; | |
365 u32 v = 0; | |
366 if(size == 1) | |
367 v = debuggerReadByte(location); | |
368 else if(size == 2) | |
369 v = debuggerReadHalfWord(location); | |
370 else if(size == 4) | |
371 v = debuggerReadMemory(location); | |
372 | |
373 while(bitSize) { | |
374 int top = size*8 - off; | |
375 int bot = top - bitSize; | |
376 top--; | |
377 if(bot >= 0) { | |
378 value = (v >> (size*8 - bitSize - off)) & ((1 << bitSize)-1); | |
379 bitSize = 0; | |
380 } else { | |
381 value |= (v & ((1 << top)-1)) << (bitSize - top); | |
382 bitSize -= (top+1); | |
383 location -= size; | |
384 off = 0; | |
385 if(size == 1) | |
386 v = debuggerReadByte(location); | |
387 else if(size == 2) | |
388 v = debuggerReadHalfWord(location); | |
389 else | |
390 v = debuggerReadMemory(location); | |
391 } | |
392 } | |
393 debuggerPrintBaseType(m->type, value, location, LOCATION_memory, | |
394 bitSize, 0); | |
395 } else { | |
396 debuggerPrintValueInternal(f, m->type, m->location, m->bitSize, | |
397 m->bitOffset, objLocation); | |
398 } | |
399 } | |
400 | |
401 void debuggerPrintStructure(Function *f, Type *t, u32 objLocation) | |
402 { | |
403 printf("{"); | |
404 int count = t->structure->memberCount; | |
405 int i = 0; | |
406 while(i < count) { | |
407 Member *m = &t->structure->members[i]; | |
408 printf("%s=", m->name); | |
409 LocationType type; | |
410 u32 location = elfDecodeLocation(f, m->location, &type, objLocation); | |
411 debuggerPrintMember(f, m, objLocation, location); | |
412 i++; | |
413 if(i < count) | |
414 printf(","); | |
415 } | |
416 printf("}"); | |
417 } | |
418 | |
419 void debuggerPrintUnion(Function *f, Type *t, u32 objLocation) | |
420 { | |
421 // todo | |
422 printf("{"); | |
423 int count = t->structure->memberCount; | |
424 int i = 0; | |
425 while(i < count) { | |
426 Member *m = &t->structure->members[i]; | |
427 printf("%s=", m->name); | |
428 debuggerPrintMember(f, m, objLocation, 0); | |
429 i++; | |
430 if(i < count) | |
431 printf(","); | |
432 } | |
433 printf("}"); | |
434 } | |
435 | |
436 void debuggerPrintEnum(Type *t, u32 value) | |
437 { | |
438 int i; | |
439 for(i = 0; i < t->enumeration->count; i++) { | |
440 EnumMember *m = (EnumMember *)&t->enumeration->members[i]; | |
441 if(value == m->value) { | |
442 puts(m->name); | |
443 return; | |
444 } | |
445 } | |
446 printf("(UNKNOWN VALUE) %d", value); | |
447 } | |
448 | |
449 void debuggerPrintValueInternal(Function *f, Type *t, | |
450 int bitSize, int bitOffset, | |
451 u32 objLocation, LocationType type) | |
452 { | |
453 u32 value = debuggerGetValue(objLocation, type); | |
454 if(!t) { | |
455 printf("void"); | |
456 return; | |
457 } | |
458 switch(t->type) { | |
459 case TYPE_base: | |
460 debuggerPrintBaseType(t, value, objLocation, type, bitSize, bitOffset); | |
461 break; | |
462 case TYPE_pointer: | |
463 debuggerPrintPointer(t, value); | |
464 break; | |
465 case TYPE_reference: | |
466 debuggerPrintReference(t, value); | |
467 break; | |
468 case TYPE_function: | |
469 debuggerPrintFunction(t, value); | |
470 break; | |
471 case TYPE_array: | |
472 debuggerPrintArray(t, objLocation); | |
473 break; | |
474 case TYPE_struct: | |
475 debuggerPrintStructure(f, t, objLocation); | |
476 break; | |
477 case TYPE_union: | |
478 debuggerPrintUnion(f, t, objLocation); | |
479 break; | |
480 case TYPE_enum: | |
481 debuggerPrintEnum(t, value); | |
482 break; | |
483 default: | |
484 printf("%08x", value); | |
485 break; | |
486 } | |
487 } | |
488 | |
489 void debuggerPrintValueInternal(Function *f, Type *t, ELFBlock *loc, | |
490 int bitSize, int bitOffset, u32 objLocation) | |
491 { | |
492 LocationType type; | |
493 u32 location; | |
494 if(loc) { | |
495 if(objLocation) | |
496 location = elfDecodeLocation(f, loc, &type, objLocation); | |
497 else | |
498 location = elfDecodeLocation(f, loc,&type); | |
499 } else { | |
500 location = objLocation; | |
501 type = LOCATION_memory; | |
502 } | |
503 | |
504 debuggerPrintValueInternal(f, t, bitSize, bitOffset, location, type); | |
505 } | |
506 | |
507 void debuggerPrintValue(Function *f, Object *o) | |
508 { | |
509 debuggerPrintValueInternal(f, o->type, o->location, 0, 0, 0); | |
510 | |
511 printf("\n"); | |
512 } | |
513 | |
514 void debuggerSymbols(int argc, char **argv) | |
515 { | |
516 int i = 0; | |
517 u32 value; | |
518 u32 size; | |
519 int type; | |
520 bool match = false; | |
521 int matchSize = 0; | |
522 char *matchStr = NULL; | |
523 | |
524 if(argc == 2) { | |
525 match = true; | |
526 matchSize = strlen(argv[1]); | |
527 matchStr = argv[1]; | |
528 } | |
529 printf("Symbol Value Size Type \n"); | |
530 printf("-------------------- ------- -------- -------\n"); | |
531 char *s = NULL; | |
532 while((s = elfGetSymbol(i, &value, &size, &type))) { | |
533 if(*s) { | |
534 if(match) { | |
535 if(strncmp(s, matchStr, matchSize) != 0) { | |
536 i++; | |
537 continue; | |
538 } | |
539 } | |
540 const char *ts = "?"; | |
541 switch(type) { | |
542 case 2: | |
543 ts = "ARM"; | |
544 break; | |
545 case 0x0d: | |
546 ts = "THUMB"; | |
547 break; | |
548 case 1: | |
549 ts = "DATA"; | |
550 break; | |
551 } | |
552 printf("%-20s %08x %08x %-7s\n", | |
553 s, value, size, ts); | |
554 } | |
555 i++; | |
556 } | |
557 } | |
558 | |
559 void debuggerSetRadix(int argc, char **argv) | |
560 { | |
561 if(argc != 2) | |
562 debuggerUsage(argv[0]); | |
563 else { | |
564 int r = atoi(argv[1]); | |
565 | |
566 bool error = false; | |
567 switch(r) { | |
568 case 10: | |
569 debuggerRadix = 0; | |
570 break; | |
571 case 8: | |
572 debuggerRadix = 2; | |
573 break; | |
574 case 16: | |
575 debuggerRadix = 1; | |
576 break; | |
577 default: | |
578 error = true; | |
579 printf("Unknown radix %d. Valid values are 8, 10 and 16.\n", r); | |
580 break; | |
581 } | |
582 if(!error) | |
583 printf("Radix set to %d\n", r); | |
584 } | |
585 } | |
586 | |
587 void debuggerPrint(int argc, char **argv) | |
588 { | |
589 if(argc != 2 && argc != 3) { | |
590 debuggerUsage(argv[0]); | |
591 } else { | |
592 u32 pc = armNextPC; | |
593 Function *f = NULL; | |
594 CompileUnit *u = NULL; | |
595 | |
596 elfGetCurrentFunction(pc, | |
597 &f, &u); | |
598 | |
599 int oldRadix = debuggerRadix; | |
600 if(argc == 3) { | |
601 if(argv[1][0] == '/') { | |
602 if(argv[1][1] == 'x') | |
603 debuggerRadix = 1; | |
604 else if(argv[1][1] == 'o') | |
605 debuggerRadix = 2; | |
606 else if(argv[1][1] == 'd') | |
607 debuggerRadix = 0; | |
608 else { | |
609 printf("Unknown format %c\n", argv[1][1]); | |
610 return; | |
611 } | |
612 } else { | |
613 printf("Unknown option %s\n", argv[1]); | |
614 return; | |
615 } | |
616 } | |
617 | |
618 char *s = argc == 2 ? argv[1] : argv[2]; | |
619 | |
620 extern char *exprString; | |
621 extern int exprCol; | |
622 extern int yyparse(); | |
623 exprString = s; | |
624 exprCol = 0; | |
625 if(!yyparse()) { | |
626 extern Node *result; | |
627 if(result->resolve(result, f, u)) { | |
628 if(result->member) | |
629 debuggerPrintMember(f, | |
630 result->member, | |
631 result->objLocation, | |
632 result->location); | |
633 else | |
634 debuggerPrintValueInternal(f, result->type, 0, 0, | |
635 result->location, | |
636 result->locType); | |
637 printf("\n"); | |
638 } else { | |
639 printf("Error resolving expression\n"); | |
640 } | |
641 } else { | |
642 printf("Error parsing expression:\n"); | |
643 printf("%s\n", s); | |
644 exprCol--; | |
645 for(int i = 0; i < exprCol; i++) | |
646 printf(" "); | |
647 printf("^\n"); | |
648 } | |
649 extern void exprCleanBuffer(); | |
650 exprCleanBuffer(); | |
651 exprNodeCleanUp(); | |
652 debuggerRadix = oldRadix; | |
653 } | |
654 } | |
655 | |
656 void debuggerHelp(int n, char **args) | |
657 { | |
658 if(n == 2) { | |
659 debuggerUsage(args[1]); | |
660 } else { | |
661 for(int i = 0; ; i++) { | |
662 if(debuggerCommands[i].name) { | |
663 printf("%s\t%s\n", debuggerCommands[i].name, debuggerCommands[i].help); | |
664 } else | |
665 break; | |
666 } | |
667 } | |
668 } | |
669 | |
670 void debuggerDebug(int n, char **args) | |
671 { | |
672 if(n == 2) { | |
673 int v = 0; | |
674 sscanf(args[1], "%d", &v); | |
675 systemDebug = v; | |
676 printf("Debug level set to %d\n", systemDebug); | |
677 } else | |
678 debuggerUsage("trace"); | |
679 } | |
680 | |
681 void debuggerVerbose(int n, char **args) | |
682 { | |
683 if(n == 2) { | |
684 int v = 0; | |
685 sscanf(args[1], "%d", &v); | |
686 systemVerbose = v; | |
687 printf("Verbose level set to %d\n", systemVerbose); | |
688 } else | |
689 debuggerUsage("verbose"); | |
690 } | |
691 | |
692 void debuggerWhere(int n, char **args) | |
693 { | |
694 void elfPrintCallChain(u32); | |
695 elfPrintCallChain(armNextPC); | |
696 } | |
697 | |
698 void debuggerLocals(int n, char **args) | |
699 { | |
700 Function *f = NULL; | |
701 CompileUnit *u = NULL; | |
702 u32 pc = armNextPC; | |
703 if(elfGetCurrentFunction(pc, | |
704 &f, &u)) { | |
705 Object *o = f->parameters; | |
706 while(o) { | |
707 printf("%s=", o->name); | |
708 debuggerPrintValue(f, o); | |
709 o = o->next; | |
710 } | |
711 | |
712 o = f->variables; | |
713 while(o) { | |
714 bool visible = o->startScope ? pc>=o->startScope : true; | |
715 if(visible) | |
716 visible = o->endScope ? pc < o->endScope : true; | |
717 if(visible) { | |
718 printf("%s=", o->name); | |
719 debuggerPrintValue(f, o); | |
720 } | |
721 o = o->next; | |
722 } | |
723 } else { | |
724 printf("No information for current address\n"); | |
725 } | |
726 } | |
727 | |
728 void debuggerNext(int n, char **args) | |
729 { | |
730 int count = 1; | |
731 if(n == 2) { | |
732 sscanf(args[1], "%d", &count); | |
733 } | |
734 for(int i = 0; i < count; i++) { | |
735 if(debuggerAtBreakpoint) { | |
736 debuggerContinueAfterBreakpoint(); | |
737 debuggerEnableBreakpoints(false); | |
738 } else | |
739 theEmulator.emuMain(1); | |
740 } | |
741 debuggerDisableBreakpoints(); | |
742 Function *f = NULL; | |
743 CompileUnit *u = NULL; | |
744 u32 a = armNextPC; | |
745 if(elfGetCurrentFunction(a, &f, &u)) { | |
746 char *file; | |
747 int line = elfFindLine(u, f, a, &file); | |
748 | |
749 printf("File %s, function %s, line %d\n", file, f->name, | |
750 line); | |
751 } | |
752 debuggerRegisters(0, NULL); | |
753 } | |
754 | |
755 void debuggerContinue(int n, char **args) | |
756 { | |
757 if(debuggerAtBreakpoint) | |
758 debuggerContinueAfterBreakpoint(); | |
759 debuggerEnableBreakpoints(false); | |
760 debugger = false; | |
761 } | |
762 | |
763 void debuggerSignal(int sig,int number) | |
764 { | |
765 switch(sig) { | |
766 case 4: | |
767 { | |
768 printf("Illegal instruction at %08x\n", armNextPC); | |
769 debugger = true; | |
770 } | |
771 break; | |
772 case 5: | |
773 { | |
774 printf("Breakpoint %d reached\n", number); | |
775 debugger = true; | |
776 debuggerAtBreakpoint = true; | |
777 debuggerBreakpointNumber = number; | |
778 debuggerDisableBreakpoints(); | |
779 | |
780 Function *f = NULL; | |
781 CompileUnit *u = NULL; | |
782 | |
783 if(elfGetCurrentFunction(armNextPC, &f, &u)) { | |
784 char *file; | |
785 int line = elfFindLine(u,f,armNextPC,&file); | |
786 printf("File %s, function %s, line %d\n", file, f->name, | |
787 line); | |
788 } | |
789 } | |
790 break; | |
791 default: | |
792 printf("Unknown signal %d\n", sig); | |
793 break; | |
794 } | |
795 } | |
796 | |
797 void debuggerBreakList(int, char **) | |
798 { | |
799 printf("Num Address Type Symbol\n"); | |
800 printf("--- -------- ----- ------\n"); | |
801 for(int i = 0; i < debuggerNumOfBreakpoints; i++) { | |
802 printf("%3d %08x %s %s\n",i, debuggerBreakpointList[i].address, | |
803 debuggerBreakpointList[i].size ? "ARM" : "THUMB", | |
804 elfGetAddressSymbol(debuggerBreakpointList[i].address)); | |
805 } | |
806 } | |
807 | |
808 void debuggerBreakDelete(int n, char **args) | |
809 { | |
810 if(n == 2) { | |
811 int n = 0; | |
812 sscanf(args[1], "%d", &n); | |
813 printf("Deleting breakpoint %d (%d)\n", n, debuggerNumOfBreakpoints); | |
814 if(n >= 0 && n < debuggerNumOfBreakpoints) { | |
815 n++; | |
816 if(n < debuggerNumOfBreakpoints) { | |
817 for(int i = n; i < debuggerNumOfBreakpoints; i++) { | |
818 debuggerBreakpointList[i-1].address = | |
819 debuggerBreakpointList[i].address; | |
820 debuggerBreakpointList[i-1].value = | |
821 debuggerBreakpointList[i].value; | |
822 debuggerBreakpointList[i-1].size = | |
823 debuggerBreakpointList[i].size; | |
824 } | |
825 } | |
826 debuggerNumOfBreakpoints--; | |
827 } | |
828 } else | |
829 debuggerUsage("bd"); | |
830 } | |
831 | |
832 void debuggerBreak(int n, char **args) | |
833 { | |
834 if(n == 2) { | |
835 u32 address = 0; | |
836 u32 value = 0; | |
837 int type = 0; | |
838 char *s = args[1]; | |
839 char c = *s; | |
840 if(strchr(s, ':')) { | |
841 char *name = s; | |
842 char *l = strchr(s, ':'); | |
843 *l++ = 0; | |
844 int line = atoi(l); | |
845 | |
846 u32 addr; | |
847 Function *f; | |
848 CompileUnit *u; | |
849 | |
850 if(elfFindLineInModule(&addr, name, line)) { | |
851 if(elfGetCurrentFunction(addr, &f, &u)) { | |
852 u32 addr2; | |
853 if(elfGetSymbolAddress(f->name, &addr2, &value, &type)) { | |
854 address = addr; | |
855 } else { | |
856 printf("Unable to get function symbol data\n"); | |
857 return; | |
858 } | |
859 } else { | |
860 printf("Unable to find function for address\n"); | |
861 return; | |
862 } | |
863 } else { | |
864 printf("Unable to find module or line\n"); | |
865 return; | |
866 } | |
867 } else if(c >= '0' && c <= '9') { | |
868 int line = atoi(s); | |
869 Function *f; | |
870 CompileUnit *u; | |
871 u32 addr; | |
872 | |
873 if(elfGetCurrentFunction(armNextPC, &f, &u)) { | |
874 if(elfFindLineInUnit(&addr, u, line)) { | |
875 if(elfGetCurrentFunction(addr, &f, &u)) { | |
876 u32 addr2; | |
877 if(elfGetSymbolAddress(f->name, &addr2, &value, &type)) { | |
878 address = addr; | |
879 } else { | |
880 printf("Unable to get function symbol data\n"); | |
881 return; | |
882 } | |
883 } else { | |
884 printf("Unable to find function for address\n"); | |
885 return; | |
886 } | |
887 } else { | |
888 printf("Unable to find line\n"); | |
889 return; | |
890 } | |
891 } else { | |
892 printf("Cannot find current function\n"); | |
893 return; | |
894 } | |
895 } else { | |
896 if(!elfGetSymbolAddress(s, &address, &value, &type)) { | |
897 printf("Function %s not found\n", args[1]); | |
898 return; | |
899 } | |
900 } | |
901 if(type == 0x02 || type == 0x0d) { | |
902 int i = debuggerNumOfBreakpoints; | |
903 int size = 0; | |
904 if(type == 2) | |
905 size = 1; | |
906 debuggerBreakpointList[i].address = address; | |
907 debuggerBreakpointList[i].value = type == 0x02 ? | |
908 debuggerReadMemory(address) : debuggerReadHalfWord(address); | |
909 debuggerBreakpointList[i].size = size; | |
910 // debuggerApplyBreakpoint(address, i, size); | |
911 debuggerNumOfBreakpoints++; | |
912 if(size) | |
913 printf("Added ARM breakpoint at %08x\n", address); | |
914 else | |
915 printf("Added THUMB breakpoint at %08x\n", address); | |
916 } else { | |
917 printf("%s is not a function symbol\n", args[1]); | |
918 } | |
919 } else | |
920 debuggerUsage("break"); | |
921 } | |
922 | |
923 void debuggerBreakThumb(int n, char **args) | |
924 { | |
925 if(n == 2) { | |
926 u32 address = 0; | |
927 sscanf(args[1],"%x", &address); | |
928 int i = debuggerNumOfBreakpoints; | |
929 debuggerBreakpointList[i].address = address; | |
930 debuggerBreakpointList[i].value = debuggerReadHalfWord(address); | |
931 debuggerBreakpointList[i].size = 0; | |
932 // debuggerApplyBreakpoint(address, i, 0); | |
933 debuggerNumOfBreakpoints++; | |
934 printf("Added THUMB breakpoint at %08x\n", address); | |
935 } else | |
936 debuggerUsage("bt"); | |
937 } | |
938 | |
939 void debuggerBreakArm(int n, char **args) | |
940 { | |
941 if(n == 2) { | |
942 u32 address = 0; | |
943 sscanf(args[1],"%x", &address); | |
944 int i = debuggerNumOfBreakpoints; | |
945 debuggerBreakpointList[i].address = address; | |
946 debuggerBreakpointList[i].value = debuggerReadMemory(address); | |
947 debuggerBreakpointList[i].size = 1; | |
948 // debuggerApplyBreakpoint(address, i, 1); | |
949 debuggerNumOfBreakpoints++; | |
950 printf("Added ARM breakpoint at %08x\n", address); | |
951 } else | |
952 debuggerUsage("ba"); | |
953 } | |
954 | |
955 void debuggerBreakOnWrite(u32 *mem, u32 oldvalue, u32 value, int size) | |
956 { | |
957 u32 address = 0; | |
958 if(mem >= (u32*)&workRAM[0] && mem <= (u32*)&workRAM[0x3ffff]) | |
959 address = 0x2000000 + ((u64)mem - (u64)&workRAM[0]); | |
960 else | |
961 address = 0x3000000 + ((u64)mem - (u64)&internalRAM[0]); | |
962 | |
963 if(size == 2) | |
964 printf("Breakpoint (on write) address %08x old:%08x new:%08x\n", | |
965 address, oldvalue, value); | |
966 else if(size == 1) | |
967 printf("Breakpoint (on write) address %08x old:%04x new:%04x\n", | |
968 address, (u16)oldvalue,(u16)value); | |
969 else | |
970 printf("Breakpoint (on write) address %08x old:%02x new:%02x\n", | |
971 address, (u8)oldvalue, (u8)value); | |
972 debugger = true; | |
973 } | |
974 | |
975 void debuggerBreakWriteClear(int n, char **args) | |
976 { | |
977 memset(freezeWorkRAM, false, 0x40000); | |
978 memset(freezeInternalRAM, false, 0x8000); | |
979 printf("Cleared all break on write\n"); | |
980 } | |
981 | |
982 void debuggerBreakWrite(int n, char **args) | |
983 { | |
984 if(n == 3) { | |
985 if(cheatsNumber != 0) { | |
986 printf("Cheats are enabled. Cannot continue.\n"); | |
987 return; | |
988 } | |
989 u32 address = 0; | |
990 sscanf(args[1], "%x", &address); | |
991 int n = 0; | |
992 sscanf(args[2], "%d", &n); | |
993 | |
994 if(address < 0x2000000 || address > 0x3007fff) { | |
995 printf("Invalid address: %08x\n", address); | |
996 return; | |
997 } | |
998 | |
999 if(address > 0x203ffff && address < 0x3000000) { | |
1000 printf("Invalid address: %08x\n", address); | |
1001 return; | |
1002 } | |
1003 | |
1004 u32 final = address + n; | |
1005 | |
1006 if(address < 0x2040000 && final > 0x2040000) { | |
1007 printf("Invalid byte count: %d\n", n); | |
1008 return; | |
1009 } else if(address < 0x3008000 && final > 0x3008000) { | |
1010 printf("Invalid byte count: %d\n", n); | |
1011 return; | |
1012 } | |
1013 printf("Added break on write at %08x for %d bytes\n", address, n); | |
1014 for(int i = 0; i < n; i++) { | |
1015 if((address >> 24) == 2) | |
1016 freezeWorkRAM[address & 0x3ffff] = true; | |
1017 else | |
1018 freezeInternalRAM[address & 0x7fff] = true; | |
1019 address++; | |
1020 } | |
1021 } else | |
1022 debuggerUsage("bpw"); | |
1023 } | |
1024 | |
1025 void debuggerDisassembleArm(int n, char **args) | |
1026 { | |
1027 char buffer[80]; | |
1028 u32 pc = reg[15].I; | |
1029 pc -= 4; | |
1030 int count = 20; | |
1031 if(n >= 2) { | |
1032 sscanf(args[1], "%x", &pc); | |
1033 } | |
1034 if(pc & 3) { | |
1035 printf("Misaligned address %08x\n", pc); | |
1036 pc &= 0xfffffffc; | |
1037 } | |
1038 if(n >= 3) { | |
1039 sscanf(args[2], "%d", &count); | |
1040 } | |
1041 int i = 0; | |
1042 int len = 0; | |
1043 char format[30]; | |
1044 for(i = 0; i < count; i++) { | |
1045 int l = strlen(elfGetAddressSymbol(pc+4*i)); | |
1046 if(l > len) | |
1047 len = l; | |
1048 } | |
1049 sprintf(format, "%%08x %%-%ds %%s\n", len); | |
1050 for(i = 0; i < count; i++) { | |
1051 u32 addr = pc; | |
1052 pc += disArm(pc, buffer, 2); | |
1053 printf(format, addr, elfGetAddressSymbol(addr), buffer); | |
1054 } | |
1055 } | |
1056 | |
1057 void debuggerDisassembleThumb(int n, char **args) | |
1058 { | |
1059 char buffer[80]; | |
1060 u32 pc = reg[15].I; | |
1061 pc -= 2; | |
1062 int count = 20; | |
1063 if(n >= 2) { | |
1064 sscanf(args[1], "%x", &pc); | |
1065 } | |
1066 if(pc & 1) { | |
1067 printf("Misaligned address %08x\n", pc); | |
1068 pc &= 0xfffffffe; | |
1069 } | |
1070 if(n >= 3) { | |
1071 sscanf(args[2], "%d", &count); | |
1072 } | |
1073 | |
1074 int i = 0; | |
1075 int len = 0; | |
1076 char format[30]; | |
1077 for(i = 0; i < count; i++) { | |
1078 int l = strlen(elfGetAddressSymbol(pc+2*i)); | |
1079 if(l > len) | |
1080 len = l; | |
1081 } | |
1082 sprintf(format, "%%08x %%-%ds %%s\n", len); | |
1083 | |
1084 for(i = 0; i < count; i++) { | |
1085 u32 addr = pc; | |
1086 pc += disThumb(pc, buffer, 2); | |
1087 printf(format, addr, elfGetAddressSymbol(addr), buffer); | |
1088 } | |
1089 } | |
1090 | |
1091 void debuggerDisassemble(int n, char **args) | |
1092 { | |
1093 if(armState) | |
1094 debuggerDisassembleArm(n, args); | |
1095 else | |
1096 debuggerDisassembleThumb(n, args); | |
1097 } | |
1098 | |
1099 void debuggerContinueAfterBreakpoint() | |
1100 { | |
1101 printf("Continuing after breakpoint\n"); | |
1102 debuggerEnableBreakpoints(true); | |
1103 theEmulator.emuMain(1); | |
1104 debuggerAtBreakpoint = false; | |
1105 } | |
1106 | |
1107 void debuggerRegisters(int, char **) | |
1108 { | |
1109 char *command[3]; | |
1110 char buffer[10]; | |
1111 | |
1112 printf("R00=%08x R04=%08x R08=%08x R12=%08x\n", | |
1113 reg[0].I, reg[4].I, reg[8].I, reg[12].I); | |
1114 printf("R01=%08x R05=%08x R09=%08x R13=%08x\n", | |
1115 reg[1].I, reg[5].I, reg[9].I, reg[13].I); | |
1116 printf("R02=%08x R06=%08x R10=%08x R14=%08x\n", | |
1117 reg[2].I, reg[6].I, reg[10].I, reg[14].I); | |
1118 printf("R03=%08x R07=%08x R11=%08x R15=%08x\n", | |
1119 reg[3].I, reg[7].I, reg[11].I, reg[15].I); | |
1120 printf("CPSR=%08x (%c%c%c%c%c%c%c Mode: %02x)\n", | |
1121 reg[16].I, | |
1122 (N_FLAG ? 'N' : '.'), | |
1123 (Z_FLAG ? 'Z' : '.'), | |
1124 (C_FLAG ? 'C' : '.'), | |
1125 (V_FLAG ? 'V' : '.'), | |
1126 (armIrqEnable ? '.' : 'I'), | |
1127 ((!(reg[16].I & 0x40)) ? '.' : 'F'), | |
1128 (armState ? '.' : 'T'), | |
1129 armMode); | |
1130 sprintf(buffer,"%08x", armState ? reg[15].I - 4 : reg[15].I - 2); | |
1131 command[0]=const_cast<char *>("m"); | |
1132 command[1]=buffer; | |
1133 command[2]=const_cast<char *>("1"); | |
1134 debuggerDisassemble(3, command); | |
1135 } | |
1136 | |
1137 void debuggerIoVideo() | |
1138 { | |
1139 printf("DISPCNT = %04x\n", DISPCNT); | |
1140 printf("DISPSTAT = %04x\n", DISPSTAT); | |
1141 printf("VCOUNT = %04x\n", VCOUNT); | |
1142 printf("BG0CNT = %04x\n", BG0CNT); | |
1143 printf("BG1CNT = %04x\n", BG1CNT); | |
1144 printf("BG2CNT = %04x\n", BG2CNT); | |
1145 printf("BG3CNT = %04x\n", BG3CNT); | |
1146 printf("WIN0H = %04x\n", WIN0H); | |
1147 printf("WIN0V = %04x\n", WIN0V); | |
1148 printf("WIN1H = %04x\n", WIN1H); | |
1149 printf("WIN1V = %04x\n", WIN1V); | |
1150 printf("WININ = %04x\n", WININ); | |
1151 printf("WINOUT = %04x\n", WINOUT); | |
1152 printf("MOSAIC = %04x\n", MOSAIC); | |
1153 printf("BLDMOD = %04x\n", BLDMOD); | |
1154 printf("COLEV = %04x\n", COLEV); | |
1155 printf("COLY = %04x\n", COLY); | |
1156 } | |
1157 | |
1158 void debuggerIoVideo2() | |
1159 { | |
1160 printf("BG0HOFS = %04x\n", BG0HOFS); | |
1161 printf("BG0VOFS = %04x\n", BG0VOFS); | |
1162 printf("BG1HOFS = %04x\n", BG1HOFS); | |
1163 printf("BG1VOFS = %04x\n", BG1VOFS); | |
1164 printf("BG2HOFS = %04x\n", BG2HOFS); | |
1165 printf("BG2VOFS = %04x\n", BG2VOFS); | |
1166 printf("BG3HOFS = %04x\n", BG3HOFS); | |
1167 printf("BG3VOFS = %04x\n", BG3VOFS); | |
1168 printf("BG2PA = %04x\n", BG2PA); | |
1169 printf("BG2PB = %04x\n", BG2PB); | |
1170 printf("BG2PC = %04x\n", BG2PC); | |
1171 printf("BG2PD = %04x\n", BG2PD); | |
1172 printf("BG2X = %08x\n", (BG2X_H<<16)|BG2X_L); | |
1173 printf("BG2Y = %08x\n", (BG2Y_H<<16)|BG2Y_L); | |
1174 printf("BG3PA = %04x\n", BG3PA); | |
1175 printf("BG3PB = %04x\n", BG3PB); | |
1176 printf("BG3PC = %04x\n", BG3PC); | |
1177 printf("BG3PD = %04x\n", BG3PD); | |
1178 printf("BG3X = %08x\n", (BG3X_H<<16)|BG3X_L); | |
1179 printf("BG3Y = %08x\n", (BG3Y_H<<16)|BG3Y_L); | |
1180 } | |
1181 | |
1182 void debuggerIoDMA() | |
1183 { | |
1184 printf("DM0SAD = %08x\n", (DM0SAD_H<<16)|DM0SAD_L); | |
1185 printf("DM0DAD = %08x\n", (DM0DAD_H<<16)|DM0DAD_L); | |
1186 printf("DM0CNT = %08x\n", (DM0CNT_H<<16)|DM0CNT_L); | |
1187 printf("DM1SAD = %08x\n", (DM1SAD_H<<16)|DM1SAD_L); | |
1188 printf("DM1DAD = %08x\n", (DM1DAD_H<<16)|DM1DAD_L); | |
1189 printf("DM1CNT = %08x\n", (DM1CNT_H<<16)|DM1CNT_L); | |
1190 printf("DM2SAD = %08x\n", (DM2SAD_H<<16)|DM2SAD_L); | |
1191 printf("DM2DAD = %08x\n", (DM2DAD_H<<16)|DM2DAD_L); | |
1192 printf("DM2CNT = %08x\n", (DM2CNT_H<<16)|DM2CNT_L); | |
1193 printf("DM3SAD = %08x\n", (DM3SAD_H<<16)|DM3SAD_L); | |
1194 printf("DM3DAD = %08x\n", (DM3DAD_H<<16)|DM3DAD_L); | |
1195 printf("DM3CNT = %08x\n", (DM3CNT_H<<16)|DM3CNT_L); | |
1196 } | |
1197 | |
1198 void debuggerIoTimer() | |
1199 { | |
1200 printf("TM0D = %04x\n", TM0D); | |
1201 printf("TM0CNT = %04x\n", TM0CNT); | |
1202 printf("TM1D = %04x\n", TM1D); | |
1203 printf("TM1CNT = %04x\n", TM1CNT); | |
1204 printf("TM2D = %04x\n", TM2D); | |
1205 printf("TM2CNT = %04x\n", TM2CNT); | |
1206 printf("TM3D = %04x\n", TM3D); | |
1207 printf("TM3CNT = %04x\n", TM3CNT); | |
1208 } | |
1209 | |
1210 void debuggerIoMisc() | |
1211 { | |
1212 printf("P1 = %04x\n", P1); | |
1213 printf("IE = %04x\n", IE); | |
1214 printf("IF = %04x\n", IF); | |
1215 printf("IME = %04x\n", IME); | |
1216 } | |
1217 | |
1218 void debuggerIo(int n, char **args) | |
1219 { | |
1220 if(n == 1) { | |
1221 debuggerIoVideo(); | |
1222 return; | |
1223 } | |
1224 if(!strcmp(args[1], "video")) | |
1225 debuggerIoVideo(); | |
1226 else if(!strcmp(args[1], "video2")) | |
1227 debuggerIoVideo2(); | |
1228 else if(!strcmp(args[1], "dma")) | |
1229 debuggerIoDMA(); | |
1230 else if(!strcmp(args[1], "timer")) | |
1231 debuggerIoTimer(); | |
1232 else if(!strcmp(args[1], "misc")) | |
1233 debuggerIoMisc(); | |
1234 else printf("Unrecognized option %s\n", args[1]); | |
1235 } | |
1236 | |
1237 void debuggerEditByte(int n, char **args) | |
1238 { | |
1239 if(n == 3) { | |
1240 u32 address; | |
1241 u32 byte; | |
1242 sscanf(args[1], "%x", &address); | |
1243 sscanf(args[2], "%x", &byte); | |
1244 debuggerWriteByte(address, (u8)byte); | |
1245 } else | |
1246 debuggerUsage("eb"); | |
1247 } | |
1248 | |
1249 void debuggerEditHalfWord(int n, char **args) | |
1250 { | |
1251 if(n == 3) { | |
1252 u32 address; | |
1253 u32 byte; | |
1254 sscanf(args[1], "%x", &address); | |
1255 if(address & 1) { | |
1256 printf("Error: address must be half-word aligned\n"); | |
1257 return; | |
1258 } | |
1259 sscanf(args[2], "%x", &byte); | |
1260 debuggerWriteHalfWord(address, (u16)byte); | |
1261 } else | |
1262 debuggerUsage("eh"); | |
1263 } | |
1264 | |
1265 void debuggerEdit(int n, char **args) | |
1266 { | |
1267 if(n == 3) { | |
1268 u32 address; | |
1269 u32 byte; | |
1270 sscanf(args[1], "%x", &address); | |
1271 if(address & 3) { | |
1272 printf("Error: address must be word aligned\n"); | |
1273 return; | |
1274 } | |
1275 sscanf(args[2], "%x", &byte); | |
1276 debuggerWriteMemory(address, (u32)byte); | |
1277 } else | |
1278 debuggerUsage("ew"); | |
1279 } | |
1280 | |
1281 | |
1282 #define ASCII(c) (c) < 32 ? '.' : (c) > 127 ? '.' : (c) | |
1283 | |
1284 void debuggerMemoryByte(int n, char **args) | |
1285 { | |
1286 if(n == 2) { | |
1287 u32 addr = 0; | |
1288 sscanf(args[1], "%x", &addr); | |
1289 for(int ii = 0; ii < 16; ii++) { | |
1290 int a = debuggerReadByte(addr); | |
1291 int b = debuggerReadByte(addr+1); | |
1292 int c = debuggerReadByte(addr+2); | |
1293 int d = debuggerReadByte(addr+3); | |
1294 int e = debuggerReadByte(addr+4); | |
1295 int f = debuggerReadByte(addr+5); | |
1296 int g = debuggerReadByte(addr+6); | |
1297 int h = debuggerReadByte(addr+7); | |
1298 int i = debuggerReadByte(addr+8); | |
1299 int j = debuggerReadByte(addr+9); | |
1300 int k = debuggerReadByte(addr+10); | |
1301 int l = debuggerReadByte(addr+11); | |
1302 int m = debuggerReadByte(addr+12); | |
1303 int n = debuggerReadByte(addr+13); | |
1304 int o = debuggerReadByte(addr+14); | |
1305 int p = debuggerReadByte(addr+15); | |
1306 | |
1307 printf("%08x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", | |
1308 addr,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p, | |
1309 ASCII(a),ASCII(b),ASCII(c),ASCII(d), | |
1310 ASCII(e),ASCII(f),ASCII(g),ASCII(h), | |
1311 ASCII(i),ASCII(j),ASCII(k),ASCII(l), | |
1312 ASCII(m),ASCII(n),ASCII(o),ASCII(p)); | |
1313 addr += 16; | |
1314 } | |
1315 } else | |
1316 debuggerUsage("mb"); | |
1317 } | |
1318 | |
1319 void debuggerMemoryHalfWord(int n, char **args) | |
1320 { | |
1321 if(n == 2) { | |
1322 u32 addr = 0; | |
1323 sscanf(args[1], "%x", &addr); | |
1324 addr = addr & 0xfffffffe; | |
1325 for(int ii = 0; ii < 16; ii++) { | |
1326 int a = debuggerReadByte(addr); | |
1327 int b = debuggerReadByte(addr+1); | |
1328 int c = debuggerReadByte(addr+2); | |
1329 int d = debuggerReadByte(addr+3); | |
1330 int e = debuggerReadByte(addr+4); | |
1331 int f = debuggerReadByte(addr+5); | |
1332 int g = debuggerReadByte(addr+6); | |
1333 int h = debuggerReadByte(addr+7); | |
1334 int i = debuggerReadByte(addr+8); | |
1335 int j = debuggerReadByte(addr+9); | |
1336 int k = debuggerReadByte(addr+10); | |
1337 int l = debuggerReadByte(addr+11); | |
1338 int m = debuggerReadByte(addr+12); | |
1339 int n = debuggerReadByte(addr+13); | |
1340 int o = debuggerReadByte(addr+14); | |
1341 int p = debuggerReadByte(addr+15); | |
1342 | |
1343 printf("%08x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", | |
1344 addr,b,a,d,c,f,e,h,g,j,i,l,k,n,m,p,o, | |
1345 ASCII(a),ASCII(b),ASCII(c),ASCII(d), | |
1346 ASCII(e),ASCII(f),ASCII(g),ASCII(h), | |
1347 ASCII(i),ASCII(j),ASCII(k),ASCII(l), | |
1348 ASCII(m),ASCII(n),ASCII(o),ASCII(p)); | |
1349 addr += 16; | |
1350 } | |
1351 } else | |
1352 debuggerUsage("mh"); | |
1353 } | |
1354 | |
1355 void debuggerMemory(int n, char **args) | |
1356 { | |
1357 if(n == 2) { | |
1358 u32 addr = 0; | |
1359 sscanf(args[1], "%x", &addr); | |
1360 addr = addr & 0xfffffffc; | |
1361 for(int ii = 0; ii < 16; ii++) { | |
1362 int a = debuggerReadByte(addr); | |
1363 int b = debuggerReadByte(addr+1); | |
1364 int c = debuggerReadByte(addr+2); | |
1365 int d = debuggerReadByte(addr+3); | |
1366 | |
1367 int e = debuggerReadByte(addr+4); | |
1368 int f = debuggerReadByte(addr+5); | |
1369 int g = debuggerReadByte(addr+6); | |
1370 int h = debuggerReadByte(addr+7); | |
1371 | |
1372 int i = debuggerReadByte(addr+8); | |
1373 int j = debuggerReadByte(addr+9); | |
1374 int k = debuggerReadByte(addr+10); | |
1375 int l = debuggerReadByte(addr+11); | |
1376 | |
1377 int m = debuggerReadByte(addr+12); | |
1378 int n = debuggerReadByte(addr+13); | |
1379 int o = debuggerReadByte(addr+14); | |
1380 int p = debuggerReadByte(addr+15); | |
1381 | |
1382 printf("%08x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", | |
1383 addr,d,c,b,a,h,g,f,e,l,k,j,i,p,o,n,m, | |
1384 ASCII(a),ASCII(b),ASCII(c),ASCII(d), | |
1385 ASCII(e),ASCII(f),ASCII(g),ASCII(h), | |
1386 ASCII(i),ASCII(j),ASCII(k),ASCII(l), | |
1387 ASCII(m),ASCII(n),ASCII(o),ASCII(p)); | |
1388 addr += 16; | |
1389 } | |
1390 } else | |
1391 debuggerUsage("mw"); | |
1392 } | |
1393 | |
1394 void debuggerQuit(int, char **) | |
1395 { | |
1396 char buffer[10]; | |
1397 printf("Are you sure you want to quit (y/n)? "); | |
1398 fgets(buffer, 1024, stdin); | |
1399 | |
1400 if(buffer[0] == 'y' || buffer[0] == 'Y') { | |
1401 debugger = false; | |
1402 emulating = false; | |
1403 } | |
1404 } | |
1405 | |
1406 void debuggerOutput(char *s, u32 addr) | |
1407 { | |
1408 if(s) | |
1409 puts(s); | |
1410 else { | |
1411 char c; | |
1412 | |
1413 c = debuggerReadByte(addr); | |
1414 addr++; | |
1415 while(c) { | |
1416 putchar(c); | |
1417 c = debuggerReadByte(addr); | |
1418 addr++; | |
1419 } | |
1420 } | |
1421 } | |
1422 | |
1423 void debuggerMain() | |
1424 { | |
1425 char buffer[1024]; | |
1426 char *commands[10]; | |
1427 int commandCount = 0; | |
1428 | |
1429 if(theEmulator.emuUpdateCPSR) | |
1430 theEmulator.emuUpdateCPSR(); | |
1431 debuggerRegisters(0, NULL); | |
1432 | |
1433 while(debugger) { | |
1434 systemSoundPause(); | |
1435 printf("debugger> "); | |
1436 commandCount = 0; | |
1437 char *s = fgets(buffer, 1024, stdin); | |
1438 | |
1439 commands[0] = strtok(s, " \t\n"); | |
1440 if(commands[0] == NULL) | |
1441 continue; | |
1442 commandCount++; | |
1443 while((s = strtok(NULL, " \t\n"))) { | |
1444 commands[commandCount++] = s; | |
1445 if(commandCount == 10) | |
1446 break; | |
1447 } | |
1448 | |
1449 for(int j = 0; ; j++) { | |
1450 if(debuggerCommands[j].name == NULL) { | |
1451 printf("Unrecognized command %s. Type h for help.\n", commands[0]); | |
1452 break; | |
1453 } | |
1454 if(!strcmp(commands[0], debuggerCommands[j].name)) { | |
1455 debuggerCommands[j].function(commandCount, commands); | |
1456 break; | |
1457 } | |
1458 } | |
1459 } | |
1460 } |