view src/sdl/debugger.cpp @ 359:8c474d1d6956

script: got leomnades and TM13, shopping is complete.
author Robert McIntyre <rlm@mit.edu>
date Mon, 09 Apr 2012 08:27:45 -0500
parents f9f4f1b99eed
children
line wrap: on
line source
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
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.
19 extern "C" {
20 #include <stdio.h>
21 #include <stdlib.h>
22 } // FIXME: should use c++ headers instead
24 #include <string.h>
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"
35 extern bool debugger;
36 extern int emulating;
38 extern struct EmulatedSystem theEmulator;
40 #define debuggerReadMemory(addr) \
41 READ32LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
43 #define debuggerReadHalfWord(addr) \
44 READ16LE((&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
46 #define debuggerReadByte(addr) \
47 map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
49 #define debuggerWriteMemory(addr, value) \
50 WRITE32LE(&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], value)
52 #define debuggerWriteHalfWord(addr, value) \
53 WRITE16LE(&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask], value)
55 #define debuggerWriteByte(addr, value) \
56 map[(addr)>>24].address[(addr) & map[(addr)>>24].mask] = (value)
58 struct breakpointInfo {
59 u32 address;
60 u32 value;
61 int size;
62 };
64 struct DebuggerCommand {
65 const char *name;
66 void (*function)(int,char **);
67 const char *help;
68 const char *syntax;
69 };
71 void debuggerContinueAfterBreakpoint();
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 **);
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 };
141 breakpointInfo debuggerBreakpointList[100];
143 int debuggerNumOfBreakpoints = 0;
144 bool debuggerAtBreakpoint = false;
145 int debuggerBreakpointNumber = 0;
146 int debuggerRadix = 0;
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 }
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 }
171 void debuggerEnableBreakpoints(bool skipPC)
172 {
173 for(int i = 0; i < debuggerNumOfBreakpoints; i++) {
174 if(debuggerBreakpointList[i].address == armNextPC && skipPC)
175 continue;
177 debuggerApplyBreakpoint(debuggerBreakpointList[i].address,
178 i,
179 debuggerBreakpointList[i].size);
180 }
181 }
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 }
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 }
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 }
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 }
296 char *debuggerPrintType(Type *t)
297 {
298 char buffer[1024];
299 static char buffer2[1024];
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 }
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);
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 }
334 void debuggerPrintPointer(Type *t, u32 value)
335 {
336 printf("(%s)0x%08x", debuggerPrintType(t), value);
337 }
339 void debuggerPrintReference(Type *t, u32 value)
340 {
341 printf("(%s)0x%08x", debuggerPrintType(t), value);
342 }
344 void debuggerPrintFunction(Type *t, u32 value)
345 {
346 printf("(%s)0x%08x", debuggerPrintType(t), value);
347 }
349 void debuggerPrintArray(Type *t, u32 value)
350 {
351 // todo
352 printf("(%s[])0x%08x", debuggerPrintType(t->array->type), value);
353 }
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);
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 }
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 }
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 }
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 }
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 }
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 }
504 debuggerPrintValueInternal(f, t, bitSize, bitOffset, location, type);
505 }
507 void debuggerPrintValue(Function *f, Object *o)
508 {
509 debuggerPrintValueInternal(f, o->type, o->location, 0, 0, 0);
511 printf("\n");
512 }
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;
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 }
559 void debuggerSetRadix(int argc, char **argv)
560 {
561 if(argc != 2)
562 debuggerUsage(argv[0]);
563 else {
564 int r = atoi(argv[1]);
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 }
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;
596 elfGetCurrentFunction(pc,
597 &f, &u);
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 }
618 char *s = argc == 2 ? argv[1] : argv[2];
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 }
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 }
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 }
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 }
692 void debuggerWhere(int n, char **args)
693 {
694 void elfPrintCallChain(u32);
695 elfPrintCallChain(armNextPC);
696 }
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 }
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 }
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);
749 printf("File %s, function %s, line %d\n", file, f->name,
750 line);
751 }
752 debuggerRegisters(0, NULL);
753 }
755 void debuggerContinue(int n, char **args)
756 {
757 if(debuggerAtBreakpoint)
758 debuggerContinueAfterBreakpoint();
759 debuggerEnableBreakpoints(false);
760 debugger = false;
761 }
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();
780 Function *f = NULL;
781 CompileUnit *u = NULL;
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 }
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 }
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 }
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);
846 u32 addr;
847 Function *f;
848 CompileUnit *u;
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;
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 }
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 }
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 }
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]);
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 }
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 }
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);
994 if(address < 0x2000000 || address > 0x3007fff) {
995 printf("Invalid address: %08x\n", address);
996 return;
997 }
999 if(address > 0x203ffff && address < 0x3000000) {
1000 printf("Invalid address: %08x\n", address);
1001 return;
1004 u32 final = address + n;
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;
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++;
1021 } else
1022 debuggerUsage("bpw");
1025 void debuggerDisassembleArm(int n, char **args)
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);
1034 if(pc & 3) {
1035 printf("Misaligned address %08x\n", pc);
1036 pc &= 0xfffffffc;
1038 if(n >= 3) {
1039 sscanf(args[2], "%d", &count);
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;
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);
1057 void debuggerDisassembleThumb(int n, char **args)
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);
1066 if(pc & 1) {
1067 printf("Misaligned address %08x\n", pc);
1068 pc &= 0xfffffffe;
1070 if(n >= 3) {
1071 sscanf(args[2], "%d", &count);
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;
1082 sprintf(format, "%%08x %%-%ds %%s\n", len);
1084 for(i = 0; i < count; i++) {
1085 u32 addr = pc;
1086 pc += disThumb(pc, buffer, 2);
1087 printf(format, addr, elfGetAddressSymbol(addr), buffer);
1091 void debuggerDisassemble(int n, char **args)
1093 if(armState)
1094 debuggerDisassembleArm(n, args);
1095 else
1096 debuggerDisassembleThumb(n, args);
1099 void debuggerContinueAfterBreakpoint()
1101 printf("Continuing after breakpoint\n");
1102 debuggerEnableBreakpoints(true);
1103 theEmulator.emuMain(1);
1104 debuggerAtBreakpoint = false;
1107 void debuggerRegisters(int, char **)
1109 char *command[3];
1110 char buffer[10];
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);
1137 void debuggerIoVideo()
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);
1158 void debuggerIoVideo2()
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);
1182 void debuggerIoDMA()
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);
1198 void debuggerIoTimer()
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);
1210 void debuggerIoMisc()
1212 printf("P1 = %04x\n", P1);
1213 printf("IE = %04x\n", IE);
1214 printf("IF = %04x\n", IF);
1215 printf("IME = %04x\n", IME);
1218 void debuggerIo(int n, char **args)
1220 if(n == 1) {
1221 debuggerIoVideo();
1222 return;
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]);
1237 void debuggerEditByte(int n, char **args)
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");
1249 void debuggerEditHalfWord(int n, char **args)
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;
1259 sscanf(args[2], "%x", &byte);
1260 debuggerWriteHalfWord(address, (u16)byte);
1261 } else
1262 debuggerUsage("eh");
1265 void debuggerEdit(int n, char **args)
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;
1275 sscanf(args[2], "%x", &byte);
1276 debuggerWriteMemory(address, (u32)byte);
1277 } else
1278 debuggerUsage("ew");
1282 #define ASCII(c) (c) < 32 ? '.' : (c) > 127 ? '.' : (c)
1284 void debuggerMemoryByte(int n, char **args)
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);
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;
1315 } else
1316 debuggerUsage("mb");
1319 void debuggerMemoryHalfWord(int n, char **args)
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);
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;
1351 } else
1352 debuggerUsage("mh");
1355 void debuggerMemory(int n, char **args)
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);
1367 int e = debuggerReadByte(addr+4);
1368 int f = debuggerReadByte(addr+5);
1369 int g = debuggerReadByte(addr+6);
1370 int h = debuggerReadByte(addr+7);
1372 int i = debuggerReadByte(addr+8);
1373 int j = debuggerReadByte(addr+9);
1374 int k = debuggerReadByte(addr+10);
1375 int l = debuggerReadByte(addr+11);
1377 int m = debuggerReadByte(addr+12);
1378 int n = debuggerReadByte(addr+13);
1379 int o = debuggerReadByte(addr+14);
1380 int p = debuggerReadByte(addr+15);
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;
1390 } else
1391 debuggerUsage("mw");
1394 void debuggerQuit(int, char **)
1396 char buffer[10];
1397 printf("Are you sure you want to quit (y/n)? ");
1398 fgets(buffer, 1024, stdin);
1400 if(buffer[0] == 'y' || buffer[0] == 'Y') {
1401 debugger = false;
1402 emulating = false;
1406 void debuggerOutput(char *s, u32 addr)
1408 if(s)
1409 puts(s);
1410 else {
1411 char c;
1413 c = debuggerReadByte(addr);
1414 addr++;
1415 while(c) {
1416 putchar(c);
1417 c = debuggerReadByte(addr);
1418 addr++;
1423 void debuggerMain()
1425 char buffer[1024];
1426 char *commands[10];
1427 int commandCount = 0;
1429 if(theEmulator.emuUpdateCPSR)
1430 theEmulator.emuUpdateCPSR();
1431 debuggerRegisters(0, NULL);
1433 while(debugger) {
1434 systemSoundPause();
1435 printf("debugger> ");
1436 commandCount = 0;
1437 char *s = fgets(buffer, 1024, stdin);
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;
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;
1454 if(!strcmp(commands[0], debuggerCommands[j].name)) {
1455 debuggerCommands[j].function(commandCount, commands);
1456 break;