summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2017-04-24 20:49:31 -0700
committerMichael Pavone <pavone@retrodev.com>2017-04-24 20:49:31 -0700
commit3f8fd3720d38bded32fdf88ed3824f9c8745a4a7 (patch)
treea89fd02a712b39a83eee336471a3752f5bb5797f
parent8d362430c6785dcc4b9ed3a7a97acba8ebb15950 (diff)
Fix interaction between 68K debugger and instruction retranslation due to self modifying code or bank switching
-rw-r--r--debug.c6
-rw-r--r--debug.h2
-rw-r--r--gdb_remote.c3
-rw-r--r--gdb_remote.h2
-rw-r--r--m68k_core.c74
-rw-r--r--m68k_core.h19
-rw-r--r--m68k_core_x86.c90
-rw-r--r--m68k_internal.h2
8 files changed, 145 insertions, 53 deletions
diff --git a/debug.c b/debug.c
index b7bc9ed..547a2bd 100644
--- a/debug.c
+++ b/debug.c
@@ -885,7 +885,7 @@ int run_debugger_command(m68k_context *context, char *input_buf, m68kinst inst,
}
-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 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
if (debugging) {
printf("68K Breakpoint %d hit\n", (*this_bp)->index);
} else {
- return context;
+ return;
}
} else {
remove_breakpoint(context, address);
@@ -986,5 +986,5 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
}
debugging = run_debugger_command(context, input_buf, inst, after);
}
- return context;
+ return;
}
diff --git a/debug.h b/debug.h
index 8120c88..3ae71df 100644
--- a/debug.h
+++ b/debug.h
@@ -23,7 +23,7 @@ bp_def ** find_breakpoint(bp_def ** cur, uint32_t address);
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 --git a/gdb_remote.c b/gdb_remote.c
index d862124..17929f8 100644
--- a/gdb_remote.c
+++ b/gdb_remote.c
@@ -474,7 +474,7 @@ not_impl:
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 @@ m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc)
curbuf = NULL;
}
}
- return context;
}
#ifdef _WIN32
diff --git a/gdb_remote.h b/gdb_remote.h
index a908d65..0e85009 100644
--- a/gdb_remote.h
+++ b/gdb_remote.h
@@ -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 --git a/m68k_core.c b/m68k_core.c
index c5b40c2..a3a3c32 100644
--- a/m68k_core.c
+++ b/m68k_core.c
@@ -780,6 +780,49 @@ uint16_t m68k_get_ir(m68k_context *context)
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 @@ static impl_info m68k_impls[] = {
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 @@ void translate_m68k_stream(uint32_t address, m68k_context * context)
//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 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
//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 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
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 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
} 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 @@ code_ptr get_native_address_trans(m68k_context * context, uint32_t address)
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 --git a/m68k_core.h b/m68k_core.h
index 48a2a90..7773d64 100644
--- a/m68k_core.h
+++ b/m68k_core.h
@@ -56,13 +56,23 @@ typedef struct {
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 @@ typedef struct m68k_context {
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 --git a/m68k_core_x86.c b/m68k_core_x86.c
index 7935c4f..2ec0e90 100644
--- a/m68k_core_x86.c
+++ b/m68k_core_x86.c
@@ -2484,51 +2484,27 @@ void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t
}
}
-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 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu
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 --git a/m68k_internal.h b/m68k_internal.h
index 981cbfb..fbe26ce 100644
--- a/m68k_internal.h
+++ b/m68k_internal.h
@@ -35,6 +35,7 @@ void check_user_mode_swap_ssp_usp(m68k_options *opts);
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 @@ code_ptr get_native_address(m68k_options *opts, uint32_t address);
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);