Reduce WOW64 code duplication

Message ID 20241122195834.656-1-ssbssa@yahoo.de
State New
Headers
Series Reduce WOW64 code duplication |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Test passed

Commit Message

Hannes Domani Nov. 22, 2024, 7:58 p.m. UTC
  Currently we have duplicate code for each place where
windows_thread_info::context is touched, since for WOW64 processes
it has to do the equivalent with wow64_context instead.

For example this code...:

 #ifdef __x86_64__
   if (windows_process.wow64_process)
     {
       th->wow64_context.ContextFlags = WOW64_CONTEXT_ALL;
       CHECK (Wow64GetThreadContext (th->h, &th->wow64_context));
       ...
     }
   else
 #endif
     {
       th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
       CHECK (GetThreadContext (th->h, &th->context));
       ...
     }

...changes to look like this instead:

   windows_process.with_context (th, [&] (auto *context)
     {
       context->ContextFlags = WindowsContext<decltype(context)>::all;
       CHECK (get_thread_context (th->h, context));
       ...
     }

The actual choice if context or wow64_context are used, is handled by
this new function in windows_process_info:

   template<typename Function>
   auto with_context (windows_thread_info *th, Function function)
   {
 #ifdef __x86_64__
     if (wow64_process)
       return function (th != nullptr ? th->wow64_context : nullptr);
     else
 #endif
       return function (th != nullptr ? th->context : nullptr);
   }

The other parts to make this work are the templated WindowsContext class
which give the appropriate ContextFlags for both types.
And there are also overloaded helper functions, like in the case of
get_thread_context here, call either GetThreadContext or
Wow64GetThreadContext.

According git log --stat, this results in 120 lines less code.
---
 gdb/nat/windows-nat.c       |  63 +++-------
 gdb/nat/windows-nat.h       | 117 ++++++++++++++++++
 gdb/windows-nat.c           | 232 +++++++++---------------------------
 gdbserver/win32-i386-low.cc | 150 +++++++----------------
 gdbserver/win32-low.cc      |  44 ++-----
 5 files changed, 243 insertions(+), 363 deletions(-)
  

Comments

Tom Tromey Dec. 3, 2024, 8:42 p.m. UTC | #1
>>>>> "Hannes" == Hannes Domani <ssbssa@yahoo.de> writes:

Hannes> Currently we have duplicate code for each place where
Hannes> windows_thread_info::context is touched, since for WOW64 processes
Hannes> it has to do the equivalent with wow64_context instead.

Thanks for the patch.

It took me a little while to understand what it was doing, mostly
because I didn't realize the 'auto' thing was possible in C++17.

Hannes> The other parts to make this work are the templated WindowsContext class
Hannes> which give the appropriate ContextFlags for both types.
Hannes> And there are also overloaded helper functions, like in the case of
Hannes> get_thread_context here, call either GetThreadContext or
Hannes> Wow64GetThreadContext.

In the end I like it.  It'd be nice to do without callbacks, but on the
other hand this is a convenient way to reduce the code duplication.

Approved-By: Tom Tromey <tom@tromey.com>

Tom
  

Patch

diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index f9f6848861d..6f1ce81c59b 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -172,23 +172,13 @@  windows_process_info::get_exec_module_filename (char *exe_name_ret,
   DWORD cbNeeded;
 
   cbNeeded = 0;
-#ifdef __x86_64__
-  if (wow64_process)
-    {
-      if (!EnumProcessModulesEx (handle,
-				 &dh_buf, sizeof (HMODULE), &cbNeeded,
-				 LIST_MODULES_32BIT)
-	  || !cbNeeded)
-	return 0;
-    }
-  else
-#endif
+  BOOL ret = with_context (nullptr, [&] (auto *context)
     {
-      if (!EnumProcessModules (handle,
-			       &dh_buf, sizeof (HMODULE), &cbNeeded)
-	  || !cbNeeded)
-	return 0;
-    }
+      return enum_process_modules (context, handle, &dh_buf,
+				   sizeof (HMODULE), &cbNeeded);
+    });
+  if (!ret || !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.  */
@@ -523,41 +513,22 @@  windows_process_info::add_dll (LPVOID load_addr)
   HMODULE *hmodules;
   int i;
 
-#ifdef __x86_64__
-  if (wow64_process)
+  BOOL ret = with_context (nullptr, [&] (auto *context)
     {
-      if (EnumProcessModulesEx (handle, &dummy_hmodule,
-				sizeof (HMODULE), &cb_needed,
-				LIST_MODULES_32BIT) == 0)
-	return;
-    }
-  else
-#endif
-    {
-      if (EnumProcessModules (handle, &dummy_hmodule,
-			      sizeof (HMODULE), &cb_needed) == 0)
-	return;
-    }
-
-  if (cb_needed < 1)
+      return enum_process_modules (context, handle, &dummy_hmodule,
+				   sizeof (HMODULE), &cb_needed);
+    });
+  if (!ret || cb_needed < 1)
     return;
 
   hmodules = (HMODULE *) alloca (cb_needed);
-#ifdef __x86_64__
-  if (wow64_process)
+  ret = with_context (nullptr, [&] (auto *context)
     {
-      if (EnumProcessModulesEx (handle, hmodules,
-				cb_needed, &cb_needed,
-				LIST_MODULES_32BIT) == 0)
-	return;
-    }
-  else
-#endif
-    {
-      if (EnumProcessModules (handle, hmodules,
-			      cb_needed, &cb_needed) == 0)
-	return;
-    }
+      return enum_process_modules (context, handle, hmodules,
+				   cb_needed, &cb_needed);
+    });
+  if (!ret)
+    return;
 
   char system_dir[MAX_PATH];
   char syswow_dir[MAX_PATH];
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index f2b5d777016..dc637d4ed04 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -29,6 +29,12 @@ 
 #define STATUS_WX86_BREAKPOINT 0x4000001F
 #define STATUS_WX86_SINGLE_STEP 0x4000001E
 
