@@ -47,6 +47,7 @@
#include "build-id.h"
#include "gdbsupport/pathstuff.h"
#include "gdbsupport/scoped_fd.h"
+#include "gdbsupport/x86-xstate.h"
#include "debuginfod-support.h"
#include <unordered_map>
#include <unordered_set>
@@ -109,6 +110,8 @@ class core_target final : public process_stratum_target
bool fetch_memtags (CORE_ADDR address, size_t len,
gdb::byte_vector &tags, int type) override;
+ x86_xsave_layout fetch_x86_xsave_layout () override;
+
/* A few helpers. */
/* Getter, see variable definition. */
@@ -1239,6 +1242,24 @@ core_target::fetch_memtags (CORE_ADDR address, size_t len,
return false;
}
+/* 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;
+ 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. */
@@ -1013,6 +1013,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 bool 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 bool gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch);
@@ -182,6 +182,7 @@ struct gdbarch
gdbarch_core_pid_to_str_ftype *core_pid_to_str = nullptr;
gdbarch_core_thread_name_ftype *core_thread_name = nullptr;
gdbarch_core_xfer_siginfo_ftype *core_xfer_siginfo = nullptr;
+ gdbarch_core_read_x86_xsave_layout_ftype *core_read_x86_xsave_layout = nullptr;
const char * gcore_bfd_target = 0;
int vtable_function_descriptors = 0;
int vbit_in_delta = 0;
@@ -443,6 +444,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 */
@@ -1071,6 +1073,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: core_xfer_siginfo = <%s>\n",
host_address_to_string (gdbarch->core_xfer_siginfo));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_core_read_x86_xsave_layout_p() = %d\n",
+ gdbarch_core_read_x86_xsave_layout_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: core_read_x86_xsave_layout = <%s>\n",
+ host_address_to_string (gdbarch->core_read_x86_xsave_layout));
gdb_printf (file,
"gdbarch_dump: gdbarch_gcore_bfd_target_p() = %d\n",
gdbarch_gcore_bfd_target_p (gdbarch));
@@ -3958,6 +3966,30 @@ set_gdbarch_core_xfer_siginfo (struct gdbarch *gdbarch,
gdbarch->core_xfer_siginfo = core_xfer_siginfo;
}
+bool
+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)
+ gdb_printf (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;
+}
+
bool
gdbarch_gcore_bfd_target_p (struct gdbarch *gdbarch)
{
@@ -57,6 +57,7 @@ struct syscalls_info;
struct thread_info;
struct ui_out;
struct inferior;
+struct x86_xsave_layout;
#include "regcache.h"
@@ -1709,6 +1709,17 @@ of bytes read (zero indicates EOF, a negative value indicates failure).
predicate=True,
)
+Method(
+ comment="""
+Read x86 XSAVE layout information from core file into XSAVE_LAYOUT.
+Returns true if the layout was read successfully.
+""",
+ type="bool",
+ name="core_read_x86_xsave_layout",
+ params=[("x86_xsave_layout &", "xsave_layout")],
+ predicate=True,
+)
+
Value(
comment="""
BFD target to use when generating a core file.
@@ -898,6 +898,61 @@ static int xsave_pkeys_offset[] =
(xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+/* See i387-tdep.h. */
+
+bool
+i387_set_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. */
@@ -25,6 +25,7 @@ class frame_info_ptr;
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,13 @@ 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_set_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,