From: Christina Schimpe Date: Tue, 3 Dec 2024 16:32:10 +0000 (-0800) Subject: gdb, gdbserver: Use xstate_bv for target description creation on x86. X-Git-Tag: gdb-17-branchpoint~126 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6ef3896cfe781078bf5b576c0e5a264874f2381c;p=thirdparty%2Fbinutils-gdb.git 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 Approved-By: Luis Machado --- diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 3848a8531aa..13612a0fad7 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -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; } diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h index cbf8a97fa3c..55c308502a3 100644 --- a/gdb/amd64-tdep.h +++ b/gdb/amd64-tdep.h @@ -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 diff --git a/gdb/arch/amd64-linux-tdesc.c b/gdb/arch/amd64-linux-tdesc.c index 91de75873a1..879666274e0 100644 --- a/gdb/arch/amd64-linux-tdesc.c +++ b/gdb/arch/amd64-linux-tdesc.c @@ -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; /* 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; } diff --git a/gdb/arch/amd64-linux-tdesc.h b/gdb/arch/amd64-linux-tdesc.h index 8806a132562..4c0c591f5bf 100644 --- a/gdb/arch/amd64-linux-tdesc.h +++ b/gdb/arch/amd64-linux-tdesc.h @@ -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 */ diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c index 252650b6390..e16652ac045 100644 --- a/gdb/arch/amd64.c +++ b/gdb/arch/amd64.c @@ -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 (); diff --git a/gdb/arch/amd64.h b/gdb/arch/amd64.h index 695660c55d6..60c17ebc42d 100644 --- a/gdb/arch/amd64.h +++ b/gdb/arch/amd64.h @@ -21,7 +21,13 @@ #include "gdbsupport/tdesc.h" #include -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 */ diff --git a/gdb/arch/i386-linux-tdesc.c b/gdb/arch/i386-linux-tdesc.c index 51513176464..bd736eb6881 100644 --- a/gdb/arch/i386-linux-tdesc.c +++ b/gdb/arch/i386-linux-tdesc.c @@ -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 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; } diff --git a/gdb/arch/i386-linux-tdesc.h b/gdb/arch/i386-linux-tdesc.h index 2c3c1740d81..1cf2931a4d3 100644 --- a/gdb/arch/i386-linux-tdesc.h +++ b/gdb/arch/i386-linux-tdesc.h @@ -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 */ diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c index 835df53c75d..424bd27b4ec 100644 --- a/gdb/arch/i386.c +++ b/gdb/arch/i386.c @@ -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 (); diff --git a/gdb/arch/i386.h b/gdb/arch/i386.h index 1fc41014624..91a581f83ee 100644 --- a/gdb/arch/i386.h +++ b/gdb/arch/i386.h @@ -21,7 +21,12 @@ #include "gdbsupport/tdesc.h" #include -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 */ diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c index f65920cb95b..3863d1f30ed 100644 --- a/gdb/arch/x86-linux-tdesc-features.c +++ b/gdb/arch/x86-linux-tdesc-features.c @@ -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. - - 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. */ + 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 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 */ diff --git a/gdb/arch/x86-linux-tdesc-features.h b/gdb/arch/x86-linux-tdesc-features.h index 89fe7cecc68..bc727277aba 100644 --- a/gdb/arch/x86-linux-tdesc-features.h +++ b/gdb/arch/x86-linux-tdesc-features.h @@ -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 */ diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 21a5a28986f..4715ade61f1 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -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; } diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h index e4895b1d932..65095939d0b 100644 --- a/gdb/i386-tdep.h +++ b/gdb/i386-tdep.h @@ -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. */ diff --git a/gdb/nat/x86-linux-tdesc.c b/gdb/nat/x86-linux-tdesc.c index 80e4337a270..e9cf2527c5f 100644 --- a/gdb/nat/x86-linux-tdesc.c +++ b/gdb/nat/x86-linux-tdesc.c @@ -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 */ diff --git a/gdb/nat/x86-linux-tdesc.h b/gdb/nat/x86-linux-tdesc.h index 38c71f10df2..19aa84f6b3f 100644 --- a/gdb/nat/x86-linux-tdesc.h +++ b/gdb/nat/x86-linux-tdesc.h @@ -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 */ diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index 81db5d86a5e..1b7dd8506dd 100644 --- a/gdb/x86-linux-nat.c +++ b/gdb/x86-linux-nat.c @@ -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); } diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc index 4be0083a6fb..90824bdaee5 100644 --- a/gdbserver/i387-fp.cc +++ b/gdbserver/i387-fp.cc @@ -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 i387_get_xsave_storage () { - return { &x86_xcr0, &xsave_layout }; + return { &x86_xstate_bv, &xsave_layout }; } diff --git a/gdbserver/linux-amd64-ipa.cc b/gdbserver/linux-amd64-ipa.cc index af4eb03b9b8..ec663675fe9 100644 --- a/gdbserver/linux-amd64-ipa.cc +++ b/gdbserver/linux-amd64-ipa.cc @@ -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 } diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc index 17af6eb3610..4f8398df2a1 100644 --- a/gdbserver/linux-i386-ipa.cc +++ b/gdbserver/linux-i386-ipa.cc @@ -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)); } diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc index 24920e71a53..57661344921 100644 --- a/gdbserver/linux-x86-low.cc +++ b/gdbserver/linux-x86-low.cc @@ -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 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. */ diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h index 5d563ff4622..9bb373c3100 100644 --- a/gdbsupport/x86-xstate.h +++ b/gdbsupport/x86-xstate.h @@ -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