+#ifndef CONTEXT_EXTENDED_REGISTERS
+/* This macro is only defined on ia32.  It only makes sense on this target,
+   so define it as zero if not already defined.  */
+#define CONTEXT_EXTENDED_REGISTERS 0
+#endif
+
 namespace windows_nat
 {
 
@@ -250,6 +256,25 @@  struct windows_process_info
 
   const char *pid_to_exec_file (int);
 
+  template<typename Function>
+  auto with_context (windows_thread_info *th, Function function)
+  {
+#ifdef __x86_64__
+    if (wow64_process)
+      return function (th != nullptr ? &th->wow64_context : nullptr);
+    else
+#endif
+      return function (th != nullptr ? &th->context : nullptr);
+  }
+
+  DWORD *context_flags_ptr (windows_thread_info *th)
+  {
+    return with_context (th, [] (auto *context)
+      {
+	return &context->ContextFlags;
+      });
+  }
+
 private:
 
   /* Handle MS_VC_EXCEPTION when processing a stop.  MS_VC_EXCEPTION is
@@ -433,6 +458,98 @@  extern DeleteProcThreadAttributeList_ftype *DeleteProcThreadAttributeList;
 
 extern bool disable_randomization_available ();
 
+/* Helper classes to get the correct ContextFlags values based on the
+   used type (CONTEXT or WOW64_CONTEXT).  */
+
+template<typename Context>
+struct WindowsContext;
+
+template<>
+struct WindowsContext<CONTEXT *>
+{
+  static constexpr DWORD control  = CONTEXT_CONTROL;
+  static constexpr DWORD floating = CONTEXT_FLOATING_POINT;
+  static constexpr DWORD debug    = CONTEXT_DEBUG_REGISTERS;
+  static constexpr DWORD extended = CONTEXT_EXTENDED_REGISTERS;
+  static constexpr DWORD full	  = CONTEXT_FULL;
+  static constexpr DWORD all	  = (CONTEXT_FULL
+				     | CONTEXT_FLOATING_POINT
+				     | CONTEXT_SEGMENTS
+				     | CONTEXT_DEBUG_REGISTERS
+				     | CONTEXT_EXTENDED_REGISTERS);
+};
+
+#ifdef __x86_64__
+template<>
+struct WindowsContext<WOW64_CONTEXT *>
+{
+  static constexpr DWORD control  = WOW64_CONTEXT_CONTROL;
+  static constexpr DWORD floating = WOW64_CONTEXT_FLOATING_POINT;
+  static constexpr DWORD debug	  = WOW64_CONTEXT_DEBUG_REGISTERS;
+  static constexpr DWORD extended = WOW64_CONTEXT_EXTENDED_REGISTERS;
+  static constexpr DWORD full	  = WOW64_CONTEXT_FULL;
+  static constexpr DWORD all	  = WOW64_CONTEXT_ALL;
+};
+#endif
+
+/* Overloaded helper functions to call the correct function based on the used
+   type (CONTEXT or WOW64_CONTEXT).  */
+
+static inline BOOL
+get_thread_context (HANDLE h, CONTEXT *context)
+{
+  return GetThreadContext (h, context);
+}
+
+static inline BOOL
+set_thread_context (HANDLE h, CONTEXT *context)
+{
+  return SetThreadContext (h, context);
+}
+
+static inline BOOL
+get_thread_selector_entry (CONTEXT *, HANDLE thread, DWORD sel,
+			   LDT_ENTRY *info)
+{
+  return GetThreadSelectorEntry (thread, sel, info);
+}
+
+static inline BOOL
+enum_process_modules (CONTEXT *, HANDLE process,
+		      HMODULE *modules, DWORD size, LPDWORD needed)
+{
+  return EnumProcessModules (process, modules, size, needed);
+}
+
+#ifdef __x86_64__
+static inline BOOL
+get_thread_context (HANDLE h, WOW64_CONTEXT *context)
+{
+  return Wow64GetThreadContext (h, context);
+}
+
+static inline BOOL
+set_thread_context (HANDLE h, WOW64_CONTEXT *context)
+{
+  return Wow64SetThreadContext (h, context);
+}
+
+static inline BOOL
+get_thread_selector_entry (WOW64_CONTEXT *, HANDLE thread, DWORD sel,
+			   LDT_ENTRY *info)
+{
+  return Wow64GetThreadSelectorEntry (thread, sel, info);
+}
+
+static inline BOOL
+enum_process_modules (WOW64_CONTEXT *, HANDLE process,
+		      HMODULE *modules, DWORD size, LPDWORD needed)
+{
+  return EnumProcessModulesEx (process, modules, size, needed,
+			       LIST_MODULES_32BIT);
+}
+#endif
+
 /* Load any functions which may not be available in ancient versions
    of Windows.  */
 
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index abacafe7af8..f2d0633b32f 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -166,16 +166,6 @@  enum
   };
 #endif
 
