This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: PR/2386 [2/2]: MinGW attach to process without an exec file
Updated version reinstating 9x support using ToolHelp32 functions,
following Eli's remarks.
OK ?
--
Pedro Alves
2007-12-28 Pedro Alves <pedro_alves@portugalmail.pt>
PR gdb/2386
* win32-nat.c: Include "tlhelp32.h". Minor cleanups.
(toolhelp_loaded, toolhelp_CreateToolhelp32Snapshot)
(toolhelp_Process32First, toolhelp_Process32Next): New variables.
(load_toolhelp, load_psapi): New functions.
(psapi_get_dll_name): Use load_psapi.
(win32_pid_to_exec_file): Use PSAPI to find native Windows
processes on NT, and ToolHelp32 to find native Windows processes
on 9x.
---
gdb/win32-nat.c | 215 ++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 165 insertions(+), 50 deletions(-)
Index: src/gdb/win32-nat.c
===================================================================
--- src.orig/gdb/win32-nat.c 2007-12-28 22:29:52.000000000 +0000
+++ src/gdb/win32-nat.c 2007-12-29 14:18:38.000000000 +0000
@@ -38,6 +38,8 @@
#include <stdlib.h>
#include <windows.h>
#include <imagehlp.h>
+#include <tlhelp32.h>
+#include <psapi.h>
#ifdef __CYGWIN__
#include <sys/cygwin.h>
#endif
@@ -84,7 +86,6 @@ enum
CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
};
#endif
-#include <psapi.h>
#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
| CONTEXT_EXTENDED_REGISTERS
@@ -247,6 +248,36 @@ check (BOOL ok, const char *file, int li
GetLastError ());
}
+static int toolhelp_loaded = 0;
+static HANDLE WINAPI (*toolhelp_CreateToolhelp32Snapshot) (DWORD, DWORD);
+static BOOL WINAPI (*toolhelp_Process32First) (HANDLE, LPPROCESSENTRY32);
+static BOOL WINAPI (*toolhelp_Process32Next) (HANDLE, LPPROCESSENTRY32);
+
+/* Try to get pointers into ToolHelp32 funcions and return true if
+ available. Loaded dunamically, because ToolHelp32 is not available
+ on some versions of NT. */
+static int
+load_toolhelp (void)
+{
+ if (!toolhelp_loaded)
+ {
+ HMODULE h = GetModuleHandle ("kernel32.dll");
+ if (h != NULL)
+ {
+ toolhelp_CreateToolhelp32Snapshot = (void *)
+ GetProcAddress (h, "CreateToolhelp32Snapshot");
+ toolhelp_Process32First = GetProcAddress (h, "Process32First");
+ toolhelp_Process32Next = GetProcAddress (h, "Process32Next");
+ }
+
+ toolhelp_loaded = 1;
+ }
+
+ return (toolhelp_CreateToolhelp32Snapshot != NULL
+ && toolhelp_Process32First != NULL
+ && toolhelp_Process32Next != NULL);
+}
+
/* Find a thread record given a thread id. If GET_CONTEXT is not 0,
then also retrieve the context for this thread. If GET_CONTEXT is
negative, then don't suspend the thread. */
@@ -458,9 +489,41 @@ win32_store_inferior_registers (struct r
static int psapi_loaded = 0;
static HMODULE psapi_module_handle = NULL;
-static BOOL WINAPI (*psapi_EnumProcessModules) (HANDLE, HMODULE *, DWORD, LPDWORD) = NULL;
-static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, DWORD) = NULL;
-static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, DWORD) = NULL;
+static BOOL WINAPI (*psapi_EnumProcessModules) (HANDLE, HMODULE *,
+ DWORD, LPDWORD) = NULL;
+static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE,
+ LPMODULEINFO, DWORD) = NULL;
+static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE,
+ LPSTR, DWORD) = NULL;
+
+/* Dinamically load psapi.dll, and get pointers to the functions we
+ need from it. PSAPI (Process Status API) is an NT helper library
+ available as a redistributable from MSFT, but chances are the user
+ already has it on the system.
+
+ Return true if the library is available. The clients are
+ responsible for checking if the function they want was found. */
+static int
+load_psapi (void)
+{
+ if (!psapi_loaded)
+ {
+ psapi_loaded = 1;
+ psapi_module_handle = LoadLibrary ("psapi.dll");
+ if (psapi_module_handle != NULL)
+ {
+ psapi_EnumProcessModules
+ = GetProcAddress (psapi_module_handle, "EnumProcessModules");
+ psapi_GetModuleInformation
+ = GetProcAddress (psapi_module_handle, "GetModuleInformation");
+ psapi_GetModuleFileNameExA = (void *)
+ GetProcAddress (psapi_module_handle, "GetModuleFileNameExA");
+ }
+ }
+
+ return psapi_module_handle != NULL;
+}
+
static int
psapi_get_dll_name (DWORD BaseAddress, char *dll_name_ret)
@@ -473,29 +536,13 @@ psapi_get_dll_name (DWORD BaseAddress, c
DWORD cbNeeded;
BOOL ok;
- if (!psapi_loaded ||
- psapi_EnumProcessModules == NULL ||
- psapi_GetModuleInformation == NULL ||
- psapi_GetModuleFileNameExA == NULL)
- {
- if (psapi_loaded)
- goto failed;
- psapi_loaded = 1;
- psapi_module_handle = LoadLibrary ("psapi.dll");
- if (!psapi_module_handle)
- {
- /* printf_unfiltered ("error loading psapi.dll: %u", GetLastError ()); */
- goto failed;
- }
- psapi_EnumProcessModules = GetProcAddress (psapi_module_handle, "EnumProcessModules");
- psapi_GetModuleInformation = GetProcAddress (psapi_module_handle, "GetModuleInformation");
- psapi_GetModuleFileNameExA = (void *) GetProcAddress (psapi_module_handle,
- "GetModuleFileNameExA");
- if (psapi_EnumProcessModules == NULL ||
- psapi_GetModuleInformation == NULL ||
- psapi_GetModuleFileNameExA == NULL)
- goto failed;
- }
+ if (!load_psapi ())
+ goto failed;
+
+ if (psapi_EnumProcessModules == NULL
+ || psapi_GetModuleInformation == NULL
+ || psapi_GetModuleFileNameExA == NULL)
+ goto failed;
cbNeeded = 0;
ok = (*psapi_EnumProcessModules) (current_process_handle,
@@ -1727,38 +1774,106 @@ win32_detach (char *args, int from_tty)
unpush_target (&win32_ops);
}
+/* Accepts an integer PID; Returns a string representing a file that
+ can be opened to get the symbols for the child process. */
+
static char *
win32_pid_to_exec_file (int pid)
{
- /* Try to find the process path using the Cygwin internal process list
- pid isn't a valid pid, unfortunately. Use current_event.dwProcessId
- instead. */
-
static char path[MAX_PATH + 1];
- char *path_ptr = NULL;
+ BOOL ok = FALSE;
+ OSVERSIONINFO osvi = { 0 };
+
+ /* PID isn't a valid pid, unfortunately. Use current_event.dwProcessId
+ instead. */
+ pid = current_event.dwProcessId;
#ifdef __CYGWIN__
- /* TODO: Also find native Windows processes using CW_GETPINFO_FULL. */
- int cpid;
- struct external_pinfo *pinfo;
-
- cygwin_internal (CW_LOCK_PINFO, 1000);
- for (cpid = 0;
- (pinfo = (struct external_pinfo *)
- cygwin_internal (CW_GETPINFO, cpid | CW_NEXTPID));
- cpid = pinfo->pid)
- {
- if (pinfo->dwProcessId == current_event.dwProcessId) /* Got it */
- {
- cygwin_conv_to_full_posix_path (pinfo->progname, path);
- path_ptr = path;
- break;
- }
+ {
+ /* Try to find the process path using the Cygwin internal process
+ list. */
+ int cpid;
+ struct external_pinfo *pinfo;
+
+ cygwin_internal (CW_LOCK_PINFO, 1000);
+ for (cpid = 0;
+ (pinfo = (struct external_pinfo *)
+ cygwin_internal (CW_GETPINFO, cpid | CW_NEXTPID));
+ cpid = pinfo->pid)
+ {
+ if (pinfo->dwProcessId == current_event.dwProcessId) /* Got it */
+ {
+ cygwin_conv_to_full_posix_path (pinfo->progname, path);
+ ok = TRUE;
+ break;
+ }
+ }
+ cygwin_internal (CW_UNLOCK_PINFO);
+ if (ok)
+ return path;
+ }
+#endif
+
+ osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ GetVersionEx (&osvi);
+ if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ /* Try to find native Windows processes using PSAPI. */
+ if (load_psapi ()
+ && psapi_GetModuleFileNameExA != NULL)
+ {
+ HANDLE h;
+ h = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+ 0, pid);
+ if (h != NULL)
+ {
+ if (psapi_GetModuleFileNameExA (h, 0, path, MAX_PATH) > 0)
+ ok = TRUE;
+ CloseHandle (h);
+ }
+ }
}
- cygwin_internal (CW_UNLOCK_PINFO);
+ else
+ {
+ /* Iterate through all the processes in the system using
+ ToolHelp32 looking for PID. We only use this method on 9x
+ because on on NT the szExeFile field doesn't include the full
+ path to the executable. */
+
+ if (load_toolhelp ())
+ {
+ HANDLE h;
+ h = toolhelp_CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, pid);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ PROCESSENTRY32 e = { sizeof (PROCESSENTRY32) };
+ int n;
+ for (n = toolhelp_Process32First (h, &e);
+ n;
+ n = toolhelp_Process32Next (h, &e))
+ if (e.th32ProcessID == pid)
+ {
+ strcpy (path, e.szExeFile);
+ ok = TRUE;
+ break;
+ }
+
+ CloseHandle (h);
+ }
+ }
+ }
+
+ if (ok)
+ {
+#ifdef __CYGWIN__
+ char buf[sizeof path];
+ strcpy (buf, path);
+ cygwin_conv_to_full_posix_path (buf, path);
#endif
+ return path;
+ }
- return path_ptr;
+ return NULL;
}
/* Print status information about what we're accessing. */