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/3] Use longjmp and exception probes when available


Hello,

This is the third and last patch.  It implements the bits necessary for
using longjmp and exception probes on glibc and libgcc, respectively.

Is this OK to check-in?

gdb/ChangeLog
2012-09-03  Sergio Durigan Junior  <sergiodj@redhat.com>
	    Tom Tromey  <tromey@redhat.com>

	* breakpoint.c (struct breakpoint_objfile_data)
	<longjmp_searched>,<longjmp_probes>,<exception_searched>,
	<exception_probes>: New fields.
	(free_breakpoint_probes): New function.
	(create_longjmp_master_breakpoint): Prefer SystemTap probe over
	`_Unwind_DebugHook'.
	(create_exception_master_breakpoint): Likewise.
	(_initialize_breakpoint): Registering cleanup for SystemTap probes.
	* infrun.c: Including necessary header files for handling SystemTap
	probes.
	(handle_inferior_event): Handling longjmp breakpoint and exceptions
	via SystemTap probes.
	(check_exception_resume): Remove `func' argument.  Handle exception
	unwinding breakpoint set via a SystemTap probe.
	(insert_exception_resume_from_probe): New function.

---
 gdb/breakpoint.c |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gdb/infrun.c     |   77 ++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 154 insertions(+), 12 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index a8f3a42..7b3f209 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -2752,11 +2752,23 @@ struct breakpoint_objfile_data
   /* Minimal symbol(s) for "longjmp", "siglongjmp", etc. (if any).  */
   struct minimal_symbol *longjmp_msym[NUM_LONGJMP_NAMES];
 
+  /* True if we have looked for longjmp probes.  */
+  int longjmp_searched;
+
+  /* SystemTap probe points for longjmp (if any).  */
+  VEC (stap_probe_p) *longjmp_probes;
+
   /* Minimal symbol for "std::terminate()" (if any).  */
   struct minimal_symbol *terminate_msym;
 
   /* Minimal symbol for "_Unwind_DebugHook" (if any).  */
   struct minimal_symbol *exception_msym;
+
+  /* True if we have looked for exception probes.  */
+  int exception_searched;
+
+  /* SystemTap probe points for unwinding (if any).  */
+  VEC (stap_probe_p) *exception_probes;
 };
 
 static const struct objfile_data *breakpoint_objfile_key;
@@ -2793,6 +2805,15 @@ get_breakpoint_objfile_data (struct objfile *objfile)
 }
 
 static void