-#ifndef CONTEXT_EXTENDED_REGISTERS
-/* This macro is only defined on ia32.  It only makes sense on this target,
-   so define it as zero if not already defined.  */
-#define CONTEXT_EXTENDED_REGISTERS 0
-#endif
-
-#define CONTEXT_DEBUGGER_DR CONTEXT_FULL | CONTEXT_FLOATING_POINT \
-	| CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS \
-	| CONTEXT_EXTENDED_REGISTERS
-
 #define DR6_CLEAR_VALUE 0xffff0ff0
 
 /* The string sent by cygwin when it processes a signal.
@@ -657,11 +647,10 @@  windows_fetch_one_register (struct regcache *regcache,
   gdb_assert (r >= 0);
   gdb_assert (!th->reload_context);
 
-  char *context_ptr = (char *) &th->context;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    context_ptr = (char *) &th->wow64_context;
-#endif
+  char *context_ptr = windows_process.with_context (th, [] (auto *context)
+    {
+      return (char *) context;
+    });
 
   char *context_offset = context_ptr + windows_process.mappings[r];
   struct gdbarch *gdbarch = regcache->arch ();
@@ -727,42 +716,24 @@  windows_nat_target::fetch_registers (struct regcache *regcache, int r)
 
   if (th->reload_context)
     {
-#ifdef __x86_64__
-      if (windows_process.wow64_process)
+      windows_process.with_context (th, [&] (auto *context)
 	{
-	  th->wow64_context.ContextFlags = WOW64_CONTEXT_ALL;
-	  CHECK (Wow64GetThreadContext (th->h, &th->wow64_context));
+	  context->ContextFlags = WindowsContext<decltype(context)>::all;
+	  CHECK (get_thread_context (th->h, context));
 	  /* Copy dr values from that thread.
 	     But only if there were not modified since last stop.
 	     PR gdb/2388 */
 	  if (!th->debug_registers_changed)
 	    {
-	      windows_process.dr[0] = th->wow64_context.Dr0;
-	      windows_process.dr[1] = th->wow64_context.Dr1;
-	      windows_process.dr[2] = th->wow64_context.Dr2;
-	      windows_process.dr[3] = th->wow64_context.Dr3;
-	      windows_process.dr[6] = th->wow64_context.Dr6;
-	      windows_process.dr[7] = th->wow64_context.Dr7;
+	      windows_process.dr[0] = context->Dr0;
+	      windows_process.dr[1] = context->Dr1;
+	      windows_process.dr[2] = context->Dr2;
+	      windows_process.dr[3] = context->Dr3;
+	      windows_process.dr[6] = context->Dr6;
+	      windows_process.dr[7] = context->Dr7;
 	    }
