2007-12-28 Pedro Alves PR gdb/2386 * win32-nat.c: Include "ntdef.h", "wchar.h" and "safe-ctype.h". (current_process_file_handle): New variable. (load_psapi): New function. (psapi_get_dll_name): Use load_psapi. (get_win32_debug_event): Don't close the process file handle. Store it in current_process_file_handle. (do_initial_win32_stuff): Clear current_process_file_handle. (pid_to_exec_file_psapi, device_filename_to_dos_filename): New functions. (OBJECT_INFO_CLASS, OBJECT_NAME_INFO): New structs. (NTQUERYOBJECT): New variable. (get_nt_object_name, get_file_name_from_handle_objname) (win32_pid_to_exec_file): Also find native Windows processes. (win32_mourn_inferior): Close current_process_file_handle. * Makefile.in (win32-nat.o): Add dependency on $(safe_ctype_h). --- gdb/Makefile.in | 2 gdb/win32-nat.c | 262 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 214 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-28 22:30:48.000000000 +0000 @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include #ifdef __CYGWIN__ #include #endif @@ -57,6 +60,7 @@ #include "solist.h" #include "solib.h" #include "xml-support.h" +#include "safe-ctype.h" #include "i386-tdep.h" #include "i387-tdep.h" @@ -84,7 +88,6 @@ enum CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT) }; #endif -#include #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \ | CONTEXT_EXTENDED_REGISTERS @@ -135,6 +138,8 @@ static thread_info thread_head; static DEBUG_EVENT current_event; /* The current debug event from WaitForDebugEvent */ static HANDLE current_process_handle; /* Currently executing process */ +static HANDLE current_process_file_handle; /* Currently executing + process' file handle */ static thread_info *current_thread; /* Info on currently selected thread */ static DWORD main_thread_id; /* Thread ID of the main thread */ @@ -463,6 +468,28 @@ static BOOL WINAPI (*psapi_GetModuleInfo static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, DWORD) = NULL; 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) { DWORD len; @@ -473,29 +500,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, @@ -1345,7 +1356,7 @@ get_win32_debug_event (int pid, struct t (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_PROCESS_DEBUG_EVENT")); - CloseHandle (current_event.u.CreateProcessInfo.hFile); + current_process_file_handle = current_event.u.CreateProcessInfo.hFile; if (++saw_create != 1) break; @@ -1507,8 +1518,9 @@ do_initial_win32_stuff (DWORD pid) #ifdef __CYGWIN__ cygwin_load_start = cygwin_load_end = 0; #endif - current_event.dwProcessId = pid; memset (¤t_event, 0, sizeof (current_event)); + current_event.dwProcessId = pid; + current_process_file_handle = INVALID_HANDLE_VALUE; push_target (&win32_ops); disable_breakpoints_in_shlibs (); win32_clear_solib (); @@ -1727,38 +1739,184 @@ win32_detach (char *args, int from_tty) unpush_target (&win32_ops); } +static BOOL +pid_to_exec_file_psapi (DWORD pid, char *pathbuf) +{ + BOOL ok = FALSE; + + load_psapi (); + + if (psapi_GetModuleFileNameExA != NULL) + { + HANDLE h; + h = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); + if (h != NULL) + { + if (psapi_GetModuleFileNameExA (h, 0, pathbuf, MAX_PATH) > 0) + ok = TRUE; + CloseHandle (h); + } + } + + return ok; +} + +/* Translate a Windows path with device name to a dos style path with + drive letters. + E.g.: + "\\Device\\HarddiskVolume1\\cygwin\\bin\\cat.exe" + -> "c:\\cygwin\\bin\\cat.exe" +*/ +static BOOL +device_filename_to_dos_filename (char *out, const char *in, size_t outsize) +{ + char drive[] = "_:"; + char all_drives[0x1000]; + char devices[MAX_PATH + 1]; + char *p; + + /* A NULL terminated list of NULL terminated strings. */ + if (!GetLogicalDriveStrings (sizeof all_drives - 1, all_drives)) + return FALSE; + + p = all_drives; + while (*p) + { + /* Copy the drive letter to the template string. */ + *drive = *p; + + /* Look up each device name. DEVICES is a NULL terminated list + of NULL terminated strings. */ + if (QueryDosDevice (drive, devices, sizeof devices - 1)) + { + size_t len = strlen (devices); + if (len < MAX_PATH + && (in[len] == '\\' || in[len] == '\0') + && strncasecmp (in, devices, len) == 0) + { + /* Reconstruct the filename by replacing the device path + with a DOS drive path. */ + snprintf (out, outsize, "%s%s", drive, in + len); + return TRUE; + } + } + + /* Next drive letter. */ + while (*p++) + ; + } + + return FALSE; +} + +typedef enum tagOBJECT_INFO_CLASS +{ + ObjectNameInfo = 1, +} OBJECT_INFO_CLASS; + +typedef struct tagOBJECT_NAME_INFO +{ + UNICODE_STRING ObjectName; + WCHAR ObjectNameBuffer[1]; +} OBJECT_NAME_INFO; + +typedef NTSTATUS (NTAPI *NTQUERYOBJECT)(HANDLE, OBJECT_INFO_CLASS, + PVOID, ULONG, PULONG); +static BOOL +get_nt_object_name (HANDLE h, char *namebuf) +{ + BOOL ok = FALSE; + HMODULE ntdll = GetModuleHandle ("ntdll.dll"); + NTQUERYOBJECT NtQueryObject + = (NTQUERYOBJECT) GetProcAddress (ntdll, "NtQueryObject"); + + size_t size = sizeof (OBJECT_NAME_INFO) + (MAX_PATH + 1) * sizeof (WCHAR); + OBJECT_NAME_INFO *nameinfo = xmalloc (size); + + NTSTATUS rc = NtQueryObject (h, ObjectNameInfo, nameinfo, size, NULL); + if (rc == STATUS_SUCCESS) + { + wchar_t *wname = nameinfo->ObjectName.Buffer; + wcstombs (namebuf, wname, wcslen (wname) + 1); + ok = TRUE; + } + + xfree (nameinfo); + return ok; +} + +static BOOL +get_file_name_from_handle_objname (HANDLE file, char *pathbuf) +{ + char buf[MAX_PATH + 1]; + return (file != INVALID_HANDLE_VALUE + && get_nt_object_name (file, buf) + && device_filename_to_dos_filename (pathbuf, buf, MAX_PATH) + && ISALPHA (pathbuf[0]) && pathbuf[1] == ':'); +} + +/* 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 + static char path[MAX_PATH + 1]; + BOOL ok = FALSE; + + /* PID isn't a valid pid, unfortunately. Use current_event.dwProcessId instead. */ + pid = current_event.dwProcessId; - static char path[MAX_PATH + 1]; - char *path_ptr = NULL; +#ifdef __CYGWIN__ + { + /* 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 + /* Try with native NT functionality. This only works if + pid == current_event.dwProcessId. */ + if (!ok + && pid == current_event.dwProcessId + && get_file_name_from_handle_objname (current_process_file_handle, + path)) + ok = TRUE; + + /* Fallback to trying with PSAPI. */ + if (!ok && pid_to_exec_file_psapi (pid, path)) + ok = TRUE; + + if (ok) + { #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; - } - } - cygwin_internal (CW_UNLOCK_PINFO); + 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. */ @@ -1916,8 +2074,14 @@ win32_mourn_inferior (void) if (open_process_used) { CHECK (CloseHandle (current_process_handle)); + current_process_handle = NULL; open_process_used = 0; } + if (current_process_file_handle != INVALID_HANDLE_VALUE) + { + CHECK (CloseHandle (current_process_file_handle)); + current_process_file_handle = INVALID_HANDLE_VALUE; + } unpush_target (&win32_ops); generic_mourn_inferior (); } Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2007-12-28 22:29:46.000000000 +0000 +++ src/gdb/Makefile.in 2007-12-28 22:30:48.000000000 +0000 @@ -2946,7 +2946,7 @@ win32-nat.o: win32-nat.c $(defs_h) $(fra $(regcache_h) $(top_h) $(buildsym_h) $(symfile_h) $(objfiles_h) \ $(gdb_string_h) $(gdbthread_h) $(gdbcmd_h) $(exec_h) $(solist_h) \ $(solib_h) $(i386_tdep_h) $(i387_tdep_h) $(gdb_obstack_h) \ - $(xml_support_h) $(i386_cygwin_tdep_h) $(gdb_stdint_h) + $(xml_support_h) $(safe_ctype_h) $(i386_cygwin_tdep_h) $(gdb_stdint_h) win32-termcap.o: win32-termcap.c wrapper.o: wrapper.c $(defs_h) $(value_h) $(exceptions_h) $(wrapper_h) \ $(ui_out_h)