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]

3/5 - Rework stepping over longjmp support


This rework was motivated by the non-stop mode.

To handle stepping over longjmp, currently, we create internal
disabled breakpoints on everything that looks like a 
longjmp : "longjmp", "_longjmp", "siglongjmp", and "_siglongjmp".
These should cover all cases and all OSs.  The basic
idea it that when one of these breakpoints is hit, we look
into the jmp_buf passed into longjmp, and extract the
destination PC from it.  We then set a breakpoint at
that address, and let the inferior hit it.  This handling
is only desirable when the user is activelly doing a 
next or a step.  We don't care for the inferior hitting
a longjmp when the inferior is running freely -- if we
left the breakpoint enabled all the time, even when
not stepping (e.g., user did a continue, and no user
breakpoints were hit, the inferior just runs
uninterrupted), anytime the inferior called longjmp, it
would hit the breakpoint, and then gdb would notice the
inferior was not being stepped, so it should be resumed
immediately.  It is much more efficient to not hit that
breakpoint at all in that case.  So far, so good, this
works OK in all-stop mode.  Well, in theory, because the
current implementation is broken.

However, in non-stop mode, we can step more than one thread
independenly and simultaneously.  Having one thread finish a
step, and disable the global longjmp breakpoint at that
point, while another thread is still stepping is definitelly
wrong.  The other thread may happen to step a longjmp and it
would go unnoticed.  Basically, we need to associate
the longjmp breakpoints with each stepping thread.
Fortunally, the concept of per-thread breakpoints already
exists in GDB.

The current implementation sets a handling_longjmp variable
when a longjmp is hit, and we insert a longjmp-resume
breakpoint.  If you look at infrun.c, you'll see there's
always a FIXME associated with it.  And it's right, because
it's handling is broken.

You can easilly see it breaking, by trying to step over
something like this:

#include <setjmp.h>

jmp_buf env;

int
call_longjmp (jmp_buf *buf)
{
  longjmp (*buf, 1);
}

int main ()
{
  if (setjmp (env) == 0) /* patt2 */
    {
      call_longjmp (&env);  <<<<<<<< try to step over this.
    }
  else
    {
      printf ("resumed\n");
    }
}

Basically, the symptom is that GDB will not stop at the longjmp-resume
address, instead the inferior will run to exit.  Quite annoying.

Instead of trying to explain deeply why the current implementation
is broken (has to do with bad breakpoint handling, thread hopping,
removing breakpoints at the wrong time, and the handling_longjmp
variable getting in the way), I propose another implementation.
We get rid of handling_longjmp, and instead, we handle a
longjmp-resume breakpoint much like a step-resume breakpoint.  It's
natural to not have both set at the same time, and the current
code already gets rid of the active step-resume breakpoint when
inserting the  longjmp-resume breakpoint.  Setting
step_resume_breakpoint to the new longjmp-resume breakpoint
is exactly what we want.  We want to keep stepping while it
is set, we want to context switch it.  We want to delete it everywhere
a step-resume is being deleted.  Of course, we could have a
seperate per-thread context-switchable longjmp_resume_breakpoint
instead, since we never have both a longjmp-resume and a
step-resume breakpoint simulatenously (in a given thread), and
it's handling would be equal everywhere else, it just feels better
to overload step_resume_breakpoint.

This patch implements the same behaviour that's in HEAD (if it weren't broken 
a lot of the times) where any longjmp hit while stepping, causes the
step to stop.  

-- 
Pedro Alves

P.S.:

However, we could extend this to be smarter.  E.g.:

void
hidden_longjmp (void)
{
  if (setjmp (env) == 0)
    {
      longjmp (env, 1);
    }
  else
    {
      printf ("resumed\n");
    }
}

int
main ()
{
   hidden_longjmp (); <<<< step over this.
}

