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

@@ -3568,23 +3568,23 @@ amd64_x32_none_init_abi (gdbarch_info info, gdbarch *arch)
amd64_target_description (X86_XSTATE_SSE_MASK, true));
}
/* Return the target description for a specified XSAVE feature mask. */
/* See amd64-tdep.h. */
const struct target_desc *
amd64_target_description (uint64_t xcr0, bool segments)
amd64_target_description (uint64_t xstate_bv, bool segments)
{
static target_desc *amd64_tdescs \
[2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {};
target_desc **tdesc;
tdesc = &amd64_tdescs[(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
[(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
[(xcr0 & X86_XSTATE_PKRU) ? 1 : 0]
tdesc = &amd64_tdescs[(xstate_bv & X86_XSTATE_AVX) ? 1 : 0]
[(xstate_bv & X86_XSTATE_AVX512) ? 1 : 0]
[(xstate_bv & X86_XSTATE_PKRU) ? 1 : 0]
[segments ? 1 : 0];
if (*tdesc == NULL)
*tdesc = amd64_create_target_description (xcr0, false, false,
segments);
*tdesc = amd64_create_target_description (xstate_bv, false,
false, segments);
return *tdesc;
}

View File

@@ -108,8 +108,12 @@ extern void amd64_init_abi (struct gdbarch_info info,
extern void amd64_x32_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch,
const target_desc *default_tdesc);
extern const struct target_desc *amd64_target_description (uint64_t xcr0,
bool segments);
/* Return the target description for the specified xsave features as
defined in XSTATE_BV and SEGMENTS. */
extern const struct target_desc *amd64_target_description
(uint64_t xstate_bv, bool segments);
/* Fill register REGNUM in REGCACHE with the appropriate
floating-point or SSE register value from *FXSAVE. If REGNUM is

View File

@@ -26,34 +26,35 @@
/* See arch/amd64-linux-tdesc.h. */
const struct target_desc *
amd64_linux_read_description (uint64_t xcr0, bool is_x32)
amd64_linux_read_description (uint64_t xstate_bv, bool is_x32)
{
/* The type used for the amd64 and x32 target description caches. */
using tdesc_cache_type = std::unordered_map<uint64_t, const target_desc_up>;
/* Caches for the previously seen amd64 and x32 target descriptions,
indexed by the xcr0 value that created the target description. These
need to be static within this function to ensure they are initialised
before first use. */
indexed by the xstate_bv value that created the target
description. These need to be static within this function to ensure
they are initialised before first use. */
static tdesc_cache_type amd64_tdesc_cache, x32_tdesc_cache;
tdesc_cache_type &tdesc_cache = is_x32 ? x32_tdesc_cache : amd64_tdesc_cache;
/* Only some bits are checked when creating a tdesc, but the XCR0 value
contains other feature bits that are not relevant for tdesc creation.
When indexing into the TDESC_CACHE we need to use a consistent xcr0
value otherwise we might fail to find an existing tdesc which has the
same set of relevant bits set. */
xcr0 &= is_x32
? x86_linux_x32_xcr0_feature_mask ()
: x86_linux_amd64_xcr0_feature_mask ();
/* Only some bits are checked when creating a tdesc, but the
xstate_bv value contains other feature bits that are not
relevant for tdesc creation.
When indexing into the TDESC_CACHE we need to use a consistent
xstate_bv value otherwise we might fail to find an existing
tdesc which has the same set of relevant bits set. */
xstate_bv &= is_x32
? x86_linux_x32_xstate_bv_feature_mask ()
: x86_linux_amd64_xstate_bv_feature_mask ();
const auto it = tdesc_cache.find (xcr0);
const auto it = tdesc_cache.find (xstate_bv);
if (it != tdesc_cache.end ())
return it->second.get ();
/* Create the previously unseen target description. */
target_desc_up tdesc (amd64_create_target_description (xcr0, is_x32,
target_desc_up tdesc (amd64_create_target_description (xstate_bv, is_x32,
true, true));
x86_linux_post_init_tdesc (tdesc.get (), true);
@@ -61,6 +62,6 @@ amd64_linux_read_description (uint64_t xcr0, bool is_x32)
target_desc_up. This is safe as the cache (and the pointers contained
within it) are not deleted until GDB exits. */
target_desc *ptr = tdesc.get ();
tdesc_cache.emplace (xcr0, std::move (tdesc));
tdesc_cache.emplace (xstate_bv, std::move (tdesc));
return ptr;
}

View File

@@ -22,9 +22,10 @@
struct target_desc;
/* Return the AMD64 target descriptions corresponding to XCR0 and IS_X32. */
/* Return the AMD64 target descriptions corresponding to XSTATE_BV and
IS_X32. */
extern const target_desc *amd64_linux_read_description (uint64_t xcr0,
bool is_x32);
extern const target_desc *amd64_linux_read_description
(uint64_t xstate_bv, bool is_x32);
#endif /* GDB_ARCH_AMD64_LINUX_TDESC_H */

View File

@@ -30,14 +30,11 @@
#include "../features/i386/x32-core.c"
/* Create amd64 target descriptions according to XCR0. If IS_X32 is
true, create the x32 ones. If IS_LINUX is true, create target
descriptions for Linux. If SEGMENTS is true, then include
the "org.gnu.gdb.i386.segments" feature registers. */
/* See arch/amd64.h. */
target_desc *
amd64_create_target_description (uint64_t xcr0, bool is_x32, bool is_linux,
bool segments)
amd64_create_target_description (uint64_t xstate_bv, bool is_x32,
bool is_linux, bool segments)
{
target_desc_up tdesc = allocate_target_description ();
@@ -62,13 +59,13 @@ amd64_create_target_description (uint64_t xcr0, bool is_x32, bool is_linux,
if (segments)
regnum = create_feature_i386_64bit_segments (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_AVX)
if (xstate_bv & X86_XSTATE_AVX)
regnum = create_feature_i386_64bit_avx (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_AVX512)
if (xstate_bv & X86_XSTATE_AVX512)
regnum = create_feature_i386_64bit_avx512 (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_PKRU)
if (xstate_bv & X86_XSTATE_PKRU)
regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
return tdesc.release ();

View File

@@ -21,7 +21,13 @@
#include "gdbsupport/tdesc.h"
#include <stdint.h>
target_desc *amd64_create_target_description (uint64_t xcr0, bool is_x32,
bool is_linux, bool segments);
/* Create amd64 target descriptions according to XSTATE_BV. If
IS_X32 is true, create the x32 ones. If IS_LINUX is true, create
target descriptions for Linux. If SEGMENTS is true, then include
the "org.gnu.gdb.i386.segments" feature registers. */
target_desc *amd64_create_target_description (uint64_t xstate_bv,
bool is_x32, bool is_linux,
bool segments);
#endif /* GDB_ARCH_AMD64_H */

View File

@@ -25,32 +25,35 @@
/* See arch/i386-linux-tdesc.h. */
const target_desc *
i386_linux_read_description (uint64_t xcr0)
i386_linux_read_description (uint64_t xstate_bv)
{
/* Cache of previously seen i386 target descriptions, indexed by the xcr0
value that created the target description. This needs to be static
within this function to ensure it is initialised before first use. */
/* Cache of previously seen i386 target descriptions, indexed by the
xstate_bv value that created the target description. This
needs to be static within this function to ensure it is initialised
before first use. */
static std::unordered_map<uint64_t, const target_desc_up> i386_tdesc_cache;
/* Only some bits are checked when creating a tdesc, but the XCR0 value
contains other feature bits that are not relevant for tdesc creation.
When indexing into the I386_TDESC_CACHE we need to use a consistent
xcr0 value otherwise we might fail to find an existing tdesc which has
the same set of relevant bits set. */
xcr0 &= x86_linux_i386_xcr0_feature_mask ();
/* Only some bits are checked when creating a tdesc, but the
XSTATE_BV value contains other feature bits that are not relevant
for tdesc creation. When indexing into the I386_TDESC_CACHE
we need to use a consistent XSTATE_BV value otherwise we might fail
to find an existing tdesc which has the same set of relevant bits
set. */
xstate_bv &= x86_linux_i386_xstate_bv_feature_mask ();
const auto it = i386_tdesc_cache.find (xcr0);
const auto it = i386_tdesc_cache.find (xstate_bv);
if (it != i386_tdesc_cache.end ())
return it->second.get ();
/* Create the previously unseen target description. */
target_desc_up tdesc (i386_create_target_description (xcr0, true, false));
target_desc_up tdesc
(i386_create_target_description (xstate_bv, true, false));
x86_linux_post_init_tdesc (tdesc.get (), false);
/* Add to the cache, and return a pointer borrowed from the
target_desc_up. This is safe as the cache (and the pointers contained
within it) are not deleted until GDB exits. */
target_desc *ptr = tdesc.get ();
i386_tdesc_cache.emplace (xcr0, std::move (tdesc));
i386_tdesc_cache.emplace (xstate_bv, std::move (tdesc));
return ptr;
}

View File

@@ -22,8 +22,9 @@
struct target_desc;
/* Return the i386 target description corresponding to XCR0. */
/* Return the i386 target description corresponding to XSTATE_BV. */
extern const struct target_desc *i386_linux_read_description (uint64_t xcr0);
extern const struct target_desc *i386_linux_read_description
(uint64_t xstate_bv);
#endif /* GDB_ARCH_I386_LINUX_TDESC_H */

View File

@@ -29,10 +29,11 @@
#include "../features/i386/32bit-segments.c"
#include "../features/i386/pkeys.c"
/* Create i386 target descriptions according to XCR0. */
/* See arch/i386.h. */
target_desc *
i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments)
i386_create_target_description (uint64_t xstate_bv, bool is_linux,
bool segments)
{
target_desc_up tdesc = allocate_target_description ();
@@ -44,10 +45,10 @@ i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments)
long regnum = 0;
if (xcr0 & X86_XSTATE_X87)
if (xstate_bv & X86_XSTATE_X87)
regnum = create_feature_i386_32bit_core (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_SSE)
if (xstate_bv & X86_XSTATE_SSE)
regnum = create_feature_i386_32bit_sse (tdesc.get (), regnum);
if (is_linux)
@@ -56,13 +57,13 @@ i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments)
if (segments)
regnum = create_feature_i386_32bit_segments (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_AVX)
if (xstate_bv & X86_XSTATE_AVX)
regnum = create_feature_i386_32bit_avx (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_AVX512)
if (xstate_bv & X86_XSTATE_AVX512)
regnum = create_feature_i386_32bit_avx512 (tdesc.get (), regnum);
if (xcr0 & X86_XSTATE_PKRU)
if (xstate_bv & X86_XSTATE_PKRU)
regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
return tdesc.release ();

View File

@@ -21,7 +21,12 @@
#include "gdbsupport/tdesc.h"
#include <stdint.h>
target_desc *i386_create_target_description (uint64_t xcr0, bool is_linux,
/* Create i386 target descriptions according to XSTATE_BV. If IS_LINUX is
true, create target descriptions for Linux. If SEGMENTS is true, then
include the "org.gnu.gdb.i386.segments" feature registers. */
target_desc *i386_create_target_description (uint64_t xstate_bv,
bool is_linux,
bool segments);
#endif /* GDB_ARCH_I386_H */

View File

@@ -28,18 +28,21 @@
We want to cache target descriptions, and this is currently done in
three separate caches, one each for i386, amd64, and x32. Additionally,
the caching we're discussing here is Linux only, and for Linux, the only
thing that has an impact on target description creation is the xcr0
value.
the caching we're discussing here is Linux only. Currently for Linux,
the only thing that has an impact on target description creation are
the supported features in xsave which are modelled by a xstate_bv
value, which has the same format than the state component bitmap.
In order to ensure the cache functions correctly we need to filter out
only those xcr0 feature bits that are relevant, we can then cache target
descriptions based on the relevant feature bits. Two xcr0 values might
be different, but have the same relevant feature bits. In this case we
would expect the two xcr0 values to map to the same cache entry. */
In order to ensure the cache functions correctly we need to filter only
those xstate_bv feature bits that are relevant, we can then cache
target descriptions based on the relevant feature bits. Two xstate_bv
values might be different, but have the same relevant feature bits. In
this case we would expect the two xstate_bv values to map to the same
cache entry. */
struct x86_xstate_feature {
/* The xstate feature mask. This is a mask against an xcr0 value. */
/* The xstate feature mask. This is a mask against the state component
bitmap. */
uint64_t feature;
/* Is this feature checked when creating an i386 target description. */
@@ -56,9 +59,9 @@ struct x86_xstate_feature {
checked when building a target description for i386, amd64, or x32.
If in the future, due to simplifications or refactoring, this table ever
ends up with 'true' for every xcr0 feature on every target type, then this
is an indication that this table should probably be removed, and that the
rest of the code in this file can be simplified. */
ends up with 'true' for every xsave feature on every target type, then
this is an indication that this table should probably be removed, and
that the rest of the code in this file can be simplified. */
static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = {
/* Feature, i386, amd64, x32. */
@@ -73,7 +76,7 @@ static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = {
that are checked for when building an i386 target description. */
static constexpr uint64_t
x86_linux_i386_xcr0_feature_mask_1 ()
x86_linux_i386_xstate_bv_feature_mask_1 ()
{
uint64_t mask = 0;
@@ -88,7 +91,7 @@ x86_linux_i386_xcr0_feature_mask_1 ()
that are checked for when building an amd64 target description. */
static constexpr uint64_t
x86_linux_amd64_xcr0_feature_mask_1 ()
x86_linux_amd64_xstate_bv_feature_mask_1 ()
{
uint64_t mask = 0;
@@ -103,7 +106,7 @@ x86_linux_amd64_xcr0_feature_mask_1 ()
that are checked for when building an x32 target description. */
static constexpr uint64_t
x86_linux_x32_xcr0_feature_mask_1 ()
x86_linux_x32_xstate_bv_feature_mask_1 ()
{
uint64_t mask = 0;
@@ -117,25 +120,25 @@ x86_linux_x32_xcr0_feature_mask_1 ()
/* See arch/x86-linux-tdesc-features.h. */
uint64_t
x86_linux_i386_xcr0_feature_mask ()
x86_linux_i386_xstate_bv_feature_mask ()
{
return x86_linux_i386_xcr0_feature_mask_1 ();
return x86_linux_i386_xstate_bv_feature_mask_1 ();
}
/* See arch/x86-linux-tdesc-features.h. */
uint64_t
x86_linux_amd64_xcr0_feature_mask ()
x86_linux_amd64_xstate_bv_feature_mask ()
{
return x86_linux_amd64_xcr0_feature_mask_1 ();
return x86_linux_amd64_xstate_bv_feature_mask_1 ();
}
/* See arch/x86-linux-tdesc-features.h. */
uint64_t
x86_linux_x32_xcr0_feature_mask ()
x86_linux_x32_xstate_bv_feature_mask ()
{
return x86_linux_x32_xcr0_feature_mask_1 ();
return x86_linux_x32_xstate_bv_feature_mask_1 ();
}
#ifdef GDBSERVER
@@ -143,7 +146,7 @@ x86_linux_x32_xcr0_feature_mask ()
/* See arch/x86-linux-tdesc-features.h. */
int
x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0)
x86_linux_xstate_bv_to_tdesc_idx (uint64_t xstate_bv)
{
/* The following table shows which features are checked for when creating
the target descriptions (see nat/x86-linux-tdesc.c), the feature order
@@ -160,7 +163,7 @@ x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0)
for (int i = 0; i < ARRAY_SIZE (x86_linux_all_xstate_features); ++i)
{
if ((xcr0 & x86_linux_all_xstate_features[i].feature)
if ((xstate_bv & x86_linux_all_xstate_features[i].feature)
== x86_linux_all_xstate_features[i].feature)
idx |= (1 << i);
}
@@ -250,17 +253,17 @@ x86_linux_i386_tdesc_count ()
/* See arch/x86-linux-tdesc-features.h. */
uint64_t
x86_linux_tdesc_idx_to_xcr0 (int idx)
x86_linux_tdesc_idx_to_xstate_bv (int idx)
{
uint64_t xcr0 = 0;
uint64_t xstate_bv = 0;
for (int i = 0; i < ARRAY_SIZE (x86_linux_all_xstate_features); ++i)
{
if ((idx & (1 << i)) != 0)
xcr0 |= x86_linux_all_xstate_features[i].feature;
xstate_bv |= x86_linux_all_xstate_features[i].feature;
}
return xcr0;
return xstate_bv;
}
#endif /* IN_PROCESS_AGENT */

View File

@@ -27,17 +27,20 @@
the set of features which are checked for when creating the target
description for each of amd64, x32, and i386. */
extern uint64_t x86_linux_amd64_xcr0_feature_mask ();
extern uint64_t x86_linux_x32_xcr0_feature_mask ();
extern uint64_t x86_linux_i386_xcr0_feature_mask ();
extern uint64_t x86_linux_amd64_xstate_bv_feature_mask ();
extern uint64_t x86_linux_x32_xstate_bv_feature_mask ();
extern uint64_t x86_linux_i386_xstate_bv_feature_mask ();
#ifdef GDBSERVER
/* Convert an xcr0 value into an integer. The integer will be passed from
gdbserver to the in-process-agent where it will then be passed through
x86_linux_tdesc_idx_to_xcr0 to get back the original xcr0 value. */
/* Convert an XSTATE_BV value into an integer. XSTATE_BV has the same
format than the state component bitmap and does include user and
supervisor state components. The integer will be passed from gdbserver
to the in-process-agent where it will then be passed through
x86_linux_tdesc_idx_to_xstate_bv to get back the original value. */
extern int x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0);
extern int x86_linux_xstate_bv_to_tdesc_idx (uint64_t xstate_bv);
#endif /* GDBSERVER */
@@ -51,11 +54,13 @@ extern int x86_linux_amd64_tdesc_count ();
extern int x86_linux_x32_tdesc_count ();
extern int x86_linux_i386_tdesc_count ();
/* Convert an index number (as returned from x86_linux_xcr0_to_tdesc_idx)
into an xcr0 value which can then be used to create a target
description. */
/* Convert an index number (as returned from
x86_linux_xstate_bv_to_tdesc_idx) into an xstate_bv value which can
then be used to create a target description.
The return mask has the same format than the state component bitmap
and does include user and supervisor state components. */
extern uint64_t x86_linux_tdesc_idx_to_xcr0 (int idx);
extern uint64_t x86_linux_tdesc_idx_to_xstate_bv (int idx);
#endif /* IN_PROCESS_AGENT */

View File

@@ -9097,23 +9097,23 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Return the target description for a specified XSAVE feature mask. */
/* See i386-tdep.h. */
const struct target_desc *
i386_target_description (uint64_t xcr0, bool segments)
i386_target_description (uint64_t xstate_bv, bool segments)
{
static target_desc *i386_tdescs \
[2/*SSE*/][2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {};
target_desc **tdesc;
tdesc = &i386_tdescs[(xcr0 & X86_XSTATE_SSE) ? 1 : 0]
[(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
[(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
[(xcr0 & X86_XSTATE_PKRU) ? 1 : 0]
tdesc = &i386_tdescs[(xstate_bv & X86_XSTATE_SSE) ? 1 : 0]
[(xstate_bv & X86_XSTATE_AVX) ? 1 : 0]
[(xstate_bv & X86_XSTATE_AVX512) ? 1 : 0]
[(xstate_bv & X86_XSTATE_PKRU) ? 1 : 0]
[segments ? 1 : 0];
if (*tdesc == NULL)
*tdesc = i386_create_target_description (xcr0, false, segments);
*tdesc = i386_create_target_description (xstate_bv, false, segments);
return *tdesc;
}

View File

@@ -454,8 +454,11 @@ extern int i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg);
extern int i386_process_record (struct gdbarch *gdbarch,
struct regcache *regcache, CORE_ADDR addr);
extern const struct target_desc *i386_target_description (uint64_t xcr0,
bool segments);
/* Return the target description for the specified xsave features as
defined in XSTATE_BV and SEGMENTS. */
extern const struct target_desc *i386_target_description
(uint64_t xstate_bv, bool segments);
/* Functions and variables exported from i386-bsd-tdep.c. */

View File

@@ -43,7 +43,7 @@
/* See nat/x86-linux-tdesc.h. */
const target_desc *
x86_linux_tdesc_for_tid (int tid, uint64_t *xcr0_storage,
x86_linux_tdesc_for_tid (int tid, uint64_t *xstate_bv_storage,
x86_xsave_layout *xsave_layout_storage)
{
#ifdef __x86_64__
@@ -96,30 +96,32 @@ x86_linux_tdesc_for_tid (int tid, uint64_t *xcr0_storage,
these bits being set we generate a completely empty tdesc for
i386 which will be rejected by GDB. */
have_ptrace_getregset = TRIBOOL_FALSE;
*xcr0_storage = X86_XSTATE_SSE_MASK;
*xstate_bv_storage = X86_XSTATE_SSE_MASK;
}
else
{
have_ptrace_getregset = TRIBOOL_TRUE;
/* Get XCR0 from XSAVE extended state. */
*xcr0_storage = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET
uint64_t xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET
/ sizeof (uint64_t))];
*xsave_layout_storage
= x86_fetch_xsave_layout (*xcr0_storage, x86_xsave_length ());
= x86_fetch_xsave_layout (xcr0, x86_xsave_length ());
*xstate_bv_storage = xcr0;
}
}
/* Use cached xcr0 value. */
uint64_t xcr0_features_bits = *xcr0_storage & X86_XSTATE_ALL_MASK;
/* Use cached XSTATE_BV_STORAGE value. */
uint64_t xstate_bv_features_bits = *xstate_bv_storage & X86_XSTATE_ALL_MASK;
#ifdef __x86_64__
if (is_64bit)
return amd64_linux_read_description (xcr0_features_bits, is_x32);
return amd64_linux_read_description (xstate_bv_features_bits, is_x32);
else
#endif
return i386_linux_read_description (xcr0_features_bits);
return i386_linux_read_description (xstate_bv_features_bits);
}
#endif /* !IN_PROCESS_AGENT */

View File

@@ -27,9 +27,9 @@ struct x86_xsave_layout;
/* Return the target description for Linux thread TID.
The storage pointed to by XCR0_STORAGE and XSAVE_LAYOUT_STORAGE must
The storage pointed to by XSTATE_BV_STORAGE and XSAVE_LAYOUT_STORAGE must
exist until the program (GDB or gdbserver) terminates, this storage is
used to cache the xcr0 and xsave layout values. The values pointed to
used to cache the xstate_bv and xsave layout values. The values pointed to
by these arguments are only updated at most once, the first time this
function is called if the have_ptrace_getregset global is set to
TRIBOOL_UNKNOWN.
@@ -45,6 +45,7 @@ struct x86_xsave_layout;
returned. */
extern const target_desc *x86_linux_tdesc_for_tid
(int tid, uint64_t *xcr0_storage, x86_xsave_layout *xsave_layout_storage);
(int tid, uint64_t *xstate_bv_storage,
x86_xsave_layout *xsave_layout_storage);
#endif /* GDB_NAT_X86_LINUX_TDESC_H */

View File

@@ -97,15 +97,20 @@ const struct target_desc *
x86_linux_nat_target::read_description ()
{
/* The x86_linux_tdesc_for_tid call only reads xcr0 the first time it is
called, the xcr0 value is stored here and reused on subsequent calls. */
static uint64_t xcr0_storage;
called. The mask is stored in XSTATE_BV_STORAGE and reused on
subsequent calls. Note that GDB currently supports features for user
state components only. However, once supervisor state components are
supported in GDB, the value XSTATE_BV_STORAGE will not be configured
based on xcr0 only. */
static uint64_t xstate_bv_storage;
if (inferior_ptid == null_ptid)
return this->beneath ()->read_description ();
int tid = inferior_ptid.pid ();
return x86_linux_tdesc_for_tid (tid, &xcr0_storage, &this->m_xsave_layout);
return x86_linux_tdesc_for_tid (tid, &xstate_bv_storage,
&this->m_xsave_layout);
}

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. */

View File

@@ -83,8 +83,10 @@ constexpr bool operator!= (const x86_xsave_layout &lhs,
#define X86_XSTATE_AVX_AVX512_PKU_MASK (X86_XSTATE_AVX_MASK\
| X86_XSTATE_AVX512 | X86_XSTATE_PKRU)
#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK)
/* Supported mask of state-component bitmap xstate_bv. The SDM defines
xstate_bv as XCR0 | IA32_XSS. */
#define X86_XSTATE_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK)
#define X86_XSTATE_SSE_SIZE 576
#define X86_XSTATE_AVX_SIZE 832