From c72f45d16c16954478dcd87531df146f68acd87c Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 22 Oct 2015 16:40:45 +0100 Subject: [PATCH] gdb/Windows: use windows_wait/windows_resume directly in initial startup Explation below based on what Joel wrote at: https://sourceware.org/ml/gdb-patches/2015-10/msg00274.html The merge async/sync code paths patch broke attaching on Windows. This is what we observe, after attaching to any process. At first, it seems like everything worked fine, since the process stops, and we get the prompt back: (gdb) att 3156 Attaching to program `C:\[...]\foo.exe', process 3156 [New Thread 3156.0xcd8] [New Thread 3156.0xfe4] 0x7770000d in ntdll!DbgBreakPoint () from C:\Windows\SysWOW64\ntdll.dll (gdb) However, enter any commands at all, and GDB appears to be hanging. For instance: (gdb) set lang ada [nothing happens] Despite appearances, GDB is not reading from the prompt. It is blocked waiting for an event from the inferior. And since our inferior is stopped, there aren't going to be any events to read. In chronological order, what happens is that windows_attach calls do_initial_windows_stuff, which performs the inferior creation, and repeatedly waits until we get the first SIGTRAP: while (1) { stop_after_trap = 1; wait_for_inferior (); tp = inferior_thread (); if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP) resume (tp->suspend.stop_signal); else break; } The call to wait_for_inferior triggers a call to do_target_wait to get the event, followed by handle_inferior_event to process it. However, because the first couple of events are "spurious" events, GDB resumes the execution, and prepares the inferior to wait again: case TARGET_WAITKIND_SPURIOUS: [...] resume (GDB_SIGNAL_0); prepare_to_wait (ecs); And prepare_to_wait just does... ecs->wait_some_more = 1; if (!target_is_async_p ()) mark_infrun_async_event_handler (); ... which as a result sets the infrun_async_event_handler "ready" flag to 1. We get a couple of spurious events before we get the initial SIGTRAP, at which point we exit the "while (1)" loop above, after which we reach the end of the attach_command, followed by the normal end-of-command processing (normal_stop, bp handling, printing the GDB prompt), back finally to the root of the event loop. Notice that, at this point, nothing has unset the "ready" flag for the infrun_async_event_handler. So, when another cycle of gdb_do_one_event from the event loop, we eventually call check_async_event_handlers, which finds that the infrun async event handler is "ready", and therefore calls it's associated "proc" callback, which does... inferior_event_handler (INF_REG_EVENT, NULL); ... triggering a blocking call to target_wait, thus hanging forever. The fix is to use windows_wait and windows_resume directly, similarly to gdbserver. This will also allow getting rid of 'stop_after_trap'. gdb/ChangeLog: 2015-10-22 Pedro Alves * windows-nat.c (do_initial_windows_stuff): Rewrite loop using windows_wait and windows_resume directly instead of wait_for_inferior and resume. --- gdb/ChangeLog | 6 ++++++ gdb/windows-nat.c | 21 +++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0df8246272a..65d056bcb3e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2015-10-22 Pedro Alves + + * windows-nat.c (do_initial_windows_stuff): Rewrite loop using + windows_wait and windows_resume directly instead of + wait_for_inferior and resume. + 2015-10-22 Simon Marchi * xtensa-tdep.h (XTREG): Add casts. diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 4ab74b4a6ea..e6c396bfa5c 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1642,7 +1642,6 @@ windows_add_all_dlls (void) static void do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) { - extern int stop_after_trap; int i; struct inferior *inf; struct thread_info *tp; @@ -1681,16 +1680,20 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) target_terminal_inferior (); windows_initialization_done = 0; - inf->control.stop_soon = STOP_QUIETLY; + while (1) { - stop_after_trap = 1; - wait_for_inferior (); - tp = inferior_thread (); - if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP) - resume (tp->suspend.stop_signal); - else + struct target_waitstatus status; + + windows_wait (ops, minus_one_ptid, &status, 0); + + /* Note windows_wait returns TARGET_WAITKIND_SPURIOUS for thread + events. */ + if (status.kind != TARGET_WAITKIND_LOADED + && status.kind != TARGET_WAITKIND_SPURIOUS) break; + + windows_resume (ops, minus_one_ptid, 0, GDB_SIGNAL_0); } /* Now that the inferior has been started and all DLLs have been mapped, @@ -1711,8 +1714,6 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) windows_add_all_dlls (); windows_initialization_done = 1; - inf->control.stop_soon = NO_STOP_QUIETLY; - stop_after_trap = 0; return; } -- 2.30.2