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]

Re: [rfc / remote protocol] Remote shared library events


On Thu, May 10, 2007 at 11:34:51PM +0200, Mark Kettenis wrote:
> I think this diff needs to be split up.  I looked at it twice now, but
> I don't see how the bits are related, and the changes to infrun.c make
> me very nervous.

Here are just the infrun parts.  They've gained a test case for the
trickiest part, a cleanup, a better changelog, and an explanation.

First of all, I don't remember why I was testing
inferior_ignoring_startup_exec_events in the last version of this
patch.  I discovered that now there are no references to it (there may
have been one when I wrote it).  I didn't really need it, so I garbage
collected it.

Secondly, I needed to make TARGET_WAITKIND_LOADED support work with
the current solib.c implementation.  You can tell it hasn't been used
in a while since it was conditioned on "#ifdef SOLIB_ADD"; there are
almost no definitions of that left.

Third, while debugging shared library support for SymbianOS I kept
encountering an unpleasant surprise.  I would disconnect from the
remote target when it was stopped at a load event (usually because my
GDB crashed :-).  When I reconnected, GDB would automatically resume
the program!  That's where the ugly stop_soon test was in the last
version of this.  For this version, I reviewed every setting and use
of stop_soon and decided that none of them quite matched the case in
stop_remote, so I added a new STOP_QUIETLY_REMOTE (and some comments
about it).  This is just like STOP_QUIETLY_NO_SIGSTOP except that it
does not need to hide a SIGSTOP if it finds one.  It means we're
connecting to the target for the first time, so we shouldn't decide to
resume it without giving the user a chance to look around.

I hope this version is clearer; what do you think of it?

-- 
Daniel Jacobowitz
CodeSourcery

2007-05-15  Daniel Jacobowitz  <dan@codesourcery.com>

	* infrun.c (inferior_ignoring_startup_exec_events): Delete.
	(start_remote): Use STOP_QUIETLY_REMOTE.
	(handle_inferior_event): Do not condition TARGET_WAITKIND_LOADED
	support on a SOLIB_ADD definition.  Update breakpoints_inserted.
	Update to match shared library event breakpoint support.  Only
	resume if appropriate.  Handle STOP_QUIETLY_REMOTE.
	(normal_stop): Handle TARGET_WAITKIND_LOADED.
	* fork-child.c (startup_inferior): Do not set
	inferior_ignoring_startup_exec_events
	* inferior.h (inferior_ignoring_startup_exec_events): Delete
	declaration.
	(enum stop_kind): Improve documentation.  Add STOP_QUIETLY_REMOTE.

	* config/gdbserver.exp (gdb_reconnect): New.
	* gdb.base/so-disc-shr.c, gdb.base/solib-disc.c,
	gdb.base/solib-disc.exp: New files.
	* lib/gdb.exp (gdb_test_multiple): Allow tests to match "Ending
	remote debugging".
	(gdb_compile): Add shlib_load flag.
	* lib/gdbserver-support.exp (gdbserver_run): Save the protocol and
	port.
	(gdbserver_reconnect): New.

---
 gdb/fork-child.c                        |    4 -
 gdb/inferior.h                          |   26 ++------
 gdb/infrun.c                            |   79 ++++++++++++++++++++----
 gdb/testsuite/config/gdbserver.exp      |    4 +
 gdb/testsuite/gdb.base/so-disc-shr.c    |   25 +++++++
 gdb/testsuite/gdb.base/solib-disc.c     |   57 +++++++++++++++++
 gdb/testsuite/gdb.base/solib-disc.exp   |  104 ++++++++++++++++++++++++++++++++
 gdb/testsuite/lib/gdb.exp               |   17 ++++-
 gdb/testsuite/lib/gdbserver-support.exp |   18 ++++-
 9 files changed, 292 insertions(+), 42 deletions(-)

