From f428cac6151a5fb66812be52fd05b8eae8a164cd Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Thu, 21 Oct 2021 18:16:58 +0100 Subject: Windows gdb+gdbserver: Make current_event per-thread state With non-stop mode, each thread is controlled independently of the others, and each thread has its own independent reason for its last stop. Thus, any thread-specific state that is currently per-process must be converted to per-thread state. This patch converts windows_process_info::current_event, moving it to windows_thread_info instead, renamed to last_event. Since each thread will have its own copy of its last Windows debug event, we no longer need the same information stored in struct pending_stop. Since windows_process.current_event no longer exists, we need to pass the current event as parameter to a number of methods. This adjusts both native gdb and gdbserver. Change-Id: Ice09a5d932c912210608d5af25e1898f823e3c99 --- gdb/nat/windows-nat.c | 13 +++-- gdb/nat/windows-nat.h | 24 ++++----- gdb/windows-nat.c | 136 ++++++++++++++++++++++++++------------------------ 3 files changed, 91 insertions(+), 82 deletions(-) (limited to 'gdb') diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c index 7f8834f..cabc61f 100644 --- a/gdb/nat/windows-nat.c +++ b/gdb/nat/windows-nat.c @@ -310,8 +310,10 @@ get_image_name (HANDLE h, void *address, int unicode) /* See nat/windows-nat.h. */ bool -windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec) +windows_process_info::handle_ms_vc_exception (const DEBUG_EVENT ¤t_event) { + const EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord; + if (rec->NumberParameters >= 3 && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) { @@ -352,7 +354,8 @@ windows_process_info::handle_ms_vc_exception (const EXCEPTION_RECORD *rec) #define MS_VC_EXCEPTION 0x406d1388 handle_exception_result -windows_process_info::handle_exception (struct target_waitstatus *ourstatus, +windows_process_info::handle_exception (DEBUG_EVENT ¤t_event, + struct target_waitstatus *ourstatus, bool debug_exceptions) { #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ @@ -480,7 +483,7 @@ windows_process_info::handle_exception (struct target_waitstatus *ourstatus, break; case MS_VC_EXCEPTION: DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION"); - if (handle_ms_vc_exception (rec)) + if (handle_ms_vc_exception (current_event)) { ourstatus->set_stopped (GDB_SIGNAL_TRAP); result = HANDLE_EXCEPTION_IGNORED; @@ -634,11 +637,11 @@ windows_process_info::add_dll (LPVOID load_addr) /* See nat/windows-nat.h. */ void -windows_process_info::dll_loaded_event () +windows_process_info::dll_loaded_event (const DEBUG_EVENT ¤t_event) { gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT); - LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; + const LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; const char *dll_name; /* Try getting the DLL name via the lpImageName field of the event. diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h index 70912fd..73c828e 100644 --- a/gdb/nat/windows-nat.h +++ b/gdb/nat/windows-nat.h @@ -40,10 +40,6 @@ 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; }; @@ -98,6 +94,10 @@ struct windows_thread_info process them once the step has completed. See PR gdb/22992. */ struct pending_stop pending_stop {}; + /* The last Windows event returned by WaitForDebugEvent for this + thread. */ + DEBUG_EVENT last_event {}; + /* The context of the thread, including any manipulations. */ union { @@ -143,10 +143,6 @@ struct windows_process_info DWORD main_thread_id = 0; enum gdb_signal last_sig = GDB_SIGNAL_0; - /* The current debug event from WaitForDebugEvent or from a pending - stop. */ - DEBUG_EVENT current_event {}; - /* Contents of $_siginfo */ EXCEPTION_RECORD siginfo_er {}; @@ -170,7 +166,8 @@ struct windows_process_info a Cygwin signal. Otherwise just print the string as a warning. This function must be supplied by the embedding application. */ - virtual DWORD handle_output_debug_string (struct target_waitstatus *ourstatus) = 0; + virtual DWORD handle_output_debug_string (const DEBUG_EVENT ¤t_event, + struct target_waitstatus *ourstatus) = 0; /* Handle a DLL load event. @@ -191,7 +188,7 @@ struct windows_process_info This function must be supplied by the embedding application. */ - virtual void handle_unload_dll () = 0; + virtual void handle_unload_dll (const DEBUG_EVENT ¤t_event) = 0; /* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding application a chance to change it to be considered "unhandled". @@ -201,11 +198,12 @@ struct windows_process_info virtual bool handle_access_violation (const EXCEPTION_RECORD *rec) = 0; handle_exception_result handle_exception - (struct target_waitstatus *ourstatus, bool debug_exceptions); + (DEBUG_EVENT ¤t_event, + struct target_waitstatus *ourstatus, bool debug_exceptions); /* Call to indicate that a DLL was loaded. */ - void dll_loaded_event (); + void dll_loaded_event (const DEBUG_EVENT ¤t_event); /* Iterate over all DLLs currently mapped by our inferior, and add them to our list of solibs. */ @@ -222,7 +220,7 @@ private: Return true if the exception was handled; return false otherwise. */ - bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec); + bool handle_ms_vc_exception (const DEBUG_EVENT ¤t_event); /* Iterate over all DLLs currently mapped by our inferior, looking for a DLL which is loaded at LOAD_ADDR. If found, add the DLL to our diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 2913da6..bba8468 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -107,9 +107,10 @@ DEF_ENUM_FLAGS_TYPE (windows_continue_flag, windows_continue_flags); struct windows_per_inferior : public windows_process_info { windows_thread_info *find_thread (ptid_t ptid) override; - DWORD handle_output_debug_string (struct target_waitstatus *ourstatus) override; + DWORD handle_output_debug_string (const DEBUG_EVENT ¤t_event, + struct target_waitstatus *ourstatus) override; void handle_load_dll (const char *dll_name, LPVOID base) override; - void handle_unload_dll () override; + void handle_unload_dll (const DEBUG_EVENT ¤t_event) override; bool handle_access_violation (const EXCEPTION_RECORD *rec) override; void invalidate_context (windows_thread_info *th); @@ -321,7 +322,8 @@ struct windows_nat_target final : public x86_nat_target const char *thread_name (struct thread_info *) override; ptid_t get_windows_debug_event (int pid, struct target_waitstatus *ourstatus, - target_wait_flags options); + target_wait_flags options, + DEBUG_EVENT *current_event); void do_initial_windows_stuff (DWORD pid, bool attaching); @@ -352,7 +354,7 @@ private: windows_thread_info *add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p); void delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p); - DWORD fake_create_process (); + DWORD fake_create_process (const DEBUG_EVENT ¤t_event); BOOL windows_continue (DWORD continue_status, int id, windows_continue_flags cont_flags = 0); @@ -980,7 +982,7 @@ windows_per_inferior::handle_load_dll (const char *dll_name, LPVOID base) /* See nat/windows-nat.h. */ void -windows_per_inferior::handle_unload_dll () +windows_per_inferior::handle_unload_dll (const DEBUG_EVENT ¤t_event) { LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll; @@ -1043,7 +1045,8 @@ signal_event_command (const char *args, int from_tty) DWORD windows_per_inferior::handle_output_debug_string - (struct target_waitstatus *ourstatus) + (const DEBUG_EVENT ¤t_event, + struct target_waitstatus *ourstatus) { DWORD thread_id = 0; @@ -1388,11 +1391,11 @@ windows_nat_target::windows_continue (DWORD continue_status, int id, /* Called in pathological case where Windows fails to send a CREATE_PROCESS_DEBUG_EVENT after an attach. */ DWORD -windows_nat_target::fake_create_process () +windows_nat_target::fake_create_process (const DEBUG_EVENT ¤t_event) { windows_process.handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, - windows_process.current_event.dwProcessId); + current_event.dwProcessId); if (windows_process.handle != NULL) windows_process.open_process_used = 1; else @@ -1401,12 +1404,11 @@ windows_nat_target::fake_create_process () throw_winerror_with_name (_("OpenProcess call failed"), err); /* We can not debug anything in that case. */ } - add_thread (ptid_t (windows_process.current_event.dwProcessId, - windows_process.current_event.dwThreadId, 0), - windows_process.current_event.u.CreateThread.hThread, - windows_process.current_event.u.CreateThread.lpThreadLocalBase, + add_thread (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0), + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase, true /* main_thread_p */); - return windows_process.current_event.dwThreadId; + return current_event.dwThreadId; } void @@ -1423,6 +1425,13 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) if (resume_all) ptid = inferior_ptid; + DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d", + ptid.pid (), (unsigned) ptid.lwp (), step, sig); + + /* Get currently selected thread. */ + th = windows_process.find_thread (inferior_ptid); + gdb_assert (th != nullptr); + if (sig != GDB_SIGNAL_0) { /* Note it is OK to call get_last_debug_event_ptid() from the @@ -1435,8 +1444,7 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) DEBUG_EXCEPT ("Cannot continue with signal %d here. " "Not last-event thread", sig); } - else if (windows_process.current_event.dwDebugEventCode - != EXCEPTION_DEBUG_EVENT) + else if (th->last_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) { DEBUG_EXCEPT ("Cannot continue with signal %d here. " "Not stopped for EXCEPTION_DEBUG_EVENT", sig); @@ -1453,7 +1461,7 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) for (const xlate_exception &x : xlate) if (x.us == sig) { - current_event.u.Exception.ExceptionRecord.ExceptionCode + th->last_event.u.Exception.ExceptionRecord.ExceptionCode = x.them; continue_status = DBG_EXCEPTION_NOT_HANDLED; break; @@ -1470,36 +1478,28 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) windows_process.last_sig = GDB_SIGNAL_0; - DEBUG_EXEC ("pid=%d, tid=0x%x, step=%d, sig=%d", - ptid.pid (), (unsigned) ptid.lwp (), step, sig); - - /* Get context for currently selected thread. */ - th = windows_process.find_thread (inferior_ptid); - if (th) - { #ifdef __x86_64__ - if (windows_process.wow64_process) + if (windows_process.wow64_process) + { + if (step) { - if (step) - { - /* Single step by setting t bit. */ - regcache *regcache = get_thread_regcache (inferior_thread ()); - struct gdbarch *gdbarch = regcache->arch (); - fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); - th->wow64_context.EFlags |= FLAG_TRACE_BIT; - } + /* Single step by setting t bit. */ + regcache *regcache = get_thread_regcache (inferior_thread ()); + struct gdbarch *gdbarch = regcache->arch (); + fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); + th->wow64_context.EFlags |= FLAG_TRACE_BIT; } - else + } + else #endif + { + if (step) { - if (step) - { - /* Single step by setting t bit. */ - regcache *regcache = get_thread_regcache (inferior_thread ()); - struct gdbarch *gdbarch = regcache->arch (); - fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); - th->context.EFlags |= FLAG_TRACE_BIT; - } + /* Single step by setting t bit. */ + regcache *regcache = get_thread_regcache (inferior_thread ()); + struct gdbarch *gdbarch = regcache->arch (); + fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); + th->context.EFlags |= FLAG_TRACE_BIT; } } @@ -1563,7 +1563,8 @@ windows_nat_target::pass_ctrlc () ptid_t windows_nat_target::get_windows_debug_event - (int pid, struct target_waitstatus *ourstatus, target_wait_flags options) + (int pid, struct target_waitstatus *ourstatus, target_wait_flags options, + DEBUG_EVENT *current_event) { DWORD continue_status, event_code; DWORD thread_id = 0; @@ -1581,7 +1582,7 @@ windows_nat_target::get_windows_debug_event thread_id = th->tid; *ourstatus = th->pending_stop.status; th->pending_stop.status.set_ignore (); - windows_process.current_event = th->pending_stop.event; + *current_event = th->last_event; ptid_t ptid (windows_process.process_id, thread_id); windows_process.invalidate_context (th.get ()); @@ -1590,7 +1591,6 @@ windows_nat_target::get_windows_debug_event } windows_process.last_sig = GDB_SIGNAL_0; - DEBUG_EVENT *current_event = &windows_process.current_event; if ((options & TARGET_WNOHANG) != 0 && !m_debug_event_pending) { @@ -1598,11 +1598,11 @@ windows_nat_target::get_windows_debug_event return minus_one_ptid; } - wait_for_debug_event_main_thread (&windows_process.current_event); + wait_for_debug_event_main_thread (current_event); continue_status = DBG_CONTINUE; - event_code = windows_process.current_event.dwDebugEventCode; + event_code = current_event->dwDebugEventCode; ourstatus->set_spurious (); switch (event_code) @@ -1620,7 +1620,7 @@ windows_nat_target::get_windows_debug_event /* Kludge around a Windows bug where first event is a create thread event. Caused when attached process does not have a main thread. */ - thread_id = fake_create_process (); + thread_id = fake_create_process (*current_event); if (thread_id) windows_process.saw_create++; } @@ -1717,7 +1717,7 @@ windows_nat_target::get_windows_debug_event break; try { - windows_process.dll_loaded_event (); + windows_process.dll_loaded_event (*current_event); } catch (const gdb_exception &ex) { @@ -1737,7 +1737,7 @@ windows_nat_target::get_windows_debug_event break; try { - windows_process.handle_unload_dll (); + windows_process.handle_unload_dll (*current_event); } catch (const gdb_exception &ex) { @@ -1754,7 +1754,8 @@ windows_nat_target::get_windows_debug_event "EXCEPTION_DEBUG_EVENT"); if (windows_process.saw_create != 1) break; - switch (windows_process.handle_exception (ourstatus, debug_exceptions)) + switch (windows_process.handle_exception (*current_event, + ourstatus, debug_exceptions)) { case HANDLE_EXCEPTION_UNHANDLED: default: @@ -1776,7 +1777,8 @@ windows_nat_target::get_windows_debug_event "OUTPUT_DEBUG_STRING_EVENT"); if (windows_process.saw_create != 1) break; - thread_id = windows_process.handle_output_debug_string (ourstatus); + thread_id = windows_process.handle_output_debug_string (*current_event, + ourstatus); break; default: @@ -1801,6 +1803,8 @@ windows_nat_target::get_windows_debug_event const ptid_t ptid = ptid_t (current_event->dwProcessId, thread_id, 0); windows_thread_info *th = windows_process.find_thread (ptid); + th->last_event = *current_event; + if (th->suspended) { /* Pending stop. See the comment by the definition of @@ -1819,8 +1823,8 @@ windows_nat_target::get_windows_debug_event th->stopped_at_software_breakpoint = true; th->pc_adjusted = false; } + th->pending_stop.status = *ourstatus; - th->pending_stop.event = *current_event; ourstatus->set_ignore (); continue_last_debug_event_main_thread @@ -1846,7 +1850,10 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, while (1) { - ptid_t result = get_windows_debug_event (pid, ourstatus, options); + DEBUG_EVENT current_event; + + ptid_t result = get_windows_debug_event (pid, ourstatus, options, + ¤t_event); if ((options & TARGET_WNOHANG) != 0 && ourstatus->kind () == TARGET_WAITKIND_IGNORE) @@ -1865,11 +1872,11 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, windows_thread_info *th = windows_process.find_thread (result); th->stopped_at_software_breakpoint = false; - if (windows_process.current_event.dwDebugEventCode + if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT - && ((windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode + && ((current_event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) - || (windows_process.current_event.u.Exception.ExceptionRecord.ExceptionCode + || (current_event.u.Exception.ExceptionRecord.ExceptionCode == STATUS_WX86_BREAKPOINT)) && windows_process.windows_initialization_done) { @@ -1910,8 +1917,6 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching) windows_process.cygwin_load_end = 0; #endif windows_process.process_id = pid; - memset (&windows_process.current_event, 0, - sizeof (windows_process.current_event)); inf = current_inferior (); if (!inf->target_is_pushed (this)) inf->push_target (this); @@ -1958,7 +1963,10 @@ windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching) && status.kind () != TARGET_WAITKIND_SPURIOUS) break; - this->resume (minus_one_ptid, 0, GDB_SIGNAL_0); + /* Don't use windows_nat_target::resume here because that + assumes that inferior_ptid points at a valid thread, and we + haven't switched to any thread yet. */ + windows_continue (DBG_CONTINUE, -1); } switch_to_thread (this->find_thread (last_ptid)); @@ -2234,7 +2242,7 @@ windows_nat_target::detach (inferior *inf, int from_tty) if (process_alive) do_synchronously ([&] () { - if (!DebugActiveProcessStop (windows_process.current_event.dwProcessId)) + if (!DebugActiveProcessStop (windows_process.process_id)) err = (unsigned) GetLastError (); else DebugSetProcessKillOnExit (FALSE); @@ -2245,7 +2253,7 @@ windows_nat_target::detach (inferior *inf, int from_tty) { std::string msg = string_printf (_("Can't detach process %u"), - (unsigned) windows_process.current_event.dwProcessId); + windows_process.process_id); throw_winerror_with_name (msg.c_str (), *err); } @@ -3042,9 +3050,9 @@ windows_nat_target::kill () { if (!windows_continue (DBG_CONTINUE, -1, WCONT_KILLED)) break; - wait_for_debug_event_main_thread (&windows_process.current_event); - if (windows_process.current_event.dwDebugEventCode - == EXIT_PROCESS_DEBUG_EVENT) + DEBUG_EVENT current_event; + wait_for_debug_event_main_thread (¤t_event); + if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) break; } -- cgit v1.1