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]

RFC: change longjmp logic to follow exception logic


I'd appreciate comments on this patch.

Fedora 16 has SystemTap probe points in its glibc longjmp code, and it
ships a gdb with these probes enabled.  This means that when debugging
gdb itself, I finally got to see how the longjmp logic worked in
practice.

I have found it to be quite confusing to use.  The issue is that any
longjump will cause the inferior to stop.  For example, this behavior
means that "next"ing will often cause a stop in some random bit of code
much further down the stack; and then I have to use multiple "finish"es
to get somewhere close to where I started, so I can finish the "next" by
hand.

This is basically never what I want gdb to do.

Instead, I would like gdb's longjmp behavior to work more like gdb's
"next over throw" behavior.  That is, if I "next" in a given frame, only
longjmps which are caught in that frame, or somewhere above it, should
cause a stop.

That is what this patch implements.

Built and regtested on x86-64 Fedora 16.
I modified the longjmp test case to reflect the new behavior.

Tom

2012-06-08  Tom Tromey  <tromey@redhat.com>

	* infrun.c (handle_inferior_event)
	<BPSTAT_WHAT_SET_LONGJMP_RESUME>: Don't delete the step-resume
	breakpoint.
	<BPSTAT_WHAT_CLEAR_LONGJMP_RESUME>: Remove longjmp logic; use
	exception logic in all cases.  Update comments.
	(insert_longjmp_resume_breakpoint): Set the exception resume
	breakpoint.

2012-06-08  Tom Tromey  <tromey@redhat.com>

	* gdb.base/longjmp.c (hidden_longjmp): Move expected catch
	location...
	(main): ...here.

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 210cdd7..b98e379 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -4423,10 +4423,6 @@ process_event_stop_test:
 		return;
 	      }
 
-	    /* We're going to replace the current step-resume breakpoint
-	       with a longjmp-resume breakpoint.  */
-	    delete_step_resume_breakpoint (ecs->event_thread);
-
 	    /* Insert a breakpoint at resume address.  */
 	    insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc);
 	  }
@@ -4436,62 +4432,59 @@ process_event_stop_test:
 	return;
 
       case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
-        if (debug_infrun)
-	  fprintf_unfiltered (gdb_stdlog,
-			      "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
+	{
+	  struct frame_info *init_frame;
 
-	if (what.is_longjmp)
-	  {
-	    gdb_assert (ecs->event_thread->control.step_resume_breakpoint
-			!= NULL);
-	    delete_step_resume_breakpoint (ecs->event_thread);
-	  }
-	else
-	  {
-	    /* There are several cases to consider.
+	  /* There are several cases to consider.
 
-	       1. The initiating frame no longer exists.  In this case
-	       we must stop, because the exception has gone too far.
+	     1. The initiating frame no longer exists.  In this case
+	     we must stop, because the exception or longjmp has gone
+	     too far.
 
-	       2. The initiating frame exists, and is the same as the
-	       current frame.  We stop, because the exception has been
-	       caught.
+	     2. The initiating frame exists, and is the same as the
+	     current frame.  We stop, because the exception or longjmp
+	     has been caught.
 
-	       3. The initiating frame exists and is different from
-	       the current frame.  This means the exception has been
-	       caught beneath the initiating frame, so keep going.  */
-	    struct frame_info *init_frame
-	      = frame_find_by_id (ecs->event_thread->initiating_frame);
+	     3. The initiating frame exists and is different from the
+	     current frame.  This means the exception or longjmp has
+	     been caught beneath the initiating frame, so keep
+	     going.  */
 
-	    gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
-			!= NULL);
-	    delete_exception_resume_breakpoint (ecs->event_thread);
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
 
-	    if (init_frame)
-	      {
-		struct frame_id current_id
-		  = get_frame_id (get_current_frame ());
-		if (frame_id_eq (current_id,
-				 ecs->event_thread->initiating_frame))
-		  {
-		    /* Case 2.  Fall through.  */
-		  }
-		else
-		  {
-		    /* Case 3.  */
-		    keep_going (ecs);
-		    return;
-		  }
-	      }
+	  init_frame = frame_find_by_id (ecs->event_thread->initiating_frame);
 
-	    /* For Cases 1 and 2, remove the step-resume breakpoint,
-	       if it exists.  */
-	    delete_step_resume_breakpoint (ecs->event_thread);
-	  }
+	  gdb_assert (ecs->event_thread->control.exception_resume_breakpoint
+		      != NULL);
+	  delete_exception_resume_breakpoint (ecs->event_thread);
 
-	ecs->event_thread->control.stop_step = 1;
-	print_end_stepping_range_reason ();
-	stop_stepping (ecs);
+	  if (init_frame)
+	    {
+	      struct frame_id current_id
+		= get_frame_id (get_current_frame ());
+	      if (frame_id_eq (current_id,
+			       ecs->event_thread->initiating_frame))
+		{
+		  /* Case 2.  Fall through.  */
+		}
+	      else
+		{
+		  /* Case 3.  */
+		  keep_going (ecs);
+		  return;
+		}
+	    }
+
+	  /* For Cases 1 and 2, remove the step-resume breakpoint,
+	     if it exists.  */
+	  delete_step_resume_breakpoint (ecs->event_thread);
+
+	  ecs->event_thread->control.stop_step = 1;
+	  print_end_stepping_range_reason ();
+	  stop_stepping (ecs);
+	}
 	return;
 
       case BPSTAT_WHAT_SINGLE:
@@ -5461,17 +5454,17 @@ insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame)
 static void
 insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, 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
+  /* There should never be more than one longjmp-resume breakpoint per
+     thread, so we should never be setting a new
      longjmp_resume_breakpoint when one is already active.  */
-  gdb_assert (inferior_thread ()->control.step_resume_breakpoint == NULL);
+  gdb_assert (inferior_thread ()->control.exception_resume_breakpoint == NULL);
 
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog,
 			"infrun: inserting longjmp-resume breakpoint at %s\n",
 			paddress (gdbarch, pc));
 
-  inferior_thread ()->control.step_resume_breakpoint =
+  inferior_thread ()->control.exception_resume_breakpoint =
     set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume);
 }
 
diff --git a/gdb/testsuite/gdb.base/longjmp.c b/gdb/testsuite/gdb.base/longjmp.c
index e9e0e56..b203a8d 100644
--- a/gdb/testsuite/gdb.base/longjmp.c
+++ b/gdb/testsuite/gdb.base/longjmp.c
@@ -33,7 +33,7 @@ call_longjmp (jmp_buf *buf)
 void
 hidden_longjmp (void)
 {
-  if (setjmp (env) == 0) /* longjmp caught */
+  if (setjmp (env) == 0)
     {
       call_longjmp (&env);
     }
@@ -75,6 +75,8 @@ main ()
   /* Pattern 3 - setjmp/longjmp inside stepped-over function.  */
   hidden_longjmp (); /* patt3 */
 
+  i = 77; /* longjmp caught */
+
   i = 3; /* patt_end3.  */
 
   return 0;


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