// // Created by imanol on 12/26/16. // #include #include #include "debug.h" #include uint32_t cycle_count = 0; uint8_t breakpoint = 1; uint16_t breakpoints[0xFF]; uint16_t nbpoints = 0; char lastchoice = 0; uint8_t terminate = 0; uint8_t break_on_next = 0; void to_debugger(int signal) { if(signal == SIGINT) { fprintf(stderr,"CTRL+C hit. Falling to debugger (Press enter if in the middle of input)\n"); breakpoint = 1; return; } core_dump(); } void load_state(char *filename) { FILE *state = fopen(filename,"r"); uint16_t regsdump[NUM_REGISTERS+1]; uint16_t memdump[MEMSIZE]; uint16_t *stackdump; uint32_t stacksize; long stackpos; fread(regsdump,sizeof(uint16_t),NUM_REGISTERS+1,state); fread(memdump,sizeof(uint16_t),MEMSIZE,state); stackpos = ftell(state); fseek(state,0,SEEK_END); stacksize = (ftell(state) - stackpos)/sizeof(uint16_t); stackdump = calloc(stacksize,sizeof(uint16_t)); fseek(state,stackpos,SEEK_SET); fread(stackdump,sizeof(uint16_t),stacksize,state); fclose(state); load_regs(regsdump); load_memory(memdump); stack_load(stackdump,stacksize); free(stackdump); } void save_state(char *filename) { FILE *state = fopen(filename,"w"); uint16_t regsdump[NUM_REGISTERS+1]; uint16_t memdump[MEMSIZE]; uint16_t *stackdump; uint32_t stacksize; dump_regs(regsdump); dump_memory(memdump); stacksize = stack_dump(&stackdump); fwrite(regsdump,sizeof(uint16_t),NUM_REGISTERS+1,state); fwrite(memdump,sizeof(uint16_t),MEMSIZE,state); fwrite(stackdump,sizeof(uint16_t),stacksize,state); fclose(state); free(stackdump); } void query() { uint8_t end = 0; uint16_t bpoint; uint16_t mempos; char input[100] = {0}; char filename[32]; uint8_t reg; uint16_t value; while(!end) { printf("\n> "); char command = 0; fgets(input,100,stdin); command = input[0]; //FIXME: Input is not validated in any way. Crashes *will* occur on misuse. Have fun! if (command != '\n') { lastchoice = command; } else { command = lastchoice; } switch (command) { case 'b': sscanf(input,"b %hx\n",&bpoint); fprintf(stderr,"Set breakpoint %hu to %hx",nbpoints,bpoint); breakpoints[nbpoints] = bpoint; nbpoints = (uint16_t)(nbpoints + 1 % 0xFF); break; case 'd': sscanf(input,"d %hu\n",&bpoint); fprintf(stderr,"Deleted breakpoint %hu",bpoint); breakpoints[bpoint] = 0; break; case 'c': breakpoint = 0; end = 1; break; case 'n': break_on_next = 1; end = 1; break; case 'r': print_regs(); break; case 'm': sscanf(input,"m %hX\n",&mempos); fprintf(stderr,"%02X: %02x\n",mempos,mem[mempos]); break; case 't': sscanf(input,"t %s\n",filename); save_state(filename); fprintf(stderr,"Saved state as %s",filename); break; case 's': end = 1; break; case 'l': sscanf(input,"l %s\n",filename); load_state(filename); fprintf(stderr,"Loaded state as %s",filename); break; case 'w': sscanf(input,"w r%hhu %hu\n",®,&value); fprintf(stderr,"Setting r%hhu = %02X",reg,value); regs[reg] = value; break; case 'q': terminate = 1; end = 1; break; case 'h': //print_debug_commands(); break; default: break; } } } uint8_t in_breakpoint(uint16_t pc) { uint8_t i; for(i = 0; i < nbpoints; i++) { if(breakpoints[i] == pc) { return 1; } } return 0; } uint16_t fetch_debug() { uint16_t value = mem[pc++]; return value; } void translate_args(uint16_t a1, uint16_t a2, uint16_t a3, char *arg1, char *arg2, char *arg3) { if(a1 > MAX_INT) { sprintf(arg1,"r%d",a1-(MAX_INT+1)); } else { sprintf(arg1,"%02X",a1); } if(a2 > MAX_INT) { sprintf(arg2,"r%d",a2-(MAX_INT+1)); } else { sprintf(arg2,"%02X",a2); } if(a3 > MAX_INT) { sprintf(arg3,"r%d",a3-(MAX_INT+1)); } else { sprintf(arg3,"%02X",a3); } } void print_instruction(uint16_t opcode, uint16_t a1, uint16_t a2, uint16_t a3) { char arg1[10]; char arg2[10]; char arg3[10]; translate_args(a1,a2,a3,arg1,arg2,arg3); switch(opcode) { case HALT: fprintf(stderr, "HALT\n"); break; case MOV: fprintf(stderr, "MOV %s %s\n", arg1, arg2); break; case PUSH: fprintf(stderr, "PUSH %s\n", arg1); break; case POP: fprintf(stderr, "POP %s\n", arg1); break; case TEQ: fprintf(stderr, "TEQ %s %s %s\n", arg1, arg2, arg3); break; case TGT: fprintf(stderr, "TGT %s %s %s\n", arg1, arg2, arg3); break; case JMP: fprintf(stderr, "JMP %s\n", arg1); break; case JNZ: fprintf(stderr, "JNZ %s %s\n", arg1, arg2); break; case JZ: fprintf(stderr, "JZ %s %s\n", arg1, arg2); break; case ADD: fprintf(stderr, "ADD %s %s %s\n", arg1, arg2, arg3); break; case MUL: fprintf(stderr, "MUL %s %s %s\n", arg1, arg2, arg3); break; case MOD: fprintf(stderr, "MOD %s %s %s\n", arg1, arg2, arg3); break; case AND: fprintf(stderr, "AND %s %s %s\n", arg1, arg2, arg3); break; case OR: fprintf(stderr, "OR %s %s %s\n", arg1, arg2, arg3); break; case NOT: fprintf(stderr, "NOT %s %s\n", arg1, arg2); break; case LOAD: fprintf(stderr, "LOAD %s %s\n", arg1, arg2); break; case STOR: fprintf(stderr, "STOR %s %s\n", arg1, arg2); break; case CALL: fprintf(stderr, "CALL %s\n", arg1); break; case RET: fprintf(stderr, "RET\n"); break; case OUT: if (a1 <= MAX_INT) { fprintf(stderr, "OUT '%c'\n",a1); } else { fprintf(stderr, "OUT %s\n", arg1); } break; case IN: fprintf(stderr,"IN %s\n",arg1); break; case NOP: fprintf(stderr,"NOP\n"); break; default: fprintf(stderr,"UNK %02X\n", opcode); break; } } void debug_program() { signal(SIGINT, to_debugger); memset(breakpoints,0x00,0xFF); uint16_t arg1; uint16_t arg2; uint16_t arg3; for(;;) { cycle_count++; if(in_breakpoint(pc)) { breakpoint = 1; fprintf(stderr,"Breakpoint hit @ pc=%X\n",pc); } if(breakpoint) { break_on_next = 0; fprintf(stderr, "cycle: %d\n", cycle_count); fprintf(stderr, "%02X: ", pc); print_instruction(mem[pc], mem[pc+1], mem[pc+2], mem[pc+3]); if(stdin_length()) { read_input(); } query(); if(terminate) { return; } } uint16_t opcode = fetch_debug(); if(opcode == CALL && break_on_next != 0) { breakpoint = 0; break_on_next++; } else if(opcode == RET && break_on_next != 0) { if(--break_on_next == 1) { breakpoint = 1; break_on_next = 0; } } decode_instruction(opcode, &arg1, &arg2, &arg3); if (execute_instruction(opcode, arg1, arg2, arg3)) { return; } } }