From: Hannes Domani Date: Sun, 26 Jan 2020 21:04:04 +0000 (+0100) Subject: Implement debugging of WOW64 processes X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=46f9f93119daaa8eceb7233a17759e10e858c9fd;p=binutils-gdb.git Implement debugging of WOW64 processes For WOW64 processes, the Wow64* variants of SuspendThread, GetThreadContext, SetThreadContext, and GetThreadSelectorEntry have to be used instead. And instead of EnumProcessModules, EnumProcessModulesEx with LIST_MODULES_32BIT is necessary. gdb/ChangeLog: 2020-03-04 Hannes Domani * NEWS: Mention support for WOW64 processes. * amd64-windows-nat.c (amd64_mappings): Rename and remove static. (amd64_windows_segment_register_p): Remove static. (_initialize_amd64_windows_nat): Update. * configure.nat (NATDEPFILES): Add i386-windows-nat.o. * i386-windows-nat.c (context_offset): Update. (i386_mappings): Rename and remove static. (i386_windows_segment_register_p): Remove static. (_initialize_i386_windows_nat): Update. * windows-nat.c (STATUS_WX86_BREAKPOINT): New macro. (STATUS_WX86_SINGLE_STEP): New macro. (EnumProcessModulesEx): New macro. (Wow64SuspendThread): New macro. (Wow64GetThreadContext): New macro. (Wow64SetThreadContext): New macro. (Wow64GetThreadSelectorEntry): New macro. (windows_set_context_register_offsets): Add static. (windows_set_segment_register_p): Likewise. (windows_add_thread): Adapt for WOW64 processes. (windows_fetch_one_register): Likewise. (windows_nat_target::fetch_registers): Likewise. (windows_store_one_register): Likewise. (display_selector): Likewise. (display_selectors): Likewise. (handle_exception): Likewise. (windows_continue): Likewise. (windows_nat_target::resume): Likewise. (windows_add_all_dlls): Likewise. (do_initial_windows_stuff): Likewise. (windows_nat_target::attach): Likewise. (windows_get_exec_module_filename): Likewise. (windows_nat_target::create_inferior): Likewise. (windows_xfer_siginfo): Likewise. (_initialize_loadable): Initialize Wow64SuspendThread, Wow64GetThreadContext, Wow64SetThreadContext, Wow64GetThreadSelectorEntry and EnumProcessModulesEx. * windows-nat.h (windows_set_context_register_offsets): Remove declaration. (windows_set_segment_register_p): Likewise. (i386_windows_segment_register_p): Add declaration. (amd64_windows_segment_register_p): Likewise. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 36b3f3dc439..51785c76127 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,47 @@ +2020-03-04 Hannes Domani + + * NEWS: Mention support for WOW64 processes. + * amd64-windows-nat.c (amd64_mappings): Rename and remove static. + (amd64_windows_segment_register_p): Remove static. + (_initialize_amd64_windows_nat): Update. + * configure.nat (NATDEPFILES): Add i386-windows-nat.o. + * i386-windows-nat.c (context_offset): Update. + (i386_mappings): Rename and remove static. + (i386_windows_segment_register_p): Remove static. + (_initialize_i386_windows_nat): Update. + * windows-nat.c (STATUS_WX86_BREAKPOINT): New macro. + (STATUS_WX86_SINGLE_STEP): New macro. + (EnumProcessModulesEx): New macro. + (Wow64SuspendThread): New macro. + (Wow64GetThreadContext): New macro. + (Wow64SetThreadContext): New macro. + (Wow64GetThreadSelectorEntry): New macro. + (windows_set_context_register_offsets): Add static. + (windows_set_segment_register_p): Likewise. + (windows_add_thread): Adapt for WOW64 processes. + (windows_fetch_one_register): Likewise. + (windows_nat_target::fetch_registers): Likewise. + (windows_store_one_register): Likewise. + (display_selector): Likewise. + (display_selectors): Likewise. + (handle_exception): Likewise. + (windows_continue): Likewise. + (windows_nat_target::resume): Likewise. + (windows_add_all_dlls): Likewise. + (do_initial_windows_stuff): Likewise. + (windows_nat_target::attach): Likewise. + (windows_get_exec_module_filename): Likewise. + (windows_nat_target::create_inferior): Likewise. + (windows_xfer_siginfo): Likewise. + (_initialize_loadable): Initialize Wow64SuspendThread, + Wow64GetThreadContext, Wow64SetThreadContext, + Wow64GetThreadSelectorEntry and EnumProcessModulesEx. + * windows-nat.h (windows_set_context_register_offsets): + Remove declaration. + (windows_set_segment_register_p): Likewise. + (i386_windows_segment_register_p): Add declaration. + (amd64_windows_segment_register_p): Likewise. + 2020-03-04 Luis Machado Revert aa66aac47b4dd38f9524ddb5546c08cc09930d37 due to regressions diff --git a/gdb/NEWS b/gdb/NEWS index cbdfcadb411..4dc6b33b650 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -39,6 +39,9 @@ string is that GDB will not try to load any previous command history. +* On Windows targets, it is now possible to debug 32-bit programs with a + 64-bit GDB. + * New commands set exec-file-mismatch -- Set exec-file-mismatch handling (ask|warn|off). diff --git a/gdb/amd64-windows-nat.c b/gdb/amd64-windows-nat.c index 5b2c261aba7..6f185ad15be 100644 --- a/gdb/amd64-windows-nat.c +++ b/gdb/amd64-windows-nat.c @@ -23,7 +23,7 @@ #include #define context_offset(x) (offsetof (CONTEXT, x)) -static const int mappings[] = +const int amd64_mappings[] = { context_offset (Rax), context_offset (Rbx), @@ -89,7 +89,7 @@ static const int mappings[] = /* segment_register_p_ftype implementation for amd64. */ -static int +int amd64_windows_segment_register_p (int regnum) { return regnum >= AMD64_CS_REGNUM && regnum <= AMD64_GS_REGNUM; @@ -99,7 +99,5 @@ void _initialize_amd64_windows_nat (); void _initialize_amd64_windows_nat () { - windows_set_context_register_offsets (mappings); - windows_set_segment_register_p (amd64_windows_segment_register_p); x86_set_debug_register_length (8); } diff --git a/gdb/configure.nat b/gdb/configure.nat index 3fc6f5cb4a2..83ffdb80486 100644 --- a/gdb/configure.nat +++ b/gdb/configure.nat @@ -137,7 +137,7 @@ case ${gdb_host} in i386) # Native config information for GDB on amd64 # systems running Cygwin. - NATDEPFILES="${NATDEPFILES} amd64-windows-nat.o" + NATDEPFILES="${NATDEPFILES} i386-windows-nat.o amd64-windows-nat.o" ;; esac ;; @@ -325,7 +325,7 @@ case ${gdb_host} in mingw64) case ${gdb_host_cpu} in i386) - NATDEPFILES="${NATDEPFILES} amd64-windows-nat.o" + NATDEPFILES="${NATDEPFILES} i386-windows-nat.o amd64-windows-nat.o" ;; esac ;; diff --git a/gdb/i386-windows-nat.c b/gdb/i386-windows-nat.c index 958c83eafe6..3091fc36282 100644 --- a/gdb/i386-windows-nat.c +++ b/gdb/i386-windows-nat.c @@ -22,8 +22,11 @@ #include -#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x)) -static const int mappings[] = +#ifdef __x86_64__ +#define CONTEXT WOW64_CONTEXT +#endif +#define context_offset(x) ((int)(size_t)&(((CONTEXT *)NULL)->x)) +const int i386_mappings[] = { context_offset (Eax), context_offset (Ecx), @@ -70,10 +73,11 @@ static const int mappings[] = context_offset (ExtendedRegisters[24]) }; #undef context_offset +#undef CONTEXT /* segment_register_p_ftype implementation for x86. */ -static int +int i386_windows_segment_register_p (int regnum) { return regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM; @@ -83,7 +87,7 @@ void _initialize_i386_windows_nat (); void _initialize_i386_windows_nat () { - windows_set_context_register_offsets (mappings); - windows_set_segment_register_p (i386_windows_segment_register_p); +#ifndef __x86_64__ x86_set_debug_register_length (4); +#endif } diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 76fcdd6bd47..614b235edea 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -70,16 +70,24 @@ #include "gdbsupport/pathstuff.h" #include "gdbsupport/gdb_wait.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 +108,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 +131,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 @@ -224,7 +254,13 @@ typedef struct windows_thread_info_struct char *name; int suspended; int reload_context; - CONTEXT context; + union + { + CONTEXT context; +#ifdef __x86_64__ + WOW64_CONTEXT wow64_context; +#endif + }; } windows_thread_info; @@ -243,6 +279,10 @@ 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 bool new_console = false; @@ -360,15 +400,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; @@ -452,6 +493,12 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p) th->id = id; th->h = h; th->thread_local_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) + th->thread_local_base += 0x2000; +#endif th->next = thread_head.next; thread_head.next = th; @@ -468,17 +515,36 @@ windows_add_thread (ptid_t ptid, HANDLE h, void *tlb, bool main_thread_p) /* 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; } @@ -565,7 +631,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); @@ -616,6 +688,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; @@ -655,7 +747,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 @@ -1043,7 +1141,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); @@ -1127,25 +1232,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 { @@ -1246,6 +1376,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; @@ -1258,6 +1401,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; @@ -1346,29 +1490,62 @@ windows_continue (DWORD continue_status, int id, int killed) if ((id == -1 || id == (int) th->id) && 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 (GetExitCodeThread (th->h, &ec) + && ec == STILL_ACTIVE) + { + BOOL status = SetThreadContext (th->h, &th->context); - if (!killed) - CHECK (status); + if (!killed) + CHECK (status); + } + th->context.ContextFlags = 0; } - th->context.ContextFlags = 0; } if (th->suspended > 0) (void) ResumeThread (th->h); @@ -1468,28 +1645,59 @@ windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig) 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; } } @@ -1814,17 +2022,41 @@ 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; + } for (i = 1; i < (int) (cb_needed / sizeof (HMODULE)); i++) { @@ -1879,6 +2111,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; @@ -2029,6 +2276,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 (); } @@ -2083,9 +2341,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. */ @@ -2843,6 +3113,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); @@ -3006,19 +3282,40 @@ 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 > sizeof (siginfo_er)) + if (offset > bufsize) return TARGET_XFER_E_IO; - 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); *xfered_len = len; return TARGET_XFER_OK; @@ -3368,6 +3665,12 @@ _initialize_loadable () 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 @@ -3390,6 +3693,9 @@ _initialize_loadable () if (hm) { GPA (hm, EnumProcessModules); +#ifdef __x86_64__ + GPA (hm, EnumProcessModulesEx); +#endif GPA (hm, GetModuleInformation); GetModuleFileNameEx = (GetModuleFileNameEx_ftype *) GetProcAddress (hm, GetModuleFileNameEx_name); diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h index e24305ebcdb..43c788c497e 100644 --- a/gdb/windows-nat.h +++ b/gdb/windows-nat.h @@ -18,15 +18,23 @@ #ifndef WINDOWS_NAT_H #define WINDOWS_NAT_H -extern void windows_set_context_register_offsets (const int *offsets); - /* A pointer to a function that should return non-zero iff REGNUM corresponds to one of the segment registers. */ typedef int (segment_register_p_ftype) (int regnum); -/* Set the function that should be used by this module to determine - whether a given register is a segment register or not. */ -extern void windows_set_segment_register_p (segment_register_p_ftype *fun); +/* segment_register_p_ftype implementation for x86. */ +int i386_windows_segment_register_p (int regnum); + +/* context register offests for x86. */ +extern const int i386_mappings[]; + +#ifdef __x86_64__ +/* segment_register_p_ftype implementation for amd64. */ +int amd64_windows_segment_register_p (int regnum); + +/* context register offests for amd64. */ +extern const int amd64_mappings[]; +#endif #endif