Implement pid_to_exec_file for Windows in gdbserver

I noticed that gdbserver did not implement pid_to_exec_file for
Windows, while gdb did implement it.  This patch moves the code to
nat/windows-nat.c, so that it can be shared.  This makes the gdbserver
implementation trivial.
This commit is contained in:
Tom Tromey 2022-04-26 14:16:57 -06:00
parent 4eab18b566
commit fcab58390f
5 changed files with 119 additions and 87 deletions

View file

@ -144,6 +144,99 @@ windows_thread_info::thread_name ()
return name.get (); return name.get ();
} }
/* Try to determine the executable filename.
EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN.
Upon success, the filename is stored inside EXE_NAME_RET, and
this function returns nonzero.
Otherwise, this function returns zero and the contents of
EXE_NAME_RET is undefined. */
int
windows_process_info::get_exec_module_filename (char *exe_name_ret,
size_t exe_name_max_len)
{
DWORD len;
HMODULE dh_buf;
DWORD cbNeeded;
cbNeeded = 0;
#ifdef __x86_64__
if (wow64_process)
{
if (!EnumProcessModulesEx (handle,
&dh_buf, sizeof (HMODULE), &cbNeeded,
LIST_MODULES_32BIT)
|| !cbNeeded)
return 0;
}
else
#endif
{
if (!EnumProcessModules (handle,
&dh_buf, sizeof (HMODULE), &cbNeeded)
|| !cbNeeded)
return 0;
}
/* We know the executable is always first in the list of modules,
which we just fetched. So no need to fetch more. */
#ifdef __CYGWIN__
{
/* Cygwin prefers that the path be in /x/y/z format, so extract
the filename into a temporary buffer first, and then convert it
to POSIX format into the destination buffer. */
cygwin_buf_t *pathbuf = (cygwin_buf_t *) alloca (exe_name_max_len * sizeof (cygwin_buf_t));
len = GetModuleFileNameEx (current_process_handle,
dh_buf, pathbuf, exe_name_max_len);
if (len == 0)
error (_("Error getting executable filename: %u."),
(unsigned) GetLastError ());
if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, exe_name_ret,
exe_name_max_len) < 0)
error (_("Error converting executable filename to POSIX: %d."), errno);
}
#else
len = GetModuleFileNameEx (handle,
dh_buf, exe_name_ret, exe_name_max_len);
if (len == 0)
error (_("Error getting executable filename: %u."),
(unsigned) GetLastError ());
#endif
return 1; /* success */
}
const char *
windows_process_info::pid_to_exec_file (int pid)
{
static char path[MAX_PATH];
#ifdef __CYGWIN__
/* Try to find exe name as symlink target of /proc/<pid>/exe. */
int nchars;
char procexe[sizeof ("/proc/4294967295/exe")];
xsnprintf (procexe, sizeof (procexe), "/proc/%u/exe", pid);
nchars = readlink (procexe, path, sizeof(path));
if (nchars > 0 && nchars < sizeof (path))
{
path[nchars] = '\0'; /* Got it */
return path;
}
#endif
/* If we get here then either Cygwin is hosed, this isn't a Cygwin version
of gdb, or we're trying to debug a non-Cygwin windows executable. */
if (!get_exec_module_filename (path, sizeof (path)))
path[0] = '\0';
return path;
}
/* Return the name of the DLL referenced by H at ADDRESS. UNICODE /* Return the name of the DLL referenced by H at ADDRESS. UNICODE
determines what sort of string is read from the inferior. Returns determines what sort of string is read from the inferior. Returns
the name of the DLL, or NULL on error. If a name is returned, it the name of the DLL, or NULL on error. If a name is returned, it

View file

@ -248,6 +248,8 @@ struct windows_process_info
gdb::optional<pending_stop> fetch_pending_stop (bool debug_events); gdb::optional<pending_stop> fetch_pending_stop (bool debug_events);
const char *pid_to_exec_file (int);
private: private:
/* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is /* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is
@ -266,6 +268,18 @@ private:
presumed loaded. */ presumed loaded. */
void add_dll (LPVOID load_addr); void add_dll (LPVOID load_addr);
/* Try to determine the executable filename.
EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN.
Upon success, the filename is stored inside EXE_NAME_RET, and
this function returns nonzero.
Otherwise, this function returns zero and the contents of
EXE_NAME_RET is undefined. */
int get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len);
}; };
/* A simple wrapper for ContinueDebugEvent that continues the last /* A simple wrapper for ContinueDebugEvent that continues the last

View file

@ -1937,98 +1937,12 @@ windows_nat_target::detach (inferior *inf, int from_tty)
maybe_unpush_target (); maybe_unpush_target ();
} }
/* Try to determine the executable filename.
EXE_NAME_RET is a pointer to a buffer whose size is EXE_NAME_MAX_LEN.
Upon success, the filename is stored inside EXE_NAME_RET, and
this function returns nonzero.
Otherwise, this function returns zero and the contents of
EXE_NAME_RET is undefined. */
static int
windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len)
{
DWORD len;
HMODULE dh_buf;
DWORD cbNeeded;
cbNeeded = 0;
#ifdef __x86_64__
if (windows_process.wow64_process)
{
if (!EnumProcessModulesEx (windows_process.handle,
&dh_buf, sizeof (HMODULE), &cbNeeded,
LIST_MODULES_32BIT)
|| !cbNeeded)
return 0;
}
else
#endif
{
if (!EnumProcessModules (windows_process.handle,
&dh_buf, sizeof (HMODULE), &cbNeeded)
|| !cbNeeded)
return 0;
}
/* We know the executable is always first in the list of modules,
which we just fetched. So no need to fetch more. */
#ifdef __CYGWIN__
{
/* Cygwin prefers that the path be in /x/y/z format, so extract
the filename into a temporary buffer first, and then convert it
to POSIX format into the destination buffer. */
cygwin_buf_t *pathbuf = (cygwin_buf_t *) alloca (exe_name_max_len * sizeof (cygwin_buf_t));
len = GetModuleFileNameEx (current_process_handle,
dh_buf, pathbuf, exe_name_max_len);
if (len == 0)
error (_("Error getting executable filename: %u."),
(unsigned) GetLastError ());
if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, exe_name_ret,
exe_name_max_len) < 0)
error (_("Error converting executable filename to POSIX: %d."), errno);
}
#else
len = GetModuleFileNameEx (windows_process.handle,
dh_buf, exe_name_ret, exe_name_max_len);
if (len == 0)
error (_("Error getting executable filename: %u."),
(unsigned) GetLastError ());
#endif
return 1; /* success */
}
/* The pid_to_exec_file target_ops method for this platform. */ /* The pid_to_exec_file target_ops method for this platform. */
const char * const char *
windows_nat_target::pid_to_exec_file (int pid) windows_nat_target::pid_to_exec_file (int pid)
{ {
static char path[__PMAX]; return windows_process.pid_to_exec_file (pid);
#ifdef __CYGWIN__
/* Try to find exe name as symlink target of /proc/<pid>/exe. */
int nchars;
char procexe[sizeof ("/proc/4294967295/exe")];
xsnprintf (procexe, sizeof (procexe), "/proc/%u/exe", pid);
nchars = readlink (procexe, path, sizeof(path));
if (nchars > 0 && nchars < sizeof (path))
{
path[nchars] = '\0'; /* Got it */
return path;
}
#endif
/* If we get here then either Cygwin is hosed, this isn't a Cygwin version
of gdb, or we're trying to debug a non-Cygwin windows executable. */
if (!windows_get_exec_module_filename (path, sizeof (path)))
path[0] = '\0';
return path;
} }
/* Print status information about what we're accessing. */ /* Print status information about what we're accessing. */

View file

@ -1515,6 +1515,12 @@ win32_process_target::thread_name (ptid_t thread)
return th->thread_name (); return th->thread_name ();
} }
const char *
win32_process_target::pid_to_exec_file (int pid)
{
return windows_process.pid_to_exec_file (pid);
}
/* The win32 target ops object. */ /* The win32 target ops object. */
static win32_process_target the_win32_target; static win32_process_target the_win32_target;

View file

@ -160,6 +160,11 @@ public:
bool supports_stopped_by_sw_breakpoint () override; bool supports_stopped_by_sw_breakpoint () override;
const char *thread_name (ptid_t thread) override; const char *thread_name (ptid_t thread) override;
bool supports_pid_to_exec_file () override
{ return true; }
const char *pid_to_exec_file (int pid) override;
}; };
/* The sole Windows process. */ /* The sole Windows process. */