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]

[RFA] Reverse-step/next and shared libraries (with testsuite)


OK, this is a bit of a rewrite for the infrun code that
handles reverse stepping into/over shared library functions
and trampolines.  I believe we now correctly handle various
combinations of ...
  * reverse-step, reverse-next
  * trampolines, solib-dynsym-resolver
  * resolved and unresolved symbols
  * debuggable (user) and undebuggable (eg. libc) functions

This also includes the first testsuite test case for reverse
debugging.  If this one's accepted, I've got more queued up.

Hui, this patch will replace your patch http://sourceware.org/ml/gdb-patches/2009-03/msg00005.html,
so I'll appreciate your review.


Marc, this patch should fix all of your solib step/next bugs.

No regressions on linux-i686.

2009-06-21  Michael Snyder  <msnyder@vmware.com>

	* infrun.c (handle_inferior_event): Improve handling of
	reverse-stepping into and over shared library functions.

2009-06-21  Michael Snyder  <msnyder@vmware.com>

	* gdb.base/solib-reverse.exp: New file.
	* gdb.base/solib-reverse.c: New file.

Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.392
diff -u -p -r1.392 infrun.c
--- infrun.c	18 Jun 2009 23:55:57 -0000	1.392
+++ infrun.c	21 Jun 2009 22:50:22 -0000
@@ -3639,7 +3639,7 @@ infrun: not switching back to stepped th
   if (stop_pc >= ecs->event_thread->step_range_start
       && stop_pc < ecs->event_thread->step_range_end
       && (execution_direction != EXEC_REVERSE
-	  || frame_id_eq (get_frame_id (get_current_frame ()),
+	  || frame_id_eq (get_frame_id (frame),
 			  ecs->event_thread->step_frame_id)))
     {
       if (debug_infrun)
@@ -3667,10 +3667,19 @@ infrun: not switching back to stepped th
   /* We stepped out of the stepping range.  */
 
   /* If we are stepping at the source level and entered the runtime
-     loader dynamic symbol resolution code, we keep on single stepping
-     until we exit the run time loader code and reach the callee's
-     address.  */
-  if (ecs->event_thread->step_over_calls == STEP_OVER_UNDEBUGGABLE
+     loader dynamic symbol resolution code...
+
+     EXEC_FORWARD: we keep on single stepping until we exit the run
+     time loader code and reach the callee's address.
+
+     EXEC_REVERSE: we've already executed the callee (backward), and
+     the runtime loader code is handled just like any other
+     undebuggable function call.  Now we need only keep stepping
+     backward through the trampoline code, and that's handled further
+     down, so there is nothing for us to do here.  */
+
+  if (execution_direction != EXEC_REVERSE
+      && ecs->event_thread->step_over_calls == STEP_OVER_UNDEBUGGABLE
       && in_solib_dynsym_resolve_code (stop_pc))
     {
       CORE_ADDR pc_after_resolver =
@@ -3740,12 +3749,29 @@ infrun: not switching back to stepped th
 	  /* Also, maybe we just did a "nexti" inside a prolog, so we
 	     thought it was a subroutine call but it was not.  Stop as
 	     well.  FENN */
+	  /* And this works the same backward as frontward.  MVS */
 	  ecs->event_thread->stop_step = 1;
 	  print_stop_reason (END_STEPPING_RANGE, 0);
 	  stop_stepping (ecs);
 	  return;
 	}
 
+      /* Reverse stepping through solib trampolines.  */
+
+      if (execution_direction == EXEC_REVERSE
+	  && (gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc)
+	      || (ecs->stop_func_start == 0
+		  && in_solib_dynsym_resolve_code (stop_pc))))
+	{
+	  /* Any solib trampoline code can be handled in reverse
+	     by simply continuing to single-step.  We have already
+	     executed the solib function (backwards), and a few 
+	     steps will take us back through the trampoline to the
+	     caller.  */
+	  keep_going (ecs);
+	  return;
+	}
+
       if (ecs->event_thread->step_over_calls == STEP_OVER_ALL)
 	{
 	  /* We're doing a "next".
@@ -3763,35 +3789,10 @@ infrun: not switching back to stepped th
 	    {
 	      struct symtab_and_line sr_sal;
 
-	      if (ecs->stop_func_start == 0 
-		  && in_solib_dynsym_resolve_code (stop_pc))
-		{
-		  /* Stepped into runtime loader dynamic symbol
-		     resolution code.  Since we're in reverse, 
-		     we have already backed up through the runtime
-		     loader and the dynamic function.  This is just
-		     the trampoline (jump table).
-
-		     Just keep stepping, we'll soon be home.
-		  */
-		  keep_going (ecs);
-		  return;
-		}
-	      if (gdbarch_skip_trampoline_code(current_gdbarch,
-					       get_current_frame (),
-					       stop_pc))
-		{
-		  /* We are in a function call trampoline.
-		     Keep stepping backward to get to the caller.  */
-		  ecs->event_thread->stepping_over_breakpoint = 1;
-		}
-	      else
-		{
-		  /* Normal function call return (static or dynamic).  */
-		  init_sal (&sr_sal);
-		  sr_sal.pc = ecs->stop_func_start;
-		  insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
-		}
+	      /* Normal function call return (static or dynamic).  */
+	      init_sal (&sr_sal);
+	      sr_sal.pc = ecs->stop_func_start;
+	      insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
 	    }
 	  else
 	    insert_step_resume_breakpoint_at_caller (frame);
Index: testsuite/gdb.base/solib-reverse.c
===================================================================
RCS file: testsuite/gdb.base/solib-reverse.c
diff -N testsuite/gdb.base/solib-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/solib-reverse.c	21 Jun 2009 22:54:01 -0000
@@ -0,0 +1,26 @@
+/* Test reverse debugging of shared libraries.  */
+
+#include <stdio.h>
+
+/* Shared library function */
+extern int shr2(int);
+
+int main ()
+{
+  char* cptr = "String 1";
+  int b[2] = {5,8};
+
+  b[0] = shr2(12);		/* begin part two */
+  b[1] = shr2(17);		/* middle part two */
+
+  b[0] = 6;   b[1] = 9;		/* generic statement, end part two */
+  printf ("message 1\n");	/* printf one */
+  printf ("message 2\n");	/* printf two */
+  printf ("message 3\n");	/* printf three */
+  sleep (0);			/* sleep one */
+  sleep (0);			/* sleep two */
+  sleep (0);			/* sleep three */
+
+  return 0;			/* end part one */
+}
+
Index: testsuite/gdb.base/solib-reverse.exp
===================================================================
RCS file: testsuite/gdb.base/solib-reverse.exp
diff -N testsuite/gdb.base/solib-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/solib-reverse.exp	21 Jun 2009 22:54:01 -0000
@@ -0,0 +1,127 @@
+# Copyright 2009
+# Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Michael Snyder (msnyder@vmware.com).
+
+#
+# Test reverse debugging with shared libraries.
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "solib-reverse"
+set srcfile  ${testfile}.c
+set libfile  "shr2"
+set libsrc   ${libfile}.c
+set library  ${objdir}/${subdir}/${libfile}.sl
+set binfile  ${objdir}/${subdir}/${testfile}
+
+if [get_compiler_info ${binfile}] {
+    return -1
+}
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/${libsrc} ${library} "debug"] != "" } {
+    untested "Could not compile shared library."
+    return -1
+}
+
+set exec_opts [list debug shlib=${library}]
+
+if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable $exec_opts] != "" } {
+    untested "Could not compile $binfile."
+    return -1
+}
+     
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+#
+# Test reverse-step over undebuggable solib functions.
+#
+
+# Run forward past some solib function calls.
+
+set end_part_one [gdb_get_line_number " end part one" "$srcfile"]
+set end_part_two [gdb_get_line_number " end part two" "$srcfile"]
+gdb_test "until $end_part_one" " end part one.*" "run until end part one"
+
+gdb_test "reverse-step" " sleep three .*" "reverse-step third sleep"
+gdb_test "reverse-step" " sleep two .*"   "reverse-step second sleep"
+gdb_test "reverse-step" " sleep one .*"   \
+		    "reverse-step first sleep, dynsym resolve"
+
+gdb_test "reverse-step" " printf three .*" "reverse-step third printf"
+gdb_test "reverse-step" " printf two .*"   "reverse-step second printf"
+gdb_test "reverse-step" " printf one .*"   \
+		    "reverse-step first printf, dynsym resolve"
+gdb_test "reverse-step" " generic statement.*" "reverse-step generic"
+
+
+#
+# Test reverse-next over undebuggable solib functions.
+#
+
+# Run forward again...
+
+gdb_test "until $end_part_one" " end part one.*" "forward to end part one"
+
+gdb_test "reverse-next" " sleep three .*" "reverse-next third sleep"
+gdb_test "reverse-next" " sleep two .*"   "reverse-next second sleep"
+gdb_test "reverse-next" " sleep one .*"   \
+		    "reverse-next first sleep, dynsym resolve"
+
+gdb_test "reverse-next" " printf three .*" "reverse-next third printf"
+gdb_test "reverse-next" " printf two .*"   "reverse-next second printf"
+gdb_test "reverse-next" " printf one .*"   \
+		    "reverse-next first printf, dynsym resolve"
+gdb_test "reverse-next" " generic statement.*" "reverse-next generic"
+
+
+#
+# Test reverse-step into debuggable solib function
+#
+
+gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function one"
+gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function one"
+gdb_test "reverse-step" " middle part two.*" "reverse-step back to main one"
+
+gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function two"
+gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function two"
+gdb_test "reverse-step" " begin part two.*" "reverse-step back to main two"
+
+#
+# Test reverse-next over debuggable solib function
+#
+
+gdb_test "until $end_part_two" " end part two.*" "run until end part two"
+
+gdb_test "reverse-next" " middle part two.*" "reverse-next over solib function one"
+gdb_test "reverse-next" " begin part two.*" "reverse-next over solib function two"

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