diff options
-rw-r--r-- | gdb/nat/windows-nat.c | 51 | ||||
-rw-r--r-- | gdb/nat/windows-nat.h | 71 | ||||
-rw-r--r-- | gdb/windows-nat.c | 111 | ||||
-rw-r--r-- | gdbserver/win32-low.cc | 53 |
4 files changed, 123 insertions, 163 deletions
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c index b5cfad6..a01d7b3 100644 --- a/gdb/nat/windows-nat.c +++ b/gdb/nat/windows-nat.c @@ -666,57 +666,6 @@ windows_process_info::add_all_dlls () /* See nat/windows-nat.h. */ -bool -windows_process_info::matching_pending_stop (bool debug_events) -{ - /* If there are pending stops, and we might plausibly hit one of - them, we don't want to actually continue the inferior -- we just - want to report the stop. In this case, we just pretend to - continue. See the comment by the definition of "pending_stops" - for details on why this is needed. */ - for (const auto &item : pending_stops) - { - if (desired_stop_thread_id == -1 - || desired_stop_thread_id == item.thread_id) - { - DEBUG_EVENTS ("pending stop anticipated, desired=0x%x, item=0x%x", - desired_stop_thread_id, item.thread_id); - return true; - } - } - - return false; -} - -/* See nat/windows-nat.h. */ - -std::optional<pending_stop> -windows_process_info::fetch_pending_stop (bool debug_events) -{ - std::optional<pending_stop> result; - for (auto iter = pending_stops.begin (); - iter != pending_stops.end (); - ++iter) - { - if (desired_stop_thread_id == -1 - || desired_stop_thread_id == iter->thread_id) - { - result = *iter; - current_event = iter->event; - - DEBUG_EVENTS ("pending stop found in 0x%x (desired=0x%x)", - iter->thread_id, desired_stop_thread_id); - - pending_stops.erase (iter); - break; - } - } - - return result; -} - -/* See nat/windows-nat.h. */ - BOOL continue_last_debug_event (DWORD continue_status, bool debug_events) { diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h index fdbab0f..c268a12 100644 --- a/gdb/nat/windows-nat.h +++ b/gdb/nat/windows-nat.h @@ -32,6 +32,21 @@ namespace windows_nat { +/* Info about a potential pending stop. Each thread holds one of + these. See "windows_thread_info::pending_stop" for more + information. */ +struct pending_stop +{ + /* The target waitstatus we computed. TARGET_WAITKIND_IGNORE if the + thread does not have a pending stop. */ + target_waitstatus status; + + /* The event. A few fields of this can be referenced after a stop, + and it seemed simplest to store the entire event. */ + DEBUG_EVENT event; +}; + + /* Thread information structure used to track extra information about each thread. */ struct windows_thread_info @@ -71,6 +86,18 @@ struct windows_thread_info was not. */ int suspended = 0; +/* Info about a potential pending stop. + + Sometimes, Windows will report a stop on a thread that has been + ostensibly suspended. We believe what happens here is that two + threads hit a breakpoint simultaneously, and the Windows kernel + queues the stop events. However, this can result in the strange + effect of trying to single step thread A -- leaving all other + threads suspended -- and then seeing a stop in thread B. To handle + this scenario, we queue all such "pending" stops here, and then + process them once the step has completed. See PR gdb/22992. */ + struct pending_stop pending_stop {}; + /* The context of the thread, including any manipulations. */ union { @@ -97,22 +124,6 @@ struct windows_thread_info gdb::unique_xmalloc_ptr<char> name; }; - -/* A single pending stop. See "pending_stops" for more - information. */ -struct pending_stop -{ - /* The thread id. */ - DWORD thread_id; - - /* The target waitstatus we computed. */ - target_waitstatus status; - - /* The event. A few fields of this can be referenced after a stop, - and it seemed simplest to store the entire event. */ - DEBUG_EVENT event; -}; - enum handle_exception_result { HANDLE_EXCEPTION_UNHANDLED = 0, @@ -136,22 +147,6 @@ struct windows_process_info stop. */ DEBUG_EVENT current_event {}; - /* The ID of the thread for which we anticipate a stop event. - Normally this is -1, meaning we'll accept an event in any - thread. */ - DWORD desired_stop_thread_id = -1; - - /* A vector of pending stops. Sometimes, Windows will report a stop - on a thread that has been ostensibly suspended. We believe what - happens here is that two threads hit a breakpoint simultaneously, - and the Windows kernel queues the stop events. However, this can - result in the strange effect of trying to single step thread A -- - leaving all other threads suspended -- and then seeing a stop in - thread B. To handle this scenario, we queue all such "pending" - stops here, and then process them once the step has completed. See - PR gdb/22992. */ - std::vector<pending_stop> pending_stops; - /* Contents of $_siginfo */ EXCEPTION_RECORD siginfo_er {}; @@ -217,18 +212,6 @@ struct windows_process_info void add_all_dlls (); - /* Return true if there is a pending stop matching - desired_stop_thread_id. If DEBUG_EVENTS is true, logging will be - enabled. */ - - bool matching_pending_stop (bool debug_events); - - /* See if a pending stop matches DESIRED_STOP_THREAD_ID. If so, - remove it from the list of pending stops, set 'current_event', and - return it. Otherwise, return an empty optional. */ - - std::optional<pending_stop> fetch_pending_stop (bool debug_events); - const char *pid_to_exec_file (int); private: diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 2c55ec0..7a03c8f 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1353,15 +1353,22 @@ BOOL windows_nat_target::windows_continue (DWORD continue_status, int id, windows_continue_flags cont_flags) { - windows_process.desired_stop_thread_id = id; - - if (windows_process.matching_pending_stop (debug_events)) + for (auto &th : windows_process.thread_list) { - /* There's no need to really continue, because there's already - another event pending. However, we do need to inform the - event loop of this. */ - serial_event_set (m_wait_event); - return TRUE; + if ((id == -1 || id == (int) th->tid) + && !th->suspended + && th->pending_stop.status.kind () != TARGET_WAITKIND_IGNORE) + { + DEBUG_EVENTS ("got matching pending stop event " + "for 0x%x, not resuming", + th->tid); + + /* There's no need to really continue, because there's already + another event pending. However, we do need to inform the + event loop of this. */ + serial_event_set (m_wait_event); + return TRUE; + } } for (auto &th : windows_process.thread_list) @@ -1548,20 +1555,24 @@ windows_nat_target::get_windows_debug_event DWORD thread_id = 0; /* If there is a relevant pending stop, report it now. See the - comment by the definition of "pending_stops" for details on why - this is needed. */ - std::optional<pending_stop> stop - = windows_process.fetch_pending_stop (debug_events); - if (stop.has_value ()) + comment by the definition of "windows_thread_info::pending_stop" + for details on why this is needed. */ + for (auto &th : windows_process.thread_list) { - thread_id = stop->thread_id; - *ourstatus = stop->status; - windows_process.current_event = stop->event; + if (!th->suspended + && th->pending_stop.status.kind () != TARGET_WAITKIND_IGNORE) + { + DEBUG_EVENTS ("reporting pending event for 0x%x", th->tid); + + thread_id = th->tid; + *ourstatus = th->pending_stop.status; + th->pending_stop.status.set_ignore (); + windows_process.current_event = th->pending_stop.event; - ptid_t ptid (windows_process.current_event.dwProcessId, thread_id); - windows_thread_info *th = windows_process.find_thread (ptid); - windows_process.invalidate_context (th); - return ptid; + ptid_t ptid (windows_process.process_id, thread_id); + windows_process.invalidate_context (th.get ()); + return ptid; + } } windows_process.last_sig = GDB_SIGNAL_0; @@ -1603,12 +1614,18 @@ windows_nat_target::get_windows_debug_event } /* Record the existence of this thread. */ thread_id = current_event->dwThreadId; - add_thread - (ptid_t (current_event->dwProcessId, current_event->dwThreadId, 0), - current_event->u.CreateThread.hThread, - current_event->u.CreateThread.lpThreadLocalBase, - false /* main_thread_p */); + { + windows_thread_info *th + = (add_thread + (ptid_t (current_event->dwProcessId, current_event->dwThreadId, 0), + current_event->u.CreateThread.hThread, + current_event->u.CreateThread.lpThreadLocalBase, + false /* main_thread_p */)); + + /* This updates debug registers if necessary. */ + windows_process.continue_one_thread (th, 0); + } break; case EXIT_THREAD_DEBUG_EVENT: @@ -1620,6 +1637,7 @@ windows_nat_target::get_windows_debug_event current_event->dwThreadId, 0), current_event->u.ExitThread.dwExitCode, false /* main_thread_p */); + thread_id = 0; break; case CREATE_PROCESS_DEBUG_EVENT: @@ -1670,8 +1688,7 @@ windows_nat_target::get_windows_debug_event ourstatus->set_exited (exit_status); else ourstatus->set_signalled (gdb_signal_from_host (exit_signal)); - - thread_id = current_event->dwThreadId; + return ptid_t (current_event->dwProcessId); } break; @@ -1761,17 +1778,22 @@ windows_nat_target::get_windows_debug_event if (!thread_id || windows_process.saw_create != 1) { - CHECK (windows_continue (continue_status, - windows_process.desired_stop_thread_id, 0)); + continue_last_debug_event_main_thread + (_("Failed to resume program execution"), continue_status); + ourstatus->set_ignore (); + return null_ptid; } - else if (windows_process.desired_stop_thread_id != -1 - && windows_process.desired_stop_thread_id != thread_id) + + const ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0); + windows_thread_info *th = windows_process.find_thread (ptid); + + if (th->suspended) { /* Pending stop. See the comment by the definition of "pending_stops" for details on why this is needed. */ DEBUG_EVENTS ("get_windows_debug_event - " - "unexpected stop in 0x%x (expecting 0x%x)", - thread_id, windows_process.desired_stop_thread_id); + "unexpected stop in suspended thread 0x%x", + thread_id); if (current_event->dwDebugEventCode == EXCEPTION_DEBUG_EVENT && ((current_event->u.Exception.ExceptionRecord.ExceptionCode @@ -1780,24 +1802,19 @@ windows_nat_target::get_windows_debug_event == STATUS_WX86_BREAKPOINT)) && windows_process.windows_initialization_done) { - ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0); - windows_thread_info *th = windows_process.find_thread (ptid); th->stopped_at_software_breakpoint = true; th->pc_adjusted = false; } - windows_process.pending_stops.push_back - ({thread_id, *ourstatus, windows_process.current_event}); - thread_id = 0; - CHECK (windows_continue (continue_status, - windows_process.desired_stop_thread_id, 0)); - } - - if (thread_id == 0) - { + th->pending_stop.status = *ourstatus; + th->pending_stop.event = *current_event; ourstatus->set_ignore (); + + continue_last_debug_event_main_thread + (_("Failed to resume program execution"), continue_status); return null_ptid; } - return ptid_t (windows_process.current_event.dwProcessId, thread_id, 0); + + return ptid; } /* Wait for interesting events to occur in the target process. */ @@ -1823,8 +1840,8 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, if (ourstatus->kind () == TARGET_WAITKIND_SPURIOUS) { - CHECK (windows_continue (DBG_CONTINUE, - windows_process.desired_stop_thread_id, 0)); + continue_last_debug_event_main_thread + (_("Failed to resume program execution"), DBG_CONTINUE); } else if (ourstatus->kind () != TARGET_WAITKIND_IGNORE) { diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc index 8dd8f21..8f51dd6 100644 --- a/gdbserver/win32-low.cc +++ b/gdbserver/win32-low.cc @@ -427,9 +427,14 @@ continue_one_thread (thread_info *thread, int thread_id) static BOOL child_continue (DWORD continue_status, int thread_id) { - windows_process.desired_stop_thread_id = thread_id; - if (windows_process.matching_pending_stop (debug_threads)) - return TRUE; + for (thread_info *thread : all_threads) + { + auto *th = (windows_thread_info *) thread_target_data (thread); + if ((thread_id == -1 || thread_id == (int) th->tid) + && !th->suspended + && th->pending_stop.status.kind () != TARGET_WAITKIND_IGNORE) + return TRUE; + } /* The inferior will only continue after the ContinueDebugEvent call. */ @@ -1012,15 +1017,20 @@ get_child_debug_event (DWORD *continue_status, windows_process.attaching = 0; { - std::optional<pending_stop> stop - = windows_process.fetch_pending_stop (debug_threads); - if (stop.has_value ()) + for (thread_info *thread : all_threads) { - *ourstatus = stop->status; - windows_process.current_event = stop->event; - ptid = debug_event_ptid (&windows_process.current_event); - switch_to_thread (find_thread_ptid (ptid)); - return 1; + auto *th = (windows_thread_info *) thread_target_data (thread); + + if (!th->suspended + && th->pending_stop.status.kind () != TARGET_WAITKIND_IGNORE) + { + *ourstatus = th->pending_stop.status; + th->pending_stop.status.set_ignore (); + windows_process.current_event = th->pending_stop.event; + ptid = debug_event_ptid (&windows_process.current_event); + switch_to_thread (find_thread_ptid (ptid)); + return 1; + } } /* Keep the wait time low enough for comfortable remote @@ -1112,7 +1122,7 @@ get_child_debug_event (DWORD *continue_status, else ourstatus->set_signalled (gdb_signal_from_host (exit_signal)); } - child_continue (DBG_CONTINUE, windows_process.desired_stop_thread_id); + continue_last_debug_event (DBG_CONTINUE, debug_threads); break; case LOAD_DLL_DEBUG_EVENT: @@ -1169,17 +1179,19 @@ get_child_debug_event (DWORD *continue_status, ptid = debug_event_ptid (&windows_process.current_event); - if (windows_process.desired_stop_thread_id != -1 - && windows_process.desired_stop_thread_id != ptid.lwp ()) + windows_thread_info *th = windows_process.find_thread (ptid); + + if (th != nullptr && th->suspended) { /* Pending stop. See the comment by the definition of - "pending_stops" for details on why this is needed. */ + "windows_thread_info::pending_stop" for details on why this + is needed. */ OUTMSG2 (("get_windows_debug_event - " - "unexpected stop in 0x%lx (expecting 0x%x)\n", - ptid.lwp (), windows_process.desired_stop_thread_id)); + "unexpected stop in suspended thread 0x%x\n", + th->tid)); maybe_adjust_pc (); - windows_process.pending_stops.push_back - ({(DWORD) ptid.lwp (), *ourstatus, *current_event}); + th->pending_stop.status = *ourstatus; + th->pending_stop.event = *current_event; ourstatus->set_spurious (); } else @@ -1239,8 +1251,7 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus, [[fallthrough]]; case TARGET_WAITKIND_SPURIOUS: /* do nothing, just continue */ - child_continue (continue_status, - windows_process.desired_stop_thread_id); + continue_last_debug_event (continue_status, debug_threads); break; } } |