The longjmp inside hidden_longjmp is going to land inside
hidden_longjmp.  GDB could ignore it leave the step-resume
breakpoint at the return of hidden_longjmp and pretend
that longjmp was never seen.  Think of stepping over a function
in gdb's sources, and an exception being thrown and caught all
somewhere inner to the function you're stepping.  I've
implemented a prototype patch that does this.  Does anyone
else think that behaviour is useful?  (I'm aware that any
smartness we add can be defeated by longjmp changing stacks,
or stuff like debugging coroutines implemented with set/longjmp,
but those feel like rare enough that a smart mode could be
the default and useful most of (almost-all) the times.)

2008-04-07  Pedro Alves  <pedro@codesourcery.com>

	* breakpoint.c (update_breakpoints_after_exec): Delete bp_longjmp
	and bp_longjmp_resume breakpoints.
	(breakpoint_address_is_meaningful): Claim bp_longjmp_resume as
	meaningful.
	(create_longjmp_breakpoint): Don't create bp_longjmp_resume
	breakpoints.  Create bp_longjmp breakpoints as momentary
	breakpoints.
	(enable_longjmp_breakpoint): Delete.
	(set_longjmp_breakpoint): New.
	(disable_longjmp_breakpoint): Delete.
	(delete_longjmp_breakpoint_thread, delete_longjmp_breakpoint):
	New.
	(set_longjmp_resume_breakpoint): Delete.
	(set_momentary_breakpoint_at_pc): New.
	(breakpoint_re_set_one): Don't delete bp_longjmp and
	bp_longjmp_resume breakpoints.
	(breakpoint_re_set): Don't create longjmp and longjmp-resume
	breakpoints.

	* infrun.c (step_resume_breakpoint): Add comment.
	(struct execution_control_state): Delete handling_longjmp member.
	(init_execution_control_state). Don't clear handling_longjmp.
	(context_switch): Don't context switch handling_longjmp.
	(handle_inferior_event): If handling a bp_longjmp breakpoint,
	create a bp_longjmp_resume breakpoint, and set it as current
	step_resume_breakpoint, then step over the longjmp breakpoint.  If
	handling a bp_longjmp_resume breakpoint, don't delete the longjmp
	breakpoint, delete the longjmp-resume breakpoint, and stop
	stepping.
	(currently_stepping): Remove handling_longjmp from expression.
	(insert_step_resume_breakpoint_at_sal): Update comment.
	(insert_longjmp_resume_breakpoint): New.

	* breakpoint.h (set_momentary_breakpoint_at_pc): Declare.
	(enable_longjmp_breakpoint, disable_longjmp_breakpoint): Delete
	declarations.
	(set_longjmp_breakpoint, delete_longjmp_breakpoint)
	(delete_longjmp_breakpoint_thread): Declare.
	(set_longjmp_resume_breakpoint): Delete declaration.

	* gdbthread.h (save_infrun_state): Remove handling_longjmp parameter.
	(load_infrun_state): Delete *handling_longjmp parameter.
	* thread.c (save_infrun_state): Remove handling_longjmp parameter.  Update body.
	(load_infrun_state): Delete *handling_longjmp parameter.  Update body.

	* infcmd.c Include "gdbthread.h".
	(disable_longjmp_breakpoint_cleanup): Delete.
	(delete_longjmp_breakpoint_cleanup): New.
	(step_1): Call set_longjmp_breakpoint instead of
	enable_longjmp_breakpoint.  Use delete_longjmp_breakpoint_cleanup
	instead of disable_longjmp_breakpoint_cleanup when making cleanup.

	* Makefile.in (infcmd.o): Update.

---
 gdb/Makefile.in  |    2 
 gdb/breakpoint.c |  112 +++++++++++++++++++++----------------------------------
 gdb/breakpoint.h |    9 ++--
 gdb/gdbthread.h  |    3 -
 gdb/infcmd.c     |   26 ++++++++++--
 gdb/infrun.c     |   86 +++++++++++++++++++++++++++++-------------
 gdb/thread.c     |    4 -
 7 files changed, 131 insertions(+), 111 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2008-04-07 02:24:30.000000000 +0100
+++ src/gdb/breakpoint.c	2008-04-07 02:28:24.000000000 +0100
@@ -149,8 +149,6 @@ static int watchpoint_check (void *);
 
 static void maintenance_info_breakpoints (char *, int);
 