-	}
-      else
-#endif
-	{
-	  th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
-	  CHECK (GetThreadContext (th->h, &th->context));
-	  /* Copy dr values from that thread.
-	     But only if there were not modified since last stop.
-	     PR gdb/2388 */
-	  if (!th->debug_registers_changed)
-	    {
-	      windows_process.dr[0] = th->context.Dr0;
-	      windows_process.dr[1] = th->context.Dr1;
-	      windows_process.dr[2] = th->context.Dr2;
-	      windows_process.dr[3] = th->context.Dr3;
-	      windows_process.dr[6] = th->context.Dr6;
-	      windows_process.dr[7] = th->context.Dr7;
-	    }
-	}
+	});
+
       th->reload_context = false;
     }
 
@@ -785,11 +756,10 @@  windows_store_one_register (const struct regcache *regcache,
 {
   gdb_assert (r >= 0);
 
-  char *context_ptr = (char *) &th->context;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    context_ptr = (char *) &th->wow64_context;
-#endif
+  char *context_ptr = windows_process.with_context (th, [] (auto *context)
+    {
+      return (char *) context;
+    });
 
   struct gdbarch *gdbarch = regcache->arch ();
   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
@@ -1086,13 +1056,10 @@  static int
 display_selector (HANDLE thread, DWORD sel)
 {
   LDT_ENTRY info;
-  BOOL ret;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    ret = Wow64GetThreadSelectorEntry (thread, sel, &info);
-  else
-#endif
-    ret = GetThreadSelectorEntry (thread, sel, &info);
+  BOOL ret = windows_process.with_context (nullptr, [&] (auto *context)
+    {
+      return get_thread_selector_entry (context, thread, sel, &info);
+    });
   if (ret)
     {
       int base, limit;
@@ -1181,50 +1148,21 @@  display_selectors (const char * args, int from_tty)
 
   if (!args)
     {
-#ifdef __x86_64__
-      if (windows_process.wow64_process)
-	{
-	  gdb_puts ("Selector $cs\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->wow64_context.SegCs);
-	  gdb_puts ("Selector $ds\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->wow64_context.SegDs);
-	  gdb_puts ("Selector $es\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->wow64_context.SegEs);
-	  gdb_puts ("Selector $ss\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->wow64_context.SegSs);
-	  gdb_puts ("Selector $fs\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->wow64_context.SegFs);
-	  gdb_puts ("Selector $gs\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->wow64_context.SegGs);
-	}
-      else
-#endif
+      windows_process.with_context (current_windows_thread, [&] (auto *context)
 	{
 	  gdb_puts ("Selector $cs\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->context.SegCs);
+	  display_selector (current_windows_thread->h, context->SegCs);
 	  gdb_puts ("Selector $ds\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->context.SegDs);
+	  display_selector (current_windows_thread->h, context->SegDs);
 	  gdb_puts ("Selector $es\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->context.SegEs);
+	  display_selector (current_windows_thread->h, context->SegEs);
 	  gdb_puts ("Selector $ss\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->context.SegSs);
+	  display_selector (current_windows_thread->h, context->SegSs);
 	  gdb_puts ("Selector $fs\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->context.SegFs);
+	  display_selector (current_windows_thread->h, context->SegFs);
 	  gdb_puts ("Selector $gs\n");
-	  display_selector (current_windows_thread->h,
-			    current_windows_thread->context.SegGs);
-	}
+	  display_selector (current_windows_thread->h, context->SegGs);
+	});
     }
   else
     {
@@ -1285,65 +1223,36 @@  windows_nat_target::windows_continue (DWORD continue_status, int id,
   for (auto &th : windows_process.thread_list)
     if (id == -1 || id == (int) th->tid)
       {
-#ifdef __x86_64__
-	if (windows_process.wow64_process)
+	windows_process.with_context (th.get (), [&] (auto *context)
 	  {
 	    if (th->debug_registers_changed)
 	      {
-		th->wow64_context.ContextFlags |= WOW64_CONTEXT_DEBUG_REGISTERS;
-		th->wow64_context.Dr0 = windows_process.dr[0];
-		th->wow64_context.Dr1 = windows_process.dr[1];
-		th->wow64_context.Dr2 = windows_process.dr[2];
-		th->wow64_context.Dr3 = windows_process.dr[3];
-		th->wow64_context.Dr6 = DR6_CLEAR_VALUE;
-		th->wow64_context.Dr7 = windows_process.dr[7];
+		context->ContextFlags
+		  |= WindowsContext<decltype(context)>::debug;
+		context->Dr0 = windows_process.dr[0];
+		context->Dr1 = windows_process.dr[1];
+		context->Dr2 = windows_process.dr[2];
+		context->Dr3 = windows_process.dr[3];
+		context->Dr6 = DR6_CLEAR_VALUE;
+		context->Dr7 = windows_process.dr[7];
 		th->debug_registers_changed = false;
 	      }
-	    if (th->wow64_context.ContextFlags)
+	    if (context->ContextFlags)
 	      {
 		DWORD ec = 0;
 
 		if (GetExitCodeThread (th->h, &ec)
 		    && ec == STILL_ACTIVE)
 		  {
-		    BOOL status = Wow64SetThreadContext (th->h,
-							 &th->wow64_context);
+		    BOOL status = set_thread_context (th->h, context);
 
 		    if (!killed)
 		      CHECK (status);
 		  }
-		th->wow64_context.ContextFlags = 0;
-	      }
-	  }
-	else
-#endif
-	  {
-	    if (th->debug_registers_changed)
-	      {
-		th->context.ContextFlags |= CONTEXT_DEBUG_REGISTERS;
-		th->context.Dr0 = windows_process.dr[0];
-		th->context.Dr1 = windows_process.dr[1];
-		th->context.Dr2 = windows_process.dr[2];
-		th->context.Dr3 = windows_process.dr[3];
-		th->context.Dr6 = DR6_CLEAR_VALUE;
-		th->context.Dr7 = windows_process.dr[7];
-		th->debug_registers_changed = false;
+		context->ContextFlags = 0;
 	      }
-	    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);
-		  }
-		th->context.ContextFlags = 0;
-	      }
-	  }
 	th->resume ();
       }
     else
@@ -1454,8 +1363,7 @@  windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
   th = windows_process.thread_rec (inferior_ptid, DONT_INVALIDATE_CONTEXT);
   if (th)
     {
-#ifdef __x86_64__
-      if (windows_process.wow64_process)
+      windows_process.with_context (th, [&] (auto *context)
 	{
 	  if (step)
 	    {
@@ -1463,53 +1371,25 @@  windows_nat_target::resume (ptid_t ptid, int step, enum gdb_signal sig)
 	      regcache *regcache = get_thread_regcache (inferior_thread ());
 	      struct gdbarch *gdbarch = regcache->arch ();
 	      fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
-	      th->wow64_context.EFlags |= FLAG_TRACE_BIT;
+	      context->EFlags |= FLAG_TRACE_BIT;
 	    }
 
-	  if (th->wow64_context.ContextFlags)
+	  if (context->ContextFlags)
 	    {
 	      if (th->debug_registers_changed)
 		{
-		  th->wow64_context.Dr0 = windows_process.dr[0];
-		  th->wow64_context.Dr1 = windows_process.dr[1];
-		  th->wow64_context.Dr2 = windows_process.dr[2];
-		  th->wow64_context.Dr3 = windows_process.dr[3];
-		  th->wow64_context.Dr6 = DR6_CLEAR_VALUE;
-		  th->wow64_context.Dr7 = windows_process.dr[7];
+		  context->Dr0 = windows_process.dr[0];
+		  context->Dr1 = windows_process.dr[1];
+		  context->Dr2 = windows_process.dr[2];
+		  context->Dr3 = windows_process.dr[3];
+		  context->Dr6 = DR6_CLEAR_VALUE;
+		  context->Dr7 = windows_process.dr[7];
 		  th->debug_registers_changed = false;
 		}
-	      CHECK (Wow64SetThreadContext (th->h, &th->wow64_context));
-	      th->wow64_context.ContextFlags = 0;
+	      CHECK (set_thread_context (th->h, context));
+	      context->ContextFlags = 0;
 	    }
-	}
-      else
-#endif
-	{
-	  if (step)
-	    {
-	      /* Single step by setting t bit.  */
-	      regcache *regcache = get_thread_regcache (inferior_thread ());
-	      struct gdbarch *gdbarch = regcache->arch ();
-	      fetch_registers (regcache, gdbarch_ps_regnum (gdbarch));
-	      th->context.EFlags |= FLAG_TRACE_BIT;
-	    }
-
-	  if (th->context.ContextFlags)
-	    {
-	      if (th->debug_registers_changed)
-		{
-		  th->context.Dr0 = windows_process.dr[0];
-		  th->context.Dr1 = windows_process.dr[1];
-		  th->context.Dr2 = windows_process.dr[2];
-		  th->context.Dr3 = windows_process.dr[3];
-		  th->context.Dr6 = DR6_CLEAR_VALUE;
-		  th->context.Dr7 = windows_process.dr[7];
-		  th->debug_registers_changed = false;
-		}
-	      CHECK (SetThreadContext (th->h, &th->context));
-	      th->context.ContextFlags = 0;
-	    }
-	}
+	});
     }
 
   /* Allow continuing with the same signal that interrupted us.
diff --git a/gdbserver/win32-i386-low.cc b/gdbserver/win32-i386-low.cc
index 7898ac12bcf..200126044cc 100644
--- a/gdbserver/win32-i386-low.cc
+++ b/gdbserver/win32-i386-low.cc
@@ -88,31 +88,12 @@  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 (windows_process.wow64_process)
+  return windows_process.with_context (th, [&] (auto *context) -> DWORD64
     {
-      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
+      case DR:					\
+	return context->Dr ## DR
 
-    {
       switch (dr)
 	{
 	  RET_DR (0);
@@ -122,11 +103,10 @@  win32_get_current_dr (int dr)
 	  RET_DR (6);
 	  RET_DR (7);
 	}
-    }
-
 #undef RET_DR
 
-  gdb_assert_not_reached ("unhandled dr");
+      gdb_assert_not_reached ("unhandled dr");
+    });
 }
 
 static CORE_ADDR
@@ -247,59 +227,33 @@  i386_initial_stuff (void)
 static void
 i386_get_thread_context (windows_thread_info *th)
 {
-  /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if
-     the system doesn't support extended registers.  */
-  static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS;
-#ifdef __x86_64__
-  static DWORD wow64_extended_registers = WOW64_CONTEXT_EXTENDED_REGISTERS;
-#endif
+  windows_process.with_context (th, [&] (auto *context)
+    {
+      /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if
+	 the system doesn't support extended registers.  */
+      static DWORD extended_registers
+	= WindowsContext<decltype(context)>::extended;
 
  again:
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    th->wow64_context.ContextFlags = (WOW64_CONTEXT_FULL
-				      | WOW64_CONTEXT_FLOATING_POINT
-				      | WOW64_CONTEXT_DEBUG_REGISTERS
-				      | wow64_extended_registers);
-  else
-#endif
-    th->context.ContextFlags = (CONTEXT_FULL
-				| CONTEXT_FLOATING_POINT
-				| CONTEXT_DEBUG_REGISTERS
-				| extended_registers);
-
-  BOOL ret;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    ret = Wow64GetThreadContext (th->h, &th->wow64_context);
-  else
-#endif
-    ret = GetThreadContext (th->h, &th->context);
-  if (!ret)
-    {
-      DWORD e = GetLastError ();
+      context->ContextFlags = (WindowsContext<decltype(context)>::full
+			       | WindowsContext<decltype(context)>::floating
+			       | WindowsContext<decltype(context)>::debug
+			       | extended_registers);
 
-#ifdef __x86_64__
-      if (windows_process.wow64_process)
-	{
-	  if (wow64_extended_registers && e == ERROR_INVALID_PARAMETER)
-	    {
-	      wow64_extended_registers = 0;
-	      goto again;
-	    }
-	}
-      else
-#endif
+      BOOL ret = get_thread_context (th->h, context);
+      if (!ret)
 	{
+	  DWORD e = GetLastError ();
+
 	  if (extended_registers && e == ERROR_INVALID_PARAMETER)
 	    {
 	      extended_registers = 0;
 	      goto again;
 	    }
-	}
 
-      error ("GetThreadContext failure %ld\n", (long) e);
-    }
+	  error ("GetThreadContext failure %ld\n", (long) e);
+	}
+    });
 }
 
 static void
@@ -311,28 +265,16 @@  i386_prepare_to_resume (windows_thread_info *th)
 
       win32_require_context (th);
 
-#ifdef __x86_64__
-      if (windows_process.wow64_process)
+      windows_process.with_context (th, [&] (auto *context)
 	{
-	  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;
+	  context->Dr0 = dr->dr_mirror[0];
+	  context->Dr1 = dr->dr_mirror[1];
+	  context->Dr2 = dr->dr_mirror[2];
+	  context->Dr3 = dr->dr_mirror[3];
+	  /* 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;
-	}
+	  context->Dr7 = dr->dr_control_mirror;
+	});
 
       th->debug_registers_changed = false;
     }
@@ -347,12 +289,10 @@  i386_thread_added (windows_thread_info *th)
 static void
 i386_single_step (windows_thread_info *th)
 {
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    th->wow64_context.EFlags |= FLAG_TRACE_BIT;
-  else
-#endif
-    th->context.EFlags |= FLAG_TRACE_BIT;
+  windows_process.with_context (th, [] (auto *context)
+    {
+      context->EFlags |= FLAG_TRACE_BIT;
+    });
 }
 
 /* An array of offset mappings into a Win32 Context structure.
@@ -532,13 +472,10 @@  i386_fetch_inferior_register (struct regcache *regcache,
 #endif
     mappings = i386_mappings;
 
-  char *context_offset;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    context_offset = (char *) &th->wow64_context + mappings[r];
-  else
-#endif
-    context_offset = (char *) &th->context + mappings[r];
+  char *context_offset = windows_process.with_context (th, [&] (auto *context)
+    {
+      return (char *) context + mappings[r];
+    });
 
   /* GDB treats some registers as 32-bit, where they are in fact only
      16 bits long.  These cases must be handled specially to avoid
@@ -571,13 +508,10 @@  i386_store_inferior_register (struct regcache *regcache,
 #endif
     mappings = i386_mappings;
 
-  char *context_offset;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    context_offset = (char *) &th->wow64_context + mappings[r];
-  else
-#endif
-    context_offset = (char *) &th->context + mappings[r];
+  char *context_offset = windows_process.with_context (th, [&] (auto *context)
+    {
+      return (char *) context + mappings[r];
+    });
 
   /* GDB treats some registers as 32-bit, where they are in fact only
      16 bits long.  These cases must be handled specially to avoid
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 0174a32e5d1..78c9fd109f1 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -81,12 +81,10 @@  debug_event_ptid (DEBUG_EVENT *event)
 static void
 win32_get_thread_context (windows_thread_info *th)
 {
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    memset (&th->wow64_context, 0, sizeof (WOW64_CONTEXT));
-  else
-#endif
-    memset (&th->context, 0, sizeof (CONTEXT));
+  windows_process.with_context (th, [] (auto *context)
+    {
+      memset (context, 0, sizeof (*context));
+    });
   (*the_low_target.get_thread_context) (th);
 }
 
@@ -95,12 +93,10 @@  win32_get_thread_context (windows_thread_info *th)
 static void
 win32_set_thread_context (windows_thread_info *th)
 {
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    Wow64SetThreadContext (th->h, &th->wow64_context);
-  else
-#endif
-    SetThreadContext (th->h, &th->context);
+  windows_process.with_context (th, [&] (auto *context)
+    {
+      set_thread_context (th->h, context);
+    });
 }
 
 /* Set the thread context of the thread associated with TH.  */
@@ -117,13 +113,7 @@  win32_prepare_to_resume (windows_thread_info *th)
 void
 win32_require_context (windows_thread_info *th)
 {
-  DWORD context_flags;
-#ifdef __x86_64__
-  if (windows_process.wow64_process)
-    context_flags = th->wow64_context.ContextFlags;
-  else
-#endif
-    context_flags = th->context.ContextFlags;
+  DWORD context_flags = *windows_process.context_flags_ptr (th);
   if (context_flags == 0)
     {
       th->suspend ();
@@ -402,13 +392,7 @@  continue_one_thread (thread_info *thread, int thread_id)
 
       if (th->suspended)
 	{
-	  DWORD *context_flags;
-#ifdef __x86_64__
-	  if (windows_process.wow64_process)
-	    context_flags = &th->wow64_context.ContextFlags;
-	  else
-#endif
-	    context_flags = &th->context.ContextFlags;
+	  DWORD *context_flags = windows_process.context_flags_ptr (th);
 	  if (*context_flags)
 	    {
 	      win32_set_thread_context (th);
@@ -818,13 +802,7 @@  win32_process_target::resume (thread_resume *resume_info, size_t n)
     {
       win32_prepare_to_resume (th);
 
-      DWORD *context_flags;
-#ifdef __x86_64__
-      if (windows_process.wow64_process)
-	context_flags = &th->wow64_context.ContextFlags;
-      else
-#endif
-	context_flags = &th->context.ContextFlags;
+      DWORD *context_flags = windows_process.context_flags_ptr (th);
       if (*context_flags)
 	{
 	  /* Move register values from the inferior into the thread