# HG changeset patch # User Michael Pavone # Date 1493092171 25200 # Node ID 85a90964b5575ef984e2c37e0f53a1e5b4bc34bb # Parent 70faad89d491a6a8efaece17d0c59b7240fb0232 Fix interaction between 68K debugger and instruction retranslation due to self modifying code or bank switching diff -r 70faad89d491 -r 85a90964b557 debug.c --- a/debug.c Sun Apr 23 00:54:33 2017 -0700 +++ b/debug.c Mon Apr 24 20:49:31 2017 -0700 @@ -885,7 +885,7 @@ } -m68k_context * debugger(m68k_context * context, uint32_t address) +void debugger(m68k_context * context, uint32_t address) { static char last_cmd[1024]; char input_buf[1024]; @@ -938,7 +938,7 @@ if (debugging) { printf("68K Breakpoint %d hit\n", (*this_bp)->index); } else { - return context; + return; } } else { remove_breakpoint(context, address); @@ -986,5 +986,5 @@ } debugging = run_debugger_command(context, input_buf, inst, after); } - return context; + return; } diff -r 70faad89d491 -r 85a90964b557 debug.h --- a/debug.h Sun Apr 23 00:54:33 2017 -0700 +++ b/debug.h Mon Apr 24 20:49:31 2017 -0700 @@ -23,7 +23,7 @@ bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index); void add_display(disp_def ** head, uint32_t *index, char format_char, char * param); void remove_display(disp_def ** head, uint32_t index); -m68k_context * debugger(m68k_context * context, uint32_t address); +void debugger(m68k_context * context, uint32_t address); z80_context * zdebugger(z80_context * context, uint16_t address); #endif //DEBUG_H_ diff -r 70faad89d491 -r 85a90964b557 gdb_remote.c --- a/gdb_remote.c Sun Apr 23 00:54:33 2017 -0700 +++ b/gdb_remote.c Mon Apr 24 20:49:31 2017 -0700 @@ -474,7 +474,7 @@ fatal_error("Command %s is not implemented, exiting...\n", command); } -m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc) +void gdb_debug_enter(m68k_context * context, uint32_t pc) { dfprintf(stderr, "Entered debugger at address %X\n", pc); if (expect_break_response) { @@ -556,7 +556,6 @@ curbuf = NULL; } } - return context; } #ifdef _WIN32 diff -r 70faad89d491 -r 85a90964b557 gdb_remote.h --- a/gdb_remote.h Sun Apr 23 00:54:33 2017 -0700 +++ b/gdb_remote.h Mon Apr 24 20:49:31 2017 -0700 @@ -3,6 +3,6 @@ #include "genesis.h" void gdb_remote_init(void); -m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc); +void gdb_debug_enter(m68k_context * context, uint32_t pc); #endif //GDB_REMOTE_H_ diff -r 70faad89d491 -r 85a90964b557 m68k_core.c --- a/m68k_core.c Sun Apr 23 00:54:33 2017 -0700 +++ b/m68k_core.c Mon Apr 24 20:49:31 2017 -0700 @@ -780,6 +780,49 @@ return 0xFFFF; } +static m68k_debug_handler find_breakpoint(m68k_context *context, uint32_t address) +{ + for (uint32_t i = 0; i < context->num_breakpoints; i++) + { + if (context->breakpoints[i].address == address) { + return context->breakpoints[i].handler; + } + } + return NULL; +} + +void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler) +{ + if (!find_breakpoint(context, address)) { + if (context->bp_storage == context->num_breakpoints) { + context->bp_storage *= 2; + if (context->bp_storage < 4) { + context->bp_storage = 4; + } + context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(m68k_breakpoint)); + } + context->breakpoints[context->num_breakpoints++] = (m68k_breakpoint){ + .handler = bp_handler, + .address = address + }; + m68k_breakpoint_patch(context, address, bp_handler, NULL); + } +} + +m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address) +{ + m68k_debug_handler handler = find_breakpoint(context, address); + if (handler) { + handler(context, address); + } else { + //spurious breakoint? + warning("Spurious breakpoing at %X\n", address); + remove_breakpoint(context, address); + } + + return context; +} + typedef enum { RAW_FUNC = 1, BINARY_ARITH, @@ -895,13 +938,21 @@ RAW_IMPL(M68K_TAS, translate_m68k_tas), }; -static void translate_m68k(m68k_options * opts, m68kinst * inst) +static void translate_m68k(m68k_context *context, m68kinst * inst) { + m68k_options * opts = context->options; if (inst->address & 1) { translate_m68k_odd(opts, inst); return; } + code_ptr start = opts->gen.code.cur; check_cycles_int(&opts->gen, inst->address); + + m68k_debug_handler bp; + if ((bp = find_breakpoint(context, inst->address))) { + m68k_breakpoint_patch(context, inst->address, bp, start); + } + //log_address(&opts->gen, inst->address, "M68K: %X @ %d\n"); if ( (inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE) @@ -981,7 +1032,7 @@ //make sure the beginning of the code for an instruction is contiguous check_code_prologue(code); code_ptr start = code->cur; - translate_m68k(opts, &instbuf); + translate_m68k(context, &instbuf); code_ptr after = code->cur; map_native_address(context, instbuf.address, start, m68k_size, after-start); } while(!m68k_is_terminal(&instbuf) && !(address & 1)); @@ -1009,7 +1060,7 @@ //make sure we have enough code space for the max size instruction check_alloc_code(code, MAX_NATIVE_SIZE); code_ptr native_start = code->cur; - translate_m68k(opts, &instbuf); + translate_m68k(context, &instbuf); code_ptr native_end = code->cur; /*uint8_t is_terminal = m68k_is_terminal(&instbuf); if ((native_end - native_start) <= orig_size) { @@ -1025,7 +1076,7 @@ tmp.last = code->last; code->cur = orig_code.cur; code->last = orig_code.last; - translate_m68k(opts, &instbuf); + translate_m68k(context, &instbuf); native_end = orig_code.cur = code->cur; code->cur = tmp.cur; code->last = tmp.last; @@ -1056,7 +1107,7 @@ } else { code_info tmp = *code; *code = orig_code; - translate_m68k(opts, &instbuf); + translate_m68k(context, &instbuf); orig_code = *code; *code = tmp; if (!m68k_is_terminal(&instbuf)) { @@ -1079,7 +1130,20 @@ void remove_breakpoint(m68k_context * context, uint32_t address) { + for (uint32_t i = 0; i < context->num_breakpoints; i++) + { + if (context->breakpoints[i].address == address) { + if (i != (context->num_breakpoints-1)) { + context->breakpoints[i] = context->breakpoints[context->num_breakpoints-1]; + } + context->num_breakpoints--; + break; + } + } code_ptr native = get_native_address(context->options, address); + if (!native) { + return; + } code_info tmp = context->options->gen.code; context->options->gen.code.cur = native; context->options->gen.code.last = native + MAX_NATIVE_SIZE; diff -r 70faad89d491 -r 85a90964b557 m68k_core.h --- a/m68k_core.h Sun Apr 23 00:54:33 2017 -0700 +++ b/m68k_core.h Mon Apr 24 20:49:31 2017 -0700 @@ -56,13 +56,23 @@ code_ptr get_sr; code_ptr set_sr; code_ptr set_ccr; + code_ptr bp_stub; code_info extra_code; movem_fun *big_movem; uint32_t num_movem; uint32_t movem_storage; + code_word prologue_start; } m68k_options; -typedef struct m68k_context { +typedef struct m68k_context m68k_context; +typedef void (*m68k_debug_handler)(m68k_context *context, uint32_t pc); + +typedef struct { + m68k_debug_handler handler; + uint32_t address; +} m68k_breakpoint; + +struct m68k_context { uint8_t flags[5]; uint8_t status; uint16_t int_ack; @@ -79,14 +89,17 @@ code_ptr reset_handler; m68k_options *options; void *system; + m68k_breakpoint *breakpoints; + uint32_t num_breakpoints; + uint32_t bp_storage; uint8_t int_pending; uint8_t trace_pending; uint8_t should_return; uint8_t ram_code_flags[]; -} m68k_context; +}; typedef m68k_context *(*m68k_reset_handler)(m68k_context *context); -typedef m68k_context *(*m68k_debug_handler)(m68k_context *context, uint32_t pc); + void translate_m68k_stream(uint32_t address, m68k_context * context); void start_68k_context(m68k_context * context, uint32_t address); diff -r 70faad89d491 -r 85a90964b557 m68k_core_x86.c --- a/m68k_core_x86.c Sun Apr 23 00:54:33 2017 -0700 +++ b/m68k_core_x86.c Mon Apr 24 20:49:31 2017 -0700 @@ -2484,51 +2484,27 @@ } } -void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler) +void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr) { - static code_ptr bp_stub = NULL; m68k_options * opts = context->options; code_info native; - native.cur = get_native_address_trans(context, address); + native.cur = native_addr ? native_addr : get_native_address(context->options, address); + + if (!native.cur) { + return; + } + + if (*native.cur != opts->prologue_start) { + //instruction has already been patched, probably for retranslation + return; + } native.last = native.cur + 128; native.stack_off = 0; code_ptr start_native = native.cur; mov_ir(&native, address, opts->gen.scratch1, SZ_D); - if (!bp_stub) { - code_info *code = &opts->gen.code; - check_code_prologue(code); - bp_stub = code->cur; - call(&native, bp_stub); - - uint32_t tmp_stack_off = code->stack_off; - //Calculate length of prologue - check_cycles_int(&opts->gen, address); - int check_int_size = code->cur-bp_stub; - code->cur = bp_stub; - code->stack_off = tmp_stack_off; - - //Save context and call breakpoint handler - call(code, opts->gen.save_context); - push_r(code, opts->gen.scratch1); - call_args_abi(code, (code_ptr)bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); - mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); - //Restore context - call(code, opts->gen.load_context); - pop_r(code, opts->gen.scratch1); - //do prologue stuff - cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); - code_ptr jmp_off = code->cur + 1; - jcc(code, CC_NC, code->cur + 7); - call(code, opts->gen.handle_cycle_limit_int); - *jmp_off = code->cur - (jmp_off+1); - //jump back to body of translated instruction - pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - (native.cur-start_native), opts->gen.scratch1, SZ_PTR); - jmp_r(code, opts->gen.scratch1); - code->stack_off = tmp_stack_off; - } else { - call(&native, bp_stub); - } + + + call(&native, opts->bp_stub); } void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider) @@ -3129,4 +3105,42 @@ mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); call(code, opts->gen.load_context); jmp_r(code, opts->gen.scratch1); + + + check_code_prologue(code); + opts->bp_stub = code->cur; + + tmp_stack_off = code->stack_off; + //Calculate length of prologue + check_cycles_int(&opts->gen, 0x1234); + int check_int_size = code->cur-opts->bp_stub; + code->cur = opts->bp_stub; + code->stack_off = tmp_stack_off; + opts->prologue_start = *opts->bp_stub; + //Calculate length of patch + mov_ir(code, 0x1234, opts->gen.scratch1, SZ_D); + call(code, opts->bp_stub); + int patch_size = code->cur - opts->bp_stub; + code->cur = opts->bp_stub; + code->stack_off = tmp_stack_off; + + //Save context and call breakpoint handler + call(code, opts->gen.save_context); + push_r(code, opts->gen.scratch1); + call_args_abi(code, (code_ptr)m68k_bp_dispatcher, 2, opts->gen.context_reg, opts->gen.scratch1); + mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); + //Restore context + call(code, opts->gen.load_context); + pop_r(code, opts->gen.scratch1); + //do prologue stuff + cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); + code_ptr jmp_off = code->cur + 1; + jcc(code, CC_NC, code->cur + 7); + call(code, opts->gen.handle_cycle_limit_int); + *jmp_off = code->cur - (jmp_off+1); + //jump back to body of translated instruction + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR); + jmp_r(code, opts->gen.scratch1); + code->stack_off = tmp_stack_off; } diff -r 70faad89d491 -r 85a90964b557 m68k_internal.h --- a/m68k_internal.h Sun Apr 23 00:54:33 2017 -0700 +++ b/m68k_internal.h Mon Apr 24 20:49:31 2017 -0700 @@ -35,6 +35,7 @@ void m68k_set_last_prefetch(m68k_options *opts, uint32_t address); void translate_m68k_odd(m68k_options *opts, m68kinst *inst); void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst); +void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr); //functions implemented in m68k_core.c int8_t native_reg(m68k_op_info * op, m68k_options * opts); @@ -51,6 +52,7 @@ uint8_t m68k_is_terminal(m68kinst * inst); code_ptr get_native_address_trans(m68k_context * context, uint32_t address); void * m68k_retranslate_inst(uint32_t address, m68k_context * context); +m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address); //individual instructions void translate_m68k_bcc(m68k_options * opts, m68kinst * inst);