-static void create_longjmp_breakpoint (char *);
-
 static void create_overlay_event_breakpoint (char *);
 
 static int hw_breakpoint_used_count (void);
@@ -1430,6 +1428,14 @@ update_breakpoints_after_exec (void)
 	continue;
       }
 
+    /* Longjmp and longjmp-resume breakpoints are also meaningless
+       after an exec.  */
+    if (b->type == bp_longjmp || b->type == bp_longjmp_resume)
+      {
+	delete_breakpoint (b);
+	continue;
+      }
+
     /* Don't delete an exec catchpoint, because else the inferior
        won't stop when it ought!
 
@@ -3968,7 +3974,6 @@ set_default_breakpoint (int valid, CORE_
       bp_read_watchpoint
       bp_access_watchpoint
       bp_catch_exec
-      bp_longjmp_resume
       bp_catch_fork
       bp_catch_vork */
 
@@ -3982,7 +3987,6 @@ breakpoint_address_is_meaningful (struct
 	  && type != bp_read_watchpoint
 	  && type != bp_access_watchpoint
 	  && type != bp_catch_exec
-	  && type != bp_longjmp_resume
 	  && type != bp_catch_fork
 	  && type != bp_catch_vfork);
 }
@@ -4349,20 +4353,9 @@ create_longjmp_breakpoint (char *func_na
   struct breakpoint *b;
   struct minimal_symbol *m;
 
-  if (func_name == NULL)
-    b = create_internal_breakpoint (0, bp_longjmp_resume);
-  else
-    {
-      if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
-	return;
- 
-      b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
-    }
-
-  b->enable_state = bp_disabled;
-  b->silent = 1;
-  if (func_name)
-    b->addr_string = xstrdup (func_name);
+  if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL)
+    return;
+  set_momentary_breakpoint_at_pc (SYMBOL_VALUE_ADDRESS (m), bp_longjmp);
 }
 
 /* Call this routine when stepping and nexting to enable a breakpoint
@@ -4370,30 +4363,31 @@ create_longjmp_breakpoint (char *func_na
    set_longjmp_resume_breakpoint() to figure out where we are going. */
 
 void
-enable_longjmp_breakpoint (void)
+set_longjmp_breakpoint (void)
 {
   struct breakpoint *b;
 
-  ALL_BREAKPOINTS (b)
-    if (b->type == bp_longjmp)
+  if (gdbarch_get_longjmp_target_p (current_gdbarch))
     {
-      b->enable_state = bp_enabled;
-      check_duplicates (b);
+      create_longjmp_breakpoint ("longjmp");
+      create_longjmp_breakpoint ("_longjmp");
+      create_longjmp_breakpoint ("siglongjmp");
+      create_longjmp_breakpoint ("_siglongjmp");
     }
 }
 
+/* Delete all longjmp breakpoints from PTID.  */
 void
-disable_longjmp_breakpoint (void)
+delete_longjmp_breakpoint (int thread)
 {
-  struct breakpoint *b;
+  struct breakpoint *b, *temp;
 
-  ALL_BREAKPOINTS (b)
-    if (b->type == bp_longjmp
-	|| b->type == bp_longjmp_resume)
-    {
-      b->enable_state = bp_disabled;
-      check_duplicates (b);
-    }
+  ALL_BREAKPOINTS_SAFE (b, temp)
+    if (b->type == bp_longjmp)
+      {
+	if (b->thread == thread)
+	  delete_breakpoint (b);
+      }
 }
 
 static void
@@ -4679,30 +4673,6 @@ hw_watchpoint_used_count (enum bptype ty
   return i;
 }
 
