Backport patches for x86 XSTATE update in gdb and gdbserver.

Resolves: RHEL-10464
This commit is contained in:
Keith Seitz 2024-04-11 20:23:31 -07:00
parent 250ae50eab
commit bd876a4f72
25 changed files with 3740 additions and 2 deletions

View File

@ -521,3 +521,92 @@ Patch125: gdb-rhel-17399-sect_index_data-not-initialized.patch
# (Andreas Arnez, RHEL-10550)
Patch126: gdb-rhel-10550-add-arch14-record.patch
# Backport "x86: Add an x86_xsave_layout structure to
# handle variable XSAVE layouts."
# (John Baldwin, RHEL-10464)
Patch127: gdb-rhel-10464-xsave-update-1of21.patch
# Backport "gdb: Store an x86_xsave_layout in i386_gdbarch_tdep."
# (John Baldwin, RHEL-10464)
Patch128: gdb-rhel-10464-xsave-update-2of21.patch
# Backport "core: Support fetching x86 XSAVE layout from architectures."
# (John Baldwin, RHEL-10464)
Patch129: gdb-rhel-10464-xsave-update-3of21.patch
# Backport "nat/x86--cpuid.h: Add x86_cpuid_count wrapper around
# __get_cpuid_count."
# (John Baldwin, RHEL-10464)
Patch130: gdb-rhel-10464-xsave-update-4of21.patch
# Backport "x86 nat: Add helper functions to save the XSAVE layout for
# the host."
# (John Baldwin, RHEL-10464)
Patch131: gdb-rhel-10464-xsave-update-5of21.patch
# Backport "gdb: Update x86 Linux architectures to support XSAVE layouts."
# (John Baldwin, RHEL-10464)
Patch132: gdb-rhel-10464-xsave-update-6of21.patch
# Backport "gdb: Support XSAVE layouts for the current host in the Linux
# x86 targets."
# (John Baldwin, RHEL-10464)
Patch133: gdb-rhel-10464-xsave-update-7of21.patch
# Backport "gdb: Use x86_xstate_layout to parse the XSAVE extended state area."
# (John Baldwin, RHEL-10464)
Patch134: gdb-rhel-10464-xsave-update-8of21.patch
# Backport "gdbserver: Add a function to set the XSAVE mask and size."
# (John Baldwin, RHEL-10464)
Patch135: gdb-rhel-10464-xsave-update-9of21.patch
# Backport "x86: Remove X86_XSTATE_SIZE and related constants."
# (John Baldwin, RHEL-10464)
Patch136: gdb-rhel-10464-xsave-update-10of21.patch
# Backport "[gdb/tdep] Fix avx512 -m32 support in gdbserver"
# (Tom de Vries, RHEL-10464)
Patch137: gdb-rhel-10464-xsave-update-11of21.patch
# Backport "gdbserver: Use x86_xstate_layout to parse the XSAVE extended
# state area."
# (Aleksandar Paunovic, RHEL-10464)
Patch138: gdb-rhel-10464-xsave-update-12of21.patch
# Backport "gdbserver: Simplify handling of ZMM registers."
# (John Baldwin, RHEL-10464)
Patch139: gdb-rhel-10464-xsave-update-13of21.patch
# Backport "gdbserver: Refactor the legacy region within the xsave struct"
# (Aleksandar Paunovic, RHEL-10464)
Patch140: gdb-rhel-10464-xsave-update-14of21.patch
# Backport "gdbserver: Fix style of struct declarations in i387-fp.cc"
# (John Baldwin, RHEL-10464)
Patch141: gdb-rhel-10464-xsave-update-15of21.patch
# Backport "nat/x86-cpuid.h: Remove non-x86 fallbacks"
# (John Baldwin, RHEL-10464)
Patch142: gdb-rhel-10464-xsave-update-16of21.patch
# Backport "i386: Use a fallback XSAVE layout for remote targets"
# (John Baldwin, RHEL-10464)
Patch143: gdb-rhel-10464-xsave-update-17of21.patch
# Backport "gdbserver: i387_cache_to_xsave: fix copy dest of zmm registers"
# (Simon Marchi, RHEL-10464)
Patch144: gdb-rhel-10464-xsave-update-18of21.patch
# Backport "bfd/binutils: support for gdb target descriptions in the core file"
# (Andrew Burgess, RHEL-10464)
Patch145: gdb-rhel-10464-xsave-update-19of21.patch
# Backport "gdb: write target description into core file"
# (Andrew Burgess, RHEL-10464)
Patch146: gdb-rhel-10464-xsave-update-20of21.patch
# Backport "gdb/corefile: write NT_GDB_TDESC based on signalled thread"
# (Andrew Burgess, RHEL-10464)
Patch147: gdb-rhel-10464-xsave-update-21of21.patch

View File

@ -124,3 +124,24 @@
%patch124 -p1
%patch125 -p1
%patch126 -p1
%patch127 -p1
%patch128 -p1
%patch129 -p1
%patch130 -p1
%patch131 -p1
%patch132 -p1
%patch133 -p1
%patch134 -p1
%patch135 -p1
%patch136 -p1
%patch137 -p1
%patch138 -p1
%patch139 -p1
%patch140 -p1
%patch141 -p1
%patch142 -p1
%patch143 -p1
%patch144 -p1
%patch145 -p1
%patch146 -p1
%patch147 -p1

View File

@ -124,3 +124,24 @@ gdb-find_and_open_source-empty-string-ub-3of4.patch
gdb-find_and_open_source-empty-string-ub-4of4.patch
gdb-rhel-17399-sect_index_data-not-initialized.patch
gdb-rhel-10550-add-arch14-record.patch
gdb-rhel-10464-xsave-update-1of21.patch
gdb-rhel-10464-xsave-update-2of21.patch
gdb-rhel-10464-xsave-update-3of21.patch
gdb-rhel-10464-xsave-update-4of21.patch
gdb-rhel-10464-xsave-update-5of21.patch
gdb-rhel-10464-xsave-update-6of21.patch
gdb-rhel-10464-xsave-update-7of21.patch
gdb-rhel-10464-xsave-update-8of21.patch
gdb-rhel-10464-xsave-update-9of21.patch
gdb-rhel-10464-xsave-update-10of21.patch
gdb-rhel-10464-xsave-update-11of21.patch
gdb-rhel-10464-xsave-update-12of21.patch
gdb-rhel-10464-xsave-update-13of21.patch
gdb-rhel-10464-xsave-update-14of21.patch
gdb-rhel-10464-xsave-update-15of21.patch
gdb-rhel-10464-xsave-update-16of21.patch
gdb-rhel-10464-xsave-update-17of21.patch
gdb-rhel-10464-xsave-update-18of21.patch
gdb-rhel-10464-xsave-update-19of21.patch
gdb-rhel-10464-xsave-update-20of21.patch
gdb-rhel-10464-xsave-update-21of21.patch

View File