Index: gdb/infrun.c
===================================================================
--- gdb/infrun.c.orig	2007-05-11 09:21:52.000000000 -0400
+++ gdb/infrun.c	2007-05-15 09:10:23.000000000 -0400
@@ -84,7 +84,6 @@ static int prepare_to_proceed (void);
 
 void _initialize_infrun (void);
 
-int inferior_ignoring_startup_exec_events = 0;
 int inferior_ignoring_leading_exec_events = 0;
 
 /* When set, stop the 'step' command if we enter a function which has
@@ -821,7 +820,7 @@ start_remote (int from_tty)
 {
   init_thread_list ();
   init_wait_for_inferior ();
-  stop_soon = STOP_QUIETLY;
+  stop_soon = STOP_QUIETLY_REMOTE;
   trap_expected = 0;
 
   /* Always go on waiting for the target, regardless of the mode. */
@@ -1308,16 +1307,22 @@ handle_inferior_event (struct execution_
     case TARGET_WAITKIND_LOADED:
       if (debug_infrun)
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
-      /* Ignore gracefully during startup of the inferior, as it
-         might be the shell which has just loaded some objects,
-         otherwise add the symbols for the newly loaded objects.  */
-#ifdef SOLIB_ADD
+      /* Ignore gracefully during startup of the inferior, as it might
+         be the shell which has just loaded some objects, otherwise
+         add the symbols for the newly loaded objects.  Also ignore at
+         the beginning of an attach or remote session; we will query
+         the full list of libraries once the connection is
+         established.  */
       if (stop_soon == NO_STOP_QUIETLY)
 	{
+	  int breakpoints_were_inserted;
+
 	  /* Remove breakpoints, SOLIB_ADD might adjust
 	     breakpoint addresses via breakpoint_re_set.  */
+	  breakpoints_were_inserted = breakpoints_inserted;
 	  if (breakpoints_inserted)
 	    remove_breakpoints ();
+	  breakpoints_inserted = 0;
 
 	  /* Check for any newly added shared libraries if we're
 	     supposed to be adding them automatically.  Switch
@@ -1339,17 +1344,50 @@ handle_inferior_event (struct execution_
 	     exec/process stratum, instead relying on the target stack
 	     to propagate relevant changes (stop, section table
 	     changed, ...) up to other layers.  */
+#ifdef SOLIB_ADD
 	  SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+#else
+	  solib_add (NULL, 0, &current_target, auto_solib_add);
+#endif
 	  target_terminal_inferior ();
 
+	  /* Try to reenable shared library breakpoints, additional
+	     code segments in shared libraries might be mapped in now. */
+	  re_enable_breakpoints_in_shlibs ();
+
+	  /* If requested, stop when the dynamic linker notifies
+	     gdb of events.  This allows the user to get control
+	     and place breakpoints in initializer routines for
+	     dynamically loaded objects (among other things).  */
+	  if (stop_on_solib_events)
+	    {
+	      stop_stepping (ecs);
+	      return;
+	    }
+
+	  /* NOTE drow/2007-05-11: This might be a good place to check
+	     for "catch load".  */
+
 	  /* Reinsert breakpoints and continue.  */
-	  if (breakpoints_inserted)
-	    insert_breakpoints ();
+	  if (breakpoints_were_inserted)
+	    {
+	      insert_breakpoints ();
+	      breakpoints_inserted = 1;
+	    }
 	}
-#endif
-      resume (0, TARGET_SIGNAL_0);
-      prepare_to_wait (ecs);
-      return;
+
+      /* If we are skipping through a shell, or through shared library
+	 loading that we aren't interested in, resume the program.  If
+	 we're running the program normally, also resume.  But stop if
+	 we're attaching or setting up a remote connection.  */
+      if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
+	{
+	  resume (0, TARGET_SIGNAL_0);
+	  prepare_to_wait (ecs);
+	  return;
+	}
+
+      break;
 
     case TARGET_WAITKIND_SPURIOUS:
       if (debug_infrun)
@@ -1872,7 +1910,8 @@ handle_inferior_event (struct execution_
 	  && (stop_signal == TARGET_SIGNAL_ILL
 	      || stop_signal == TARGET_SIGNAL_SEGV
 	      || stop_signal == TARGET_SIGNAL_EMT))
-      || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP)
+      || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
+      || stop_soon == STOP_QUIETLY_REMOTE)
     {
       if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
 	{
@@ -1885,7 +1924,7 @@ handle_inferior_event (struct execution_
 
       /* This is originated from start_remote(), start_inferior() and
          shared libraries hook functions.  */
-      if (stop_soon == STOP_QUIETLY)
+      if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
 	{
           if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
@@ -3170,6 +3209,18 @@ Further execution is probably impossible
 	  switch (bpstat_ret)
 	    {
 	    case PRINT_UNKNOWN:
+	      /* If we had hit a shared library event breakpoint,
+		 bpstat_print would print out this message.  If we hit
+		 an OS-level shared library event, do the same
+		 thing.  */
+	      if (last.kind == TARGET_WAITKIND_LOADED)
+		{
+		  printf_filtered (_("Stopped due to shared library event\n"));
+		  source_flag = SRC_LINE;	/* something bogus */
+		  do_frame_printing = 0;
+		  break;
+		}
+
 	      /* FIXME: cagney/2002-12-01: Given that a frame ID does
 	         (or should) carry around the function and does (or
 	         should) use that when doing a frame comparison.  */
Index: gdb/fork-child.c
===================================================================
--- gdb/fork-child.c.orig	2007-05-11 12:57:25.000000000 -0400
+++ gdb/fork-child.c	2007-05-11 12:57:37.000000000 -0400
@@ -416,10 +416,6 @@ startup_inferior (int ntraps)
 
   init_wait_for_inferior ();
 
-  if (STARTUP_WITH_SHELL)
-    inferior_ignoring_startup_exec_events = ntraps;
-  else
-    inferior_ignoring_startup_exec_events = 0;
   inferior_ignoring_leading_exec_events =
     target_reported_exec_events_per_exec_call () - 1;
 
Index: gdb/inferior.h
===================================================================
--- gdb/inferior.h.orig	2007-05-11 12:48:02.000000000 -0400
+++ gdb/inferior.h	2007-05-11 12:57:21.000000000 -0400
@@ -124,20 +124,7 @@ extern int target_executing;
    redisplay the prompt until the execution is actually over. */
 extern int sync_execution;
 
-/* This is only valid when inferior_ptid is non-zero.
-
-   If this is 0, then exec events should be noticed and responded to
-   by the debugger (i.e., be reported to the user).
-
-   If this is > 0, then that many subsequent exec events should be
-   ignored (i.e., not be reported to the user).
- */
-extern int inferior_ignoring_startup_exec_events;
-
-/* This is only valid when inferior_ignoring_startup_exec_events is
-   zero.
-
-   Some targets (stupidly) report more than one exec event per actual
+/* Some targets (stupidly) report more than one exec event per actual
    call to an event() system call.  If only the last such exec event
    need actually be noticed and responded to by the debugger (i.e.,
    be reported to the user), then this is the number of "leading"
@@ -355,10 +342,12 @@ extern enum step_over_calls_kind step_ov
 
 extern int step_multi;
 
-/* Nonzero means expecting a trap and caller will handle it
-   themselves.  It is used when running in the shell before the child
-   program has been exec'd; and when running some kinds of remote
-   stuff (FIXME?).  */
+/* Anything but NO_STOP_QUIETLY means we expect a trap and the caller
+   will handle it themselves.  STOP_QUIETLY is used when running in
+   the shell before the child program has been exec'd and when running
+   through shared library loading.  STOP_QUIETLY_REMOTE is used when
+   setting up a remote connection; it is like STOP_QUIETLY_NO_SIGSTOP
+   except that there is no need to hide a signal.  */
 
 /* It is also used after attach, due to attaching to a process. This
    is a bit trickier.  When doing an attach, the kernel stops the
@@ -382,6 +371,7 @@ enum stop_kind
   {
     NO_STOP_QUIETLY = 0,
     STOP_QUIETLY,
+    STOP_QUIETLY_REMOTE,
     STOP_QUIETLY_NO_SIGSTOP
   };
 
Index: gdb/testsuite/config/gdbserver.exp
===================================================================
--- gdb/testsuite/config/gdbserver.exp.orig	2007-05-15 07:58:34.000000000 -0400
+++ gdb/testsuite/config/gdbserver.exp	2007-05-15 07:58:50.000000000 -0400
@@ -81,3 +81,7 @@ proc gdbserver_gdb_load { } {
 proc gdb_reload { } {
     return [gdbserver_run ""]
 }
+
+proc gdb_reconnect { } {
+    return [gdbserver_reconnect]
+}
Index: gdb/testsuite/gdb.base/so-disc-shr.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb/testsuite/gdb.base/so-disc-shr.c	2007-05-15 09:01:21.000000000 -0400
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2007 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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#include <stdio.h>
+
+void shrfunc (void)
+{
+  printf ("in shrfunc\n");
+}
Index: gdb/testsuite/gdb.base/solib-disc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb/testsuite/gdb.base/solib-disc.c	2007-05-15 09:01:21.000000000 -0400
@@ -0,0 +1,57 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2007 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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#define dlopen(name, mode) LoadLibrary (name)
+#define dlsym(handle, func) GetProcAddress (handle, func)
+#define dlclose(handle) FreeLibrary (handle)
+#define dlerror() "an error occurred"
+#else
+#include <dlfcn.h>
+#endif
+
+int main()
+{
+  void *handle;
+  void (*func) (void);
+
+  handle = dlopen (SHLIB_NAME, RTLD_LAZY);
+  if (!handle)
+    {
+      fprintf (stderr, dlerror ());
+      exit (1);
+    }
+
+  func = (void (*)(void)) dlsym (handle, "shrfunc");
+  if (!func)
+    {
+      fprintf (stderr, dlerror ());
+      exit (1);
+    }
+
+  func ();
+
+  dlclose (handle);
+
+  return 0;
+}
Index: gdb/testsuite/gdb.base/solib-disc.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb/testsuite/gdb.base/solib-disc.exp	2007-05-15 09:01:21.000000000 -0400
@@ -0,0 +1,104 @@
+# Copyright 2007 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+# Test connecting and disconnecting at shared library events.
+
+if {[skip_shlib_tests]} {
+    return 0
+}
+
+if { [info proc gdb_reconnect] == "" } {
+    return 0
+}
+
+set testfile solib-disc
+set libfile so-disc-shr
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+set libsrc "${srcdir}/${subdir}/${libfile}.c"
+set libname "${libfile}.so"
+set libobj "${objdir}/${subdir}/${libname}"
+set execsrc "${srcdir}/${subdir}/${srcfile}"
+
+remote_exec build "rm -f ${binfile}"
+
+if [get_compiler_info ${binfile}] {
+    return -1
+}
+
+set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${libname}\"]
+
+if { [gdb_compile_shlib $libsrc $libobj {debug}] != ""
+     || [gdb_compile $execsrc ${binfile} executable $exec_opts] != "" } {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+gdb_load_shlibs $libobj
+
+if ![runto_main] then {
+    fail "Can't run to main"
+    return 0
+}
+
+gdb_test "set stop-on-solib-events 1" ""
+
+gdb_test "continue" "Stopped due to shared library event" "continue to load"
+
+set msg "save \$pc after load"
+set saved_pc ""
+gdb_test_multiple "print/x \$pc" $msg {
+    -re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" {
+	set saved_pc $expect_out(1,string)
+	pass $msg
+    }
+}
+
+gdb_test "disconnect" "Ending remote debugging\\." "disconnect after load"
+if { [gdb_reconnect] == 0 } {
+    pass "reconnect after load"
+} else {
+    fail "reconnect after load"
+    return 0
+}
+
+gdb_test "print/x \$pc" "\\\$$decimal = $saved_pc" "check \$pc after load"
+
+
+gdb_test "continue" "Stopped due to shared library event" "continue to unload"
+
+set msg "save \$pc after unload"
+set saved_pc ""
+gdb_test_multiple "print/x \$pc" $msg {
+    -re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" {
+	set saved_pc $expect_out(1,string)
+	pass $msg
+    }
+}
+
+gdb_test "disconnect" "Ending remote debugging\\." "disconnect after unload"
+if { [gdb_reconnect] == 0 } {
+    pass "reconnect after unload"
+} else {
+    fail "reconnect after unload"
+    return 0
+}
+
+gdb_test "print/x \$pc" "\\\$$decimal = $saved_pc" "check \$pc after unload"
Index: gdb/testsuite/lib/gdb.exp
===================================================================
--- gdb/testsuite/lib/gdb.exp.orig	2007-05-15 08:18:12.000000000 -0400
+++ gdb/testsuite/lib/gdb.exp	2007-05-15 08:29:30.000000000 -0400
@@ -671,6 +671,9 @@ proc gdb_test_multiple { command message
 	     gdb_suppress_entire_file "GDB died";
 	     set result -1;
 	 }
+    }
+    append code $processed_code
+    append code {
 	 -re "Ending remote debugging.*$gdb_prompt $" {
 	    if ![isnative] then {
 		warning "Can`t communicate to remote target."
@@ -679,9 +682,6 @@ proc gdb_test_multiple { command message
 	    gdb_start
 	    set result -1
 	}
-    }
-    append code $processed_code
-    append code {
 	 -re "Undefined\[a-z\]* command:.*$gdb_prompt $" {
 	    perror "Undefined command \"$command\"."
             fail "$message"
@@ -1543,6 +1543,17 @@ proc gdb_compile {source dest type optio
                     lappend options "additional_flags=-rpath ${objdir}/${subdir}"
                 }
             }
+	} elseif { $opt == "shlib_load" } {
+	    if { ([istarget "*-*-mingw*"]
+		  || [istarget *-*-cygwin*]
+		  || [istarget *-*-pe*]
+		  || [istarget arm*-*-symbianelf*]
+		  || [istarget hppa*-*-hpux*])} {
+		# Do not need anything.
+	    } else {
+		lappend new_options "libs=-ldl"
+		lappend new_options "additional_flags=-Wl,-rpath,\\\$ORIGIN"
+	    }
         } else {
             lappend new_options $opt
         }
Index: gdb/testsuite/lib/gdbserver-support.exp
===================================================================
--- gdb/testsuite/lib/gdbserver-support.exp.orig	2007-05-15 07:57:23.000000000 -0400
+++ gdb/testsuite/lib/gdbserver-support.exp	2007-05-15 08:16:48.000000000 -0400
@@ -236,9 +236,21 @@ proc gdbserver_spawn { child_args } {
 # to it.  Return 0 on success, or non-zero on failure.
 
 proc gdbserver_run { child_args } {
+    global gdbserver_protocol
+    global gdbserver_gdbport
+
     set res [gdbserver_spawn $child_args]
-    set protocol [lindex $res 0]
-    set gdbport [lindex $res 1]
+    set gdbserver_protocol [lindex $res 0]
+    set gdbserver_gdbport [lindex $res 1]
+
+    return [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport]
+}
+
+# Reconnect to the previous gdbserver session.
+
+proc gdbserver_reconnect { } {
+    global gdbserver_protocol
+    global gdbserver_gdbport
 
-    return [gdb_target_cmd $protocol $gdbport]
+    return [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport]
 }


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