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 1/4] - Only longjmp if going outer.


Here's the patch that implements the decision to follow the longjmp, or if
the current step-resume breakpoint is to be kept.

This adds a new parameter to the gdbarch_get_longjmp_target to also
extract the SP out of it.  Then, whenever we're setting a step-resume
breakpoint, we store the current SP in it.  If a longjmp is hit, we
extract the PC and SP out of the jmp_buf, and compare the SP with
what was stored in the step-resume breakpoint.  If the longjmp would
take us outer frame we follow it, otherwise, we just keep going as
if we didn't see the longjmp.

Updating all targets will be done in patch 3.

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

	* breakpoint.h (struct breakpoint): Add bp_specific member.
	* gdbarch.sh (get_longjmp_target): Add *sp parameter.
	* infrun.c (handle_inferior_event): When handling a longjmp
	breakpoint, if the step-resume breakpoint frame is outer in
	relation to the longjmp-resume's, ignore the longjmp.
	(is_longjmp, longjmp_at_pc_p): New.
	(insert_step_resume_breakpoint_at_sal): Set step_resume_sp to -1.
	(insert_step_resume_breakpoint_at_caller): If not stepping into a
	longjmp, mark current SP of caller in the breakpoint.
	* gdbarch.c, gdbarch.h: Regenerate.

---
 gdb/breakpoint.h |   10 ++++++
 gdb/gdbarch.c    |    4 +-
 gdb/gdbarch.h    |    4 +-
 gdb/gdbarch.sh   |    2 -
 gdb/infrun.c     |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 95 insertions(+), 6 deletions(-)

Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h	2008-04-07 13:50:56.000000000 +0100
+++ src/gdb/breakpoint.h	2008-04-07 13:51:17.000000000 +0100
@@ -450,6 +450,16 @@ struct breakpoint
        no location initially so had no context to parse
        the condition in.  */
     int condition_not_parsed;
+
+    union
+    {
+      struct step_resume
+      {
+	/* The stack pointer contents of the frame the breakpoint was
+	   set at, or -1 if invalid.  */
+	CORE_ADDR sp;
+      } step_resume;
+    } bp_specific;
   };
 
 typedef struct breakpoint *breakpoint_p;
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c	2008-04-05 23:52:10.000000000 +0100
+++ src/gdb/gdbarch.c	2008-04-07 13:51:17.000000000 +0100
@@ -1875,13 +1875,13 @@ gdbarch_get_longjmp_target_p (struct gdb
 }
 
 int
-gdbarch_get_longjmp_target (struct gdbarch *gdbarch, struct frame_info *frame, CORE_ADDR *pc)
+gdbarch_get_longjmp_target (struct gdbarch *gdbarch, struct frame_info *frame, CORE_ADDR *pc, CORE_ADDR *sp)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->get_longjmp_target != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_get_longjmp_target called\n");
-  return gdbarch->get_longjmp_target (frame, pc);
+  return gdbarch->get_longjmp_target (frame, pc, sp);
 }
 
 void
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h	2008-04-05 23:52:10.000000000 +0100
+++ src/gdb/gdbarch.h	2008-04-07 13:51:17.000000000 +0100
@@ -318,8 +318,8 @@ extern void set_gdbarch_cannot_store_reg
 
 extern int gdbarch_get_longjmp_target_p (struct gdbarch *gdbarch);
 
-typedef int (gdbarch_get_longjmp_target_ftype) (struct frame_info *frame, CORE_ADDR *pc);
-extern int gdbarch_get_longjmp_target (struct gdbarch *gdbarch, struct frame_info *frame, CORE_ADDR *pc);
+typedef int (gdbarch_get_longjmp_target_ftype) (struct frame_info *frame, CORE_ADDR *pc, CORE_ADDR *sp);
+extern int gdbarch_get_longjmp_target (struct gdbarch *gdbarch, struct frame_info *frame, CORE_ADDR *pc, CORE_ADDR *sp);
 extern void set_gdbarch_get_longjmp_target (struct gdbarch *gdbarch, gdbarch_get_longjmp_target_ftype *get_longjmp_target);
 
 extern int gdbarch_believe_pcc_promotion (struct gdbarch *gdbarch);
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh	2008-04-05 23:52:10.000000000 +0100
+++ src/gdb/gdbarch.sh	2008-04-07 13:51:17.000000000 +0100
@@ -453,7 +453,7 @@ m:int:register_sim_regno:int reg_nr:reg_
 m:int:cannot_fetch_register:int regnum:regnum::cannot_register_not::0
 m:int:cannot_store_register:int regnum:regnum::cannot_register_not::0
 # setjmp/longjmp support.
