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  <tromey@adacore.com>

	* 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  <tromey@adacore.com>

	* 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.
This commit is contained in:
Tom Tromey 2021-04-30 10:22:23 -06:00
parent de07187290
commit e228ef975e
6 changed files with 209 additions and 331 deletions

View File

@ -1,3 +1,16 @@
2021-04-30 Tom Tromey <tromey@adacore.com>
* 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 <tromey@adacore.com>
* nat/windows-nat.h (GenerateConsoleCtrlEvent): New define.

View File

@ -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 = &current_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

View File

@ -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. */

View File

@ -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 = &current_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)
{

View File

@ -1,3 +1,12 @@
2021-04-30 Tom Tromey <tromey@adacore.com>
* 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 <tromey@adacore.com>
* win32-low.cc (GETPROCADDRESS): Remove.

View File

@ -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 = &current_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;