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 5/7] Add a proxy unwinder.


Have the proxy unwinder pass down all calls to the functions the JIT
reader provides.
---
 gdb/ChangeLog |    9 +++
 gdb/jit.c     |  191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/jit.h     |    6 ++
 3 files changed, 206 insertions(+), 0 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index bd63356..2556be7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
 2011-08-09  Sanjoy Das  <sdas@igalia.com>
 
+	* jit.c (jut_unwind_reg_set_impl, free_reg_value_impl)
+	(jit_unwind_reg_get_impl, jit_frame_sniffer)
+	(jit_frame_unwind_stop_reason, jit_frame_this_id)
+	(jit_frame_prev_register, jit_dealloc_cache)
+	(jit_prepend_unwinder): New functions
+	* jit.h (jit_prepend_unwinder): New function
+
+2011-08-09  Sanjoy Das  <sdas@igalia.com>
+
 	* jit.c (add_objfile_entry, jit_target_read_impl)
 	(jit_object_open_impl, jit_symtab_open_impl, compare_block)
 	(jit_block_open_impl, jit_block_open_impl)
diff --git a/gdb/jit.c b/gdb/jit.c
index e81a386..58c3149 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -31,6 +31,7 @@
 #include "inferior.h"
 #include "observer.h"
 #include "objfiles.h"
+#include "regcache.h"
 #include "symfile.h"
 #include "symtab.h"
 #include "target.h"
@@ -843,6 +844,190 @@ jit_breakpoint_re_set_internal (struct gdbarch *gdbarch,
   return 0;
 }
 
+/* The private data passed around in the frame unwind callback
+   functions. */
+struct jit_unwind_private
+{
+  /* Cached register values. See jit_frame_sniffer to see how this
+     works. */
+  struct gdb_reg_value **registers;
+  /* The frame being unwound. */
+  struct frame_info *this_frame;
+};
+
+static void
+jit_unwind_reg_set_impl (struct gdb_unwind_callbacks *cb, int regnum,
+                         struct gdb_reg_value *value)
+{
+  struct jit_unwind_private *priv = cb->priv_data;
+  int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum);
+  gdb_assert (priv->registers);
+  priv->registers[gdb_reg] = value;
+}
+
+static void
+free_reg_value_impl (struct gdb_reg_value *reg_value)
+{
+  free (reg_value);
+}
+
+static struct gdb_reg_value *
+jit_unwind_reg_get_impl (struct gdb_unwind_callbacks *cb, int regnum)
+{
+  struct jit_unwind_private *priv = cb->priv_data;
+  int gdb_reg = gdbarch_dwarf2_reg_to_regnum (target_gdbarch, regnum);
+  int size = register_size (target_gdbarch, gdb_reg);
+  struct gdb_reg_value *value = malloc (sizeof (struct gdb_reg_value) +
+                                        size - 1);
+  value->defined = frame_register_read (priv->this_frame, gdb_reg,
+                                        value->value);
+  value->size = size;
+  value->free = free_reg_value_impl;
+  return value;
+}
+
+/* The frame sniffer for the pseudo unwinder.
+
+   While this is nominally a frame sniffer, in the case where the JIT
+   reader actually recognizes the frame, it does a lot more work -- it
+   unwinds the frame and saves the corresponding register values in
+   the cache. jit_frame_prev_register simply returns the saved
+   register values. */
+static int
+jit_frame_sniffer (const struct frame_unwind *self,
+                   struct frame_info *this_frame, void **cache)
+{
+  struct jit_inferior_data *inf_data = get_jit_inferior_data ();
+  struct jit_unwind_private *priv_data;
+  struct jit_dbg_reader *iter;
+  struct gdb_unwind_callbacks callbacks =
+    {
+      jit_unwind_reg_get_impl,
+      jit_unwind_reg_set_impl,
+      jit_target_read_impl
+    };
+  struct gdb_reader_funcs *funcs;
+
+  if (loaded_jit_reader == NULL)
+    return 0;
+  funcs = loaded_jit_reader->functions;
+
+  if (!*cache)
+    {
+      *cache = XZALLOC (struct jit_unwind_private);
+      priv_data = *cache;
+      priv_data->registers = XCALLOC (gdbarch_num_regs (target_gdbarch),
+                                      struct gdb_reg_value *);
+      priv_data->this_frame = this_frame;
+    }
+  else
+    {
+      priv_data = *cache;
+      priv_data->this_frame = this_frame;
+    }
+
+  callbacks.priv_data = priv_data;
+
+  /* Try to coax the provided unwinder to unwind the stack */
+  if (funcs->unwind (funcs, &callbacks) == GDB_SUCCESS)
+    {
+      if (jit_debug)
+        fprintf_unfiltered (gdb_stdlog, "Successfully unwound frame using "
+                            "JIT reader.\n");
+      return 1;
+    }
+  if (jit_debug)
+    fprintf_unfiltered (gdb_stdlog, "Could not unwind frame using "
+                        "JIT reader.\n");
+
+  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_unwind_private private =
+    {
+      NULL,
+      this_frame
+    };
+  struct gdb_frame_id frame_id;
+  struct gdb_reader_funcs *funcs;
+  struct gdb_unwind_callbacks callbacks =
+    {
+      jit_unwind_reg_get_impl,
+      NULL,
+      jit_target_read_impl,
+
+      &private
+    };
+
+  gdb_assert (loaded_jit_reader);
+  funcs = loaded_jit_reader->functions;
+
+  frame_id = funcs->get_frame_id (funcs, &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 gdb_reg_value *value;
+
+  if (priv == NULL)
+    return frame_unwind_got_optimized (this_frame, reg);
+
+  gdb_assert (priv->registers);
+  value = priv->registers[reg];
+  if (value && value->defined)
+    return frame_unwind_got_bytes (this_frame, reg, value->value);
+  else
+    return frame_unwind_got_optimized (this_frame, reg);
+}
+
+/* gdb_reg_value has a free function, which must be called on each
+   saved register value. */
+static void
+jit_dealloc_cache (struct frame_info *this_frame, void *cache)
+{
+  struct jit_unwind_private *priv_data = cache;
+  int i;
+
+  gdb_assert (priv_data->registers);
+
+  for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++)
+    if (priv_data->registers[i] && priv_data->registers[i]->free)
+      priv_data->registers[i]->free (priv_data->registers[i]);
+
+  xfree (priv_data->registers);
+  xfree (priv_data);
+}
+
+/* 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
@@ -1010,6 +1195,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..29cd10d 100644
--- a/gdb/jit.h
+++ b/gdb/jit.h
@@ -80,4 +80,10 @@ extern void jit_breakpoint_re_set (void);
 
 extern void jit_event_handler (struct gdbarch *gdbarch);
 
+/* Prepend the JIT unwinder GDBARCH's. Prepending adds negligible
+   overhead since this unwinder quickly fails if no JIT reader is
+   loaded. This also prevents other unwinders which depend on the BFD
+   field not being NULL from tripping. */
+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]