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]

fix attach in remote non-stop mode in some cases


Hi,

"attach" in non-stop mode wasn't working correctly against a stub we're
developing.  This target doesn't stop threads implicitly on a vAttach,
and it happened that the thread that we installed the continuation on,
wasn't the first thread that reported a stop event, which made it so
that all stop events prior to the one we installed to continuation on
didn't go through normal_stop, hence we didn't tag those threads as
stopped, although they were.  A follow up "c -a" wouldn't resume those
threads, as GDB thought they were already running.  The stub's behaviour
is perfectly legal, but GDB wasn't coping with it.

That attached patch fixes it, by adding new per-inferior
continuations for the situation that we want to do something on the
next stop of the inferior, doesn't matter which thread.

In addition, since GDB stopped the inferior explicitly,
the inferior reported "signal 0" on each thread stop, but GDB wasn't
considering it a normal signal to get in that case, which made it
so that "attach&" printed one thread stop, while it should have been
silent.

Tested on native x86-pc-linux-gnu, sync, async, all-stop/non-stop,
and checked in.

-- 
Pedro Alves
2008-11-05  Pedro Alves  <pedro@codesourcery.com>

	* defs.h (add_inferior_continuation)
	(do_all_inferior_continuations)
	(discard_all_inferior_continuations): Declare.
	* utils.c (add_inferior_continuation)
	(do_all_inferior_continuations)
	(discard_all_inferior_continuations): New.
	* inferior.h (struct inferior) <continuations>: New field.
	* inferior.c (free_inferior): Discard all the inferior
	continuations.
	* inf-loop.c (inferior_event_handler): Do all current inferior
	continuations.
	* infcmd.c (attach_command): Register an inferior continuation
	instead of a thread continuation.
	* infrun.c (handle_inferior_event): If stop_soon is
	STOP_QUIETLY_NO_SIGSTOP, also expect a TARGET_SIGNAL_0.

---
 gdb/defs.h     |   12 ++++++++++++
 gdb/inf-loop.c |    5 +++++
 gdb/infcmd.c   |    5 ++---
 gdb/inferior.c |    1 +
 gdb/inferior.h |    5 +++++
 gdb/infrun.c   |   13 +++++++++++--
 gdb/utils.c    |   53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 89 insertions(+), 5 deletions(-)

