From e228ef975e92d3bc860fc6b87039447392ba53aa Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Fri, 30 Apr 2021 10:22:23 -0600 Subject: [PATCH] Share DLL code between gdb and gdbserver This moves the new DLL-loading code into nat/windows-nat.c, and changes both gdb and gdbserver to use the shared code. One client-provided callback, handle_load_dll, is changed to allow the code to be shared. This callback was actually never called from nat/windows-nat.c; maybe I had planned to share more here and then didn't finish... I'm not sure. gdb/ChangeLog 2021-04-30 Tom Tromey * windows-nat.c (windows_nat::handle_load_dll): Update. (windows_nat_target::get_windows_debug_event): Call dll_loaded_event. (windows_add_all_dlls, windows_add_dll): Move to nat/windows-nat.c. * nat/windows-nat.h (handle_load_dll): Change parameters. (dll_loaded_event, windows_add_all_dlls): Declare. * nat/windows-nat.c (windows_add_dll, windows_add_all_dlls): Move from windows-nat.c. (dll_loaded_event): New function. gdbserver/ChangeLog 2021-04-30 Tom Tromey * win32-low.cc (do_initial_child_stuff): Update. (windows_nat::handle_load_dll): Rename from win32_add_one_solib. Change parameter type. (win32_add_dll, win32_add_all_dlls) (windows_nat::handle_load_dll): Remove. (get_child_debug_event): Call dll_loaded_event. --- gdb/ChangeLog | 13 ++++ gdb/nat/windows-nat.c | 162 ++++++++++++++++++++++++++++++++++++++ gdb/nat/windows-nat.h | 14 +++- gdb/windows-nat.c | 172 +---------------------------------------- gdbserver/ChangeLog | 9 +++ gdbserver/win32-low.cc | 170 ++-------------------------------------- 6 files changed, 209 insertions(+), 331 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 6f1f66876f8..4bb6ef832d9 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2021-04-30 Tom Tromey + + * windows-nat.c (windows_nat::handle_load_dll): Update. + (windows_nat_target::get_windows_debug_event): Call + dll_loaded_event. + (windows_add_all_dlls, windows_add_dll): Move to + nat/windows-nat.c. + * nat/windows-nat.h (handle_load_dll): Change parameters. + (dll_loaded_event, windows_add_all_dlls): Declare. + * nat/windows-nat.c (windows_add_dll, windows_add_all_dlls): Move + from windows-nat.c. + (dll_loaded_event): New function. + 2021-04-30 Tom Tromey * nat/windows-nat.h (GenerateConsoleCtrlEvent): New define. diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c index 1bc3fca3cc3..377810c9f0e 100644 --- a/gdb/nat/windows-nat.c +++ b/gdb/nat/windows-nat.c @@ -333,6 +333,168 @@ 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. */ + +static void +windows_add_dll (LPVOID load_addr) +{ + HMODULE dummy_hmodule; + DWORD cb_needed; + HMODULE *hmodules; + int i; + +#ifdef __x86_64__ + if (wow64_process) + { + if (EnumProcessModulesEx (current_process_handle, &dummy_hmodule, + sizeof (HMODULE), &cb_needed, + LIST_MODULES_32BIT) == 0) + return; + } + else +#endif + { + if (EnumProcessModules (current_process_handle, &dummy_hmodule, + sizeof (HMODULE), &cb_needed) == 0) + return; + } + + if (cb_needed < 1) + return; + + hmodules = (HMODULE *) alloca (cb_needed); +#ifdef __x86_64__ + if (wow64_process) + { + if (EnumProcessModulesEx (current_process_handle, hmodules, + cb_needed, &cb_needed, + LIST_MODULES_32BIT) == 0) + return; + } + else +#endif + { + if (EnumProcessModules (current_process_handle, hmodules, + cb_needed, &cb_needed) == 0) + return; + } + + char system_dir[MAX_PATH]; + char syswow_dir[MAX_PATH]; + size_t system_dir_len = 0; + bool convert_syswow_dir = false; +#ifdef __x86_64__ + if (wow64_process) +#endif + { + /* This fails on 32bit Windows because it has no SysWOW64 directory, + and in this case a path conversion isn't necessary. */ + UINT len = GetSystemWow64DirectoryA (syswow_dir, sizeof (syswow_dir)); + if (len > 0) + { + /* Check that we have passed a large enough buffer. */ + gdb_assert (len < sizeof (syswow_dir)); + + len = GetSystemDirectoryA (system_dir, sizeof (system_dir)); + /* Error check. */ + gdb_assert (len != 0); + /* Check that we have passed a large enough buffer. */ + gdb_assert (len < sizeof (system_dir)); + + strcat (system_dir, "\\"); + strcat (syswow_dir, "\\"); + system_dir_len = strlen (system_dir); + + convert_syswow_dir = true; + } + + } + for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++) + { + MODULEINFO mi; +#ifdef __USEWIDE + wchar_t dll_name[MAX_PATH]; + char dll_name_mb[MAX_PATH]; +#else + char dll_name[MAX_PATH]; +#endif + const char *name; + if (GetModuleInformation (current_process_handle, hmodules[i], + &mi, sizeof (mi)) == 0) + continue; + + if (GetModuleFileNameEx (current_process_handle, hmodules[i], + dll_name, sizeof (dll_name)) == 0) + continue; +#ifdef __USEWIDE + wcstombs (dll_name_mb, dll_name, MAX_PATH); + name = dll_name_mb; +#else + name = dll_name; +#endif + /* Convert the DLL path of 32bit processes returned by + GetModuleFileNameEx from the 64bit system directory to the + 32bit syswow64 directory if necessary. */ + std::string syswow_dll_path; + if (convert_syswow_dir + && strncasecmp (name, system_dir, system_dir_len) == 0 + && strchr (name + system_dir_len, '\\') == nullptr) + { + syswow_dll_path = syswow_dir; + syswow_dll_path += name + system_dir_len; + name = syswow_dll_path.c_str(); + } + + /* Record the DLL if either LOAD_ADDR is NULL or the address + at which the DLL was loaded is equal to LOAD_ADDR. */ + if (!(load_addr != nullptr && mi.lpBaseOfDll != load_addr)) + { + handle_load_dll (name, mi.lpBaseOfDll); + if (load_addr != nullptr) + return; + } + } +} + +/* See nat/windows-nat.h. */ + +void +dll_loaded_event () +{ + gdb_assert (current_event.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT); + + 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. + Note that Microsoft documents this fields as strictly optional, + 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); + /* 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); +} + +/* See nat/windows-nat.h. */ + +void +windows_add_all_dlls () +{ + windows_add_dll (nullptr); +} + /* See nat/windows-nat.h. */ bool diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h index c7ef00ea30b..821866bc63f 100644 --- a/gdb/nat/windows-nat.h +++ b/gdb/nat/windows-nat.h @@ -135,9 +135,12 @@ extern int handle_output_debug_string (struct target_waitstatus *ourstatus); 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. + This function must be supplied by the embedding application. */ -extern void handle_load_dll (); +extern void handle_load_dll (const char *dll_name, LPVOID base); /* Handle a DLL unload event. @@ -234,6 +237,15 @@ typedef enum extern handle_exception_result handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions); +/* Call to indicate that a DLL was loaded. */ + +extern void dll_loaded_event (); + +/* Iterate over all DLLs currently mapped by our inferior, and + add them to our list of solibs. */ + +extern void windows_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. */ diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 471d8fca99a..22f8b7a2028 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -787,38 +787,13 @@ windows_make_so (const char *name, LPVOID load_addr) return so; } -static bool windows_add_dll (LPVOID); - /* See nat/windows-nat.h. */ void -windows_nat::handle_load_dll () +windows_nat::handle_load_dll (const char *dll_name, LPVOID base) { - 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. - Note that Microsoft documents this fields as strictly optional, - 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); - /* 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) - { - - solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll); - solib_end = solib_end->next; - } - else if (event->lpBaseOfDll != nullptr - && windows_add_dll (event->lpBaseOfDll)) - dll_name = solib_end->so_name; - - if (dll_name == nullptr) - return; + solib_end->next = windows_make_so (dll_name, base); + solib_end = solib_end->next; lm_info_windows *li = (lm_info_windows *) solib_end->lm_info; @@ -1641,7 +1616,7 @@ windows_nat_target::get_windows_debug_event (int pid, CloseHandle (current_event.u.LoadDll.hFile); if (saw_create != 1 || ! windows_initialization_done) break; - catch_errors (handle_load_dll); + catch_errors (dll_loaded_event); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.integer = 0; thread_id = current_event.dwThreadId; @@ -1823,145 +1798,6 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, } } -/* Iterate over all DLLs currently mapped by our inferior, and - add them to our list of solibs. */ - -static void -windows_add_all_dlls (void) -{ - windows_add_dll (NULL); -} - -/* 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 and return 'true'; otherwise do nothing and return - 'false'. 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. */ - -static bool -windows_add_dll (LPVOID load_addr) -{ - HMODULE dummy_hmodule; - DWORD cb_needed; - HMODULE *hmodules; - int i; - -#ifdef __x86_64__ - if (wow64_process) - { - if (EnumProcessModulesEx (current_process_handle, &dummy_hmodule, - sizeof (HMODULE), &cb_needed, - LIST_MODULES_32BIT) == 0) - return false; - } - else -#endif - { - if (EnumProcessModules (current_process_handle, &dummy_hmodule, - sizeof (HMODULE), &cb_needed) == 0) - return false; - } - - if (cb_needed < 1) - return false; - - hmodules = (HMODULE *) alloca (cb_needed); -#ifdef __x86_64__ - if (wow64_process) - { - if (EnumProcessModulesEx (current_process_handle, hmodules, - cb_needed, &cb_needed, - LIST_MODULES_32BIT) == 0) - return false; - } - else -#endif - { - if (EnumProcessModules (current_process_handle, hmodules, - cb_needed, &cb_needed) == 0) - return false; - } - - char system_dir[__PMAX]; - char syswow_dir[__PMAX]; - size_t system_dir_len = 0; - bool convert_syswow_dir = false; -#ifdef __x86_64__ - if (wow64_process) -#endif - { - /* This fails on 32bit Windows because it has no SysWOW64 directory, - and in this case a path conversion isn't necessary. */ - UINT len = GetSystemWow64DirectoryA (syswow_dir, sizeof (syswow_dir)); - if (len > 0) - { - /* Check that we have passed a large enough buffer. */ - gdb_assert (len < sizeof (syswow_dir)); - - len = GetSystemDirectoryA (system_dir, sizeof (system_dir)); - /* Error check. */ - gdb_assert (len != 0); - /* Check that we have passed a large enough buffer. */ - gdb_assert (len < sizeof (system_dir)); - - strcat (system_dir, "\\"); - strcat (syswow_dir, "\\"); - system_dir_len = strlen (system_dir); - - convert_syswow_dir = true; - } - - } - for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++) - { - MODULEINFO mi; -#ifdef __USEWIDE - wchar_t dll_name[__PMAX]; - char dll_name_mb[__PMAX]; -#else - char dll_name[__PMAX]; -#endif - const char *name; - if (GetModuleInformation (current_process_handle, hmodules[i], - &mi, sizeof (mi)) == 0) - continue; - - if (GetModuleFileNameEx (current_process_handle, hmodules[i], - dll_name, sizeof (dll_name)) == 0) - continue; -#ifdef __USEWIDE - wcstombs (dll_name_mb, dll_name, __PMAX); - name = dll_name_mb; -#else - name = dll_name; -#endif - /* Convert the DLL path of 32bit processes returned by - GetModuleFileNameEx from the 64bit system directory to the - 32bit syswow64 directory if necessary. */ - std::string syswow_dll_path; - if (convert_syswow_dir - && strncasecmp (name, system_dir, system_dir_len) == 0 - && strchr (name + system_dir_len, '\\') == nullptr) - { - syswow_dll_path = syswow_dir; - syswow_dll_path += name + system_dir_len; - name = syswow_dll_path.c_str(); - } - - /* Record the DLL if either LOAD_ADDR is NULL or the address - at which the DLL was loaded is equal to LOAD_ADDR. */ - if (!(load_addr != nullptr && mi.lpBaseOfDll != load_addr)) - { - solib_end->next = windows_make_so (name, mi.lpBaseOfDll); - solib_end = solib_end->next; - if (load_addr != nullptr) - return true; - } - } - return load_addr == nullptr ? true : false; -} - void windows_nat_target::do_initial_windows_stuff (DWORD pid, bool attaching) { diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog index 86e87c54eda..057ed158be9 100644 --- a/gdbserver/ChangeLog +++ b/gdbserver/ChangeLog @@ -1,3 +1,12 @@ +2021-04-30 Tom Tromey + + * win32-low.cc (do_initial_child_stuff): Update. + (windows_nat::handle_load_dll): Rename from win32_add_one_solib. + Change parameter type. + (win32_add_dll, win32_add_all_dlls) + (windows_nat::handle_load_dll): Remove. + (get_child_debug_event): Call dll_loaded_event. + 2021-04-30 Tom Tromey * win32-low.cc (GETPROCADDRESS): Remove. diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc index d742ecd0d8f..5c7946bd33a 100644 --- a/gdbserver/win32-low.cc +++ b/gdbserver/win32-low.cc @@ -90,8 +90,6 @@ const struct target_desc *wow64_win32_tdesc; #define NUM_REGS (the_low_target.num_regs ()) -static void win32_add_all_dlls (void); - /* Get the thread ID from the current selected inferior (the current thread). */ static ptid_t @@ -419,7 +417,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) Rather than try to work around this sort of issue, it is much simpler to just ignore DLL load/unload events during the startup phase, and then process them all in one batch now. */ - win32_add_all_dlls (); + windows_add_all_dlls (); child_initialization_done = 1; } @@ -937,9 +935,13 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) child_continue (continue_status, tid); } -static void -win32_add_one_solib (const char *name, CORE_ADDR load_addr) +/* See nat/windows-nat.h. */ + +void +windows_nat::handle_load_dll (const char *name, LPVOID base) { + CORE_ADDR load_addr = (CORE_ADDR) (uintptr_t) base; + char buf[MAX_PATH + 1]; char buf2[MAX_PATH + 1]; @@ -987,162 +989,6 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) loaded_dll (buf2, load_addr); } -/* Iterate over all DLLs currently mapped by our inferior, looking for - a DLL loaded at LOAD_ADDR; if found, return its file name, - otherwise return NULL. If LOAD_ADDR is NULL, add all mapped DLLs - to our list of solibs. */ - -static char * -win32_add_dll (LPVOID load_addr) -{ - size_t i; - HMODULE dh_buf[1]; - HMODULE *DllHandle = dh_buf; - DWORD cbNeeded; - BOOL ok; - - cbNeeded = 0; -#ifdef __x86_64__ - if (wow64_process) - ok = EnumProcessModulesEx (current_process_handle, - DllHandle, - sizeof (HMODULE), - &cbNeeded, - LIST_MODULES_32BIT); - else -#endif - ok = EnumProcessModules (current_process_handle, - DllHandle, - sizeof (HMODULE), - &cbNeeded); - - if (!ok || !cbNeeded) - return NULL; - - DllHandle = (HMODULE *) alloca (cbNeeded); - if (!DllHandle) - return NULL; - -#ifdef __x86_64__ - if (wow64_process) - ok = EnumProcessModulesEx (current_process_handle, - DllHandle, - cbNeeded, - &cbNeeded, - LIST_MODULES_32BIT); - else -#endif - ok = EnumProcessModules (current_process_handle, - DllHandle, - cbNeeded, - &cbNeeded); - if (!ok) - return NULL; - - char system_dir[MAX_PATH]; - char syswow_dir[MAX_PATH]; - size_t system_dir_len = 0; - bool convert_syswow_dir = false; -#ifdef __x86_64__ - if (wow64_process) -#endif - { - /* This fails on 32bit Windows because it has no SysWOW64 directory, - and in this case a path conversion isn't necessary. */ - UINT len = GetSystemWow64DirectoryA (syswow_dir, sizeof (syswow_dir)); - if (len > 0) - { - /* Check that we have passed a large enough buffer. */ - gdb_assert (len < sizeof (syswow_dir)); - - len = GetSystemDirectoryA (system_dir, sizeof (system_dir)); - /* Error check. */ - gdb_assert (len != 0); - /* Check that we have passed a large enough buffer. */ - gdb_assert (len < sizeof (system_dir)); - - strcat (system_dir, "\\"); - strcat (syswow_dir, "\\"); - system_dir_len = strlen (system_dir); - - convert_syswow_dir = true; - } - - } - - for (i = 1; i < ((size_t) cbNeeded / sizeof (HMODULE)); i++) - { - MODULEINFO mi; - static char dll_name[MAX_PATH]; - - if (!GetModuleInformation (current_process_handle, - DllHandle[i], - &mi, - sizeof (mi))) - continue; - if (GetModuleFileNameExA (current_process_handle, - DllHandle[i], - dll_name, - MAX_PATH) == 0) - continue; - - if (load_addr != nullptr && mi.lpBaseOfDll != load_addr) - continue; - - const char *name = dll_name; - /* Convert the DLL path of 32bit processes returned by - GetModuleFileNameEx from the 64bit system directory to the - 32bit syswow64 directory if necessary. */ - std::string syswow_dll_path; - if (convert_syswow_dir - && strncasecmp (dll_name, system_dir, system_dir_len) == 0 - && strchr (dll_name + system_dir_len, '\\') == nullptr) - { - syswow_dll_path = syswow_dir; - syswow_dll_path += dll_name + system_dir_len; - name = syswow_dll_path.c_str(); - } - - if (load_addr != nullptr) - { - if (name != dll_name) - strcpy (dll_name, name); - return dll_name; - } - else - win32_add_one_solib (name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll); - } - return NULL; -} - -/* Iterate over all DLLs currently mapped by our inferior, and - add them to our list of solibs. */ - -static void -win32_add_all_dlls (void) -{ - win32_add_dll (NULL); -} - -/* See nat/windows-nat.h. */ - -void -windows_nat::handle_load_dll () -{ - LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; - const char *dll_name; - - dll_name = get_image_name (current_process_handle, - event->lpImageName, event->fUnicode); - if (dll_name == nullptr - && event->lpBaseOfDll != nullptr) - dll_name = win32_add_dll (event->lpBaseOfDll); - if (dll_name == nullptr) - return; - - win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) event->lpBaseOfDll); -} - /* See nat/windows-nat.h. */ void @@ -1367,7 +1213,7 @@ get_child_debug_event (DWORD *continue_status, CloseHandle (current_event.u.LoadDll.hFile); if (! child_initialization_done) break; - handle_load_dll (); + dll_loaded_event (); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.sig = GDB_SIGNAL_TRAP; -- 2.30.2