PR gdb/11327, PR gdb/11328, PR breakpoints/11368:
authorTom Tromey <tromey@redhat.com>
Thu, 25 Mar 2010 20:48:53 +0000 (20:48 +0000)
committerTom Tromey <tromey@redhat.com>
Thu, 25 Mar 2010 20:48:53 +0000 (20:48 +0000)
* infrun.c (handle_inferior_event): Change initialization of
stop_stack_dummy.
(handle_inferior_event): Change assignment to stop_stack_dummy.
(normal_stop): Update use of stop_stack_dummy.
(struct inferior_status) <stop_stack_dummy>: Change type.
* inferior.h (stop_stack_dummy): Update.
* infcmd.c (stop_stack_dummy): Change type.
* infcall.c (cleanup_delete_std_terminate_breakpoint): New
function.
(call_function_by_hand): Call set_std_terminate_breakpoint.
Rewrite std::terminate handling.
* breakpoint.h (enum bptype) <bp_std_terminate,
bp_std_terminate_master>: New.
(enum stop_stack_kind): New.
(struct bpstat_what) <call_dummy>: Change type.
(set_std_terminate_breakpoint, delete_std_terminate_breakpoint):
Declare.
* breakpoint.c (create_std_terminate_master_breakpoint): New
function.
(update_breakpoints_after_exec): Handle bp_std_terminate_master.
Call create_std_terminate_master_breakpoint.
(print_it_typical): Handle new breakpoint kinds.
(bpstat_stop_status): Handle bp_std_terminate_master.
(bpstat_what): Correctly set call_dummy field.  Handle
bp_std_terminate_master and bp_std_terminate.
(print_one_breakpoint_location): Update.
(allocate_bp_location): Update.
(set_std_terminate_breakpoint): New function.
(delete_std_terminate_breakpoint): Likewise.
(create_thread_event_breakpoint): Update.
(delete_command): Update.
(breakpoint_re_set_one): Update.
(breakpoint_re_set): Call create_std_terminate_master_breakpoint.

gdb/ChangeLog
gdb/breakpoint.c
gdb/breakpoint.h
gdb/infcall.c
gdb/infcmd.c
gdb/inferior.h
gdb/infrun.c

index d3ecb9141f57d1c9db0a1c56a7a138cf7fe68211..d2c44c0df8cbed7865f565c3ae017b0b587e10ab 100644 (file)
@@ -1,3 +1,40 @@
+2010-03-25  Tom Tromey  <tromey@redhat.com>
+
+       PR gdb/11327, PR gdb/11328, PR breakpoints/11368:
+       * infrun.c (handle_inferior_event): Change initialization of
+       stop_stack_dummy.
+       (handle_inferior_event): Change assignment to stop_stack_dummy.
+       (normal_stop): Update use of stop_stack_dummy.
+       (struct inferior_status) <stop_stack_dummy>: Change type.
+       * inferior.h (stop_stack_dummy): Update.
+       * infcmd.c (stop_stack_dummy): Change type.
+       * infcall.c (cleanup_delete_std_terminate_breakpoint): New
+       function.
+       (call_function_by_hand): Call set_std_terminate_breakpoint.
+       Rewrite std::terminate handling.
+       * breakpoint.h (enum bptype) <bp_std_terminate,
+       bp_std_terminate_master>: New.
+       (enum stop_stack_kind): New.
+       (struct bpstat_what) <call_dummy>: Change type.
+       (set_std_terminate_breakpoint, delete_std_terminate_breakpoint):
+       Declare.
+       * breakpoint.c (create_std_terminate_master_breakpoint): New
+       function.
+       (update_breakpoints_after_exec): Handle bp_std_terminate_master.
+       Call create_std_terminate_master_breakpoint.
+       (print_it_typical): Handle new breakpoint kinds.
+       (bpstat_stop_status): Handle bp_std_terminate_master.
+       (bpstat_what): Correctly set call_dummy field.  Handle
+       bp_std_terminate_master and bp_std_terminate.
+       (print_one_breakpoint_location): Update.
+       (allocate_bp_location): Update.
+       (set_std_terminate_breakpoint): New function.
+       (delete_std_terminate_breakpoint): Likewise.
+       (create_thread_event_breakpoint): Update.
+       (delete_command): Update.
+       (breakpoint_re_set_one): Update.
+       (breakpoint_re_set): Call create_std_terminate_master_breakpoint.
+
 2010-03-25  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * symfile.c (build_section_addr_info_from_bfd): New.
