From 08b6b5de1dfbf8a82204adf7e59b3abe421a83fa Mon Sep 17 00:00:00 2001 From: Anthony Pesch Date: Mon, 15 May 2017 07:37:19 -0400 Subject: [PATCH] reenabled gdb-based debugger --- CMakeLists.txt | 1 + src/hw/dreamcast.c | 26 +++++- src/hw/dreamcast.h | 8 ++ src/hw/gdrom/gdrom.c | 3 +- src/hw/sh4/sh4.c | 19 ++-- src/hw/sh4/sh4.h | 13 +++ src/hw/sh4/sh4_dbg.c | 203 +++++++++++++++++++++++++++---------------- 7 files changed, 182 insertions(+), 91 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8149aff6..8a9fb42b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -172,6 +172,7 @@ set(REDREAM_SOURCES src/hw/rom/flash.c src/hw/sh4/sh4.c src/hw/sh4/sh4_ccn.c + src/hw/sh4/sh4_dbg.c src/hw/sh4/sh4_dmac.c src/hw/sh4/sh4_intc.c src/hw/sh4/sh4_tmu.c diff --git a/src/hw/dreamcast.c b/src/hw/dreamcast.c index cc38d6f7..42f69ed8 100644 --- a/src/hw/dreamcast.c +++ b/src/hw/dreamcast.c @@ -15,8 +15,6 @@ #include "hw/scheduler.h" #include "hw/sh4/sh4.h" -DEFINE_OPTION_INT(gdb, 0, "Run gdb debug server"); - void dc_poll_input(struct dreamcast *dc) { if (!dc->poll_input) { return; @@ -198,6 +196,26 @@ struct execute_interface *dc_create_execute_interface(device_run_cb run, return execute; } +void dc_destroy_debug_interface(struct debug_interface *dbg) { + free(dbg); +} + +struct debug_interface *dc_create_debug_interface(device_num_regs_cb num_regs, + device_step_cb step, + device_add_bp_cb add_bp, + device_rem_bp_cb rem_bp, + device_read_mem_cb read_mem, + device_read_reg_cb read_reg) { + struct debug_interface *dbg = calloc(1, sizeof(struct debug_interface)); + dbg->num_regs = num_regs; + dbg->step = step; + dbg->add_bp = add_bp; + dbg->rem_bp = rem_bp; + dbg->read_mem = read_mem; + dbg->read_reg = read_reg; + return dbg; +} + void dc_destroy_device(struct device *dev) { list_remove(&dev->dc->devices, &dev->it); @@ -250,7 +268,9 @@ void dc_destroy(struct dreamcast *dc) { struct dreamcast *dc_create() { struct dreamcast *dc = calloc(1, sizeof(struct dreamcast)); - dc->debugger = OPTION_gdb ? debugger_create(dc) : NULL; +#ifndef NDEBUG + dc->debugger = debugger_create(dc); +#endif dc->memory = memory_create(dc); dc->scheduler = scheduler_create(dc); dc->sh4 = sh4_create(dc); diff --git a/src/hw/dreamcast.h b/src/hw/dreamcast.h index 4c68a612..ae64f3b4 100644 --- a/src/hw/dreamcast.h +++ b/src/hw/dreamcast.h @@ -165,6 +165,14 @@ void *dc_create_device(struct dreamcast *dc, size_t size, const char *name, struct device *dc_get_device(struct dreamcast *dc, const char *name); void dc_destroy_device(struct device *dev); +struct debug_interface *dc_create_debug_interface(device_num_regs_cb num_regs, + device_step_cb step, + device_add_bp_cb add_bp, + device_rem_bp_cb rem_bp, + device_read_mem_cb read_mem, + device_read_reg_cb read_reg); +void dc_destroy_debug_interface(struct debug_interface *dbg); + struct execute_interface *dc_create_execute_interface(device_run_cb run, int running); void dc_destroy_execute_interface(struct execute_interface *execute); diff --git a/src/hw/gdrom/gdrom.c b/src/hw/gdrom/gdrom.c index 3fd6aee1..0fb13556 100644 --- a/src/hw/gdrom/gdrom.c +++ b/src/hw/gdrom/gdrom.c @@ -540,7 +540,8 @@ static int gdrom_init(struct device *dev) { } void gdrom_dma_end(struct gdrom *gd) { - LOG_GDROM("gd_dma_end, %d / %d read from dma buffer", gd->dma_head, gd->dma_size); + LOG_GDROM("gd_dma_end, %d / %d read from dma buffer", gd->dma_head, + gd->dma_size); if (gd->dma_head < gd->dma_size) { return; diff --git a/src/hw/sh4/sh4.c b/src/hw/sh4/sh4.c index b22aa8c0..6fb3af0f 100644 --- a/src/hw/sh4/sh4.c +++ b/src/hw/sh4/sh4.c @@ -41,19 +41,6 @@ static void sh4_swap_fpr_bank(struct sh4 *sh4) { } } -static void sh4_invalid_instr(void *data, uint32_t addr) { - /*struct sh4 *self = reinterpret_cast(ctx->sh4); - - auto it = self->breakpoints.find(addr); - CHECK_NE(it, self->breakpoints.end()); - - // force the main loop to break - self->ctx.num_cycles = 0; - - // let the debugger know execution has stopped - self->dc->debugger->Trap();*/ -} - void sh4_sr_updated(void *data, uint32_t old_sr) { struct sh4 *sh4 = data; struct sh4_ctx *ctx = &sh4->ctx; @@ -227,7 +214,7 @@ static int sh4_init(struct device *dev) { sh4->guest->ctx = &sh4->ctx; sh4->guest->mem = sh4->memory_if->space->base; sh4->guest->space = sh4->memory_if->space; - sh4->guest->invalid_instr = &sh4_invalid_instr; + sh4->guest->invalid_instr = &sh4_dbg_invalid_instr; sh4->guest->sq_prefetch = &sh4_ccn_sq_prefetch; sh4->guest->sr_updated = &sh4_sr_updated; sh4->guest->fpscr_updated = &sh4_fpscr_updated; @@ -259,12 +246,16 @@ void sh4_destroy(struct sh4 *sh4) { dc_destroy_memory_interface(sh4->memory_if); dc_destroy_execute_interface(sh4->execute_if); + dc_destroy_debug_interface(sh4->debug_if); dc_destroy_device((struct device *)sh4); } struct sh4 *sh4_create(struct dreamcast *dc) { struct sh4 *sh4 = dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init, &sh4_debug_menu); + sh4->debug_if = dc_create_debug_interface( + &sh4_dbg_num_registers, &sh4_dbg_step, &sh4_dbg_add_breakpoint, + &sh4_dbg_remove_breakpoint, &sh4_dbg_read_memory, &sh4_dbg_read_register); sh4->execute_if = dc_create_execute_interface(&sh4_run, 0); sh4->memory_if = dc_create_memory_interface(dc, &sh4_data_map); diff --git a/src/hw/sh4/sh4.h b/src/hw/sh4/sh4.h index 7a67c347..a58f0e43 100644 --- a/src/hw/sh4/sh4.h +++ b/src/hw/sh4/sh4.h @@ -51,6 +51,9 @@ struct sh4 { struct sh4_frontend *frontend; struct x64_backend *backend; + /* dbg */ + struct list breakpoints; + /* intc */ enum sh4_interrupt sorted_interrupts[NUM_SH_INTERRUPTS]; uint64_t sort_id[NUM_SH_INTERRUPTS]; @@ -76,6 +79,16 @@ uint32_t sh4_ccn_sq_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask); void sh4_ccn_sq_write(struct sh4 *sh4, uint32_t addr, uint32_t data, uint32_t data_mask); +int sh4_dbg_num_registers(struct device *dev); +void sh4_dbg_step(struct device *dev); +void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr); +void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr); +void sh4_dbg_read_memory(struct device *dev, uint32_t addr, uint8_t *buffer, + int size); +void sh4_dbg_read_register(struct device *dev, int n, uint64_t *value, + int *size); +void sh4_dbg_invalid_instr(void *data, uint32_t addr); + void sh4_dmac_ddt(struct sh4 *sh, struct sh4_dtr *dtr); void sh4_intc_update_pending(struct sh4 *sh4); diff --git a/src/hw/sh4/sh4_dbg.c b/src/hw/sh4/sh4_dbg.c index 3a6f1730..550d104a 100644 --- a/src/hw/sh4/sh4_dbg.c +++ b/src/hw/sh4/sh4_dbg.c @@ -1,86 +1,143 @@ -// static int sh4_dbg_num_registers() { -// return 59; -// } +#include "hw/debugger.h" +#include "hw/sh4/sh4.h" +#include "jit/frontend/sh4/sh4_disasm.h" +#include "jit/frontend/sh4/sh4_fallback.h" -// static void sh4_dbg_step() { -// // invalidate the block for the current pc -// sh4->code_cache->RemoveBlocks(sh4->ctx.pc); +struct breakpoint { + uint32_t addr; + uint16_t instr; + struct list_node it; +}; -// // recompile it with only one instruction and run it -// uint32_t guest_addr = sh4->ctx.pc; -// uint8_t *host_addr = space->Translate(guest_addr); -// int flags = GetCompileFlags() | SH4_SINGLE_INSTR; +static struct breakpoint *lookup_breakpoint(struct sh4 *sh4, uint32_t addr) { + list_for_each_entry(bp, &sh4->breakpoints, struct breakpoint, it) { + if (bp->addr == addr) { + return bp; + } + } + return NULL; +} -// code_pointer_t code = sh4->code_cache->CompileCode(guest_addr, host_addr, -// flags); -// sh4->ctx.pc = code(); +static void destroy_breakpoint(struct sh4 *sh4, struct breakpoint *bp) { + list_remove(&sh4->breakpoints, &bp->it); + free(bp); +} -// // let the debugger know we've stopped -// dc->debugger->Trap(); -// } +static struct breakpoint *create_breakpoint(struct sh4 *sh4, uint32_t addr, + uint16_t instr) { + struct breakpoint *bp = calloc(1, sizeof(struct breakpoint)); + bp->addr = addr; + bp->instr = instr; + list_add(&sh4->breakpoints, &bp->it); + return bp; +} -// static void sh4_dbg_add_breakpoint(int type, uint32_t addr) { -// // save off the original instruction -// uint16_t instr = space->R16(addr); -// breakpoints_.insert(std::make_pair(addr, instr)); +void sh4_dbg_invalid_instr(void *data, uint32_t addr) { + struct sh4 *sh4 = data; -// // write out an invalid instruction -// space->W16(addr, 0); + /* ensure a breakpoint exists for this address */ + struct breakpoint *bp = lookup_breakpoint(sh4, addr); + CHECK_NOTNULL(bp); -// sh4->code_cache->RemoveBlocks(addr); -// } + /* force a break from dispatch */ + sh4->ctx.run_cycles = 0; -// static void sh4_dbg_remove_breakpoint(int type, uint32_t addr) { -// // recover the original instruction -// auto it = breakpoints_.find(addr); -// CHECK_NE(it, breakpoints_.end()); -// uint16_t instr = it->second; -// breakpoints_.erase(it); + /* let the debugger know execution has stopped */ + debugger_trap(sh4->dc->debugger); +} -// // overwrite the invalid instruction with the original -// space->W16(addr, instr); +void sh4_dbg_read_register(struct device *dev, int n, uint64_t *value, + int *size) { + struct sh4 *sh4 = (struct sh4 *)dev; -// sh4->code_cache->RemoveBlocks(addr); -// } + if (n < 16) { + *value = sh4->ctx.r[n]; + } else if (n == 16) { + *value = sh4->ctx.pc; + } else if (n == 17) { + *value = sh4->ctx.pr; + } else if (n == 18) { + *value = sh4->ctx.gbr; + } else if (n == 19) { + *value = sh4->ctx.vbr; + } else if (n == 20) { + *value = sh4->ctx.mach; + } else if (n == 21) { + *value = sh4->ctx.macl; + } else if (n == 22) { + *value = sh4->ctx.sr; + } else if (n == 23) { + *value = sh4->ctx.fpul; + } else if (n == 24) { + *value = sh4->ctx.fpscr; + } else if (n < 41) { + *value = sh4->ctx.fr[n - 25]; + } else if (n == 41) { + *value = sh4->ctx.ssr; + } else if (n == 42) { + *value = sh4->ctx.spc; + } else if (n < 51) { + uint32_t *b0 = (sh4->ctx.sr & RB_MASK) ? sh4->ctx.ralt : sh4->ctx.r; + *value = b0[n - 43]; + } else if (n < 59) { + uint32_t *b1 = (sh4->ctx.sr & RB_MASK) ? sh4->ctx.r : sh4->ctx.ralt; + *value = b1[n - 51]; + } -// static void sh4_dbg_read_memory(uint32_t addr, uint8_t *buffer, int size) { -// space->Memcpy(buffer, addr, size); -// } + *size = 4; +} -// void sh4_dbg_read_register(int n, uint64_t *value, int *size) { -// if (n < 16) { -// *value = sh4->ctx.r[n]; -// } else if (n == 16) { -// *value = sh4->ctx.pc; -// } else if (n == 17) { -// *value = sh4->ctx.pr; -// } else if (n == 18) { -// *value = sh4->ctx.gbr; -// } else if (n == 19) { -// *value = sh4->ctx.vbr; -// } else if (n == 20) { -// *value = sh4->ctx.mach; -// } else if (n == 21) { -// *value = sh4->ctx.macl; -// } else if (n == 22) { -// *value = sh4->ctx.sr; -// } else if (n == 23) { -// *value = sh4->ctx.fpul; -// } else if (n == 24) { -// *value = sh4->ctx.fpscr; -// } else if (n < 41) { -// *value = sh4->ctx.fr[n - 25]; -// } else if (n == 41) { -// *value = sh4->ctx.ssr; -// } else if (n == 42) { -// *value = sh4->ctx.spc; -// } else if (n < 51) { -// uint32_t *b0 = (sh4->ctx.sr & RB) ? sh4->ctx.ralt : sh4->ctx.r; -// *value = b0[n - 43]; -// } else if (n < 59) { -// uint32_t *b1 = (sh4->ctx.sr & RB) ? sh4->ctx.r : sh4->ctx.ralt; -// *value = b1[n - 51]; -// } +void sh4_dbg_read_memory(struct device *dev, uint32_t addr, uint8_t *buffer, + int size) { + struct sh4 *sh4 = (struct sh4 *)dev; -// *size = 4; -// } + while (size--) { + *(buffer++) = as_read8(sh4->memory_if->space, addr++); + } +} + +void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr) { + struct sh4 *sh4 = (struct sh4 *)dev; + + struct breakpoint *bp = lookup_breakpoint(sh4, addr); + CHECK_NOTNULL(bp); + + /* restore the original instruction */ + as_write16(sh4->memory_if->space, addr, bp->instr); + + /* free code cache to remove block containing the invalid instruction */ + jit_free_blocks(sh4->jit); + + destroy_breakpoint(sh4, bp); +} + +void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr) { + struct sh4 *sh4 = (struct sh4 *)dev; + + uint16_t instr = as_read16(sh4->memory_if->space, addr); + struct breakpoint *bp = create_breakpoint(sh4, addr, instr); + + /* write out an invalid instruction */ + as_write16(sh4->memory_if->space, addr, 0); + + /* free code cache to remove block containing the original instruction */ + jit_free_blocks(sh4->jit); +} + +void sh4_dbg_step(struct device *dev) { + struct sh4 *sh4 = (struct sh4 *)dev; + + /* run the fallback handler for the current pc */ + uint16_t data = as_read16(sh4->memory_if->space, sh4->ctx.pc); + union sh4_instr instr = {data}; + struct sh4_opdef *def = sh4_get_opdef(data); + sh4_fallback_cb cb = sh4_get_fallback(data); + cb(sh4->guest, sh4->ctx.pc, instr); + + /* let the debugger know we've stopped */ + debugger_trap(sh4->dc->debugger); +} + +int sh4_dbg_num_registers(struct device *dev) { + return 59; +}