diff options
author | Tom Tromey <tromey@adacore.com> | 2022-03-31 13:41:02 -0600 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2022-04-04 13:58:37 -0600 |
commit | 0578e87f93b09e4cc41d3982eb1672bcfc81042d (patch) | |
tree | f2781002de2cf155a7f4cc9ae5f0c7bf08d1a270 /gdb/nat | |
parent | fc0b013e44e5a450631706bc25612b975cfbc692 (diff) | |
download | gdb-0578e87f93b09e4cc41d3982eb1672bcfc81042d.zip gdb-0578e87f93b09e4cc41d3982eb1672bcfc81042d.tar.gz gdb-0578e87f93b09e4cc41d3982eb1672bcfc81042d.tar.bz2 |
Remove some globals from nat/windows-nat.c
nat/windows-nat.c has a number of globals that it uses to communicate
with its clients (gdb and gdbserver). However, if we ever want the
Windows ports to be multi-inferior, globals won't work.
This patch takes a step toward that by moving most nat/windows-nat.c
globals into a new struct windows_process_info. Many functions are
converted to be methods on this object.
A couple of globals remain, as they are needed to truly be global due
to the way that the Windows debugging APIs work.
The clients still have a global for the current process. That is,
this patch is a step toward the end goal, but doesn't implement the
goal itself.
Diffstat (limited to 'gdb/nat')
-rw-r--r-- | gdb/nat/windows-nat.c | 56 | ||||
-rw-r--r-- | gdb/nat/windows-nat.h | 217 |
2 files changed, 135 insertions, 138 deletions
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c index 3907286..c890ee1 100644 --- a/gdb/nat/windows-nat.c +++ b/gdb/nat/windows-nat.c @@ -23,12 +23,6 @@ namespace windows_nat { -HANDLE current_process_handle; -DWORD current_process_id; -DWORD main_thread_id; -enum gdb_signal last_sig = GDB_SIGNAL_0; -DEBUG_EVENT current_event; - /* The most recent event from WaitForDebugEvent. Unlike current_event, this is guaranteed never to come from a pending stop. This is important because only data from the most recent @@ -36,15 +30,6 @@ DEBUG_EVENT current_event; ContinueDebugEvent. */ static DEBUG_EVENT last_wait_event; -DWORD desired_stop_thread_id = -1; -std::vector<pending_stop> pending_stops; -EXCEPTION_RECORD siginfo_er; - -#ifdef __x86_64__ -bool wow64_process = false; -bool ignore_first_breakpoint = false; -#endif - AdjustTokenPrivileges_ftype *AdjustTokenPrivileges; DebugActiveProcessStop_ftype *DebugActiveProcessStop; DebugBreakProcess_ftype *DebugBreakProcess; @@ -180,7 +165,8 @@ get_image_name (HANDLE h, void *address, int unicode) #define MS_VC_EXCEPTION 0x406d1388 handle_exception_result -handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions) +windows_process_info::handle_exception (struct target_waitstatus *ourstatus, + bool debug_exceptions) { #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ debug_printf ("gdb: Target exception %s at %s\n", x, \ @@ -335,15 +321,10 @@ handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions) #undef DEBUG_EXCEPTION_SIMPLE } -/* 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 - list of solibs; otherwise do nothing. LOAD_ADDR NULL means add all - DLLs to the list of solibs; this is used when the inferior finishes - its initialization, and all the DLLs it statically depends on are - presumed loaded. */ +/* See nat/windows-nat.h. */ -static void -windows_add_dll (LPVOID load_addr) +void +windows_process_info::add_dll (LPVOID load_addr) { HMODULE dummy_hmodule; DWORD cb_needed; @@ -353,7 +334,7 @@ windows_add_dll (LPVOID load_addr) #ifdef __x86_64__ if (wow64_process) { - if (EnumProcessModulesEx (current_process_handle, &dummy_hmodule, + if (EnumProcessModulesEx (handle, &dummy_hmodule, sizeof (HMODULE), &cb_needed, LIST_MODULES_32BIT) == 0) return; @@ -361,7 +342,7 @@ windows_add_dll (LPVOID load_addr) else #endif { - if (EnumProcessModules (current_process_handle, &dummy_hmodule, + if (EnumProcessModules (handle, &dummy_hmodule, sizeof (HMODULE), &cb_needed) == 0) return; } @@ -373,7 +354,7 @@ windows_add_dll (LPVOID load_addr) #ifdef __x86_64__ if (wow64_process) { - if (EnumProcessModulesEx (current_process_handle, hmodules, + if (EnumProcessModulesEx (handle, hmodules, cb_needed, &cb_needed, LIST_MODULES_32BIT) == 0) return; @@ -381,7 +362,7 @@ windows_add_dll (LPVOID load_addr) else #endif { - if (EnumProcessModules (current_process_handle, hmodules, + if (EnumProcessModules (handle, hmodules, cb_needed, &cb_needed) == 0) return; } @@ -426,11 +407,11 @@ windows_add_dll (LPVOID load_addr) char dll_name[MAX_PATH]; #endif const char *name; - if (GetModuleInformation (current_process_handle, hmodules[i], + if (GetModuleInformation (handle, hmodules[i], &mi, sizeof (mi)) == 0) continue; - if (GetModuleFileNameEx (current_process_handle, hmodules[i], + if (GetModuleFileNameEx (handle, hmodules[i], dll_name, sizeof (dll_name)) == 0) continue; #ifdef __USEWIDE @@ -466,7 +447,7 @@ windows_add_dll (LPVOID load_addr) /* See nat/windows-nat.h. */ void -dll_loaded_event () +windows_process_info::dll_loaded_event () { gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT); @@ -478,29 +459,28 @@ dll_loaded_event () in the sense that it might be NULL. And the first DLL event in particular is explicitly documented as "likely not pass[ed]" (source: MSDN LOAD_DLL_DEBUG_INFO structure). */ - dll_name = get_image_name (current_process_handle, - event->lpImageName, event->fUnicode); + dll_name = get_image_name (handle, event->lpImageName, event->fUnicode); /* If the DLL name could not be gleaned via lpImageName, try harder by enumerating all the DLLs loaded into the inferior, looking for one that is loaded at base address = lpBaseOfDll. */ if (dll_name != nullptr) handle_load_dll (dll_name, event->lpBaseOfDll); else if (event->lpBaseOfDll != nullptr) - windows_add_dll (event->lpBaseOfDll); + add_dll (event->lpBaseOfDll); } /* See nat/windows-nat.h. */ void -windows_add_all_dlls () +windows_process_info::add_all_dlls () { - windows_add_dll (nullptr); + add_dll (nullptr); } /* See nat/windows-nat.h. */ bool -matching_pending_stop (bool debug_events) +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 @@ -524,7 +504,7 @@ matching_pending_stop (bool debug_events) /* See nat/windows-nat.h. */ gdb::optional<pending_stop> -fetch_pending_stop (bool debug_events) +windows_process_info::fetch_pending_stop (bool debug_events) { gdb::optional<pending_stop> result; for (auto iter = pending_stops.begin (); diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h index bfb359e..7f76ba0 100644 --- a/gdb/nat/windows-nat.h +++ b/gdb/nat/windows-nat.h @@ -109,145 +109,162 @@ enum thread_disposition_type INVALIDATE_CONTEXT }; -/* Find a thread record given a thread id. THREAD_DISPOSITION - controls whether the thread is suspended, and whether the context - is invalidated. +/* A single pending stop. See "pending_stops" for more + information. */ +struct pending_stop +{ + /* The thread id. */ + DWORD thread_id; - This function must be supplied by the embedding application. */ -extern windows_thread_info *thread_rec (ptid_t ptid, - thread_disposition_type disposition); + /* 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; +}; -/* Handle OUTPUT_DEBUG_STRING_EVENT from child process. Updates - OURSTATUS and returns the thread id if this represents a thread - change (this is specific to Cygwin), otherwise 0. +typedef enum +{ + HANDLE_EXCEPTION_UNHANDLED = 0, + HANDLE_EXCEPTION_HANDLED, + HANDLE_EXCEPTION_IGNORED +} handle_exception_result; - Cygwin prepends its messages with a "cygwin:". Interpret this as - a Cygwin signal. Otherwise just print the string as a warning. +/* A single Windows process. An object of this type (or subclass) is + created by the client. Some methods must be provided by the client + as well. */ - This function must be supplied by the embedding application. */ -extern int handle_output_debug_string (struct target_waitstatus *ourstatus); +struct windows_process_info +{ + /* The process handle */ + HANDLE handle = 0; + DWORD id = 0; + 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 {}; + + /* 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 {}; -/* Handle a DLL load event. +#ifdef __x86_64__ + /* The target is a WOW64 process */ + bool wow64_process = false; + /* Ignore first breakpoint exception of WOW64 process */ + bool ignore_first_breakpoint = false; +#endif - This function assumes that the current event did not occur during - inferior initialization. - DLL_NAME is the name of the library. BASE is the base load - address. + /* Find a thread record given a thread id. THREAD_DISPOSITION + controls whether the thread is suspended, and whether the context + is invalidated. - This function must be supplied by the embedding application. */ + This function must be supplied by the embedding application. */ + windows_thread_info *thread_rec (ptid_t ptid, + thread_disposition_type disposition); -extern void handle_load_dll (const char *dll_name, LPVOID base); + /* Handle OUTPUT_DEBUG_STRING_EVENT from child process. Updates + OURSTATUS and returns the thread id if this represents a thread + change (this is specific to Cygwin), otherwise 0. -/* Handle a DLL unload event. + Cygwin prepends its messages with a "cygwin:". Interpret this as + a Cygwin signal. Otherwise just print the string as a warning. - This function assumes that this event did not occur during inferior - initialization. + This function must be supplied by the embedding application. */ + int handle_output_debug_string (struct target_waitstatus *ourstatus); - This function must be supplied by the embedding application. */ + /* Handle a DLL load event. -extern void handle_unload_dll (); + This function assumes that the current event did not occur during + inferior initialization. -/* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is - somewhat undocumented but is used to tell the debugger the name of - a thread. + DLL_NAME is the name of the library. BASE is the base load + address. - Return true if the exception was handled; return false otherwise. + This function must be supplied by the embedding application. */ - This function must be supplied by the embedding application. */ + void handle_load_dll (const char *dll_name, LPVOID base); -extern bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec); + /* Handle a DLL unload event. -/* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding - application a chance to change it to be considered "unhandled". - This function must be supplied by the embedding application. If it - returns true, then the exception is "unhandled". */ + This function assumes that this event did not occur during inferior + initialization. -extern bool handle_access_violation (const EXCEPTION_RECORD *rec); + This function must be supplied by the embedding application. */ + void handle_unload_dll (); -/* Currently executing process */ -extern HANDLE current_process_handle; -extern DWORD current_process_id; -extern DWORD main_thread_id; -extern enum gdb_signal last_sig; + /* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is + somewhat undocumented but is used to tell the debugger the name of + a thread. -/* The current debug event from WaitForDebugEvent or from a pending - stop. */ -extern DEBUG_EVENT current_event; + Return true if the exception was handled; return false otherwise. -/* 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. */ -extern DWORD desired_stop_thread_id; + This function must be supplied by the embedding application. */ -/* A single pending stop. See "pending_stops" for more - information. */ -struct pending_stop -{ - /* The thread id. */ - DWORD thread_id; + bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec); - /* 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; -}; + /* When EXCEPTION_ACCESS_VIOLATION is processed, we give the embedding + application a chance to change it to be considered "unhandled". + This function must be supplied by the embedding application. If it + returns true, then the exception is "unhandled". */ -/* 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. */ -extern std::vector<pending_stop> pending_stops; + bool handle_access_violation (const EXCEPTION_RECORD *rec); -/* Contents of $_siginfo */ -extern EXCEPTION_RECORD siginfo_er; + handle_exception_result handle_exception + (struct target_waitstatus *ourstatus, bool debug_exceptions); -#ifdef __x86_64__ -/* The target is a WOW64 process */ -extern bool wow64_process; -/* Ignore first breakpoint exception of WOW64 process */ -extern bool ignore_first_breakpoint; -#endif + /* Call to indicate that a DLL was loaded. */ -typedef enum -{ - HANDLE_EXCEPTION_UNHANDLED = 0, - HANDLE_EXCEPTION_HANDLED, - HANDLE_EXCEPTION_IGNORED -} handle_exception_result; + void dll_loaded_event (); -extern handle_exception_result handle_exception - (struct target_waitstatus *ourstatus, bool debug_exceptions); + /* Iterate over all DLLs currently mapped by our inferior, and + add them to our list of solibs. */ -/* Call to indicate that a DLL was loaded. */ + void add_all_dlls (); -extern void dll_loaded_event (); + /* Return true if there is a pending stop matching + desired_stop_thread_id. If DEBUG_EVENTS is true, logging will be + enabled. */ -/* Iterate over all DLLs currently mapped by our inferior, and - add them to our list of solibs. */ + bool matching_pending_stop (bool debug_events); -extern void windows_add_all_dlls (); + /* 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. */ -/* Return true if there is a pending stop matching - desired_stop_thread_id. If DEBUG_EVENTS is true, logging will be - enabled. */ + gdb::optional<pending_stop> fetch_pending_stop (bool debug_events); -extern bool matching_pending_stop (bool debug_events); +private: -/* 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. */ + /* 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 + list of solibs; otherwise do nothing. LOAD_ADDR NULL means add all + DLLs to the list of solibs; this is used when the inferior finishes + its initialization, and all the DLLs it statically depends on are + presumed loaded. */ -extern gdb::optional<pending_stop> fetch_pending_stop (bool debug_events); + void add_dll (LPVOID load_addr); +}; /* A simple wrapper for ContinueDebugEvent that continues the last waited-for event. If DEBUG_EVENTS is true, logging will be |