X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=5bcb7b70cd58d0c1c2ec60a8de989bd690a61c50;hb=17fde6d091a9a661119d152e2304012de5fce056;hp=d8c2599b24475cda2923589796a0e8c027b109db;hpb=bb0613a5d5d424407828ac19d0908b191b489f14;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index d8c2599b24..5bcb7b70cd 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,7 +1,6 @@ /* 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, 2009 Free Software Foundation, Inc. + Copyright (C) 1995-2014 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -40,18 +39,20 @@ #include #include #ifdef __CYGWIN__ +#include #include +#include #endif -#include #include "buildsym.h" +#include "filenames.h" #include "symfile.h" #include "objfiles.h" +#include "gdb_bfd.h" #include "gdb_obstack.h" -#include "gdb_string.h" +#include #include "gdbthread.h" #include "gdbcmd.h" -#include #include #include "exec.h" #include "solist.h" @@ -64,16 +65,18 @@ #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 GetModuleFileNameExA dyn_GetModuleFileNameExA #define GetModuleInformation dyn_GetModuleInformation #define LookupPrivilegeValueA dyn_LookupPrivilegeValueA #define OpenProcessToken dyn_OpenProcessToken +#define GetConsoleFontSize dyn_GetConsoleFontSize +#define GetCurrentConsoleFont dyn_GetCurrentConsoleFont static BOOL WINAPI (*AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); @@ -82,27 +85,50 @@ static BOOL WINAPI (*DebugBreakProcess) (HANDLE); static BOOL WINAPI (*DebugSetProcessKillOnExit) (BOOL); static BOOL WINAPI (*EnumProcessModules) (HANDLE, HMODULE *, DWORD, LPDWORD); -static DWORD WINAPI (*GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, - DWORD); static BOOL WINAPI (*GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, DWORD); static BOOL WINAPI (*LookupPrivilegeValueA)(LPCSTR, LPCSTR, PLUID); static BOOL WINAPI (*OpenProcessToken)(HANDLE, DWORD, PHANDLE); +static BOOL WINAPI (*GetCurrentConsoleFont) (HANDLE, BOOL, + CONSOLE_FONT_INFO *); +static COORD WINAPI (*GetConsoleFontSize) (HANDLE, DWORD); static struct target_ops windows_ops; -#ifdef __CYGWIN__ -/* The starting and ending address of the cygwin1.dll text segment. */ -static CORE_ADDR cygwin_load_start; -static CORE_ADDR cygwin_load_end; +#undef STARTUPINFO +#undef CreateProcess +#undef GetModuleFileNameEx + +#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 CORE_ADDR cygwin_load_start; + static CORE_ADDR cygwin_load_end; +# 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 #endif -static int have_saved_context; /* True if we've saved context from a cygwin signal. */ -static CONTEXT saved_context; /* Containes the saved context from a cygwin signal. */ +static int have_saved_context; /* True if we've saved context from a + cygwin signal. */ +static CONTEXT saved_context; /* Containes the saved context from a + cygwin signal. */ /* If we're not using the old Cygwin header file set, define the following which never should have been in the generic Win32 API - headers in the first place since they were our own invention... */ + headers in the first place since they were our own invention... */ #ifndef _GNU_H_WINDOWS_H enum { @@ -123,10 +149,12 @@ enum 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. - FIXME: This should be in a cygwin include file. */ + FIXME: This should be in a cygwin include file. */ #ifndef _CYGWIN_SIGNAL_STRING #define _CYGWIN_SIGNAL_STRING "cYgSiGw00f" #endif @@ -143,10 +171,12 @@ 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 CORE_ADDR cygwin_get_dr (int i); static unsigned long cygwin_get_dr6 (void); +static unsigned long cygwin_get_dr7 (void); -static enum target_signal last_sig = TARGET_SIGNAL_0; -/* Set if a signal was received from the debugged process */ +static enum gdb_signal last_sig = GDB_SIGNAL_0; +/* Set if a signal was received from the debugged process. */ /* Thread information structure used to track information that is not available in gdb's thread structure. */ @@ -155,6 +185,7 @@ typedef struct thread_info_struct struct thread_info_struct *next; DWORD id; HANDLE h; + CORE_ADDR thread_local_base; char *name; int suspended; int reload_context; @@ -165,7 +196,7 @@ thread_info; static thread_info thread_head; -/* The process and thread handles for the above context. */ +/* The process and thread handles for the above context. */ static DEBUG_EVENT current_event; /* The current debug event from WaitForDebugEvent */ @@ -173,13 +204,13 @@ static HANDLE current_process_handle; /* Currently executing process */ static thread_info *current_thread; /* Info on currently selected thread */ static DWORD main_thread_id; /* Thread ID of the main thread */ -/* Counts of things. */ +/* Counts of things. */ static int exception_count = 0; static int event_count = 0; static int saw_create; static int open_process_used = 0; -/* User options. */ +/* User options. */ static int new_console = 0; #ifdef __CYGWIN__ static int cygwin_exceptions = 0; @@ -204,31 +235,35 @@ static int useshell = 0; /* use shell for subprocesses */ 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 - context already contains what we need, we just unpack it. Then to + context already contains what we need, we just unpack it. Then to write a register, first we have to ensure that the context contains the other regs of the group, and then we copy the info in and set - out bit. */ + out bit. */ static const int *mappings; +/* The function to use in order to determine whether a register is + a segment register or not. */ +static segment_register_p_ftype *segment_register_p; + /* This vector maps the target's idea of an exception (extracted - from the DEBUG_EVENT structure) to GDB's idea. */ + from the DEBUG_EVENT structure) to GDB's idea. */ struct xlate_exception { int them; - enum target_signal us; + enum gdb_signal us; }; static const struct xlate_exception xlate[] = { - {EXCEPTION_ACCESS_VIOLATION, TARGET_SIGNAL_SEGV}, - {STATUS_STACK_OVERFLOW, TARGET_SIGNAL_SEGV}, - {EXCEPTION_BREAKPOINT, TARGET_SIGNAL_TRAP}, - {DBG_CONTROL_C, TARGET_SIGNAL_INT}, - {EXCEPTION_SINGLE_STEP, TARGET_SIGNAL_TRAP}, - {STATUS_FLOAT_DIVIDE_BY_ZERO, TARGET_SIGNAL_FPE}, + {EXCEPTION_ACCESS_VIOLATION, GDB_SIGNAL_SEGV}, + {STATUS_STACK_OVERFLOW, GDB_SIGNAL_SEGV}, + {EXCEPTION_BREAKPOINT, GDB_SIGNAL_TRAP}, + {DBG_CONTROL_C, GDB_SIGNAL_INT}, + {EXCEPTION_SINGLE_STEP, GDB_SIGNAL_TRAP}, + {STATUS_FLOAT_DIVIDE_BY_ZERO, GDB_SIGNAL_FPE}, {-1, -1}}; /* Set the MAPPINGS static global to OFFSETS. @@ -240,12 +275,20 @@ windows_set_context_register_offsets (const int *offsets) mappings = offsets; } +/* See windows-nat.h. */ + +void +windows_set_segment_register_p (segment_register_p_ftype *fun) +{ + segment_register_p = fun; +} + static void check (BOOL ok, const char *file, int line) { if (!ok) - printf_filtered ("error return %s:%d was %lu\n", file, line, - GetLastError ()); + printf_filtered ("error return %s:%d was %u\n", file, line, + (unsigned) GetLastError ()); } /* Find a thread record given a thread id. If GET_CONTEXT is not 0, @@ -266,8 +309,10 @@ thread_rec (DWORD id, int get_context) if (SuspendThread (th->h) == (DWORD) -1) { DWORD err = GetLastError (); - warning (_("SuspendThread failed. (winerr %d)"), - (int) err); + + warning (_("SuspendThread (tid=0x%x) failed." + " (winerr %u)"), + (unsigned) id, (unsigned) err); return NULL; } th->suspended = 1; @@ -284,7 +329,7 @@ thread_rec (DWORD id, int get_context) /* Add a thread to the thread list. */ static thread_info * -windows_add_thread (ptid_t ptid, HANDLE h) +windows_add_thread (ptid_t ptid, HANDLE h, void *tlb) { thread_info *th; DWORD id; @@ -296,9 +341,10 @@ windows_add_thread (ptid_t ptid, HANDLE h) if ((th = thread_rec (id, FALSE))) return th; - th = XZALLOC (thread_info); + th = XCNEW (thread_info); th->id = id; th->h = h; + th->thread_local_base = (CORE_ADDR) (uintptr_t) tlb; th->next = thread_head.next; thread_head.next = th; add_thread (ptid); @@ -321,7 +367,7 @@ windows_add_thread (ptid_t ptid, HANDLE h) } /* Clear out any old thread list and reintialize it to a - pristine state. */ + pristine state. */ static void windows_init_thread_list (void) { @@ -338,9 +384,9 @@ windows_init_thread_list (void) thread_head.next = NULL; } -/* Delete a thread from the list of threads */ +/* Delete a thread from the list of threads. */ static void -windows_delete_thread (ptid_t ptid) +windows_delete_thread (ptid_t ptid, DWORD exit_code) { thread_info *th; DWORD id; @@ -351,6 +397,9 @@ windows_delete_thread (ptid_t ptid) if (info_verbose) printf_unfiltered ("[Deleting %s]\n", target_pid_to_str (ptid)); + else if (print_thread_events && id != main_thread_id) + printf_unfiltered (_("[%s exited with code %u]\n"), + target_pid_to_str (ptid), (unsigned) exit_code); delete_thread (ptid); for (th = &thread_head; @@ -376,17 +425,19 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) if (!current_thread) return; /* Windows sometimes uses a non-existent thread id in its - events */ + events. */ if (current_thread->reload_context) { #ifdef __COPY_CONTEXT_SIZE if (have_saved_context) { - /* Lie about where the program actually is stopped since cygwin has informed us that - we should consider the signal to have occurred at another location which is stored - in "saved_context. */ - memcpy (¤t_thread->context, &saved_context, __COPY_CONTEXT_SIZE); + /* Lie about where the program actually is stopped since + cygwin has informed us that we should consider the signal + to have occurred at another location which is stored in + "saved_context. */ + memcpy (¤t_thread->context, &saved_context, + __COPY_CONTEXT_SIZE); have_saved_context = 0; } else @@ -396,7 +447,8 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) th->context.ContextFlags = CONTEXT_DEBUGGER_DR; GetThreadContext (th->h, &th->context); /* Copy dr values from that thread. - But only if there were not modified since last stop. PR gdb/2388 */ + But only if there were not modified since last stop. + PR gdb/2388 */ if (!debug_registers_changed) { dr[0] = th->context.Dr0; @@ -420,6 +472,14 @@ do_windows_fetch_inferior_registers (struct regcache *regcache, int r) l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); regcache_raw_supply (regcache, r, (char *) &l); } + else if (segment_register_p (r)) + { + /* GDB treats segment registers as 32bit registers, but they are + in fact only 16 bits long. Make sure we do not read extra + bits from our source buffer. */ + l = *((long *) context_offset) & 0xffff; + regcache_raw_supply (regcache, r, (char *) &l); + } else if (r >= 0) regcache_raw_supply (regcache, r, context_offset); else @@ -435,7 +495,7 @@ windows_fetch_inferior_registers (struct target_ops *ops, { 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 */ + thread id in its events. */ if (current_thread) do_windows_fetch_inferior_registers (regcache, r); } @@ -444,7 +504,7 @@ static void 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 */; + /* Windows sometimes uses a non-existent thread id in its events. */; else if (r >= 0) regcache_raw_collect (regcache, r, ((char *) ¤t_thread->context) + mappings[r]); @@ -455,19 +515,19 @@ do_windows_store_inferior_registers (const struct regcache *regcache, int r) } } -/* Store a new register value into the current thread context */ +/* Store a new register value into the current thread context. */ static void windows_store_inferior_registers (struct target_ops *ops, struct regcache *regcache, int r) { 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 */ + thread id in its events. */ if (current_thread) do_windows_store_inferior_registers (regcache, r); } -/* Get the name of a given module at at given base address. If base_address +/* Get the name of a given module at given base address. If base_address is zero return the first loaded module (which is always the name of the executable). */ static int @@ -477,48 +537,59 @@ get_module_name (LPVOID base_address, char *dll_name_ret) MODULEINFO mi; int i; HMODULE dh_buf[1]; - HMODULE *DllHandle = dh_buf; /* Set to temporary storage for initial query */ + 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 cbNeeded = 0; - /* Find size of buffer needed to handle list of modules loaded in inferior */ + /* Find size of buffer needed to handle list of modules loaded in + inferior. */ if (!EnumProcessModules (current_process_handle, DllHandle, sizeof (HMODULE), &cbNeeded) || !cbNeeded) goto failed; - /* Allocate correct amount of space for module list */ + /* Allocate correct amount of space for module list. */ DllHandle = (HMODULE *) alloca (cbNeeded); if (!DllHandle) goto failed; - /* Get the list of modules */ + /* Get the list of modules. */ if (!EnumProcessModules (current_process_handle, DllHandle, cbNeeded, &cbNeeded)) goto failed; for (i = 0; i < (int) (cbNeeded / sizeof (HMODULE)); i++) { - /* Get information on this module */ + /* Get information on this module. */ if (!GetModuleInformation (current_process_handle, DllHandle[i], &mi, sizeof (mi))) error (_("Can't get module info")); if (!base_address || mi.lpBaseOfDll == base_address) { - /* Try to find the name of the given module */ - len = GetModuleFileNameExA (current_process_handle, - DllHandle[i], pathbuf, MAX_PATH); - if (len == 0) - error (_("Error getting dll name: %u."), (unsigned) GetLastError ()); + /* Try to find the name of the given module. */ #ifdef __CYGWIN__ - /* Cygwin prefers that the path be in /x/y/z format */ - cygwin_conv_to_full_posix_path (pathbuf, dll_name_ret); + /* Cygwin prefers that the path be in /x/y/z format. */ + len = GetModuleFileNameEx (current_process_handle, + DllHandle[i], pathbuf, __PMAX); + if (len == 0) + error (_("Error getting dll name: %u."), + (unsigned) 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 */ } @@ -530,7 +601,7 @@ failed: } /* Encapsulate the information required in a call to - symbol_file_add_args */ + symbol_file_add_args. */ struct safe_symbol_file_add_args { char *name; @@ -542,7 +613,7 @@ struct safe_symbol_file_add_args struct objfile *ret; }; -/* Maintain a linked list of "so" information. */ +/* Maintain a linked list of "so" information. */ struct lm_info { LPVOID load_addr; @@ -551,7 +622,7 @@ struct lm_info static struct so_list solib_start, *solib_end; /* Call symbol_file_add with stderr redirected. We don't care if there - are errors. */ + are errors. */ static int safe_symbol_file_add_stub (void *argv) { @@ -563,7 +634,7 @@ safe_symbol_file_add_stub (void *argv) #undef p } -/* Restore gdb's stderr after calling symbol_file_add */ +/* Restore gdb's stderr after calling symbol_file_add. */ static void safe_symbol_file_add_cleanup (void *p) { @@ -577,7 +648,7 @@ safe_symbol_file_add_cleanup (void *p) #undef sp } -/* symbol_file_add wrapper that prevents errors from being displayed. */ +/* symbol_file_add wrapper that prevents errors from being displayed. */ static struct objfile * safe_symbol_file_add (char *name, int from_tty, struct section_addr_info *addrs, @@ -609,12 +680,12 @@ static struct so_list * 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); @@ -632,20 +703,52 @@ windows_make_so (const char *name, LPVOID load_addr) SetCurrentDirectory (cwd); } } - if (strcasecmp (buf, "ntdll.dll") == 0) { GetSystemDirectory (buf, sizeof (buf)); strcat (buf, "\\ntdll.dll"); } - so = XZALLOC (struct so_list); +#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 = XCNEW (struct so_list); so->lm_info = (struct lm_info *) xmalloc (sizeof (struct lm_info)); so->lm_info->load_addr = load_addr; strcpy (so->so_original_name, name); #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) @@ -654,7 +757,7 @@ windows_make_so (const char *name, LPVOID load_addr) asection *text = NULL; CORE_ADDR text_vma; - abfd = bfd_openr (so->so_name, "pei-i386"); + abfd = gdb_bfd_open (so->so_name, "pei-i386", -1); if (!abfd) return so; @@ -664,17 +767,18 @@ windows_make_so (const char *name, LPVOID load_addr) if (!text) { - bfd_close (abfd); + gdb_bfd_unref (abfd); return so; } - /* The symbols in a dll are offset by 0x1000, which is the the + /* The symbols in a dll are offset by 0x1000, which is the offset from 0 of the first byte in an image - because of the - file header and the section alignment. */ - cygwin_load_start = (CORE_ADDR) (uintptr_t) ((char *) load_addr + 0x1000); + file header and the section alignment. */ + 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); + gdb_bfd_unref (abfd); } #endif @@ -684,7 +788,11 @@ windows_make_so (const char *name, LPVOID 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; @@ -693,17 +801,18 @@ get_image_name (HANDLE h, void *address, int unicode) /* Attempt to read the name of the dll that was detected. This is documented to work only when actively debugging - a program. It will not work for attached processes. */ + a program. It will not work for attached processes. */ if (address == NULL) return NULL; /* See if we could read the address of a string, and that the - address isn't null. */ - if (!ReadProcessMemory (h, address, &address_ptr, sizeof (address_ptr), &done) + address isn't null. */ + if (!ReadProcessMemory (h, address, &address_ptr, + sizeof (address_ptr), &done) || done != sizeof (address_ptr) || !address_ptr) return NULL; - /* Find the length of the string */ + /* Find the length of the string. */ while (ReadProcessMemory (h, address_ptr + len++ * size, &b, size, &done) && (b[0] != 0 || b[size - 1] != 0) && done == size) continue; @@ -715,8 +824,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; @@ -728,16 +841,36 @@ 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'; + /* Try getting the DLL name by searching the list of known modules + and matching their base address against this new DLL's base address. + + FIXME: brobecker/2013-12-10: + It seems odd to be going through this search if the DLL name could + simply be extracted via "event->lpImageName". Moreover, some + experimentation with various versions of Windows seem to indicate + that it might still be too early for this DLL to be listed when + querying the system about the current list of modules, thus making + this attempt pointless. + + This code can therefore probably be removed. But at the time of + this writing, we are too close to creating the GDB 7.7 branch + for us to make such a change. We are therefore defering it. */ + if (!get_module_name (event->lpBaseOfDll, dll_buf)) dll_buf[0] = dll_buf[sizeof (dll_buf) - 1] = '\0'; dll_name = dll_buf; + /* Try getting the DLL name via the lpImageName field of the event. + Note that Microsoft documents this fields as strictly optional, + in the sense that it might be NULL. And the first DLL event in + particular is explicitly documented as "likely not pass[ed]" + (source: MSDN LOAD_DLL_DEBUG_INFO structure). */ if (*dll_name == '\0') dll_name = get_image_name (current_process_handle, event->lpImageName, event->fUnicode); @@ -771,23 +904,30 @@ handle_unload_dll (void *dummy) if (so->next->lm_info->load_addr == lpBaseOfDll) { struct so_list *sodel = so->next; + so->next = sodel->next; if (!so->next) solib_end = so; DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name)); windows_free_so (sodel); - solib_add (NULL, 0, NULL, auto_solib_add); return 1; } - error (_("Error: dll starting at %s not found."), - host_address_to_string (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. */ +/* Clear list of loaded DLLs. */ static void windows_clear_solib (void) { @@ -795,8 +935,8 @@ windows_clear_solib (void) solib_end = &solib_start; } -/* Load DLL symbol info. */ -void +/* Load DLL symbol info. */ +static void dll_symbol_command (char *args, int from_tty) { int n; @@ -819,7 +959,7 @@ dll_symbol_command (char *args, int from_tty) /* Handle DEBUG_STRING output from child process. Cygwin prepends its messages with a "cygwin:". Interpret this as - a Cygwin signal. Otherwise just print the string as a warning. */ + a Cygwin signal. Otherwise just print the string as a warning. */ static int handle_output_debug_string (struct target_waitstatus *ourstatus) { @@ -831,7 +971,8 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) &s, 1024, 0) || !s || !*s) /* nothing to do */; - else if (strncmp (s, _CYGWIN_SIGNAL_STRING, sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0) + else if (strncmp (s, _CYGWIN_SIGNAL_STRING, + sizeof (_CYGWIN_SIGNAL_STRING) - 1) != 0) { #ifdef __CYGWIN__ if (strncmp (s, "cYg", 3) != 0) @@ -841,26 +982,31 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) #ifdef __COPY_CONTEXT_SIZE else { - /* Got a cygwin signal marker. A cygwin signal is followed by the signal number - itself and then optionally followed by the thread id and address to saved context - within the DLL. If these are supplied, then the given thread is assumed to have - issued the signal and the context from the thread is assumed to be stored at the - given address in the inferior. Tell gdb to treat this like a real signal. */ + /* Got a cygwin signal marker. A cygwin signal is followed by + the signal number itself and then optionally followed by the + thread id and address to saved context within the DLL. If + these are supplied, then the given thread is assumed to have + issued the signal and the context from the thread is assumed + to be stored at the given address in the inferior. Tell gdb + to treat this like a real signal. */ char *p; int sig = strtol (s + sizeof (_CYGWIN_SIGNAL_STRING) - 1, &p, 0); - int gotasig = target_signal_from_host (sig); + int gotasig = gdb_signal_from_host (sig); + ourstatus->value.sig = gotasig; if (gotasig) { LPCVOID x; - DWORD n; + SIZE_T n; + ourstatus->kind = TARGET_WAITKIND_STOPPED; retval = strtoul (p, &p, 0); if (!retval) retval = main_thread_id; - else if ((x = (LPCVOID) strtoul (p, &p, 0)) + else if ((x = (LPCVOID) (uintptr_t) strtoull (p, NULL, 0)) && ReadProcessMemory (current_process_handle, x, - &saved_context, __COPY_CONTEXT_SIZE, &n) + &saved_context, + __COPY_CONTEXT_SIZE, &n) && n == __COPY_CONTEXT_SIZE) have_saved_context = 1; current_event.dwThreadId = retval; @@ -880,7 +1026,7 @@ display_selector (HANDLE thread, DWORD sel) if (GetThreadSelectorEntry (thread, sel, &info)) { int base, limit; - printf_filtered ("0x%03lx: ", sel); + printf_filtered ("0x%03x: ", (unsigned) sel); if (!info.HighWord.Bits.Pres) { puts_filtered ("Segment not present\n"); @@ -940,7 +1086,11 @@ display_selector (HANDLE thread, DWORD sel) } else { - printf_filtered ("Invalid selector 0x%lx.\n",sel); + DWORD err = GetLastError (); + if (err == ERROR_NOT_SUPPORTED) + printf_filtered ("Function not supported\n"); + else + printf_filtered ("Invalid selector 0x%x.\n", (unsigned) sel); return 0; } } @@ -984,15 +1134,6 @@ display_selectors (char * args, int from_tty) } } -static struct cmd_list_element *info_w32_cmdlist = NULL; - -static void -info_w32_command (char *args, int from_tty) -{ - help_list (info_w32_cmdlist, "info w32 ", class_info, gdb_stdout); -} - - #define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ printf_unfiltered ("gdb: Target exception %s at %s\n", x, \ host_address_to_string (\ @@ -1006,112 +1147,118 @@ handle_exception (struct target_waitstatus *ourstatus) ourstatus->kind = TARGET_WAITKIND_STOPPED; - /* Record the context of the current thread */ + /* Record the context of the current thread. */ th = thread_rec (current_event.dwThreadId, -1); switch (code) { case EXCEPTION_ACCESS_VIOLATION: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION"); - ourstatus->value.sig = TARGET_SIGNAL_SEGV; + ourstatus->value.sig = GDB_SIGNAL_SEGV; #ifdef __CYGWIN__ { - /* See if the access violation happened within the cygwin DLL itself. Cygwin uses - a kind of exception handling to deal with passed-in invalid addresses. gdb - should not treat these as real SEGVs since they will be silently handled by - cygwin. A real SEGV will (theoretically) be caught by cygwin later in the process - 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; - CORE_ADDR addr = (CORE_ADDR) (uintptr_t) current_event.u.Exception.ExceptionRecord.ExceptionAddress; - if ((!cygwin_exceptions && (addr >= cygwin_load_start && addr < cygwin_load_end)) + /* See if the access violation happened within the cygwin DLL + itself. Cygwin uses a kind of exception handling to deal + with passed-in invalid addresses. gdb should not treat + these as real SEGVs since they will be silently handled by + cygwin. A real SEGV will (theoretically) be caught by + cygwin later in the process and will be sent as a + cygwin-specific-signal. So, ignore SEGVs if they show up + within the text segment of the DLL itself. */ + const char *fn; + 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)) + && strncmp (fn, "KERNEL32!IsBad", + strlen ("KERNEL32!IsBad")) == 0)) return 0; } #endif break; case STATUS_STACK_OVERFLOW: DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW"); - ourstatus->value.sig = TARGET_SIGNAL_SEGV; + ourstatus->value.sig = GDB_SIGNAL_SEGV; break; case STATUS_FLOAT_DENORMAL_OPERAND: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_INEXACT_RESULT: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_INVALID_OPERATION: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_OVERFLOW: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_STACK_CHECK: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_UNDERFLOW: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_FLOAT_DIVIDE_BY_ZERO: DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_INTEGER_DIVIDE_BY_ZERO: DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case STATUS_INTEGER_OVERFLOW: DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW"); - ourstatus->value.sig = TARGET_SIGNAL_FPE; + ourstatus->value.sig = GDB_SIGNAL_FPE; break; case EXCEPTION_BREAKPOINT: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT"); - ourstatus->value.sig = TARGET_SIGNAL_TRAP; + ourstatus->value.sig = GDB_SIGNAL_TRAP; break; case DBG_CONTROL_C: DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C"); - ourstatus->value.sig = TARGET_SIGNAL_INT; + ourstatus->value.sig = GDB_SIGNAL_INT; break; case DBG_CONTROL_BREAK: DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK"); - ourstatus->value.sig = TARGET_SIGNAL_INT; + ourstatus->value.sig = GDB_SIGNAL_INT; break; case EXCEPTION_SINGLE_STEP: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP"); - ourstatus->value.sig = TARGET_SIGNAL_TRAP; + ourstatus->value.sig = GDB_SIGNAL_TRAP; break; case EXCEPTION_ILLEGAL_INSTRUCTION: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION"); - ourstatus->value.sig = TARGET_SIGNAL_ILL; + ourstatus->value.sig = GDB_SIGNAL_ILL; break; case EXCEPTION_PRIV_INSTRUCTION: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION"); - ourstatus->value.sig = TARGET_SIGNAL_ILL; + ourstatus->value.sig = GDB_SIGNAL_ILL; break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); - ourstatus->value.sig = TARGET_SIGNAL_ILL; + ourstatus->value.sig = GDB_SIGNAL_ILL; break; default: - /* Treat unhandled first chance exceptions specially. */ + /* Treat unhandled first chance exceptions specially. */ if (current_event.u.Exception.dwFirstChance) return -1; - printf_unfiltered ("gdb: unknown target exception 0x%08lx at %s\n", - current_event.u.Exception.ExceptionRecord.ExceptionCode, + printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n", + (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, host_address_to_string ( current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN; + ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; break; } exception_count++; @@ -1120,7 +1267,7 @@ handle_exception (struct target_waitstatus *ourstatus) } /* Resume all artificially suspended threads if we are continuing - execution */ + execution. */ static BOOL windows_continue (DWORD continue_status, int id) { @@ -1128,8 +1275,9 @@ windows_continue (DWORD continue_status, int id) thread_info *th; BOOL res; - DEBUG_EVENTS (("ContinueDebugEvent (cpid=%ld, ctid=%ld, %s);\n", - current_event.dwProcessId, current_event.dwThreadId, + DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId, continue_status == DBG_CONTINUE ? "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); @@ -1176,20 +1324,22 @@ fake_create_process (void) open_process_used = 1; else { - error (_("OpenProcess call failed, GetLastError = %lud\n"), - GetLastError ()); + error (_("OpenProcess call failed, GetLastError = %u"), + (unsigned) GetLastError ()); /* We can not debug anything in that case. */ } main_thread_id = current_event.dwThreadId; - current_thread = windows_add_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId), - current_event.u.CreateThread.hThread); + current_thread = windows_add_thread ( + ptid_build (current_event.dwProcessId, 0, + current_event.dwThreadId), + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase); return main_thread_id; } static void windows_resume (struct target_ops *ops, - ptid_t ptid, int step, enum target_signal sig) + ptid_t ptid, int step, enum gdb_signal sig) { thread_info *th; DWORD continue_status = DBG_CONTINUE; @@ -1202,7 +1352,7 @@ windows_resume (struct target_ops *ops, if (resume_all) ptid = inferior_ptid; - if (sig != TARGET_SIGNAL_0) + if (sig != GDB_SIGNAL_0) { if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT) { @@ -1221,8 +1371,8 @@ windows_resume (struct target_ops *ops, for (i = 0; xlate[i].them != -1; i++) if (xlate[i].us == sig) { - current_event.u.Exception.ExceptionRecord.ExceptionCode = - xlate[i].them; + current_event.u.Exception.ExceptionRecord.ExceptionCode + = xlate[i].them; continue_status = DBG_EXCEPTION_NOT_HANDLED; break; } @@ -1236,18 +1386,18 @@ windows_resume (struct target_ops *ops, last_sig)); } - last_sig = TARGET_SIGNAL_0; + last_sig = GDB_SIGNAL_0; 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 */ + /* Get context for currently selected thread. */ th = thread_rec (ptid_get_tid (inferior_ptid), FALSE); if (th) { if (step) { - /* Single step by setting t bit */ + /* Single step by setting t bit. */ struct regcache *regcache = get_current_regcache (); struct gdbarch *gdbarch = get_regcache_arch (regcache); windows_fetch_inferior_registers (ops, regcache, @@ -1272,7 +1422,7 @@ windows_resume (struct target_ops *ops, } /* Allow continuing with the same signal that interrupted us. - Otherwise complain. */ + Otherwise complain. */ if (resume_all) windows_continue (continue_status, -1); @@ -1284,7 +1434,7 @@ windows_resume (struct target_ops *ops, 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 +static BOOL WINAPI ctrl_c_handler (DWORD event_type) { const int attach_flag = current_inferior ()->attach_flag; @@ -1299,8 +1449,8 @@ ctrl_c_handler (DWORD event_type) return TRUE; if (!DebugBreakProcess (current_process_handle)) - warning (_("\ -Could not interrupt program. Press Ctrl-c in the program console.")); + warning (_("Could not interrupt program. " + "Press Ctrl-c in the program console.")); /* Return true to tell that Ctrl-C has been handled. */ return TRUE; @@ -1318,7 +1468,7 @@ get_windows_debug_event (struct target_ops *ops, static thread_info dummy_thread_info; int retval = 0; - last_sig = TARGET_SIGNAL_0; + last_sig = GDB_SIGNAL_0; if (!(debug_event = WaitForDebugEvent (¤t_event, 1000))) goto out; @@ -1334,7 +1484,7 @@ get_windows_debug_event (struct target_ops *ops, switch (event_code) { case CREATE_THREAD_DEBUG_EVENT: - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%x code=%s)\n", + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_THREAD_DEBUG_EVENT")); @@ -1346,35 +1496,39 @@ get_windows_debug_event (struct target_ops *ops, { /* Kludge around a Windows bug where first event is a create thread event. Caused when attached process does not have - a main thread. */ + a main thread. */ retval = fake_create_process (); if (retval) saw_create++; } break; } - /* Record the existence of this thread */ + /* Record the existence of this thread. */ retval = current_event.dwThreadId; th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, current_event.dwThreadId), - current_event.u.CreateThread.hThread); + current_event.u.CreateThread.hThread, + current_event.u.CreateThread.lpThreadLocalBase); + 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=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXIT_THREAD_DEBUG_EVENT")); + if (current_event.dwThreadId != main_thread_id) { windows_delete_thread (ptid_build (current_event.dwProcessId, 0, - current_event.dwThreadId)); + current_event.dwThreadId), + current_event.u.ExitThread.dwExitCode); 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=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "CREATE_PROCESS_DEBUG_EVENT")); @@ -1385,29 +1539,39 @@ get_windows_debug_event (struct target_ops *ops, current_process_handle = current_event.u.CreateProcessInfo.hProcess; if (main_thread_id) windows_delete_thread (ptid_build (current_event.dwProcessId, 0, - main_thread_id)); + main_thread_id), + 0); main_thread_id = current_event.dwThreadId; - /* Add the main thread */ + /* Add the main thread. */ th = windows_add_thread (ptid_build (current_event.dwProcessId, 0, current_event.dwThreadId), - current_event.u.CreateProcessInfo.hThread); + current_event.u.CreateProcessInfo.hThread, + current_event.u.CreateProcessInfo.lpThreadLocalBase); 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=%u tid=0x%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=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "LOAD_DLL_DEBUG_EVENT")); @@ -1421,7 +1585,7 @@ get_windows_debug_event (struct target_ops *ops, 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=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "UNLOAD_DLL_DEBUG_EVENT")); @@ -1434,7 +1598,7 @@ get_windows_debug_event (struct target_ops *ops, 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=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "EXCEPTION_DEBUG_EVENT")); @@ -1455,8 +1619,8 @@ get_windows_debug_event (struct target_ops *ops, } break; - case OUTPUT_DEBUG_STRING_EVENT: /* message from the kernel */ - DEBUG_EVENTS (("gdb: kernel event for pid=%d tid=%d code=%s)\n", + case OUTPUT_DEBUG_STRING_EVENT: /* Message from the kernel. */ + DEBUG_EVENTS (("gdb: kernel event for pid=%u tid=0x%x code=%s)\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId, "OUTPUT_DEBUG_STRING_EVENT")); @@ -1468,11 +1632,11 @@ get_windows_debug_event (struct target_ops *ops, default: if (saw_create != 1) break; - printf_unfiltered ("gdb: kernel event for pid=%ld tid=%ld\n", - (DWORD) current_event.dwProcessId, - (DWORD) current_event.dwThreadId); - printf_unfiltered (" unknown event code %ld\n", - current_event.dwDebugEventCode); + printf_unfiltered ("gdb: kernel event for pid=%u tid=0x%x\n", + (unsigned) current_event.dwProcessId, + (unsigned) current_event.dwThreadId); + printf_unfiltered (" unknown event code %u\n", + (unsigned) current_event.dwDebugEventCode); break; } @@ -1507,7 +1671,7 @@ windows_wait (struct target_ops *ops, with a SPURIOUS because resume can try and step or modify things, which needs a current_thread->h. But some of these exceptions mark the birth or death of threads, which mean that the current thread - isn't necessarily what you think it is. */ + isn't necessarily what you think it is. */ while (1) { @@ -1520,8 +1684,8 @@ windows_wait (struct target_ops *ops, - 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 + 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 @@ -1558,6 +1722,74 @@ windows_wait (struct target_ops *ops, } } +/* On certain versions of Windows, the information about ntdll.dll + is not available yet at the time we get the LOAD_DLL_DEBUG_EVENT, + thus preventing us from reporting this DLL as an SO. This has been + witnessed on Windows 8.1, for instance. A possible explanation + is that ntdll.dll might be mapped before the SO info gets created + by the Windows system -- ntdll.dll is the first DLL to be reported + via LOAD_DLL_DEBUG_EVENT and other DLLs do not seem to suffer from + that problem. + + If we indeed are missing ntdll.dll, this function tries to recover + from this issue, after the fact. Do nothing if we encounter any + issue trying to locate that DLL. */ + +static void +windows_ensure_ntdll_loaded (void) +{ + struct so_list *so; + HMODULE dummy_hmodule; + DWORD cb_needed; + HMODULE *hmodules; + int i; + + for (so = solib_start.next; so != NULL; so = so->next) + if (FILENAME_CMP (lbasename (so->so_name), "ntdll.dll") == 0) + return; /* ntdll.dll already loaded, nothing to do. */ + + if (EnumProcessModules (current_process_handle, &dummy_hmodule, + sizeof (HMODULE), &cb_needed) == 0) + return; + + if (cb_needed < 1) + return; + + hmodules = (HMODULE *) alloca (cb_needed); + if (EnumProcessModules (current_process_handle, hmodules, + cb_needed, &cb_needed) == 0) + return; + + for (i = 0; i < (int) (cb_needed / sizeof (HMODULE)); i++) + { + MODULEINFO mi; +#ifdef __USEWIDE + wchar_t dll_name[__PMAX]; + char name[__PMAX]; +#else + char dll_name[__PMAX]; + char *name; +#endif + if (GetModuleInformation (current_process_handle, hmodules[i], + &mi, sizeof (mi)) == 0) + continue; + if (GetModuleFileNameEx (current_process_handle, hmodules[i], + dll_name, sizeof (dll_name)) == 0) + continue; +#ifdef __USEWIDE + wcstombs (name, dll_name, __PMAX); +#else + name = dll_name; +#endif + if (FILENAME_CMP (lbasename (name), "ntdll.dll") == 0) + { + solib_end->next = windows_make_so (name, mi.lpBaseOfDll); + solib_end = solib_end->next; + return; + } + } +} + static void do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) { @@ -1566,7 +1798,7 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) struct inferior *inf; struct thread_info *tp; - last_sig = TARGET_SIGNAL_0; + last_sig = GDB_SIGNAL_0; event_count = 0; exception_count = 0; open_process_used = 0; @@ -1585,7 +1817,8 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) clear_proceed_status (); init_wait_for_inferior (); - inf = add_inferior (pid); + inf = current_inferior (); + inferior_appeared (inf, pid); inf->attach_flag = attaching; /* Make the new process the current inferior, so terminal handling @@ -1597,19 +1830,29 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) terminal_init_inferior_with_pgrp (pid); target_terminal_inferior (); - inf->stop_soon = STOP_QUIETLY; + windows_initialization_done = 0; + inf->control.stop_soon = STOP_QUIETLY; while (1) { stop_after_trap = 1; - wait_for_inferior (0); + wait_for_inferior (); tp = inferior_thread (); - if (tp->stop_signal != TARGET_SIGNAL_TRAP) - resume (0, tp->stop_signal); + if (tp->suspend.stop_signal != GDB_SIGNAL_TRAP) + resume (0, tp->suspend.stop_signal); else break; } - inf->stop_soon = NO_STOP_QUIETLY; + /* FIXME: brobecker/2013-12-10: We should try another approach where + we first ignore all DLL load/unload events up until this point, + and then iterate over all modules to create the associated shared + objects. This is a fairly significant change, however, and we are + close to creating a release branch, so we are delaying it a bit, + after the branch is created. */ + windows_ensure_ntdll_loaded (); + + windows_initialization_done = 1; + inf->control.stop_soon = NO_STOP_QUIETLY; stop_after_trap = 0; return; } @@ -1619,7 +1862,7 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) This code is copied from the Cygwin source code and rearranged to allow dynamically loading of the needed symbols from advapi32 which is only - available on NT/2K/XP. */ + available on NT/2K/XP. */ static int set_process_privilege (const char *privilege, BOOL enable) { @@ -1647,9 +1890,9 @@ 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 - windows_attach(). */ + windows_attach(). */ /* AdjustTokenPrivileges returns TRUE even if the privilege could not - be enabled. GetLastError () returns an correct error code, though. */ + be enabled. GetLastError () returns an correct error code, though. */ if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED) goto out; #endif @@ -1670,17 +1913,15 @@ 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) { printf_unfiltered ("Warning: Failed to get SE_DEBUG_NAME privilege\n"); - printf_unfiltered ("This can cause attach to fail on Windows NT/2K/XP\n"); + printf_unfiltered ("This can cause attach to " + "fail on Windows NT/2K/XP\n"); } - pid = strtoul (args, 0, 0); /* Windows pid */ - windows_init_thread_list (); ok = DebugActiveProcess (pid); saw_create = 0; @@ -1688,7 +1929,7 @@ windows_attach (struct target_ops *ops, char *args, int from_tty) #ifdef __CYGWIN__ if (!ok) { - /* Try fall back to Cygwin pid */ + /* Try fall back to Cygwin pid. */ pid = cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid); if (pid > 0) @@ -1720,17 +1961,17 @@ windows_attach (struct target_ops *ops, char *args, int from_tty) } static void -windows_detach (struct target_ops *ops, char *args, int from_tty) +windows_detach (struct target_ops *ops, const char *args, int from_tty) { int detached = 1; ptid_t ptid = {-1}; - windows_resume (ops, ptid, 0, TARGET_SIGNAL_0); + windows_resume (ops, ptid, 0, GDB_SIGNAL_0); if (!DebugActiveProcessStop (current_event.dwProcessId)) { - error (_("Can't detach process %lu (error %lu)"), - current_event.dwProcessId, GetLastError ()); + error (_("Can't detach process %u (error %u)"), + (unsigned) current_event.dwProcessId, (unsigned) GetLastError ()); detached = 0; } DebugSetProcessKillOnExit (FALSE); @@ -1740,11 +1981,12 @@ windows_detach (struct target_ops *ops, char *args, int from_tty) char *exec_file = get_exec_file (0); if (exec_file == 0) exec_file = ""; - printf_unfiltered ("Detaching from program: %s, Pid %lu\n", exec_file, - current_event.dwProcessId); + printf_unfiltered ("Detaching from program: %s, Pid %u\n", exec_file, + (unsigned) current_event.dwProcessId); gdb_flush (gdb_stdout); } + i386_cleanup_dregs (); inferior_ptid = null_ptid; detach_inferior (current_event.dwProcessId); @@ -1754,13 +1996,13 @@ windows_detach (struct target_ops *ops, char *args, int from_tty) static char * 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 */ + /* Try to find exe name as symlink target of /proc//exe. */ int nchars; char procexe[sizeof ("/proc/4294967295/exe")]; - sprintf (procexe, "/proc/%u/exe", pid); + + xsnprintf (procexe, sizeof (procexe), "/proc/%u/exe", pid); nchars = readlink (procexe, path, sizeof(path)); if (nchars > 0 && nchars < sizeof (path)) { @@ -1770,7 +2012,7 @@ windows_pid_to_exec_file (int pid) #endif /* If we get here then either Cygwin is hosed, this isn't a Cygwin version - of gdb, or we're trying to debug a non-Cygwin windows executable. */ + of gdb, or we're trying to debug a non-Cygwin windows executable. */ if (!get_module_name (0, path)) path[0] = '\0'; @@ -1795,6 +2037,85 @@ windows_open (char *arg, int from_tty) error (_("Use the \"run\" command to start a Unix child process.")); } +/* Modify CreateProcess parameters for use of a new separate console. + Parameters are: + *FLAGS: DWORD parameter for general process creation flags. + *SI: STARTUPINFO structure, for which the console window size and + console buffer size is filled in if GDB is running in a console. + to create the new console. + The size of the used font is not available on all versions of + Windows OS. Furthermore, the current font might not be the default + font, but this is still better than before. + If the windows and buffer sizes are computed, + SI->DWFLAGS is changed so that this information is used + by CreateProcess function. */ + +static void +windows_set_console_info (STARTUPINFO *si, DWORD *flags) +{ + HANDLE hconsole = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + + if (hconsole != INVALID_HANDLE_VALUE) + { + CONSOLE_SCREEN_BUFFER_INFO sbinfo; + COORD font_size; + CONSOLE_FONT_INFO cfi; + + GetCurrentConsoleFont (hconsole, FALSE, &cfi); + font_size = GetConsoleFontSize (hconsole, cfi.nFont); + GetConsoleScreenBufferInfo(hconsole, &sbinfo); + si->dwXSize = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1; + si->dwYSize = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1; + if (font_size.X) + si->dwXSize *= font_size.X; + else + si->dwXSize *= 8; + if (font_size.Y) + si->dwYSize *= font_size.Y; + else + si->dwYSize *= 12; + si->dwXCountChars = sbinfo.dwSize.X; + si->dwYCountChars = sbinfo.dwSize.Y; + si->dwFlags |= STARTF_USESIZE | STARTF_USECOUNTCHARS; + } + *flags |= CREATE_NEW_CONSOLE; +} + +#ifndef __CYGWIN__ +/* Function called by qsort to sort environment strings. */ + +static int +envvar_cmp (const void *a, const void *b) +{ + const char **p = (const char **) a; + const char **q = (const char **) b; + return strcasecmp (*p, *q); +} +#endif + +#ifdef __CYGWIN__ +static void +clear_win32_environment (char **env) +{ + int i; + size_t len; + wchar_t *copy = NULL, *equalpos; + + for (i = 0; env[i] && *env[i]; i++) + { + len = mbstowcs (NULL, env[i], 0) + 1; + copy = (wchar_t *) xrealloc (copy, len * sizeof (wchar_t)); + mbstowcs (copy, env[i], len); + equalpos = wcschr (copy, L'='); + if (equalpos) + *equalpos = L'\0'; + SetEnvironmentVariableW (copy, NULL); + } + xfree (copy); +} +#endif + /* 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. @@ -1805,20 +2126,35 @@ 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 */ - const char *sh; #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; + char **old_env = NULL; + PWCHAR w32_env; + size_t len; int tty; int ostdin, ostdout, ostderr; #else + char real_path[__PMAX]; + char shell[__PMAX]; /* Path to shell */ + char *toexec; + char *args; + size_t args_len; HANDLE tty; + char *w32env; + char *temp; + size_t envlen; + int i; + size_t envsize; + char **env; #endif + PROCESS_INFORMATION pi; + BOOL ret; + DWORD flags = 0; const char *inferior_io_terminal = get_inferior_io_terminal (); if (!exec_file) @@ -1827,46 +2163,82 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, memset (&si, 0, sizeof (si)); si.cb = sizeof (si); + if (new_group) + flags |= CREATE_NEW_PROCESS_GROUP; + + if (new_console) + windows_set_console_info (&si, &flags); + #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; + len = (sizeof (" -c 'exec '") + strlen (exec_file) + + strlen (allargs) + 2); + cygallargs = (char *) alloca (len); + xsnprintf (cygallargs, len, " -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; - - 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); +#ifdef CW_CVT_ENV_TO_WINENV + /* First try to create a direct Win32 copy of the POSIX environment. */ + w32_env = (PWCHAR) cygwin_internal (CW_CVT_ENV_TO_WINENV, in_env); + if (w32_env != (PWCHAR) -1) + flags |= CREATE_UNICODE_ENVIRONMENT; + else + /* If that fails, fall back to old method tweaking GDB's environment. */ +#endif + { + /* Reset all Win32 environment variables to avoid leftover on next run. */ + clear_win32_environment (environ); + /* Prepare the environment vars for CreateProcess. */ + old_env = environ; + environ = in_env; + cygwin_internal (CW_SYNC_WINENV); + w32_env = NULL; + } if (!inferior_io_terminal) tty = ostdin = ostdout = ostderr = -1; @@ -1888,7 +2260,52 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, dup2 (tty, 2); } } + + windows_init_thread_list (); + ret = CreateProcess (0, + args, /* command line */ + NULL, /* Security */ + NULL, /* thread */ + TRUE, /* inherit handles */ + flags, /* start flags */ + w32_env, /* environment */ + NULL, /* current directory */ + &si, + &pi); + if (w32_env) + /* Just free the Win32 environment, if it could be created. */ + free (w32_env); + else + { + /* Reset all environment variables to avoid leftover on next run. */ + clear_win32_environment (in_env); + /* Restore normal GDB environment variables. */ + environ = old_env; + cygwin_internal (CW_SYNC_WINENV); + } + + if (tty >= 0) + { + close (tty); + dup2 (ostdin, 0); + dup2 (ostdout, 1); + dup2 (ostderr, 2); + close (ostdin); + close (ostdout); + close (ostderr); + } #else + toexec = exec_file; + /* Build the command line, a space-separated list of tokens where + the first token is the name of the module to be executed. + To avoid ambiguities introduced by spaces in the module name, + we quote it. */ + args_len = strlen (toexec) + 2 /* quotes */ + strlen (allargs) + 2; + args = alloca (args_len); + xsnprintf (args, args_len, "\"%s\" %s", toexec, allargs); + + flags |= DEBUG_ONLY_THIS_PROCESS; + if (!inferior_io_terminal) tty = INVALID_HANDLE_VALUE; else @@ -1910,38 +2327,49 @@ windows_create_inferior (struct target_ops *ops, char *exec_file, si.dwFlags |= STARTF_USESTDHANDLES; } } -#endif - windows_init_thread_list (); - ret = CreateProcess (0, - args, /* command line */ - NULL, /* Security */ - NULL, /* thread */ - TRUE, /* inherit handles */ - flags, /* start flags */ - NULL, /* environment */ - NULL, /* current directory */ - &si, - &pi); + /* CreateProcess takes the environment list as a null terminated set of + strings (i.e. two nulls terminate the list). */ -#ifdef __CYGWIN__ - if (tty >= 0) + /* Get total size for env strings. */ + for (envlen = 0, i = 0; in_env[i] && *in_env[i]; i++) + envlen += strlen (in_env[i]) + 1; + + envsize = sizeof (in_env[0]) * (i + 1); + env = (char **) alloca (envsize); + memcpy (env, in_env, envsize); + /* Windows programs expect the environment block to be sorted. */ + qsort (env, i, sizeof (char *), envvar_cmp); + + w32env = alloca (envlen + 1); + + /* Copy env strings into new buffer. */ + for (temp = w32env, i = 0; env[i] && *env[i]; i++) { - close (tty); - dup2 (ostdin, 0); - dup2 (ostdout, 1); - dup2 (ostderr, 2); - close (ostdin); - close (ostdout); - close (ostderr); + strcpy (temp, env[i]); + temp += strlen (temp) + 1; } -#else + + /* Final nil string to terminate new env. */ + *temp = 0; + + windows_init_thread_list (); + ret = CreateProcessA (0, + args, /* command line */ + NULL, /* Security */ + NULL, /* thread */ + TRUE, /* inherit handles */ + flags, /* start flags */ + w32env, /* environment */ + NULL, /* current directory */ + &si, + &pi); if (tty != INVALID_HANDLE_VALUE) CloseHandle (tty); #endif if (!ret) - error (_("Error creating process %s, (error %d)."), + error (_("Error creating process %s, (error %u)."), exec_file, (unsigned) GetLastError ()); CloseHandle (pi.hThread); @@ -1972,7 +2400,7 @@ windows_mourn_inferior (struct target_ops *ops) } /* Send a SIGINT to the process group. This acts just like the user typed a - ^C on the controlling terminal. */ + ^C on the controlling terminal. */ static void windows_stop (ptid_t ptid) @@ -1982,33 +2410,43 @@ windows_stop (ptid_t ptid) registers_changed (); /* refresh register state */ } -static int -windows_xfer_memory (CORE_ADDR memaddr, gdb_byte *our, int len, - int write, struct mem_attrib *mem, - struct target_ops *target) +/* Helper for windows_xfer_partial that handles memory transfers. + Arguments are like target_xfer_partial. */ + +static LONGEST +windows_xfer_memory (gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST memaddr, ULONGEST len) { SIZE_T done = 0; - if (write) + BOOL success; + DWORD lasterror = 0; + + if (writebuf != NULL) { - DEBUG_MEM (("gdb: write target memory, %d bytes at 0x%08lx\n", - len, (DWORD) (uintptr_t) memaddr)); - if (!WriteProcessMemory (current_process_handle, - (LPVOID) (uintptr_t) memaddr, our, - len, &done)) - done = 0; + DEBUG_MEM (("gdb: write target memory, %s bytes at %s\n", + pulongest (len), core_addr_to_string (memaddr))); + success = WriteProcessMemory (current_process_handle, + (LPVOID) (uintptr_t) memaddr, writebuf, + len, &done); + if (!success) + lasterror = GetLastError (); 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, - (LPCVOID) (uintptr_t) memaddr, our, - len, &done)) - done = 0; + DEBUG_MEM (("gdb: read target memory, %s bytes at %s\n", + pulongest (len), core_addr_to_string (memaddr))); + success = ReadProcessMemory (current_process_handle, + (LPCVOID) (uintptr_t) memaddr, readbuf, + len, &done); + if (!success) + lasterror = GetLastError (); } - return done; + if (!success && lasterror == ERROR_PARTIAL_COPY && done > 0) + return done; + else + return success ? done : TARGET_XFER_E_IO; } static void @@ -2026,13 +2464,13 @@ windows_kill_inferior (struct target_ops *ops) break; } - target_mourn_inferior (); /* or just windows_mourn_inferior? */ + target_mourn_inferior (); /* Or just windows_mourn_inferior? */ } static void -windows_prepare_to_store (struct regcache *regcache) +windows_prepare_to_store (struct target_ops *self, struct regcache *regcache) { - /* Do nothing, since we can store individual regs */ + /* Do nothing, since we can store individual regs. */ } static int @@ -2042,13 +2480,13 @@ windows_can_run (void) } static void -windows_close (int x) +windows_close (void) { DEBUG_EVENTS (("gdb: windows_close, inferior_ptid=%d\n", - PIDGET (inferior_ptid))); + ptid_get_pid (inferior_ptid))); } -/* Convert pid to printable format. */ +/* Convert pid to printable format. */ static char * windows_pid_to_str (struct target_ops *ops, ptid_t ptid) { @@ -2068,7 +2506,7 @@ static LONGEST 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) + ULONGEST offset, ULONGEST len) { struct obstack obstack; const char *buf; @@ -2081,18 +2519,21 @@ windows_xfer_shared_libraries (struct target_ops *ops, obstack_init (&obstack); obstack_grow_str (&obstack, "\n"); for (so = solib_start.next; so; so = so->next) - windows_xfer_shared_library (so->so_name, (CORE_ADDR) (uintptr_t) so->lm_info->load_addr, - target_gdbarch, &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); len_avail = strlen (buf); if (offset >= len_avail) - return 0; - - if (len > len_avail - offset) - len = len_avail - offset; - memcpy (readbuf, buf + offset, len); + len= 0; + else + { + if (len > len_avail - offset) + len = len_avail - offset; + memcpy (readbuf, buf + offset, len); + } obstack_free (&obstack, NULL); return len; @@ -2101,18 +2542,12 @@ windows_xfer_shared_libraries (struct target_ops *ops, static LONGEST 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) + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len) { switch (object) { case TARGET_OBJECT_MEMORY: - if (readbuf) - return (*ops->deprecated_xfer_memory) (offset, readbuf, - len, 0/*read*/, NULL, ops); - if (writebuf) - return (*ops->deprecated_xfer_memory) (offset, (gdb_byte *) writebuf, - len, 1/*write*/, NULL, ops); - return -1; + return windows_xfer_memory (readbuf, writebuf, offset, len); case TARGET_OBJECT_LIBRARIES: return windows_xfer_shared_libraries (ops, object, annex, readbuf, @@ -2126,6 +2561,24 @@ windows_xfer_partial (struct target_ops *ops, enum target_object object, } } +/* Provide thread local base, i.e. Thread Information Block address. + Returns 1 if ptid is found and sets *ADDR to thread_local_base. */ + +static int +windows_get_tib_address (ptid_t ptid, CORE_ADDR *addr) +{ + thread_info *th; + + th = thread_rec (ptid_get_tid (ptid), 0); + if (th == NULL) + return 0; + + if (addr != NULL) + *addr = th->thread_local_base; + + return 1; +} + static ptid_t windows_get_ada_task_ptid (long lwp, long thread) { @@ -2148,7 +2601,6 @@ init_windows_ops (void) 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; @@ -2174,13 +2626,15 @@ init_windows_ops (void) 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; + windows_ops.to_get_tib_address = windows_get_tib_address; 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_addr = cygwin_get_dr; i386_dr_low.get_status = cygwin_get_dr6; + i386_dr_low.get_control = cygwin_get_dr7; /* i386_dr_low.debug_register_length field is set by calling i386_set_debug_register_length function @@ -2195,6 +2649,9 @@ set_windows_aliases (char *argv0) add_info_alias ("dll", "sharedlibrary", 1); } +/* -Wmissing-prototypes */ +extern initialize_file_ftype _initialize_windows_nat; + void _initialize_windows_nat (void) { @@ -2202,6 +2659,10 @@ _initialize_windows_nat (void) 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.")); set_cmd_completer (c, filename_completer); @@ -2220,7 +2681,8 @@ Show use of shell to start subprocess."), NULL, NULL, /* FIXME: i18n: */ &setlist, &showlist); - add_setshow_boolean_cmd ("cygwin-exceptions", class_support, &cygwin_exceptions, _("\ + add_setshow_boolean_cmd ("cygwin-exceptions", class_support, + &cygwin_exceptions, _("\ Break when an exception is detected in the Cygwin DLL itself."), _("\ Show whether gdb breaks on exceptions in the Cygwin DLL itself."), NULL, NULL, @@ -2271,9 +2733,7 @@ Show whether to display kernel exceptions in child process."), NULL, NULL, /* FIXME: i18n: */ &setlist, &showlist); - add_prefix_cmd ("w32", class_info, info_w32_command, - _("Print information specific to Win32 debugging."), - &info_w32_cmdlist, "info w32 ", 0, &infolist); + init_w32_command_list (); add_cmd ("selector", class_info, display_selectors, _("Display selectors infos."), @@ -2309,6 +2769,14 @@ cygwin_set_dr7 (unsigned long val) debug_registers_used = 1; } +/* Get the value of debug register I from the inferior. */ + +static CORE_ADDR +cygwin_get_dr (int i) +{ + return dr[i]; +} + /* 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. */ @@ -2318,9 +2786,19 @@ cygwin_get_dr6 (void) return (unsigned long) dr[6]; } +/* Get the value of the DR7 debug status register from the inferior. + Here we just return the value stored in dr[7] by the last call to + thread_rec for current_event.dwThreadId id. */ + +static unsigned long +cygwin_get_dr7 (void) +{ + return (unsigned long) dr[7]; +} + /* Determine if the thread referenced by "ptid" is alive by "polling" it. If WaitForSingleObject returns WAIT_OBJECT_0 - it means that the thread 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 windows_thread_alive (struct target_ops *ops, ptid_t ptid) { @@ -2329,10 +2807,13 @@ windows_thread_alive (struct target_ops *ops, ptid_t ptid) 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; + return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) == WAIT_OBJECT_0 + ? FALSE : TRUE; } +/* -Wmissing-prototypes */ +extern initialize_file_ftype _initialize_check_for_gdb_ini; + void _initialize_check_for_gdb_ini (void) { @@ -2348,22 +2829,23 @@ _initialize_check_for_gdb_ini (void) sizeof ("/gdb.ini")); strcpy (oldini, homedir); p = strchr (oldini, '\0'); - if (p > oldini && p[-1] != '/') + if (p > oldini && !IS_DIR_SEPARATOR (p[-1])) *p++ = '/'; strcpy (p, "gdb.ini"); if (access (oldini, 0) == 0) { int len = strlen (oldini); char *newini = alloca (len + 1); - sprintf (newini, "%.*s.gdbinit", - (int) (len - (sizeof ("gdb.ini") - 1)), oldini); + + xsnprintf (newini, len + 1, "%.*s.gdbinit", + (int) (len - (sizeof ("gdb.ini") - 1)), oldini); warning (_("obsolete '%s' found. Rename to '%s'."), oldini, newini); } } } /* Define dummy functions which always return error for the rare cases where - these functions could not be found. */ + these functions could not be found. */ static BOOL WINAPI bad_DebugActiveProcessStop (DWORD w) { @@ -2384,11 +2866,21 @@ 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) { @@ -2401,8 +2893,27 @@ bad_OpenProcessToken (HANDLE w, DWORD x, PHANDLE y) return FALSE; } +static BOOL WINAPI +bad_GetCurrentConsoleFont (HANDLE w, BOOL bMaxWindow, CONSOLE_FONT_INFO *f) +{ + f->nFont = 0; + return 1; +} +static COORD WINAPI +bad_GetConsoleFontSize (HANDLE w, DWORD nFont) +{ + COORD size; + size.X = 8; + size.Y = 12; + return size; +} + +/* -Wmissing-prototypes */ +extern initialize_file_ftype _initialize_loadable; + /* Load any functions which may not be available in ancient versions - of Windows. */ + of Windows. */ + void _initialize_loadable (void) { @@ -2411,61 +2922,71 @@ _initialize_loadable (void) hm = LoadLibrary ("kernel32.dll"); if (hm) { - dyn_DebugActiveProcessStop = (void *) + DebugActiveProcessStop = (void *) GetProcAddress (hm, "DebugActiveProcessStop"); - dyn_DebugBreakProcess = (void *) + DebugBreakProcess = (void *) GetProcAddress (hm, "DebugBreakProcess"); - dyn_DebugSetProcessKillOnExit = (void *) + DebugSetProcessKillOnExit = (void *) GetProcAddress (hm, "DebugSetProcessKillOnExit"); + GetConsoleFontSize = (void *) + GetProcAddress (hm, "GetConsoleFontSize"); + GetCurrentConsoleFont = (void *) + GetProcAddress (hm, "GetCurrentConsoleFont"); } /* Set variables to dummy versions of these processes if the function - wasn't found in kernel32.dll. */ - if (!dyn_DebugBreakProcess) - dyn_DebugBreakProcess = bad_DebugBreakProcess; - if (!dyn_DebugActiveProcessStop || !dyn_DebugSetProcessKillOnExit) + wasn't found in kernel32.dll. */ + if (!DebugBreakProcess) + DebugBreakProcess = bad_DebugBreakProcess; + if (!DebugActiveProcessStop || !DebugSetProcessKillOnExit) { - dyn_DebugActiveProcessStop = bad_DebugActiveProcessStop; - dyn_DebugSetProcessKillOnExit = bad_DebugSetProcessKillOnExit; + DebugActiveProcessStop = bad_DebugActiveProcessStop; + DebugSetProcessKillOnExit = bad_DebugSetProcessKillOnExit; } + if (!GetConsoleFontSize) + GetConsoleFontSize = bad_GetConsoleFontSize; + if (!GetCurrentConsoleFont) + GetCurrentConsoleFont = bad_GetCurrentConsoleFont; /* Load optional functions used for retrieving filename information - associated with the currently debugged process or its dlls. */ + associated with the currently debugged process or its dlls. */ hm = LoadLibrary ("psapi.dll"); if (hm) { - dyn_EnumProcessModules = (void *) + EnumProcessModules = (void *) GetProcAddress (hm, "EnumProcessModules"); - dyn_GetModuleInformation = (void *) + GetModuleInformation = (void *) GetProcAddress (hm, "GetModuleInformation"); - dyn_GetModuleFileNameExA = (void *) - GetProcAddress (hm, "GetModuleFileNameExA"); + GetModuleFileNameEx = (void *) + GetProcAddress (hm, GetModuleFileNameEx_name); } - if (!dyn_EnumProcessModules || !dyn_GetModuleInformation || !dyn_GetModuleFileNameExA) + if (!EnumProcessModules || !GetModuleInformation || !GetModuleFileNameEx) { /* Set variables to dummy versions of these processes if the function - wasn't found in psapi.dll. */ - dyn_EnumProcessModules = bad_EnumProcessModules; - dyn_GetModuleInformation = bad_GetModuleInformation; - dyn_GetModuleFileNameExA = bad_GetModuleFileNameExA; - /* 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.")); + 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.\n\ +Use \"file\" or \"dll\" command to load executable/libraries directly.")); } hm = LoadLibrary ("advapi32.dll"); if (hm) { - dyn_OpenProcessToken = (void *) - GetProcAddress (hm, "OpenProcessToken"); - dyn_LookupPrivilegeValueA = (void *) + OpenProcessToken = (void *) GetProcAddress (hm, "OpenProcessToken"); + LookupPrivilegeValueA = (void *) GetProcAddress (hm, "LookupPrivilegeValueA"); - dyn_AdjustTokenPrivileges = (void *) + AdjustTokenPrivileges = (void *) GetProcAddress (hm, "AdjustTokenPrivileges"); /* Only need to set one of these since if OpenProcessToken fails nothing - else is needed. */ - if (!dyn_OpenProcessToken || !dyn_LookupPrivilegeValueA || !dyn_AdjustTokenPrivileges) - dyn_OpenProcessToken = bad_OpenProcessToken; + else is needed. */ + if (!OpenProcessToken || !LookupPrivilegeValueA + || !AdjustTokenPrivileges) + OpenProcessToken = bad_OpenProcessToken; } }