+free_breakpoint_probes (struct objfile *obj, void *data)
+{
+  struct breakpoint_objfile_data *bp_objfile_data = data;
+
+  VEC_free (stap_probe_p, bp_objfile_data->longjmp_probes);
+  VEC_free (stap_probe_p, bp_objfile_data->exception_probes);
+}
+
+static void
 create_overlay_event_breakpoint (void)
 {
   struct objfile *objfile;
@@ -2869,6 +2890,37 @@ create_longjmp_master_breakpoint (void)
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
+      if (!bp_objfile_data->longjmp_searched)
+	{
+	  bp_objfile_data->longjmp_probes
+	    = find_probes_in_objfile (objfile, "libc", "longjmp");
+	  bp_objfile_data->longjmp_searched = 1;
+	}
+
+      if (bp_objfile_data->longjmp_probes != NULL)
+	{
+	  int i;
+	  struct stap_probe *probe;
+	  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+	  for (i = 0;
+	       VEC_iterate (stap_probe_p,
+			    bp_objfile_data->longjmp_probes,
+			    i, probe);
+	       ++i)
+	    {
+	      struct breakpoint *b;
+
+	      b = create_internal_breakpoint (gdbarch, probe->address,
+					      bp_longjmp_master,
+					      &internal_breakpoint_ops);
+	      b->addr_string = xstrdup ("-p libc:longjmp");
+	      b->enable_state = bp_disabled;
+	    }
+
+	  continue;
+	}
+
       for (i = 0; i < NUM_LONGJMP_NAMES; i++)
 	{
 	  struct breakpoint *b;
@@ -2979,6 +3031,40 @@ create_exception_master_breakpoint (void)
 
       bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
+      /* We prefer the SystemTap probe point if it exists.  */
+      if (!bp_objfile_data->exception_searched)
+	{
+	  bp_objfile_data->exception_probes
+	    = find_probes_in_objfile (objfile, "libgcc", "unwind");
+	  bp_objfile_data->exception_searched = 1;
+	}
+
+      if (bp_objfile_data->exception_probes != NULL)
+	{
+	  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+	  int i;
+	  struct stap_probe *probe;
+
+	  for (i = 0;
+	       VEC_iterate (stap_probe_p,
+			    bp_objfile_data->exception_probes,
+			    i, probe);
+	       ++i)
+	    {
+	      struct breakpoint *b;
+
+	      b = create_internal_breakpoint (gdbarch, probe->address,
+					      bp_exception_master,
+					      &internal_breakpoint_ops);
+	      b->addr_string = xstrdup ("-p libgcc:unwind");
+	      b->enable_state = bp_disabled;
+	    }
+
+	  continue;
+	}
+
+      /* Otherwise, try the hook function.  */
+
       if (msym_not_found_p (bp_objfile_data->exception_msym))
 	continue;
 
@@ -15066,7 +15152,8 @@ _initialize_breakpoint (void)
   observer_attach_inferior_exit (clear_syscall_counts);
   observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
 
-  breakpoint_objfile_key = register_objfile_data ();
+  breakpoint_objfile_key
+    = register_objfile_data_with_cleanup (NULL, free_breakpoint_probes);
 
   breakpoint_chain = 0;
   /* Don't bother to call set_breakpoint_count.  $bpnum isn't useful
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 54e39ef..d9bd886 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -55,6 +55,8 @@
 #include "continuations.h"
 #include "interps.h"
 #include "skip.h"
+#include "stap-probe.h"
+#include "objfiles.h"
 
 /* Prototypes for local functions */
 
@@ -2392,7 +2394,7 @@ static void handle_step_into_function (struct gdbarch *gdbarch,
 static void handle_step_into_function_backward (struct gdbarch *gdbarch,
 						struct execution_control_state *ecs);
 static void check_exception_resume (struct execution_control_state *,
-				    struct frame_info *, struct symbol *);
+				    struct frame_info *);
 
 static void stop_stepping (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
@@ -4427,9 +4429,17 @@ process_event_stop_test:
 
 	if (what.is_longjmp)
 	  {
-	    if (!gdbarch_get_longjmp_target_p (gdbarch)
-		|| !gdbarch_get_longjmp_target (gdbarch,
-						frame, &jmp_buf_pc))
+	    struct value *arg_value;
+
+	    /* If we set the longjmp breakpoint via a SystemTap probe,
+	       then use it to extract the arguments.  The destination
+	       PC is the third argument to the probe.  */
+	    arg_value = stap_safe_evaluate_at_pc (frame, 2);
+	    if (arg_value)
+	      jmp_buf_pc = value_as_address (arg_value);
+	    else if (!gdbarch_get_longjmp_target_p (gdbarch)
+		     || !gdbarch_get_longjmp_target (gdbarch,
+						     frame, &jmp_buf_pc))
 	      {
 		if (debug_infrun)
 		  fprintf_unfiltered (gdb_stdlog,
@@ -4447,12 +4457,7 @@ process_event_stop_test:
 	    insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
 	  }
 	else
-	  {
-	    struct symbol *func = get_frame_function (frame);
-
-	    if (func)
-	      check_exception_resume (ecs, frame, func);
-	  }
+	  check_exception_resume (ecs, frame);
 	keep_going (ecs);
 	return;
 
@@ -5539,15 +5544,65 @@ insert_exception_resume_breakpoint (struct thread_info *tp,
     }
 }
 
+/* A helper for check_exception_resume that sets an
+   exception-breakpoint based on a SystemTap probe.  */
+
+static void
+insert_exception_resume_from_probe (struct thread_info *tp,
+				    const struct stap_probe *probe,
+				    struct objfile *objfile,
+				    struct frame_info *frame)
+{
+  struct value *arg_value;
+  CORE_ADDR handler;
+  struct breakpoint *bp;
+
+  arg_value = stap_safe_evaluate_at_pc (frame, 1);
+  if (!arg_value)
+    return;
+
+  handler = value_as_address (arg_value);
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+			"infrun: exception resume at %s\n",
+			paddress (get_objfile_arch (objfile),
+				  handler));
+
+  bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
+				       handler, bp_exception_resume);
+  bp->thread = tp->num;
+  inferior_thread ()->control.exception_resume_breakpoint = bp;
+}
+
 /* This is called when an exception has been intercepted.  Check to
    see whether the exception's destination is of interest, and if so,
    set an exception resume breakpoint there.  */
 
 static void
 check_exception_resume (struct execution_control_state *ecs,
-			struct frame_info *frame, struct symbol *func)
+			struct frame_info *frame)
 {
   volatile struct gdb_exception e;
+  struct objfile *objfile;
+  const struct stap_probe *probe;
+  struct symbol *func;
+
+  /* First see if this exception unwinding breakpoint was set via a
+     SystemTap probe point.  If so, the probe has two arguments: the
+     CFA and the HANDLER.  We ignore the CFA, extract the handler, and
+     set a breakpoint there.  */
+  probe = find_probe_by_pc (get_frame_pc (frame), &objfile);
+  if (probe)
+    {
+      insert_exception_resume_from_probe (ecs->event_thread, probe,
+					  objfile, frame);
+      return;
+    }
+
+  func = get_frame_function (frame);
+  if (!func)
+    return;
 
   TRY_CATCH (e, RETURN_MASK_ERROR)
     {

-- 
Sergio


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