-F:int:get_longjmp_target:struct frame_info *frame, CORE_ADDR *pc:frame, pc
+F:int:get_longjmp_target:struct frame_info *frame, CORE_ADDR *pc, CORE_ADDR *sp:frame, pc, sp
 #
 v:int:believe_pcc_promotion:::::::
 #
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2008-04-07 13:50:56.000000000 +0100
+++ src/gdb/infrun.c	2008-04-07 13:53:47.000000000 +0100
@@ -2095,6 +2095,7 @@ process_event_stop_test:
   /* Handle cases caused by hitting a breakpoint.  */
   {
     CORE_ADDR jmp_buf_pc;
+    CORE_ADDR jmp_buf_sp;
     struct bpstat_what what;
 
     what = bpstat_what (stop_bpstat);
@@ -2119,7 +2120,8 @@ process_event_stop_test:
 
 	if (!gdbarch_get_longjmp_target_p (current_gdbarch)
 	    || !gdbarch_get_longjmp_target (current_gdbarch,
-					    get_current_frame (), &jmp_buf_pc))
+					    get_current_frame (),
+					    &jmp_buf_pc, &jmp_buf_sp))
 	  {
 	    if (debug_infrun)
 	      fprintf_unfiltered (gdb_stdlog, "\
@@ -2128,6 +2130,32 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (
 	    return;
 	  }
 
+ 	/* If there's a step-resume breakpoint inserted, and the
+ 	   step-resume is outermost compared to the longjmp-resume
+ 	   frame, then, we want to silently ignore this longjmp.  */
+ 	if (step_resume_breakpoint)
+ 	  {
+ 	    CORE_ADDR srsp = step_resume_breakpoint->bp_specific.step_resume.sp;
+ 	    if (debug_infrun)
+ 	      fprintf_unfiltered (gdb_stdlog,
+ 				  "infrun step-resume sp(%s), jmp_buf_sp(%s)\n",
+ 				  paddr_nz (srsp), paddr_nz (jmp_buf_sp));
+
+ 	    if (srsp != ~ (CORE_ADDR) 0
+ 		&& gdbarch_inner_than (current_gdbarch, jmp_buf_sp, srsp))
+ 	      {
+ 		if (debug_infrun)
+ 		  fprintf_unfiltered (gdb_stdlog,
+ 				      "infrun: prefering step-resume\n");
+
+ 		keep_going (ecs);
+ 		return;
+ 	      }
+ 	  }
+
+ 	if (debug_infrun)
+ 	  fprintf_unfiltered (gdb_stdlog, "infrun: prefering longjmp-resume\n");
+
 	/* We're going to replace the current step-resume breakpoint
 	   with a longjmp-resume breakpoint.  */
 	if (step_resume_breakpoint != NULL)
@@ -2798,6 +2826,49 @@ step_into_function (struct execution_con
   keep_going (ecs);
 }
 
+static int
+is_longjmp (struct general_symbol_info *ginfo)
+{
+  static const char *longjmp_names[] =
+    {
+      "longjmp", "longjmp@plt",
+      "_longjmp", "_longjmp@plt",
+      "siglongjmp", "siglongjmp@plt",
+      "_siglongjmp", "_siglongjmp@plt"
+    };
+
+  const char *name = ginfo->name;
+  int i;
+
+  if (!name)
+    return 0;
+
+  for (i = 0;
+       i < sizeof (longjmp_names) / sizeof (longjmp_names[0]);
+       i++)
+    if (strcmp (name, longjmp_names[i]) == 0)
+      return 1;
+
+  return 0;
+}
+
+static int
+longjmp_at_pc_p (CORE_ADDR pc)
+{
+  struct minimal_symbol *min_sym;
+  struct symbol *sym;
+
+  min_sym = lookup_minimal_symbol_by_pc (pc);
+  if (min_sym && is_longjmp (&min_sym->ginfo))
+    return 1;
+
+  sym = find_pc_function (pc);
+  if (sym && is_longjmp (&sym->ginfo))
+    return 1;
+
+  return 0;
+}
+
 /* Insert a "step-resume breakpoint" at SR_SAL with frame ID SR_ID.
    This is used to both functions and to skip over code.  */
 
@@ -2817,6 +2888,7 @@ insert_step_resume_breakpoint_at_sal (st
 
   step_resume_breakpoint = set_momentary_breakpoint (sr_sal, sr_id,
 						     bp_step_resume);
+  step_resume_breakpoint->bp_specific.step_resume.sp = ~ (CORE_ADDR) 0;
 }
 
 /* Insert a "step-resume breakpoint" at RETURN_FRAME.pc.  This is used
@@ -2872,6 +2944,13 @@ insert_step_resume_breakpoint_at_caller 
   sr_sal.section = find_pc_overlay (sr_sal.pc);
 
   insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame));
+
+  /* Store the caller's SP for comparision with the lompjmp-resume SP
+     in infrun.c, except if we detect we entered a longjmp.  In that
+     case, we always want to follow it.  */
+  if (!longjmp_at_pc_p (get_frame_pc (next_frame)))
+    step_resume_breakpoint->bp_specific.step_resume.sp =
+      get_frame_sp (next_frame);
 }
 
 /* Insert a "longjmp-resume" breakpoint at PC.  This is used to set a

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