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