index 2cc1f08eb6077285f9fc861e25e6dae70cd5d09c..ded2a556226286341a1e8b434d90f7b51fe81888 100644 (file)
@@ -2157,6 +2157,41 @@ create_longjmp_master_breakpoint (char *func_name)
   do_cleanups (old_chain);
 }
 
+/* Create a master std::terminate breakpoint.  The actual function
+   looked for is named FUNC_NAME.  */
+static void
+create_std_terminate_master_breakpoint (const char *func_name)
+{
+  struct program_space *pspace;
+  struct objfile *objfile;
+  struct cleanup *old_chain;
+
+  old_chain = save_current_program_space ();
+
+  ALL_PSPACES (pspace)
+    ALL_OBJFILES (objfile)
+    {
+      struct breakpoint *b;
+      struct minimal_symbol *m;
+
+      set_current_program_space (pspace);
+
+      m = lookup_minimal_symbol (func_name, NULL, objfile);
+      if (m == NULL || (MSYMBOL_TYPE (m) != mst_text
+                       && MSYMBOL_TYPE (m) != mst_file_text))
+        continue;
+
+      b = create_internal_breakpoint (get_objfile_arch (objfile),
+                                     SYMBOL_VALUE_ADDRESS (m),
+                                      bp_std_terminate_master);
+      b->addr_string = xstrdup (func_name);
+      b->enable_state = bp_disabled;
+    }
+  update_global_location_list (1);
+
+  do_cleanups (old_chain);
+}
+
 void
 update_breakpoints_after_exec (void)
 {
@@ -2198,7 +2233,7 @@ update_breakpoints_after_exec (void)
     /* Thread event breakpoints must be set anew after an exec(),
        as must overlay event and longjmp master breakpoints.  */
     if (b->type == bp_thread_event || b->type == bp_overlay_event
-       || b->type == bp_longjmp_master)
+       || b->type == bp_longjmp_master || b->type == bp_std_terminate_master)
       {
        delete_breakpoint (b);
        continue;
@@ -2274,6 +2309,7 @@ update_breakpoints_after_exec (void)
   create_longjmp_master_breakpoint ("_longjmp");
   create_longjmp_master_breakpoint ("siglongjmp");
   create_longjmp_master_breakpoint ("_siglongjmp");
+  create_std_terminate_master_breakpoint ("std::terminate()");
 }
 
 int
@@ -3202,6 +3238,12 @@ print_it_typical (bpstat bs)
       result = PRINT_NOTHING;
       break;
 
+    case bp_std_terminate_master:
+      /* These should never be enabled.  */
+      printf_filtered (_("std::terminate Master Breakpoint: gdb should not stop!\n"));
+      result = PRINT_NOTHING;
+      break;
+
     case bp_watchpoint:
     case bp_hardware_watchpoint:
       annotate_watchpoint (b->number);
@@ -3292,6 +3334,7 @@ print_it_typical (bpstat bs)
     case bp_step_resume:
     case bp_watchpoint_scope:
     case bp_call_dummy:
+    case bp_std_terminate:
     case bp_tracepoint:
     case bp_fast_tracepoint:
     case bp_jit_event:
@@ -4035,7 +4078,8 @@ bpstat_stop_status (struct address_space *aspace,
            continue;
 
          if (b->type == bp_thread_event || b->type == bp_overlay_event
-             || b->type == bp_longjmp_master)
+             || b->type == bp_longjmp_master
+             || b->type == bp_std_terminate_master)
            /* We do not stop for these.  */
            bs->stop = 0;
          else
@@ -4245,7 +4289,7 @@ bpstat_what (bpstat bs)
   enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
   struct bpstat_what retval;
 
-  retval.call_dummy = 0;
+  retval.call_dummy = STOP_NONE;
   for (; bs != NULL; bs = bs->next)
     {
       enum class bs_class = no_effect;
@@ -4318,6 +4362,7 @@ bpstat_what (bpstat bs)
        case bp_thread_event:
        case bp_overlay_event:
        case bp_longjmp_master:
+       case bp_std_terminate_master:
          bs_class = bp_nostop;
          break;
        case bp_catchpoint:
@@ -4337,7 +4382,13 @@ bpstat_what (bpstat bs)
          /* Make sure the action is stop (silent or noisy),
             so infrun.c pops the dummy frame.  */
          bs_class = bp_silent;
-         retval.call_dummy = 1;
+         retval.call_dummy = STOP_STACK_DUMMY;
+         break;
+       case bp_std_terminate:
+         /* Make sure the action is stop (silent or noisy),
+            so infrun.c pops the dummy frame.  */
+         bs_class = bp_silent;
+         retval.call_dummy = STOP_STD_TERMINATE;
          break;
        case bp_tracepoint:
        case bp_fast_tracepoint:
@@ -4465,10 +4516,12 @@ print_one_breakpoint_location (struct breakpoint *b,
     {bp_step_resume, "step resume"},
     {bp_watchpoint_scope, "watchpoint scope"},
     {bp_call_dummy, "call dummy"},
+    {bp_std_terminate, "std::terminate"},
     {bp_shlib_event, "shlib events"},
     {bp_thread_event, "thread events"},
     {bp_overlay_event, "overlay events"},
     {bp_longjmp_master, "longjmp master"},
+    {bp_std_terminate_master, "std::terminate master"},
     {bp_catchpoint, "catchpoint"},
     {bp_tracepoint, "tracepoint"},
     {bp_fast_tracepoint, "fast tracepoint"},
@@ -4596,10 +4649,12 @@ print_one_breakpoint_location (struct breakpoint *b,
       case bp_step_resume:
       case bp_watchpoint_scope:
       case bp_call_dummy:
+      case bp_std_terminate:
       case bp_shlib_event:
       case bp_thread_event:
       case bp_overlay_event:
       case bp_longjmp_master:
+      case bp_std_terminate_master:
       case bp_tracepoint:
       case bp_fast_tracepoint:
       case bp_jit_event:
@@ -5235,11 +5290,13 @@ allocate_bp_location (struct breakpoint *bpt)
     case bp_step_resume:
     case bp_watchpoint_scope:
     case bp_call_dummy:
+    case bp_std_terminate:
     case bp_shlib_event:
     case bp_thread_event:
     case bp_overlay_event:
     case bp_jit_event:
     case bp_longjmp_master:
+    case bp_std_terminate_master:
       loc->loc_type = bp_loc_software_breakpoint;
       break;
     case bp_hardware_breakpoint:
@@ -5492,6 +5549,33 @@ disable_overlay_breakpoints (void)
     }
 }
 
+/* Set an active std::terminate breakpoint for each std::terminate
+   master breakpoint.  */
+void
+set_std_terminate_breakpoint (void)
+{
+  struct breakpoint *b, *temp;
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+    if (b->pspace == current_program_space
+       && b->type == bp_std_terminate_master)
+      {
+       struct breakpoint *clone = clone_momentary_breakpoint (b);
+       clone->type = bp_std_terminate;
+      }
+}
+
+/* Delete all the std::terminate breakpoints.  */
+void
+delete_std_terminate_breakpoint (void)
+{
+  struct breakpoint *b, *temp;
+
+  ALL_BREAKPOINTS_SAFE (b, temp)
+    if (b->type == bp_std_terminate)
+      delete_breakpoint (b);
+}
+
 struct breakpoint *
 create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
 {
@@ -6537,12 +6621,14 @@ mention (struct breakpoint *b)
       case bp_longjmp_resume:
       case bp_step_resume:
       case bp_call_dummy:
+      case bp_std_terminate:
       case bp_watchpoint_scope:
       case bp_shlib_event:
       case bp_thread_event:
       case bp_overlay_event:
       case bp_jit_event:
       case bp_longjmp_master:
+      case bp_std_terminate_master:
        break;
       }
 
@@ -9222,11 +9308,13 @@ delete_command (char *arg, int from_tty)
       ALL_BREAKPOINTS (b)
       {
        if (b->type != bp_call_dummy
+           && b->type != bp_std_terminate
            && b->type != bp_shlib_event
            && b->type != bp_jit_event
            && b->type != bp_thread_event
            && b->type != bp_overlay_event
            && b->type != bp_longjmp_master
+           && b->type != bp_std_terminate_master
            && b->number >= 0)
          {
            breaks_to_delete = 1;
@@ -9241,11 +9329,13 @@ delete_command (char *arg, int from_tty)
          ALL_BREAKPOINTS_SAFE (b, temp)
          {
            if (b->type != bp_call_dummy
+               && b->type != bp_std_terminate
                && b->type != bp_shlib_event
                && b->type != bp_thread_event
                && b->type != bp_jit_event
                && b->type != bp_overlay_event
                && b->type != bp_longjmp_master
+               && b->type != bp_std_terminate_master
                && b->number >= 0)
              delete_breakpoint (b);
          }
@@ -9556,6 +9646,7 @@ breakpoint_re_set_one (void *bint)
         reset later by breakpoint_re_set.  */
     case bp_overlay_event:
     case bp_longjmp_master:
+    case bp_std_terminate_master:
       delete_breakpoint (b);
       break;
 
@@ -9575,6 +9666,7 @@ breakpoint_re_set_one (void *bint)
     case bp_finish:
     case bp_watchpoint_scope:
     case bp_call_dummy:
+    case bp_std_terminate:
     case bp_step_resume:
     case bp_longjmp:
     case bp_longjmp_resume:
@@ -9620,6 +9712,7 @@ breakpoint_re_set (void)
   create_longjmp_master_breakpoint ("_longjmp");
   create_longjmp_master_breakpoint ("siglongjmp");
   create_longjmp_master_breakpoint ("_siglongjmp");
+  create_std_terminate_master_breakpoint ("std::terminate()");
 }
 \f
 /* Reset the thread number of this breakpoint:
index 197bbc4698e1b36eb4a298bed8e9da7f2b79c596..98a7157ea10e4c153b7dc6aa2818259aafa206e4 100644 (file)
@@ -83,6 +83,10 @@ enum bptype
        of scope (with hardware support for watchpoints)).  */
     bp_call_dummy,
 
+    /* A breakpoint set on std::terminate, that is used to catch
+       otherwise uncaught exceptions thrown during an inferior call.  */
+    bp_std_terminate,
+
     /* Some dynamic linkers (HP, maybe Solaris) can arrange for special
        code in the inferior to run when significant events occur in the
        dynamic linker (for example a library is loaded or unloaded).
@@ -118,6 +122,9 @@ enum bptype
 
     bp_longjmp_master,
 
+    /* Master copies of std::terminate breakpoints.  */
+    bp_std_terminate_master,
+
     bp_catchpoint,
 
     bp_tracepoint,
@@ -609,6 +616,20 @@ enum bpstat_what_main_action
     BPSTAT_WHAT_LAST
   };
 
+/* An enum indicating the kind of "stack dummy" stop.  This is a bit
+   of a misnomer because only one kind of truly a stack dummy.  */
+enum stop_stack_kind
+  {
+    /* We didn't stop at a stack dummy breakpoint.  */
+    STOP_NONE = 0,
+
+    /* Stopped at a stack dummy.  */
+    STOP_STACK_DUMMY,
+
+    /* Stopped at std::terminate.  */
+    STOP_STD_TERMINATE
+  };
+
 struct bpstat_what
   {
     enum bpstat_what_main_action main_action;
@@ -617,7 +638,7 @@ struct bpstat_what
        of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of
        continuing from a call dummy without popping the frame is not a
        useful one).  */
-    int call_dummy;
+    enum stop_stack_kind call_dummy;
   };
 
 /* The possible return values for print_bpstat, print_it_normal,
@@ -865,6 +886,9 @@ extern void delete_longjmp_breakpoint (int thread);
 extern void enable_overlay_breakpoints (void);
 extern void disable_overlay_breakpoints (void);
 
+extern void set_std_terminate_breakpoint (void);
+extern void delete_std_terminate_breakpoint (void);
+
 /* These functions respectively disable or reenable all currently
    enabled watchpoints.  When disabled, the watchpoints are marked
    call_disabled.  When reenabled, they are marked enabled.
index d6a8de36b79ea6f441a0f2bdaef0c8820a6d4909..b603cf601acd89cdd8c582951dcaff232a983ee4 100644 (file)
@@ -403,6 +403,13 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc)
   return e;
 }
 
+/* A cleanup function that calls delete_std_terminate_breakpoint.  */
+static void
+cleanup_delete_std_terminate_breakpoint (void *ignore)
+{
+  delete_std_terminate_breakpoint ();
+}
+
 /* All this stuff with a dummy frame may seem unnecessarily complicated
    (why not just save registers in GDB?).  The purpose of pushing a dummy
    frame which looks just like a real frame is so that if you call a
@@ -440,9 +447,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
   struct cleanup *args_cleanup;
   struct frame_info *frame;
   struct gdbarch *gdbarch;
-  struct breakpoint *terminate_bp = NULL;
-  struct minimal_symbol *tm;
-  struct cleanup *terminate_bp_cleanup = NULL;
+  struct cleanup *terminate_bp_cleanup;
   ptid_t call_thread_ptid;
   struct gdb_exception e;
   const char *name;
@@ -757,13 +762,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
      call.  Place a momentary breakpoint in the std::terminate function
      and if triggered in the call, rewind.  */
   if (unwind_on_terminating_exception_p)
-     {
-       struct minimal_symbol *tm = lookup_minimal_symbol  ("std::terminate()",
-                                                          NULL, NULL);
-       if (tm != NULL)
-          terminate_bp = set_momentary_breakpoint_at_pc
-            (gdbarch, SYMBOL_VALUE_ADDRESS (tm),  bp_breakpoint);
-     }
+    set_std_terminate_breakpoint ();
 
   /* Everything's ready, push all the info needed to restore the
      caller (and identify the dummy-frame) onto the dummy-frame
@@ -776,8 +775,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
   discard_cleanups (inf_status_cleanup);
 
   /* Register a clean-up for unwind_on_terminating_exception_breakpoint.  */
-  if (terminate_bp)
-    terminate_bp_cleanup = make_cleanup_delete_breakpoint (terminate_bp);
+  terminate_bp_cleanup = make_cleanup (cleanup_delete_std_terminate_breakpoint,
+                                      NULL);
 
   /* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP -
      If you're looking to implement asynchronous dummy-frames, then
@@ -878,7 +877,7 @@ When the function is done executing, GDB will silently stop."),
               name);
     }
 
-  if (stopped_by_random_signal || !stop_stack_dummy)
+  if (stopped_by_random_signal || stop_stack_dummy != STOP_STACK_DUMMY)
     {
       const char *name = get_function_name (funaddr,
                                            name_buf, sizeof (name_buf));
@@ -932,30 +931,17 @@ When the function is done executing, GDB will silently stop."),
            }
        }
 
-      if (!stop_stack_dummy)
+      if (stop_stack_dummy == STOP_STD_TERMINATE)
        {
+         /* We must get back to the frame we were before the dummy
+            call.  */
+         dummy_frame_pop (dummy_id);
 