-/* Call this after hitting the longjmp() breakpoint.  Use this to set
-   a new breakpoint at the target of the jmp_buf.
-
-   FIXME - This ought to be done by setting a temporary breakpoint
-   that gets deleted automatically... */
-
-void
-set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_id frame_id)
-{
-  struct breakpoint *b;
-
-  ALL_BREAKPOINTS (b)
-    if (b->type == bp_longjmp_resume)
-    {
-      b->loc->requested_address = pc;
-      b->loc->address = adjust_breakpoint_address (b->loc->requested_address,
-                                                   b->type);
-      b->enable_state = bp_enabled;
-      b->frame_id = frame_id;
-      check_duplicates (b);
-      return;
-    }
-}
-
 void
 disable_watchpoints_before_interactive_call_start (void)
 {
@@ -4764,6 +4734,19 @@ set_momentary_breakpoint (struct symtab_
 
   return b;
 }
+
+struct breakpoint *
+set_momentary_breakpoint_at_pc (CORE_ADDR pc, enum bptype type)
+{
+  struct symtab_and_line sal;
+
+  sal = find_pc_line (pc, 0);
+  sal.pc = pc;
+  sal.section = find_pc_overlay (pc);
+  sal.explicit_pc = 1;
+
+  return set_momentary_breakpoint (sal, null_frame_id, type);
+}
 
 
 /* Tell the user we have just set a breakpoint B.  */
@@ -7423,10 +7406,8 @@ breakpoint_re_set_one (void *bint)
     default:
       printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type);
       /* fall through */
-      /* Delete longjmp and overlay event breakpoints; they will be
-         reset later by breakpoint_re_set.  */
-    case bp_longjmp:
-    case bp_longjmp_resume:
+      /* Delete overlay event breakpoints; they will be reset later by
+         breakpoint_re_set.  */
     case bp_overlay_event:
       delete_breakpoint (b);
       break;
@@ -7448,6 +7429,8 @@ breakpoint_re_set_one (void *bint)
     case bp_watchpoint_scope:
     case bp_call_dummy:
     case bp_step_resume:
+    case bp_longjmp:
+    case bp_longjmp_resume:
       break;
     }
 
@@ -7475,15 +7458,6 @@ breakpoint_re_set (void)
   }
   set_language (save_language);
   input_radix = save_input_radix;
-
-  if (gdbarch_get_longjmp_target_p (current_gdbarch))
-    {
-      create_longjmp_breakpoint ("longjmp");
-      create_longjmp_breakpoint ("_longjmp");
-      create_longjmp_breakpoint ("siglongjmp");
-      create_longjmp_breakpoint ("_siglongjmp");
-      create_longjmp_breakpoint (NULL);
-    }
   
   create_overlay_event_breakpoint ("_ovly_debug_event");
 }
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2008-04-07 02:24:30.000000000 +0100
+++ src/gdb/infrun.c	2008-04-07 02:41:01.000000000 +0100
@@ -271,6 +271,7 @@ struct regcache *stop_registers;
 
 static int stop_print_frame;
 
+/* Step-resume or longjmp-resume breakpoint.  */
 static struct breakpoint *step_resume_breakpoint = NULL;
 
 /* This is a cached copy of the pid/waitstatus of the last event
@@ -947,7 +948,6 @@ struct execution_control_state
   struct symtab_and_line sal;
   int current_line;
   struct symtab *current_symtab;
-  int handling_longjmp;		/* FIXME */
   ptid_t ptid;
   ptid_t saved_inferior_ptid;
   int step_after_step_resume_breakpoint;
@@ -969,6 +969,8 @@ static void insert_step_resume_breakpoin
 static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
 static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal,
 						  struct frame_id sr_id);
