From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2111) id 0C318395C86E; Thu, 30 Apr 2020 16:35:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0C318395C86E Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Hannes Domani To: gdb-cvs@sourceware.org Subject: [binutils-gdb] Implement debugging of WOW64 processes in gdbserver X-Act-Checkin: binutils-gdb X-Git-Author: Hannes Domani X-Git-Refname: refs/heads/master X-Git-Oldrev: ee9d1e5f76033cd8432713a76381ade76697df04 X-Git-Newrev: 7d186bc04245c5757f396c2d4f8f89f24818628e Message-Id: <20200430163527.0C318395C86E@sourceware.org> Date: Thu, 30 Apr 2020 16:35:27 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 30 Apr 2020 16:35:27 -0000 https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7d186bc04245c5757f396c2d4f8f89f24818628e commit 7d186bc04245c5757f396c2d4f8f89f24818628e Author: Hannes Domani Date: Fri Apr 24 17:23:59 2020 +0200 Implement debugging of WOW64 processes in gdbserver gdbserver/ChangeLog: 2020-04-30 Hannes Domani * configure.srv (srv_tgtobj): Add arch/i386.o. * win32-arm-low.cc (arm_num_regs): New function. (struct win32_target_ops): Use arm_num_regs. * win32-i386-low.cc (win32_get_current_dr): Adapt for WOW64 processes. (i386_get_thread_context): Likewise. (i386_prepare_to_resume): Likewise. (i386_thread_added): Likewise. (i386_single_step): Likewise. (i386_fetch_inferior_register): Likewise. (i386_store_inferior_register): Likewise. (i386_arch_setup): Likewise. (i386_win32_num_regs): New function. (struct win32_target_ops): Use i386_win32_num_regs. * win32-low.cc (win32_get_thread_context): Adapt for WOW64 processes. (win32_require_context): Likewise. (child_add_thread): Likewise. (do_initial_child_stuff): Likewise. (continue_one_thread): Likewise. (win32_process_target::resume): Likewise. (load_psapi): Likewise. (win32_add_all_dlls): Likewise. (maybe_adjust_pc): Likewise. (win32_process_target::qxfer_siginfo): Likewise. (initialize_low): Likewise. * win32-low.h (struct win32_target_ops): Change num_regs to callback function. Diff: --- gdbserver/ChangeLog | 32 ++++++ gdbserver/configure.srv | 4 +- gdbserver/win32-arm-low.cc | 10 +- gdbserver/win32-i386-low.cc | 171 +++++++++++++++++++++++++------ gdbserver/win32-low.cc | 239 +++++++++++++++++++++++++++++++++++++++----- gdbserver/win32-low.h | 10 +- 6 files changed, 404 insertions(+), 62 deletions(-) diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog index 3b5fd99de14..4853463d05d 100644 --- a/gdbserver/ChangeLog +++ b/gdbserver/ChangeLog @@ -1,3 +1,35 @@ +2020-04-30 Hannes Domani + + * configure.srv (srv_tgtobj): + Add arch/i386.o. + * win32-arm-low.cc (arm_num_regs): New function. + (struct win32_target_ops): Use arm_num_regs. + * win32-i386-low.cc (win32_get_current_dr): Adapt for WOW64 + processes. + (i386_get_thread_context): Likewise. + (i386_prepare_to_resume): Likewise. + (i386_thread_added): Likewise. + (i386_single_step): Likewise. + (i386_fetch_inferior_register): Likewise. + (i386_store_inferior_register): Likewise. + (i386_arch_setup): Likewise. + (i386_win32_num_regs): New function. + (struct win32_target_ops): Use i386_win32_num_regs. + * win32-low.cc (win32_get_thread_context): Adapt for WOW64 + processes. + (win32_require_context): Likewise. + (child_add_thread): Likewise. + (do_initial_child_stuff): Likewise. + (continue_one_thread): Likewise. + (win32_process_target::resume): Likewise. + (load_psapi): Likewise. + (win32_add_all_dlls): Likewise. + (maybe_adjust_pc): Likewise. + (win32_process_target::qxfer_siginfo): Likewise. + (initialize_low): Likewise. + * win32-low.h (struct win32_target_ops): Change num_regs to + callback function. + 2020-04-27 Simon Marchi * configure.ac: Remove check for fs_base/gs_base in diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv index 7acf229fbef..9a027e44af6 100644 --- a/gdbserver/configure.srv +++ b/gdbserver/configure.srv @@ -397,14 +397,14 @@ case "${gdbserver_host}" in srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o" srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o" srv_tgtobj="${srv_tgtobj} nat/windows-nat.o" - srv_tgtobj="${srv_tgtobj} arch/amd64.o" + srv_tgtobj="${srv_tgtobj} arch/amd64.o arch/i386.o" srv_mingw=yes ;; x86_64-*-cygwin*) srv_regobj="" srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o" srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o" srv_tgtobj="${srv_tgtobj} nat/windows-nat.o" - srv_tgtobj="${srv_tgtobj} arch/amd64.o" + srv_tgtobj="${srv_tgtobj} arch/amd64.o arch/i386.o" ;; xtensa*-*-linux*) srv_regobj=reg-xtensa.o diff --git a/gdbserver/win32-arm-low.cc b/gdbserver/win32-arm-low.cc index 238ee4b05be..aacf2cdf8cd 100644 --- a/gdbserver/win32-arm-low.cc +++ b/gdbserver/win32-arm-low.cc @@ -111,6 +111,14 @@ arm_arch_setup (void) win32_tdesc = tdesc_arm; } +/* Implement win32_target_ops "num_regs" method. */ + +static int +arm_num_regs (void) +{ + return sizeof (mappings) / sizeof (mappings[0]), +} + /* Correct in either endianness. We do not support Thumb yet. */ static const unsigned long arm_wince_breakpoint = 0xe6000010; #define arm_wince_breakpoint_len 4 @@ -138,7 +146,7 @@ arm_win32_set_pc (struct regcache *regcache, CORE_ADDR pc) struct win32_target_ops the_low_target = { arm_arch_setup, - sizeof (mappings) / sizeof (mappings[0]), + arm_num_regs, NULL, /* initial_stuff */ arm_get_thread_context, NULL, /* prepare_to_resume */ diff --git a/gdbserver/win32-i386-low.cc b/gdbserver/win32-i386-low.cc index 48893af33b2..389ec492847 100644 --- a/gdbserver/win32-i386-low.cc +++ b/gdbserver/win32-i386-low.cc @@ -80,18 +80,40 @@ win32_get_current_dr (int dr) win32_require_context (th); +#ifdef __x86_64__ +#define RET_DR(DR) \ + case DR: \ + return th->wow64_context.Dr ## DR + + if (wow64_process) + { + switch (dr) + { + RET_DR (0); + RET_DR (1); + RET_DR (2); + RET_DR (3); + RET_DR (6); + RET_DR (7); + } + } + else +#undef RET_DR +#endif #define RET_DR(DR) \ case DR: \ return th->context.Dr ## DR - switch (dr) { - RET_DR (0); - RET_DR (1); - RET_DR (2); - RET_DR (3); - RET_DR (6); - RET_DR (7); + switch (dr) + { + RET_DR (0); + RET_DR (1); + RET_DR (2); + RET_DR (3); + RET_DR (6); + RET_DR (7); + } } #undef RET_DR @@ -219,12 +241,27 @@ i386_get_thread_context (windows_thread_info *th) static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS; again: - th->context.ContextFlags = (CONTEXT_FULL - | CONTEXT_FLOATING_POINT - | CONTEXT_DEBUG_REGISTERS - | extended_registers); +#ifdef __x86_64__ + if (wow64_process) + th->wow64_context.ContextFlags = (CONTEXT_FULL + | CONTEXT_FLOATING_POINT + | CONTEXT_DEBUG_REGISTERS + | extended_registers); + else +#endif + th->context.ContextFlags = (CONTEXT_FULL + | CONTEXT_FLOATING_POINT + | CONTEXT_DEBUG_REGISTERS + | extended_registers); - if (!GetThreadContext (th->h, &th->context)) + BOOL ret; +#ifdef __x86_64__ + if (wow64_process) + ret = win32_Wow64GetThreadContext (th->h, &th->wow64_context); + else +#endif + ret = GetThreadContext (th->h, &th->context); + if (!ret) { DWORD e = GetLastError (); @@ -247,13 +284,28 @@ i386_prepare_to_resume (windows_thread_info *th) win32_require_context (th); - th->context.Dr0 = dr->dr_mirror[0]; - th->context.Dr1 = dr->dr_mirror[1]; - th->context.Dr2 = dr->dr_mirror[2]; - th->context.Dr3 = dr->dr_mirror[3]; - /* th->context.Dr6 = dr->dr_status_mirror; - FIXME: should we set dr6 also ?? */ - th->context.Dr7 = dr->dr_control_mirror; +#ifdef __x86_64__ + if (wow64_process) + { + th->wow64_context.Dr0 = dr->dr_mirror[0]; + th->wow64_context.Dr1 = dr->dr_mirror[1]; + th->wow64_context.Dr2 = dr->dr_mirror[2]; + th->wow64_context.Dr3 = dr->dr_mirror[3]; + /* th->wow64_context.Dr6 = dr->dr_status_mirror; + FIXME: should we set dr6 also ?? */ + th->wow64_context.Dr7 = dr->dr_control_mirror; + } + else +#endif + { + th->context.Dr0 = dr->dr_mirror[0]; + th->context.Dr1 = dr->dr_mirror[1]; + th->context.Dr2 = dr->dr_mirror[2]; + th->context.Dr3 = dr->dr_mirror[3]; + /* th->context.Dr6 = dr->dr_status_mirror; + FIXME: should we set dr6 also ?? */ + th->context.Dr7 = dr->dr_control_mirror; + } th->debug_registers_changed = false; } @@ -268,11 +320,14 @@ i386_thread_added (windows_thread_info *th) static void i386_single_step (windows_thread_info *th) { - th->context.EFlags |= FLAG_TRACE_BIT; +#ifdef __x86_64__ + if (wow64_process) + th->wow64_context.EFlags |= FLAG_TRACE_BIT; + else +#endif + th->context.EFlags |= FLAG_TRACE_BIT; } -#ifndef __x86_64__ - /* An array of offset mappings into a Win32 Context structure. This is a one-to-one mapping which is indexed by gdb's register numbers. It retrieves an offset into the context structure where @@ -280,8 +335,12 @@ i386_single_step (windows_thread_info *th) An offset value of -1 indicates that Win32 does not provide this register in it's CONTEXT structure. In this case regptr will return a pointer into a dummy register. */ +#ifdef __x86_64__ +#define context_offset(x) (offsetof (WOW64_CONTEXT, x)) +#else #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) -static const int mappings[] = { +#endif +static const int i386_mappings[] = { context_offset (Eax), context_offset (Ecx), context_offset (Edx), @@ -328,10 +387,10 @@ static const int mappings[] = { }; #undef context_offset -#else /* __x86_64__ */ +#ifdef __x86_64__ #define context_offset(x) (offsetof (CONTEXT, x)) -static const int mappings[] = +static const int amd64_mappings[] = { context_offset (Rax), context_offset (Rbx), @@ -402,7 +461,21 @@ static void i386_fetch_inferior_register (struct regcache *regcache, windows_thread_info *th, int r) { - char *context_offset = (char *) &th->context + mappings[r]; + const int *mappings; +#ifdef __x86_64__ + if (!wow64_process) + mappings = amd64_mappings; + else +#endif + mappings = i386_mappings; + + char *context_offset; +#ifdef __x86_64__ + if (wow64_process) + context_offset = (char *) &th->wow64_context + mappings[r]; + else +#endif + context_offset = (char *) &th->context + mappings[r]; long l; if (r == FCS_REGNUM) @@ -424,7 +497,22 @@ static void i386_store_inferior_register (struct regcache *regcache, windows_thread_info *th, int r) { - char *context_offset = (char *) &th->context + mappings[r]; + const int *mappings; +#ifdef __x86_64__ + if (!wow64_process) + mappings = amd64_mappings; + else +#endif + mappings = i386_mappings; + + char *context_offset; +#ifdef __x86_64__ + if (wow64_process) + context_offset = (char *) &th->wow64_context + mappings[r]; + else +#endif + context_offset = (char *) &th->context + mappings[r]; + collect_register (regcache, r, context_offset); } @@ -439,15 +527,32 @@ i386_arch_setup (void) #ifdef __x86_64__ tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false, false, false); - const char **expedite_regs = amd64_expedite_regs; -#else + init_target_desc (tdesc, amd64_expedite_regs); + win32_tdesc = tdesc; +#endif + tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); - const char **expedite_regs = i386_expedite_regs; + init_target_desc (tdesc, i386_expedite_regs); +#ifdef __x86_64__ + wow64_win32_tdesc = tdesc; +#else + win32_tdesc = tdesc; #endif +} - init_target_desc (tdesc, expedite_regs); +/* Implement win32_target_ops "num_regs" method. */ - win32_tdesc = tdesc; +static int +i386_win32_num_regs (void) +{ + int num_regs; +#ifdef __x86_64__ + if (!wow64_process) + num_regs = sizeof (amd64_mappings) / sizeof (amd64_mappings[0]); + else +#endif + num_regs = sizeof (i386_mappings) / sizeof (i386_mappings[0]); + return num_regs; } /* Implement win32_target_ops "get_pc" method. */ @@ -496,7 +601,7 @@ i386_win32_set_pc (struct regcache *regcache, CORE_ADDR pc) struct win32_target_ops the_low_target = { i386_arch_setup, - sizeof (mappings) / sizeof (mappings[0]), + i386_win32_num_regs, i386_initial_stuff, i386_get_thread_context, i386_prepare_to_resume, diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc index 5a6f0df39f5..4eb63b7ca25 100644 --- a/gdbserver/win32-low.cc +++ b/gdbserver/win32-low.cc @@ -88,15 +88,30 @@ static int soft_interrupt_requested = 0; by suspending all the threads. */ static int faked_breakpoint = 0; +#ifdef __x86_64__ +bool wow64_process = false; +#endif + const struct target_desc *win32_tdesc; +#ifdef __x86_64__ +const struct target_desc *wow64_win32_tdesc; +#endif -#define NUM_REGS (the_low_target.num_regs) +#define NUM_REGS (the_low_target.num_regs ()) typedef BOOL (WINAPI *winapi_DebugActiveProcessStop) (DWORD dwProcessId); typedef BOOL (WINAPI *winapi_DebugSetProcessKillOnExit) (BOOL KillOnExit); typedef BOOL (WINAPI *winapi_DebugBreakProcess) (HANDLE); typedef BOOL (WINAPI *winapi_GenerateConsoleCtrlEvent) (DWORD, DWORD); +#ifdef __x86_64__ +typedef BOOL (WINAPI *winapi_Wow64SetThreadContext) (HANDLE, + const WOW64_CONTEXT *); + +winapi_Wow64GetThreadContext win32_Wow64GetThreadContext; +static winapi_Wow64SetThreadContext win32_Wow64SetThreadContext; +#endif + #ifndef _WIN32_WCE static void win32_add_all_dlls (void); #endif @@ -121,7 +136,12 @@ debug_event_ptid (DEBUG_EVENT *event) static void win32_get_thread_context (windows_thread_info *th) { - memset (&th->context, 0, sizeof (CONTEXT)); +#ifdef __x86_64__ + if (wow64_process) + memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT)); + else +#endif + memset (&th->context, 0, sizeof (CONTEXT)); (*the_low_target.get_thread_context) (th); #ifdef _WIN32_WCE memcpy (&th->base_context, &th->context, sizeof (CONTEXT)); @@ -146,7 +166,14 @@ win32_set_thread_context (windows_thread_info *th) it between stopping and resuming. */ if (memcmp (&th->context, &th->base_context, sizeof (CONTEXT)) != 0) #endif - SetThreadContext (th->h, &th->context); + { +#ifdef __x86_64__ + if (wow64_process) + win32_Wow64SetThreadContext (th->h, &th->wow64_context); + else +#endif + SetThreadContext (th->h, &th->context); + } } /* Set the thread context of the thread associated with TH. */ @@ -163,7 +190,14 @@ win32_prepare_to_resume (windows_thread_info *th) void win32_require_context (windows_thread_info *th) { - if (th->context.ContextFlags == 0) + DWORD context_flags; +#ifdef __x86_64__ + if (wow64_process) + context_flags = th->wow64_context.ContextFlags; + else +#endif + context_flags = th->context.ContextFlags; + if (context_flags == 0) { th->suspend (); win32_get_thread_context (th); @@ -195,7 +229,14 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb) if ((th = thread_rec (ptid, DONT_INVALIDATE_CONTEXT))) return th; - th = new windows_thread_info (tid, h, (CORE_ADDR) (uintptr_t) tlb); + 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 += 2 * 4096; /* page size = 4096 */ +#endif + th = new windows_thread_info (tid, h, base); add_thread (ptid, th); @@ -345,8 +386,31 @@ do_initial_child_stuff (HANDLE proch, DWORD pid, int attached) memset (¤t_event, 0, sizeof (current_event)); +#ifdef __x86_64__ + BOOL wow64; + if (!IsWow64Process (proch, &wow64)) + { + DWORD err = GetLastError (); + error ("Check if WOW64 process failed (error %d): %s\n", + (int) err, strwinerror (err)); + } + wow64_process = wow64; + + if (wow64_process + && (win32_Wow64GetThreadContext == nullptr + || win32_Wow64SetThreadContext == nullptr)) + error ("WOW64 debugging is not supported on this system.\n"); + + ignore_first_breakpoint = !attached && wow64_process; +#endif + proc = add_process (pid, attached); - proc->tdesc = win32_tdesc; +#ifdef __x86_64__ + if (wow64_process) + proc->tdesc = wow64_win32_tdesc; + else +#endif + proc->tdesc = win32_tdesc; child_init_thread_list (); child_initialization_done = 0; @@ -416,10 +480,17 @@ continue_one_thread (thread_info *thread, int thread_id) if (th->suspended) { - if (th->context.ContextFlags) + DWORD *context_flags; +#ifdef __x86_64__ + if (wow64_process) + context_flags = &th->wow64_context.ContextFlags; + else +#endif + context_flags = &th->context.ContextFlags; + if (*context_flags) { win32_set_thread_context (th); - th->context.ContextFlags = 0; + *context_flags = 0; } th->resume (); @@ -943,7 +1014,14 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) { win32_prepare_to_resume (th); - if (th->context.ContextFlags) + DWORD *context_flags; +#ifdef __x86_64__ + if (wow64_process) + context_flags = &th->wow64_context.ContextFlags; + else +#endif + context_flags = &th->context.ContextFlags; + if (*context_flags) { /* Move register values from the inferior into the thread context structure. */ @@ -959,7 +1037,7 @@ win32_process_target::resume (thread_resume *resume_info, size_t n) } win32_set_thread_context (th); - th->context.ContextFlags = 0; + *context_flags = 0; } } @@ -1032,12 +1110,19 @@ win32_add_one_solib (const char *name, CORE_ADDR load_addr) typedef BOOL (WINAPI *winapi_EnumProcessModules) (HANDLE, HMODULE *, DWORD, LPDWORD); +#ifdef __x86_64__ +typedef BOOL (WINAPI *winapi_EnumProcessModulesEx) (HANDLE, HMODULE *, DWORD, + LPDWORD, DWORD); +#endif typedef BOOL (WINAPI *winapi_GetModuleInformation) (HANDLE, HMODULE, LPMODULEINFO, DWORD); typedef DWORD (WINAPI *winapi_GetModuleFileNameExA) (HANDLE, HMODULE, LPSTR, DWORD); static winapi_EnumProcessModules win32_EnumProcessModules; +#ifdef __x86_64__ +static winapi_EnumProcessModulesEx win32_EnumProcessModulesEx; +#endif static winapi_GetModuleInformation win32_GetModuleInformation; static winapi_GetModuleFileNameExA win32_GetModuleFileNameExA; @@ -1055,12 +1140,21 @@ load_psapi (void) return FALSE; win32_EnumProcessModules = GETPROCADDRESS (dll, EnumProcessModules); +#ifdef __x86_64__ + win32_EnumProcessModulesEx = + GETPROCADDRESS (dll, EnumProcessModulesEx); +#endif win32_GetModuleInformation = GETPROCADDRESS (dll, GetModuleInformation); win32_GetModuleFileNameExA = GETPROCADDRESS (dll, GetModuleFileNameExA); } +#ifdef __x86_64__ + if (wow64_process && win32_EnumProcessModulesEx == nullptr) + return FALSE; +#endif + return (win32_EnumProcessModules != NULL && win32_GetModuleInformation != NULL && win32_GetModuleFileNameExA != NULL); @@ -1084,10 +1178,19 @@ win32_add_all_dlls (void) return; cbNeeded = 0; - ok = (*win32_EnumProcessModules) (current_process_handle, - DllHandle, - sizeof (HMODULE), - &cbNeeded); +#ifdef __x86_64__ + if (wow64_process) + ok = (*win32_EnumProcessModulesEx) (current_process_handle, + DllHandle, + sizeof (HMODULE), + &cbNeeded, + LIST_MODULES_32BIT); + else +#endif + ok = (*win32_EnumProcessModules) (current_process_handle, + DllHandle, + sizeof (HMODULE), + &cbNeeded); if (!ok || !cbNeeded) return; @@ -1096,13 +1199,53 @@ win32_add_all_dlls (void) if (!DllHandle) return; - ok = (*win32_EnumProcessModules) (current_process_handle, - DllHandle, - cbNeeded, - &cbNeeded); +#ifdef __x86_64__ + if (wow64_process) + ok = (*win32_EnumProcessModulesEx) (current_process_handle, + DllHandle, + cbNeeded, + &cbNeeded, + LIST_MODULES_32BIT); + else +#endif + ok = (*win32_EnumProcessModules) (current_process_handle, + DllHandle, + cbNeeded, + &cbNeeded); if (!ok) return; + char system_dir[MAX_PATH]; + char syswow_dir[MAX_PATH]; + 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 < ((size_t) cbNeeded / sizeof (HMODULE)); i++) { MODULEINFO mi; @@ -1118,7 +1261,22 @@ win32_add_all_dlls (void) dll_name, MAX_PATH) == 0) continue; - win32_add_one_solib (dll_name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll); + + const char *name = dll_name; + /* 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 (dll_name, system_dir, system_dir_len) == 0 + && strchr (dll_name + system_dir_len, '\\') == nullptr) + { + syswow_dll_path = syswow_dir; + syswow_dll_path += dll_name + system_dir_len; + name = syswow_dll_path.c_str(); + } + + win32_add_one_solib (name, (CORE_ADDR) (uintptr_t) mi.lpBaseOfDll); } } #endif @@ -1221,8 +1379,10 @@ maybe_adjust_pc () th->stopped_at_software_breakpoint = false; if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT - && (current_event.u.Exception.ExceptionRecord.ExceptionCode - == EXCEPTION_BREAKPOINT) + && ((current_event.u.Exception.ExceptionRecord.ExceptionCode + == EXCEPTION_BREAKPOINT) + || (current_event.u.Exception.ExceptionRecord.ExceptionCode + == STATUS_WX86_BREAKPOINT)) && child_initialization_done) { th->stopped_at_software_breakpoint = true; @@ -1684,13 +1844,34 @@ win32_process_target::qxfer_siginfo (const char *annex, if (readbuf == nullptr) return -1; - if (offset > sizeof (siginfo_er)) + 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 (offset > bufsize) return -1; - if (offset + len > sizeof (siginfo_er)) - len = sizeof (siginfo_er) - offset; + if (offset + len > bufsize) + len = bufsize - offset; - memcpy (readbuf, (char *) &siginfo_er + offset, len); + memcpy (readbuf, buf + offset, len); return len; } @@ -1760,4 +1941,12 @@ initialize_low (void) { set_target_ops (&the_win32_target); the_low_target.arch_setup (); + +#ifdef __x86_64__ + /* These functions are loaded dynamically, because they are not available + on Windows XP. */ + HMODULE dll = GetModuleHandle (_T("KERNEL32.DLL")); + win32_Wow64GetThreadContext = GETPROCADDRESS (dll, Wow64GetThreadContext); + win32_Wow64SetThreadContext = GETPROCADDRESS (dll, Wow64SetThreadContext); +#endif } diff --git a/gdbserver/win32-low.h b/gdbserver/win32-low.h index b3fa392dd31..a023eb1f839 100644 --- a/gdbserver/win32-low.h +++ b/gdbserver/win32-low.h @@ -27,6 +27,14 @@ struct target_desc; /* The inferior's target description. This is a global because the Windows ports support neither bi-arch nor multi-process. */ extern const struct target_desc *win32_tdesc; +#ifdef __x86_64__ +extern const struct target_desc *wow64_win32_tdesc; + +extern bool wow64_process; + +typedef BOOL (WINAPI *winapi_Wow64GetThreadContext) (HANDLE, PWOW64_CONTEXT); +extern winapi_Wow64GetThreadContext win32_Wow64GetThreadContext; +#endif struct win32_target_ops { @@ -34,7 +42,7 @@ struct win32_target_ops void (*arch_setup) (void); /* The number of target registers. */ - int num_regs; + int (*num_regs) (void); /* Perform initializations on startup. */ void (*initial_stuff) (void);