-         /* Check if unwind on terminating exception behaviour is on.  */
-         if (unwind_on_terminating_exception_p)
-           {
-             /* Check that the breakpoint is our special std::terminate
-                breakpoint.  If it is, we do not want to kill the inferior
-                in an inferior function call. Rewind, and warn the
-                user.  */
-
-             if (terminate_bp != NULL
-                 && (inferior_thread ()->stop_bpstat->breakpoint_at->address
-                     == terminate_bp->loc->address))
-               {
-                 /* We must get back to the frame we were before the
-                    dummy call.  */
-                 dummy_frame_pop (dummy_id);
-
-                 /* We also need to restore inferior status to that before the
-                    dummy call.  */
-                 restore_inferior_status (inf_status);
-
-                 error (_("\
+         /* We also need to restore inferior status to that before
+            the dummy call.  */
+         restore_inferior_status (inf_status);
+
+         error (_("\
 The program being debugged entered a std::terminate call, most likely\n\
 caused by an unhandled C++ exception.  GDB blocked this call in order\n\
 to prevent the program from being terminated, and has restored the\n\
@@ -963,9 +949,11 @@ context to its original state before the call.\n\
 To change this behaviour use \"set unwind-on-terminating-exception off\".\n\
 Evaluation of the expression containing the function (%s)\n\
 will be abandoned."),
-                        name);
-               }
-           }
+                name);
+       }
+      else if (stop_stack_dummy == STOP_NONE)
+       {
+
          /* We hit a breakpoint inside the FUNCTION.
             Keep the dummy frame, the user may want to examine its state.
             Discard inferior status, we're not at the same point
@@ -992,10 +980,7 @@ When the function is done executing, GDB will silently stop."),
       internal_error (__FILE__, __LINE__, _("... should not be here"));
     }
 
-  /* If we get here and the std::terminate() breakpoint has been set,
-     it has to be cleaned manually.  */
-  if (terminate_bp)
-    do_cleanups (terminate_bp_cleanup);
+  do_cleanups (terminate_bp_cleanup);
 
   /* If we get here the called FUNCTION ran to completion,
      and the dummy frame has already been popped.  */
index 174acde8da7e70833a54a0b5b259104abdbfcbeb..db2232d4668e6a22de4e8400f7cf283e940b2bca 100644 (file)
@@ -155,7 +155,7 @@ int breakpoint_proceeded;
 
 /* Nonzero if stopped due to completion of a stack dummy routine.  */
 
-int stop_stack_dummy;
+enum stop_stack_kind stop_stack_dummy;
 
 /* Nonzero if stopped due to a random (unexpected) signal in inferior
    process.  */
index dc87a9e1929b520bf60d0c9e4a8b7ee4642469cd..17b2c6fbfcecf86b1ecb6ba6585ca3c04186b962 100644 (file)
@@ -297,7 +297,7 @@ extern CORE_ADDR stop_pc;
 
 /* Nonzero if stopped due to completion of a stack dummy routine.  */
 
-extern int stop_stack_dummy;
+extern enum stop_stack_kind stop_stack_dummy;
 
 /* Nonzero if program stopped due to a random (unexpected) signal in
    inferior process.  */
index 4bfe5465d249c2f2526e38d7830cd04d5ea1cfcb..5f5875957d06e8e66d52f86065de600f0789b022 100644 (file)
@@ -2904,7 +2904,7 @@ handle_inferior_event (struct execution_control_state *ecs)
   target_last_waitstatus = ecs->ws;
 
   /* Always clear state belonging to the previous time we stopped.  */
-  stop_stack_dummy = 0;
+  stop_stack_dummy = STOP_NONE;
 
   /* If it's a new process, add it to the thread database */
 
@@ -3970,7 +3970,7 @@ process_event_stop_test:
 
     if (what.call_dummy)
       {
-       stop_stack_dummy = 1;
+       stop_stack_dummy = what.call_dummy;
       }
 
     switch (what.main_action)
@@ -5460,7 +5460,7 @@ Further execution is probably impossible.\n"));
       stop_registers = regcache_dup (get_current_regcache ());
     }
 
-  if (stop_stack_dummy)
+  if (stop_stack_dummy == STOP_STACK_DUMMY)
     {
       /* Pop the empty frame that contains the stack dummy.
         This also restores inferior state prior to the call
@@ -6038,7 +6038,7 @@ struct inferior_status
 {
   bpstat stop_bpstat;
   int stop_step;
-  int stop_stack_dummy;
+  enum stop_stack_kind stop_stack_dummy;
   int stopped_by_random_signal;
   int stepping_over_breakpoint;
   CORE_ADDR step_range_start;