changeset 1329:85a90964b557

Fix interaction between 68K debugger and instruction retranslation due to self modifying code or bank switching
author Michael Pavone <pavone@retrodev.com>
date Mon, 24 Apr 2017 20:49:31 -0700
parents 70faad89d491
children af26a1ce92f7
files debug.c debug.h gdb_remote.c gdb_remote.h m68k_core.c m68k_core.h m68k_core_x86.c m68k_internal.h
diffstat 8 files changed, 145 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }
--- 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_
--- 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
--- 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_
--- 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;
--- 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);
--- 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;
 }
--- 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);