X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=f2f42f79d710400af1cf1fa0065d5cfee71992db;hb=452fa0647cbaf4fbf4eb5eeb16ef4ac01c88e76f;hp=8fedf9e60a36dd0eba5364568a24eeae92c6ea2e;hpb=f9c72d524f7c66a7ae979f3aa4f7523e16fca2f6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 8fedf9e60a..f2f42f79d7 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,7 +1,7 @@ -/* Target-vector operations for controlling win32 child processes, for GDB. +/* Target-vector operations for controlling windows child processes, for GDB. Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -38,8 +38,10 @@ #include #include #include +#include #ifdef __CYGWIN__ #include +#include #endif #include @@ -60,14 +62,73 @@ #include "i386-tdep.h" #include "i387-tdep.h" -#include "i386-cygwin-tdep.h" - -static struct target_ops win32_ops; +#include "windows-tdep.h" +#include "windows-nat.h" +#include "i386-nat.h" +#include "complaints.h" + +#define AdjustTokenPrivileges dyn_AdjustTokenPrivileges +#define DebugActiveProcessStop dyn_DebugActiveProcessStop +#define DebugBreakProcess dyn_DebugBreakProcess +#define DebugSetProcessKillOnExit dyn_DebugSetProcessKillOnExit +#define EnumProcessModules dyn_EnumProcessModules +#define GetModuleInformation dyn_GetModuleInformation +#define LookupPrivilegeValueA dyn_LookupPrivilegeValueA +#define OpenProcessToken dyn_OpenProcessToken + +static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, + DWORD, PTOKEN_PRIVILEGES, PDWORD); +static BOOL WINAPI (*DebugActiveProcessStop) (DWORD); +static BOOL WINAPI (*DebugBreakProcess) (HANDLE); +static BOOL WINAPI (*DebugSetProcessKillOnExit) (BOOL); +static BOOL WINAPI (*EnumProcessModules) (HANDLE, HMODULE *, DWORD, + LPDWORD); +static BOOL WINAPI (*GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, + DWORD); +static BOOL WINAPI (*LookupPrivilegeValueA)(LPCSTR, LPCSTR, PLUID); +static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE); + +static struct target_ops windows_ops; + +#undef STARTUPINFO +#undef CreateProcess +#undef GetModuleFileNameEx -#ifdef __CYGWIN__ +#ifndef __CYGWIN__ +# define __PMAX (MAX_PATH + 1) + static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPSTR, DWORD); +# define STARTUPINFO STARTUPINFOA +# define CreateProcess CreateProcessA +# define GetModuleFileNameEx_name "GetModuleFileNameExA" +# define bad_GetModuleFileNameEx bad_GetModuleFileNameExA +#else +# define __PMAX PATH_MAX /* The starting and ending address of the cygwin1.dll text segment. */ -static bfd_vma cygwin_load_start; -static bfd_vma cygwin_load_end; + static CORE_ADDR cygwin_load_start; + static CORE_ADDR cygwin_load_end; +# if CYGWIN_VERSION_DLL_MAKE_COMBINED(CYGWIN_VERSION_API_MAJOR,CYGWIN_VERSION_API_MINOR) >= 181 +# define __USEWIDE + typedef wchar_t cygwin_buf_t; + static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPWSTR, DWORD); +# define STARTUPINFO STARTUPINFOW +# define CreateProcess CreateProcessW +# define GetModuleFileNameEx_name "GetModuleFileNameExW" +# define bad_GetModuleFileNameEx bad_GetModuleFileNameExW +# else +# define CCP_POSIX_TO_WIN_W 1 +# define CCP_WIN_W_TO_POSIX 3 +# define cygwin_conv_path(op, from, to, size) \ + (op == CCP_WIN_W_TO_POSIX) ? \ + cygwin_conv_to_full_posix_path (from, to) : \ + cygwin_conv_to_win32_path (from, to) + typedef char cygwin_buf_t; + static DWORD WINAPI (*GetModuleFileNameEx) (HANDLE, HMODULE, LPSTR, DWORD); +# define STARTUPINFO STARTUPINFOA +# define CreateProcess CreateProcessA +# define GetModuleFileNameEx_name "GetModuleFileNameExA" +# define bad_GetModuleFileNameEx bad_GetModuleFileNameExA +# define CW_SET_DOS_FILE_WARNING -1 /* no-op this for older Cygwin */ +# endif #endif static int have_saved_context; /* True if we've saved context from a cygwin signal. */ @@ -83,14 +144,21 @@ enum CONTEXT_DEBUGGER = (CONTEXT_FULL | CONTEXT_FLOATING_POINT) }; #endif -#include + +#ifndef CONTEXT_EXTENDED_REGISTERS +/* This macro is only defined on ia32. It only makes sense on this target, + so define it as zero if not already defined. */ +#define CONTEXT_EXTENDED_REGISTERS 0 +#endif #define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \ | CONTEXT_EXTENDED_REGISTERS -static unsigned dr[8]; +static uintptr_t dr[8]; static int debug_registers_changed; static int debug_registers_used; + +static int windows_initialization_done; #define DR6_CLEAR_VALUE 0xffff0ff0 /* The string sent by cygwin when it processes a signal. @@ -105,9 +173,13 @@ static int debug_registers_used; #define DEBUG_MEM(x) if (debug_memory) printf_unfiltered x #define DEBUG_EXCEPT(x) if (debug_exceptions) printf_unfiltered x -static void win32_stop (ptid_t); -static int win32_win32_thread_alive (ptid_t); -static void win32_kill_inferior (void); +static void windows_stop (ptid_t); +static int windows_thread_alive (struct target_ops *, ptid_t); +static void windows_kill_inferior (struct target_ops *); + +static void cygwin_set_dr (int i, CORE_ADDR addr); +static void cygwin_set_dr7 (unsigned long val); +static unsigned long cygwin_get_dr6 (void); static enum target_signal last_sig = TARGET_SIGNAL_0; /* Set if a signal was received from the debugged process */ @@ -155,11 +227,16 @@ static int debug_memory = 0; /* show target memory accesses */ static int debug_exceptions = 0; /* show target exceptions */ static int useshell = 0; /* use shell for subprocesses */ -/* This vector maps GDB's idea of a register's number into an address - in the win32 exception context vector. +/* This vector maps GDB's idea of a register's number into an offset + in the windows exception context vector. It also contains the bit mask needed to load the register in question. + The contents of this table can only be computed by the units + that provide CPU-specific support for Windows native debugging. + These units should set the table by calling + windows_set_context_register_offsets. + One day we could read a reg, we could inspect the context we already have loaded, if it doesn't have the bit set that we need, we read that set of registers in using GetThreadContext. If the @@ -168,55 +245,7 @@ static int useshell = 0; /* use shell for subprocesses */ the other regs of the group, and then we copy the info in and set out bit. */ -#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) -static const int mappings[] = -{ - context_offset (Eax), - context_offset (Ecx), - context_offset (Edx), - context_offset (Ebx), - context_offset (Esp), - context_offset (Ebp), - context_offset (Esi), - context_offset (Edi), - context_offset (Eip), - context_offset (EFlags), - context_offset (SegCs), - context_offset (SegSs), - context_offset (SegDs), - context_offset (SegEs), - context_offset (SegFs), - context_offset (SegGs), - context_offset (FloatSave.RegisterArea[0 * 10]), - context_offset (FloatSave.RegisterArea[1 * 10]), - context_offset (FloatSave.RegisterArea[2 * 10]), - context_offset (FloatSave.RegisterArea[3 * 10]), - context_offset (FloatSave.RegisterArea[4 * 10]), - context_offset (FloatSave.RegisterArea[5 * 10]), - context_offset (FloatSave.RegisterArea[6 * 10]), - context_offset (FloatSave.RegisterArea[7 * 10]), - context_offset (FloatSave.ControlWord), - context_offset (FloatSave.StatusWord), - context_offset (FloatSave.TagWord), - context_offset (FloatSave.ErrorSelector), - context_offset (FloatSave.ErrorOffset), - context_offset (FloatSave.DataSelector), - context_offset (FloatSave.DataOffset), - context_offset (FloatSave.ErrorSelector) - /* XMM0-7 */ , - context_offset (ExtendedRegisters[10*16]), - context_offset (ExtendedRegisters[11*16]), - context_offset (ExtendedRegisters[12*16]), - context_offset (ExtendedRegisters[13*16]), - context_offset (ExtendedRegisters[14*16]), - context_offset (ExtendedRegisters[15*16]), - context_offset (ExtendedRegisters[16*16]), - context_offset (ExtendedRegisters[17*16]), - /* MXCSR */ - context_offset (ExtendedRegisters[24]) -}; - -#undef context_offset +static const int *mappings; /* This vector maps the target's idea of an exception (extracted from the DEBUG_EVENT structure) to GDB's idea. */ @@ -238,6 +267,15 @@ static const struct xlate_exception {STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE}, {-1, -1}}; +/* Set the MAPPINGS static global to OFFSETS. + See the description of MAPPINGS for more details. */ + +void +windows_set_context_register_offsets (const int *offsets) +{ + mappings = offsets; +} + static void check (BOOL ok, const char *file, int line) { @@ -280,11 +318,16 @@ thread_rec (DWORD id, int get_context) return NULL; } -/* Add a thread to the thread list */ +/* Add a thread to the thread list. */ static thread_info * -win32_add_thread (DWORD id, HANDLE h) +windows_add_thread (ptid_t ptid, HANDLE h) { thread_info *th; + DWORD id; + + gdb_assert (ptid_get_tid (ptid) != 0); + + id = ptid_get_tid (ptid); if ((th = thread_rec (id, FALSE))) return th; @@ -294,8 +337,8 @@ win32_add_thread (DWORD id, HANDLE h) th->h = h; th->next = thread_head.next; thread_head.next = th; - add_thread (pid_to_ptid (id)); - /* Set the debug registers for the new thread in they are used. */ + add_thread (ptid); + /* Set the debug registers for the new thread if they are used. */ if (debug_registers_used) { /* Only change the value of the debug registers. */ @@ -316,11 +359,11 @@ win32_add_thread (DWORD id, HANDLE h) /* Clear out any old thread list and reintialize it to a pristine state. */ static void -win32_init_thread_list (void) +windows_init_thread_list (void) { thread_info *th = &thread_head; - DEBUG_EVENTS (("gdb: win32_init_thread_list\n")); + DEBUG_EVENTS (("gdb: windows_init_thread_list\n")); init_thread_list (); while (th->next != NULL) { @@ -333,13 +376,18 @@ win32_init_thread_list (void) /* Delete a thread from the list of threads */ static void -win32_delete_thread (DWORD id) +windows_delete_thread (ptid_t ptid) { thread_info *th; + DWORD id; + + gdb_assert (ptid_get_tid (ptid) != 0); + + id = ptid_get_tid (ptid); if (info_verbose) - printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (pid_to_ptid (id))); - delete_thread (pid_to_ptid (id)); + printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid)); + delete_thread (ptid); for (th = &thread_head; th->next != NULL && th->next->id != id; @@ -355,7 +403,7 @@ win32_delete_thread (DWORD id) } static void -do_win32_fetch_inferior_registers (struct regcache *regcache, int r) +do_windows_fetch_inferior_registers (struct regcache *regcache, int r) { char *context_offset = ((char *) ¤t_thread->context) + mappings[r]; struct gdbarch *gdbarch = get_regcache_arch (regcache); @@ -383,7 +431,7 @@ do_win32_fetch_inferior_registers (struct regcache *regcache, int r) thread_info *th = current_thread; th->context.ContextFlags = CONTEXT_DEBUGGER_DR; GetThreadContext (th->h, &th->context); - /* Copy dr values from that thread. + /* Copy dr values from that thread. But only if there were not modified since last stop. PR gdb/2388 */ if (!debug_registers_changed) { @@ -413,22 +461,23 @@ do_win32_fetch_inferior_registers (struct regcache *regcache, int r) else { for (r = 0; r < gdbarch_num_regs (gdbarch); r++) - do_win32_fetch_inferior_registers (regcache, r); + do_windows_fetch_inferior_registers (regcache, r); } } static void -win32_fetch_inferior_registers (struct regcache *regcache, int r) +windows_fetch_inferior_registers (struct target_ops *ops, + struct regcache *regcache, int r) { - current_thread = thread_rec (PIDGET (inferior_ptid), TRUE); + current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE); /* Check if current_thread exists. Windows sometimes uses a non-existent thread id in its events */ if (current_thread) - do_win32_fetch_inferior_registers (regcache, r); + do_windows_fetch_inferior_registers (regcache, r); } static void -do_win32_store_inferior_registers (const struct regcache *regcache, int r) +do_windows_store_inferior_registers (const struct regcache *regcache, int r) { if (!current_thread) /* Windows sometimes uses a non-existent thread id in its events */; @@ -438,34 +487,27 @@ do_win32_store_inferior_registers (const struct regcache *regcache, int r) else { for (r = 0; r < gdbarch_num_regs (get_regcache_arch (regcache)); r++) - do_win32_store_inferior_registers (regcache, r); + do_windows_store_inferior_registers (regcache, r); } } /* Store a new register value into the current thread context */ static void -win32_store_inferior_registers (struct regcache *regcache, int r) +windows_store_inferior_registers (struct target_ops *ops, + struct regcache *regcache, int r) { - current_thread = thread_rec (PIDGET (inferior_ptid), TRUE); + current_thread = thread_rec (ptid_get_tid (inferior_ptid), TRUE); /* Check if current_thread exists. Windows sometimes uses a non-existent thread id in its events */ if (current_thread) - do_win32_store_inferior_registers (regcache, r); + do_windows_store_inferior_registers (regcache, r); } -static int psapi_loaded = 0; -static BOOL WINAPI (*psapi_EnumProcessModules) (HANDLE, HMODULE *, DWORD, - LPDWORD); -static BOOL WINAPI (*psapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, - DWORD); -static DWORD WINAPI (*psapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, - DWORD); - /* Get the name of a given module at at given base address. If base_address is zero return the first loaded module (which is always the name of the executable). */ static int -get_module_name (DWORD base_address, char *dll_name_ret) +get_module_name (LPVOID base_address, char *dll_name_ret) { DWORD len; MODULEINFO mi; @@ -474,21 +516,16 @@ get_module_name (DWORD base_address, char *dll_name_ret) HMODULE *DllHandle = dh_buf; /* Set to temporary storage for initial query */ DWORD cbNeeded; #ifdef __CYGWIN__ - char pathbuf[PATH_MAX + 1]; /* Temporary storage prior to converting to - posix form */ -#else - char *pathbuf = dll_name_ret; /* Just copy directly to passed-in arg */ + cygwin_buf_t pathbuf[__PMAX]; /* Temporary storage prior to converting to + posix form. __PMAX is always enough + as long as SO_NAME_MAX_PATH_SIZE is defined + as 512. */ #endif - /* If psapi_loaded < 0 either psapi.dll is not available or it does not contain - the needed functions. */ - if (psapi_loaded <= 0) - goto failed; - cbNeeded = 0; /* Find size of buffer needed to handle list of modules loaded in inferior */ - if (!psapi_EnumProcessModules (current_process_handle, DllHandle, - sizeof (HMODULE), &cbNeeded) || !cbNeeded) + if (!EnumProcessModules (current_process_handle, DllHandle, + sizeof (HMODULE), &cbNeeded) || !cbNeeded) goto failed; /* Allocate correct amount of space for module list */ @@ -497,27 +534,34 @@ get_module_name (DWORD base_address, char *dll_name_ret) goto failed; /* Get the list of modules */ - if (!psapi_EnumProcessModules (current_process_handle, DllHandle, cbNeeded, + if (!EnumProcessModules (current_process_handle, DllHandle, cbNeeded, &cbNeeded)) goto failed; for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++) { /* Get information on this module */ - if (!psapi_GetModuleInformation (current_process_handle, DllHandle[i], - &mi, sizeof (mi))) + if (!GetModuleInformation (current_process_handle, DllHandle[i], + &mi, sizeof (mi))) error (_("Can't get module info")); - if (!base_address || (DWORD) (mi.lpBaseOfDll) == base_address) + if (!base_address || mi.lpBaseOfDll == base_address) { /* Try to find the name of the given module */ - len = psapi_GetModuleFileNameExA (current_process_handle, - DllHandle[i], pathbuf, MAX_PATH); - if (len == 0) - error (_("Error getting dll name: %u."), (unsigned) GetLastError ()); #ifdef __CYGWIN__ /* Cygwin prefers that the path be in /x/y/z format */ - cygwin_conv_to_full_posix_path (pathbuf, dll_name_ret); + len = GetModuleFileNameEx (current_process_handle, + DllHandle[i], pathbuf, __PMAX); + if (len == 0) + error (_("Error getting dll name: %lu."), GetLastError ()); + if (cygwin_conv_path (CCP_WIN_W_TO_POSIX, pathbuf, dll_name_ret, + __PMAX) < 0) + error (_("Error converting dll name to POSIX: %d."), errno); +#else + len = GetModuleFileNameEx (current_process_handle, + DllHandle[i], dll_name_ret, __PMAX); + if (len == 0) + error (_("Error getting dll name: %u."), (unsigned) GetLastError ()); #endif return 1; /* success */ } @@ -544,7 +588,7 @@ struct safe_symbol_file_add_args /* Maintain a linked list of "so" information. */ struct lm_info { - DWORD load_addr; + LPVOID load_addr; }; static struct so_list solib_start, *solib_end; @@ -555,7 +599,9 @@ static int safe_symbol_file_add_stub (void *argv) { #define p ((struct safe_symbol_file_add_args *) argv) - p->ret = symbol_file_add (p->name, p->from_tty, p->addrs, p->mainline, p->flags); + const int add_flags = ((p->from_tty ? SYMFILE_VERBOSE : 0) + | (p->mainline ? SYMFILE_MAINLINE : 0)); + p->ret = symbol_file_add (p->name, add_flags, p->addrs, p->flags); return !!p->ret; #undef p } @@ -603,15 +649,15 @@ safe_symbol_file_add (char *name, int from_tty, } static struct so_list * -win32_make_so (const char *name, DWORD load_addr) +windows_make_so (const char *name, LPVOID load_addr) { struct so_list *so; - char buf[MAX_PATH + 1]; - char cwd[MAX_PATH + 1]; char *p; +#ifndef __CYGWIN__ + char buf[__PMAX]; + char cwd[__PMAX]; WIN32_FIND_DATA w32_fd; HANDLE h = FindFirstFile(name, &w32_fd); - MEMORY_BASIC_INFORMATION m; if (h == INVALID_HANDLE_VALUE) strcpy (buf, name); @@ -629,12 +675,31 @@ win32_make_so (const char *name, DWORD load_addr) SetCurrentDirectory (cwd); } } - if (strcasecmp (buf, "ntdll.dll") == 0) { GetSystemDirectory (buf, sizeof (buf)); strcat (buf, "\\ntdll.dll"); } +#else + cygwin_buf_t buf[__PMAX]; + + buf[0] = 0; + if (access (name, F_OK) != 0) + { + if (strcasecmp (name, "ntdll.dll") == 0) +#ifdef __USEWIDE + { + GetSystemDirectoryW (buf, sizeof (buf) / sizeof (wchar_t)); + wcscat (buf, L"\\ntdll.dll"); + } +#else + { + GetSystemDirectoryA (buf, sizeof (buf) / sizeof (wchar_t)); + strcat (buf, "\\ntdll.dll"); + } +#endif + } +#endif so = XZALLOC (struct so_list); so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info)); so->lm_info->load_addr = load_addr; @@ -642,7 +707,20 @@ win32_make_so (const char *name, DWORD load_addr) #ifndef __CYGWIN__ strcpy (so->so_name, buf); #else - cygwin_conv_to_posix_path (buf, so->so_name); + if (buf[0]) + cygwin_conv_path (CCP_WIN_W_TO_POSIX, buf, so->so_name, + SO_NAME_MAX_PATH_SIZE); + else + { + char *rname = realpath (name, NULL); + if (rname && strlen (rname) < SO_NAME_MAX_PATH_SIZE) + { + strcpy (so->so_name, rname); + free (rname); + } + else + error (_("dll path too long")); + } /* Record cygwin1.dll .text start/end. */ p = strchr (so->so_name, '\0') - (sizeof ("/cygwin1.dll") - 1); if (p >= so->so_name && strcasecmp (p, "/cygwin1.dll") == 0) @@ -668,7 +746,7 @@ win32_make_so (const char *name, DWORD load_addr) /* The symbols in a dll are offset by 0x1000, which is the the offset from 0 of the first byte in an image - because of the file header and the section alignment. */ - cygwin_load_start = load_addr + 0x1000; + cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *) load_addr + 0x1000); cygwin_load_end = cygwin_load_start + bfd_section_size (abfd, text); bfd_close (abfd); @@ -681,12 +759,16 @@ win32_make_so (const char *name, DWORD load_addr) static char * get_image_name (HANDLE h, void *address, int unicode) { - static char buf[(2 * MAX_PATH) + 1]; +#ifdef __CYGWIN__ + static char buf[__PMAX]; +#else + static char buf[(2 * __PMAX) + 1]; +#endif DWORD size = unicode ? sizeof (WCHAR) : sizeof (char); char *address_ptr; int len = 0; char b[2]; - DWORD done; + SIZE_T done; /* Attempt to read the name of the dll that was detected. This is documented to work only when actively debugging @@ -712,8 +794,12 @@ get_image_name (HANDLE h, void *address, int unicode) WCHAR *unicode_address = (WCHAR *) alloca (len * sizeof (WCHAR)); ReadProcessMemory (h, address_ptr, unicode_address, len * sizeof (WCHAR), &done); - - WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, len, 0, 0); +#ifdef __CYGWIN__ + wcstombs (buf, unicode_address, __PMAX); +#else + WideCharToMultiByte (CP_ACP, 0, unicode_address, len, buf, sizeof buf, + 0, 0); +#endif } return buf; @@ -725,12 +811,12 @@ static int handle_load_dll (void *dummy) { LOAD_DLL_DEBUG_INFO *event = ¤t_event.u.LoadDll; - char dll_buf[MAX_PATH + 1]; + char dll_buf[__PMAX]; char *dll_name = NULL; dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; - if (!get_module_name ((DWORD) event->lpBaseOfDll, dll_buf)) + if (!get_module_name (event->lpBaseOfDll, dll_buf)) dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; dll_name = dll_buf; @@ -741,17 +827,17 @@ handle_load_dll (void *dummy) if (!dll_name) return 1; - solib_end->next = win32_make_so (dll_name, (DWORD) event->lpBaseOfDll); + solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll); solib_end = solib_end->next; - DEBUG_EVENTS (("gdb: Loading dll \"%s\" at 0x%lx.\n", solib_end->so_name, - (DWORD) solib_end->lm_info->load_addr)); + DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name, + host_address_to_string (solib_end->lm_info->load_addr))); return 1; } static void -win32_free_so (struct so_list *so) +windows_free_so (struct so_list *so) { if (so->lm_info) xfree (so->lm_info); @@ -761,7 +847,7 @@ win32_free_so (struct so_list *so) static int handle_unload_dll (void *dummy) { - DWORD lpBaseOfDll = (DWORD) current_event.u.UnloadDll.lpBaseOfDll; + LPVOID lpBaseOfDll = current_event.u.UnloadDll.lpBaseOfDll; struct so_list *so; for (so = &solib_start; so->next != NULL; so = so->next) @@ -773,19 +859,27 @@ handle_unload_dll (void *dummy) solib_end = so; DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name)); - win32_free_so (sodel); + windows_free_so (sodel); solib_add (NULL, 0, NULL, auto_solib_add); return 1; } - error (_("Error: dll starting at 0x%lx not found."), (DWORD) lpBaseOfDll); + /* We did not find any DLL that was previously loaded at this address, + so register a complaint. We do not report an error, because we have + observed that this may be happening under some circumstances. For + instance, running 32bit applications on x64 Windows causes us to receive + 4 mysterious UNLOAD_DLL_DEBUG_EVENTs during the startup phase (these + events are apparently caused by the WOW layer, the interface between + 32bit and 64bit worlds). */ + complaint (&symfile_complaints, _("dll starting at %s not found."), + host_address_to_string (lpBaseOfDll)); return 0; } /* Clear list of loaded DLLs. */ static void -win32_clear_solib (void) +windows_clear_solib (void) { solib_start.next = NULL; solib_end = &solib_start; @@ -990,8 +1084,9 @@ info_w32_command (char *args, int from_tty) #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ - printf_unfiltered ("gdb: Target exception %s at 0x%08lx\n", x, \ - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress) + printf_unfiltered ("gdb: Target exception %s at %s\n", x, \ + host_address_to_string (\ + current_event.u.Exception.ExceptionRecord.ExceptionAddress)) static int handle_exception (struct target_waitstatus *ourstatus) @@ -1018,8 +1113,7 @@ handle_exception (struct target_waitstatus *ourstatus) and will be sent as a cygwin-specific-signal. So, ignore SEGVs if they show up within the text segment of the DLL itself. */ char *fn; - bfd_vma addr = (bfd_vma) (uintptr_t) current_event.u.Exception. - ExceptionRecord.ExceptionAddress; + CORE_ADDR addr = (CORE_ADDR) (uintptr_t) current_event.u.Exception.ExceptionRecord.ExceptionAddress; if ((!cygwin_exceptions && (addr >= cygwin_load_start && addr < cygwin_load_end)) || (find_pc_partial_function (addr, &fn, NULL, NULL) && strncmp (fn, "KERNEL32!IsBad", strlen ("KERNEL32!IsBad")) == 0)) @@ -1103,9 +1197,10 @@ handle_exception (struct target_waitstatus *ourstatus) /* Treat unhandled first chance exceptions specially. */ if (current_event.u.Exception.dwFirstChance) return -1; - printf_unfiltered ("gdb: unknown target exception 0x%08lx at 0x%08lx\n", - current_event.u.Exception.ExceptionRecord.ExceptionCode, - (DWORD) current_event.u.Exception.ExceptionRecord.ExceptionAddress); + printf_unfiltered ("gdb: unknown target exception 0x%08lx at %s\n", + current_event.u.Exception.ExceptionRecord.ExceptionCode, + host_address_to_string ( + current_event.u.Exception.ExceptionRecord.ExceptionAddress)); ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; break; } @@ -1117,13 +1212,13 @@ handle_exception (struct target_waitstatus *ourstatus) /* Resume all artificially suspended threads if we are continuing execution */ static BOOL -win32_continue (DWORD continue_status, int id) +windows_continue (DWORD continue_status, int id) { int i; thread_info *th; BOOL res; - DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, %s);\n", + DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%lx, %s);\n", current_event.dwProcessId, current_event.dwThreadId, continue_status == DBG_CONTINUE ? "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); @@ -1176,18 +1271,26 @@ fake_create_process (void) /* We can not debug anything in that case. */ } main_thread_id = current_event.dwThreadId; - current_thread = win32_add_thread (main_thread_id, - current_event.u.CreateThread.hThread); + current_thread = windows_add_thread (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateThread.hThread); return main_thread_id; } static void -win32_resume (ptid_t ptid, int step, enum target_signal sig) +windows_resume (struct target_ops *ops, + ptid_t ptid, int step, enum target_signal sig) { thread_info *th; DWORD continue_status = DBG_CONTINUE; - int pid = PIDGET (ptid); + /* A specific PTID means `step only this thread id'. */ + int resume_all = ptid_equal (ptid, minus_one_ptid); + + /* If we're continuing all threads, it's the current inferior that + should be handled specially. */ + if (resume_all) + ptid = inferior_ptid; if (sig != TARGET_SIGNAL_0) { @@ -1225,18 +1328,20 @@ win32_resume (ptid_t ptid, int step, enum target_signal sig) last_sig = TARGET_SIGNAL_0; - DEBUG_EXEC (("gdb: win32_resume (pid=%d, step=%d, sig=%d);\n", - pid, step, sig)); + DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=%ld, step=%d, sig=%d);\n", + ptid_get_pid (ptid), ptid_get_tid (ptid), step, sig)); /* Get context for currently selected thread */ - th = thread_rec (PIDGET (inferior_ptid), FALSE); + th = thread_rec (ptid_get_tid (inferior_ptid), FALSE); if (th) { if (step) { /* Single step by setting t bit */ - win32_fetch_inferior_registers (get_current_regcache (), - gdbarch_ps_regnum (current_gdbarch)); + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + windows_fetch_inferior_registers (ops, regcache, + gdbarch_ps_regnum (gdbarch)); th->context.EFlags |= FLAG_TRACE_BIT; } @@ -1259,21 +1364,49 @@ win32_resume (ptid_t ptid, int step, enum target_signal sig) /* Allow continuing with the same signal that interrupted us. Otherwise complain. */ - win32_continue (continue_status, pid); + if (resume_all) + windows_continue (continue_status, -1); + else + windows_continue (continue_status, ptid_get_tid (ptid)); +} + +/* Ctrl-C handler used when the inferior is not run in the same console. The + handler is in charge of interrupting the inferior using DebugBreakProcess. + Note that this function is not available prior to Windows XP. In this case + we emit a warning. */ +BOOL WINAPI +ctrl_c_handler (DWORD event_type) +{ + const int attach_flag = current_inferior ()->attach_flag; + + /* Only handle Ctrl-C and Ctrl-Break events. Ignore others. */ + if (event_type != CTRL_C_EVENT && event_type != CTRL_BREAK_EVENT) + return FALSE; + + /* If the inferior and the debugger share the same console, do nothing as + the inferior has also received the Ctrl-C event. */ + if (!new_console && !attach_flag) + return TRUE; + + if (!DebugBreakProcess (current_process_handle)) + warning (_("\ +Could not interrupt program. Press Ctrl-c in the program console.")); + + /* Return true to tell that Ctrl-C has been handled. */ + return TRUE; } /* Get the next event from the child. Return 1 if the event requires - handling by WFI (or whatever). - */ + handling by WFI (or whatever). */ static int -get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) +get_windows_debug_event (struct target_ops *ops, + int pid, struct target_waitstatus *ourstatus) { BOOL debug_event; DWORD continue_status, event_code; thread_info *th; static thread_info dummy_thread_info; int retval = 0; - ptid_t ptid = {-1}; last_sig = TARGET_SIGNAL_0; @@ -1297,37 +1430,42 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) "CREATE_THREAD_DEBUG_EVENT")); if (saw_create != 1) { - if (!saw_create && attach_flag) + struct inferior *inf; + inf = find_inferior_pid (current_event.dwProcessId); + if (!saw_create && inf->attach_flag) { /* Kludge around a Windows bug where first event is a create thread event. Caused when attached process does not have a main thread. */ retval = fake_create_process (); - if (retval) - saw_create++; + if (retval) + saw_create++; } break; } /* Record the existence of this thread */ - th = win32_add_thread (current_event.dwThreadId, - current_event.u.CreateThread.hThread); retval = current_event.dwThreadId; + th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateThread.hThread); break; case EXIT_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_THREAD_DEBUG_EVENT")); + if (current_event.dwThreadId != main_thread_id) { - win32_delete_thread (current_event.dwThreadId); + windows_delete_thread (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId)); th = &dummy_thread_info; } break; case CREATE_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_PROCESS_DEBUG_EVENT")); @@ -1337,28 +1475,38 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) current_process_handle = current_event.u.CreateProcessInfo.hProcess; if (main_thread_id) - win32_delete_thread (main_thread_id); + windows_delete_thread (ptid_build (current_event.dwProcessId, 0, + main_thread_id)); main_thread_id = current_event.dwThreadId; /* Add the main thread */ - th = win32_add_thread (main_thread_id, - current_event.u.CreateProcessInfo.hThread); + th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateProcessInfo.hThread); retval = current_event.dwThreadId; break; case EXIT_PROCESS_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_PROCESS_DEBUG_EVENT")); - if (saw_create != 1) - break; - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; - retval = main_thread_id; + if (!windows_initialization_done) + { + target_terminal_ours (); + target_mourn_inferior (); + error (_("During startup program exited with code 0x%x."), + (unsigned int) current_event.u.ExitProcess.dwExitCode); + } + else if (saw_create == 1) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; + retval = main_thread_id; + } break; case LOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "LOAD_DLL_DEBUG_EVENT")); @@ -1372,7 +1520,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) break; case UNLOAD_DLL_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "UNLOAD_DLL_DEBUG_EVENT")); @@ -1385,7 +1533,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) break; case EXCEPTION_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXCEPTION_DEBUG_EVENT")); @@ -1407,7 +1555,7 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) break; case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */ - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "OUTPUT_DEBUG_STRING_EVENT")); @@ -1430,13 +1578,14 @@ get_win32_debug_event (int pid, struct target_waitstatus *ourstatus) if (!retval || saw_create != 1) { if (continue_status == -1) - win32_resume (ptid, 0, 1); + windows_resume (ops, minus_one_ptid, 0, 1); else - CHECK (win32_continue (continue_status, -1)); + CHECK (windows_continue (continue_status, -1)); } else { - inferior_ptid = pid_to_ptid (retval); + inferior_ptid = ptid_build (current_event.dwProcessId, 0, + retval); current_thread = th ?: thread_rec (current_event.dwThreadId, TRUE); } @@ -1444,11 +1593,12 @@ out: return retval; } -/* Wait for interesting events to occur in the target process. */ +/* Wait for interesting events to occur in the target process. */ static ptid_t -win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus) +windows_wait (struct target_ops *ops, + ptid_t ptid, struct target_waitstatus *ourstatus, int options) { - int pid = PIDGET (ptid); + int pid = -1; target_terminal_ours (); @@ -1461,26 +1611,39 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus) while (1) { int retval; - - /* Ignore CTRL+C signals while waiting for a debug event. - FIXME: brobecker/2008-05-20: When the user presses CTRL+C while - the inferior is running, both the inferior and GDB receive the - associated signal. If the inferior receives the signal first - and the delay until GDB receives that signal is sufficiently long, - GDB can sometimes receive the SIGINT after we have unblocked - the CTRL+C handler. This would lead to the debugger to stop - prematurely while handling the new-thread event that comes - with the handling of the SIGINT inside the inferior, and then - stop again immediately when the user tries to resume the execution - in the inferior. This is a classic race, and it would be nice - to find a better solution to that problem. But in the meantime, - the current approach already greatly mitigate this issue. */ - SetConsoleCtrlHandler (NULL, TRUE); - retval = get_win32_debug_event (pid, ourstatus); - SetConsoleCtrlHandler (NULL, FALSE); + + /* If the user presses Ctrl-c while the debugger is waiting + for an event, he expects the debugger to interrupt his program + and to get the prompt back. There are two possible situations: + + - The debugger and the program do not share the console, in + which case the Ctrl-c event only reached the debugger. + In that case, the ctrl_c handler will take care of interrupting + the inferior. Note that this case is working starting with + Windows XP. For Windows 2000, Ctrl-C should be pressed in the + inferior console. + + - The debugger and the program share the same console, in which + case both debugger and inferior will receive the Ctrl-c event. + In that case the ctrl_c handler will ignore the event, as the + Ctrl-c event generated inside the inferior will trigger the + expected debug event. + + FIXME: brobecker/2008-05-20: If the inferior receives the + signal first and the delay until GDB receives that signal + is sufficiently long, GDB can sometimes receive the SIGINT + after we have unblocked the CTRL+C handler. This would + lead to the debugger stopping prematurely while handling + the new-thread event that comes with the handling of the SIGINT + inside the inferior, and then stop again immediately when + the user tries to resume the execution in the inferior. + This is a classic race that we should try to fix one day. */ + SetConsoleCtrlHandler (&ctrl_c_handler, TRUE); + retval = get_windows_debug_event (ops, pid, ourstatus); + SetConsoleCtrlHandler (&ctrl_c_handler, FALSE); if (retval) - return pid_to_ptid (retval); + return ptid_build (current_event.dwProcessId, 0, retval); else { int detach = 0; @@ -1489,16 +1652,18 @@ win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus) detach = deprecated_ui_loop_hook (0); if (detach) - win32_kill_inferior (); + windows_kill_inferior (ops); } } } static void -do_initial_win32_stuff (DWORD pid) +do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) { extern int stop_after_trap; int i; + struct inferior *inf; + struct thread_info *tp; last_sig = TARGET_SIGNAL_0; event_count = 0; @@ -1513,60 +1678,44 @@ do_initial_win32_stuff (DWORD pid) #endif current_event.dwProcessId = pid; memset (¤t_event, 0, sizeof (current_event)); - push_target (&win32_ops); + push_target (ops); disable_breakpoints_in_shlibs (); - win32_clear_solib (); + windows_clear_solib (); clear_proceed_status (); init_wait_for_inferior (); + inf = current_inferior (); + inferior_appeared (inf, pid); + inf->attach_flag = attaching; + + /* Make the new process the current inferior, so terminal handling + can rely on it. When attaching, we don't know about any thread + id here, but that's OK --- nothing should be referencing the + current thread until we report an event out of windows_wait. */ + inferior_ptid = pid_to_ptid (pid); + terminal_init_inferior_with_pgrp (pid); target_terminal_inferior (); - stop_soon = STOP_QUIETLY; + windows_initialization_done = 0; + inf->stop_soon = STOP_QUIETLY; while (1) { stop_after_trap = 1; wait_for_inferior (0); - if (stop_signal != TARGET_SIGNAL_TRAP) - resume (0, stop_signal); + tp = inferior_thread (); + if (tp->stop_signal != TARGET_SIGNAL_TRAP) + resume (0, tp->stop_signal); else break; } - stop_soon = NO_STOP_QUIETLY; + windows_initialization_done = 1; + inf->stop_soon = NO_STOP_QUIETLY; stop_after_trap = 0; return; } -/* Since Windows XP, detaching from a process is supported by Windows. - The following code tries loading the appropriate functions dynamically. - If loading these functions succeeds use them to actually detach from - the inferior process, otherwise behave as usual, pretending that - detach has worked. */ -static BOOL WINAPI (*DebugSetProcessKillOnExit)(BOOL); -static BOOL WINAPI (*DebugActiveProcessStop)(DWORD); - -static int -has_detach_ability (void) -{ - static HMODULE kernel32 = NULL; - - if (!kernel32) - kernel32 = LoadLibrary ("kernel32.dll"); - if (kernel32) - { - if (!DebugSetProcessKillOnExit) - DebugSetProcessKillOnExit = GetProcAddress (kernel32, - "DebugSetProcessKillOnExit"); - if (!DebugActiveProcessStop) - DebugActiveProcessStop = GetProcAddress (kernel32, - "DebugActiveProcessStop"); - if (DebugSetProcessKillOnExit && DebugActiveProcessStop) - return 1; - } - return 0; -} - /* Try to set or remove a user privilege to the current process. Return -1 if that fails, the previous setting of that privilege otherwise. @@ -1576,46 +1725,18 @@ has_detach_ability (void) static int set_process_privilege (const char *privilege, BOOL enable) { - static HMODULE advapi32 = NULL; - static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE); - static BOOL WINAPI (*LookupPrivilegeValue)(LPCSTR, LPCSTR, PLUID); - static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, - DWORD, PTOKEN_PRIVILEGES, PDWORD); - HANDLE token_hdl = NULL; LUID restore_priv; TOKEN_PRIVILEGES new_priv, orig_priv; int ret = -1; DWORD size; - if (GetVersion () >= 0x80000000) /* No security availbale on 9x/Me */ - return 0; - - if (!advapi32) - { - if (!(advapi32 = LoadLibrary ("advapi32.dll"))) - goto out; - if (!OpenProcessToken) - OpenProcessToken = GetProcAddress (advapi32, "OpenProcessToken"); - if (!LookupPrivilegeValue) - LookupPrivilegeValue = GetProcAddress (advapi32, - "LookupPrivilegeValueA"); - if (!AdjustTokenPrivileges) - AdjustTokenPrivileges = GetProcAddress (advapi32, - "AdjustTokenPrivileges"); - if (!OpenProcessToken || !LookupPrivilegeValue || !AdjustTokenPrivileges) - { - advapi32 = NULL; - goto out; - } - } - if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &token_hdl)) goto out; - if (!LookupPrivilegeValue (NULL, privilege, &restore_priv)) + if (!LookupPrivilegeValueA (NULL, privilege, &restore_priv)) goto out; new_priv.PrivilegeCount = 1; @@ -1628,7 +1749,7 @@ set_process_privilege (const char *privilege, BOOL enable) #if 0 /* Disabled, otherwise every `attach' in an unprivileged user session would raise the "Failed to get SE_DEBUG_NAME privilege" warning in - win32_attach(). */ + windows_attach(). */ /* AdjustTokenPrivileges returns TRUE even if the privilege could not be enabled. GetLastError () returns an correct error code, though. */ if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED) @@ -1646,13 +1767,12 @@ out: /* Attach to process PID, then initialize for debugging it. */ static void -win32_attach (char *args, int from_tty) +windows_attach (struct target_ops *ops, char *args, int from_tty) { BOOL ok; DWORD pid; - if (!args) - error_no_arg (_("process-id to attach")); + pid = parse_pid_to_attach (args); if (set_process_privilege (SE_DEBUG_NAME, TRUE) < 0) { @@ -1660,9 +1780,7 @@ win32_attach (char *args, int from_tty) printf_unfiltered ("This can cause attach to fail on Windows NT/2K/XP\n"); } - pid = strtoul (args, 0, 0); /* Windows pid */ - - win32_init_thread_list (); + windows_init_thread_list (); ok = DebugActiveProcess (pid); saw_create = 0; @@ -1680,10 +1798,7 @@ win32_attach (char *args, int from_tty) if (!ok) error (_("Can't attach to process.")); - if (has_detach_ability ()) - DebugSetProcessKillOnExit (FALSE); - - attach_flag = 1; + DebugSetProcessKillOnExit (FALSE); if (from_tty) { @@ -1699,28 +1814,26 @@ win32_attach (char *args, int from_tty) gdb_flush (gdb_stdout); } - do_initial_win32_stuff (pid); + do_initial_windows_stuff (ops, pid, 1); target_terminal_ours (); } static void -win32_detach (char *args, int from_tty) +windows_detach (struct target_ops *ops, char *args, int from_tty) { int detached = 1; - if (has_detach_ability ()) - { - ptid_t ptid = {-1}; - win32_resume (ptid, 0, TARGET_SIGNAL_0); + ptid_t ptid = {-1}; + windows_resume (ops, ptid, 0, TARGET_SIGNAL_0); - if (!DebugActiveProcessStop (current_event.dwProcessId)) - { - error (_("Can't detach process %lu (error %lu)"), - current_event.dwProcessId, GetLastError ()); - detached = 0; - } - DebugSetProcessKillOnExit (FALSE); + if (!DebugActiveProcessStop (current_event.dwProcessId)) + { + error (_("Can't detach process %lu (error %lu)"), + current_event.dwProcessId, GetLastError ()); + detached = 0; } + DebugSetProcessKillOnExit (FALSE); + if (detached && from_tty) { char *exec_file = get_exec_file (0); @@ -1730,20 +1843,22 @@ win32_detach (char *args, int from_tty) current_event.dwProcessId); gdb_flush (gdb_stdout); } + inferior_ptid = null_ptid; - unpush_target (&win32_ops); + detach_inferior (current_event.dwProcessId); + + unpush_target (ops); } static char * -win32_pid_to_exec_file (int pid) +windows_pid_to_exec_file (int pid) { - static char path[MAX_PATH + 1]; - + static char path[__PMAX]; #ifdef __CYGWIN__ /* Try to find exe name as symlink target of /proc//exe */ int nchars; char procexe[sizeof ("/proc/4294967295/exe")]; - sprintf (procexe, "/proc/%lu/exe", current_event.dwProcessId); + sprintf (procexe, "/proc/%u/exe", pid); nchars = readlink (procexe, path, sizeof(path)); if (nchars > 0 && nchars < sizeof (path)) { @@ -1763,38 +1878,51 @@ win32_pid_to_exec_file (int pid) /* Print status information about what we're accessing. */ static void -win32_files_info (struct target_ops *ignore) +windows_files_info (struct target_ops *ignore) { + struct inferior *inf = current_inferior (); + printf_unfiltered ("\tUsing the running image of %s %s.\n", - attach_flag ? "attached" : "child", target_pid_to_str (inferior_ptid)); + inf->attach_flag ? "attached" : "child", + target_pid_to_str (inferior_ptid)); } static void -win32_open (char *arg, int from_tty) +windows_open (char *arg, int from_tty) { error (_("Use the \"run\" command to start a Unix child process.")); } -/* Start an inferior win32 child process and sets inferior_ptid to its pid. +/* Start an inferior windows child process and sets inferior_ptid to its pid. EXEC_FILE is the file to run. ALLARGS is a string containing the arguments to the program. ENV is the environment vector to pass. Errors reported with error(). */ static void -win32_create_inferior (char *exec_file, char *allargs, char **in_env, - int from_tty) +windows_create_inferior (struct target_ops *ops, char *exec_file, + char *allargs, char **in_env, int from_tty) { STARTUPINFO si; - PROCESS_INFORMATION pi; - BOOL ret; - DWORD flags; - char *args; - char real_path[MAXPATHLEN]; - char *toexec; - char shell[MAX_PATH + 1]; /* Path to shell */ +#ifdef __CYGWIN__ + cygwin_buf_t real_path[__PMAX]; + cygwin_buf_t shell[__PMAX]; /* Path to shell */ const char *sh; + cygwin_buf_t *toexec; + cygwin_buf_t *cygallargs; + cygwin_buf_t *args; + size_t len; int tty; int ostdin, ostdout, ostderr; +#else + char real_path[__PMAX]; + char shell[__PMAX]; /* Path to shell */ + char *toexec; + char *args; + HANDLE tty; +#endif + PROCESS_INFORMATION pi; + BOOL ret; + DWORD flags = 0; const char *inferior_io_terminal = get_inferior_io_terminal (); if (!exec_file) @@ -1803,46 +1931,64 @@ win32_create_inferior (char *exec_file, char *allargs, char **in_env, memset (&si, 0, sizeof (si)); si.cb = sizeof (si); + if (new_group) + flags |= CREATE_NEW_PROCESS_GROUP; + + if (new_console) + flags |= CREATE_NEW_CONSOLE; + #ifdef __CYGWIN__ if (!useshell) { - flags = DEBUG_ONLY_THIS_PROCESS; - cygwin_conv_to_win32_path (exec_file, real_path); + flags |= DEBUG_ONLY_THIS_PROCESS; + if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, exec_file, real_path, + __PMAX * sizeof (cygwin_buf_t)) < 0) + error (_("Error starting executable: %d"), errno); toexec = real_path; +#ifdef __USEWIDE + len = mbstowcs (NULL, allargs, 0) + 1; + if (len == (size_t) -1) + error (_("Error starting executable: %d"), errno); + cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t)); + mbstowcs (cygallargs, allargs, len); +#else + cygallargs = allargs; +#endif } else { - char *newallargs; sh = getenv ("SHELL"); if (!sh) sh = "/bin/sh"; - cygwin_conv_to_win32_path (sh, shell); - newallargs = alloca (sizeof (" -c 'exec '") + strlen (exec_file) - + strlen (allargs) + 2); - sprintf (newallargs, " -c 'exec %s %s'", exec_file, allargs); - allargs = newallargs; - toexec = shell; - flags = DEBUG_PROCESS; - } + if (cygwin_conv_path (CCP_POSIX_TO_WIN_W, sh, shell, __PMAX) < 0) + error (_("Error starting executable via shell: %d"), errno); +#ifdef __USEWIDE + len = sizeof (L" -c 'exec '") + mbstowcs (NULL, exec_file, 0) + + mbstowcs (NULL, allargs, 0) + 2; + cygallargs = (wchar_t *) alloca (len * sizeof (wchar_t)); + swprintf (cygallargs, len, L" -c 'exec %s %s'", exec_file, allargs); #else - toexec = exec_file; - flags = DEBUG_ONLY_THIS_PROCESS; + cygallargs = (char *) alloca (sizeof (" -c 'exec '") + strlen (exec_file) + + strlen (allargs) + 2); + sprintf (cygallargs, " -c 'exec %s %s'", exec_file, allargs); #endif + toexec = shell; + flags |= DEBUG_PROCESS; + } - if (new_group) - flags |= CREATE_NEW_PROCESS_GROUP; - - if (new_console) - flags |= CREATE_NEW_CONSOLE; - - attach_flag = 0; - - args = alloca (strlen (toexec) + strlen (allargs) + 2); +#ifdef __USEWIDE + args = (cygwin_buf_t *) alloca ((wcslen (toexec) + wcslen (cygallargs) + 2) + * sizeof (wchar_t)); + wcscpy (args, toexec); + wcscat (args, L" "); + wcscat (args, cygallargs); +#else + args = (cygwin_buf_t *) alloca (strlen (toexec) + strlen (cygallargs) + 2); strcpy (args, toexec); strcat (args, " "); - strcat (args, allargs); + strcat (args, cygallargs); +#endif -#ifdef __CYGWIN__ /* Prepare the environment vars for CreateProcess. */ cygwin_internal (CW_SYNC_WINENV); @@ -1866,9 +2012,8 @@ win32_create_inferior (char *exec_file, char *allargs, char **in_env, dup2 (tty, 2); } } -#endif - win32_init_thread_list (); + windows_init_thread_list (); ret = CreateProcess (0, args, /* command line */ NULL, /* Security */ @@ -1879,8 +2024,6 @@ win32_create_inferior (char *exec_file, char *allargs, char **in_env, NULL, /* current directory */ &si, &pi); - -#ifdef __CYGWIN__ if (tty >= 0) { close (tty); @@ -1891,6 +2034,50 @@ win32_create_inferior (char *exec_file, char *allargs, char **in_env, close (ostdout); close (ostderr); } +#else + toexec = exec_file; + args = alloca (strlen (toexec) + strlen (allargs) + 2); + strcpy (args, toexec); + strcat (args, " "); + strcat (args, allargs); + + flags |= DEBUG_ONLY_THIS_PROCESS; + + if (!inferior_io_terminal) + tty = INVALID_HANDLE_VALUE; + else + { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = TRUE; + tty = CreateFileA (inferior_io_terminal, GENERIC_READ | GENERIC_WRITE, + 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (tty == INVALID_HANDLE_VALUE) + warning (_("Warning: Failed to open TTY %s, error %#x."), + inferior_io_terminal, (unsigned) GetLastError ()); + else + { + si.hStdInput = tty; + si.hStdOutput = tty; + si.hStdError = tty; + si.dwFlags |= STARTF_USESTDHANDLES; + } + } + + windows_init_thread_list (); + ret = CreateProcessA (0, + args, /* command line */ + NULL, /* Security */ + NULL, /* thread */ + TRUE, /* inherit handles */ + flags, /* start flags */ + NULL, /* environment */ + NULL, /* current directory */ + &si, + &pi); + if (tty != INVALID_HANDLE_VALUE) + CloseHandle (tty); #endif if (!ret) @@ -1905,22 +2092,22 @@ win32_create_inferior (char *exec_file, char *allargs, char **in_env, else saw_create = 0; - do_initial_win32_stuff (pi.dwProcessId); + do_initial_windows_stuff (ops, pi.dwProcessId, 0); - /* win32_continue (DBG_CONTINUE, -1); */ + /* windows_continue (DBG_CONTINUE, -1); */ } static void -win32_mourn_inferior (void) +windows_mourn_inferior (struct target_ops *ops) { - (void) win32_continue (DBG_CONTINUE, -1); + (void) windows_continue (DBG_CONTINUE, -1); i386_cleanup_dregs(); if (open_process_used) { CHECK (CloseHandle (current_process_handle)); open_process_used = 0; } - unpush_target (&win32_ops); + unpush_target (ops); generic_mourn_inferior (); } @@ -1928,7 +2115,7 @@ win32_mourn_inferior (void) ^C on the controlling terminal. */ static void -win32_stop (ptid_t ptid) +windows_stop (ptid_t ptid) { DEBUG_EVENTS (("gdb: GenerateConsoleCtrlEvent (CTRLC_EVENT, 0)\n")); CHECK (GenerateConsoleCtrlEvent (CTRL_C_EVENT, current_event.dwProcessId)); @@ -1936,27 +2123,27 @@ win32_stop (ptid_t ptid) } static int -win32_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, +windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, int write, struct mem_attrib *mem, struct target_ops *target) { - DWORD done = 0; + SIZE_T done = 0; if (write) { DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n", len, (DWORD) (uintptr_t) memaddr)); - if (!WriteProcessMemory (current_process_handle, + if (!WriteProcessMemory (current_process_handle, (LPVOID) (uintptr_t) memaddr, our, len, &done)) done = 0; - FlushInstructionCache (current_process_handle, + FlushInstructionCache (current_process_handle, (LPCVOID) (uintptr_t) memaddr, len); } else { DEBUG_MEM (("gdb: read target memory, %d bytes at 0x%08lx\n", len, (DWORD) (uintptr_t) memaddr)); - if (!ReadProcessMemory (current_process_handle, + if (!ReadProcessMemory (current_process_handle, (LPCVOID) (uintptr_t) memaddr, our, len, &done)) done = 0; @@ -1965,13 +2152,13 @@ win32_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, } static void -win32_kill_inferior (void) +windows_kill_inferior (struct target_ops *ops) { CHECK (TerminateProcess (current_process_handle, 0)); for (;;) { - if (!win32_continue (DBG_CONTINUE, -1)) + if (!windows_continue (DBG_CONTINUE, -1)) break; if (!WaitForDebugEvent (¤t_event, INFINITE)) break; @@ -1979,44 +2166,46 @@ win32_kill_inferior (void) break; } - target_mourn_inferior (); /* or just win32_mourn_inferior? */ + target_mourn_inferior (); /* or just windows_mourn_inferior? */ } static void -win32_prepare_to_store (struct regcache *regcache) +windows_prepare_to_store (struct regcache *regcache) { /* Do nothing, since we can store individual regs */ } static int -win32_can_run (void) +windows_can_run (void) { return 1; } static void -win32_close (int x) +windows_close (int x) { - DEBUG_EVENTS (("gdb: win32_close, inferior_ptid=%d\n", + DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n", PIDGET (inferior_ptid))); } /* Convert pid to printable format. */ static char * -win32_pid_to_str (ptid_t ptid) +windows_pid_to_str (struct target_ops *ops, ptid_t ptid) { static char buf[80]; - int pid = PIDGET (ptid); - if ((DWORD) pid == current_event.dwProcessId) - sprintf (buf, "process %d", pid); - else - sprintf (buf, "Thread %ld.0x%x", current_event.dwProcessId, pid); - return buf; + if (ptid_get_tid (ptid) != 0) + { + snprintf (buf, sizeof (buf), "Thread %d.0x%lx", + ptid_get_pid (ptid), ptid_get_tid (ptid)); + return buf; + } + + return normal_pid_to_str (ptid); } static LONGEST -win32_xfer_shared_libraries (struct target_ops *ops, +windows_xfer_shared_libraries (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) @@ -2032,7 +2221,8 @@ win32_xfer_shared_libraries (struct target_ops *ops, obstack_init (&obstack); obstack_grow_str (&obstack, "\n"); for (so = solib_start.next; so; so = so->next) - win32_xfer_shared_library (so->so_name, so->lm_info->load_addr, &obstack); + windows_xfer_shared_library (so->so_name, (CORE_ADDR) (uintptr_t) so->lm_info->load_addr, + target_gdbarch, &obstack); obstack_grow_str0 (&obstack, "\n"); buf = obstack_finish (&obstack); @@ -2049,7 +2239,7 @@ win32_xfer_shared_libraries (struct target_ops *ops, } static LONGEST -win32_xfer_partial (struct target_ops *ops, enum target_object object, +windows_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { @@ -2065,7 +2255,7 @@ win32_xfer_partial (struct target_ops *ops, enum target_object object, return -1; case TARGET_OBJECT_LIBRARIES: - return win32_xfer_shared_libraries (ops, object, annex, readbuf, + return windows_xfer_shared_libraries (ops, object, annex, readbuf, writebuf, offset, len); default: @@ -2076,62 +2266,85 @@ win32_xfer_partial (struct target_ops *ops, enum target_object object, } } +static ptid_t +windows_get_ada_task_ptid (long lwp, long thread) +{ + return ptid_build (ptid_get_pid (inferior_ptid), 0, lwp); +} + static void -init_win32_ops (void) -{ - win32_ops.to_shortname = "child"; - win32_ops.to_longname = "Win32 child process"; - win32_ops.to_doc = "Win32 child process (started by the \"run\" command)."; - win32_ops.to_open = win32_open; - win32_ops.to_close = win32_close; - win32_ops.to_attach = win32_attach; - win32_ops.to_attach_no_wait = 1; - win32_ops.to_detach = win32_detach; - win32_ops.to_resume = win32_resume; - win32_ops.to_wait = win32_wait; - win32_ops.to_fetch_registers = win32_fetch_inferior_registers; - win32_ops.to_store_registers = win32_store_inferior_registers; - win32_ops.to_prepare_to_store = win32_prepare_to_store; - win32_ops.deprecated_xfer_memory = win32_xfer_memory; - win32_ops.to_xfer_partial = win32_xfer_partial; - win32_ops.to_files_info = win32_files_info; - win32_ops.to_insert_breakpoint = memory_insert_breakpoint; - win32_ops.to_remove_breakpoint = memory_remove_breakpoint; - win32_ops.to_terminal_init = terminal_init_inferior; - win32_ops.to_terminal_inferior = terminal_inferior; - win32_ops.to_terminal_ours_for_output = terminal_ours_for_output; - win32_ops.to_terminal_ours = terminal_ours; - win32_ops.to_terminal_save_ours = terminal_save_ours; - win32_ops.to_terminal_info = child_terminal_info; - win32_ops.to_kill = win32_kill_inferior; - win32_ops.to_create_inferior = win32_create_inferior; - win32_ops.to_mourn_inferior = win32_mourn_inferior; - win32_ops.to_can_run = win32_can_run; - win32_ops.to_thread_alive = win32_win32_thread_alive; - win32_ops.to_pid_to_str = win32_pid_to_str; - win32_ops.to_stop = win32_stop; - win32_ops.to_stratum = process_stratum; - win32_ops.to_has_all_memory = 1; - win32_ops.to_has_memory = 1; - win32_ops.to_has_stack = 1; - win32_ops.to_has_registers = 1; - win32_ops.to_has_execution = 1; - win32_ops.to_magic = OPS_MAGIC; - win32_ops.to_pid_to_exec_file = win32_pid_to_exec_file; +init_windows_ops (void) +{ + windows_ops.to_shortname = "child"; + windows_ops.to_longname = "Win32 child process"; + windows_ops.to_doc = "Win32 child process (started by the \"run\" command)."; + windows_ops.to_open = windows_open; + windows_ops.to_close = windows_close; + windows_ops.to_attach = windows_attach; + windows_ops.to_attach_no_wait = 1; + windows_ops.to_detach = windows_detach; + windows_ops.to_resume = windows_resume; + windows_ops.to_wait = windows_wait; + windows_ops.to_fetch_registers = windows_fetch_inferior_registers; + windows_ops.to_store_registers = windows_store_inferior_registers; + windows_ops.to_prepare_to_store = windows_prepare_to_store; + windows_ops.deprecated_xfer_memory = windows_xfer_memory; + windows_ops.to_xfer_partial = windows_xfer_partial; + windows_ops.to_files_info = windows_files_info; + windows_ops.to_insert_breakpoint = memory_insert_breakpoint; + windows_ops.to_remove_breakpoint = memory_remove_breakpoint; + windows_ops.to_terminal_init = terminal_init_inferior; + windows_ops.to_terminal_inferior = terminal_inferior; + windows_ops.to_terminal_ours_for_output = terminal_ours_for_output; + windows_ops.to_terminal_ours = terminal_ours; + windows_ops.to_terminal_save_ours = terminal_save_ours; + windows_ops.to_terminal_info = child_terminal_info; + windows_ops.to_kill = windows_kill_inferior; + windows_ops.to_create_inferior = windows_create_inferior; + windows_ops.to_mourn_inferior = windows_mourn_inferior; + windows_ops.to_can_run = windows_can_run; + windows_ops.to_thread_alive = windows_thread_alive; + windows_ops.to_pid_to_str = windows_pid_to_str; + windows_ops.to_stop = windows_stop; + windows_ops.to_stratum = process_stratum; + windows_ops.to_has_all_memory = default_child_has_all_memory; + windows_ops.to_has_memory = default_child_has_memory; + windows_ops.to_has_stack = default_child_has_stack; + windows_ops.to_has_registers = default_child_has_registers; + windows_ops.to_has_execution = default_child_has_execution; + windows_ops.to_pid_to_exec_file = windows_pid_to_exec_file; + windows_ops.to_get_ada_task_ptid = windows_get_ada_task_ptid; + + i386_use_watchpoints (&windows_ops); + + i386_dr_low.set_control = cygwin_set_dr7; + i386_dr_low.set_addr = cygwin_set_dr; + i386_dr_low.reset_addr = NULL; + i386_dr_low.get_status = cygwin_get_dr6; + + /* i386_dr_low.debug_register_length field is set by + calling i386_set_debug_register_length function + in processor windows specific native file. */ + + windows_ops.to_magic = OPS_MAGIC; } static void -set_win32_aliases (char *argv0) +set_windows_aliases (char *argv0) { add_info_alias ("dll", "sharedlibrary", 1); } void -_initialize_win32_nat (void) +_initialize_windows_nat (void) { struct cmd_list_element *c; - init_win32_ops (); + init_windows_ops (); + +#ifdef __CYGWIN__ + cygwin_internal (CW_SET_DOS_FILE_WARNING, 0); +#endif c = add_com ("dll-symbols", class_files, dll_symbol_command, _("Load dll library symbols from FILE.")); @@ -2139,6 +2352,10 @@ _initialize_win32_nat (void) add_com_alias ("sharedlibrary", "dll-symbols", class_alias, 1); + add_com_alias ("add-shared-symbol-files", "dll-symbols", class_alias, 1); + + add_com_alias ("assf", "dll-symbols", class_alias, 1); + #ifdef __CYGWIN__ add_setshow_boolean_cmd ("shell", class_support, &useshell, _("\ Set use of shell to start subprocess."), _("\ @@ -2205,33 +2422,33 @@ Show whether to display kernel exceptions in child process."), NULL, add_cmd ("selector", class_info, display_selectors, _("Display selectors infos."), &info_w32_cmdlist); - add_target (&win32_ops); - deprecated_init_ui_hook = set_win32_aliases; + add_target (&windows_ops); + deprecated_init_ui_hook = set_windows_aliases; } /* Hardware watchpoint support, adapted from go32-nat.c code. */ /* Pass the address ADDR to the inferior in the I'th debug register. Here we just store the address in dr array, the registers will be - actually set up when win32_continue is called. */ -void + actually set up when windows_continue is called. */ +static void cygwin_set_dr (int i, CORE_ADDR addr) { if (i < 0 || i > 3) internal_error (__FILE__, __LINE__, _("Invalid register %d in cygwin_set_dr.\n"), i); - dr[i] = (unsigned) addr; + dr[i] = addr; debug_registers_changed = 1; debug_registers_used = 1; } /* Pass the value VAL to the inferior in the DR7 debug control register. Here we just store the address in D_REGS, the watchpoint - will be actually set up in win32_wait. */ -void -cygwin_set_dr7 (unsigned val) + will be actually set up in windows_wait. */ +static void +cygwin_set_dr7 (unsigned long val) { - dr[7] = val; + dr[7] = (CORE_ADDR) val; debug_registers_changed = 1; debug_registers_used = 1; } @@ -2239,21 +2456,24 @@ cygwin_set_dr7 (unsigned val) /* Get the value of the DR6 debug status register from the inferior. Here we just return the value stored in dr[6] by the last call to thread_rec for current_event.dwThreadId id. */ -unsigned +static unsigned long cygwin_get_dr6 (void) { - return dr[6]; + return (unsigned long) dr[6]; } -/* Determine if the thread referenced by "pid" is alive +/* Determine if the thread referenced by "ptid" is alive by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0 - it means that the pid has died. Otherwise it is assumed to be alive. */ + it means that the thread has died. Otherwise it is assumed to be alive. */ static int -win32_win32_thread_alive (ptid_t ptid) +windows_thread_alive (struct target_ops *ops, ptid_t ptid) { - int pid = PIDGET (ptid); + int tid; - return WaitForSingleObject (thread_rec (pid, FALSE)->h, 0) == WAIT_OBJECT_0 ? + gdb_assert (ptid_get_tid (ptid) != 0); + tid = ptid_get_tid (ptid); + + return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0 ? FALSE : TRUE; } @@ -2286,33 +2506,119 @@ _initialize_check_for_gdb_ini (void) } } +/* Define dummy functions which always return error for the rare cases where + these functions could not be found. */ +static BOOL WINAPI +bad_DebugActiveProcessStop (DWORD w) +{ + return FALSE; +} +static BOOL WINAPI +bad_DebugBreakProcess (HANDLE w) +{ + return FALSE; +} +static BOOL WINAPI +bad_DebugSetProcessKillOnExit (BOOL w) +{ + return FALSE; +} +static BOOL WINAPI +bad_EnumProcessModules (HANDLE w, HMODULE *x, DWORD y, LPDWORD z) +{ + return FALSE; +} + +#ifdef __USEWIDE +static DWORD WINAPI +bad_GetModuleFileNameExW (HANDLE w, HMODULE x, LPWSTR y, DWORD z) +{ + return 0; +} +#else +static DWORD WINAPI +bad_GetModuleFileNameExA (HANDLE w, HMODULE x, LPSTR y, DWORD z) +{ + return 0; +} +#endif + +static BOOL WINAPI +bad_GetModuleInformation (HANDLE w, HMODULE x, LPMODULEINFO y, DWORD z) +{ + return FALSE; +} + +static BOOL WINAPI +bad_OpenProcessToken (HANDLE w, DWORD x, PHANDLE y) +{ + return FALSE; +} + +/* Load any functions which may not be available in ancient versions + of Windows. */ void -_initialize_psapi (void) +_initialize_loadable (void) { + HMODULE hm = NULL; + + hm = LoadLibrary ("kernel32.dll"); + if (hm) + { + DebugActiveProcessStop = (void *) + GetProcAddress (hm, "DebugActiveProcessStop"); + DebugBreakProcess = (void *) + GetProcAddress (hm, "DebugBreakProcess"); + DebugSetProcessKillOnExit = (void *) + GetProcAddress (hm, "DebugSetProcessKillOnExit"); + } + + /* Set variables to dummy versions of these processes if the function + wasn't found in kernel32.dll. */ + if (!DebugBreakProcess) + DebugBreakProcess = bad_DebugBreakProcess; + if (!DebugActiveProcessStop || !DebugSetProcessKillOnExit) + { + DebugActiveProcessStop = bad_DebugActiveProcessStop; + DebugSetProcessKillOnExit = bad_DebugSetProcessKillOnExit; + } + /* Load optional functions used for retrieving filename information associated with the currently debugged process or its dlls. */ - if (!psapi_loaded) + hm = LoadLibrary ("psapi.dll"); + if (hm) { - HMODULE psapi_module_handle; - - psapi_loaded = -1; + EnumProcessModules = (void *) + GetProcAddress (hm, "EnumProcessModules"); + GetModuleInformation = (void *) + GetProcAddress (hm, "GetModuleInformation"); + GetModuleFileNameEx = (void *) + GetProcAddress (hm, GetModuleFileNameEx_name); + } - psapi_module_handle = LoadLibrary ("psapi.dll"); - if (psapi_module_handle) - { - psapi_EnumProcessModules = (void *) GetProcAddress (psapi_module_handle, "EnumProcessModules"); - psapi_GetModuleInformation = (void *) GetProcAddress (psapi_module_handle, "GetModuleInformation"); - psapi_GetModuleFileNameExA = (void *) GetProcAddress (psapi_module_handle, "GetModuleFileNameExA"); - - if (psapi_EnumProcessModules != NULL - && psapi_GetModuleInformation != NULL - && psapi_GetModuleFileNameExA != NULL) - psapi_loaded = 1; - } + if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx) + { + /* Set variables to dummy versions of these processes if the function + wasn't found in psapi.dll. */ + EnumProcessModules = bad_EnumProcessModules; + GetModuleInformation = bad_GetModuleInformation; + GetModuleFileNameEx = bad_GetModuleFileNameEx; + /* This will probably fail on Windows 9x/Me. Let the user know that we're + missing some functionality. */ + warning(_("cannot automatically find executable file or library to read symbols.\nUse \"file\" or \"dll\" command to load executable/libraries directly.")); } - /* This will probably fail on Windows 9x/Me. Let the user know that we're - missing some functionality. */ - if (psapi_loaded < 0) - warning(_("cannot automatically find executable file or library to read symbols. Use \"file\" or \"dll\" command to load executable/libraries directly.")); + hm = LoadLibrary ("advapi32.dll"); + if (hm) + { + OpenProcessToken = (void *) GetProcAddress (hm, "OpenProcessToken"); + LookupPrivilegeValueA = (void *) + GetProcAddress (hm, "LookupPrivilegeValueA"); + AdjustTokenPrivileges = (void *) + GetProcAddress (hm, "AdjustTokenPrivileges"); + /* Only need to set one of these since if OpenProcessToken fails nothing + else is needed. */ + if (!OpenProcessToken || !LookupPrivilegeValueA || !AdjustTokenPrivileges) + OpenProcessToken = bad_OpenProcessToken; + } }