+static void insert_longjmp_resume_breakpoint (CORE_ADDR);
+
 static void stop_stepping (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static void keep_going (struct execution_control_state *ecs);
@@ -1118,7 +1120,6 @@ init_execution_control_state (struct exe
   ecs->stepping_over_breakpoint = 0;
   ecs->random_signal = 0;
   ecs->step_after_step_resume_breakpoint = 0;
-  ecs->handling_longjmp = 0;	/* FIXME */
   ecs->stepping_through_solib_after_catch = 0;
   ecs->stepping_through_solib_catchpoints = NULL;
   ecs->sal = find_pc_line (prev_pc, 0);
@@ -1173,7 +1174,7 @@ context_switch (struct execution_control
 			 stepping_over_breakpoint, step_resume_breakpoint,
 			 step_range_start,
 			 step_range_end, &step_frame_id,
-			 ecs->handling_longjmp, ecs->stepping_over_breakpoint,
+			 ecs->stepping_over_breakpoint,
 			 ecs->stepping_through_solib_after_catch,
 			 ecs->stepping_through_solib_catchpoints,
 			 ecs->current_line, ecs->current_symtab);
@@ -1183,7 +1184,7 @@ context_switch (struct execution_control
 			 &stepping_over_breakpoint, &step_resume_breakpoint,
 			 &step_range_start,
 			 &step_range_end, &step_frame_id,
-			 &ecs->handling_longjmp, &ecs->stepping_over_breakpoint,
+			 &ecs->stepping_over_breakpoint,
 			 &ecs->stepping_through_solib_after_catch,
 			 &ecs->stepping_through_solib_catchpoints,
 			 &ecs->current_line, &ecs->current_symtab);
@@ -2106,38 +2107,50 @@ process_event_stop_test:
     switch (what.main_action)
       {
       case BPSTAT_WHAT_SET_LONGJMP_RESUME:
-	/* If we hit the breakpoint at longjmp, disable it for the
-	   duration of this command.  Then, install a temporary
-	   breakpoint at the target of the jmp_buf. */
-        if (debug_infrun)
-	  fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
-	disable_longjmp_breakpoint ();
+	/* If we hit the breakpoint at longjmp while stepping, we
+	   install a momentary breakpoint at the target of the
+	   jmp_buf.  */
+
+	if (debug_infrun)
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n");
+
+	ecs->stepping_over_breakpoint = 1;
+
 	if (!gdbarch_get_longjmp_target_p (current_gdbarch)
 	    || !gdbarch_get_longjmp_target (current_gdbarch,
 					    get_current_frame (), &jmp_buf_pc))
 	  {
+	    if (debug_infrun)
+	      fprintf_unfiltered (gdb_stdlog, "\
+infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	    keep_going (ecs);
 	    return;
 	  }
 
-	/* Need to blow away step-resume breakpoint, as it
-	   interferes with us */
+	/* We're going to replace the current step-resume breakpoint
+	   with a longjmp-resume breakpoint.  */
 	if (step_resume_breakpoint != NULL)
-	  {
-	    delete_step_resume_breakpoint (&step_resume_breakpoint);
-	  }
+	  delete_step_resume_breakpoint (&step_resume_breakpoint);
+
+	/* Insert a breakpoint at resume address.  */
+	insert_longjmp_resume_breakpoint (jmp_buf_pc);
 
-	set_longjmp_resume_breakpoint (jmp_buf_pc, null_frame_id);
-	ecs->handling_longjmp = 1;	/* FIXME */
 	keep_going (ecs);
 	return;
 
       case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
         if (debug_infrun)
-	  fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
-	disable_longjmp_breakpoint ();
-	ecs->handling_longjmp = 0;	/* FIXME */
-	break;
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
+
+	gdb_assert (step_resume_breakpoint != NULL);
+	delete_step_resume_breakpoint (&step_resume_breakpoint);
+
+	stop_step = 1;
+	print_stop_reason (END_STEPPING_RANGE, 0);
+	stop_stepping (ecs);
+	return;
 
       case BPSTAT_WHAT_SINGLE:
         if (debug_infrun)
@@ -2704,9 +2717,8 @@ process_event_stop_test:
 static int
 currently_stepping (struct execution_control_state *ecs)
 {
-  return ((!ecs->handling_longjmp
-	   && ((step_range_end && step_resume_breakpoint == NULL)
-	       || stepping_over_breakpoint))
+  return (((step_range_end && step_resume_breakpoint == NULL)
+	   || stepping_over_breakpoint)
 	  || ecs->stepping_through_solib_after_catch
 	  || bpstat_should_step ());
 }
@@ -2793,8 +2805,8 @@ static void
 insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal,
 				      struct frame_id sr_id)
 {
-  /* There should never be more than one step-resume breakpoint per
-     thread, so we should never be setting a new
+  /* There should never be more than one step-resume or longjmp-resume
+     breakpoint per thread, so we should never be setting a new
      step_resume_breakpoint when one is already active.  */
   gdb_assert (step_resume_breakpoint == NULL);
 
@@ -2862,6 +2874,28 @@ insert_step_resume_breakpoint_at_caller 
   insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame));
 }
 
+/* Insert a "longjmp-resume" breakpoint at PC.  This is used to set a
+   new breakpoint at the target of a jmp_buf.  The handling of
+   longjmp-resume uses the same mechanisms used for handling
+   "step-resume" breakpoints.  */
+
+static void
+insert_longjmp_resume_breakpoint (CORE_ADDR pc)
+{
+  /* There should never be more than one step-resume or longjmp-resume
+     breakpoint per thread, so we should never be setting a new
+     longjmp_resume_breakpoint when one is already active.  */
+  gdb_assert (step_resume_breakpoint == NULL);
+
+  if (debug_infrun)
+    fprintf_unfiltered (gdb_stdlog,
+			"infrun: inserting longjmp-resume breakpoint at 0x%s\n",
+			paddr_nz (pc));
+
+  step_resume_breakpoint =
+    set_momentary_breakpoint_at_pc (pc, bp_longjmp_resume);
+}
+
 static void
 stop_stepping (struct execution_control_state *ecs)
 {
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h	2008-04-07 02:24:30.000000000 +0100
+++ src/gdb/breakpoint.h	2008-04-07 02:28:24.000000000 +0100
@@ -686,6 +686,9 @@ extern int ep_is_exception_catchpoint (s
 extern struct breakpoint *set_momentary_breakpoint
   (struct symtab_and_line, struct frame_id, enum bptype);
 
+extern struct breakpoint *set_momentary_breakpoint_at_pc
+  (CORE_ADDR pc, enum bptype type);
+
 extern void set_ignore_count (int, int, int);
 
 extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int);
@@ -756,12 +759,12 @@ extern void update_breakpoints_after_exe
    inferior_ptid.  */
 extern int detach_breakpoints (int);
 
-extern void enable_longjmp_breakpoint (void);
-extern void disable_longjmp_breakpoint (void);
+extern void set_longjmp_breakpoint (void);
+extern void delete_longjmp_breakpoint (int thread);
+
 extern void enable_overlay_breakpoints (void);
 extern void disable_overlay_breakpoints (void);
 
-extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_id);
 /* 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: src/gdb/gdbthread.h
===================================================================
--- src.orig/gdb/gdbthread.h	2008-04-07 02:24:30.000000000 +0100
+++ src/gdb/gdbthread.h	2008-04-07 02:28:24.000000000 +0100
@@ -50,7 +50,6 @@ struct thread_info
   int current_line;
   struct symtab *current_symtab;
   int trap_expected;
-  int handling_longjmp;
   int stepping_over_breakpoint;
 
   /* This is set TRUE when a catchpoint of a shared library event
@@ -123,7 +122,6 @@ extern void save_infrun_state (ptid_t pt
 			       CORE_ADDR step_range_start,
 			       CORE_ADDR step_range_end,
 			       const struct frame_id *step_frame_id,
-			       int       handling_longjmp,
 			       int       another_trap,
 			       int       stepping_through_solib_after_catch,
 			       bpstat    stepping_through_solib_catchpoints,
@@ -139,7 +137,6 @@ extern void load_infrun_state (ptid_t pt
 			       CORE_ADDR *step_range_start,
 			       CORE_ADDR *step_range_end,
 			       struct frame_id *step_frame_id,
-			       int       *handling_longjmp,
 			       int       *another_trap,
 			       int       *stepping_through_solib_affter_catch,
 			       bpstat    *stepping_through_solib_catchpoints,
Index: src/gdb/thread.c
===================================================================
--- src.orig/gdb/thread.c	2008-04-07 02:24:30.000000000 +0100
+++ src/gdb/thread.c	2008-04-07 02:28:24.000000000 +0100
@@ -316,7 +316,6 @@ load_infrun_state (ptid_t ptid,
 		   CORE_ADDR *step_range_start,
 		   CORE_ADDR *step_range_end,
 		   struct frame_id *step_frame_id,
-		   int *handling_longjmp,
 		   int *stepping_over_breakpoint,
 		   int *stepping_through_solib_after_catch,
 		   bpstat *stepping_through_solib_catchpoints,
@@ -337,7 +336,6 @@ load_infrun_state (ptid_t ptid,
   *step_range_start = tp->step_range_start;
   *step_range_end = tp->step_range_end;
   *step_frame_id = tp->step_frame_id;
-  *handling_longjmp = tp->handling_longjmp;
   *stepping_over_breakpoint = tp->stepping_over_breakpoint;
   *stepping_through_solib_after_catch =
     tp->stepping_through_solib_after_catch;
@@ -357,7 +355,6 @@ save_infrun_state (ptid_t ptid,
 		   CORE_ADDR step_range_start,
 		   CORE_ADDR step_range_end,
 		   const struct frame_id *step_frame_id,
-		   int handling_longjmp,
 		   int stepping_over_breakpoint,
 		   int stepping_through_solib_after_catch,
 		   bpstat stepping_through_solib_catchpoints,
@@ -378,7 +375,6 @@ save_infrun_state (ptid_t ptid,
   tp->step_range_start = step_range_start;
   tp->step_range_end = step_range_end;
   tp->step_frame_id = (*step_frame_id);
-  tp->handling_longjmp = handling_longjmp;
   tp->stepping_over_breakpoint = stepping_over_breakpoint;
   tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch;
   tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints;
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c	2008-04-07 02:24:30.000000000 +0100
+++ src/gdb/infcmd.c	2008-04-07 02:28:24.000000000 +0100
@@ -49,6 +49,7 @@
 #include "target-descriptions.h"
 #include "user-regs.h"
 #include "exceptions.h"
+#include "gdbthread.h"
 
 /* Functions exported for general use, in inferior.h: */
 
@@ -689,9 +690,11 @@ nexti_command (char *count_string, int f
 }
 
 static void
-disable_longjmp_breakpoint_cleanup (void *ignore)
+delete_longjmp_breakpoint_cleanup (void *arg)
 {
-  disable_longjmp_breakpoint ();
+  int thread = * (int *) arg;
+  xfree (arg);
+  delete_longjmp_breakpoint (thread);
 }
 
 static void
@@ -724,11 +727,24 @@ step_1 (int skip_subroutines, int single
 
   if (!single_inst || skip_subroutines)		/* leave si command alone */
     {
-      enable_longjmp_breakpoint ();
+      struct cleanup *old_chain;
+      int *thread;
+
+      thread = xmalloc (sizeof (int));
+      old_chain = make_cleanup (xfree, thread);
+
+      if (in_thread_list (inferior_ptid))
+	*thread = pid_to_thread_id (inferior_ptid);
+      else
+	*thread = -1;
+
+      set_longjmp_breakpoint ();
+
+      discard_cleanups (old_chain);
       if (!target_can_async_p ())
-	cleanups = make_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/);
+	cleanups = make_cleanup (delete_longjmp_breakpoint_cleanup, thread);
       else
-        make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/);
+        make_exec_cleanup (delete_longjmp_breakpoint_cleanup, thread);
     }
 
   /* In synchronous case, all is well, just use the regular for loop. */
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2008-04-07 02:28:11.000000000 +0100
+++ src/gdb/Makefile.in	2008-04-07 02:41:05.000000000 +0100
@@ -2291,7 +2291,7 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_strin
 	$(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \
 	$(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \
 	$(solib_h) $(gdb_assert_h) $(observer_h) $(target_descriptions_h) \
-	$(user_regs_h) $(exceptions_h)
+	$(user_regs_h) $(exceptions_h) $(gdbthread_h)
 inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \
 	$(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) \
 	$(language_h)

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