This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 3/4] Add an unwinder for JIT compiled code.


Add a (pseudo) unwinder which proxies back everything to the unwinder registered by the JIT debug info reader.

gdb/ChangeLog:

	* jit.c: Add JIT frame unwinding code.
	* jit-reader.h: Added jit_prepend_unwinder.
---
 gdb/ChangeLog |    5 ++
 gdb/jit.c     |  150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/jit.h     |    2 +
 3 files changed, 157 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ac207d1..8485b05 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
 2011-07-13  Sanjoy Das  <sanjoy@playingwithpointers.com>
 
+	* jit.c: Add JIT frame unwinding code.
+	* jit-reader.h: Added jit_prepend_unwinder.
+
+2011-07-13  Sanjoy Das  <sanjoy@playingwithpointers.com>
+
 	* jit.c: Add symbol handling callbacks for the JIT reader interface.
 
 2011-07-13  Sanjoy Das  <sanjoy@playingwithpointers.com>
diff --git a/gdb/jit.c b/gdb/jit.c
index 2899469..03a3d0b 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -28,6 +28,7 @@
 #include "breakpoint.h"
 #include "command.h"
 #include "dictionary.h"
+#include "frame-unwind.h"
 #include "gdbcmd.h"
 #include "gdbcore.h"
 #include "inferior.h"
@@ -781,6 +782,149 @@ 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)
+{
+  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 = frame_id_build (frame_id.stack_address, frame_id.code_address);
+}
+
+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
@@ -960,6 +1104,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.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]