keiths / rpms / gdb

Forked from rpms/gdb 19 days ago
Clone
00f225b
http://sourceware.org/ml/gdb-patches/2010-02/msg00625.html
00f225b
Subject: RFC: fix bug with std::terminate handler
00f225b
00f225b
I would appreciate comments on this patch.
00f225b
00f225b
This comes from an automatically-reported bug in the Red Hat bugzilla:
00f225b
00f225b
    https://bugzilla.redhat.com/show_bug.cgi?id=562975
00f225b
00f225b
call_function_by_hand installs a momentary breakpoint on std::terminate,
00f225b
and then deletes it later.  However, this can cause a double deletion of
00f225b
the breakpoint.  In the bug, the called function is dlopen, which causes
00f225b
gdb to enter solib_add, which calls breakpoint_re_set, deleting the
00f225b
momentary breakpoint.
00f225b
00f225b
This fix works by creating the momentary breakpoint with an internal
00f225b
breakpoint number, and then trying to delete the breakpoint by number.
00f225b
00f225b
This bug does not always manifest in a crash.  In fact, I couldn't make
00f225b
it crash here, but I could observe the problem under valgrind.
00f225b
00f225b
Built and regtested on x86-64 (compile farm).  I also manually verified
00f225b
it using valgrind.
00f225b
00f225b
I think this patch is mildly ugly, due to the introduction of
00f225b
set_momentary_breakpoint_at_pc_with_number.  However, in the absence of
00f225b
comments, I plan to check it in after a reasonable waiting period.
00f225b
00f225b
Tom
00f225b
00f225b
2010-02-25  Tom Tromey  <tromey@redhat.com>
00f225b
00f225b
	* infcall.c (do_delete_breakpoint_by_number): New function.
00f225b
	(call_function_by_hand): Refer to momentary breakpoint by number.
00f225b
	* breakpoint.h (set_momentary_breakpoint_at_pc_with_number):
00f225b
	Declare.
00f225b
	* breakpoint.c (set_momentary_breakpoint_at_pc_with_number): New
00f225b
	function.
00f225b
00f225b
Index: gdb-7.0.90.20100312/gdb/breakpoint.c
00f225b
===================================================================
00f225b
--- gdb-7.0.90.20100312.orig/gdb/breakpoint.c	2010-03-12 14:54:26.000000000 +0100
00f225b
+++ gdb-7.0.90.20100312/gdb/breakpoint.c	2010-03-12 14:54:53.000000000 +0100
00f225b
@@ -6115,6 +6115,20 @@ set_momentary_breakpoint_at_pc (struct g
00f225b
 
00f225b
   return set_momentary_breakpoint (gdbarch, sal, null_frame_id, type);
00f225b
 }
00f225b
+
00f225b
+/* Like set_momentary_breakpoint_at_pc, but ensure that the new
00f225b
+   breakpoint has a number.  */
00f225b
+
00f225b
+struct breakpoint *
00f225b
+set_momentary_breakpoint_at_pc_with_number (struct gdbarch *gdbarch,
00f225b
+					    CORE_ADDR pc,
00f225b
+					    enum bptype type)
00f225b
+{
00f225b
+  struct breakpoint *result = set_momentary_breakpoint_at_pc (gdbarch, pc,
00f225b
+							      type);
00f225b
+  result->number = internal_breakpoint_number--;
00f225b
+  return result;
00f225b
+}
00f225b
 
00f225b
 
00f225b
 /* Tell the user we have just set a breakpoint B.  */
00f225b
Index: gdb-7.0.90.20100312/gdb/breakpoint.h
00f225b
===================================================================
00f225b
--- gdb-7.0.90.20100312.orig/gdb/breakpoint.h	2010-03-12 14:54:26.000000000 +0100
00f225b
+++ gdb-7.0.90.20100312/gdb/breakpoint.h	2010-03-12 14:54:53.000000000 +0100
00f225b
@@ -774,6 +774,9 @@ extern struct breakpoint *set_momentary_
00f225b
 extern struct breakpoint *set_momentary_breakpoint_at_pc
00f225b
   (struct gdbarch *, CORE_ADDR pc, enum bptype type);
00f225b
 
00f225b
+extern struct breakpoint *set_momentary_breakpoint_at_pc_with_number
00f225b
+  (struct gdbarch *, CORE_ADDR pc, enum bptype type);
00f225b
+
00f225b
 extern struct breakpoint *clone_momentary_breakpoint (struct breakpoint *bpkt);
00f225b
 
00f225b
 extern void set_ignore_count (int, int, int);
