This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]