X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fwindows-nat.c;h=715cf602a070f7d0662e0af957ad5d2b9a3e0b95;hb=e9534bd257ac9ea2f7921e8000d27c5dc4477b4e;hp=d38ade5855b660585664e654dfb83ee16442e6f9;hpb=d4cbef22ba406707a4fcb30a7a57308447626f14;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index d38ade5855..715cf602a0 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -1,6 +1,6 @@ /* Target-vector operations for controlling windows child processes, for GDB. - Copyright (C) 1995-2019 Free Software Foundation, Inc. + Copyright (C) 1995-2020 Free Software Foundation, Inc. Contributed by Cygnus Solutions, A Red Hat Company. @@ -43,8 +43,8 @@ #include #endif #include +#include -#include "buildsym-legacy.h" #include "filenames.h" #include "symfile.h" #include "objfiles.h" @@ -67,19 +67,29 @@ #include "x86-nat.h" #include "complaints.h" #include "inf-child.h" -#include "common/gdb_tilde_expand.h" -#include "common/pathstuff.h" +#include "gdbsupport/gdb_tilde_expand.h" +#include "gdbsupport/pathstuff.h" +#include "gdbsupport/gdb_wait.h" +#include "nat/windows-nat.h" + +#define STATUS_WX86_BREAKPOINT 0x4000001F +#define STATUS_WX86_SINGLE_STEP 0x4000001E #define AdjustTokenPrivileges dyn_AdjustTokenPrivileges #define DebugActiveProcessStop dyn_DebugActiveProcessStop #define DebugBreakProcess dyn_DebugBreakProcess #define DebugSetProcessKillOnExit dyn_DebugSetProcessKillOnExit #define EnumProcessModules dyn_EnumProcessModules +#define EnumProcessModulesEx dyn_EnumProcessModulesEx #define GetModuleInformation dyn_GetModuleInformation #define LookupPrivilegeValueA dyn_LookupPrivilegeValueA #define OpenProcessToken dyn_OpenProcessToken #define GetConsoleFontSize dyn_GetConsoleFontSize #define GetCurrentConsoleFont dyn_GetCurrentConsoleFont +#define Wow64SuspendThread dyn_Wow64SuspendThread +#define Wow64GetThreadContext dyn_Wow64GetThreadContext +#define Wow64SetThreadContext dyn_Wow64SetThreadContext +#define Wow64GetThreadSelectorEntry dyn_Wow64GetThreadSelectorEntry typedef BOOL WINAPI (AdjustTokenPrivileges_ftype) (HANDLE, BOOL, PTOKEN_PRIVILEGES, @@ -100,6 +110,12 @@ typedef BOOL WINAPI (EnumProcessModules_ftype) (HANDLE, HMODULE *, DWORD, LPDWORD); static EnumProcessModules_ftype *EnumProcessModules; +#ifdef __x86_64__ +typedef BOOL WINAPI (EnumProcessModulesEx_ftype) (HANDLE, HMODULE *, DWORD, + LPDWORD, DWORD); +static EnumProcessModulesEx_ftype *EnumProcessModulesEx; +#endif + typedef BOOL WINAPI (GetModuleInformation_ftype) (HANDLE, HMODULE, LPMODULEINFO, DWORD); static GetModuleInformation_ftype *GetModuleInformation; @@ -117,6 +133,22 @@ static GetCurrentConsoleFont_ftype *GetCurrentConsoleFont; typedef COORD WINAPI (GetConsoleFontSize_ftype) (HANDLE, DWORD); static GetConsoleFontSize_ftype *GetConsoleFontSize; +#ifdef __x86_64__ +typedef DWORD WINAPI (Wow64SuspendThread_ftype) (HANDLE); +static Wow64SuspendThread_ftype *Wow64SuspendThread; + +typedef BOOL WINAPI (Wow64GetThreadContext_ftype) (HANDLE, PWOW64_CONTEXT); +static Wow64GetThreadContext_ftype *Wow64GetThreadContext; + +typedef BOOL WINAPI (Wow64SetThreadContext_ftype) (HANDLE, + const WOW64_CONTEXT *); +static Wow64SetThreadContext_ftype *Wow64SetThreadContext; + +typedef BOOL WINAPI (Wow64GetThreadSelectorEntry_ftype) (HANDLE, DWORD, + PLDT_ENTRY); +static Wow64GetThreadSelectorEntry_ftype *Wow64GetThreadSelectorEntry; +#endif + #undef STARTUPINFO #undef CreateProcess #undef GetModuleFileNameEx @@ -148,7 +180,7 @@ static GetConsoleFontSize_ftype *GetConsoleFontSize; static int have_saved_context; /* True if we've saved context from a cygwin signal. */ #ifdef __CYGWIN__ -static CONTEXT saved_context; /* Containes the saved context from a +static CONTEXT saved_context; /* Contains the saved context from a cygwin signal. */ #endif @@ -213,23 +245,7 @@ static unsigned long cygwin_get_dr7 (void); 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. */ -typedef struct windows_thread_info_struct - { - struct windows_thread_info_struct *next; - DWORD id; - HANDLE h; - CORE_ADDR thread_local_base; - char *name; - int suspended; - int reload_context; - CONTEXT context; - STACKFRAME sf; - } -windows_thread_info; - -static windows_thread_info thread_head; +static std::vector thread_list; /* The process and thread handles for the above context. */ @@ -237,25 +253,29 @@ static DEBUG_EVENT current_event; /* The current debug event from WaitForDebugEvent */ static HANDLE current_process_handle; /* Currently executing process */ static windows_thread_info *current_thread; /* Info on currently selected thread */ -static DWORD main_thread_id; /* Thread ID of the main thread */ +static EXCEPTION_RECORD siginfo_er; /* Contents of $_siginfo */ /* Counts of things. */ static int exception_count = 0; static int event_count = 0; static int saw_create; static int open_process_used = 0; +#ifdef __x86_64__ +static bool wow64_process = false; +static bool ignore_first_breakpoint = false; +#endif /* User options. */ -static int new_console = 0; +static bool new_console = false; #ifdef __CYGWIN__ -static int cygwin_exceptions = 0; +static bool cygwin_exceptions = false; #endif -static int new_group = 1; -static int debug_exec = 0; /* show execution */ -static int debug_events = 0; /* show events from kernel */ -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 */ +static bool new_group = true; +static bool debug_exec = false; /* show execution */ +static bool debug_events = false; /* show events from kernel */ +static bool debug_memory = false; /* show target memory accesses */ +static bool debug_exceptions = false; /* show target exceptions */ +static bool useshell = false; /* use shell for subprocesses */ /* This vector maps GDB's idea of a register's number into an offset in the windows exception context vector. @@ -352,6 +372,8 @@ struct windows_nat_target final : public x86_nat_target bool get_tib_address (ptid_t ptid, CORE_ADDR *addr) override; const char *thread_name (struct thread_info *) override; + + int get_windows_debug_event (int pid, struct target_waitstatus *ourstatus); }; static windows_nat_target the_windows_nat_target; @@ -359,15 +381,16 @@ static windows_nat_target the_windows_nat_target; /* Set the MAPPINGS static global to OFFSETS. See the description of MAPPINGS for more details. */ -void +static void windows_set_context_register_offsets (const int *offsets) { mappings = offsets; } -/* See windows-nat.h. */ +/* Set the function that should be used by this module to determine + whether a given register is a segment register or not. */ -void +static void windows_set_segment_register_p (segment_register_p_ftype *fun) { segment_register_p = fun; @@ -387,10 +410,8 @@ check (BOOL ok, const char *file, int line) static windows_thread_info * thread_rec (DWORD id, int get_context) { - windows_thread_info *th; - - for (th = &thread_head; (th = th->next) != NULL;) - if (th->id == id) + for (windows_thread_info *th : thread_list) + if (th->tid == id) { if (!th->suspended && get_context) { @@ -447,12 +468,15 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p) if ((th = thread_rec (id, FALSE))) return th; - th = XCNEW (windows_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; + CORE_ADDR base = (CORE_ADDR) (uintptr_t) tlb; +#ifdef __x86_64__ + /* For WOW64 processes, this is actually the pointer to the 64bit TIB, + and the 32bit TIB is exactly 2 pages after it. */ + if (wow64_process) + base += 0x2000; +#endif + th = new windows_thread_info (id, h, base); + thread_list.push_back (th); /* Add this new thread to the list of threads. @@ -460,24 +484,43 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p) the main thread silently (in reality, this thread is really more of a process to the user than a thread). */ if (main_thread_p) - add_thread_silent (ptid); + add_thread_silent (&the_windows_nat_target, ptid); else - add_thread (ptid); + add_thread (&the_windows_nat_target, 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. */ - th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; - CHECK (GetThreadContext (th->h, &th->context)); - th->context.Dr0 = dr[0]; - th->context.Dr1 = dr[1]; - th->context.Dr2 = dr[2]; - th->context.Dr3 = dr[3]; - th->context.Dr6 = DR6_CLEAR_VALUE; - th->context.Dr7 = dr[7]; - CHECK (SetThreadContext (th->h, &th->context)); - th->context.ContextFlags = 0; +#ifdef __x86_64__ + if (wow64_process) + { + /* Only change the value of the debug registers. */ + th->wow64_context.ContextFlags = CONTEXT_DEBUG_REGISTERS; + CHECK (Wow64GetThreadContext (th->h, &th->wow64_context)); + th->wow64_context.Dr0 = dr[0]; + th->wow64_context.Dr1 = dr[1]; + th->wow64_context.Dr2 = dr[2]; + th->wow64_context.Dr3 = dr[3]; + th->wow64_context.Dr6 = DR6_CLEAR_VALUE; + th->wow64_context.Dr7 = dr[7]; + CHECK (Wow64SetThreadContext (th->h, &th->wow64_context)); + th->wow64_context.ContextFlags = 0; + } + else +#endif + { + /* Only change the value of the debug registers. */ + th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; + CHECK (GetThreadContext (th->h, &th->context)); + th->context.Dr0 = dr[0]; + th->context.Dr1 = dr[1]; + th->context.Dr2 = dr[2]; + th->context.Dr3 = dr[3]; + th->context.Dr6 = DR6_CLEAR_VALUE; + th->context.Dr7 = dr[7]; + CHECK (SetThreadContext (th->h, &th->context)); + th->context.ContextFlags = 0; + } } return th; } @@ -487,17 +530,13 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p) static void windows_init_thread_list (void) { - windows_thread_info *th = &thread_head; - DEBUG_EVENTS (("gdb: windows_init_thread_list\n")); init_thread_list (); - while (th->next != NULL) - { - windows_thread_info *here = th->next; - th->next = here->next; - xfree (here); - } - thread_head.next = NULL; + + for (windows_thread_info *here : thread_list) + delete here; + + thread_list.clear (); } /* Delete a thread from the list of threads. @@ -510,7 +549,6 @@ windows_init_thread_list (void) static void windows_delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p) { - windows_thread_info *th; DWORD id; gdb_assert (ptid.tid () != 0); @@ -521,7 +559,7 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p) Note that no notification was printed when the main thread was created, and thus, unless in verbose mode, we should be - symetrical, and avoid that notification for the main thread + symmetrical, and avoid that notification for the main thread here as well. */ if (info_verbose) @@ -531,19 +569,18 @@ windows_delete_thread (ptid_t ptid, DWORD exit_code, bool main_thread_p) target_pid_to_str (ptid).c_str (), (unsigned) exit_code); - delete_thread (find_thread_ptid (ptid)); + delete_thread (find_thread_ptid (&the_windows_nat_target, ptid)); - for (th = &thread_head; - th->next != NULL && th->next->id != id; - th = th->next) - continue; + auto iter = std::find_if (thread_list.begin (), thread_list.end (), + [=] (windows_thread_info *th) + { + return th->tid == id; + }); - if (th->next != NULL) + if (iter != thread_list.end ()) { - windows_thread_info *here = th->next; - th->next = here->next; - xfree (here->name); - xfree (here); + delete *iter; + thread_list.erase (iter); } } @@ -564,7 +601,13 @@ windows_fetch_one_register (struct regcache *regcache, gdb_assert (r >= 0); gdb_assert (!th->reload_context); - char *context_offset = ((char *) &th->context) + mappings[r]; + char *context_ptr = (char *) &th->context; +#ifdef __x86_64__ + if (wow64_process) + context_ptr = (char *) &th->wow64_context; +#endif + + char *context_offset = context_ptr + mappings[r]; struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); @@ -593,8 +636,8 @@ windows_fetch_one_register (struct regcache *regcache, void windows_nat_target::fetch_registers (struct regcache *regcache, int r) { - DWORD pid = regcache->ptid ().tid (); - windows_thread_info *th = thread_rec (pid, TRUE); + DWORD tid = regcache->ptid ().tid (); + windows_thread_info *th = thread_rec (tid, TRUE); /* Check if TH exists. Windows sometimes uses a non-existent thread id in its events. */ @@ -615,6 +658,26 @@ windows_nat_target::fetch_registers (struct regcache *regcache, int r) have_saved_context = 0; } else +#endif +#ifdef __x86_64__ + if (wow64_process) + { + th->wow64_context.ContextFlags = CONTEXT_DEBUGGER_DR; + CHECK (Wow64GetThreadContext (th->h, &th->wow64_context)); + /* Copy dr values from that thread. + But only if there were not modified since last stop. + PR gdb/2388 */ + if (!debug_registers_changed) + { + dr[0] = th->wow64_context.Dr0; + dr[1] = th->wow64_context.Dr1; + dr[2] = th->wow64_context.Dr2; + dr[3] = th->wow64_context.Dr3; + dr[6] = th->wow64_context.Dr6; + dr[7] = th->wow64_context.Dr7; + } + } + else #endif { th->context.ContextFlags = CONTEXT_DEBUGGER_DR; @@ -654,7 +717,13 @@ windows_store_one_register (const struct regcache *regcache, { gdb_assert (r >= 0); - regcache->raw_collect (r, ((char *) &th->context) + mappings[r]); + char *context_ptr = (char *) &th->context; +#ifdef __x86_64__ + if (wow64_process) + context_ptr = (char *) &th->wow64_context; +#endif + + regcache->raw_collect (r, context_ptr + mappings[r]); } /* Store a new register value into the context of the thread tied to @@ -663,8 +732,8 @@ windows_store_one_register (const struct regcache *regcache, void windows_nat_target::store_registers (struct regcache *regcache, int r) { - DWORD pid = regcache->ptid ().tid (); - windows_thread_info *th = thread_rec (pid, TRUE); + DWORD tid = regcache->ptid ().tid (); + windows_thread_info *th = thread_rec (tid, TRUE); /* Check if TH exists. Windows sometimes uses a non-existent thread id in its events. */ @@ -678,23 +747,11 @@ windows_nat_target::store_registers (struct regcache *regcache, int r) windows_store_one_register (regcache, th, r); } -/* Encapsulate the information required in a call to - symbol_file_add_args. */ -struct safe_symbol_file_add_args -{ - char *name; - int from_tty; - section_addr_info *addrs; - int mainline; - int flags; - struct ui_file *err, *out; - struct objfile *ret; -}; - /* Maintain a linked list of "so" information. */ struct lm_info_windows : public lm_info_base { LPVOID load_addr = 0; + CORE_ADDR text_offset = 0; }; static struct so_list solib_start, *solib_end; @@ -795,8 +852,7 @@ windows_make_so (const char *name, LPVOID load_addr) 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.get (), - text); + cygwin_load_end = cygwin_load_start + bfd_section_size (text); } #endif @@ -943,22 +999,28 @@ handle_unload_dll () static void catch_errors (void (*func) ()) { - TRY + try { func (); } - CATCH (ex, RETURN_MASK_ALL) + catch (const gdb_exception &ex) { exception_print (gdb_stderr, ex); } - END_CATCH } /* Clear list of loaded DLLs. */ static void windows_clear_solib (void) { - solib_start.next = NULL; + struct so_list *so; + + for (so = solib_start.next; so; so = solib_start.next) + { + solib_start.next = so->next; + windows_free_so (so); + } + solib_end = &solib_start; } @@ -1031,7 +1093,7 @@ handle_output_debug_string (struct target_waitstatus *ourstatus) ourstatus->kind = TARGET_WAITKIND_STOPPED; retval = strtoul (p, &p, 0); if (!retval) - retval = main_thread_id; + retval = current_event.dwThreadId; else if ((x = (LPCVOID) (uintptr_t) strtoull (p, NULL, 0)) && ReadProcessMemory (current_process_handle, x, &saved_context, @@ -1049,7 +1111,14 @@ static int display_selector (HANDLE thread, DWORD sel) { LDT_ENTRY info; - if (GetThreadSelectorEntry (thread, sel, &info)) + BOOL ret; +#ifdef __x86_64__ + if (wow64_process) + ret = Wow64GetThreadSelectorEntry (thread, sel, &info); + else +#endif + ret = GetThreadSelectorEntry (thread, sel, &info); + if (ret) { int base, limit; printf_filtered ("0x%03x: ", (unsigned) sel); @@ -1096,14 +1165,16 @@ display_selector (HANDLE thread, DWORD sel) puts_filtered ("Code (Exec/Read, Conf"); break; default: - printf_filtered ("Unknown type 0x%lx",info.HighWord.Bits.Type); + printf_filtered ("Unknown type 0x%lx", + (unsigned long) info.HighWord.Bits.Type); } if ((info.HighWord.Bits.Type & 0x1) == 0) puts_filtered(", N.Acc"); puts_filtered (")\n"); if ((info.HighWord.Bits.Type & 0x10) == 0) puts_filtered("System selector "); - printf_filtered ("Priviledge level = %ld. ", info.HighWord.Bits.Dpl); + printf_filtered ("Priviledge level = %ld. ", + (unsigned long) info.HighWord.Bits.Dpl); if (info.HighWord.Bits.Granularity) puts_filtered ("Page granular.\n"); else @@ -1131,25 +1202,50 @@ display_selectors (const char * args, int from_tty) } if (!args) { - - puts_filtered ("Selector $cs\n"); - display_selector (current_thread->h, - current_thread->context.SegCs); - puts_filtered ("Selector $ds\n"); - display_selector (current_thread->h, - current_thread->context.SegDs); - puts_filtered ("Selector $es\n"); - display_selector (current_thread->h, - current_thread->context.SegEs); - puts_filtered ("Selector $ss\n"); - display_selector (current_thread->h, - current_thread->context.SegSs); - puts_filtered ("Selector $fs\n"); - display_selector (current_thread->h, - current_thread->context.SegFs); - puts_filtered ("Selector $gs\n"); - display_selector (current_thread->h, - current_thread->context.SegGs); +#ifdef __x86_64__ + if (wow64_process) + { + puts_filtered ("Selector $cs\n"); + display_selector (current_thread->h, + current_thread->wow64_context.SegCs); + puts_filtered ("Selector $ds\n"); + display_selector (current_thread->h, + current_thread->wow64_context.SegDs); + puts_filtered ("Selector $es\n"); + display_selector (current_thread->h, + current_thread->wow64_context.SegEs); + puts_filtered ("Selector $ss\n"); + display_selector (current_thread->h, + current_thread->wow64_context.SegSs); + puts_filtered ("Selector $fs\n"); + display_selector (current_thread->h, + current_thread->wow64_context.SegFs); + puts_filtered ("Selector $gs\n"); + display_selector (current_thread->h, + current_thread->wow64_context.SegGs); + } + else +#endif + { + puts_filtered ("Selector $cs\n"); + display_selector (current_thread->h, + current_thread->context.SegCs); + puts_filtered ("Selector $ds\n"); + display_selector (current_thread->h, + current_thread->context.SegDs); + puts_filtered ("Selector $es\n"); + display_selector (current_thread->h, + current_thread->context.SegEs); + puts_filtered ("Selector $ss\n"); + display_selector (current_thread->h, + current_thread->context.SegSs); + puts_filtered ("Selector $fs\n"); + display_selector (current_thread->h, + current_thread->context.SegFs); + puts_filtered ("Selector $gs\n"); + display_selector (current_thread->h, + current_thread->context.SegGs); + } } else { @@ -1172,6 +1268,8 @@ handle_exception (struct target_waitstatus *ourstatus) DWORD code = rec->ExceptionCode; handle_exception_result result = HANDLE_EXCEPTION_HANDLED; + memcpy (&siginfo_er, rec, sizeof siginfo_er); + ourstatus->kind = TARGET_WAITKIND_STOPPED; /* Record the context of the current thread. */ @@ -1248,6 +1346,19 @@ handle_exception (struct target_waitstatus *ourstatus) ourstatus->value.sig = GDB_SIGNAL_FPE; break; case EXCEPTION_BREAKPOINT: +#ifdef __x86_64__ + if (ignore_first_breakpoint) + { + /* For WOW64 processes, there are always 2 breakpoint exceptions + on startup, first a BREAKPOINT for the 64bit ntdll.dll, + then a WX86_BREAKPOINT for the 32bit ntdll.dll. + Here we only care about the WX86_BREAKPOINT's. */ + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + ignore_first_breakpoint = false; + } +#endif + /* FALLTHROUGH */ + case STATUS_WX86_BREAKPOINT: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT"); ourstatus->value.sig = GDB_SIGNAL_TRAP; break; @@ -1260,6 +1371,7 @@ handle_exception (struct target_waitstatus *ourstatus) ourstatus->value.sig = GDB_SIGNAL_INT; break; case EXCEPTION_SINGLE_STEP: + case STATUS_WX86_SINGLE_STEP: DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP"); ourstatus->value.sig = GDB_SIGNAL_TRAP; break; @@ -1335,7 +1447,6 @@ handle_exception (struct target_waitstatus *ourstatus) static BOOL windows_continue (DWORD continue_status, int id, int killed) { - windows_thread_info *th; BOOL res; DEBUG_EVENTS (("ContinueDebugEvent (cpid=%d, ctid=0x%x, %s);\n", @@ -1344,33 +1455,66 @@ windows_continue (DWORD continue_status, int id, int killed) continue_status == DBG_CONTINUE ? "DBG_CONTINUE" : "DBG_EXCEPTION_NOT_HANDLED")); - for (th = &thread_head; (th = th->next) != NULL;) - if ((id == -1 || id == (int) th->id) + for (windows_thread_info *th : thread_list) + if ((id == -1 || id == (int) th->tid) && th->suspended) { - if (debug_registers_changed) +#ifdef __x86_64__ + if (wow64_process) { - th->context.ContextFlags |= CONTEXT_DEBUG_REGISTERS; - th->context.Dr0 = dr[0]; - th->context.Dr1 = dr[1]; - th->context.Dr2 = dr[2]; - th->context.Dr3 = dr[3]; - th->context.Dr6 = DR6_CLEAR_VALUE; - th->context.Dr7 = dr[7]; + if (debug_registers_changed) + { + th->wow64_context.ContextFlags |= CONTEXT_DEBUG_REGISTERS; + th->wow64_context.Dr0 = dr[0]; + th->wow64_context.Dr1 = dr[1]; + th->wow64_context.Dr2 = dr[2]; + th->wow64_context.Dr3 = dr[3]; + th->wow64_context.Dr6 = DR6_CLEAR_VALUE; + th->wow64_context.Dr7 = dr[7]; + } + if (th->wow64_context.ContextFlags) + { + DWORD ec = 0; + + if (GetExitCodeThread (th->h, &ec) + && ec == STILL_ACTIVE) + { + BOOL status = Wow64SetThreadContext (th->h, + &th->wow64_context); + + if (!killed) + CHECK (status); + } + th->wow64_context.ContextFlags = 0; + } } - if (th->context.ContextFlags) + else +#endif { - DWORD ec = 0; - - if (GetExitCodeThread (th->h, &ec) - && ec == STILL_ACTIVE) + if (debug_registers_changed) { - BOOL status = SetThreadContext (th->h, &th->context); + th->context.ContextFlags |= CONTEXT_DEBUG_REGISTERS; + th->context.Dr0 = dr[0]; + th->context.Dr1 = dr[1]; + th->context.Dr2 = dr[2]; + th->context.Dr3 = dr[3]; + th->context.Dr6 = DR6_CLEAR_VALUE; + th->context.Dr7 = dr[7]; + } + if (th->context.ContextFlags) + { + DWORD ec = 0; - if (!killed) - CHECK (status); + if (GetExitCodeThread (th->h, &ec) + && ec == STILL_ACTIVE) + { + BOOL status = SetThreadContext (th->h, &th->context); + + if (!killed) + CHECK (status); + } + th->context.ContextFlags = 0; } - th->context.ContextFlags = 0; } if (th->suspended > 0) (void) ResumeThread (th->h); @@ -1405,14 +1549,13 @@ fake_create_process (void) (unsigned) GetLastError ()); /* We can not debug anything in that case. */ } - main_thread_id = current_event.dwThreadId; current_thread = windows_add_thread (ptid_t (current_event.dwProcessId, 0, current_event.dwThreadId), current_event.u.CreateThread.hThread, current_event.u.CreateThread.lpThreadLocalBase, true /* main_thread_p */); - return main_thread_id; + return current_event.dwThreadId; } void @@ -1464,35 +1607,66 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) last_sig = GDB_SIGNAL_0; - DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=%ld, step=%d, sig=%d);\n", - ptid.pid (), ptid.tid (), step, sig)); + DEBUG_EXEC (("gdb: windows_resume (pid=%d, tid=0x%x, step=%d, sig=%d);\n", + ptid.pid (), (unsigned) ptid.tid (), step, sig)); /* Get context for currently selected thread. */ th = thread_rec (inferior_ptid.tid (), FALSE); if (th) { - if (step) +#ifdef __x86_64__ + if (wow64_process) { - /* Single step by setting t bit. */ - struct regcache *regcache = get_current_regcache (); - struct gdbarch *gdbarch = regcache->arch (); - fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); - th->context.EFlags |= FLAG_TRACE_BIT; - } + if (step) + { + /* Single step by setting t bit. */ + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = regcache->arch (); + fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); + th->wow64_context.EFlags |= FLAG_TRACE_BIT; + } - if (th->context.ContextFlags) + if (th->wow64_context.ContextFlags) + { + if (debug_registers_changed) + { + th->wow64_context.Dr0 = dr[0]; + th->wow64_context.Dr1 = dr[1]; + th->wow64_context.Dr2 = dr[2]; + th->wow64_context.Dr3 = dr[3]; + th->wow64_context.Dr6 = DR6_CLEAR_VALUE; + th->wow64_context.Dr7 = dr[7]; + } + CHECK (Wow64SetThreadContext (th->h, &th->wow64_context)); + th->wow64_context.ContextFlags = 0; + } + } + else +#endif { - if (debug_registers_changed) + if (step) { - th->context.Dr0 = dr[0]; - th->context.Dr1 = dr[1]; - th->context.Dr2 = dr[2]; - th->context.Dr3 = dr[3]; - th->context.Dr6 = DR6_CLEAR_VALUE; - th->context.Dr7 = dr[7]; + /* Single step by setting t bit. */ + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = regcache->arch (); + fetch_registers (regcache, gdbarch_ps_regnum (gdbarch)); + th->context.EFlags |= FLAG_TRACE_BIT; + } + + if (th->context.ContextFlags) + { + if (debug_registers_changed) + { + th->context.Dr0 = dr[0]; + th->context.Dr1 = dr[1]; + th->context.Dr2 = dr[2]; + th->context.Dr3 = dr[3]; + th->context.Dr6 = DR6_CLEAR_VALUE; + th->context.Dr7 = dr[7]; + } + CHECK (SetThreadContext (th->h, &th->context)); + th->context.ContextFlags = 0; } - CHECK (SetThreadContext (th->h, &th->context)); - th->context.ContextFlags = 0; } } @@ -1533,14 +1707,15 @@ ctrl_c_handler (DWORD event_type) /* Get the next event from the child. Returns a non-zero thread id if the event requires handling by WFI (or whatever). */ -static int -get_windows_debug_event (struct target_ops *ops, - int pid, struct target_waitstatus *ourstatus) + +int +windows_nat_target::get_windows_debug_event (int pid, + struct target_waitstatus *ourstatus) { BOOL debug_event; DWORD continue_status, event_code; windows_thread_info *th; - static windows_thread_info dummy_thread_info; + static windows_thread_info dummy_thread_info (0, 0, 0); DWORD thread_id = 0; last_sig = GDB_SIGNAL_0; @@ -1565,8 +1740,7 @@ get_windows_debug_event (struct target_ops *ops, "CREATE_THREAD_DEBUG_EVENT")); if (saw_create != 1) { - struct inferior *inf; - inf = find_inferior_pid (current_event.dwProcessId); + inferior *inf = find_inferior_pid (this, current_event.dwProcessId); if (!saw_create && inf->attach_flag) { /* Kludge around a Windows bug where first event is a create @@ -1610,7 +1784,6 @@ get_windows_debug_event (struct target_ops *ops, break; current_process_handle = current_event.u.CreateProcessInfo.hProcess; - main_thread_id = current_event.dwThreadId; /* Add the main thread. */ th = windows_add_thread (ptid_t (current_event.dwProcessId, 0, @@ -1636,11 +1809,26 @@ get_windows_debug_event (struct target_ops *ops, else if (saw_create == 1) { windows_delete_thread (ptid_t (current_event.dwProcessId, 0, - main_thread_id), + current_event.dwThreadId), 0, true /* main_thread_p */); - ourstatus->kind = TARGET_WAITKIND_EXITED; - ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode; - thread_id = main_thread_id; + DWORD exit_status = current_event.u.ExitProcess.dwExitCode; + /* If the exit status looks like a fatal exception, but we + don't recognize the exception's code, make the original + exit status value available, to avoid losing + information. */ + int exit_signal + = WIFSIGNALED (exit_status) ? WTERMSIG (exit_status) : -1; + if (exit_signal == -1) + { + ourstatus->kind = TARGET_WAITKIND_EXITED; + ourstatus->value.integer = exit_status; + } + else + { + ourstatus->kind = TARGET_WAITKIND_SIGNALLED; + ourstatus->value.sig = gdb_signal_from_host (exit_signal); + } + thread_id = current_event.dwThreadId; } break; @@ -1655,7 +1843,7 @@ get_windows_debug_event (struct target_ops *ops, catch_errors (handle_load_dll); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.integer = 0; - thread_id = main_thread_id; + thread_id = current_event.dwThreadId; break; case UNLOAD_DLL_DEBUG_EVENT: @@ -1668,7 +1856,7 @@ get_windows_debug_event (struct target_ops *ops, catch_errors (handle_unload_dll); ourstatus->kind = TARGET_WAITKIND_LOADED; ourstatus->value.integer = 0; - thread_id = main_thread_id; + thread_id = current_event.dwThreadId; break; case EXCEPTION_DEBUG_EVENT: @@ -1774,7 +1962,7 @@ windows_nat_target::wait (ptid_t ptid, struct target_waitstatus *ourstatus, 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 (this, pid, ourstatus); + retval = get_windows_debug_event (pid, ourstatus); SetConsoleCtrlHandler (&ctrl_c_handler, FALSE); if (retval) @@ -1803,28 +1991,82 @@ windows_add_all_dlls (void) HMODULE *hmodules; int i; - if (EnumProcessModules (current_process_handle, &dummy_hmodule, - sizeof (HMODULE), &cb_needed) == 0) - return; +#ifdef __x86_64__ + if (wow64_process) + { + if (EnumProcessModulesEx (current_process_handle, &dummy_hmodule, + sizeof (HMODULE), &cb_needed, + LIST_MODULES_32BIT) == 0) + return; + } + else +#endif + { + 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; +#ifdef __x86_64__ + if (wow64_process) + { + if (EnumProcessModulesEx (current_process_handle, hmodules, + cb_needed, &cb_needed, + LIST_MODULES_32BIT) == 0) + return; + } + else +#endif + { + if (EnumProcessModules (current_process_handle, hmodules, + cb_needed, &cb_needed) == 0) + return; + } + + char system_dir[__PMAX]; + char syswow_dir[__PMAX]; + size_t system_dir_len = 0; + bool convert_syswow_dir = false; +#ifdef __x86_64__ + if (wow64_process) +#endif + { + /* This fails on 32bit Windows because it has no SysWOW64 directory, + and in this case a path conversion isn't necessary. */ + UINT len = GetSystemWow64DirectoryA (syswow_dir, sizeof (syswow_dir)); + if (len > 0) + { + /* Check that we have passed a large enough buffer. */ + gdb_assert (len < sizeof (syswow_dir)); + + len = GetSystemDirectoryA (system_dir, sizeof (system_dir)); + /* Error check. */ + gdb_assert (len != 0); + /* Check that we have passed a large enough buffer. */ + gdb_assert (len < sizeof (system_dir)); + + strcat (system_dir, "\\"); + strcat (syswow_dir, "\\"); + system_dir_len = strlen (system_dir); + + convert_syswow_dir = true; + } + } for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++) { MODULEINFO mi; #ifdef __USEWIDE wchar_t dll_name[__PMAX]; - char name[__PMAX]; + char dll_name_mb[__PMAX]; #else char dll_name[__PMAX]; - char *name; #endif + const char *name; if (GetModuleInformation (current_process_handle, hmodules[i], &mi, sizeof (mi)) == 0) continue; @@ -1832,10 +2074,23 @@ windows_add_all_dlls (void) dll_name, sizeof (dll_name)) == 0) continue; #ifdef __USEWIDE - wcstombs (name, dll_name, __PMAX); + wcstombs (dll_name_mb, dll_name, __PMAX); + name = dll_name_mb; #else name = dll_name; #endif + /* Convert the DLL path of 32bit processes returned by + GetModuleFileNameEx from the 64bit system directory to the + 32bit syswow64 directory if necessary. */ + std::string syswow_dll_path; + if (convert_syswow_dir + && strncasecmp (name, system_dir, system_dir_len) == 0 + && strchr (name + system_dir_len, '\\') == nullptr) + { + syswow_dll_path = syswow_dir; + syswow_dll_path += name + system_dir_len; + name = syswow_dll_path.c_str(); + } solib_end->next = windows_make_so (name, mi.lpBaseOfDll); solib_end = solib_end->next; @@ -1868,6 +2123,21 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching) clear_proceed_status (0); init_wait_for_inferior (); +#ifdef __x86_64__ + ignore_first_breakpoint = !attaching && wow64_process; + + if (!wow64_process) + { + windows_set_context_register_offsets (amd64_mappings); + windows_set_segment_register_p (amd64_windows_segment_register_p); + } + else +#endif + { + windows_set_context_register_offsets (i386_mappings); + windows_set_segment_register_p (i386_windows_segment_register_p); + } + inf = current_inferior (); inferior_appeared (inf, pid); inf->attach_flag = attaching; @@ -2001,13 +2271,14 @@ windows_nat_target::attach (const char *args, int from_tty) #endif if (!ok) - error (_("Can't attach to process.")); + error (_("Can't attach to process %u (error %u)"), + (unsigned) pid, (unsigned) GetLastError ()); DebugSetProcessKillOnExit (FALSE); if (from_tty) { - char *exec_file = (char *) get_exec_file (0); + const char *exec_file = get_exec_file (0); if (exec_file) printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, @@ -2017,6 +2288,17 @@ windows_nat_target::attach (const char *args, int from_tty) target_pid_to_str (ptid_t (pid)).c_str ()); } +#ifdef __x86_64__ + HANDLE h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid); + if (h != NULL) + { + BOOL wow64; + if (IsWow64Process (h, &wow64)) + wow64_process = wow64; + CloseHandle (h); + } +#endif + do_initial_windows_stuff (this, pid, 1); target_terminal::ours (); } @@ -2071,9 +2353,21 @@ windows_get_exec_module_filename (char *exe_name_ret, size_t exe_name_max_len) DWORD cbNeeded; cbNeeded = 0; - if (!EnumProcessModules (current_process_handle, &dh_buf, - sizeof (HMODULE), &cbNeeded) || !cbNeeded) - return 0; +#ifdef __x86_64__ + if (wow64_process) + { + if (!EnumProcessModulesEx (current_process_handle, &dh_buf, + sizeof (HMODULE), &cbNeeded, + LIST_MODULES_32BIT) || !cbNeeded) + return 0; + } + else +#endif + { + if (!EnumProcessModules (current_process_handle, &dh_buf, + sizeof (HMODULE), &cbNeeded) || !cbNeeded) + return 0; + } /* We know the executable is always first in the list of modules, which we just fetched. So no need to fetch more. */ @@ -2727,7 +3021,7 @@ windows_nat_target::create_inferior (const char *exec_file, redirect_inferior_handles (allargs, allargs_copy, &fd_inp, &fd_out, &fd_err); if (errno) - warning (_("Error in redirection: %s."), strerror (errno)); + warning (_("Error in redirection: %s."), safe_strerror (errno)); else errno = e; allargs_len = strlen (allargs_copy); @@ -2831,6 +3125,12 @@ windows_nat_target::create_inferior (const char *exec_file, error (_("Error creating process %s, (error %u)."), exec_file, (unsigned) GetLastError ()); +#ifdef __x86_64__ + BOOL wow64; + if (IsWow64Process (pi.hProcess, &wow64)) + wow64_process = wow64; +#endif + CloseHandle (pi.hThread); CloseHandle (pi.hProcess); @@ -2854,6 +3154,7 @@ windows_nat_target::mourn_inferior () CHECK (CloseHandle (current_process_handle)); open_process_used = 0; } + siginfo_er.ExceptionCode = 0; inf_child_target::mourn_inferior (); } @@ -2966,6 +3267,7 @@ windows_xfer_shared_libraries (struct target_ops *ops, windows_xfer_shared_library (so->so_name, (CORE_ADDR) (uintptr_t) li->load_addr, + &li->text_offset, target_gdbarch (), &obstack); } obstack_grow_str0 (&obstack, "\n"); @@ -2986,6 +3288,51 @@ windows_xfer_shared_libraries (struct target_ops *ops, return len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF; } +/* Helper for windows_nat_target::xfer_partial that handles signal info. */ + +static enum target_xfer_status +windows_xfer_siginfo (gdb_byte *readbuf, ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) +{ + char *buf = (char *) &siginfo_er; + size_t bufsize = sizeof (siginfo_er); + +#ifdef __x86_64__ + EXCEPTION_RECORD32 er32; + if (wow64_process) + { + buf = (char *) &er32; + bufsize = sizeof (er32); + + er32.ExceptionCode = siginfo_er.ExceptionCode; + er32.ExceptionFlags = siginfo_er.ExceptionFlags; + er32.ExceptionRecord = (uintptr_t) siginfo_er.ExceptionRecord; + er32.ExceptionAddress = (uintptr_t) siginfo_er.ExceptionAddress; + er32.NumberParameters = siginfo_er.NumberParameters; + int i; + for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++) + er32.ExceptionInformation[i] = siginfo_er.ExceptionInformation[i]; + } +#endif + + if (siginfo_er.ExceptionCode == 0) + return TARGET_XFER_E_IO; + + if (readbuf == nullptr) + return TARGET_XFER_E_IO; + + if (offset > bufsize) + return TARGET_XFER_E_IO; + + if (offset + len > bufsize) + len = bufsize - offset; + + memcpy (readbuf, buf + offset, len); + *xfered_len = len; + + return TARGET_XFER_OK; +} + enum target_xfer_status windows_nat_target::xfer_partial (enum target_object object, const char *annex, gdb_byte *readbuf, @@ -3001,6 +3348,9 @@ windows_nat_target::xfer_partial (enum target_object object, return windows_xfer_shared_libraries (this, object, annex, readbuf, writebuf, offset, len, xfered_len); + case TARGET_OBJECT_SIGNAL_INFO: + return windows_xfer_siginfo (readbuf, offset, len, xfered_len); + default: if (beneath () == NULL) { @@ -3048,8 +3398,9 @@ windows_nat_target::thread_name (struct thread_info *thr) } +void _initialize_windows_nat (); void -_initialize_windows_nat (void) +_initialize_windows_nat () { x86_dr_low.set_control = cygwin_set_dr7; x86_dr_low.set_addr = cygwin_set_dr; @@ -3210,8 +3561,9 @@ windows_nat_target::thread_alive (ptid_t ptid) return WaitForSingleObject (thread_rec (tid, FALSE)->h, 0) != WAIT_OBJECT_0; } +void _initialize_check_for_gdb_ini (); void -_initialize_check_for_gdb_ini (void) +_initialize_check_for_gdb_ini () { char *homedir; if (inhibit_gdbinit) @@ -3307,8 +3659,9 @@ bad_GetConsoleFontSize (HANDLE w, DWORD nFont) /* Load any functions which may not be available in ancient versions of Windows. */ +void _initialize_loadable (); void -_initialize_loadable (void) +_initialize_loadable () { HMODULE hm = NULL; @@ -3324,6 +3677,12 @@ _initialize_loadable (void) GPA (hm, GetConsoleFontSize); GPA (hm, DebugActiveProcessStop); GPA (hm, GetCurrentConsoleFont); +#ifdef __x86_64__ + GPA (hm, Wow64SuspendThread); + GPA (hm, Wow64GetThreadContext); + GPA (hm, Wow64SetThreadContext); + GPA (hm, Wow64GetThreadSelectorEntry); +#endif } /* Set variables to dummy versions of these processes if the function @@ -3346,6 +3705,9 @@ _initialize_loadable (void) if (hm) { GPA (hm, EnumProcessModules); +#ifdef __x86_64__ + GPA (hm, EnumProcessModulesEx); +#endif GPA (hm, GetModuleInformation); GetModuleFileNameEx = (GetModuleFileNameEx_ftype *) GetProcAddress (hm, GetModuleFileNameEx_name);