Index: src/gdb/defs.h
===================================================================
--- src.orig/gdb/defs.h	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/defs.h	2008-11-05 20:09:41.000000000 +0000
@@ -701,8 +701,12 @@ extern void free_command_lines (struct c
 
 struct continuation;
 struct thread_info;
+struct inferior;
 
 /* From utils.c */
+
+/* Thread specific continuations.  */
+
 extern void add_continuation (struct thread_info *,
 			      void (*)(void *), void *,
 			      void (*)(void *));
@@ -719,6 +723,14 @@ extern void do_all_intermediate_continua
 extern void discard_all_intermediate_continuations (void);
 extern void discard_all_intermediate_continuations_thread (struct thread_info *);
 
+/* Inferior specific (any thread) continuations.  */
+
+extern void add_inferior_continuation (void (*) (void *),
+				       void *,
+				       void (*) (void *));
+extern void do_all_inferior_continuations (void);
+extern void discard_all_inferior_continuations (struct inferior *inf);
+
 /* String containing the current directory (what getwd would return).  */
 
 extern char *current_directory;
Index: src/gdb/inf-loop.c
===================================================================
--- src.orig/gdb/inf-loop.c	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/inf-loop.c	2008-11-05 20:09:41.000000000 +0000
@@ -89,6 +89,11 @@ inferior_event_handler (enum inferior_ev
       was_sync = sync_execution;
       async_enable_stdin ();
 
+      /* Do all continuations associated with the whole inferior (not
+	 a particular thread).  */
+      if (!ptid_equal (inferior_ptid, null_ptid))
+	do_all_inferior_continuations ();
+
       /* If we were doing a multi-step (eg: step n, next n), but it
 	 got interrupted by a breakpoint, still do the pending
 	 continuations.  The continuation itself is responsible for
Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/infcmd.c	2008-11-05 20:09:41.000000000 +0000
@@ -2320,9 +2320,8 @@ attach_command (char *args, int from_tty
 	  a->args = xstrdup (args);
 	  a->from_tty = from_tty;
 	  a->async_exec = async_exec;
-	  add_continuation (inferior_thread (),
-			    attach_command_continuation, a,
-			    attach_command_continuation_free_args);
+	  add_inferior_continuation (attach_command_continuation, a,
+				     attach_command_continuation_free_args);
 	  discard_cleanups (back_to);
 	  return;
 	}
Index: src/gdb/inferior.c
===================================================================
--- src.orig/gdb/inferior.c	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/inferior.c	2008-11-05 20:09:41.000000000 +0000
@@ -45,6 +45,7 @@ current_inferior (void)
 static void
 free_inferior (struct inferior *inf)
 {
+  discard_all_inferior_continuations (inf);
   xfree (inf->private);
   xfree (inf);
 }
Index: src/gdb/inferior.h
===================================================================
--- src.orig/gdb/inferior.h	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/inferior.h	2008-11-05 20:13:02.000000000 +0000
@@ -424,6 +424,11 @@ struct inferior
      forked.  */
   int attach_flag;
 
+  /* What is left to do for an execution command after any thread of
+     this inferior stops.  For continuations associated with a
+     specific thread, see `struct thread_info'.  */
+  struct continuation *continuations;
+
   /* Private data used by the target vector implementation.  */
   struct private_inferior *private;
 };
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/infrun.c	2008-11-05 20:22:17.000000000 +0000
@@ -2834,10 +2834,19 @@ targets should add new threads to the th
 	 SIGTRAP.  Some systems (e.g. Windows), and stubs supporting
 	 target extended-remote report it instead of a SIGSTOP
 	 (e.g. gdbserver).  We already rely on SIGTRAP being our
-	 signal, so this is no exception.  */
+	 signal, so this is no exception.
+
+	 Also consider that the attach is complete when we see a
+	 TARGET_SIGNAL_0.  In non-stop mode, GDB will explicitly tell
+	 the target to stop all threads of the inferior, in case the
+	 low level attach operation doesn't stop them implicitly.  If
+	 they weren't stopped implicitly, then the stub will report a
+	 TARGET_SIGNAL_0, meaning: stopped for no particular reason
+	 other than GDB's request.  */
       if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
 	  && (ecs->event_thread->stop_signal == TARGET_SIGNAL_STOP
-	      || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP))
+	      || ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
+	      || ecs->event_thread->stop_signal == TARGET_SIGNAL_0))
 	{
 	  stop_stepping (ecs);
 	  ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
Index: src/gdb/utils.c
===================================================================
--- src.orig/gdb/utils.c	2008-11-05 20:07:52.000000000 +0000
+++ src/gdb/utils.c	2008-11-05 20:09:41.000000000 +0000
@@ -505,6 +505,59 @@ add_continuation (struct thread_info *th
   thread->continuations = (struct continuation *) as_cleanup;
 }
 
+/* Add a continuation to the continuation list of INFERIOR.  The new
+   continuation will be added at the front.  */
+
+void
+add_inferior_continuation (void (*continuation_hook) (void *), void *args,
+			   void (*continuation_free_args) (void *))
+{
+  struct inferior *inf = current_inferior ();
+  struct cleanup *as_cleanup = &inf->continuations->base;
+  make_cleanup_ftype *continuation_hook_fn = continuation_hook;
+
+  make_my_cleanup2 (&as_cleanup,
+		    continuation_hook_fn,
+		    args,
+		    continuation_free_args);
+
+  inf->continuations = (struct continuation *) as_cleanup;
+}
+
+/* Do all continuations of the current inferior.  */
+
+void
+do_all_inferior_continuations (void)
+{
+  struct cleanup *old_chain;
+  struct cleanup *as_cleanup;
+  struct inferior *inf = current_inferior ();
+
+  if (inf->continuations == NULL)
+    return;
+
+  /* Copy the list header into another pointer, and set the global
+     list header to null, so that the global list can change as a side
+     effect of invoking the continuations and the processing of the
+     preexisting continuations will not be affected.  */
+
+  as_cleanup = &inf->continuations->base;
+  inf->continuations = NULL;
+
+  /* Work now on the list we have set aside.  */
+  do_my_cleanups (&as_cleanup, NULL);
+}
+
+/* Get rid of all the inferior-wide continuations of INF.  */
+
+void
+discard_all_inferior_continuations (struct inferior *inf)
+{
+  struct cleanup *continuation_ptr = &inf->continuations->base;
+  discard_my_cleanups (&continuation_ptr, NULL);
+  inf->continuations = NULL;
+}
+
 static void
 restore_thread_cleanup (void *arg)
 {

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