@ -0,0 +1,39 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:44 -0700
Subject: gdb-rhel-10464-xsave-update-10of21.patch
;; Backport "x86: Remove X86_XSTATE_SIZE and related constants."
;; (John Baldwin, RHEL-10464)
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
--- a/gdbsupport/x86-xstate.h
+++ b/gdbsupport/x86-xstate.h
@@ -99,11 +99,6 @@ constexpr bool operator!= (const x86_xsave_layout &lhs,
#define X86_XSTATE_SSE_SIZE 576
#define X86_XSTATE_AVX_SIZE 832
-#define X86_XSTATE_BNDREGS_SIZE 1024
-#define X86_XSTATE_BNDCFG_SIZE 1088
-#define X86_XSTATE_AVX512_SIZE 2688
-#define X86_XSTATE_PKRU_SIZE 2696
-#define X86_XSTATE_MAX_SIZE 2696
/* In case one of the MPX XCR0 bits is set we consider we have MPX. */
@@ -112,13 +107,6 @@ constexpr bool operator!= (const x86_xsave_layout &lhs,
#define HAS_AVX512(XCR0) (((XCR0) & X86_XSTATE_AVX512) != 0)
#define HAS_PKRU(XCR0) (((XCR0) & X86_XSTATE_PKRU) != 0)
-/* Get I386 XSAVE extended state size. */
-#define X86_XSTATE_SIZE(XCR0) \
- (HAS_PKRU (XCR0) ? X86_XSTATE_PKRU_SIZE : \
- (HAS_AVX512 (XCR0) ? X86_XSTATE_AVX512_SIZE : \
- (HAS_MPX (XCR0) ? X86_XSTATE_BNDCFG_SIZE : \
- (HAS_AVX (XCR0) ? X86_XSTATE_AVX_SIZE : X86_XSTATE_SSE_SIZE))))
-
/* Initial value for fctrl register, as defined in the X86 manual, and
confirmed in the (Linux) kernel source. When the x87 floating point
feature is not enabled in an inferior we use this as the value of the

View File

@ -0,0 +1,170 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Tom de Vries <tdevries@suse.de>
Date: Thu, 11 Apr 2024 14:05:44 -0700
Subject: gdb-rhel-10464-xsave-update-11of21.patch
;; Backport "[gdb/tdep] Fix avx512 -m32 support in gdbserver"
;; (Tom de Vries, RHEL-10464)
PR27257 reports a problem that can be reproduced as follows:
- use x86_64 machine with avx512 support
- compile a hello world with -m32 to a.out
- start a gdbserver session with a.out
- use gdb to connect to the gdbserver session
This makes us run into:
...
Listening on port 2346
Remote debugging from host ::1, port 34940
src/gdbserver/regcache.cc:257: \
A problem internal to GDBserver has been detected.
Unknown register zmm16h requested
...
The problem is that i387_xsave_to_cache in gdbserver/i387-fp.cc can't find a
register zmm16h in the register cache.
To understand how this happens, first some background.
SSE has 16 128-bit wide xmm registers.
AVX extends the SSE registers set as follows:
- it extends the 16 existing 128-bit wide xmm registers to 256-bit wide ymm
registers.
AVX512 extends the AVX register set as follows:
- it extends the 16 existing 256-bit wide ymm registers to 512-bit wide zmm
registers.
- it adds 16 additional 512-bit wide zmm registers (with corresponding ymm and
xmm subregisters added as well)
However, in 32-bit mode, there are only 8 xmm/ymm/zmm registers.
The problem we're running into is that gdbserver/i387-fp.cc uses these
constants to describe the size of the register file:
...
static const int num_avx512_zmmh_low_registers = 16;
static const int num_avx512_zmmh_high_registers = 16;
static const int num_avx512_ymmh_registers = 16;
static const int num_avx512_xmm_registers = 16;
...
which are all incorrect for the 32-bit case.
Fix this by replacing the constants with variables that have the appropriate
values in 64-bit and 32-bit mode.
Tested on x86_64-linux with native and unix/-m32.
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -27,10 +27,6 @@ static unsigned long long x86_xcr0 = X86_XSTATE_SSE_MASK;
static const int num_mpx_bnd_registers = 4;
static const int num_mpx_cfg_registers = 2;
static const int num_avx512_k_registers = 8;
-static const int num_avx512_zmmh_low_registers = 16;
-static const int num_avx512_zmmh_high_registers = 16;
-static const int num_avx512_ymmh_registers = 16;
-static const int num_avx512_xmm_registers = 16;
static const int num_pkeys_registers = 1;
static x86_xsave_layout xsave_layout;
@@ -262,14 +258,22 @@ void
i387_cache_to_xsave (struct regcache *regcache, void *buf)
{
struct i387_xsave *fp = (struct i387_xsave *) buf;
+ bool amd64 = register_size (regcache->tdesc, 0) == 8;
int i;
unsigned long val, val2;
unsigned long long xstate_bv = 0;
unsigned long long clear_bv = 0;
char raw[64];
char *p;
+
/* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
- int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8;
+ int num_xmm_registers = amd64 ? 16 : 8;
+ /* AVX512 extends the existing xmm/ymm registers to a wider mode: zmm. */
+ int num_avx512_zmmh_low_registers = num_xmm_registers;
+ /* AVX512 adds 16 extra regs in Amd64 mode, but none in I386 mode.*/
+ int num_avx512_zmmh_high_registers = amd64 ? 16 : 0;
+ int num_avx512_ymmh_registers = amd64 ? 16 : 0;
+ int num_avx512_xmm_registers = amd64 ? 16 : 0;
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
@@ -458,7 +462,9 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
/* Check if any of ZMM16H-ZMM31H registers are changed. */
if ((x86_xcr0 & X86_XSTATE_ZMM))
{
- int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
+ int zmm16h_regnum = (num_avx512_zmmh_high_registers == 0
+ ? -1
+ : find_regno (regcache->tdesc, "zmm16h"));
for (i = 0; i < num_avx512_zmmh_high_registers; i++)
{
@@ -475,7 +481,9 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
/* Check if any XMM_AVX512 registers are changed. */
if ((x86_xcr0 & X86_XSTATE_ZMM))
{
- int xmm_avx512_regnum = find_regno (regcache->tdesc, "xmm16");
+ int xmm_avx512_regnum = (num_avx512_xmm_registers == 0
+ ? -1
+ : find_regno (regcache->tdesc, "xmm16"));
for (i = 0; i < num_avx512_xmm_registers; i++)
{
@@ -492,7 +500,9 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
/* Check if any YMMH_AVX512 registers are changed. */
if ((x86_xcr0 & X86_XSTATE_ZMM))
{
- int ymmh_avx512_regnum = find_regno (regcache->tdesc, "ymm16h");
+ int ymmh_avx512_regnum = (num_avx512_ymmh_registers == 0
+ ? -1
+ : find_regno (regcache->tdesc, "ymm16h"));
for (i = 0; i < num_avx512_ymmh_registers; i++)
{
@@ -716,12 +726,20 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
{
struct i387_xsave *fp = (struct i387_xsave *) buf;
struct i387_fxsave *fxp = (struct i387_fxsave *) buf;
+ bool amd64 = register_size (regcache->tdesc, 0) == 8;
int i, top;
unsigned long val;
unsigned long long clear_bv;
gdb_byte *p;
- /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
- int num_xmm_registers = register_size (regcache->tdesc, 0) == 8 ? 16 : 8;
+
+ /* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
+ int num_xmm_registers = amd64 ? 16 : 8;
+ /* AVX512 extends the existing xmm/ymm registers to a wider mode: zmm. */
+ int num_avx512_zmmh_low_registers = num_xmm_registers;
+ /* AVX512 adds 16 extra regs in Amd64 mode, but none in I386 mode.*/
+ int num_avx512_zmmh_high_registers = amd64 ? 16 : 0;
+ int num_avx512_ymmh_registers = amd64 ? 16 : 0;
+ int num_avx512_xmm_registers = amd64 ? 16 : 0;
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
@@ -851,9 +869,15 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
if ((x86_xcr0 & X86_XSTATE_ZMM) != 0)
{
- int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
- int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
- int xmm16_regnum = find_regno (regcache->tdesc, "xmm16");
+ int zmm16h_regnum = (num_avx512_zmmh_high_registers == 0
+ ? -1
+ : find_regno (regcache->tdesc, "zmm16h"));
+ int ymm16h_regnum = (num_avx512_ymmh_registers == 0
+ ? -1
+ : find_regno (regcache->tdesc, "ymm16h"));
+ int xmm16_regnum = (num_avx512_xmm_registers == 0
+ ? -1
+ : find_regno (regcache->tdesc, "xmm16"));
if ((clear_bv & X86_XSTATE_ZMM) != 0)
{

View File

@ -0,0 +1,341 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Aleksandar Paunovic <aleksandar.paunovic@intel.com>
Date: Thu, 11 Apr 2024 14:05:45 -0700
Subject: gdb-rhel-10464-xsave-update-12of21.patch
;; Backport "gdbserver: Use x86_xstate_layout to parse the XSAVE extended
;; state area."
;; (Aleksandar Paunovic, RHEL-10464)
Replace the extended state area fields of i387_xsave with methods which
return an offset into the XSAVE buffer.
The two changed functions are called within all tests which runs
gdbserver.
Signed-off-by: Aleksandar Paunovic <aleksandar.paunovic@intel.com>
Co-authored-by: John Baldwin <jhb@FreeBSD.org>
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -81,6 +81,8 @@ struct i387_fxsave {
unsigned char xmm_space[256];
};
+gdb_static_assert (sizeof(i387_fxsave) == 416);
+
struct i387_xsave {
/* All these are only sixteen bits, plus padding, except for fop (which
is only eleven bits), and fooff / fioff (which are 32 bits each). */
@@ -115,36 +117,57 @@ struct i387_xsave {
/* The XSTATE_BV bit vector. */
unsigned long long xstate_bv;
- unsigned char reserved3[56];
-
- /* Space for eight upper 128-bit YMM values, or 16 on x86-64. */
- unsigned char ymmh_space[256];
+ /* The XCOMP_BV bit vector. */
+ unsigned long long xcomp_bv;
- unsigned char reserved4[128];
+ unsigned char reserved3[48];
- /* Space for 4 bound registers values of 128 bits. */
- unsigned char mpx_bnd_space[64];
-
- /* Space for 2 MPX configuration registers of 64 bits
- plus reserved space. */
- unsigned char mpx_cfg_space[16];
+ /* Byte 576. End of registers with fixed position in XSAVE.
+ The position of other XSAVE registers will be calculated
+ from the appropriate CPUID calls. */
- unsigned char reserved5[48];
+private:
+ /* Base address of XSAVE data as an unsigned char *. Used to derive
+ pointers to XSAVE state components in the extended state
+ area. */
+ unsigned char *xsave ()
+ { return reinterpret_cast<unsigned char *> (this); }
- /* Space for 8 OpMask register values of 64 bits. */
- unsigned char k_space[64];
+public:
+ /* Memory address of eight upper 128-bit YMM values, or 16 on x86-64. */
+ unsigned char *ymmh_space ()
+ { return xsave () + xsave_layout.avx_offset; }
- /* Space for 16 256-bit zmm0-15. */
- unsigned char zmmh_low_space[512];
+ /* Memory address of 4 bound registers values of 128 bits. */
+ unsigned char *bndregs_space ()
+ { return xsave () + xsave_layout.bndregs_offset; }
- /* Space for 16 512-bit zmm16-31 values. */
- unsigned char zmmh_high_space[1024];
-
- /* Space for 1 32-bit PKRU register. The HW XSTATE size for this feature is
- actually 64 bits, but WRPKRU/RDPKRU instructions ignore upper 32 bits. */
- unsigned char pkru_space[8];
+ /* Memory address of 2 MPX configuration registers of 64 bits
+ plus reserved space. */
+ unsigned char *bndcfg_space ()
+ { return xsave () + xsave_layout.bndcfg_offset; }
+
+ /* Memory address of 8 OpMask register values of 64 bits. */
+ unsigned char *k_space ()
+ { return xsave () + xsave_layout.k_offset; }
+
+ /* Memory address of 16 256-bit zmm0-15. */
+ unsigned char *zmmh_space ()
+ { return xsave () + xsave_layout.zmm_h_offset; }
+
+ /* Memory address of 16 512-bit zmm16-31 values. */
+ unsigned char *zmm16_space ()
+ { return xsave () + xsave_layout.zmm_offset; }
+
+ /* Memory address of 1 32-bit PKRU register. The HW XSTATE size for this
+ feature is actually 64 bits, but WRPKRU/RDPKRU instructions ignore upper
+ 32 bits. */
+ unsigned char *pkru_space ()
+ { return xsave () + xsave_layout.pkru_offset; }
};
+gdb_static_assert (sizeof(i387_xsave) == 576);
+
void
i387_cache_to_fsave (struct regcache *regcache, void *buf)
{
@@ -264,7 +287,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
unsigned long long xstate_bv = 0;
unsigned long long clear_bv = 0;
char raw[64];
- char *p;
+ unsigned char *p;
/* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
int num_xmm_registers = amd64 ? 16 : 8;
@@ -304,40 +327,40 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
if ((clear_bv & X86_XSTATE_AVX))
for (i = 0; i < num_xmm_registers; i++)
- memset (((char *) &fp->ymmh_space[0]) + i * 16, 0, 16);
+ memset (fp->ymmh_space () + i * 16, 0, 16);
if ((clear_bv & X86_XSTATE_SSE) && (clear_bv & X86_XSTATE_AVX))
memset (((char *) &fp->mxcsr), 0, 4);
if ((clear_bv & X86_XSTATE_BNDREGS))
for (i = 0; i < num_mpx_bnd_registers; i++)
- memset (((char *) &fp->mpx_bnd_space[0]) + i * 16, 0, 16);
+ memset (fp->bndregs_space () + i * 16, 0, 16);
if ((clear_bv & X86_XSTATE_BNDCFG))
for (i = 0; i < num_mpx_cfg_registers; i++)
- memset (((char *) &fp->mpx_cfg_space[0]) + i * 8, 0, 8);
+ memset (fp->bndcfg_space () + i * 8, 0, 8);
if ((clear_bv & X86_XSTATE_K))
for (i = 0; i < num_avx512_k_registers; i++)
- memset (((char *) &fp->k_space[0]) + i * 8, 0, 8);
+ memset (fp->k_space () + i * 8, 0, 8);
if ((clear_bv & X86_XSTATE_ZMM_H))
for (i = 0; i < num_avx512_zmmh_low_registers; i++)
- memset (((char *) &fp->zmmh_low_space[0]) + i * 32, 0, 32);
+ memset (fp->zmmh_space () + i * 32, 0, 32);
if ((clear_bv & X86_XSTATE_ZMM))
{
for (i = 0; i < num_avx512_zmmh_high_registers; i++)
- memset (((char *) &fp->zmmh_low_space[0]) + 32 + i * 64, 0, 32);
+ memset (fp->zmm16_space () + 32 + i * 64, 0, 32);
for (i = 0; i < num_avx512_xmm_registers; i++)
- memset (((char *) &fp->zmmh_high_space[0]) + i * 64, 0, 16);
+ memset (fp->zmm16_space () + i * 64, 0, 16);
for (i = 0; i < num_avx512_ymmh_registers; i++)
- memset (((char *) &fp->zmmh_high_space[0]) + 16 + i * 64, 0, 16);
+ memset (fp->zmm16_space () + 16 + i * 64, 0, 16);
}
if ((clear_bv & X86_XSTATE_PKRU))
for (i = 0; i < num_pkeys_registers; i++)
- memset (((char *) &fp->pkru_space[0]) + i * 4, 0, 4);
+ memset (fp->pkru_space () + i * 4, 0, 4);
}
/* Check if any x87 registers are changed. */
@@ -348,7 +371,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < 8; i++)
{
collect_register (regcache, i + st0_regnum, raw);
- p = ((char *) &fp->st_space[0]) + i * 16;
+ p = fp->st_space + i * 16;
if (memcmp (raw, p, 10))
{
xstate_bv |= X86_XSTATE_X87;
@@ -365,7 +388,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_xmm_registers; i++)
{
collect_register (regcache, i + xmm0_regnum, raw);
- p = ((char *) &fp->xmm_space[0]) + i * 16;
+ p = fp->xmm_space + i * 16;
if (memcmp (raw, p, 16))
{
xstate_bv |= X86_XSTATE_SSE;
@@ -382,7 +405,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_xmm_registers; i++)
{
collect_register (regcache, i + ymm0h_regnum, raw);
- p = ((char *) &fp->ymmh_space[0]) + i * 16;
+ p = fp->ymmh_space () + i * 16;
if (memcmp (raw, p, 16))
{
xstate_bv |= X86_XSTATE_AVX;
@@ -399,7 +422,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_mpx_bnd_registers; i++)
{
collect_register (regcache, i + bnd0r_regnum, raw);
- p = ((char *) &fp->mpx_bnd_space[0]) + i * 16;
+ p = fp->bndregs_space () + i * 16;
if (memcmp (raw, p, 16))
{
xstate_bv |= X86_XSTATE_BNDREGS;
@@ -416,7 +439,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_mpx_cfg_registers; i++)
{
collect_register (regcache, i + bndcfg_regnum, raw);
- p = ((char *) &fp->mpx_cfg_space[0]) + i * 8;
+ p = fp->bndcfg_space () + i * 8;
if (memcmp (raw, p, 8))
{
xstate_bv |= X86_XSTATE_BNDCFG;
@@ -433,7 +456,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_avx512_k_registers; i++)
{
collect_register (regcache, i + k0_regnum, raw);
- p = ((char *) &fp->k_space[0]) + i * 8;
+ p = fp->k_space () + i * 8;
if (memcmp (raw, p, 8) != 0)
{
xstate_bv |= X86_XSTATE_K;
@@ -450,7 +473,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_avx512_zmmh_low_registers; i++)
{
collect_register (regcache, i + zmm0h_regnum, raw);
- p = ((char *) &fp->zmmh_low_space[0]) + i * 32;
+ p = fp->zmmh_space () + i * 32;
if (memcmp (raw, p, 32) != 0)
{
xstate_bv |= X86_XSTATE_ZMM_H;
@@ -469,7 +492,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_avx512_zmmh_high_registers; i++)
{
collect_register (regcache, i + zmm16h_regnum, raw);
- p = ((char *) &fp->zmmh_high_space[0]) + 32 + i * 64;
+ p = fp->zmm16_space () + 32 + i * 64;
if (memcmp (raw, p, 32) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
@@ -488,7 +511,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_avx512_xmm_registers; i++)
{
collect_register (regcache, i + xmm_avx512_regnum, raw);
- p = ((char *) &fp->zmmh_high_space[0]) + i * 64;
+ p = fp->zmm16_space () + i * 64;
if (memcmp (raw, p, 16) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
@@ -507,7 +530,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_avx512_ymmh_registers; i++)
{
collect_register (regcache, i + ymmh_avx512_regnum, raw);
- p = ((char *) &fp->zmmh_high_space[0]) + 16 + i * 64;
+ p = fp->zmm16_space () + 16 + i * 64;
if (memcmp (raw, p, 16) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
@@ -524,7 +547,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
for (i = 0; i < num_pkeys_registers; i++)
{
collect_register (regcache, i + pkru_regnum, raw);
- p = ((char *) &fp->pkru_space[0]) + i * 4;
+ p = fp->pkru_space () + i * 4;
if (memcmp (raw, p, 4) != 0)
{
xstate_bv |= X86_XSTATE_PKRU;
@@ -730,7 +753,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
int i, top;
unsigned long val;
unsigned long long clear_bv;
- gdb_byte *p;
+ unsigned char *p;
/* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
int num_xmm_registers = amd64 ? 16 : 8;
@@ -791,7 +814,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->ymmh_space[0];
+ p = fp->ymmh_space ();
for (i = 0; i < num_xmm_registers; i++)
supply_register (regcache, i + ymm0h_regnum, p + i * 16);
}
@@ -809,7 +832,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->mpx_bnd_space[0];
+ p = fp->bndregs_space ();
for (i = 0; i < num_mpx_bnd_registers; i++)
supply_register (regcache, i + bnd0r_regnum, p + i * 16);
}
@@ -827,7 +850,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->mpx_cfg_space[0];
+ p = fp->bndcfg_space ();
for (i = 0; i < num_mpx_cfg_registers; i++)
supply_register (regcache, i + bndcfg_regnum, p + i * 8);
}
@@ -844,7 +867,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->k_space[0];
+ p = fp->k_space ();
for (i = 0; i < num_avx512_k_registers; i++)
supply_register (regcache, i + k0_regnum, p + i * 8);
}
@@ -861,7 +884,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->zmmh_low_space[0];
+ p = fp->zmmh_space ();
for (i = 0; i < num_avx512_zmmh_low_registers; i++)
supply_register (regcache, i + zmm0h_regnum, p + i * 32);
}
@@ -890,7 +913,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->zmmh_high_space[0];
+ p = fp->zmm16_space ();
for (i = 0; i < num_avx512_zmmh_high_registers; i++)
supply_register (regcache, i + zmm16h_regnum, p + 32 + i * 64);
for (i = 0; i < num_avx512_ymmh_registers; i++)
@@ -911,7 +934,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
else
{
- p = (gdb_byte *) &fp->pkru_space[0];
+ p = fp->pkru_space ();
for (i = 0; i < num_pkeys_registers; i++)
supply_register (regcache, i + pkru_regnum, p + i * 4);
}

View File

@ -0,0 +1,229 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:45 -0700
Subject: gdb-rhel-10464-xsave-update-13of21.patch
;; Backport "gdbserver: Simplify handling of ZMM registers."
;; (John Baldwin, RHEL-10464)
- Reuse num_xmm_registers directly for the count of ZMM0-15 registers
as is already done for the YMM registers for AVX rather than using
a new variable that is always the same.
- Replace 3 identical variables for the count of upper ZMM16-31
registers with a single variable. Make use of this to merge
various loops working on the ZMM XSAVE region so that all of the
handling for the various sub-registers in this region are always
handled in a single loop.
- While here, fix some bugs in i387_cache_to_xsave where if
X86_XSTATE_ZMM was set on i386 (e.g. a 32-bit process on a 64-bit
kernel), the -1 register nums would wrap around and store the value
of GPRs in the XSAVE area. This should be harmless, but is
definitely odd. Instead, check num_zmm_high_registers directly when
checking X86_XSTATE_ZMM and skip the ZMM region handling entirely if
the register count is 0.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -291,12 +291,8 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
/* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
int num_xmm_registers = amd64 ? 16 : 8;
- /* AVX512 extends the existing xmm/ymm registers to a wider mode: zmm. */
- int num_avx512_zmmh_low_registers = num_xmm_registers;
- /* AVX512 adds 16 extra regs in Amd64 mode, but none in I386 mode.*/
- int num_avx512_zmmh_high_registers = amd64 ? 16 : 0;
- int num_avx512_ymmh_registers = amd64 ? 16 : 0;
- int num_avx512_xmm_registers = amd64 ? 16 : 0;
+ /* AVX512 adds 16 extra ZMM regs in Amd64 mode, but none in I386 mode.*/
+ int num_zmm_high_registers = amd64 ? 16 : 0;
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
@@ -345,18 +341,12 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
memset (fp->k_space () + i * 8, 0, 8);
if ((clear_bv & X86_XSTATE_ZMM_H))
- for (i = 0; i < num_avx512_zmmh_low_registers; i++)
+ for (i = 0; i < num_xmm_registers; i++)
memset (fp->zmmh_space () + i * 32, 0, 32);
if ((clear_bv & X86_XSTATE_ZMM))
- {
- for (i = 0; i < num_avx512_zmmh_high_registers; i++)
- memset (fp->zmm16_space () + 32 + i * 64, 0, 32);
- for (i = 0; i < num_avx512_xmm_registers; i++)
- memset (fp->zmm16_space () + i * 64, 0, 16);
- for (i = 0; i < num_avx512_ymmh_registers; i++)
- memset (fp->zmm16_space () + 16 + i * 64, 0, 16);
- }
+ for (i = 0; i < num_zmm_high_registers; i++)
+ memset (fp->zmm16_space () + i * 64, 0, 64);
if ((clear_bv & X86_XSTATE_PKRU))
for (i = 0; i < num_pkeys_registers; i++)
@@ -470,7 +460,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
{
int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h");
- for (i = 0; i < num_avx512_zmmh_low_registers; i++)
+ for (i = 0; i < num_xmm_registers; i++)
{
collect_register (regcache, i + zmm0h_regnum, raw);
p = fp->zmmh_space () + i * 32;
@@ -482,55 +472,36 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
}
- /* Check if any of ZMM16H-ZMM31H registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_ZMM))
+ /* Check if any of ZMM16-ZMM31 registers are changed. */
+ if ((x86_xcr0 & X86_XSTATE_ZMM) && num_zmm_high_registers != 0)
{
- int zmm16h_regnum = (num_avx512_zmmh_high_registers == 0
- ? -1
- : find_regno (regcache->tdesc, "zmm16h"));
+ int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
+ int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
+ int xmm16_regnum = find_regno (regcache->tdesc, "xmm16");
- for (i = 0; i < num_avx512_zmmh_high_registers; i++)
+ for (i = 0; i < num_zmm_high_registers; i++)
{
+ p = fp->zmm16_space () + i * 64;
+
+ /* ZMMH sub-register. */
collect_register (regcache, i + zmm16h_regnum, raw);
p = fp->zmm16_space () + 32 + i * 64;
- if (memcmp (raw, p, 32) != 0)
+ if (memcmp (raw, p + 32, 32) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
memcpy (p, raw, 32);
}
- }
- }
-
- /* Check if any XMM_AVX512 registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_ZMM))
- {
- int xmm_avx512_regnum = (num_avx512_xmm_registers == 0
- ? -1
- : find_regno (regcache->tdesc, "xmm16"));
- for (i = 0; i < num_avx512_xmm_registers; i++)
- {
- collect_register (regcache, i + xmm_avx512_regnum, raw);
- p = fp->zmm16_space () + i * 64;
- if (memcmp (raw, p, 16) != 0)
+ /* YMMH sub-register. */
+ collect_register (regcache, i + ymm16h_regnum, raw);
+ if (memcmp (raw, p + 16, 16) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
memcpy (p, raw, 16);
}
- }
- }
- /* Check if any YMMH_AVX512 registers are changed. */
- if ((x86_xcr0 & X86_XSTATE_ZMM))
- {
- int ymmh_avx512_regnum = (num_avx512_ymmh_registers == 0
- ? -1
- : find_regno (regcache->tdesc, "ymm16h"));
-
- for (i = 0; i < num_avx512_ymmh_registers; i++)
- {
- collect_register (regcache, i + ymmh_avx512_regnum, raw);
- p = fp->zmm16_space () + 16 + i * 64;
+ /* XMM sub-register. */
+ collect_register (regcache, i + xmm16_regnum, raw);
if (memcmp (raw, p, 16) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
@@ -757,12 +728,8 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
/* Amd64 has 16 xmm regs; I386 has 8 xmm regs. */
int num_xmm_registers = amd64 ? 16 : 8;
- /* AVX512 extends the existing xmm/ymm registers to a wider mode: zmm. */
- int num_avx512_zmmh_low_registers = num_xmm_registers;
- /* AVX512 adds 16 extra regs in Amd64 mode, but none in I386 mode.*/
- int num_avx512_zmmh_high_registers = amd64 ? 16 : 0;
- int num_avx512_ymmh_registers = amd64 ? 16 : 0;
- int num_avx512_xmm_registers = amd64 ? 16 : 0;
+ /* AVX512 adds 16 extra ZMM regs in Amd64 mode, but none in I386 mode.*/
+ int num_zmm_high_registers = amd64 ? 16 : 0;
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
@@ -879,47 +846,41 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
if ((clear_bv & X86_XSTATE_ZMM_H) != 0)
{
- for (i = 0; i < num_avx512_zmmh_low_registers; i++)
+ for (i = 0; i < num_xmm_registers; i++)
supply_register_zeroed (regcache, i + zmm0h_regnum);
}
else
{
p = fp->zmmh_space ();
- for (i = 0; i < num_avx512_zmmh_low_registers; i++)
+ for (i = 0; i < num_xmm_registers; i++)
supply_register (regcache, i + zmm0h_regnum, p + i * 32);
}
}
- if ((x86_xcr0 & X86_XSTATE_ZMM) != 0)
+ if ((x86_xcr0 & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0)
{
- int zmm16h_regnum = (num_avx512_zmmh_high_registers == 0
- ? -1
- : find_regno (regcache->tdesc, "zmm16h"));
- int ymm16h_regnum = (num_avx512_ymmh_registers == 0
- ? -1
- : find_regno (regcache->tdesc, "ymm16h"));
- int xmm16_regnum = (num_avx512_xmm_registers == 0
- ? -1
- : find_regno (regcache->tdesc, "xmm16"));
+ int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
+ int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
+ int xmm16_regnum = find_regno (regcache->tdesc, "xmm16");
if ((clear_bv & X86_XSTATE_ZMM) != 0)
{
- for (i = 0; i < num_avx512_zmmh_high_registers; i++)
- supply_register_zeroed (regcache, i + zmm16h_regnum);
- for (i = 0; i < num_avx512_ymmh_registers; i++)
- supply_register_zeroed (regcache, i + ymm16h_regnum);
- for (i = 0; i < num_avx512_xmm_registers; i++)
- supply_register_zeroed (regcache, i + xmm16_regnum);
+ for (i = 0; i < num_zmm_high_registers; i++)
+ {
+ supply_register_zeroed (regcache, i + zmm16h_regnum);
+ supply_register_zeroed (regcache, i + ymm16h_regnum);
+ supply_register_zeroed (regcache, i + xmm16_regnum);
+ }
}
else
{
p = fp->zmm16_space ();
- for (i = 0; i < num_avx512_zmmh_high_registers; i++)
- supply_register (regcache, i + zmm16h_regnum, p + 32 + i * 64);
- for (i = 0; i < num_avx512_ymmh_registers; i++)
- supply_register (regcache, i + ymm16h_regnum, p + 16 + i * 64);
- for (i = 0; i < num_avx512_xmm_registers; i++)
- supply_register (regcache, i + xmm16_regnum, p + i * 64);
+ for (i = 0; i < num_zmm_high_registers; i++)
+ {
+ supply_register (regcache, i + zmm16h_regnum, p + 32 + i * 64);
+ supply_register (regcache, i + ymm16h_regnum, p + 16 + i * 64);
+ supply_register (regcache, i + xmm16_regnum, p + i * 64);
+ }
}
}

View File

@ -0,0 +1,69 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Aleksandar Paunovic <aleksandar.paunovic@intel.com>
Date: Thu, 11 Apr 2024 14:05:45 -0700
Subject: gdb-rhel-10464-xsave-update-14of21.patch
;; Backport "gdbserver: Refactor the legacy region within the xsave struct"
;; (Aleksandar Paunovic, RHEL-10464)
Legacy fields of the XSAVE area are already defined within fx_save
struct. Use class inheritance to remove code duplication.
The two changed functions are called within all tests which run
gdbserver.
Signed-off-by: Aleksandar Paunovic <aleksandar.paunovic@intel.com>
Co-authored-by: John Baldwin <jhb@FreeBSD.org>
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -83,29 +83,7 @@ struct i387_fxsave {
gdb_static_assert (sizeof(i387_fxsave) == 416);
-struct i387_xsave {
- /* All these are only sixteen bits, plus padding, except for fop (which
- is only eleven bits), and fooff / fioff (which are 32 bits each). */
- unsigned short fctrl;
- unsigned short fstat;
- unsigned short ftag;
- unsigned short fop;
- unsigned int fioff;
- unsigned short fiseg;
- unsigned short pad1;
- unsigned int fooff;
- unsigned short foseg;
- unsigned short pad12;
-
- unsigned int mxcsr;
- unsigned int mxcsr_mask;
-
- /* Space for eight 80-bit FP values in 128-bit spaces. */
- unsigned char st_space[128];
-
- /* Space for eight 128-bit XMM values, or 16 on x86-64. */
- unsigned char xmm_space[256];
-
+struct i387_xsave : public i387_fxsave {
unsigned char reserved1[48];
/* The extended control register 0 (the XFEATURE_ENABLED_MASK
@@ -719,7 +697,6 @@ void
i387_xsave_to_cache (struct regcache *regcache, const void *buf)
{
struct i387_xsave *fp = (struct i387_xsave *) buf;
- struct i387_fxsave *fxp = (struct i387_fxsave *) buf;
bool amd64 = register_size (regcache->tdesc, 0) == 8;
int i, top;
unsigned long val;
@@ -946,7 +923,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
{
int tag;
if (fp->ftag & (1 << i))
- tag = i387_ftag (fxp, (i + 8 - top) % 8);
+ tag = i387_ftag (fp, (i + 8 - top) % 8);
else
tag = 3;
val |= tag << (2 * i);

View File

@ -0,0 +1,41 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:45 -0700
Subject: gdb-rhel-10464-xsave-update-15of21.patch
;; Backport "gdbserver: Fix style of struct declarations in i387-fp.cc"
;; (John Baldwin, RHEL-10464)
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -37,7 +37,8 @@ static x86_xsave_layout xsave_layout;
/* These structs should have the proper sizes and alignment on both
i386 and x86-64 machines. */
-struct i387_fsave {
+struct i387_fsave
+{
/* All these are only sixteen bits, plus padding, except for fop (which
is only eleven bits), and fooff / fioff (which are 32 bits each). */
unsigned short fctrl;
@@ -57,7 +58,8 @@ struct i387_fsave {
unsigned char st_space[80];
};
-struct i387_fxsave {
+struct i387_fxsave
+{
/* All these are only sixteen bits, plus padding, except for fop (which
is only eleven bits), and fooff / fioff (which are 32 bits each). */
unsigned short fctrl;
@@ -83,7 +85,8 @@ struct i387_fxsave {
gdb_static_assert (sizeof(i387_fxsave) == 416);
-struct i387_xsave : public i387_fxsave {
+struct i387_xsave : public i387_fxsave
+{
unsigned char reserved1[48];
/* The extended control register 0 (the XFEATURE_ENABLED_MASK

View File

@ -0,0 +1,52 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:45 -0700
Subject: gdb-rhel-10464-xsave-update-16of21.patch
;; Backport "nat/x86-cpuid.h: Remove non-x86 fallbacks"
;; (John Baldwin, RHEL-10464)
This header is only suitable for use on x86 hosts and is only included
there, so these fallbacks should not be needed.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/nat/x86-cpuid.h b/gdb/nat/x86-cpuid.h
--- a/gdb/nat/x86-cpuid.h
+++ b/gdb/nat/x86-cpuid.h
@@ -28,8 +28,6 @@
#define nullptr ((void *) 0)
#endif
-#if defined(__i386__) || defined(__x86_64__)
-
/* Return cpuid data for requested cpuid level, as found in returned
eax, ebx, ecx and edx registers. The function checks if cpuid is
supported and returns 1 for valid cpuid information or 0 for
@@ -78,26 +76,6 @@ x86_cpuid_count (unsigned int __level, unsigned int __sublevel,
return __get_cpuid_count (__level, __sublevel, __eax, __ebx, __ecx, __edx);
}
-#else
-
-static __inline int
-x86_cpuid (unsigned int __level,
- unsigned int *__eax, unsigned int *__ebx,
- unsigned int *__ecx, unsigned int *__edx)
-{
- return 0;
-}
-
-static __inline int
-x86_cpuid_count (unsigned int __level, unsigned int __sublevel,
- unsigned int *__eax, unsigned int *__ebx,
- unsigned int *__ecx, unsigned int *__edx)
-{
- return 0;
-}
-
-#endif /* i386 && x86_64 */
-
#ifndef __cplusplus
/* Avoid leaking this local definition beyond the scope of this header
file. */

View File

@ -0,0 +1,188 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:46 -0700
Subject: gdb-rhel-10464-xsave-update-17of21.patch
;; Backport "i386: Use a fallback XSAVE layout for remote targets"
;; (John Baldwin, RHEL-10464)
If a target provides a target description including registers from the
XSAVE extended region, but does not provide an XSAVE layout, use a
fallback XSAVE layout based on the included registers. This fallback
layout matches GDB's behavior in earlier releases which assumes the
layout from Intel CPUs.
This fallback layout is currently only used for remote targets since
native targets which support XSAVE provide an explicit layout derived
from CPUID.
PR gdb/30912
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30912
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8244,6 +8244,72 @@ i386_floatformat_for_type (struct gdbarch *gdbarch,
return default_floatformat_for_type (gdbarch, name, len);
}
+/* Compute an XCR0 mask based on a target description. */
+
+static uint64_t
+i386_xcr0_from_tdesc (const struct target_desc *tdesc)
+{
+ if (! tdesc_has_registers (tdesc))
+ return 0;
+
+ const struct tdesc_feature *feature_core;
+
+ const struct tdesc_feature *feature_sse, *feature_avx, *feature_mpx,
+ *feature_avx512, *feature_pkeys;
+
+ /* Get core registers. */
+ feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.core");
+ if (feature_core == NULL)
+ return 0;
+
+ /* Get SSE registers. */
+ feature_sse = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse");
+
+ /* Try AVX registers. */
+ feature_avx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx");
+
+ /* Try MPX registers. */
+ feature_mpx = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx");
+
+ /* Try AVX512 registers. */
+ feature_avx512 = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.avx512");
+
+ /* Try PKEYS */
+ feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys");
+
+ /* The XCR0 bits. */
+ uint64_t xcr0 = X86_XSTATE_X87;
+
+ if (feature_sse)
+ xcr0 |= X86_XSTATE_SSE;
+
+ if (feature_avx)
+ {
+ /* AVX register description requires SSE register description. */
+ if (!feature_sse)
+ return 0;
+
+ xcr0 |= X86_XSTATE_AVX;
+ }
+
+ if (feature_mpx)
+ xcr0 |= X86_XSTATE_MPX_MASK;
+
+ if (feature_avx512)
+ {
+ /* AVX512 register description requires AVX register description. */
+ if (!feature_avx)
+ return 0;
+
+ xcr0 |= X86_XSTATE_AVX512;
+ }
+
+ if (feature_pkeys)
+ xcr0 |= X86_XSTATE_PKRU;
+
+ return xcr0;
+}
+
static int
i386_validate_tdesc_p (struct gdbarch_tdep *tdep,
struct tdesc_arch_data *tdesc_data)
@@ -8458,6 +8524,15 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
x86_xsave_layout xsave_layout = target_fetch_x86_xsave_layout ();
+ /* If the target did not provide an XSAVE layout but the target
+ description includes registers from the XSAVE extended region,
+ use a fallback XSAVE layout. Specifically, this fallback layout
+ is used when writing out a local core dump for a remote
+ target. */
+ if (xsave_layout.sizeof_xsave == 0)
+ xsave_layout
+ = i387_fallback_xsave_layout (i386_xcr0_from_tdesc (info.target_desc));
+
/* If there is already a candidate, use it. */
for (arches = gdbarch_list_lookup_by_info (arches, &info);
arches != NULL;
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -982,6 +982,55 @@ i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
return true;
}
+/* See i387-tdep.h. */
+
+x86_xsave_layout
+i387_fallback_xsave_layout (uint64_t xcr0)
+{
+ x86_xsave_layout layout;
+ memset (&layout, 0, sizeof (x86_xsave_layout));
+
+ if (HAS_PKRU (xcr0))
+ {
+ /* Intel CPUs supporting PKRU. */
+ layout.avx_offset = 576;
+ layout.bndregs_offset = 960;
+ layout.bndcfg_offset = 1024;
+ layout.k_offset = 1088;
+ layout.zmm_h_offset = 1152;
+ layout.zmm_offset = 1664;
+ layout.pkru_offset = 2688;
+ layout.sizeof_xsave = 2696;
+ }
+ else if (HAS_AVX512 (xcr0))
+ {
+ /* Intel CPUs supporting AVX512. */
+ layout.avx_offset = 576;
+ layout.bndregs_offset = 960;
+ layout.bndcfg_offset = 1024;
+ layout.k_offset = 1088;
+ layout.zmm_h_offset = 1152;
+ layout.zmm_offset = 1664;
+ layout.sizeof_xsave = 2688;
+ }
+ else if (HAS_MPX (xcr0))
+ {
+ /* Intel CPUs supporting MPX. */
+ layout.avx_offset = 576;
+ layout.bndregs_offset = 960;
+ layout.bndcfg_offset = 1024;
+ layout.sizeof_xsave = 1088;
+ }
+ else if (HAS_AVX (xcr0))
+ {
+ /* Intel and AMD CPUs supporting AVX. */
+ layout.avx_offset = 576;
+ layout.sizeof_xsave = 832;
+ }
+
+ return layout;
+}
+
/* Extract from XSAVE a bitset of the features that are available on the
target, but which have not yet been enabled. */
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -148,6 +148,11 @@ extern bool i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
x86_xsave_layout &layout);
+/* Compute an XSAVE layout based on the XCR0 bitmask. This is used
+ as a fallback if a target does not provide an XSAVE layout. */
+
+extern x86_xsave_layout i387_fallback_xsave_layout (uint64_t xcr0);
+
/* Similar to i387_supply_fxsave, but use XSAVE extended state. */
extern void i387_supply_xsave (struct regcache *regcache, int regnum,

View File

@ -0,0 +1,67 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Simon Marchi <simon.marchi@efficios.com>
Date: Thu, 11 Apr 2024 14:05:46 -0700
Subject: gdb-rhel-10464-xsave-update-18of21.patch
;; Backport "gdbserver: i387_cache_to_xsave: fix copy dest of zmm registers"
;; (Simon Marchi, RHEL-10464)
On a machine with AVX512 support (AMD EPYC 9634), I see these failures:
$ make check TESTS="gdb.arch/i386-avx512.exp" RUNTESTFLAGS="--target_board=native-gdbserver"
...
FAIL: gdb.arch/i386-avx512.exp: check contents of zmm_data[16] after writing ZMM regs
FAIL: gdb.arch/i386-avx512.exp: check contents of zmm_data[17] after writing ZMM regs
FAIL: gdb.arch/i386-avx512.exp: check contents of zmm_data[18] after writing ZMM regs
...
The problem can be reduced to:
(gdb) print $zmm16.v8_int64
$1 = {0, 0, 0, 0, 0, 0, 0, 0}
(gdb) print $zmm16.v8_int64 = {11,22,33,44,55,66,77,88}
$2 = {11, 22, 33, 44, 55, 66, 77, 88}
(gdb) print $zmm16.v8_int64
$3 = {11, 22, 33, 44, 55, 66, 77, 88}
(gdb) step
5 ++x;
(gdb) print $zmm16.v8_int64
$4 = {11, 22, 77, 88, 0, 0, 0, 0}
Writing to the local regcache in GDB works fine, but the writeback to
gdbserver (which happens when resuming / stepping) doesn't work (the
code being stepped doesn't touch AVX registers, so we don't expect the
value of zmm16 to change when stepping).
The problem is on the gdbserver side, the zmmh and ymmh portions of the
zmm register are not memcpied at the right place in the xsave buffer. Fix
that. Note now how the two modified memcpy calls match the memcmp calls
just above them.
With this patch, gdb.arch/i386-avx512.exp passes completely for me.
Change-Id: I22c417e0f5e88d4bc635a0f08f8817a031c76433
Reviewed-by: John Baldwin <jhb@FreeBSD.org>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30818
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -470,7 +470,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
if (memcmp (raw, p + 32, 32) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 32);
+ memcpy (p + 32, raw, 32);
}
/* YMMH sub-register. */
@@ -478,7 +478,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
if (memcmp (raw, p + 16, 16) != 0)
{
xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
+ memcpy (p + 16, raw, 16);
}
/* XMM sub-register. */

View File

@ -0,0 +1,132 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Andrew Burgess <andrew.burgess@embecosm.com>
Date: Thu, 11 Apr 2024 14:05:46 -0700
Subject: gdb-rhel-10464-xsave-update-19of21.patch
;; Backport "bfd/binutils: support for gdb target descriptions in the core file"
;; (Andrew Burgess, RHEL-10464)
This commit lays the ground work for allowing GDB to write its target
description into a generated core file.
The goal of this work is to allow a user to connect to a remote
target, capture a core file from within GDB, then pass the executable
and core file to another user and have the user be able to examine the
state of the machine without needing to connect to a running target.
Different remote targets can have different register sets and this
information is communicated from the target to GDB in the target
description.
It is possible for a user to extract the target description from GDB
and pass this along with the core file so that when the core file is
used the target description can be fed back into GDB, however this is
not a great user experience.
It would be nicer, I think, if GDB could write the target description
directly into the core file, and then make use of this description
when loading a core file.
This commit performs the binutils/bfd side of this task, adding the
boiler plate functions to access the target description from within a
core file note, and reserving a new number for a note containing the
target description. Later commits will extend GDB to make use of
this.
The new note is given the name 'GDB' and a type NT_GDB_TDESC. This
should hopefully protect us if there's ever a reuse of the number
assigned to NT_GDB_TDESC by some other core file producer. It should
also, hopefully, make it clearer to users that this note carries GDB
specific information.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2795,6 +2795,8 @@ extern char *elfcore_write_aarch_pauth
(bfd *, char *, int *, const void *, int);
extern char *elfcore_write_arc_v2
(bfd *, char *, int *, const void *, int);
+extern char *elfcore_write_gdb_tdesc
+ (bfd *, char *, int *, const void *, int);
extern char *elfcore_write_lwpstatus
(bfd *, char *, int *, long, int, const void *);
extern char *elfcore_write_register_note
diff --git a/bfd/elf.c b/bfd/elf.c
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9903,6 +9903,15 @@ elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
}
+/* Convert NOTE into a bfd_section called ".gdb-tdesc". Return TRUE if
+ successful otherwise, return FALSE. */
+
+static bfd_boolean
+elfcore_grok_gdb_tdesc (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".gdb-tdesc", note);
+}
+
#if defined (HAVE_PRPSINFO_T)
typedef prpsinfo_t elfcore_psinfo_t;
#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */
@@ -10560,6 +10569,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
else
return TRUE;
+ case NT_GDB_TDESC:
+ if (note->namesz == 4
+ && strcmp (note->namedata, "GDB") == 0)
+ return elfcore_grok_gdb_tdesc (abfd, note);
+ else
+ return TRUE;
+
case NT_PRPSINFO:
case NT_PSINFO:
if (bed->elf_backend_grok_psinfo)
@@ -11941,6 +11957,23 @@ elfcore_write_arc_v2 (bfd *abfd,
note_name, NT_ARC_V2, arc_v2, size);
}
+/* Write the target description (a string) pointed to by TDESC, length
+ SIZE, into the note buffer BUF, and update *BUFSIZ. ABFD is the bfd the
+ note is being written into. Return a pointer to the new start of the
+ note buffer, to replace BUF which may no longer be valid. */
+
+char *
+elfcore_write_gdb_tdesc (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *tdesc,
+ int size)
+{
+ const char *note_name = "GDB";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_GDB_TDESC, tdesc, size);
+}
+
char *
elfcore_write_register_note (bfd *abfd,
char *buf,
@@ -12025,6 +12058,8 @@ elfcore_write_register_note (bfd *abfd,
return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-arc-v2") == 0)
return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".gdb-tdesc") == 0)
+ return elfcore_write_gdb_tdesc (abfd, buf, bufsiz, data, size);
return NULL;
}
diff --git a/include/elf/common.h b/include/elf/common.h
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -665,6 +665,10 @@
#define NT_SIGINFO 0x53494749 /* Fields of siginfo_t. */
#define NT_FILE 0x46494c45 /* Description of mapped files. */
+/* The range 0xff000000 to 0xffffffff is set aside for notes that don't
+ originate from any particular operating system. */
+#define NT_GDB_TDESC 0xff000000 /* Contains copy of GDB's target description XML. */
+
/* Note segments for core files on dir-style procfs systems. */
#define NT_PSTATUS 10 /* Has a struct pstatus */

View File

@ -0,0 +1,125 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:42 -0700
Subject: gdb-rhel-10464-xsave-update-1of21.patch
;; Backport "x86: Add an x86_xsave_layout structure to
;; handle variable XSAVE layouts."
;; (John Baldwin, RHEL-10464)
The standard layout of the XSAVE extended state area consists of three
regions. The first 512 bytes (legacy region) match the layout of the
FXSAVE instruction including floating point registers, MMX registers,
and SSE registers. The next 64 bytes (XSAVE header) contains a header
with a fixed layout. The final region (extended region) contains zero
or more optional state components. Examples of these include the
upper 128 bits of YMM registers for AVX.
These optional state components generally have an
architecturally-fixed size, but they are not assigned architectural
offsets in the extended region. Instead, processors provide
additional CPUID leafs describing the size and offset of each
component in the "standard" layout for a given CPU. (There is also a
"compact" format which uses an alternate layout, but existing OS's
currently export the "standard" layout when exporting XSAVE data via
ptrace() and core dumps.)
To date, GDB has assumed the layout used on current Intel processors
for state components in the extended region and hardcoded those
offsets in the tables in i387-tdep.c and i387-fp.cc. However, this
fails on recent AMD processors which use a different layout.
Specifically, AMD Zen3 and later processors do not leave space for the
MPX register set in between the AVX and AVX512 register sets.
To rectify this, add an x86_xsave_layout structure which contains the
total size of the XSAVE extended state area as well as the offset of
each known optional state component.
Subsequent commits will modify XSAVE parsing in both gdb and gdbserver
to use x86_xsave_layout.
Co-authored-by: Aleksandar Paunovic <aleksandar.paunovic@intel.com>
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
--- a/gdbsupport/x86-xstate.h
+++ b/gdbsupport/x86-xstate.h
@@ -20,22 +20,69 @@
#ifndef COMMON_X86_XSTATE_H
#define COMMON_X86_XSTATE_H
+/* The extended state feature IDs in the state component bitmap. */
+#define X86_XSTATE_X87_ID 0
+#define X86_XSTATE_SSE_ID 1
+#define X86_XSTATE_AVX_ID 2
+#define X86_XSTATE_BNDREGS_ID 3
+#define X86_XSTATE_BNDCFG_ID 4
+#define X86_XSTATE_K_ID 5
+#define X86_XSTATE_ZMM_H_ID 6
+#define X86_XSTATE_ZMM_ID 7
+#define X86_XSTATE_PKRU_ID 9
+
/* The extended state feature bits. */
-#define X86_XSTATE_X87 (1ULL << 0)
-#define X86_XSTATE_SSE (1ULL << 1)
-#define X86_XSTATE_AVX (1ULL << 2)
-#define X86_XSTATE_BNDREGS (1ULL << 3)
-#define X86_XSTATE_BNDCFG (1ULL << 4)
+#define X86_XSTATE_X87 (1ULL << X86_XSTATE_X87_ID)
+#define X86_XSTATE_SSE (1ULL << X86_XSTATE_SSE_ID)
+#define X86_XSTATE_AVX (1ULL << X86_XSTATE_AVX_ID)
+#define X86_XSTATE_BNDREGS (1ULL << X86_XSTATE_BNDREGS_ID)
+#define X86_XSTATE_BNDCFG (1ULL << X86_XSTATE_BNDCFG_ID)
#define X86_XSTATE_MPX (X86_XSTATE_BNDREGS | X86_XSTATE_BNDCFG)
/* AVX 512 adds three feature bits. All three must be enabled. */
-#define X86_XSTATE_K (1ULL << 5)
-#define X86_XSTATE_ZMM_H (1ULL << 6)
-#define X86_XSTATE_ZMM (1ULL << 7)
+#define X86_XSTATE_K (1ULL << X86_XSTATE_K_ID)
+#define X86_XSTATE_ZMM_H (1ULL << X86_XSTATE_ZMM_H_ID)
+#define X86_XSTATE_ZMM (1ULL << X86_XSTATE_ZMM_ID)
#define X86_XSTATE_AVX512 (X86_XSTATE_K | X86_XSTATE_ZMM_H \
| X86_XSTATE_ZMM)
-#define X86_XSTATE_PKRU (1ULL << 9)
+#define X86_XSTATE_PKRU (1ULL << X86_XSTATE_PKRU_ID)
+
+/* Total size of the XSAVE area extended region and offsets of
+ register states within the region. Offsets are set to 0 to
+ indicate the absence of the associated registers. */
+
+struct x86_xsave_layout
+{
+ int sizeof_xsave;
+ int avx_offset;
+ int bndregs_offset;
+ int bndcfg_offset;
+ int k_offset;
+ int zmm_h_offset;
+ int zmm_offset;
+ int pkru_offset;
+};
+
+constexpr bool operator== (const x86_xsave_layout &lhs,
+ const x86_xsave_layout &rhs)
+{
+ return lhs.sizeof_xsave == rhs.sizeof_xsave
+ && lhs.avx_offset == rhs.avx_offset
+ && lhs.bndregs_offset == rhs.bndregs_offset
+ && lhs.bndcfg_offset == rhs.bndcfg_offset
+ && lhs.k_offset == rhs.k_offset
+ && lhs.zmm_h_offset == rhs.zmm_h_offset
+ && lhs.zmm_offset == rhs.zmm_offset
+ && lhs.pkru_offset == rhs.pkru_offset;
+}
+
+constexpr bool operator!= (const x86_xsave_layout &lhs,
+ const x86_xsave_layout &rhs)
+{
+ return !(lhs == rhs);
+}
+
/* Supported mask and size of the extended state. */
#define X86_XSTATE_X87_MASK X86_XSTATE_X87

View File

@ -0,0 +1,162 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: root <root@dell-pexr7620-01.khw.eng.bos2.dc.redhat.com>
Date: Thu, 11 Apr 2024 14:05:47 -0700
Subject: gdb-rhel-10464-xsave-update-20of21.patch
;; Backport "gdb: write target description into core file"
;; (Andrew Burgess, RHEL-10464)
When a core file is created from within GDB add the target description
into a note within the core file.
When loading a core file, if the target description note is present
then load the target description from the core file.
The benefit of this is that we can be sure that, when analysing the
core file within GDB, that we are using the exact same target
description as was in use at the time the core file was created.
GDB already supports a mechanism for figuring out the target
description from a given corefile; gdbarch_core_read_description.
This new mechanism (GDB adding the target description) is not going to
replace the old mechanism. Core files generated outside of GDB will
not include a target description, and so GDB still needs to be able to
figure out a target description for these files.
My primary motivation for adding this feature is that, in a future
commit, I will be adding support for bare metal core dumps on some
targets. For RISC-V specifically, I want to be able to dump all the
available control status registers. As different targets will present
different sets of register in their target description, including
registers that are possibly not otherwise known to GDB I wanted a way
to capture these registers in the core dump.
I therefore need a mechanism to write out an arbitrary set of
registers, and to then derive a target description from this arbitrary
set when later loading the core file. The obvious approach (I think)
is to just reuse the target description.
Once I'd decided to add support for writing out the target description
I could either choose to make this RISC-V only, or make it generic. I
figure that having the target description in the core file doesn't
hurt, and _might_ be helpful. So that's how I got here, general
support for including the target description in GDB generated core
files.
In previous versions of this patch I added the target description from
generic code (in gcore.c). However, doing this creates a dependency
between GDB's common code and bfd ELF support. As ELF support in gdb
is optional (for example the target x86_64-apple-darwin20.3.0 does not
include ELF support) then having gcore.c require ELF support would
break the GDB build in some cases.
Instead, in this version of the patch, writing the target description
note is done from each specific targets make notes function. Each of
these now calls a common function in gcore-elf.c (which is only linked
in when bfd has ELF support). And so only targets that are ELF based
will call the new function and we can therefore avoid an unconditional
dependency on ELF support.
diff --git a/gdb/corelow.c b/gdb/corelow.c
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -54,6 +54,7 @@
#include <unordered_map>
#include <unordered_set>
#include "gdbcmd.h"
+#include "xml-tdesc.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
@@ -1032,6 +1033,29 @@ core_target::thread_alive (ptid_t ptid)
const struct target_desc *
core_target::read_description ()
{
+ /* If the core file contains a target description note then we will use
+ that in preference to anything else. */
+ bfd_size_type tdesc_note_size = 0;
+ struct bfd_section *tdesc_note_section
+ = bfd_get_section_by_name (core_bfd, ".gdb-tdesc");
+ if (tdesc_note_section != nullptr)
+ tdesc_note_size = bfd_section_size (tdesc_note_section);
+ if (tdesc_note_size > 0)
+ {
+ gdb::char_vector contents (tdesc_note_size + 1);
+ if (bfd_get_section_contents (core_bfd, tdesc_note_section,
+ contents.data (), (file_ptr) 0,
+ tdesc_note_size))
+ {
+ /* Ensure we have a null terminator. */
+ contents[tdesc_note_size] = '\0';
+ const struct target_desc *result
+ = string_read_description_xml (contents.data ());
+ if (result != nullptr)
+ return result;
+ }
+ }
+
if (m_core_gdbarch && gdbarch_core_read_description_p (m_core_gdbarch))
{
const struct target_desc *result;
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -39,6 +39,7 @@
#include "gdb_regex.h"
#include "gdbsupport/enum-flags.h"
#include "gdbsupport/gdb_optional.h"
+#include "gdbsupport/tdesc.h"
#include <ctype.h>
@@ -1968,6 +1969,40 @@ find_signalled_thread ()
return nullptr;
}
+/* Add content to *NOTE_DATA (and update *NOTE_SIZE) to include a note
+ containing the current targtet's target description. The core file is
+ being written to OBFD. If something goes wrong then *NOTE_DATA can be
+ set to nullptr. */
+
+static char *
+gcore_elf_make_tdesc_note (bfd *obfd,
+ char *note_data,
+ int *note_size)
+{
+ /* Append the target description to the core file. */
+ const struct target_desc *tdesc = gdbarch_target_desc (target_gdbarch ());
+ const char *tdesc_xml
+ = tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc);
+ if (tdesc_xml != nullptr && *tdesc_xml != '\0')
+ {
+ /* Skip the leading '@'. */
+ if (*tdesc_xml == '@')
+ ++tdesc_xml;
+
+ /* Include the null terminator in the length. */
+ size_t tdesc_len = strlen (tdesc_xml) + 1;
+
+ /* Now add the target description into the core file. */
+ note_data = elfcore_write_register_note (obfd,
+ note_data,
+ note_size,
+ ".gdb-tdesc", tdesc_xml,
+ tdesc_len);
+ }
+
+ return note_data;
+}
+
/* Build the note section for a corefile, and return it in a malloc
buffer. */
@@ -2048,6 +2083,9 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
note_data = linux_make_mappings_corefile_notes (gdbarch, obfd,
note_data, note_size);
+ /* Target description. */
+ note_data = gcore_elf_make_tdesc_note (obfd, note_data, note_size);
+
return note_data;
}

View File

@ -0,0 +1,66 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: root <root@dell-pexr7620-01.khw.eng.bos2.dc.redhat.com>
Date: Thu, 11 Apr 2024 14:05:47 -0700
Subject: gdb-rhel-10464-xsave-update-21of21.patch
;; Backport "gdb/corefile: write NT_GDB_TDESC based on signalled thread"
;; (Andrew Burgess, RHEL-10464)
When creating a core file from within GDB we include a NT_GDB_TDESC
that includes the target description of the architecture in use.
For architectures with dynamic architectures (e.g. AArch64 with
sve/sme) the original architecture, calculated from the original
target description, might not match the per-thread architecture.
In the general case, where each thread has a different architecture,
then we really need a separate NT_GDB_TDESC for each thread, however,
there's currently no way to read in multiple NT_GDB_TDESC.
This commit is a step towards per-thread NT_GDB_TDESC. In this commit
I have updated the function that writes the NT_GDB_TDESC to accept a
gdbarch (rather than calling target_gdbarch() to find a gdbarch), and
I now pass in the gdbarch of the signalled thread.
In many cases (though NOT all) targets with dynamic architectures
really only use a single architecture, even when there are multiple
threads, so in the common case, this should ensure that GDB emits an
architecture that is more likely to be correct.
Additional work will be needed in order to support corefiles with
truly per-thread architectures, but that will need to be done in the
future.
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -1975,12 +1975,12 @@ find_signalled_thread ()
set to nullptr. */
static char *
-gcore_elf_make_tdesc_note (bfd *obfd,
+gcore_elf_make_tdesc_note (struct gdbarch *gdbarch, bfd *obfd,
char *note_data,
int *note_size)
{
/* Append the target description to the core file. */
- const struct target_desc *tdesc = gdbarch_target_desc (target_gdbarch ());
+ const struct target_desc *tdesc = gdbarch_target_desc (gdbarch);
const char *tdesc_xml
= tdesc == nullptr ? nullptr : tdesc_get_features_xml (tdesc);
if (tdesc_xml != nullptr && *tdesc_xml != '\0')
@@ -2083,8 +2083,12 @@ linux_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size)
note_data = linux_make_mappings_corefile_notes (gdbarch, obfd,
note_data, note_size);
- /* Target description. */
- note_data = gcore_elf_make_tdesc_note (obfd, note_data, note_size);
+ /* Include the target description when possible. Some architectures
+ allow for per-thread gdbarch so we should really be emitting a tdesc
+ per-thread, however, we don't currently support reading in a
+ per-thread tdesc, so just emit the tdesc for the signalled thread. */
+ gdbarch = target_thread_architecture (signalled_thr->ptid);
+ note_data = gcore_elf_make_tdesc_note (gdbarch, obfd, note_data, note_size);
return note_data;
}

View File

@ -0,0 +1,190 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: Keith Seitz <keiths@redhat.com>
Date: Thu, 11 Apr 2024 14:05:42 -0700
Subject: gdb-rhel-10464-xsave-update-2of21.patch
;; Backport "gdb: Store an x86_xsave_layout in i386_gdbarch_tdep."
;; (John Baldwin, RHEL-10464)
This structure is fetched from the current target in i386_gdbarch_init
via a new "fetch_x86_xsave_layout" target method.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8456,10 +8456,20 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
int bnd0_regnum;
int num_bnd_cooked;
+ x86_xsave_layout xsave_layout = target_fetch_x86_xsave_layout ();
+
/* If there is already a candidate, use it. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return arches->gdbarch;
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* Check that the XSAVE layout of ARCHES matches the layout for
+ the current target. */
+ struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
+
+ if (other_tdep->xsave_layout == xsave_layout)
+ return arches->gdbarch;
+ }
/* Allocate space for the new architecture. Assume i386 for now. */
tdep = XCNEW (struct gdbarch_tdep);
@@ -8711,6 +8721,7 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
gdbarch_free (gdbarch);
return NULL;
}
+ tdep->xsave_layout = xsave_layout;
num_bnd_cooked = (tdep->bnd0r_regnum > 0 ? I387_NUM_BND_REGS : 0);
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -22,6 +22,7 @@
#include "gdbarch.h"
#include "infrun.h"
+#include "gdbsupport/x86-xstate.h"
struct frame_info;
struct gdbarch;
@@ -144,6 +145,9 @@ struct gdbarch_tdep
/* Offset of XCR0 in XSAVE extended state. */
int xsave_xcr0_offset;
+ /* Layout of the XSAVE area extended region. */
+ x86_xsave_layout xsave_layout;
+
/* Register names. */
const char **register_names;
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -226,4 +226,23 @@ target_debug_print_signals (gdb::array_view<const unsigned char> sigs)
fputs_unfiltered (" }", gdb_stdlog);
}
+static void
+target_debug_print_x86_xsave_layout (const x86_xsave_layout &layout)
+{
+ fputs_unfiltered ("{", gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, " sizeof_xsave=%d", layout.sizeof_xsave);
+#define POFFS(region) \
+ if (layout.region##_offset != 0) \
+ fprintf_unfiltered (gdb_stdlog, ", %s_offset=%d", #region, \
+ layout.region##_offset)
+ POFFS(avx);
+ POFFS(bndregs);
+ POFFS(bndcfg);
+ POFFS(k);
+ POFFS(zmm_h);
+ POFFS(zmm);
+ POFFS(pkru);
+#undef POFFS
+ fputs_unfiltered (" }", gdb_stdlog);
+}
#endif /* TARGET_DEBUG_H */
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -173,6 +173,7 @@ struct dummy_target : public target_ops
const struct frame_unwind *get_tailcall_unwinder () override;
void prepare_to_generate_core () override;
void done_generating_core () override;
+ x86_xsave_layout fetch_x86_xsave_layout () override;
};
struct debug_target : public target_ops
@@ -344,6 +345,7 @@ struct debug_target : public target_ops
const struct frame_unwind *get_tailcall_unwinder () override;
void prepare_to_generate_core () override;
void done_generating_core () override;
+ x86_xsave_layout fetch_x86_xsave_layout () override;
};
void
@@ -4413,3 +4415,27 @@ debug_target::done_generating_core ()
fputs_unfiltered (")\n", gdb_stdlog);
}
+x86_xsave_layout
+target_ops::fetch_x86_xsave_layout ()
+{
+ return this->beneath ()->fetch_x86_xsave_layout ();
+}
+
+x86_xsave_layout
+dummy_target::fetch_x86_xsave_layout ()
+{
+ return x86_xsave_layout ();
+}
+
+x86_xsave_layout
+debug_target::fetch_x86_xsave_layout ()
+{
+ x86_xsave_layout result;
+ fprintf_unfiltered (gdb_stdlog, "-> %s->fetch_x86_xsave_layout (...)\n", this->beneath ()->shortname ());
+ result = this->beneath ()->fetch_x86_xsave_layout ();
+ fprintf_unfiltered (gdb_stdlog, "<- %s->fetch_x86_xsave_layout (", this->beneath ()->shortname ());
+ fputs_unfiltered (") = ", gdb_stdlog);
+ target_debug_print_x86_xsave_layout (result);
+ fputs_unfiltered ("\n", gdb_stdlog);
+ return result;
+}
diff --git a/gdb/target.c b/gdb/target.c
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -227,6 +227,12 @@ target_has_execution_current (void)
return target_has_execution_1 (current_inferior ());
}
+x86_xsave_layout
+target_fetch_x86_xsave_layout ()
+{
+ return current_inferior ()->top_target ()->fetch_x86_xsave_layout ();
+}
+
/* This is used to implement the various target commands. */
static void
diff --git a/gdb/target.h b/gdb/target.h
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -81,6 +81,7 @@ struct inferior;
#include "command.h"
#include "disasm.h"
#include "tracepoint.h"
+#include "gdbsupport/x86-xstate.h"
#include "gdbsupport/break-common.h" /* For enum target_hw_bp_type. */
@@ -1260,6 +1261,10 @@ struct target_ops
/* Cleanup after generating a core file. */
virtual void done_generating_core ()
TARGET_DEFAULT_IGNORE ();
+
+ /* Return the x86 XSAVE extended state area layout. */
+ virtual x86_xsave_layout fetch_x86_xsave_layout ()
+ TARGET_DEFAULT_RETURN (x86_xsave_layout ());
};
/* Deleter for std::unique_ptr. See comments in
@@ -2326,6 +2331,8 @@ extern gdb::unique_xmalloc_ptr<char> target_fileio_read_stralloc
#define target_augmented_libraries_svr4_read() \
(current_top_target ()->augmented_libraries_svr4_read) ()
+extern x86_xsave_layout target_fetch_x86_xsave_layout ();
+
/* Command logging facility. */
#define target_log_command(p) \

View File

@ -0,0 +1,269 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:42 -0700
Subject: gdb-rhel-10464-xsave-update-3of21.patch
;; Backport "core: Support fetching x86 XSAVE layout from architectures."
;; (John Baldwin, RHEL-10464)
Add gdbarch_core_read_x86_xsave_layout to fetch the x86 XSAVE layout
structure from a core file.
Current OS's do not export the offsets of XSAVE state components in
core dumps, so provide an i387_guess_xsave_layout helper function to
set offsets based on known combinations of XCR0 masks and total state
sizes. Eventually when core dumps do contain this information this
function should only be used as a fall back for older core dumps.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Please enter the commit message for your changes. Lines starting
diff --git a/gdb/corelow.c b/gdb/corelow.c
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -50,6 +50,7 @@
#include "gdbsupport/filestuff.h"
#include "build-id.h"
#include "gdbsupport/pathstuff.h"
+#include "gdbsupport/x86-xstate.h"
#include <unordered_map>
#include <unordered_set>
#include "gdbcmd.h"
@@ -103,6 +104,8 @@ class core_target final : public process_stratum_target
bool info_proc (const char *, enum info_proc_what) override;
+ x86_xsave_layout fetch_x86_xsave_layout () override;
+
/* A few helpers. */
/* Getter, see variable definition. */
@@ -1113,6 +1116,25 @@ core_target::info_proc (const char *args, enum info_proc_what request)
return true;
}
+/* Implementation of the "fetch_x86_xsave_layout" target_ops method. */
+
+x86_xsave_layout
+core_target::fetch_x86_xsave_layout ()
+{
+ if (m_core_gdbarch != nullptr &&
+ gdbarch_core_read_x86_xsave_layout_p (m_core_gdbarch))
+ {
+ x86_xsave_layout layout;
+ memset (&layout, 0, sizeof (x86_xsave_layout));
+ if (!gdbarch_core_read_x86_xsave_layout (m_core_gdbarch, layout))
+ return {};
+
+ return layout;
+ }
+
+ return {};
+}
+
/* Get a pointer to the current core target. If not connected to a
core target, return NULL. */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -282,6 +282,7 @@ struct gdbarch
gdbarch_core_pid_to_str_ftype *core_pid_to_str;
gdbarch_core_thread_name_ftype *core_thread_name;
gdbarch_core_xfer_siginfo_ftype *core_xfer_siginfo;
+ gdbarch_core_read_x86_xsave_layout_ftype *core_read_x86_xsave_layout;
const char * gcore_bfd_target;
int vtable_function_descriptors;
int vbit_in_delta;
@@ -652,6 +653,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of core_pid_to_str, has predicate. */
/* Skip verify of core_thread_name, has predicate. */
/* Skip verify of core_xfer_siginfo, has predicate. */
+ /* Skip verify of core_read_x86_xsave_layout, has predicate. */
/* Skip verify of gcore_bfd_target, has predicate. */
/* Skip verify of vtable_function_descriptors, invalid_p == 0 */
/* Skip verify of vbit_in_delta, invalid_p == 0 */
@@ -879,6 +881,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: core_read_description = <%s>\n",
host_address_to_string (gdbarch->core_read_description));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_core_read_x86_xsave_layout_p() = %d\n",
+ gdbarch_core_read_x86_xsave_layout_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: core_read_x86_xsave_layout = <%s>\n",
+ host_address_to_string (gdbarch->core_read_x86_xsave_layout));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_core_thread_name_p() = %d\n",
gdbarch_core_thread_name_p (gdbarch));
@@ -3861,6 +3869,30 @@ set_gdbarch_core_xfer_siginfo (struct gdbarch *gdbarch,
gdbarch->core_xfer_siginfo = core_xfer_siginfo;
}
+int
+gdbarch_core_read_x86_xsave_layout_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->core_read_x86_xsave_layout != NULL;
+}
+
+bool
+gdbarch_core_read_x86_xsave_layout (struct gdbarch *gdbarch, x86_xsave_layout &xsave_layout)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->core_read_x86_xsave_layout != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_core_read_x86_xsave_layout called\n");
+ return gdbarch->core_read_x86_xsave_layout (gdbarch, xsave_layout);
+}
+
+void
+set_gdbarch_core_read_x86_xsave_layout (struct gdbarch *gdbarch,
+ gdbarch_core_read_x86_xsave_layout_ftype core_read_x86_xsave_layout)
+{
+ gdbarch->core_read_x86_xsave_layout = core_read_x86_xsave_layout;
+}
+
int
gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -57,6 +57,7 @@ struct mem_range;
struct syscalls_info;
struct thread_info;
struct ui_out;
+struct x86_xsave_layout;
#include "regcache.h"
@@ -971,6 +972,15 @@ typedef LONGEST (gdbarch_core_xfer_siginfo_ftype) (struct gdbarch *gdbarch, gdb_
extern LONGEST gdbarch_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf, ULONGEST offset, ULONGEST len);
extern void set_gdbarch_core_xfer_siginfo (struct gdbarch *gdbarch, gdbarch_core_xfer_siginfo_ftype *core_xfer_siginfo);
+/* Read x86 XSAVE layout information from core file into XSAVE_LAYOUT.
+ Returns true if the layout was read successfully. */
+
+extern int gdbarch_core_read_x86_xsave_layout_p (struct gdbarch *gdbarch);
+
+typedef bool (gdbarch_core_read_x86_xsave_layout_ftype) (struct gdbarch *gdbarch, x86_xsave_layout &xsave_layout);
+extern bool gdbarch_core_read_x86_xsave_layout (struct gdbarch *gdbarch, x86_xsave_layout &xsave_layout);
+extern void set_gdbarch_core_read_x86_xsave_layout (struct gdbarch *gdbarch, gdbarch_core_read_x86_xsave_layout_ftype *core_read_x86_xsave_layout);
+
/* BFD target to use when generating a core file. */
extern int gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -742,6 +742,10 @@ M;const char *;core_thread_name;struct thread_info *thr;thr
# of bytes read (zero indicates EOF, a negative value indicates failure).
M;LONGEST;core_xfer_siginfo;gdb_byte *readbuf, ULONGEST offset, ULONGEST len; readbuf, offset, len
+# Read x86 XSAVE layout information from core file into XSAVE_LAYOUT.
+# Returns true if the layout was read successfully.
+M;bool;core_read_x86_xsave_layout;x86_xsave_layout &xsave_layout;xsave_layout
+
# BFD target to use when generating a core file.
V;const char *;gcore_bfd_target;;;0;0;;;pstring (gdbarch->gcore_bfd_target)
@@ -1297,6 +1301,7 @@ struct mem_range;
struct syscalls_info;
struct thread_info;
struct ui_out;
+struct x86_xsave_layout;
#include "regcache.h"
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -893,6 +893,61 @@ static int xsave_pkeys_offset[] =
(xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+/* See i387-tdep.h. */
+
+bool
+i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
+ x86_xsave_layout &layout)
+{
+ if (HAS_PKRU (xcr0) && xsave_size == 2696)
+ {
+ /* Intel CPUs supporting PKRU. */
+ layout.avx_offset = 576;
+ layout.bndregs_offset = 960;
+ layout.bndcfg_offset = 1024;
+ layout.k_offset = 1088;
+ layout.zmm_h_offset = 1152;
+ layout.zmm_offset = 1664;
+ layout.pkru_offset = 2688;
+ }
+ else if (HAS_PKRU (xcr0) && xsave_size == 2440)
+ {
+ /* AMD CPUs supporting PKRU. */
+ layout.avx_offset = 576;
+ layout.k_offset = 832;
+ layout.zmm_h_offset = 896;
+ layout.zmm_offset = 1408;
+ layout.pkru_offset = 2432;
+ }
+ else if (HAS_AVX512 (xcr0) && xsave_size == 2688)
+ {
+ /* Intel CPUs supporting AVX512. */
+ layout.avx_offset = 576;
+ layout.bndregs_offset = 960;
+ layout.bndcfg_offset = 1024;
+ layout.k_offset = 1088;
+ layout.zmm_h_offset = 1152;
+ layout.zmm_offset = 1664;
+ }
+ else if (HAS_MPX (xcr0) && xsave_size == 1088)
+ {
+ /* Intel CPUs supporting MPX. */
+ layout.avx_offset = 576;
+ layout.bndregs_offset = 960;
+ layout.bndcfg_offset = 1024;
+ }
+ else if (HAS_AVX (xcr0) && xsave_size == 832)
+ {
+ /* Intel and AMD CPUs supporting AVX. */
+ layout.avx_offset = 576;
+ }
+ else
+ return false;
+
+ layout.sizeof_xsave = xsave_size;
+ return true;
+}
+
/* Extract from XSAVE a bitset of the features that are available on the
target, but which have not yet been enabled. */
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -25,6 +25,7 @@ struct frame_info;
struct regcache;
struct type;
struct ui_file;
+struct x86_xsave_layout;
/* Number of i387 floating point registers. */
#define I387_NUM_REGS 16
@@ -138,6 +139,14 @@ extern void i387_collect_fsave (const struct regcache *regcache, int regnum,
extern void i387_supply_fxsave (struct regcache *regcache, int regnum,
const void *fxsave);
+/* Select an XSAVE layout based on the XCR0 bitmask and total XSAVE
+ extended state size. Returns true if the bitmask and size matched
+ a known layout. */
+
+extern bool i387_guess_xsave_layout (uint64_t xcr0, size_t xsave_size,
+ x86_xsave_layout &layout);
+
+
/* Similar to i387_supply_fxsave, but use XSAVE extended state. */
extern void i387_supply_xsave (struct regcache *regcache, int regnum,

View File

@ -0,0 +1,79 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:43 -0700
Subject: gdb-rhel-10464-xsave-update-4of21.patch
;; Backport "nat/x86--cpuid.h: Add x86_cpuid_count wrapper around
;; __get_cpuid_count."
;; (John Baldwin, RHEL-10464)
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/nat/x86-cpuid.h b/gdb/nat/x86-cpuid.h
--- a/gdb/nat/x86-cpuid.h
+++ b/gdb/nat/x86-cpuid.h
@@ -22,6 +22,12 @@
/* Always include the header for the cpu bit defines. */
#include "x86-gcc-cpuid.h"
+#ifndef __cplusplus
+/* This header file is also used in C code for some test-cases, so define
+ nullptr in C terms to avoid a compilation error. */
+#define nullptr ((void *) 0)
+#endif
+
#if defined(__i386__) || defined(__x86_64__)
/* Return cpuid data for requested cpuid level, as found in returned
@@ -48,6 +54,30 @@ x86_cpuid (unsigned int __level,
return __get_cpuid (__level, __eax, __ebx, __ecx, __edx);
}
+/* Return cpuid data for requested cpuid level and sub-level, as found
+ in returned eax, ebx, ecx and edx registers. The function checks
+ if cpuid is supported and returns 1 for valid cpuid information or
+ 0 for unsupported cpuid level. Pointers may be non-null. */
+
+static __inline int
+x86_cpuid_count (unsigned int __level, unsigned int __sublevel,
+ unsigned int *__eax, unsigned int *__ebx,
+ unsigned int *__ecx, unsigned int *__edx)
+{
+ unsigned int __scratch;
+
+ if (__eax == nullptr)
+ __eax = &__scratch;
+ if (__ebx == nullptr)
+ __ebx = &__scratch;
+ if (__ecx == nullptr)
+ __ecx = &__scratch;
+ if (__edx == nullptr)
+ __edx = &__scratch;
+
+ return __get_cpuid_count (__level, __sublevel, __eax, __ebx, __ecx, __edx);
+}
+
#else
static __inline int
@@ -58,6 +88,20 @@ x86_cpuid (unsigned int __level,
return 0;
}
+static __inline int
+x86_cpuid_count (unsigned int __level, unsigned int __sublevel,
+ unsigned int *__eax, unsigned int *__ebx,
+ unsigned int *__ecx, unsigned int *__edx)
+{
+ return 0;
+}
+
#endif /* i386 && x86_64 */
+#ifndef __cplusplus
+/* Avoid leaking this local definition beyond the scope of this header
+ file. */
+#undef nullptr
+#endif
+
#endif /* NAT_X86_CPUID_H */

View File

@ -0,0 +1,133 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:43 -0700
Subject: gdb-rhel-10464-xsave-update-5of21.patch
;; Backport "x86 nat: Add helper functions to save the XSAVE layout for
;; the host."
;; (John Baldwin, RHEL-10464)
x86_xsave_length returns the total length of the XSAVE state area
standard format as queried from CPUID.
x86_fetch_xsave_layout uses CPUID to query the offsets of XSAVE
extended regions from the running host. The total length of the XSAVE
state area can either be supplied by the caller if known (e.g. from
FreeBSD's PT_GETXSTATEINFO) or it can be queried from the running host
using x86_xsave_length.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/nat/x86-xstate.c b/gdb/nat/x86-xstate.c
new file mode 100644
--- /dev/null
+++ b/gdb/nat/x86-xstate.c
@@ -0,0 +1,68 @@
+/* x86 XSAVE extended state functions.
+
+ Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "gdbsupport/common-defs.h"
+#include "gdbsupport/x86-xstate.h"
+#include "nat/x86-cpuid.h"
+#include "nat/x86-xstate.h"
+
+/* Fetch the offset of a specific XSAVE extended region. */
+
+static int
+xsave_feature_offset (uint64_t xcr0, int feature)
+{
+ uint32_t ebx;
+
+ if ((xcr0 & (1ULL << feature)) == 0)
+ return 0;
+
+ if (!x86_cpuid_count (0xd, feature, nullptr, &ebx, nullptr, nullptr))
+ return 0;
+ return ebx;
+}
+
+/* See x86-xstate.h. */
+
+int
+x86_xsave_length ()
+{
+ uint32_t ecx;
+
+ if (!x86_cpuid_count (0xd, 0, nullptr, nullptr, &ecx, nullptr))
+ return 0;
+ return ecx;
+}
+
+/* See x86-xstate.h. */
+
+x86_xsave_layout
+x86_fetch_xsave_layout (uint64_t xcr0, int len)
+{
+ x86_xsave_layout layout;
+ memset (&layout, 0, sizeof (x86_xsave_layout));
+ layout.sizeof_xsave = len;
+ layout.avx_offset = xsave_feature_offset (xcr0, X86_XSTATE_AVX_ID);
+ layout.bndregs_offset = xsave_feature_offset (xcr0, X86_XSTATE_BNDREGS_ID);
+ layout.bndcfg_offset = xsave_feature_offset (xcr0, X86_XSTATE_BNDCFG_ID);
+ layout.k_offset = xsave_feature_offset (xcr0, X86_XSTATE_K_ID);
+ layout.zmm_h_offset = xsave_feature_offset (xcr0, X86_XSTATE_ZMM_H_ID);
+ layout.zmm_offset = xsave_feature_offset (xcr0, X86_XSTATE_ZMM_ID);
+ layout.pkru_offset = xsave_feature_offset (xcr0, X86_XSTATE_PKRU_ID);
+ return layout;
+}
diff --git a/gdb/nat/x86-xstate.h b/gdb/nat/x86-xstate.h
new file mode 100644
--- /dev/null
+++ b/gdb/nat/x86-xstate.h
@@ -0,0 +1,35 @@
+/* x86 XSAVE extended state functions.
+
+ Copyright (C) 2022-2023 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef NAT_X86_XSTATE_H
+#define NAT_X86_XSTATE_H
+
+#include "gdbsupport/x86-xstate.h"
+
+/* Return the size of the XSAVE extended state fetched via CPUID. */
+
+int x86_xsave_length ();
+
+/* Return the layout (size and offsets) of the XSAVE extended regions
+ for the running host. Offsets of each of the enabled regions in
+ XCR0 are fetched via CPUID. */
+
+x86_xsave_layout x86_fetch_xsave_layout (uint64_t xcr0, int len);
+
+#endif /* NAT_X86_XSTATE_H */

View File

@ -0,0 +1,217 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:43 -0700
Subject: gdb-rhel-10464-xsave-update-6of21.patch
;; Backport "gdb: Update x86 Linux architectures to support XSAVE layouts."
;; (John Baldwin, RHEL-10464)
Refactor i386_linux_core_read_xcr0 to fetch and return a corresponding
x86_xsave_layout as well as xcr0 using the size of an existing
NT_X86_XSTATE core dump to determine the offsets via
i387_guess_xsave_layout. Use this to add an implementation of
gdbarch_core_xfer_x86_xsave_layout.
Use tdep->xsave_layout.sizeof_xsave as the size of the XSTATE register
set.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1608,7 +1608,11 @@ amd64_linux_core_read_description (struct gdbarch *gdbarch,
bfd *abfd)
{
/* Linux/x86-64. */
- uint64_t xcr0 = i386_linux_core_read_xcr0 (abfd);
+ x86_xsave_layout layout;
+ memset (&layout, 0, sizeof (x86_xsave_layout));
+ uint64_t xcr0 = i386_linux_core_read_xsave_info (abfd, layout);
+ if (xcr0 == 0)
+ xcr0 = X86_XSTATE_SSE_MASK;
return amd64_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK,
gdbarch_ptr_bit (gdbarch) == 32);
@@ -1653,8 +1657,10 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
cb (".reg", 27 * 8, 27 * 8, &i386_gregset, NULL, cb_data);
cb (".reg2", 512, 512, &amd64_fpregset, NULL, cb_data);
- cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0), X86_XSTATE_SIZE (tdep->xcr0),
- &amd64_linux_xstateregset, "XSAVE extended state", cb_data);
+ if (tdep->xsave_layout.sizeof_xsave != 0)
+ cb (".reg-xstate", tdep->xsave_layout.sizeof_xsave,
+ tdep->xsave_layout.sizeof_xsave, &amd64_linux_xstateregset,
+ "XSAVE extended state", cb_data);
}
/* The instruction sequences used in x86_64 machines for a
@@ -1807,6 +1813,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
tdep->xsave_xcr0_offset = I386_LINUX_XSAVE_XCR0_OFFSET;
+ set_gdbarch_core_read_x86_xsave_layout
+ (gdbarch, i386_linux_core_read_x86_xsave_layout);
/* Add the %orig_rax register used for syscall restarting. */
set_gdbarch_write_pc (gdbarch, amd64_linux_write_pc);
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -637,45 +637,48 @@ static int i386_linux_sc_reg_offset[] =
0 * 4 /* %gs */
};
-/* Get XSAVE extended state xcr0 from core dump. */
+/* See i386-linux-tdep.h. */
uint64_t
-i386_linux_core_read_xcr0 (bfd *abfd)
+i386_linux_core_read_xsave_info (bfd *abfd, x86_xsave_layout &layout)
{
asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
- uint64_t xcr0;
+ if (xstate == nullptr)
+ return 0;
- if (xstate)
- {
- size_t size = bfd_section_size (xstate);
+ /* Check extended state size. */
+ size_t size = bfd_section_size (xstate);
+ if (size < X86_XSTATE_AVX_SIZE)
+ return 0;
- /* Check extended state size. */
- if (size < X86_XSTATE_AVX_SIZE)
- xcr0 = X86_XSTATE_SSE_MASK;
- else
- {
- char contents[8];
-
- if (! bfd_get_section_contents (abfd, xstate, contents,
- I386_LINUX_XSAVE_XCR0_OFFSET,
- 8))
- {
- warning (_("Couldn't read `xcr0' bytes from "
- "`.reg-xstate' section in core file."));
- return 0;
- }
-
- xcr0 = bfd_get_64 (abfd, contents);
- }
+ char contents[8];
+ if (! bfd_get_section_contents (abfd, xstate, contents,
+ I386_LINUX_XSAVE_XCR0_OFFSET, 8))
+ {
+ warning (_("Couldn't read `xcr0' bytes from "
+ "`.reg-xstate' section in core file."));
+ return 0;
}
- else
- xcr0 = 0;
+
+ uint64_t xcr0 = bfd_get_64 (abfd, contents);
+
+ if (!i387_guess_xsave_layout (xcr0, size, layout))
+ return 0;
return xcr0;
}
/* See i386-linux-tdep.h. */
+bool
+i386_linux_core_read_x86_xsave_layout (struct gdbarch *gdbarch,
+ x86_xsave_layout &layout)
+{
+ return i386_linux_core_read_xsave_info (core_bfd, layout) != 0;
+}
+
+/* See i386-linux-tdep.h. */
+
const struct target_desc *
i386_linux_read_description (uint64_t xcr0)
{
@@ -707,7 +710,9 @@ i386_linux_core_read_description (struct gdbarch *gdbarch,
bfd *abfd)
{
/* Linux/i386. */
- uint64_t xcr0 = i386_linux_core_read_xcr0 (abfd);
+ x86_xsave_layout layout;
+ memset (&layout, 0, sizeof (x86_xsave_layout));
+ uint64_t xcr0 = i386_linux_core_read_xsave_info (abfd, layout);
const struct target_desc *tdesc = i386_linux_read_description (xcr0);
if (tdesc != NULL)
@@ -766,9 +771,9 @@ i386_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
cb (".reg", 68, 68, &i386_gregset, NULL, cb_data);
- if (tdep->xcr0 & X86_XSTATE_AVX)
- cb (".reg-xstate", X86_XSTATE_SIZE (tdep->xcr0),
- X86_XSTATE_SIZE (tdep->xcr0), &i386_linux_xstateregset,
+ if (tdep->xsave_layout.sizeof_xsave != 0)
+ cb (".reg-xstate", tdep->xsave_layout.sizeof_xsave,
+ tdep->xsave_layout.sizeof_xsave, &i386_linux_xstateregset,
"XSAVE extended state", cb_data);
else if (tdep->xcr0 & X86_XSTATE_SSE)
cb (".reg-xfp", 512, 512, &i386_fpregset, "extended floating-point",
@@ -870,6 +875,8 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->sc_num_regs = ARRAY_SIZE (i386_linux_sc_reg_offset);
tdep->xsave_xcr0_offset = I386_LINUX_XSAVE_XCR0_OFFSET;
+ set_gdbarch_core_read_x86_xsave_layout
+ (gdbarch, i386_linux_core_read_x86_xsave_layout);
set_gdbarch_process_record (gdbarch, i386_process_record);
set_gdbarch_process_record_signal (gdbarch, i386_linux_record_signal);
diff --git a/gdb/i386-linux-tdep.h b/gdb/i386-linux-tdep.h
--- a/gdb/i386-linux-tdep.h
+++ b/gdb/i386-linux-tdep.h
@@ -20,6 +20,8 @@
#ifndef I386_LINUX_TDEP_H
#define I386_LINUX_TDEP_H
+#include "gdbsupport/x86-xstate.h"
+
/* The Linux kernel pretends there is an additional "orig_eax"
register. Since GDB needs access to that register to be able to
properly restart system calls when necessary (see
@@ -34,8 +36,18 @@
/* Total number of registers for GNU/Linux. */
#define I386_LINUX_NUM_REGS (I386_LINUX_ORIG_EAX_REGNUM + 1)
-/* Get XSAVE extended state xcr0 from core dump. */
-extern uint64_t i386_linux_core_read_xcr0 (bfd *abfd);
+/* Read the XSAVE extended state xcr0 value from the ABFD core file.
+ If it appears to be valid, return it and fill LAYOUT with values
+ inferred from that value.
+
+ Otherwise, return 0 to indicate no state was found and leave LAYOUT
+ untouched. */
+extern uint64_t i386_linux_core_read_xsave_info (bfd *abfd,
+ x86_xsave_layout &layout);
+
+/* Implement the core_read_x86_xsave_layout gdbarch method. */
+extern bool i386_linux_core_read_x86_xsave_layout (struct gdbarch *gdbarch,
+ x86_xsave_layout &layout);
/* Handle and display information related to the MPX bound violation
to the user. */
@@ -52,14 +64,7 @@ extern const struct target_desc *i386_linux_read_description (uint64_t xcr0);
fxsave_bytes[0..463]
sw_usable_bytes[464..511]
xstate_hdr_bytes[512..575]
- avx_bytes[576..831]
- mpx_bytes [960..1032]
- avx512_k_regs[1088..1152]
- avx512_zmmh_regs0-7[1153..1407]
- avx512_zmmh_regs8-15[1408..1663]
- avx512_zmm_regs16-31[1664..2687]
- pkru[2688..2752]
- future_state etc
+ extended state regions (AVX, MPX, AVX512, PKRU, etc.)
};
Same memory layout will be used for the coredump NT_X86_XSTATE

View File

@ -0,0 +1,148 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:43 -0700
Subject: gdb-rhel-10464-xsave-update-7of21.patch
;; Backport "gdb: Support XSAVE layouts for the current host in the Linux
;; x86 targets."
;; (John Baldwin, RHEL-10464)
Note that this uses the CPUID instruction to determine the total size
of the XSAVE register set. If there is a way to fetch the register set
size using ptrace that would probably be better.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -210,6 +210,7 @@ void
amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
{
struct gdbarch *gdbarch = regcache->arch ();
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int tid;
/* GNU/Linux LWP ID's are process ID's. */
@@ -235,7 +236,7 @@ amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
- char xstateregs[X86_XSTATE_MAX_SIZE];
+ char xstateregs[tdep->xsave_layout.sizeof_xsave];
struct iovec iov;
/* Pre-4.14 kernels have a bug (fixed by commit 0852b374173b
@@ -270,6 +271,7 @@ void
amd64_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
{
struct gdbarch *gdbarch = regcache->arch ();
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int tid;
/* GNU/Linux LWP ID's are process ID's. */
@@ -299,7 +301,7 @@ amd64_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
- char xstateregs[X86_XSTATE_MAX_SIZE];
+ char xstateregs[tdep->xsave_layout.sizeof_xsave];
struct iovec iov;
iov.iov_base = xstateregs;
diff --git a/gdb/configure.nat b/gdb/configure.nat
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -246,6 +246,7 @@ case ${gdb_host} in
i386)
# Host: Intel 386 running GNU/Linux.
NATDEPFILES="${NATDEPFILES} x86-nat.o nat/x86-dregs.o \
+ nat/x86-xstate.o \
i386-linux-nat.o x86-linux-nat.o nat/linux-btrace.o \
nat/x86-linux.o nat/x86-linux-dregs.o"
;;
@@ -303,7 +304,7 @@ case ${gdb_host} in
i386)
# Host: GNU/Linux x86-64
NATDEPFILES="${NATDEPFILES} x86-nat.o nat/x86-dregs.o \
- amd64-nat.o amd64-linux-nat.o x86-linux-nat.o \
+ nat/x86-xstate.o amd64-nat.o amd64-linux-nat.o x86-linux-nat.o \
nat/linux-btrace.o \
nat/x86-linux.o nat/x86-linux-dregs.o \
nat/amd64-linux-siginfo.o"
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -330,7 +330,9 @@ store_fpregs (const struct regcache *regcache, int tid, int regno)
static int
fetch_xstateregs (struct regcache *regcache, int tid)
{
- char xstateregs[X86_XSTATE_MAX_SIZE];
+ struct gdbarch *gdbarch = regcache->arch ();
+ const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ char xstateregs[tdep->xsave_layout.sizeof_xsave];
struct iovec iov;
if (have_ptrace_getregset != TRIBOOL_TRUE)
@@ -353,7 +355,9 @@ fetch_xstateregs (struct regcache *regcache, int tid)
static int
store_xstateregs (const struct regcache *regcache, int tid, int regno)
{
- char xstateregs[X86_XSTATE_MAX_SIZE];
+ struct gdbarch *gdbarch = regcache->arch ();
+ const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ char xstateregs[tdep->xsave_layout.sizeof_xsave];
struct iovec iov;
if (have_ptrace_getregset != TRIBOOL_TRUE)
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -36,6 +36,7 @@
#include "amd64-linux-tdep.h"
#endif
#include "gdbsupport/x86-xstate.h"
+#include "nat/x86-xstate.h"
#include "nat/linux-btrace.h"
#include "nat/linux-nat.h"
#include "nat/x86-linux.h"
@@ -177,6 +178,8 @@ x86_linux_nat_target::read_description ()
/* Get XCR0 from XSAVE extended state. */
xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET
/ sizeof (uint64_t))];
+
+ m_xsave_layout = x86_fetch_xsave_layout (xcr0, x86_xsave_length ());
}
}
diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h
--- a/gdb/x86-linux-nat.h
+++ b/gdb/x86-linux-nat.h
@@ -22,6 +22,7 @@
#include "gdb_proc_service.h" /* For ps_err_e. */
#include "linux-nat.h"
+#include "gdbsupport/x86-xstate.h"
#include "x86-nat.h"
#include "nat/x86-linux.h"
@@ -44,6 +45,9 @@ struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
enum btrace_read_type type) override;
const struct btrace_config *btrace_conf (const struct btrace_target_info *) override;
+ x86_xsave_layout fetch_x86_xsave_layout () override
+ { return m_xsave_layout; }
+
/* These two are rewired to low_ versions. linux-nat.c queries
stopped-by-watchpoint info as soon as an lwp stops (via the low_
methods) and caches the result, to be returned via the normal
@@ -73,6 +77,9 @@ struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
void low_delete_thread (struct arch_lwp_info *lwp) override
{ x86_linux_delete_thread (lwp); }
+
+private:
+ x86_xsave_layout m_xsave_layout;
};

View File

@ -0,0 +1,720 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:44 -0700
Subject: gdb-rhel-10464-xsave-update-8of21.patch
;; Backport "gdb: Use x86_xstate_layout to parse the XSAVE extended state area."
;; (John Baldwin, RHEL-10464)
All of the tables describing the offsets of individual registers for
XSAVE state components now hold relative offsets rather than absolute
offsets. Some tables (those for MPX registers and ZMMH registers) had
to be split into separate tables as they held entries that spanned
multiple state components.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -727,170 +727,204 @@ i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
/* `xstate_bv' is at byte offset 512. */
#define XSAVE_XSTATE_BV_ADDR(xsave) (xsave + 512)
-/* At xsave_avxh_offset[REGNUM] you'll find the offset to the location in
- the upper 128bit of AVX register data structure used by the "xsave"
- instruction where GDB register REGNUM is stored. */
+/* At xsave_avxh_offset[REGNUM] you'll find the relative offset within
+ the AVX region of the XSAVE extended state where the upper 128bits
+ of GDB register YMM0 + REGNUM is stored. */
static int xsave_avxh_offset[] =
{
- 576 + 0 * 16, /* Upper 128bit of %ymm0 through ... */
- 576 + 1 * 16,
- 576 + 2 * 16,
- 576 + 3 * 16,
- 576 + 4 * 16,
- 576 + 5 * 16,
- 576 + 6 * 16,
- 576 + 7 * 16,
- 576 + 8 * 16,
- 576 + 9 * 16,
- 576 + 10 * 16,
- 576 + 11 * 16,
- 576 + 12 * 16,
- 576 + 13 * 16,
- 576 + 14 * 16,
- 576 + 15 * 16 /* Upper 128bit of ... %ymm15 (128 bits each). */
+ 0 * 16, /* Upper 128bit of %ymm0 through ... */
+ 1 * 16,
+ 2 * 16,
+ 3 * 16,
+ 4 * 16,
+ 5 * 16,
+ 6 * 16,
+ 7 * 16,
+ 8 * 16,
+ 9 * 16,
+ 10 * 16,
+ 11 * 16,
+ 12 * 16,
+ 13 * 16,
+ 14 * 16,
+ 15 * 16 /* Upper 128bit of ... %ymm15 (128 bits each). */
};
-#define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
+#define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.avx_offset \
+ + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
-/* At xsave_ymm_avx512_offset[REGNUM] you'll find the offset to the location in
- the upper 128bit of ZMM register data structure used by the "xsave"
- instruction where GDB register REGNUM is stored. */
+/* At xsave_ymm_avx512_offset[REGNUM] you'll find the relative offset
+ within the ZMM region of the XSAVE extended state where the second
+ 128bits of GDB register YMM16 + REGNUM is stored. */
static int xsave_ymm_avx512_offset[] =
{
- /* HI16_ZMM_area + 16 bytes + regnum* 64 bytes. */
- 1664 + 16 + 0 * 64, /* %ymm16 through... */
- 1664 + 16 + 1 * 64,
- 1664 + 16 + 2 * 64,
- 1664 + 16 + 3 * 64,
- 1664 + 16 + 4 * 64,
- 1664 + 16 + 5 * 64,
- 1664 + 16 + 6 * 64,
- 1664 + 16 + 7 * 64,
- 1664 + 16 + 8 * 64,
- 1664 + 16 + 9 * 64,
- 1664 + 16 + 10 * 64,
- 1664 + 16 + 11 * 64,
- 1664 + 16 + 12 * 64,
- 1664 + 16 + 13 * 64,
- 1664 + 16 + 14 * 64,
- 1664 + 16 + 15 * 64 /* ... %ymm31 (128 bits each). */
+ 16 + 0 * 64, /* %ymm16 through... */
+ 16 + 1 * 64,
+ 16 + 2 * 64,
+ 16 + 3 * 64,
+ 16 + 4 * 64,
+ 16 + 5 * 64,
+ 16 + 6 * 64,
+ 16 + 7 * 64,
+ 16 + 8 * 64,
+ 16 + 9 * 64,
+ 16 + 10 * 64,
+ 16 + 11 * 64,
+ 16 + 12 * 64,
+ 16 + 13 * 64,
+ 16 + 14 * 64,
+ 16 + 15 * 64 /* ... %ymm31 (128 bits each). */
};
-#define XSAVE_YMM_AVX512_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_ymm_avx512_offset[regnum - I387_YMM16H_REGNUM (tdep)])
+#define XSAVE_YMM_AVX512_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.zmm_offset \
+ + xsave_ymm_avx512_offset[regnum - I387_YMM16H_REGNUM (tdep)])
+
+/* At xsave_xmm_avx512_offset[REGNUM] you'll find the relative offset
+ within the ZMM region of the XSAVE extended state where the first
+ 128bits of GDB register XMM16 + REGNUM is stored. */
static int xsave_xmm_avx512_offset[] =
{
- 1664 + 0 * 64, /* %ymm16 through... */
- 1664 + 1 * 64,
- 1664 + 2 * 64,
- 1664 + 3 * 64,
- 1664 + 4 * 64,
- 1664 + 5 * 64,
- 1664 + 6 * 64,
- 1664 + 7 * 64,
- 1664 + 8 * 64,
- 1664 + 9 * 64,
- 1664 + 10 * 64,
- 1664 + 11 * 64,
- 1664 + 12 * 64,
- 1664 + 13 * 64,
- 1664 + 14 * 64,
- 1664 + 15 * 64 /* ... %ymm31 (128 bits each). */
+ 0 * 64, /* %xmm16 through... */
+ 1 * 64,
+ 2 * 64,
+ 3 * 64,
+ 4 * 64,
+ 5 * 64,
+ 6 * 64,
+ 7 * 64,
+ 8 * 64,
+ 9 * 64,
+ 10 * 64,
+ 11 * 64,
+ 12 * 64,
+ 13 * 64,
+ 14 * 64,
+ 15 * 64 /* ... %xmm31 (128 bits each). */
};
-#define XSAVE_XMM_AVX512_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
+#define XSAVE_XMM_AVX512_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.zmm_offset \
+ + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
+
+/* At xsave_bndregs_offset[REGNUM] you'll find the relative offset
+ within the BNDREGS region of the XSAVE extended state where the GDB
+ register BND0R + REGNUM is stored. */
-static int xsave_mpx_offset[] = {
- 960 + 0 * 16, /* bnd0r...bnd3r registers. */
- 960 + 1 * 16,
- 960 + 2 * 16,
- 960 + 3 * 16,
- 1024 + 0 * 8, /* bndcfg ... bndstatus. */
- 1024 + 1 * 8,
+static int xsave_bndregs_offset[] = {
+ 0 * 16, /* bnd0r...bnd3r registers. */
+ 1 * 16,
+ 2 * 16,
+ 3 * 16
};
-#define XSAVE_MPX_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_mpx_offset[regnum - I387_BND0R_REGNUM (tdep)])
+#define XSAVE_BNDREGS_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.bndregs_offset \
+ + xsave_bndregs_offset[regnum - I387_BND0R_REGNUM (tdep)])
+
+static int xsave_bndcfg_offset[] = {
+ 0 * 8, /* bndcfg ... bndstatus. */
+ 1 * 8,
+};
- /* At xsave_avx512__h_offset[REGNUM] you find the offset to the location
- of the AVX512 opmask register data structure used by the "xsave"
- instruction where GDB register REGNUM is stored. */
+#define XSAVE_BNDCFG_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.bndcfg_offset \
+ + xsave_bndcfg_offset[regnum - I387_BNDCFGU_REGNUM (tdep)])
+
+/* At xsave_avx512_k_offset[REGNUM] you'll find the relative offset
+ within the K region of the XSAVE extended state where the AVX512
+ opmask register K0 + REGNUM is stored. */
static int xsave_avx512_k_offset[] =
{
- 1088 + 0 * 8, /* %k0 through... */
- 1088 + 1 * 8,
- 1088 + 2 * 8,
- 1088 + 3 * 8,
- 1088 + 4 * 8,
- 1088 + 5 * 8,
- 1088 + 6 * 8,
- 1088 + 7 * 8 /* %k7 (64 bits each). */
+ 0 * 8, /* %k0 through... */
+ 1 * 8,
+ 2 * 8,
+ 3 * 8,
+ 4 * 8,
+ 5 * 8,
+ 6 * 8,
+ 7 * 8 /* %k7 (64 bits each). */
+};
+
+#define XSAVE_AVX512_K_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.k_offset \
+ + xsave_avx512_k_offset[regnum - I387_K0_REGNUM (tdep)])
+
+
+/* At xsave_avx512_zmm0_h_offset[REGNUM] you find the relative offset
+ within the ZMM_H region of the XSAVE extended state where the upper
+ 256bits of the GDB register ZMM0 + REGNUM is stored. */
+
+static int xsave_avx512_zmm0_h_offset[] =
+{
+ 0 * 32, /* Upper 256bit of %zmmh0 through... */
+ 1 * 32,
+ 2 * 32,
+ 3 * 32,
+ 4 * 32,
+ 5 * 32,
+ 6 * 32,
+ 7 * 32,
+ 8 * 32,
+ 9 * 32,
+ 10 * 32,
+ 11 * 32,
+ 12 * 32,
+ 13 * 32,
+ 14 * 32,
+ 15 * 32 /* Upper 256bit of... %zmmh15 (256 bits each). */
};
-#define XSAVE_AVX512_K_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_avx512_k_offset[regnum - I387_K0_REGNUM (tdep)])
+#define XSAVE_AVX512_ZMM0_H_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.zmm_h_offset \
+ + xsave_avx512_zmm0_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)])
-/* At xsave_avx512_zmm_h_offset[REGNUM] you find the offset to the location in
- the upper 256bit of AVX512 ZMMH register data structure used by the "xsave"
- instruction where GDB register REGNUM is stored. */
+/* At xsave_avx512_zmm16_h_offset[REGNUM] you find the relative offset
+ within the ZMM_H region of the XSAVE extended state where the upper
+ 256bits of the GDB register ZMM16 + REGNUM is stored. */
-static int xsave_avx512_zmm_h_offset[] =
+static int xsave_avx512_zmm16_h_offset[] =
{
- 1152 + 0 * 32,
- 1152 + 1 * 32, /* Upper 256bit of %zmmh0 through... */
- 1152 + 2 * 32,
- 1152 + 3 * 32,
- 1152 + 4 * 32,
- 1152 + 5 * 32,
- 1152 + 6 * 32,
- 1152 + 7 * 32,
- 1152 + 8 * 32,
- 1152 + 9 * 32,
- 1152 + 10 * 32,
- 1152 + 11 * 32,
- 1152 + 12 * 32,
- 1152 + 13 * 32,
- 1152 + 14 * 32,
- 1152 + 15 * 32, /* Upper 256bit of... %zmmh15 (256 bits each). */
- 1664 + 32 + 0 * 64, /* Upper 256bit of... %zmmh16 (256 bits each). */
- 1664 + 32 + 1 * 64,
- 1664 + 32 + 2 * 64,
- 1664 + 32 + 3 * 64,
- 1664 + 32 + 4 * 64,
- 1664 + 32 + 5 * 64,
- 1664 + 32 + 6 * 64,
- 1664 + 32 + 7 * 64,
- 1664 + 32 + 8 * 64,
- 1664 + 32 + 9 * 64,
- 1664 + 32 + 10 * 64,
- 1664 + 32 + 11 * 64,
- 1664 + 32 + 12 * 64,
- 1664 + 32 + 13 * 64,
- 1664 + 32 + 14 * 64,
- 1664 + 32 + 15 * 64 /* Upper 256bit of... %zmmh31 (256 bits each). */
+ 32 + 0 * 64, /* Upper 256bit of... %zmmh16 (256 bits each). */
+ 32 + 1 * 64,
+ 32 + 2 * 64,
+ 32 + 3 * 64,
+ 32 + 4 * 64,
+ 32 + 5 * 64,
+ 32 + 6 * 64,
+ 32 + 7 * 64,
+ 32 + 8 * 64,
+ 32 + 9 * 64,
+ 32 + 10 * 64,
+ 32 + 11 * 64,
+ 32 + 12 * 64,
+ 32 + 13 * 64,
+ 32 + 14 * 64,
+ 32 + 15 * 64 /* Upper 256bit of... %zmmh31 (256 bits each). */
};
-#define XSAVE_AVX512_ZMM_H_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_avx512_zmm_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)])
+#define XSAVE_AVX512_ZMM16_H_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.zmm_offset \
+ + xsave_avx512_zmm16_h_offset[regnum - I387_ZMM16H_REGNUM (tdep)])
-/* At xsave_pkeys_offset[REGNUM] you find the offset to the location
- of the PKRU register data structure used by the "xsave"
- instruction where GDB register REGNUM is stored. */
+/* At xsave_pkeys_offset[REGNUM] you'll find the relative offset
+ within the PKEYS region of the XSAVE extended state where the PKRU
+ register is stored. */
static int xsave_pkeys_offset[] =
{
-2688 + 0 * 8 /* %pkru (64 bits in XSTATE, 32-bit actually used by
+ 0 * 8 /* %pkru (64 bits in XSTATE, 32-bit actually used by
instructions and applications). */
};
-#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum) \
- (xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum) \
+ (xsave + (tdep)->xsave_layout.pkru_offset \
+ + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
/* See i387-tdep.h. */
@@ -993,14 +1027,16 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
x87 = 0x1,
sse = 0x2,
avxh = 0x4,
- mpx = 0x8,
- avx512_k = 0x10,
- avx512_zmm_h = 0x20,
- avx512_ymmh_avx512 = 0x40,
- avx512_xmm_avx512 = 0x80,
- pkeys = 0x100,
- all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
- | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+ bndregs = 0x8,
+ bndcfg = 0x10,
+ avx512_k = 0x20,
+ avx512_zmm0_h = 0x40,
+ avx512_zmm16_h = 0x80,
+ avx512_ymmh_avx512 = 0x100,
+ avx512_xmm_avx512 = 0x200,
+ pkeys = 0x400,
+ all = x87 | sse | avxh | bndregs | bndcfg | avx512_k | avx512_zmm0_h
+ | avx512_zmm16_h | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
} regclass;
gdb_assert (regs != NULL);
@@ -1013,8 +1049,11 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
&& regnum < I387_PKEYSEND_REGNUM (tdep))
regclass = pkeys;
else if (regnum >= I387_ZMM0H_REGNUM (tdep)
+ && regnum < I387_ZMM16H_REGNUM (tdep))
+ regclass = avx512_zmm0_h;
+ else if (regnum >= I387_ZMM16H_REGNUM (tdep)
&& regnum < I387_ZMMENDH_REGNUM (tdep))
- regclass = avx512_zmm_h;
+ regclass = avx512_zmm16_h;
else if (regnum >= I387_K0_REGNUM (tdep)
&& regnum < I387_KEND_REGNUM (tdep))
regclass = avx512_k;
@@ -1028,8 +1067,11 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
&& regnum < I387_YMMENDH_REGNUM (tdep))
regclass = avxh;
else if (regnum >= I387_BND0R_REGNUM (tdep)
+ && regnum < I387_BNDCFGU_REGNUM (tdep))
+ regclass = bndregs;
+ else if (regnum >= I387_BNDCFGU_REGNUM (tdep)
&& regnum < I387_MPXEND_REGNUM (tdep))
- regclass = mpx;
+ regclass = bndcfg;
else if (regnum >= I387_XMM0_REGNUM (tdep)
&& regnum < I387_MXCSR_REGNUM (tdep))
regclass = sse;
@@ -1062,13 +1104,20 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
regcache->raw_supply (regnum, XSAVE_PKEYS_ADDR (tdep, regs, regnum));
return;
- case avx512_zmm_h:
- if ((clear_bv & (regnum < zmm_endlo_regnum ? X86_XSTATE_ZMM_H
- : X86_XSTATE_ZMM)))
+ case avx512_zmm0_h:
+ if ((clear_bv & X86_XSTATE_ZMM_H))
+ regcache->raw_supply (regnum, zero);
+ else
+ regcache->raw_supply (regnum,
+ XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, regnum));
+ return;
+
+ case avx512_zmm16_h:
+ if ((clear_bv & X86_XSTATE_ZMM))
regcache->raw_supply (regnum, zero);
else
regcache->raw_supply (regnum,
- XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum));
+ XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, regnum));
return;
case avx512_k:
@@ -1101,11 +1150,18 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
regcache->raw_supply (regnum, XSAVE_AVXH_ADDR (tdep, regs, regnum));
return;
- case mpx:
+ case bndcfg:
+ if ((clear_bv & X86_XSTATE_BNDCFG))
+ regcache->raw_supply (regnum, zero);
+ else
+ regcache->raw_supply (regnum, XSAVE_BNDCFG_ADDR (tdep, regs, regnum));
+ return;
+
+ case bndregs:
if ((clear_bv & X86_XSTATE_BNDREGS))
regcache->raw_supply (regnum, zero);
else
- regcache->raw_supply (regnum, XSAVE_MPX_ADDR (tdep, regs, regnum));
+ regcache->raw_supply (regnum, XSAVE_BNDREGS_ADDR (tdep, regs, regnum));
return;
case sse:
@@ -1154,7 +1210,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
{
for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
regcache->raw_supply (i,
- XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
+ XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, i));
}
}
@@ -1182,7 +1238,8 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
{
if ((clear_bv & X86_XSTATE_ZMM))
{
- for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++)
+ for (i = I387_ZMM16H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep); i++)
regcache->raw_supply (i, zero);
for (i = I387_YMM16H_REGNUM (tdep);
i < I387_YMMH_AVX512_END_REGNUM (tdep);
@@ -1195,9 +1252,10 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
}
else
{
- for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++)
+ for (i = I387_ZMM16H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep); i++)
regcache->raw_supply (i,
- XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
+ XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, i));
for (i = I387_YMM16H_REGNUM (tdep);
i < I387_YMMH_AVX512_END_REGNUM (tdep);
i++)
@@ -1240,7 +1298,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
{
for (i = I387_BND0R_REGNUM (tdep);
i < I387_BNDCFGU_REGNUM (tdep); i++)
- regcache->raw_supply (i, XSAVE_MPX_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_BNDREGS_ADDR (tdep, regs, i));
}
}
@@ -1257,7 +1315,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
{
for (i = I387_BNDCFGU_REGNUM (tdep);
i < I387_MPXEND_REGNUM (tdep); i++)
- regcache->raw_supply (i, XSAVE_MPX_ADDR (tdep, regs, i));
+ regcache->raw_supply (i, XSAVE_BNDCFG_ADDR (tdep, regs, i));
}
}
@@ -1413,14 +1471,16 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
x87 = 0x2,
sse = 0x4,
avxh = 0x8,
- mpx = 0x10,
- avx512_k = 0x20,
- avx512_zmm_h = 0x40,
- avx512_ymmh_avx512 = 0x80,
- avx512_xmm_avx512 = 0x100,
- pkeys = 0x200,
- all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
- | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+ bndregs = 0x10,
+ bndcfg = 0x20,
+ avx512_k = 0x40,
+ avx512_zmm0_h = 0x80,
+ avx512_zmm16_h = 0x100,
+ avx512_ymmh_avx512 = 0x200,
+ avx512_xmm_avx512 = 0x400,
+ pkeys = 0x800,
+ all = x87 | sse | avxh | bndregs | bndcfg | avx512_k | avx512_zmm0_h
+ | avx512_zmm16_h | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
} regclass;
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
@@ -1432,8 +1492,11 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
&& regnum < I387_PKEYSEND_REGNUM (tdep))
regclass = pkeys;
else if (regnum >= I387_ZMM0H_REGNUM (tdep)
+ && regnum < I387_ZMM16H_REGNUM (tdep))
+ regclass = avx512_zmm0_h;
+ else if (regnum >= I387_ZMM16H_REGNUM (tdep)
&& regnum < I387_ZMMENDH_REGNUM (tdep))
- regclass = avx512_zmm_h;
+ regclass = avx512_zmm16_h;
else if (regnum >= I387_K0_REGNUM (tdep)
&& regnum < I387_KEND_REGNUM (tdep))
regclass = avx512_k;
@@ -1447,8 +1510,11 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
&& regnum < I387_YMMENDH_REGNUM (tdep))
regclass = avxh;
else if (regnum >= I387_BND0R_REGNUM (tdep)
+ && regnum < I387_BNDCFGU_REGNUM (tdep))
+ regclass = bndregs;
+ else if (regnum >= I387_BNDCFGU_REGNUM (tdep)
&& regnum < I387_MPXEND_REGNUM (tdep))
- regclass = mpx;
+ regclass = bndcfg;
else if (regnum >= I387_XMM0_REGNUM (tdep)
&& regnum < I387_MXCSR_REGNUM (tdep))
regclass = sse;
@@ -1465,7 +1531,7 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
if (gcore)
{
/* Clear XSAVE extended state. */
- memset (regs, 0, X86_XSTATE_SIZE (tdep->xcr0));
+ memset (regs, 0, tdep->xsave_layout.sizeof_xsave);
/* Update XCR0 and `xstate_bv' with XCR0 for gcore. */
if (tdep->xsave_xcr0_offset != -1)
@@ -1500,16 +1566,16 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
if ((clear_bv & X86_XSTATE_BNDREGS))
for (i = I387_BND0R_REGNUM (tdep);
i < I387_BNDCFGU_REGNUM (tdep); i++)
- memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 16);
+ memset (XSAVE_BNDREGS_ADDR (tdep, regs, i), 0, 16);
if ((clear_bv & X86_XSTATE_BNDCFG))
for (i = I387_BNDCFGU_REGNUM (tdep);
i < I387_MPXEND_REGNUM (tdep); i++)
- memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 8);
+ memset (XSAVE_BNDCFG_ADDR (tdep, regs, i), 0, 8);
if ((clear_bv & X86_XSTATE_ZMM_H))
for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
- memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
+ memset (XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, i), 0, 32);
if ((clear_bv & X86_XSTATE_K))
for (i = I387_K0_REGNUM (tdep);
@@ -1518,8 +1584,9 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
if ((clear_bv & X86_XSTATE_ZMM))
{
- for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++)
- memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
+ for (i = I387_ZMM16H_REGNUM (tdep); i < I387_ZMMENDH_REGNUM (tdep);
+ i++)
+ memset (XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, i), 0, 32);
for (i = I387_YMM16H_REGNUM (tdep);
i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
memset (XSAVE_YMM_AVX512_ADDR (tdep, regs, i), 0, 16);
@@ -1582,15 +1649,27 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
}
/* Check if any ZMMH registers are changed. */
- if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
- for (i = I387_ZMM0H_REGNUM (tdep);
+ if ((tdep->xcr0 & X86_XSTATE_ZMM))
+ for (i = I387_ZMM16H_REGNUM (tdep);
i < I387_ZMMENDH_REGNUM (tdep); i++)
{
regcache->raw_collect (i, raw);
- p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i);
+ p = XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, i);
if (memcmp (raw, p, 32) != 0)
{
- xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 32);
+ }
+ }
+
+ if ((tdep->xcr0 & X86_XSTATE_ZMM_H))
+ for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++)
+ {
+ regcache->raw_collect (i, raw);
+ p = XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 32) != 0)
+ {
+ xstate_bv |= X86_XSTATE_ZMM_H;
memcpy (p, raw, 32);
}
}
@@ -1642,7 +1721,7 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
i < I387_BNDCFGU_REGNUM (tdep); i++)
{
regcache->raw_collect (i, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, i);
+ p = XSAVE_BNDREGS_ADDR (tdep, regs, i);
if (memcmp (raw, p, 16))
{
xstate_bv |= X86_XSTATE_BNDREGS;
@@ -1656,7 +1735,7 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
i < I387_MPXEND_REGNUM (tdep); i++)
{
regcache->raw_collect (i, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, i);
+ p = XSAVE_BNDCFG_ADDR (tdep, regs, i);
if (memcmp (raw, p, 8))
{
xstate_bv |= X86_XSTATE_BNDCFG;
@@ -1746,15 +1825,26 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
}
break;
- case avx512_zmm_h:
- /* This is a ZMM register. */
- p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum);
+ case avx512_zmm16_h:
+ /* This is a ZMM16-31 register. */
+ p = XSAVE_AVX512_ZMM16_H_ADDR (tdep, regs, regnum);
if (memcmp (raw, p, 32) != 0)
{
- xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
+ xstate_bv |= X86_XSTATE_ZMM;
memcpy (p, raw, 32);
}
break;
+
+ case avx512_zmm0_h:
+ /* This is a ZMM0-15 register. */
+ p = XSAVE_AVX512_ZMM0_H_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 32) != 0)
+ {
+ xstate_bv |= X86_XSTATE_ZMM_H;
+ memcpy (p, raw, 32);
+ }
+ break;
+
case avx512_k:
/* This is a AVX512 mask register. */
p = XSAVE_AVX512_K_ADDR (tdep, regs, regnum);
@@ -1795,25 +1885,22 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
}
break;
- case mpx:
- if (regnum < I387_BNDCFGU_REGNUM (tdep))
- {
- regcache->raw_collect (regnum, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_BNDREGS;
- memcpy (p, raw, 16);
- }
- }
- else
+ case bndregs:
+ regcache->raw_collect (regnum, raw);
+ p = XSAVE_BNDREGS_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16))
{
- p = XSAVE_MPX_ADDR (tdep, regs, regnum);
- xstate_bv |= X86_XSTATE_BNDCFG;
- memcpy (p, raw, 8);
+ xstate_bv |= X86_XSTATE_BNDREGS;
+ memcpy (p, raw, 16);
}
break;
+ case bndcfg:
+ p = XSAVE_BNDCFG_ADDR (tdep, regs, regnum);
+ xstate_bv |= X86_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
+ break;
+
case sse:
/* This is an SSE register. */
p = FXSAVE_ADDR (tdep, regs, regnum);
diff --git a/gdb/i387-tdep.h b/gdb/i387-tdep.h
--- a/gdb/i387-tdep.h
+++ b/gdb/i387-tdep.h
@@ -51,6 +51,7 @@ struct x86_xsave_layout;
#define I387_K0_REGNUM(tdep) ((tdep)->k0_regnum)
#define I387_NUM_ZMMH_REGS(tdep) ((tdep)->num_zmm_regs)
#define I387_ZMM0H_REGNUM(tdep) ((tdep)->zmm0h_regnum)
+#define I387_ZMM16H_REGNUM(tdep) ((tdep)->zmm0h_regnum + 16)
#define I387_NUM_YMM_AVX512_REGS(tdep) ((tdep)->num_ymm_avx512_regs)
#define I387_YMM16H_REGNUM(tdep) ((tdep)->ymm16h_regnum)

