This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
fix attach in remote non-stop mode in some cases
- From: Pedro Alves <pedro at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 5 Nov 2008 20:26:39 +0000
- Subject: 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)
{