From b2eefe94d050278420b92ec02ec0a3a233b71a6a Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Thu, 30 Jun 2011 17:32:35 +0530 Subject: [PATCH 3/3] JIT unwinder. Adds a new unwinder which relays all the unwinding action to the JIT reader loaded in memory. --- gdb/i386-tdep.c | 4 ++ gdb/jit.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/jit.h | 2 + 3 files changed, 159 insertions(+), 0 deletions(-) diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 366d0fa..66626ab 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -30,6 +30,7 @@ #include "frame-base.h" #include "frame-unwind.h" #include "inferior.h" +#include "jit.h" #include "gdbcmd.h" #include "gdbcore.h" #include "gdbtypes.h" @@ -7330,6 +7331,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) CFI info will be used if it is available. */ dwarf2_append_unwinders (gdbarch); + /* JIT reader pseudo-unwinder. */ + jit_prepend_unwinder (gdbarch); + frame_base_set_default (gdbarch, &i386_frame_base); /* Pseudo registers may be changed by amd64_init_abi. */ diff --git a/gdb/jit.c b/gdb/jit.c index d259e04..1a00a91 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -25,6 +25,7 @@ #include "breakpoint.h" #include "command.h" #include "dictionary.h" +#include "frame-unwind.h" #include "gdbcmd.h" #include "gdbcore.h" #include "inferior.h" @@ -769,6 +770,152 @@ jit_breakpoint_re_set_internal (struct gdbarch *gdbarch, return 0; } +struct jit_unwind_private { + struct gdbjit_reg_value *registers; + struct frame_info *this_frame; +}; + +static void +jit_unwind_reg_set_impl (struct gdbjit_unwind_callbacks *cb, int regnum, + struct gdbjit_reg_value value) +{ + struct jit_unwind_private *priv = cb->private; + int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum); + priv->registers[gdb_reg] = value; +} + +static struct gdbjit_reg_value +jit_unwind_reg_get_impl (struct gdbjit_unwind_callbacks *cb, int regnum) +{ + struct jit_unwind_private *priv = cb->private; + struct gdbjit_reg_value val; + int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum); + val.defined = frame_register_read (priv->this_frame, gdb_reg, val.value); + return val; +} + +static int +jit_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, void **cache) +{ + /* First look up the PC, and check if the code address has been registered or + not. */ + CORE_ADDR pc = get_frame_pc (this_frame); + struct jit_inferior_data *inf_data = get_jit_inferior_data (); + struct jit_unwind_private *priv_data; + struct jit_dbg_reader *iter; + struct gdbjit_unwind_callbacks callbacks = + { + jit_unwind_reg_get_impl, + jit_unwind_reg_set_impl, + jit_target_read_impl + }; + + if (inf_data->reader == NULL) + return 0; + + /* All the unwinding happens here, and the unwound registers are written to + this block of memory, which we then sneakily read back in + jit_frame_prev_register. */ + if (!*cache) + { + *cache = XZALLOC (struct jit_unwind_private); + priv_data = *cache; + priv_data->registers = XCALLOC (gdbarch_num_regs (target_gdbarch), + struct gdbjit_reg_value); + priv_data->this_frame = this_frame; + } + else + { + priv_data = *cache; + priv_data->this_frame = this_frame; + } + + callbacks.private = priv_data; + + /* Try to coax the provided unwinder to unwind the stack, and hope it + succeeds. */ + if (inf_data->reader->unwind (inf_data->reader->private_data, &callbacks) + == GDB_JIT_SUCCESS) + return 1; + xfree (priv_data->registers); + xfree (priv_data); + *cache = NULL; + + return 0; +} + +static enum unwind_stop_reason +jit_frame_unwind_stop_reason (struct frame_info *this_frame, void **cache) +{ + /* TODO: This needs to be fixed. */ + return UNWIND_NO_REASON; +} + +static void +jit_frame_this_id (struct frame_info *this_frame, void **cache, + struct frame_id *this_id) +{ + struct jit_inferior_data *inf_data = get_jit_inferior_data (); + struct jit_unwind_private private = + { + NULL, + this_frame + }; + struct gdbjit_frame_id frame_id; + struct gdbjit_unwind_callbacks callbacks = + { + jit_unwind_reg_get_impl, + NULL, + jit_target_read_impl, + + &private + }; + + frame_id = inf_data->reader->get_frame_id (inf_data->reader->private_data, + &callbacks); + this_id->stack_addr = (CORE_ADDR) frame_id.stack_address; + this_id->code_addr = (CORE_ADDR) frame_id.stack_address; + this_id->stack_addr_p = this_id->code_addr_p = 1; +} + +static struct value * +jit_frame_prev_register (struct frame_info *this_frame, void **cache, int reg) +{ + struct jit_unwind_private *priv = *cache; + struct gdbjit_reg_value value; + + if (priv == NULL) + return frame_unwind_got_optimized (this_frame, reg); + + value = priv->registers[reg]; + if (value.defined) + return frame_unwind_got_bytes (this_frame, reg, value.value); + else + return frame_unwind_got_optimized (this_frame, reg); +} + +static void +jit_dealloc_cache (struct frame_info *this_frame, void *cache) +{ + (void) this_frame; + + xfree (cache); +} + +/* Simply relays everything back to the unwinder registered by the jit debug + info reader.*/ +static const struct frame_unwind jit_frame_unwind = +{ + NORMAL_FRAME, + jit_frame_unwind_stop_reason, + jit_frame_this_id, + jit_frame_prev_register, + NULL, + jit_frame_sniffer, + jit_dealloc_cache +}; + /* Register any already created translations. */ static void @@ -948,6 +1095,12 @@ jit_event_handler (struct gdbarch *gdbarch) } } +void +jit_prepend_unwinder (struct gdbarch *gdbarch) +{ + frame_unwind_prepend_unwinder (gdbarch, &jit_frame_unwind); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern void _initialize_jit (void); diff --git a/gdb/jit.h b/gdb/jit.h index 73a1414..9dd8f5a 100644 --- a/gdb/jit.h +++ b/gdb/jit.h @@ -80,4 +80,6 @@ extern void jit_breakpoint_re_set (void); extern void jit_event_handler (struct gdbarch *gdbarch); +extern void jit_prepend_unwinder (struct gdbarch *gdbarch); + #endif /* JIT_H */ -- 1.7.5.3