Annotation of hatari/src/debugui.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.