00f225b
Index: gdb-7.0.90.20100312/gdb/infcall.c
00f225b
===================================================================
00f225b
--- gdb-7.0.90.20100312.orig/gdb/infcall.c	2010-03-12 14:54:26.000000000 +0100
00f225b
+++ gdb-7.0.90.20100312/gdb/infcall.c	2010-03-12 14:55:19.000000000 +0100
00f225b
@@ -410,6 +410,18 @@ run_inferior_call (struct thread_info *c
00f225b
   return e;
00f225b
 }
00f225b
 
00f225b
+/* A cleanup function that deletes a breakpoint, if it still exists,
00f225b
+   given the breakpoint's number.  */
00f225b
+
00f225b
+static void
00f225b
+do_delete_breakpoint_by_number (void *arg)
00f225b
+{
00f225b
+  int *num = arg;
00f225b
+  struct breakpoint *bp = get_breakpoint (*num);
00f225b
+  if (bp)
00f225b
+    delete_breakpoint (bp);
00f225b
+}
00f225b
+
00f225b
 /* All this stuff with a dummy frame may seem unnecessarily complicated
00f225b
    (why not just save registers in GDB?).  The purpose of pushing a dummy
00f225b
    frame which looks just like a real frame is so that if you call a
00f225b
@@ -447,7 +459,8 @@ call_function_by_hand (struct value *fun
00f225b
   struct cleanup *args_cleanup;
00f225b
   struct frame_info *frame;
00f225b
   struct gdbarch *gdbarch;
00f225b
-  struct breakpoint *terminate_bp = NULL;
00f225b
+  int terminate_bp_num = 0;
00f225b
+  CORE_ADDR terminate_bp_addr = 0;
00f225b
   struct minimal_symbol *tm;
00f225b
   struct cleanup *terminate_bp_cleanup = NULL;
00f225b
   ptid_t call_thread_ptid;
00f225b
@@ -765,8 +778,13 @@ call_function_by_hand (struct value *fun
00f225b
        struct minimal_symbol *tm = lookup_minimal_symbol  ("std::terminate()",
00f225b
 							   NULL, NULL);
00f225b
        if (tm != NULL)
00f225b
-	   terminate_bp = set_momentary_breakpoint_at_pc
00f225b
+	 {
00f225b
+	   struct breakpoint *bp;
00f225b
+	   bp = set_momentary_breakpoint_at_pc_with_number
00f225b
 	     (gdbarch, SYMBOL_VALUE_ADDRESS (tm),  bp_breakpoint);
00f225b
+	   terminate_bp_num = bp->number;
00f225b
+	   terminate_bp_addr = bp->loc->address;
00f225b
+	 }
00f225b
      }
00f225b
 
00f225b
   /* Everything's ready, push all the info needed to restore the
00f225b
@@ -780,8 +798,9 @@ call_function_by_hand (struct value *fun
00f225b
   discard_cleanups (inf_status_cleanup);
00f225b
 
00f225b
   /* Register a clean-up for unwind_on_terminating_exception_breakpoint.  */
00f225b
-  if (terminate_bp)
00f225b
-    terminate_bp_cleanup = make_cleanup_delete_breakpoint (terminate_bp);
00f225b
+  if (terminate_bp_num != 0)
00f225b
+    terminate_bp_cleanup = make_cleanup (do_delete_breakpoint_by_number,
00f225b
+					 &terminate_bp_num);
00f225b
 
00f225b
   /* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP -
00f225b
      If you're looking to implement asynchronous dummy-frames, then
00f225b
@@ -947,9 +966,9 @@ When the function is done executing, GDB
00f225b
 		 in an inferior function call. Rewind, and warn the
00f225b
 		 user.  */
00f225b
 
00f225b
-	      if (terminate_bp != NULL
00f225b
+	      if (terminate_bp_num != 0
00f225b
 		  && (inferior_thread ()->stop_bpstat->breakpoint_at->address
00f225b
-		      == terminate_bp->loc->address))
00f225b
+		      == terminate_bp_addr))
00f225b
 		{
00f225b
 		  /* We must get back to the frame we were before the
00f225b
 		     dummy call.  */
00f225b
@@ -998,7 +1017,7 @@ When the function is done executing, GDB
00f225b
 
00f225b
   /* If we get here and the std::terminate() breakpoint has been set,
00f225b
      it has to be cleaned manually.  */
00f225b
-  if (terminate_bp)
00f225b
+  if (terminate_bp_num != 0)
00f225b
     do_cleanups (terminate_bp_cleanup);
00f225b
 
00f225b
   /* If we get here the called FUNCTION ran to completion,