* [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc
[not found] <20260727174619.1089041-1-ssbssa.ref@yahoo.de>
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 2/8] Windows gdb: Use allocated buffer for CONTEXT Hannes Domani
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
_aligned_malloc has swapped arguments, and you have to use _aligned_free
to free the memory afterwards.
This is enough to make i386-sse.exp pass, and i386-avx.exp will pass at
the end of this series.
---
v2:
- Mention which test pass after the change in the commit message
---
gdb/testsuite/gdb.arch/i386-avx.c | 2 +-
gdb/testsuite/gdb.arch/i386-sse.c | 2 +-
gdb/testsuite/lib/precise-aligned-alloc.c | 20 ++++++++++++++++++++
3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/gdb/testsuite/gdb.arch/i386-avx.c b/gdb/testsuite/gdb.arch/i386-avx.c
index b6cd89e5bea..229093e5164 100644
--- a/gdb/testsuite/gdb.arch/i386-avx.c
+++ b/gdb/testsuite/gdb.arch/i386-avx.c
@@ -116,7 +116,7 @@ main (int argc, char **argv)
puts ("Bye!"); /* second breakpoint here */
- free (allocated_ptr);
+ aligned_free (allocated_ptr);
return 0;
}
diff --git a/gdb/testsuite/gdb.arch/i386-sse.c b/gdb/testsuite/gdb.arch/i386-sse.c
index 21264ed74e7..5210aee12c3 100644
--- a/gdb/testsuite/gdb.arch/i386-sse.c
+++ b/gdb/testsuite/gdb.arch/i386-sse.c
@@ -134,7 +134,7 @@ main (int argc, char **argv)
puts ("Bye!"); /* second breakpoint here */
}
- free (allocated_ptr);
+ aligned_free (allocated_ptr);
return 0;
}
diff --git a/gdb/testsuite/lib/precise-aligned-alloc.c b/gdb/testsuite/lib/precise-aligned-alloc.c
index 888814f12ef..1db35528bc8 100644
--- a/gdb/testsuite/lib/precise-aligned-alloc.c
+++ b/gdb/testsuite/lib/precise-aligned-alloc.c
@@ -21,6 +21,26 @@
#include <string.h>
#include <stdint.h>
+#ifdef _WIN32
+static void *
+aligned_alloc (size_t alignment, size_t size)
+{
+ return _aligned_malloc (size, alignment);
+}
+
+static void
+aligned_free (void *ptr)
+{
+ _aligned_free (ptr);
+}
+#else
+static void
+aligned_free (void *ptr)
+{
+ free (ptr);
+}
+#endif
+
/* Return true if address P is ALIGNMENT-byte aligned. */
static int
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/8] Windows gdb: Use allocated buffer for CONTEXT
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 3/8] Windows gdb: Remove mappings member from windows_per_inferior Hannes Domani
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
This is done in preparation for the XState functions, because the
extended registers are stored directly after the CONTEXT, and its actual
size depends on the available XState features.
---
gdb/aarch64-windows-nat.c | 16 ++++++++--------
gdb/nat/windows-nat.c | 19 +++++++++++++++++++
gdb/nat/windows-nat.h | 16 ++++++++++++----
gdb/windows-nat.c | 1 +
gdbserver/win32-aarch64-low.cc | 10 +++++-----
gdbserver/win32-low.cc | 1 +
6 files changed, 46 insertions(+), 17 deletions(-)
diff --git a/gdb/aarch64-windows-nat.c b/gdb/aarch64-windows-nat.c
index ff2c9762467..630704a8caf 100644
--- a/gdb/aarch64-windows-nat.c
+++ b/gdb/aarch64-windows-nat.c
@@ -185,7 +185,7 @@ aarch64_windows_nat_target::cleanup_windows_arch ()
void
aarch64_windows_per_inferior::fill_thread_context (windows_thread_info *th)
{
- CONTEXT *context = &th->context;
+ CONTEXT *context = th->context;
if (context->ContextFlags == 0)
{
@@ -199,7 +199,7 @@ aarch64_windows_per_inferior::fill_thread_context (windows_thread_info *th)
void
aarch64_windows_per_inferior::invalidate_thread_context (windows_thread_info *th)
{
- CONTEXT *context = &th->context;
+ CONTEXT *context = th->context;
context->ContextFlags = 0;
}
@@ -209,7 +209,7 @@ void
aarch64_windows_nat_target::thread_context_continue (windows_thread_info *th,
int killed)
{
- CONTEXT *context = &th->context;
+ CONTEXT *context = th->context;
if (th->debug_registers_changed)
{
@@ -250,9 +250,9 @@ aarch64_windows_nat_target::thread_context_step (windows_thread_info *th,
bool enable)
{
if (enable)
- th->context.Cpsr |= 0x200000;
+ th->context->Cpsr |= 0x200000;
else
- th->context.Cpsr &= ~0x200000;
+ th->context->Cpsr &= ~0x200000;
}
/* See windows-nat.h. */
@@ -263,7 +263,7 @@ aarch64_windows_nat_target::fetch_one_register (struct regcache *regcache,
{
gdb_assert (r >= 0);
- char *context_ptr = (char *) &th->context;
+ char *context_ptr = (char *) th->context;
char *context_offset = context_ptr + aarch64_windows_process.mappings[r];
struct gdbarch *gdbarch = regcache->arch ();
@@ -292,9 +292,9 @@ aarch64_windows_nat_target::store_one_register (const struct regcache *regcache,
windows_thread_info *th, int r)
{
gdb_assert (r >= 0);
- gdb_assert (th->context.ContextFlags != 0);
+ gdb_assert (th->context->ContextFlags != 0);
- char *context_ptr = (char *) &th->context;
+ char *context_ptr = (char *) th->context;
regcache->raw_collect (r, context_ptr + aarch64_windows_process.mappings[r]);
}
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index e975892f487..689601f3a82 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -291,6 +291,25 @@ windows_process_info::pid_to_exec_file (int pid)
return path;
}
+/* See windows-nat.h. */
+
+void windows_process_info::initialize_context (windows_thread_info *th)
+{
+#ifdef __x86_64__
+ if (wow64_process)
+ {
+ th->context_buffer.reset (xmalloc (sizeof (WOW64_CONTEXT)));
+ th->wow64_context = (WOW64_CONTEXT *) th->context_buffer.get ();
+ }
+ else
+#endif
+ {
+ th->context_buffer.reset (xmalloc (sizeof (CONTEXT)));
+ th->context = (CONTEXT *) th->context_buffer.get ();
+ }
+ *context_flags_ptr (th) = 0;
+}
+
/* Return the name of the DLL referenced by H at ADDRESS. UNICODE
determines what sort of string is read from the inferior. Returns
the name of the DLL, or NULL on error. If a name is returned, it
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index 44b628c9bd1..76688fa90da 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -183,9 +183,9 @@ struct windows_thread_info
/* The context of the thread, including any manipulations. */
union
{
- CONTEXT context {};
+ CONTEXT *context = nullptr;
#ifdef __x86_64__
- WOW64_CONTEXT wow64_context;
+ WOW64_CONTEXT *wow64_context;
#endif
};
@@ -204,6 +204,10 @@ struct windows_thread_info
/* The name of the thread. */
gdb::unique_xmalloc_ptr<char> name;
+
+ /* The buffer for the thread context, including any XState registers if
+ available. */
+ gdb::unique_xmalloc_ptr<void> context_buffer;
};
enum handle_exception_result
@@ -313,15 +317,19 @@ struct windows_process_info
const char *pid_to_exec_file (int);
+ /* Allocate the context buffer for this thread. */
+
+ void initialize_context (windows_thread_info *th);
+
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);
+ return function (th != nullptr ? th->wow64_context : nullptr);
else
#endif
- return function (th != nullptr ? &th->context : nullptr);
+ return function (th != nullptr ? th->context : nullptr);
}
DWORD *context_flags_ptr (windows_thread_info *th)
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index def8fa606f4..4cd301d4959 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -515,6 +515,7 @@ windows_nat_target::add_thread (ptid_t ptid, HANDLE h, void *tlb,
#endif
windows_private_thread_info *th
= new windows_private_thread_info (windows_process, ptid.lwp (), h, base);
+ windows_process->initialize_context (th);
/* Add this new thread to the list of threads.
diff --git a/gdbserver/win32-aarch64-low.cc b/gdbserver/win32-aarch64-low.cc
index 5a7b72155db..e94548b6fef 100644
--- a/gdbserver/win32-aarch64-low.cc
+++ b/gdbserver/win32-aarch64-low.cc
@@ -169,7 +169,7 @@ aarch64_initial_stuff (process_info *proc)
static void
aarch64_get_thread_context (windows_thread_info *th)
{
- CONTEXT *context = &th->context;
+ CONTEXT *context = th->context;
context->ContextFlags = (WindowsContext<decltype(context)>::full
| WindowsContext<decltype(context)>::floating
@@ -193,7 +193,7 @@ aarch64_prepare_to_resume (windows_thread_info *th)
{
win32_require_context (th);
- CONTEXT *context = &th->context;
+ CONTEXT *context = th->context;
for (int i = 0; i < aarch64_num_bp_regs; i++)
{
@@ -223,7 +223,7 @@ aarch64_thread_added (windows_thread_info *th)
static void
aarch64_single_step (windows_thread_info *th)
{
- th->context.Cpsr |= 0x200000;
+ th->context->Cpsr |= 0x200000;
}
/* An array of offset mappings into a Win32 Context structure.
@@ -322,7 +322,7 @@ aarch64_fetch_inferior_register (struct regcache *regcache,
int mappings_count;
get_mappings (mappings, mappings_count);
- char *context_ptr = (char *) &th->context;
+ char *context_ptr = (char *) th->context;
char *context_offset;
if (r < mappings_count)
context_offset = context_ptr + mappings[r];
@@ -341,7 +341,7 @@ aarch64_store_inferior_register (struct regcache *regcache,
int mappings_count;
get_mappings (mappings, mappings_count);
- char *context_ptr = (char *) &th->context;
+ char *context_ptr = (char *) th->context;
char *context_offset;
if (r < mappings_count)
context_offset = context_ptr + mappings[r];
diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc
index 7629beca213..3d85faf0785 100644
--- a/gdbserver/win32-low.cc
+++ b/gdbserver/win32-low.cc
@@ -152,6 +152,7 @@ child_add_thread (DWORD pid, DWORD tid, HANDLE h, void *tlb)
base += 2 * 4096; /* page size = 4096 */
#endif
th = new windows_thread_info (&windows_process, tid, h, base);
+ windows_process.initialize_context (th);
find_process_pid (pid)->add_thread (ptid, th);
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 3/8] Windows gdb: Remove mappings member from windows_per_inferior
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
2026-07-27 17:42 ` [PATCH v2 2/8] Windows gdb: Use allocated buffer for CONTEXT Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 4/8] Windows gdb: Refactor getting pointer to register inside context Hannes Domani
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
It's not really that useful, and simplifies later XState changes.
---
gdb/aarch64-windows-nat.c | 6 ++----
gdb/windows-nat.h | 18 ------------------
gdb/x86-windows-nat.c | 34 ++++++++++++++++++++++------------
3 files changed, 24 insertions(+), 34 deletions(-)
diff --git a/gdb/aarch64-windows-nat.c b/gdb/aarch64-windows-nat.c
index 630704a8caf..be900439047 100644
--- a/gdb/aarch64-windows-nat.c
+++ b/gdb/aarch64-windows-nat.c
@@ -168,8 +168,6 @@ aarch64_windows_nat_target::initialize_windows_arch (bool attaching)
{
memset (&aarch64_windows_process.dr_state, 0,
sizeof (aarch64_windows_process.dr_state));
-
- aarch64_windows_process.mappings = aarch64_mappings;
}
/* See windows-nat.h. */
@@ -264,7 +262,7 @@ aarch64_windows_nat_target::fetch_one_register (struct regcache *regcache,
gdb_assert (r >= 0);
char *context_ptr = (char *) th->context;
- char *context_offset = context_ptr + aarch64_windows_process.mappings[r];
+ char *context_offset = context_ptr + aarch64_mappings[r];
struct gdbarch *gdbarch = regcache->arch ();
gdb_assert (!gdbarch_read_pc_p (gdbarch));
@@ -296,7 +294,7 @@ aarch64_windows_nat_target::store_one_register (const struct regcache *regcache,
char *context_ptr = (char *) th->context;
- regcache->raw_collect (r, context_ptr + aarch64_windows_process.mappings[r]);
+ regcache->raw_collect (r, context_ptr + aarch64_mappings[r]);
}
/* See windows-nat.h. */
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index 3349755022b..d6977ff4c85 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -139,24 +139,6 @@ struct windows_per_inferior : public windows_nat::windows_process_info
void *wow64_dbgbreak = nullptr;
#endif
- /* This vector maps GDB's idea of a register's number into an offset
- in the windows exception context vector.
-
- It also contains the bit mask needed to load the register in question.
-
- The contents of this table can only be computed by the units
- that provide CPU-specific support for Windows native debugging.
-
- One day we could read a reg, we could inspect the context we
- already have loaded, if it doesn't have the bit set that we need,
- we read that set of registers in using GetThreadContext. If the
- context already contains what we need, we just unpack it. Then to
- write a register, first we have to ensure that the context contains
- the other regs of the group, and then we copy the info in and set
- out bit. */
-
- const int *mappings = nullptr;
-
std::vector<windows_solib> solibs;
#ifdef __CYGWIN__
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index 2f556e47b39..b3ad8594020 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -85,16 +85,10 @@ x86_windows_nat_target::initialize_windows_arch (bool attaching)
= !attaching && x86_windows_process.wow64_process;
if (!x86_windows_process.wow64_process)
- {
- x86_windows_process.mappings = amd64_mappings;
- x86_windows_process.segment_register_p = amd64_windows_segment_register_p;
- }
+ x86_windows_process.segment_register_p = amd64_windows_segment_register_p;
else
#endif
- {
- x86_windows_process.mappings = i386_mappings;
- x86_windows_process.segment_register_p = i386_windows_segment_register_p;
- }
+ x86_windows_process.segment_register_p = i386_windows_segment_register_p;
}
/* See windows-nat.h. */
@@ -242,7 +236,15 @@ x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
return (char *) context;
});
- char *context_offset = context_ptr + x86_windows_process.mappings[r];
+ const int *mappings;
+#ifdef __x86_64__
+ if (!x86_windows_process.wow64_process)
+ mappings = amd64_mappings;
+ else
+#endif
+ mappings = i386_mappings;
+
+ char *context_offset = context_ptr + mappings[r];
struct gdbarch *gdbarch = regcache->arch ();
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
@@ -308,6 +310,14 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
return (char *) context;
});
+ const int *mappings;
+#ifdef __x86_64__
+ if (!x86_windows_process.wow64_process)
+ mappings = amd64_mappings;
+ else
+#endif
+ mappings = i386_mappings;
+
struct gdbarch *gdbarch = regcache->arch ();
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
@@ -319,7 +329,7 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
{
gdb_byte bytes[4];
regcache->raw_collect (r, bytes);
- memcpy (context_ptr + x86_windows_process.mappings[r], bytes, 2);
+ memcpy (context_ptr + mappings[r], bytes, 2);
}
else if (r == I387_FOP_REGNUM (tdep))
{
@@ -328,10 +338,10 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
/* The value of FOP occupies the top two bytes in the context,
so write the two low-order bytes from the cache into the
appropriate spot. */
- memcpy (context_ptr + x86_windows_process.mappings[r] + 2, bytes, 2);
+ memcpy (context_ptr + mappings[r] + 2, bytes, 2);
}
else
- regcache->raw_collect (r, context_ptr + x86_windows_process.mappings[r]);
+ regcache->raw_collect (r, context_ptr + mappings[r]);
}
/* See windows-nat.h. */
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 4/8] Windows gdb: Refactor getting pointer to register inside context
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
2026-07-27 17:42 ` [PATCH v2 2/8] Windows gdb: Use allocated buffer for CONTEXT Hannes Domani
2026-07-27 17:42 ` [PATCH v2 3/8] Windows gdb: Remove mappings member from windows_per_inferior Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 5/8] Windows gdb: Prepare XState functions Hannes Domani
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
These get_context_reg_ptr helper functions will be extended for XState
registers later.
---
gdb/amd64-windows-nat.c | 3 ++
gdb/i386-windows-nat.c | 3 ++
gdb/windows-nat.h | 6 +++
gdb/x86-windows-nat.c | 75 ++++++++++++++++++++++---------------
gdbserver/win32-i386-low.cc | 46 +++++++++++++++--------
5 files changed, 87 insertions(+), 46 deletions(-)
diff --git a/gdb/amd64-windows-nat.c b/gdb/amd64-windows-nat.c
index cca606b5200..9d83a5f8334 100644
--- a/gdb/amd64-windows-nat.c
+++ b/gdb/amd64-windows-nat.c
@@ -86,6 +86,9 @@ const int amd64_mappings[] =
};
#undef context_offset
+const int amd64_mappings_count
+ = sizeof (amd64_mappings) / sizeof (amd64_mappings[0]);
+
/* segment_register_p_ftype implementation for amd64. */
int
diff --git a/gdb/i386-windows-nat.c b/gdb/i386-windows-nat.c
index 991f301cad1..151b778036c 100644
--- a/gdb/i386-windows-nat.c
+++ b/gdb/i386-windows-nat.c
@@ -74,6 +74,9 @@ const int i386_mappings[] =
#undef context_offset
#undef CONTEXT
+const int i386_mappings_count
+ = sizeof (i386_mappings) / sizeof (i386_mappings[0]);
+
/* segment_register_p_ftype implementation for x86. */
int
diff --git a/gdb/windows-nat.h b/gdb/windows-nat.h
index d6977ff4c85..69be069e419 100644
--- a/gdb/windows-nat.h
+++ b/gdb/windows-nat.h
@@ -392,12 +392,18 @@ int i386_windows_segment_register_p (int regnum);
/* context register offsets for x86. */
extern const int i386_mappings[];
+/* number of context register offests for x86. */
+extern const int i386_mappings_count;
+
#ifdef __x86_64__
/* segment_register_p_ftype implementation for amd64. */
int amd64_windows_segment_register_p (int regnum);
/* context register offsets for amd64. */
extern const int amd64_mappings[];
+
+/* number of context register offests for amd64. */
+extern const int amd64_mappings_count;
#endif
/* Creates an iterator that works like all_matching_threads_iterator,
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index b3ad8594020..3af5ef4dae0 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -223,31 +223,53 @@ x86_windows_nat_target::thread_context_step (windows_thread_info *th,
});
}
-/* See windows-nat.h. */
+/* Get pointer to register R inside CONTEXT. */
-void
-x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
- windows_thread_info *th, int r)
+template<typename Context>
+static char *
+get_context_reg_ptr (Context *context, int r)
{
- gdb_assert (r >= 0);
-
- char *context_ptr = x86_windows_process.with_context (th, [] (auto *context)
- {
- return (char *) context;
- });
-
const int *mappings;
+ int mappings_count;
#ifdef __x86_64__
if (!x86_windows_process.wow64_process)
- mappings = amd64_mappings;
+ {
+ mappings = amd64_mappings;
+ mappings_count = amd64_mappings_count;
+ }
else
#endif
- mappings = i386_mappings;
+ {
+ mappings = i386_mappings;
+ mappings_count = i386_mappings_count;
+ }
+
+ char *context_offset;
+ if (r < mappings_count)
+ context_offset = (char *) context + mappings[r];
+ else
+ gdb_assert_not_reached ("invalid register number %d", r);
+
+ return context_offset;
+}
+
+/* See windows-nat.h. */
+
+void
+x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
+ gdb_assert (r >= 0);
- char *context_offset = context_ptr + mappings[r];
struct gdbarch *gdbarch = regcache->arch ();
i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ char *context_offset
+ = x86_windows_process.with_context (th, [&] (auto *context)
+ {
+ return get_context_reg_ptr (context, r);
+ });
+
gdb_assert (!gdbarch_read_pc_p (gdbarch));
gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0);
gdb_assert (!gdbarch_write_pc_p (gdbarch));
@@ -304,23 +326,16 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
{
gdb_assert (r >= 0);
- char *context_ptr = x86_windows_process.with_context (th, [] (auto *context)
+ struct gdbarch *gdbarch = regcache->arch ();
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+
+ char *context_offset
+ = x86_windows_process.with_context (th, [&] (auto *context)
{
gdb_assert (context->ContextFlags != 0);
- return (char *) context;
+ return get_context_reg_ptr (context, r);
});
- const int *mappings;
-#ifdef __x86_64__
- if (!x86_windows_process.wow64_process)
- mappings = amd64_mappings;
- else
-#endif
- mappings = i386_mappings;
-
- struct gdbarch *gdbarch = regcache->arch ();
- i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
-
/* GDB treats some registers as 32-bit, where they are in fact only
16 bits long. These cases must be handled specially to avoid
overwriting other registers in the context. */
@@ -329,7 +344,7 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
{
gdb_byte bytes[4];
regcache->raw_collect (r, bytes);
- memcpy (context_ptr + mappings[r], bytes, 2);
+ memcpy (context_offset, bytes, 2);
}
else if (r == I387_FOP_REGNUM (tdep))
{
@@ -338,10 +353,10 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
/* The value of FOP occupies the top two bytes in the context,
so write the two low-order bytes from the cache into the
appropriate spot. */
- memcpy (context_ptr + mappings[r] + 2, bytes, 2);
+ memcpy (context_offset + 2, bytes, 2);
}
else
- regcache->raw_collect (r, context_ptr + mappings[r]);
+ regcache->raw_collect (r, context_offset);
}
/* See windows-nat.h. */
diff --git a/gdbserver/win32-i386-low.cc b/gdbserver/win32-i386-low.cc
index 1aacd302074..b77f6adc6ed 100644
--- a/gdbserver/win32-i386-low.cc
+++ b/gdbserver/win32-i386-low.cc
@@ -473,22 +473,44 @@ is_segment_register (int r)
return r >= I386_CS_REGNUM && r <= I386_GS_REGNUM;
}
-/* Fetch register from gdbserver regcache data. */
-static void
-i386_fetch_inferior_register (struct regcache *regcache,
- windows_thread_info *th, int r)
+/* Get pointer to register R inside CONTEXT. */
+
+template<typename Context>
+static char *
+get_context_reg_ptr (Context *context, int r)
{
const int *mappings;
+ int mappings_count;
#ifdef __x86_64__
if (!windows_process.wow64_process)
- mappings = amd64_mappings;
+ {
+ mappings = amd64_mappings;
+ mappings_count = sizeof (amd64_mappings) / sizeof (amd64_mappings[0]);
+ }
else
#endif
- mappings = i386_mappings;
+ {
+ mappings = i386_mappings;
+ mappings_count = sizeof (i386_mappings) / sizeof (i386_mappings[0]);
+ }
+
+ char *context_offset;
+ if (r < mappings_count)
+ context_offset = (char *) context + mappings[r];
+ else
+ gdb_assert_not_reached ("invalid register number %d", r);
+
+ return context_offset;
+}
+/* Fetch register from gdbserver regcache data. */
+static void
+i386_fetch_inferior_register (struct regcache *regcache,
+ windows_thread_info *th, int r)
+{
char *context_offset = windows_process.with_context (th, [&] (auto *context)
{
- return (char *) context + mappings[r];
+ return get_context_reg_ptr (context, r);
});
/* GDB treats some registers as 32-bit, where they are in fact only
@@ -514,17 +536,9 @@ static void
i386_store_inferior_register (struct regcache *regcache,
windows_thread_info *th, int r)
{
- const int *mappings;
-#ifdef __x86_64__
- if (!windows_process.wow64_process)
- mappings = amd64_mappings;
- else
-#endif
- mappings = i386_mappings;
-
char *context_offset = windows_process.with_context (th, [&] (auto *context)
{
- return (char *) context + mappings[r];
+ return get_context_reg_ptr (context, r);
});
/* GDB treats some registers as 32-bit, where they are in fact only
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 5/8] Windows gdb: Prepare XState functions
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
` (2 preceding siblings ...)
2026-07-27 17:42 ` [PATCH v2 4/8] Windows gdb: Refactor getting pointer to register inside context Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 6/8] Windows gdb: Get available XState features Hannes Domani
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
These functions will then be used to access the XState registers.
---
gdb/nat/windows-nat.c | 31 +++++++++++
gdb/nat/windows-nat.h | 116 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+)
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index 689601f3a82..cd1f9e7bc64 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -73,6 +73,19 @@ InitializeProcThreadAttributeList_ftype *InitializeProcThreadAttributeList;
UpdateProcThreadAttribute_ftype *UpdateProcThreadAttribute;
DeleteProcThreadAttributeList_ftype *DeleteProcThreadAttributeList;
+#if defined __i386__ || defined __x86_64__
+GetEnabledXStateFeatures_ftype *GetEnabledXStateFeatures;
+InitializeContext_ftype *InitializeContext;
+GetXStateFeaturesMask_ftype *GetXStateFeaturesMask;
+SetXStateFeaturesMask_ftype *SetXStateFeaturesMask;
+LocateXStateFeature_ftype *LocateXStateFeature;
+#ifdef __x86_64__
+RtlGetExtendedFeaturesMask_ftype *RtlGetExtendedFeaturesMask;
+RtlSetExtendedFeaturesMask_ftype *RtlSetExtendedFeaturesMask;
+RtlLocateExtendedFeature_ftype *RtlLocateExtendedFeature;
+#endif
+#endif
+
/* Note that 'debug_events' must be locally defined in the relevant
functions. */
#define DEBUG_EVENTS(fmt, ...) \
@@ -1191,6 +1204,14 @@ initialize_loadable ()
GPA (hm, InitializeProcThreadAttributeList);
GPA (hm, UpdateProcThreadAttribute);
GPA (hm, DeleteProcThreadAttributeList);
+
+#if defined __i386__ || defined __x86_64__
+ GPA (hm, GetEnabledXStateFeatures);
+ GPA (hm, InitializeContext);
+ GPA (hm, GetXStateFeaturesMask);
+ GPA (hm, SetXStateFeaturesMask);
+ GPA (hm, LocateXStateFeature);
+#endif
}
/* Set variables to dummy versions of these processes if the function
@@ -1256,6 +1277,16 @@ initialize_loadable ()
GPA (hm, GetThreadDescription);
}
+#ifdef __x86_64__
+ hm = LoadLibrary (TEXT ("ntdll.dll"));
+ if (hm)
+ {
+ GPA (hm, RtlGetExtendedFeaturesMask);
+ GPA (hm, RtlSetExtendedFeaturesMask);
+ GPA (hm, RtlLocateExtendedFeature);
+ }
+#endif
+
#undef GPA
return result;
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index 76688fa90da..a344b0a966f 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -35,6 +35,9 @@
#define CONTEXT_EXTENDED_REGISTERS 0
#endif
+#define CONTEXT_EXTENDED_REGISTERS_FLAG 0x20
+#define CONTEXT_XSTATE_FLAG 0x40
+
namespace windows_nat
{
@@ -456,6 +459,14 @@ extern BOOL create_process (const wchar_t *image, wchar_t *command_line,
#define InitializeProcThreadAttributeList dyn_InitializeProcThreadAttributeList
#define UpdateProcThreadAttribute dyn_UpdateProcThreadAttribute
#define DeleteProcThreadAttributeList dyn_DeleteProcThreadAttributeList
+#define GetEnabledXStateFeatures dyn_GetEnabledXStateFeatures
+#define InitializeContext dyn_InitializeContext
+#define GetXStateFeaturesMask dyn_GetXStateFeaturesMask
+#define SetXStateFeaturesMask dyn_SetXStateFeaturesMask
+#define LocateXStateFeature dyn_LocateXStateFeature
+#define RtlGetExtendedFeaturesMask dyn_RtlGetExtendedFeaturesMask
+#define RtlSetExtendedFeaturesMask dyn_RtlSetExtendedFeaturesMask
+#define RtlLocateExtendedFeature dyn_RtlLocateExtendedFeature
typedef BOOL WINAPI (AdjustTokenPrivileges_ftype) (HANDLE, BOOL,
PTOKEN_PRIVILEGES,
@@ -550,6 +561,35 @@ extern DeleteProcThreadAttributeList_ftype *DeleteProcThreadAttributeList;
extern bool disable_randomization_available ();
+#if defined __i386__ || defined __x86_64__
+typedef DWORD64 (WINAPI GetEnabledXStateFeatures_ftype) ();
+extern GetEnabledXStateFeatures_ftype *GetEnabledXStateFeatures;
+
+typedef BOOL (WINAPI InitializeContext_ftype) (PVOID, DWORD,
+ PCONTEXT*, PDWORD);
+extern InitializeContext_ftype *InitializeContext;
+
+typedef BOOL (WINAPI GetXStateFeaturesMask_ftype) (PCONTEXT, PDWORD64);
+extern GetXStateFeaturesMask_ftype *GetXStateFeaturesMask;
+
+typedef BOOL (WINAPI SetXStateFeaturesMask_ftype) (PCONTEXT, DWORD64);
+extern SetXStateFeaturesMask_ftype *SetXStateFeaturesMask;
+
+typedef PVOID (WINAPI LocateXStateFeature_ftype) (PCONTEXT, DWORD, PDWORD);
+extern LocateXStateFeature_ftype *LocateXStateFeature;
+
+#ifdef __x86_64__
+typedef DWORD64 (WINAPI RtlGetExtendedFeaturesMask_ftype) (PVOID);
+extern RtlGetExtendedFeaturesMask_ftype *RtlGetExtendedFeaturesMask;
+
+typedef VOID (WINAPI RtlSetExtendedFeaturesMask_ftype) (PVOID, DWORD64);
+extern RtlSetExtendedFeaturesMask_ftype *RtlSetExtendedFeaturesMask;
+
+typedef PVOID (WINAPI RtlLocateExtendedFeature_ftype) (PVOID, DWORD, PDWORD);
+extern RtlLocateExtendedFeature_ftype *RtlLocateExtendedFeature;
+#endif
+#endif
+
/* Helper classes to get the correct ContextFlags values based on the
used type (CONTEXT or WOW64_CONTEXT). */
@@ -615,16 +655,69 @@ enum_process_modules (CONTEXT *, HANDLE process,
return EnumProcessModules (process, modules, size, needed);
}
+#if defined __i386__ || defined __x86_64__
+static inline BOOL
+get_xstate_features_mask (CONTEXT *context, DWORD64 *mask)
+{
+ return GetXStateFeaturesMask (context, mask);
+}
+
+static inline BOOL
+set_xstate_features_mask (CONTEXT *context, DWORD64 mask)
+{
+ return SetXStateFeaturesMask (context, mask);
+}
+
+static inline PVOID
+locate_xstate_feature (CONTEXT *context, DWORD feature, DWORD *length)
+{
+ return LocateXStateFeature (context, feature, length);
+}
+#endif
+
#ifdef __x86_64__
static inline BOOL
get_thread_context (HANDLE h, WOW64_CONTEXT *context)
{
+ if ((context->ContextFlags & CONTEXT_XSTATE_FLAG) != 0)
+ {
+ /* Wow64GetThreadContext doesn't handle CONTEXT_EXTENDED_REGISTERS and
+ CONTEXT_XSTATE combined correctly, but separate they work fine. */
+ DWORD flags = context->ContextFlags;
+ context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS_FLAG;
+ BOOL ret = Wow64GetThreadContext (h, context);
+ context->ContextFlags = flags;
+ if (!ret)
+ return FALSE;
+
+ context->ContextFlags &= ~CONTEXT_XSTATE_FLAG;
+ ret = Wow64GetThreadContext (h, context);
+ context->ContextFlags = flags;
+ return ret;
+ }
+
return Wow64GetThreadContext (h, context);
}
static inline BOOL
set_thread_context (HANDLE h, WOW64_CONTEXT *context)
{
+ if ((context->ContextFlags & CONTEXT_XSTATE_FLAG) != 0)
+ {
+ /* Same limitation as Wow64GetThreadContext above. */
+ DWORD flags = context->ContextFlags;
+ context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS_FLAG;
+ BOOL ret = Wow64SetThreadContext (h, context);
+ context->ContextFlags = flags;
+ if (!ret)
+ return FALSE;
+
+ context->ContextFlags &= ~CONTEXT_XSTATE_FLAG;
+ ret = Wow64SetThreadContext (h, context);
+ context->ContextFlags = flags;
+ return ret;
+ }
+
return Wow64SetThreadContext (h, context);
}
@@ -642,6 +735,29 @@ enum_process_modules (WOW64_CONTEXT *, HANDLE process,
return EnumProcessModulesEx (process, modules, size, needed,
LIST_MODULES_32BIT);
}
+
+static inline BOOL
+get_xstate_features_mask (WOW64_CONTEXT *context, DWORD64 *mask)
+{
+ /* Use lower level function, since there is no Wow64GetXStateFeaturesMask. */
+ *mask = RtlGetExtendedFeaturesMask (context + 1);
+ return TRUE;
+}
+
+static inline BOOL
+set_xstate_features_mask (WOW64_CONTEXT *context, DWORD64 mask)
+{
+ /* Use lower level function, since there is no Wow64SetXStateFeaturesMask. */
+ RtlSetExtendedFeaturesMask (context + 1, mask);
+ return TRUE;
+}
+
+static inline PVOID
+locate_xstate_feature (WOW64_CONTEXT *context, DWORD feature, DWORD *length)
+{
+ /* Use lower level function, since there is no Wow64LocateXStateFeature. */
+ return RtlLocateExtendedFeature (context + 1, feature, length);
+}
#endif
/* This is available starting with Windows 10. */
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 6/8] Windows gdb: Get available XState features
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
` (3 preceding siblings ...)
2026-07-27 17:42 ` [PATCH v2 5/8] Windows gdb: Prepare XState functions Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 7/8] Windows gdb: Implement XState (Intel AVX) support Hannes Domani
2026-07-27 17:42 ` [PATCH v2 8/8] Windows gdbserver: " Hannes Domani
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
Also prepares the thread context for the additional registers.
---
v2:
- Remove PKRU from the implemented features mask
---
gdb/nat/windows-nat.c | 54 ++++++++++++++++++++++++++++++++++++++++++-
gdb/nat/windows-nat.h | 5 ++++
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c
index cd1f9e7bc64..28678b9f1a7 100644
--- a/gdb/nat/windows-nat.c
+++ b/gdb/nat/windows-nat.c
@@ -20,6 +20,7 @@
#include "gdbsupport/common-debug.h"
#include "gdbsupport/gdb_signals.h"
#include "gdbsupport/gdb_wait.h"
+#include "gdbsupport/x86-xstate.h"
#include "target/target.h"
#undef GetModuleFileNameEx
@@ -84,6 +85,8 @@ RtlGetExtendedFeaturesMask_ftype *RtlGetExtendedFeaturesMask;
RtlSetExtendedFeaturesMask_ftype *RtlSetExtendedFeaturesMask;
RtlLocateExtendedFeature_ftype *RtlLocateExtendedFeature;
#endif
+
+DWORD64 xstate_features;
#endif
/* Note that 'debug_events' must be locally defined in the relevant
@@ -308,12 +311,38 @@ windows_process_info::pid_to_exec_file (int pid)
void windows_process_info::initialize_context (windows_thread_info *th)
{
+#if defined __i386__ || defined __x86_64__
+ if (xstate_features != 0)
+ {
+ DWORD context_flags = with_context (nullptr, [] (auto *context)
+ {
+ return WindowsContext<decltype(context)>::all;
+ });
+ context_flags |= CONTEXT_XSTATE_FLAG;
+ DWORD xstate_size = 0;
+ InitializeContext (NULL, context_flags, NULL, &xstate_size);
+ th->context_buffer.reset (xmalloc (xstate_size));
+ CONTEXT *context = nullptr;
+ if (!InitializeContext (th->context_buffer.get (),
+ context_flags, &context, &xstate_size))
+ error ("InitializeContext failure %lu\n", GetLastError ());
#ifdef __x86_64__
- if (wow64_process)
+ /* InitializeContext actually initializes a WOW64_CONTEXT when
+ context_flags contains a WOW64_CONTEXT_* value, so a cast is needed.
+ */
+ if (wow64_process)
+ th->wow64_context = (WOW64_CONTEXT *) context;
+ else
+#endif
+ th->context = context;
+ }
+#ifdef __x86_64__
+ else if (wow64_process)
{
th->context_buffer.reset (xmalloc (sizeof (WOW64_CONTEXT)));
th->wow64_context = (WOW64_CONTEXT *) th->context_buffer.get ();
}
+#endif
else
#endif
{
@@ -1289,6 +1318,29 @@ initialize_loadable ()
#undef GPA
+#if defined __i386__ || defined __x86_64__
+ if (GetEnabledXStateFeatures != nullptr
+ && InitializeContext != nullptr
+ && GetXStateFeaturesMask != nullptr
+ && SetXStateFeaturesMask != nullptr
+ && LocateXStateFeature != nullptr
+#ifdef __x86_64__
+ && RtlGetExtendedFeaturesMask != nullptr
+ && RtlSetExtendedFeaturesMask != nullptr
+ && RtlLocateExtendedFeature != nullptr
+#endif
+ )
+ {
+ /* Available XState features masked with implemented features. */
+ xstate_features = GetEnabledXStateFeatures ()
+ & (X86_XSTATE_AVX_AVX512_MASK | X86_XSTATE_CET_U);
+ /* The extended XState functions are only needed if the available
+ features exceed SSE. */
+ if ((xstate_features & ~X86_XSTATE_SSE_MASK) == 0)
+ xstate_features = 0;
+ }
+#endif
+
return result;
}
diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h
index a344b0a966f..8fcf5e339cb 100644
--- a/gdb/nat/windows-nat.h
+++ b/gdb/nat/windows-nat.h
@@ -760,6 +760,11 @@ locate_xstate_feature (WOW64_CONTEXT *context, DWORD feature, DWORD *length)
}
#endif
+#if defined __i386__ || defined __x86_64__
+/* Available XState features. */
+extern DWORD64 xstate_features;
+#endif
+
/* This is available starting with Windows 10. */
#ifndef DBG_REPLY_LATER
# define DBG_REPLY_LATER 0x40010001L
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 7/8] Windows gdb: Implement XState (Intel AVX) support
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
` (4 preceding siblings ...)
2026-07-27 17:42 ` [PATCH v2 6/8] Windows gdb: Get available XState features Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
2026-07-27 17:42 ` [PATCH v2 8/8] Windows gdbserver: " Hannes Domani
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
This adds support for the Intel AVX and AVX-512 registers on Windows.
It enables accessing registers $ymm0 - $ymm31, $zmm0 - $zmm31, and
$k0 - $k7 where they are available.
It also enables reading the shadow stack pointer register $pl3_ssp (for
executables marked compatible with CET shadow stack [1]), but modifying
it seems to be restricted restricted by windows.
After this patch the tests gdb.arch/i386-avx.exp and gdb.arch/i386-avx512.exp
pass on windows.
[1] https://learn.microsoft.com/en-us/cpp/build/reference/cetcompat
---
v2:
- Extended commit message and NEWS entry
- Remove PKRU support
- Fixed context offset of $pl3_ssp
---
gdb/NEWS | 6 +++
gdb/x86-windows-nat.c | 108 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 111 insertions(+), 3 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 8f40ca5cb11..71ff5508d6d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -116,6 +116,12 @@
intent to remove it in a future release.
The s390 64-bit target (s390x-*) remains supported.
+* Support for Intel AVX registers on Windows.
+ Support displaying and modifying Intel AVX registers $ymm0 - $ymm31.
+ Support displaying and modifying Intel AVX-512 registers $zmm0 - $zmm31
+ and $k0 - $k7.
+ Support displaying the shadow stack pointer register $pl3_ssp.
+
* Configure changes
** --with-babeltrace has been removed. The babeltrace library was
diff --git a/gdb/x86-windows-nat.c b/gdb/x86-windows-nat.c
index 3af5ef4dae0..270f9eae8e7 100644
--- a/gdb/x86-windows-nat.c
+++ b/gdb/x86-windows-nat.c
@@ -27,6 +27,9 @@
#include "i386-tdep.h"
#include "i387-tdep.h"
+#ifdef __x86_64__
+#include "amd64-tdep.h"
+#endif
using namespace windows_nat;
@@ -70,6 +73,8 @@ struct x86_windows_nat_target final : public x86_nat_target<windows_nat_target>
windows_thread_info *th, int r) override;
bool is_sw_breakpoint (const EXCEPTION_RECORD *er) const override;
+
+ const struct target_desc *read_description () override;
};
/* The current process. */
@@ -109,7 +114,31 @@ x86_windows_per_inferior::fill_thread_context (windows_thread_info *th)
if (context->ContextFlags == 0)
{
context->ContextFlags = WindowsContext<decltype(context)>::all;
+ if (xstate_features != 0)
+ {
+ context->ContextFlags |= CONTEXT_XSTATE_FLAG;
+ set_xstate_features_mask (context, xstate_features);
+ }
CHECK (get_thread_context (th->h, context));
+
+ if (xstate_features != 0)
+ {
+ DWORD64 features = 0;
+ CHECK (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);
+ }
+ }
+ }
}
});
}
@@ -198,6 +227,14 @@ x86_windows_nat_target::thread_context_continue (windows_thread_info *th,
if (GetExitCodeThread (th->h, &ec)
&& ec == STILL_ACTIVE)
{
+ 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);
+ }
+
BOOL status = set_thread_context (th->h, context);
if (!killed)
@@ -227,7 +264,7 @@ x86_windows_nat_target::thread_context_step (windows_thread_info *th,
template<typename Context>
static char *
-get_context_reg_ptr (Context *context, int r)
+get_context_reg_ptr (Context *context, int r, i386_gdbarch_tdep *tdep)
{
const int *mappings;
int mappings_count;
@@ -247,6 +284,54 @@ get_context_reg_ptr (Context *context, int r)
char *context_offset;
if (r < mappings_count)
context_offset = (char *) context + mappings[r];
+ else if (I387_ZMM0H_REGNUM (tdep) > 0 && r >= I387_ZMM0H_REGNUM (tdep)
+ && r < I387_ZMM16H_REGNUM (tdep) && r < I387_ZMMENDH_REGNUM (tdep))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_H_ID, NULL);
+ context_offset += 32 * (r - I387_ZMM0H_REGNUM (tdep));
+ }
+ else if (I387_ZMM0H_REGNUM (tdep) > 0 && r >= I387_ZMM16H_REGNUM (tdep)
+ && r < I387_ZMMENDH_REGNUM (tdep))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_ID, NULL);
+ context_offset += 32 + 64 * (r - I387_ZMM16H_REGNUM (tdep));
+ }
+ else if (I387_K0_REGNUM (tdep) > 0 && r >= I387_K0_REGNUM (tdep)
+ && r < I387_KEND_REGNUM (tdep))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_K_ID, NULL);
+ context_offset += 8 * (r - I387_K0_REGNUM (tdep));
+ }
+ else if (I387_YMM16H_REGNUM (tdep) > 0 && r >= I387_YMM16H_REGNUM (tdep)
+ && r < I387_YMMH_AVX512_END_REGNUM (tdep))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_ID, NULL);
+ context_offset += 16 + 64 * (r - I387_YMM16H_REGNUM (tdep));
+ }
+ else if (I387_XMM16_REGNUM (tdep) > 0 && r >= I387_XMM16_REGNUM (tdep)
+ && r < I387_XMM_AVX512_END_REGNUM (tdep))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_ZMM_ID, NULL);
+ context_offset += 64 * (r - I387_XMM16_REGNUM (tdep));
+ }
+ else if (I387_YMM0H_REGNUM (tdep) > 0 && r >= I387_YMM0H_REGNUM (tdep)
+ && r < I387_YMMENDH_REGNUM (tdep))
+ {
+ context_offset = (char *) locate_xstate_feature
+ (context, X86_XSTATE_AVX_ID, NULL);
+ context_offset += 16 * (r - I387_YMM0H_REGNUM (tdep));
+ }
+ else if (tdep->ssp_regnum > 0 && r == tdep->ssp_regnum)
+ {
+ 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);
@@ -267,7 +352,7 @@ x86_windows_nat_target::fetch_one_register (struct regcache *regcache,
char *context_offset
= x86_windows_process.with_context (th, [&] (auto *context)
{
- return get_context_reg_ptr (context, r);
+ return get_context_reg_ptr (context, r, tdep);
});
gdb_assert (!gdbarch_read_pc_p (gdbarch));
@@ -333,7 +418,7 @@ x86_windows_nat_target::store_one_register (const struct regcache *regcache,
= x86_windows_process.with_context (th, [&] (auto *context)
{
gdb_assert (context->ContextFlags != 0);
- return get_context_reg_ptr (context, r);
+ return get_context_reg_ptr (context, r, tdep);
});
/* GDB treats some registers as 32-bit, where they are in fact only
@@ -368,6 +453,23 @@ x86_windows_nat_target::is_sw_breakpoint (const EXCEPTION_RECORD *er) const
|| er->ExceptionCode == STATUS_WX86_BREAKPOINT);
}
+const struct target_desc *
+x86_windows_nat_target::read_description ()
+{
+ if (inferior_ptid == null_ptid)
+ return this->beneath ()->read_description ();
+
+ if (xstate_features == 0)
+ return nullptr;
+
+#ifdef __x86_64__
+ if (!x86_windows_process.wow64_process)
+ return amd64_target_description (xstate_features, false);
+ else
+#endif
+ return i386_target_description (xstate_features, false);
+}
+
/* Hardware watchpoint support, adapted from go32-nat.c code. */
/* Pass the address ADDR to the inferior in the I'th debug register.
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 8/8] Windows gdbserver: Implement XState (Intel AVX) support
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
` (5 preceding siblings ...)
2026-07-27 17:42 ` [PATCH v2 7/8] Windows gdb: Implement XState (Intel AVX) support Hannes Domani
@ 2026-07-27 17:42 ` Hannes Domani
6 siblings, 0 replies; 8+ messages in thread
From: Hannes Domani @ 2026-07-27 17:42 UTC (permalink / raw)
To: gdb-patches
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
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-07-27 17:49 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20260727174619.1089041-1-ssbssa.ref@yahoo.de>
2026-07-27 17:42 ` [PATCH v2 1/8] gdb/testsuite: Add Windows replacement for aligned_alloc Hannes Domani
2026-07-27 17:42 ` [PATCH v2 2/8] Windows gdb: Use allocated buffer for CONTEXT Hannes Domani
2026-07-27 17:42 ` [PATCH v2 3/8] Windows gdb: Remove mappings member from windows_per_inferior Hannes Domani
2026-07-27 17:42 ` [PATCH v2 4/8] Windows gdb: Refactor getting pointer to register inside context Hannes Domani
2026-07-27 17:42 ` [PATCH v2 5/8] Windows gdb: Prepare XState functions Hannes Domani
2026-07-27 17:42 ` [PATCH v2 6/8] Windows gdb: Get available XState features Hannes Domani
2026-07-27 17:42 ` [PATCH v2 7/8] Windows gdb: Implement XState (Intel AVX) support Hannes Domani
2026-07-27 17:42 ` [PATCH v2 8/8] Windows gdbserver: " Hannes Domani
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox