[PATCH v6 09/15] gdb: Support XSAVE layouts for the current host in the Linux x86 targets.

John Baldwin
2023-07-14T15:56:55Z

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.
---
gdb/amd64-linux-nat.c | 6 ++++--
gdb/configure.nat | 3 ++-
gdb/i386-linux-nat.c | 8 ++++++--
gdb/x86-linux-nat.c | 3 +++
gdb/x86-linux-nat.h | 7 +++++++
5 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index b5b0703879b..6571be40bb5 100644
--- 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 i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_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 i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_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
index b371ad89afe..2739d14a1c4 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -254,6 +254,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"
;;
@@ -319,7 +320,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
index a524fdc9a1d..7e0572e1907 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -330,7 +330,9 @@ store_fpregs (const struct regcache *regcache, int tid, int regno)
static int
fetch_xstateregs (struct regcache *regcache, int tid)
{
- char xstateregs[X86_XSTATE_MAX_SIZE];
+ struct gdbarch *gdbarch = regcache->arch ();
+ const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ char xstateregs[tdep->xsave_layout.sizeof_xsave];
struct iovec iov;

if (have_ptrace_getregset != TRIBOOL_TRUE)
@@ -353,7 +355,9 @@ fetch_xstateregs (struct regcache *regcache, int tid)
static int
store_xstateregs (const struct regcache *regcache, int tid, int regno)
{
- char xstateregs[X86_XSTATE_MAX_SIZE];
+ struct gdbarch *gdbarch = regcache->arch ();
+ const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ char xstateregs[tdep->xsave_layout.sizeof_xsave];
struct iovec iov;

if (have_ptrace_getregset != TRIBOOL_TRUE)
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index ca4eaf5b645..cd8fd9c1dcd 100644
--- 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"
@@ -179,6 +180,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
index fcb5f08d251..a99de6c29ea 100644
--- 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"

@@ -41,6 +42,9 @@ struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
enum btrace_read_type type) override;
const struct btrace_config *btrace_conf (const struct btrace_target_info *) override;

+ x86_xsave_layout fetch_x86_xsave_layout () override
+ { return m_xsave_layout; }
+
/* These two are rewired to low_ versions. linux-nat.c queries
stopped-by-watchpoint info as soon as an lwp stops (via the low_
methods) and caches the result, to be returned via the normal
@@ -74,6 +78,9 @@ struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
protected:
/* Override the GNU/Linux inferior startup hook. */
void post_startup_inferior (ptid_t) override;
+
+private:
+ x86_xsave_layout m_xsave_layout;
};

\f
--
2.40.0