[PATCH v2 8/8] Windows gdbserver: Implement XState (Intel AVX) support
Hannes Domani <[email protected]> Mon, 27 Jul 2026 19:42:32 +0200
| Newsgroups | gmane.comp.gdb.patches |
|---|---|
| Message-ID | <[email protected]> |
Equivalent support as previous patch for Intel AVX registers.
---
v2:
- Remove PKRU support
- Fixed context offset of $pl3_ssp
---
gdbserver/win32-i386-low.cc | 114 ++++++++++++++++++++++++++++++++++--
gdbserver/win32-low.cc | 15 +++--
2 files changed, 118 insertions(+), 11 deletions(-)
diff --git a/gdbserver/win32-i386-low.cc b/gdbserver/win32-i386-low.cc
index b77f6adc6ed..da1aa6fed5d 100644
--- a/gdbserver/win32-i386-low.cc
+++ b/gdbserver/win32-i386-low.cc
@@ -253,6 +253,11 @@ i386_get_thread_context (windows_thread_info *th)
| WindowsContext<decltype(context)>::floating
| WindowsContext<decltype(context)>::debug
| extended_registers);
+ if (xstate_features != 0)
+ {
+ context->ContextFlags |= CONTEXT_XSTATE_FLAG;
+ set_xstate_features_mask (context, xstate_features);
+ }
BOOL ret = get_thread_context (th->h, context);
if (!ret)
@@ -267,6 +272,24 @@ i386_get_thread_context (windows_thread_info *th)
error (_("GetThreadContext failure %ld\n"), (long) e);
}
+
+ DWORD64 features = 0;
+ if (xstate_features != 0
+ && get_xstate_features_mask (context, &features))
+ {
+ DWORD64 zeroed_features = xstate_features & ~features;
+ for (int f = X86_XSTATE_AVX_ID; f <= X86_XSTATE_CET_U_ID; f++)
+ {
+ DWORD64 flag = 1ULL << f;
+ if ((zeroed_features & flag) != 0)
+ {
+ DWORD size = 0;
+ void *loc = locate_xstate_feature (context, f, &size);
+ if (loc != nullptr && size > 0)
+ memset (loc, 0, size);
+ }
+ }
+ }
});
}
@@ -292,6 +315,17 @@ i386_prepare_to_resume (windows_thread_info *th)
th->debug_registers_changed = false;
}
+
+ windows_process.with_context (th, [&] (auto *context)
+ {
+ DWORD debug_registers = WindowsContext<decltype(context)>::debug;
+ if (xstate_features != 0
+ && (context->ContextFlags & ~debug_registers) != 0)
+ {
+ context->ContextFlags |= CONTEXT_XSTATE_FLAG;
+ set_xstate_features_mask (context, xstate_features);
+ }
+ });
}
static void
@@ -477,7 +511,7 @@ is_segment_register (int r)
template<typename Context>
static char *
-get_context_reg_ptr (Context *context, int r)
+get_context_reg_ptr (Context *context, int r, const target_desc *tdesc)
{
const int *mappings;
int mappings_count;
@@ -494,9 +528,74 @@ get_context_reg_ptr (Context *context, int r)
mappings_count = sizeof (i386_mappings) / sizeof (i386_mappings[0]);
}
+ bool amd64 = register_size (tdesc, 0) == 8;
+ int ymm0h_regnum, zmm0h_regnum, k0_regnum;
+ int xmm16_regnum, ymm16h_regnum, zmm16h_regnum;
+ const int num_xmm_registers = amd64 ? 16 : 8;
+ const int num_zmm_high_registers = amd64 ? 16 : 0;
+ const int num_avx512_k_registers = 8;
+
char *context_offset;
if (r < mappings_count)
context_offset = (char *) context + mappings[r];
+ else if ((xstate_features & X86_XSTATE_ZMM_H) != 0
+ && r >= (zmm0h_regnum = find_regno (tdesc, "zmm0h"))
+ && r < zmm0h_regnum + num_xmm_registers)
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_H_ID, NULL);
+ context_offset += 32 * (r - zmm0h_regnum);
+ }
+ else if ((xstate_features & X86_XSTATE_ZMM) != 0
+ && num_zmm_high_registers != 0
+ && r >= (zmm16h_regnum = find_regno (tdesc, "zmm16h"))
+ && r < zmm16h_regnum + num_zmm_high_registers)
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_ID, NULL);
+ context_offset += 32 + 64 * (r - zmm16h_regnum);
+ }
+ else if ((xstate_features & X86_XSTATE_K) != 0
+ && r >= (k0_regnum = find_regno (tdesc, "k0"))
+ && r < k0_regnum + num_avx512_k_registers)
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_K_ID, NULL);
+ context_offset += 8 * (r - k0_regnum);
+ }
+ else if ((xstate_features & X86_XSTATE_ZMM) != 0
+ && num_zmm_high_registers != 0
+ && r >= (ymm16h_regnum = find_regno (tdesc, "ymm16h"))
+ && r < ymm16h_regnum + num_zmm_high_registers)
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_ID, NULL);
+ context_offset += 16 + 64 * (r - ymm16h_regnum);
+ }
+ else if ((xstate_features & X86_XSTATE_ZMM) != 0
+ && num_zmm_high_registers != 0
+ && r >= (xmm16_regnum = find_regno (tdesc, "xmm16"))
+ && r < xmm16_regnum + num_zmm_high_registers)
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_ID, NULL);
+ context_offset += 64 * (r - xmm16_regnum);
+ }
+ else if ((xstate_features & X86_XSTATE_AVX) != 0
+ && r >= (ymm0h_regnum = find_regno (tdesc, "ymm0h"))
+ && r < ymm0h_regnum + num_xmm_registers)
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_AVX_ID, NULL);
+ context_offset += 16 * (r - ymm0h_regnum);
+ }
+ else if ((xstate_features & X86_XSTATE_CET_U) != 0
+ && r == find_regno (tdesc, "pl3_ssp"))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_CET_U_ID, NULL);
+ context_offset += 8;
+ }
else
gdb_assert_not_reached ("invalid register number %d", r);
@@ -510,7 +609,7 @@ i386_fetch_inferior_register (struct regcache *regcache,
{
char *context_offset = windows_process.with_context (th, [&] (auto *context)
{
- return get_context_reg_ptr (context, r);
+ return get_context_reg_ptr (context, r, regcache->tdesc);
});
/* GDB treats some registers as 32-bit, where they are in fact only
@@ -538,7 +637,7 @@ i386_store_inferior_register (struct regcache *regcache,
{
char *context_offset = windows_process.with_context (th, [&] (auto *context)
{
- return get_context_reg_ptr (context, r);
+ return get_context_reg_ptr (context, r, regcache->tdesc);
});
/* GDB treats some registers as 32-bit, where they are in fact only
@@ -571,14 +670,17 @@ i386_arch_setup (void)
{
target_desc_up tdesc;
+ DWORD64 xcr0 = xstate_features;
+ if (xcr0 == 0)
+ xcr0 = X86_XSTATE_SSE_MASK;
+
#ifdef __x86_64__
- tdesc = amd64_create_target_description (X86_XSTATE_SSE_MASK, false,
- false, false);
+ tdesc = amd64_create_target_description (xcr0, false, false, false);
init_target_desc (tdesc.get (), amd64_expedite_regs, WINDOWS_OSABI);
win32_tdesc = std::move (tdesc);
#endif
- tdesc = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false);
+ tdesc = i386_create_target_description (xcr0, false, false);
init_target_desc (tdesc.get (), i386_expedite_regs, WINDOWS_OSABI);
#ifdef __x86_64__
wow64_win32_tdesc = std::move (tdesc);
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 3d85faf0785..ea5b6f8900e 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -33,6 +33,7 @@
#include <process.h>
#include "gdbsupport/gdb_tilde_expand.h"
#include "gdbsupport/common-inferior.h"
+#include "tdesc.h"
using namespace windows_nat;
@@ -427,8 +428,9 @@ child_fetch_inferior_registers (struct regcache *regcache, int r)
int regno;
windows_thread_info *th = windows_process.find_thread (current_thread->id);
win32_require_context (th);
- if (r == -1 || r > NUM_REGS)
- child_fetch_inferior_registers (regcache, NUM_REGS);
+ if (r == -1)
+ child_fetch_inferior_registers (regcache,
+ regcache->tdesc->reg_defs.size ());
else
for (regno = 0; regno < r; regno++)
(*the_low_target.fetch_inferior_register) (regcache, th, regno);
@@ -442,8 +444,9 @@ child_store_inferior_registers (struct regcache *regcache, int r)
int regno;
windows_thread_info *th = windows_process.find_thread (current_thread->id);
win32_require_context (th);
- if (r == -1 || r == 0 || r > NUM_REGS)
- child_store_inferior_registers (regcache, NUM_REGS);
+ if (r == -1)
+ child_store_inferior_registers (regcache,
+ regcache->tdesc->reg_defs.size ());
else
for (regno = 0; regno < r; regno++)
(*the_low_target.store_inferior_register) (regcache, th, regno);
@@ -1350,7 +1353,9 @@ void
initialize_low (void)
{
set_target_ops (&the_win32_target);
- the_low_target.arch_setup ();
initialize_loadable ();
+ /* Has to be done after initialize_loadable, because it uses the xstate
+ functions if available. */
+ the_low_target.arch_setup ();
}
--
2.54.0