View File

@ -0,0 +1,168 @@
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
From: John Baldwin <jhb@FreeBSD.org>
Date: Thu, 11 Apr 2024 14:05:44 -0700
Subject: gdb-rhel-10464-xsave-update-9of21.patch
;; Backport "gdbserver: Add a function to set the XSAVE mask and size."
;; (John Baldwin, RHEL-10464)
Make x86_xcr0 private to i387-fp.cc and use i387_set_xsave_mask to set
the value instead. Add a static global instance of x86_xsave_layout
and initialize it in the new function as well to be used in a future
commit to parse XSAVE extended state regions.
Update the Linux port to use this function rather than setting
x86_xcr0 directly. In the case that XML is not supported, don't
bother setting x86_xcr0 to the default value but just omit the call to
i387_set_xsave_mask as i387-fp.cc defaults to the SSE case used for
non-XML.
In addition, use x86_xsave_length to determine the size of the XSAVE
register set via CPUID.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv
--- a/gdbserver/configure.srv
+++ b/gdbserver/configure.srv
@@ -93,7 +93,8 @@ case "${gdbserver_host}" in
i[34567]86-*-linux*) srv_tgtobj="${srv_tgtobj} arch/i386.o"
srv_tgtobj="${srv_tgtobj} $srv_linux_obj"
srv_tgtobj="${srv_tgtobj} linux-x86-low.o x86-low.o"
- srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o i387-fp.o"
+ srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o"
+ srv_tgtobj="${srv_tgtobj} nat/x86-xstate.o i387-fp.o"
srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o"
srv_tgtobj="${srv_tgtobj} nat/linux-btrace.o"
srv_tgtobj="${srv_tgtobj} nat/x86-linux.o"
@@ -333,7 +334,8 @@ case "${gdbserver_host}" in
srv_linux_thread_db=yes
;;
x86_64-*-linux*) srv_tgtobj="$srv_linux_obj linux-x86-low.o x86-low.o"
- srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o i387-fp.o"
+ srv_tgtobj="${srv_tgtobj} nat/x86-dregs.o"
+ srv_tgtobj="${srv_tgtobj} nat/x86-xstate.o i387-fp.o"
srv_tgtobj="${srv_tgtobj} arch/i386.o arch/amd64.o"
srv_tgtobj="${srv_tgtobj} linux-x86-tdesc.o"
srv_tgtobj="${srv_tgtobj} nat/linux-btrace.o"
@@ -348,14 +350,16 @@ case "${gdbserver_host}" in
ipa_obj="${ipa_obj} arch/amd64-ipa.o"
;;
x86_64-*-mingw*) srv_regobj=""
- srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o"
+ srv_tgtobj="x86-low.o nat/x86-dregs.o"
+ srv_tgtobj="${srv_tgtobj} nat/x86-xstate.o i387-fp.o"
srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o"
srv_tgtobj="${srv_tgtobj} nat/windows-nat.o"
srv_tgtobj="${srv_tgtobj} arch/amd64.o arch/i386.o"
srv_mingw=yes
;;
x86_64-*-cygwin*) srv_regobj=""
- srv_tgtobj="x86-low.o nat/x86-dregs.o i387-fp.o"
+ srv_tgtobj="x86-low.o nat/x86-dregs.o"
+ srv_tgtobj="${srv_tgtobj} nat/x86-xstate.o i387-fp.o"
srv_tgtobj="${srv_tgtobj} win32-low.o win32-i386-low.o"
srv_tgtobj="${srv_tgtobj} nat/windows-nat.o"
srv_tgtobj="${srv_tgtobj} arch/amd64.o arch/i386.o"
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
--- a/gdbserver/i387-fp.cc
+++ b/gdbserver/i387-fp.cc
@@ -19,6 +19,10 @@
#include "server.h"
#include "i387-fp.h"
#include "gdbsupport/x86-xstate.h"
+#include "nat/x86-xstate.h"
+
+/* Default to SSE. */
+static unsigned long long x86_xcr0 = X86_XSTATE_SSE_MASK;
static const int num_mpx_bnd_registers = 4;
static const int num_mpx_cfg_registers = 2;
@@ -29,6 +33,8 @@ static const int num_avx512_ymmh_registers = 16;
static const int num_avx512_xmm_registers = 16;
static const int num_pkeys_registers = 1;
+static x86_xsave_layout xsave_layout;
+
/* Note: These functions preserve the reserved bits in control registers.
However, gdbserver promptly throws away that information. */
@@ -950,5 +956,11 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
-/* Default to SSE. */
-unsigned long long x86_xcr0 = X86_XSTATE_SSE_MASK;
+/* See i387-fp.h. */
+
+void
+i387_set_xsave_mask (uint64_t xcr0, int len)
+{
+ x86_xcr0 = xcr0;
+ xsave_layout = x86_fetch_xsave_layout (xcr0, len);
+}
diff --git a/gdbserver/i387-fp.h b/gdbserver/i387-fp.h
--- a/gdbserver/i387-fp.h
+++ b/gdbserver/i387-fp.h
@@ -28,6 +28,8 @@ void i387_fxsave_to_cache (struct regcache *regcache, const void *buf);
void i387_cache_to_xsave (struct regcache *regcache, void *buf);
void i387_xsave_to_cache (struct regcache *regcache, const void *buf);
-extern unsigned long long x86_xcr0;
+/* Set the XSAVE mask and fetch the XSAVE layout via CPUID. */
+
+void i387_set_xsave_mask (uint64_t xcr0, int len);
#endif /* GDBSERVER_I387_FP_H */
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -25,6 +25,7 @@
#include "i387-fp.h"
#include "x86-low.h"
#include "gdbsupport/x86-xstate.h"
+#include "nat/x86-xstate.h"
#include "nat/gdb_ptrace.h"
#ifdef __x86_64__
@@ -871,6 +872,7 @@ x86_linux_read_description (void)
int xcr0_features;
int tid;
static uint64_t xcr0;
+ static int xsave_len;
struct regset_info *regset;
tid = lwpid_of (current_thread);
@@ -905,8 +907,6 @@ x86_linux_read_description (void)
if (!use_xml)
{
- x86_xcr0 = X86_XSTATE_SSE_MASK;
-
/* Don't use XML. */
#ifdef __x86_64__
if (machine == EM_X86_64)
@@ -936,11 +936,13 @@ x86_linux_read_description (void)
xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET
/ sizeof (uint64_t))];
+ xsave_len = x86_xsave_length ();
+
/* Use PTRACE_GETREGSET if it is available. */
for (regset = x86_regsets;
regset->fill_function != NULL; regset++)
if (regset->get_request == PTRACE_GETREGSET)
- regset->size = X86_XSTATE_SIZE (xcr0);
+ regset->size = xsave_len;
else if (regset->type != GENERAL_REGS)
regset->size = 0;
}
@@ -951,7 +953,7 @@ x86_linux_read_description (void)
&& (xcr0 & X86_XSTATE_ALL_MASK));
if (xcr0_features)
- x86_xcr0 = xcr0;
+ i387_set_xsave_mask (xcr0, xsave_len);
if (machine == EM_X86_64)
{

View File

@ -37,7 +37,7 @@ Version: 10.2
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
Release: 13%{?dist}
Release: 14%{?dist}
License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and LGPLv3+ and BSD and Public Domain and GFDL
# Do not provide URL for snapshots as the file lasts there only for 2 days.
@ -1158,12 +1158,14 @@ fi
%endif
%changelog
* Thu Apr 11 2024 Keith Seitz
* Thu Apr 11 2024 Keith Seitz - 10.2-14.el9
- Backport "Fix GDB internal error by using text (instead of data)
section offset"
(Kevin Buettner, RHEL-17399)
- Backport "s390: Add arch14 record/replay support"
(Andreas Arnaz, RHEL-10550)
- Backport patches for x86 XSTATE update in gdb and gdbserver.
(John Baldwin et al, RHEL-10464)
* Wed Dec 13 2023 Keith Seitz - 10.2-13.el9
- Backport patches for "Fix undefined behaviour dereferencing empty string"