Mercurial > vba-linux
view src/sdl/debugger.cpp @ 37:9eae224b8056 recording-sans-reset
reseting the movie does not appear to work
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Mon, 05 Mar 2012 14:51:43 -0600 |
parents | f9f4f1b99eed |
children |
line wrap: on
line source
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.2 // Copyright (C) 1999-2003 Forgotten3 // Copyright (C) 2004 Forgotten and the VBA development team5 // This program is free software; you can redistribute it and/or modify6 // it under the terms of the GNU General Public License as published by7 // 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 of12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 // GNU General Public License for more details.14 //15 // You should have received a copy of the GNU General Public License16 // 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 instead24 #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_VERSION132 { "trace", debuggerDebug, "Sets the trace level", "<value>" },133 #endif134 #ifdef DEV_VERSION135 { "verbose", debuggerVerbose, "Change verbose setting", "<value>" },136 #endif137 { "where", debuggerWhere, "Shows call chain", NULL },138 { NULL, NULL, NULL, NULL} // end marker139 };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 else155 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 else166 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 else262 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 else305 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 // todo352 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 else390 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 // todo422 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 else498 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 else634 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 } else665 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 } else678 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 } else689 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 } else739 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 } else829 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 else915 printf("Added THUMB breakpoint at %08x\n", address);916 } else {917 printf("%s is not a function symbol\n", args[1]);918 }919 } else920 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 } else936 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 } else952 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 else961 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 else970 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;1002 }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;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 else1018 freezeInternalRAM[address & 0x7fff] = true;1019 address++;1020 }1021 } else1022 debuggerUsage("bpw");1023 }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 }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 }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);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 }1091 void debuggerDisassemble(int n, char **args)1092 {1093 if(armState)1094 debuggerDisassembleArm(n, args);1095 else1096 debuggerDisassembleThumb(n, args);1097 }1099 void debuggerContinueAfterBreakpoint()1100 {1101 printf("Continuing after breakpoint\n");1102 debuggerEnableBreakpoints(true);1103 theEmulator.emuMain(1);1104 debuggerAtBreakpoint = false;1105 }1107 void debuggerRegisters(int, char **)1108 {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);1135 }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 }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 }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 }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 }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 }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 }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 } else1246 debuggerUsage("eb");1247 }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 } else1262 debuggerUsage("eh");1263 }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 } else1278 debuggerUsage("ew");1279 }1282 #define ASCII(c) (c) < 32 ? '.' : (c) > 127 ? '.' : (c)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);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 } else1316 debuggerUsage("mb");1317 }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);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 } else1352 debuggerUsage("mh");1353 }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);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;1389 }1390 } else1391 debuggerUsage("mw");1392 }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);1400 if(buffer[0] == 'y' || buffer[0] == 'Y') {1401 debugger = false;1402 emulating = false;1403 }1404 }1406 void debuggerOutput(char *s, u32 addr)1407 {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++;1419 }1420 }1421 }1423 void debuggerMain()1424 {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;1447 }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 }