From bd876a4f726f5cbcac8f4350e013a2b70d332680 Mon Sep 17 00:00:00 2001 From: Keith Seitz Date: Thu, 11 Apr 2024 20:23:31 -0700 Subject: [PATCH] Backport patches for x86 XSTATE update in gdb and gdbserver. Resolves: RHEL-10464 --- _gdb.spec.Patch.include | 89 +++ _gdb.spec.patch.include | 21 + _patch_order | 21 + gdb-rhel-10464-xsave-update-10of21.patch | 39 ++ gdb-rhel-10464-xsave-update-11of21.patch | 170 ++++++ gdb-rhel-10464-xsave-update-12of21.patch | 341 +++++++++++ gdb-rhel-10464-xsave-update-13of21.patch | 229 +++++++ gdb-rhel-10464-xsave-update-14of21.patch | 69 +++ gdb-rhel-10464-xsave-update-15of21.patch | 41 ++ gdb-rhel-10464-xsave-update-16of21.patch | 52 ++ gdb-rhel-10464-xsave-update-17of21.patch | 188 ++++++ gdb-rhel-10464-xsave-update-18of21.patch | 67 +++ gdb-rhel-10464-xsave-update-19of21.patch | 132 +++++ gdb-rhel-10464-xsave-update-1of21.patch | 125 ++++ gdb-rhel-10464-xsave-update-20of21.patch | 162 +++++ gdb-rhel-10464-xsave-update-21of21.patch | 66 +++ gdb-rhel-10464-xsave-update-2of21.patch | 190 ++++++ gdb-rhel-10464-xsave-update-3of21.patch | 269 +++++++++ gdb-rhel-10464-xsave-update-4of21.patch | 79 +++ gdb-rhel-10464-xsave-update-5of21.patch | 133 +++++ gdb-rhel-10464-xsave-update-6of21.patch | 217 +++++++ gdb-rhel-10464-xsave-update-7of21.patch | 148 +++++ gdb-rhel-10464-xsave-update-8of21.patch | 720 +++++++++++++++++++++++ gdb-rhel-10464-xsave-update-9of21.patch | 168 ++++++ gdb.spec | 6 +- 25 files changed, 3740 insertions(+), 2 deletions(-) create mode 100644 gdb-rhel-10464-xsave-update-10of21.patch create mode 100644 gdb-rhel-10464-xsave-update-11of21.patch create mode 100644 gdb-rhel-10464-xsave-update-12of21.patch create mode 100644 gdb-rhel-10464-xsave-update-13of21.patch create mode 100644 gdb-rhel-10464-xsave-update-14of21.patch create mode 100644 gdb-rhel-10464-xsave-update-15of21.patch create mode 100644 gdb-rhel-10464-xsave-update-16of21.patch create mode 100644 gdb-rhel-10464-xsave-update-17of21.patch create mode 100644 gdb-rhel-10464-xsave-update-18of21.patch create mode 100644 gdb-rhel-10464-xsave-update-19of21.patch create mode 100644 gdb-rhel-10464-xsave-update-1of21.patch create mode 100644 gdb-rhel-10464-xsave-update-20of21.patch create mode 100644 gdb-rhel-10464-xsave-update-21of21.patch create mode 100644 gdb-rhel-10464-xsave-update-2of21.patch create mode 100644 gdb-rhel-10464-xsave-update-3of21.patch create mode 100644 gdb-rhel-10464-xsave-update-4of21.patch create mode 100644 gdb-rhel-10464-xsave-update-5of21.patch create mode 100644 gdb-rhel-10464-xsave-update-6of21.patch create mode 100644 gdb-rhel-10464-xsave-update-7of21.patch create mode 100644 gdb-rhel-10464-xsave-update-8of21.patch create mode 100644 gdb-rhel-10464-xsave-update-9of21.patch diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include index 0dea586..8198b37 100644 --- a/_gdb.spec.Patch.include +++ b/_gdb.spec.Patch.include @@ -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 + diff --git a/_gdb.spec.patch.include b/_gdb.spec.patch.include index 1bc02ff..17fefd4 100644 --- a/_gdb.spec.patch.include +++ b/_gdb.spec.patch.include @@ -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 diff --git a/_patch_order b/_patch_order index d7597bb..7289fa3 100644 --- a/_patch_order +++ b/_patch_order @@ -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 diff --git a/gdb-rhel-10464-xsave-update-10of21.patch b/gdb-rhel-10464-xsave-update-10of21.patch new file mode 100644 index 0000000..f907111 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-10of21.patch @@ -0,0 +1,39 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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 diff --git a/gdb-rhel-10464-xsave-update-11of21.patch b/gdb-rhel-10464-xsave-update-11of21.patch new file mode 100644 index 0000000..f7d2428 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-11of21.patch @@ -0,0 +1,170 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Tom de Vries +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) + { diff --git a/gdb-rhel-10464-xsave-update-12of21.patch b/gdb-rhel-10464-xsave-update-12of21.patch new file mode 100644 index 0000000..66f4203 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-12of21.patch @@ -0,0 +1,341 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Aleksandar Paunovic +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 +Co-authored-by: John Baldwin +Approved-By: Simon Marchi + +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 (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); + } diff --git a/gdb-rhel-10464-xsave-update-13of21.patch b/gdb-rhel-10464-xsave-update-13of21.patch new file mode 100644 index 0000000..2b9ba17 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-13of21.patch @@ -0,0 +1,229 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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); ++ } + } + } + diff --git a/gdb-rhel-10464-xsave-update-14of21.patch b/gdb-rhel-10464-xsave-update-14of21.patch new file mode 100644 index 0000000..3d7a673 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-14of21.patch @@ -0,0 +1,69 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Aleksandar Paunovic +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 +Co-authored-by: John Baldwin +Approved-By: Simon Marchi + +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); diff --git a/gdb-rhel-10464-xsave-update-15of21.patch b/gdb-rhel-10464-xsave-update-15of21.patch new file mode 100644 index 0000000..c524cf8 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-15of21.patch @@ -0,0 +1,41 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 diff --git a/gdb-rhel-10464-xsave-update-16of21.patch b/gdb-rhel-10464-xsave-update-16of21.patch new file mode 100644 index 0000000..e83e070 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-16of21.patch @@ -0,0 +1,52 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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. */ diff --git a/gdb-rhel-10464-xsave-update-17of21.patch b/gdb-rhel-10464-xsave-update-17of21.patch new file mode 100644 index 0000000..afa33f2 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-17of21.patch @@ -0,0 +1,188 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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, diff --git a/gdb-rhel-10464-xsave-update-18of21.patch b/gdb-rhel-10464-xsave-update-18of21.patch new file mode 100644 index 0000000..1fcd446 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-18of21.patch @@ -0,0 +1,67 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Simon Marchi +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 +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. */ diff --git a/gdb-rhel-10464-xsave-update-19of21.patch b/gdb-rhel-10464-xsave-update-19of21.patch new file mode 100644 index 0000000..abf790f --- /dev/null +++ b/gdb-rhel-10464-xsave-update-19of21.patch @@ -0,0 +1,132 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Andrew Burgess +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 */ diff --git a/gdb-rhel-10464-xsave-update-1of21.patch b/gdb-rhel-10464-xsave-update-1of21.patch new file mode 100644 index 0000000..372d1b1 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-1of21.patch @@ -0,0 +1,125 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 +Approved-By: Simon Marchi + +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 diff --git a/gdb-rhel-10464-xsave-update-20of21.patch b/gdb-rhel-10464-xsave-update-20of21.patch new file mode 100644 index 0000000..a2c9b18 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-20of21.patch @@ -0,0 +1,162 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: root +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 + #include + #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 + +@@ -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; + } + diff --git a/gdb-rhel-10464-xsave-update-21of21.patch b/gdb-rhel-10464-xsave-update-21of21.patch new file mode 100644 index 0000000..40bd77d --- /dev/null +++ b/gdb-rhel-10464-xsave-update-21of21.patch @@ -0,0 +1,66 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: root +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; + } diff --git a/gdb-rhel-10464-xsave-update-2of21.patch b/gdb-rhel-10464-xsave-update-2of21.patch new file mode 100644 index 0000000..5a432da --- /dev/null +++ b/gdb-rhel-10464-xsave-update-2of21.patch @@ -0,0 +1,190 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: Keith Seitz +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 + +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 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 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) \ diff --git a/gdb-rhel-10464-xsave-update-3of21.patch b/gdb-rhel-10464-xsave-update-3of21.patch new file mode 100644 index 0000000..95490b2 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-3of21.patch @@ -0,0 +1,269 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 +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 + #include + #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, diff --git a/gdb-rhel-10464-xsave-update-4of21.patch b/gdb-rhel-10464-xsave-update-4of21.patch new file mode 100644 index 0000000..800089c --- /dev/null +++ b/gdb-rhel-10464-xsave-update-4of21.patch @@ -0,0 +1,79 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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 */ diff --git a/gdb-rhel-10464-xsave-update-5of21.patch b/gdb-rhel-10464-xsave-update-5of21.patch new file mode 100644 index 0000000..a2b20d7 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-5of21.patch @@ -0,0 +1,133 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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 . */ ++ ++#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 . */ ++ ++#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 */ diff --git a/gdb-rhel-10464-xsave-update-6of21.patch b/gdb-rhel-10464-xsave-update-6of21.patch new file mode 100644 index 0000000..5ec3cb6 --- /dev/null +++ b/gdb-rhel-10464-xsave-update-6of21.patch @@ -0,0 +1,217 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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 diff --git a/gdb-rhel-10464-xsave-update-7of21.patch b/gdb-rhel-10464-xsave-update-7of21.patch new file mode 100644 index 0000000..0cf78ff --- /dev/null +++ b/gdb-rhel-10464-xsave-update-7of21.patch @@ -0,0 +1,148 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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 (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 (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 + 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 + + void low_delete_thread (struct arch_lwp_info *lwp) override + { x86_linux_delete_thread (lwp); } ++ ++private: ++ x86_xsave_layout m_xsave_layout; + }; + + diff --git a/gdb-rhel-10464-xsave-update-8of21.patch b/gdb-rhel-10464-xsave-update-8of21.patch new file mode 100644 index 0000000..5fc859b --- /dev/null +++ b/gdb-rhel-10464-xsave-update-8of21.patch @@ -0,0 +1,720 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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) + diff --git a/gdb-rhel-10464-xsave-update-9of21.patch b/gdb-rhel-10464-xsave-update-9of21.patch new file mode 100644 index 0000000..529a9fb --- /dev/null +++ b/gdb-rhel-10464-xsave-update-9of21.patch @@ -0,0 +1,168 @@ +From FEDORA_PATCHES Mon Sep 17 00:00:00 2001 +From: John Baldwin +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 + +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) + { diff --git a/gdb.spec b/gdb.spec index 8c89146..668e866 100644 --- a/gdb.spec +++ b/gdb.spec @@ -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"