gdb, gdbserver: Use xstate_bv for target description creation on x86.

The XSAVE function set is organized in state components, which are a set of
registers or parts of registers.  So-called XSAVE-supported features are
organized using state-component bitmaps, each bit corresponding to a
single state component.

The Intel Software Developer's Manual uses the term xstate_bv for a
state-component bitmap, which is defined as XCR0 | IA32_XSS.  The control
register XCR0 only contains a state-component bitmap that specifies user state
components, while IA32_XSS contains a state-component bitmap that specifies
supervisor state components.

Until now, XCR0 is used as input for target description creation in GDB.
However, a following patch will add userspace support for the CET shadow
stack feature by Intel.  The CET state is configured in IA32_XSS and consists
of 2 state components:
- State component 11 used for the 2 MSRs controlling user-mode
  functionality for CET (CET_U state)
- State component 12 used for the 3 MSRs containing shadow-stack pointers
  for privilege levels 0-2 (CET_S state).

Reading the CET shadow stack pointer register on linux requires a separate
ptrace call using NT_X86_SHSTK.  To pass the CET shadow stack enablement
state we would like to pass the xstate_bv value instead of xcr0 for target
description creation.  To prepare for that, we rename the xcr0 mask
values for target description creation to xstate_bv.  However, this
patch doesn't add any functional changes in GDB.

Future states specified in IA32_XSS such as CET will create a combined
xstate_bv_mask including xcr0 register value and its corresponding bit in
the state component bitmap.  This combined mask will then be used to create
the target descriptions.

Reviewed-By: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
Approved-By: Luis Machado <luis.machado@arm.com>
This commit is contained in:
Christina Schimpe
2024-12-03 08:32:10 -08:00
parent 92cc4fb226
commit 6ef3896cfe
22 changed files with 196 additions and 155 deletions

View File

@@ -21,7 +21,7 @@
#include "nat/x86-xstate.h"
/* Default to SSE. */
static uint64_t x86_xcr0 = X86_XSTATE_SSE_MASK;
static uint64_t x86_xstate_bv = X86_XSTATE_SSE_MASK;
static const int num_avx512_k_registers = 8;
static const int num_pkeys_registers = 1;
@@ -265,7 +265,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
clear_bv = (~fp->xstate_bv) & x86_xcr0;
clear_bv = (~fp->xstate_bv) & x86_xstate_bv;
/* Clear part in x87 and vector registers if its bit in xstat_bv is
zero. */
@@ -315,7 +315,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any x87 registers are changed. */
if ((x86_xcr0 & X86_XSTATE_X87))
if ((x86_xstate_bv & X86_XSTATE_X87))
{
int st0_regnum = find_regno (regcache->tdesc, "st0");
@@ -332,7 +332,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any SSE registers are changed. */
if ((x86_xcr0 & X86_XSTATE_SSE))
if ((x86_xstate_bv & X86_XSTATE_SSE))
{
int xmm0_regnum = find_regno (regcache->tdesc, "xmm0");
@@ -349,7 +349,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any AVX registers are changed. */
if ((x86_xcr0 & X86_XSTATE_AVX))
if ((x86_xstate_bv & X86_XSTATE_AVX))
{
int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h");
@@ -366,7 +366,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any K registers are changed. */
if ((x86_xcr0 & X86_XSTATE_K))
if ((x86_xstate_bv & X86_XSTATE_K))
{
int k0_regnum = find_regno (regcache->tdesc, "k0");
@@ -383,7 +383,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any of ZMM0H-ZMM15H registers are changed. */
if ((x86_xcr0 & X86_XSTATE_ZMM_H))
if ((x86_xstate_bv & X86_XSTATE_ZMM_H))
{
int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h");
@@ -400,7 +400,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any of ZMM16-ZMM31 registers are changed. */
if ((x86_xcr0 & X86_XSTATE_ZMM) && num_zmm_high_registers != 0)
if ((x86_xstate_bv & X86_XSTATE_ZMM) && num_zmm_high_registers != 0)
{
int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
@@ -437,7 +437,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
/* Check if any PKEYS registers are changed. */
if ((x86_xcr0 & X86_XSTATE_PKRU))
if ((x86_xstate_bv & X86_XSTATE_PKRU))
{
int pkru_regnum = find_regno (regcache->tdesc, "pkru");
@@ -453,7 +453,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_SSE) || (x86_xcr0 & X86_XSTATE_AVX))
if ((x86_xstate_bv & X86_XSTATE_SSE) || (x86_xstate_bv & X86_XSTATE_AVX))
{
collect_register_by_name (regcache, "mxcsr", raw);
if (memcmp (raw, &fp->mxcsr, 4) != 0)
@@ -465,7 +465,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
}
}
if (x86_xcr0 & X86_XSTATE_X87)
if (x86_xstate_bv & X86_XSTATE_X87)
{
collect_register_by_name (regcache, "fioff", raw);
if (memcmp (raw, &fp->fioff, 4) != 0)
@@ -658,10 +658,10 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
/* The supported bits in `xstat_bv' are 8 bytes. Clear part in
vector registers if its bit in xstat_bv is zero. */
clear_bv = (~fp->xstate_bv) & x86_xcr0;
clear_bv = (~fp->xstate_bv) & x86_xstate_bv;
/* Check if any x87 registers are changed. */
if ((x86_xcr0 & X86_XSTATE_X87) != 0)
if ((x86_xstate_bv & X86_XSTATE_X87) != 0)
{
int st0_regnum = find_regno (regcache->tdesc, "st0");
@@ -678,7 +678,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_SSE) != 0)
if ((x86_xstate_bv & X86_XSTATE_SSE) != 0)
{
int xmm0_regnum = find_regno (regcache->tdesc, "xmm0");
@@ -695,7 +695,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_AVX) != 0)
if ((x86_xstate_bv & X86_XSTATE_AVX) != 0)
{
int ymm0h_regnum = find_regno (regcache->tdesc, "ymm0h");
@@ -712,7 +712,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_K) != 0)
if ((x86_xstate_bv & X86_XSTATE_K) != 0)
{
int k0_regnum = find_regno (regcache->tdesc, "k0");
@@ -729,7 +729,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_ZMM_H) != 0)
if ((x86_xstate_bv & X86_XSTATE_ZMM_H) != 0)
{
int zmm0h_regnum = find_regno (regcache->tdesc, "zmm0h");
@@ -746,7 +746,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0)
if ((x86_xstate_bv & X86_XSTATE_ZMM) != 0 && num_zmm_high_registers != 0)
{
int zmm16h_regnum = find_regno (regcache->tdesc, "zmm16h");
int ymm16h_regnum = find_regno (regcache->tdesc, "ymm16h");
@@ -773,7 +773,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
}
}
if ((x86_xcr0 & X86_XSTATE_PKRU) != 0)
if ((x86_xstate_bv & X86_XSTATE_PKRU) != 0)
{
int pkru_regnum = find_regno (regcache->tdesc, "pkru");
@@ -858,5 +858,5 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
std::pair<uint64_t *, x86_xsave_layout *>
i387_get_xsave_storage ()
{
return { &x86_xcr0, &xsave_layout };
return { &x86_xstate_bv, &xsave_layout };
}

View File

@@ -82,7 +82,7 @@ get_raw_reg (const unsigned char *raw_regs, int regnum)
const struct target_desc *
get_ipa_tdesc (int idx)
{
uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx);
uint64_t xstate_bv = x86_linux_tdesc_idx_to_xstate_bv (idx);
#if defined __ILP32__
bool is_x32 = true;
@@ -90,7 +90,7 @@ get_ipa_tdesc (int idx)
bool is_x32 = false;
#endif
return amd64_linux_read_description (xcr0, is_x32);
return amd64_linux_read_description (xstate_bv, is_x32);
}
/* Allocate buffer for the jump pads. The branch instruction has a
@@ -159,9 +159,11 @@ initialize_low_tracepoint (void)
{
#if defined __ILP32__
for (int i = 0; i < x86_linux_x32_tdesc_count (); i++)
amd64_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i), true);
amd64_linux_read_description
(x86_linux_tdesc_idx_to_xstate_bv (i), true);
#else
for (int i = 0; i < x86_linux_amd64_tdesc_count (); i++)
amd64_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i), false);
amd64_linux_read_description
(x86_linux_tdesc_idx_to_xstate_bv (i), false);
#endif
}

View File

@@ -174,9 +174,9 @@ initialize_fast_tracepoint_trampoline_buffer (void)
const struct target_desc *
get_ipa_tdesc (int idx)
{
uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx);
uint64_t xstate_bv = x86_linux_tdesc_idx_to_xstate_bv (idx);
return i386_linux_read_description (xcr0);
return i386_linux_read_description (xstate_bv);
}
/* Allocate buffer for the jump pads. On i386, we can reach an arbitrary
@@ -199,5 +199,5 @@ initialize_low_tracepoint (void)
{
initialize_fast_tracepoint_trampoline_buffer ();
for (int i = 0; i < x86_linux_i386_tdesc_count (); i++)
i386_linux_read_description (x86_linux_tdesc_idx_to_xcr0 (i));
i386_linux_read_description (x86_linux_tdesc_idx_to_xstate_bv (i));
}

View File

@@ -873,7 +873,7 @@ x86_linux_read_description ()
bool have_ptrace_getregset_was_unknown
= have_ptrace_getregset == TRIBOOL_UNKNOWN;
/* Get pointers to where we should store the xcr0 and xsave_layout
/* Get pointers to where we should store the xstate_bv and xsave_layout
values. These will be filled in by x86_linux_tdesc_for_tid the first
time that the function is called. Subsequent calls will not modify
the stored values. */
@@ -2892,17 +2892,16 @@ x86_target::get_ipa_tdesc_idx ()
|| tdesc == tdesc_amd64_linux_no_xml.get ()
#endif /* __x86_64__ */
);
return x86_linux_xcr0_to_tdesc_idx (X86_XSTATE_SSE_MASK);
return x86_linux_xstate_bv_to_tdesc_idx (X86_XSTATE_SSE_MASK);
}
/* The xcr0 value and xsave layout value are cached when the target
/* The xstate_bv value and xsave layout value are cached when the target
description is read. Grab their cache location, and use the cached
value to calculate a tdesc index. */
std::pair<uint64_t *, x86_xsave_layout *> storage
= i387_get_xsave_storage ();
uint64_t xcr0 = *storage.first;
return x86_linux_xcr0_to_tdesc_idx (xcr0);
return x86_linux_xstate_bv_to_tdesc_idx (*storage.first);
}
/* The linux target ops object. */