* [PATCH 00/12] Add CET shadow stack support
@ 2024-12-20 20:04 Schimpe, Christina
2024-12-20 20:04 ` [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment Schimpe, Christina
` (13 more replies)
0 siblings, 14 replies; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
Hi all,
this is a series to add amd64 shadow stack support to GDB on linux.
Shadow stack is part of the Control-flow Enforcement Technology (CET) by
Intel.
Intel's CET provides the two capabilities to defend against ROP/COP/JOP
style control-flow subversion attacks: shadow stack and indirect branch
tracking (IBT).
While there is linux kernel support for CET shadow stack in userspace,
there is no linux kernel support available for userspace IBT, yet.
This series therefore focuses on CET shadow stack only.
I am looking forward to your feedback!
Regards,
Christina
Felix Willgerodt (1):
gdb, bfd: amd64 linux coredump support with shadow stack.
Schimpe, Christina (11):
gdb, testsuite: Rename set_sanitizer_default to append_environment.
gdbserver: Add optional runtime register set type.
gdbserver: Add assert in x86_linux_read_description.
gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
gdb, gdbserver: Use xstate_bv for target description creation on x86.
gdb, gdbserver: Add support of Intel shadow stack pointer register.
gdb: Handle shadow stack pointer register unwinding for amd64 linux.
gdb, gdbarch: Enable inferior calls for shadow stack support.
gdb: Implement amd64 linux shadow stack support for inferior calls.
gdb, gdbarch: Introduce gdbarch method to get the shadow stack
pointer.
gdb: Enable displaced stepping with shadow stack on amd64 linux.
bfd/elf.c | 24 +++
gdb/amd64-linux-nat.c | 17 ++
gdb/amd64-linux-tdep.c | 197 +++++++++++++++++-
gdb/amd64-tdep.c | 32 ++-
gdb/amd64-tdep.h | 9 +-
gdb/arch-utils.c | 8 +
gdb/arch-utils.h | 5 +
gdb/arch/amd64-linux-tdesc.c | 33 +--
gdb/arch/amd64-linux-tdesc.h | 7 +-
gdb/arch/amd64.c | 25 ++-
gdb/arch/amd64.h | 10 +-
gdb/arch/i386-linux-tdesc.c | 29 +--
gdb/arch/i386-linux-tdesc.h | 5 +-
gdb/arch/i386.c | 19 +-
gdb/arch/i386.h | 8 +-
gdb/arch/x86-linux-tdesc-features.c | 56 ++---
gdb/arch/x86-linux-tdesc-features.h | 25 ++-
gdb/doc/gdb.texinfo | 42 ++++
gdb/features/Makefile | 2 +
gdb/features/i386/32bit-ssp.c | 14 ++
gdb/features/i386/32bit-ssp.xml | 11 +
gdb/features/i386/64bit-ssp.c | 14 ++
gdb/features/i386/64bit-ssp.xml | 11 +
gdb/gdbarch-gen.c | 54 +++++
gdb/gdbarch-gen.h | 20 ++
gdb/gdbarch_components.py | 26 +++
gdb/i386-tdep.c | 44 +++-
gdb/i386-tdep.h | 11 +-
gdb/infcall.c | 6 +
gdb/linux-tdep.c | 47 +++++
gdb/linux-tdep.h | 7 +
gdb/nat/x86-gcc-cpuid.h | 153 +++++++++++---
gdb/nat/x86-linux-tdesc.c | 20 +-
gdb/nat/x86-linux-tdesc.h | 7 +-
gdb/nat/x86-linux.c | 55 +++++
gdb/nat/x86-linux.h | 4 +
.../gdb.arch/amd64-shadow-stack-cmds.exp | 141 +++++++++++++
.../gdb.arch/amd64-shadow-stack-corefile.exp | 50 +++++
.../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 ++++++++
gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 35 ++++
gdb/testsuite/gdb.arch/amd64-ssp.exp | 50 +++++
.../gdb.base/inline-frame-cycle-unwind.py | 4 +
gdb/testsuite/gdb.base/libsegfault.exp | 2 +-
.../gdb.threads/attach-slow-waitpid.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 77 ++++++-
gdb/x86-linux-nat.c | 51 ++++-
gdb/x86-linux-nat.h | 11 +
gdb/x86-tdep.c | 22 ++
gdb/x86-tdep.h | 9 +
gdbserver/i387-fp.cc | 40 ++--
gdbserver/linux-amd64-ipa.cc | 10 +-
gdbserver/linux-i386-ipa.cc | 6 +-
gdbserver/linux-low.cc | 40 ++--
gdbserver/linux-low.h | 7 +-
gdbserver/linux-x86-low.cc | 44 +++-
gdbsupport/x86-xstate.h | 7 +-
56 files changed, 1537 insertions(+), 212 deletions(-)
create mode 100644 gdb/features/i386/32bit-ssp.c
create mode 100644 gdb/features/i386/32bit-ssp.xml
create mode 100644 gdb/features/i386/64bit-ssp.c
create mode 100644 gdb/features/i386/64bit-ssp.xml
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack.c
create mode 100644 gdb/testsuite/gdb.arch/amd64-ssp.exp
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-01-28 13:45 ` Guinevere Larsen
2024-12-20 20:04 ` [PATCH 02/12] gdbserver: Add optional runtime register set type Schimpe, Christina
` (12 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
The procedure set_sanitizer_default has been used for the configuration
of ASAN specific environment variables. However, it is actually a
generic function. Rename it to append_environment so that its purpose
is more clear.
---
gdb/testsuite/gdb.base/libsegfault.exp | 2 +-
gdb/testsuite/gdb.threads/attach-slow-waitpid.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 8 ++++----
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/gdb/testsuite/gdb.base/libsegfault.exp b/gdb/testsuite/gdb.base/libsegfault.exp
index 2c16fe8932a..fb62bdb8746 100644
--- a/gdb/testsuite/gdb.base/libsegfault.exp
+++ b/gdb/testsuite/gdb.base/libsegfault.exp
@@ -42,7 +42,7 @@ proc gdb_spawn_with_ld_preload {lib cmdline_opts} {
# ASan runtime does not come first in initial library list; you should
# either link runtime to your application or manually preload it with
# LD_PRELOAD.
- set_sanitizer_default ASAN_OPTIONS verify_asan_link_order 0
+ append_environment ASAN_OPTIONS verify_asan_link_order 0
gdb_spawn_with_cmdline_opts $cmdline_opts
}
diff --git a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
index 28d70daad8c..abe8d434558 100644
--- a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
+++ b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
@@ -83,7 +83,7 @@ proc gdb_spawn_with_ld_preload {lib} {
# ASan runtime does not come first in initial library list; you should
# either link runtime to your application or manually preload it with
# LD_PRELOAD.
- set_sanitizer_default ASAN_OPTIONS verify_asan_link_order 0
+ append_environment ASAN_OPTIONS verify_asan_link_order 0
gdb_start
}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 7ee2043f0f8..a86f534528c 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -76,11 +76,11 @@ proc set_sanitizer { env_var var_id val } {
# Add VAR_ID=VAL to ENV_VAR, unless ENV_VAR already contains a VAR_ID setting.
-proc set_sanitizer_default { env_var var_id val } {
+proc append_environment { env_var var_id val } {
set_sanitizer_1 $env_var $var_id $val 1
}
-set_sanitizer_default TSAN_OPTIONS suppressions \
+append_environment TSAN_OPTIONS suppressions \
$srcdir/../tsan-suppressions.txt
# When using ThreadSanitizer we may run into the case that a race is detected,
@@ -89,14 +89,14 @@ set_sanitizer_default TSAN_OPTIONS suppressions \
# Try to prevent this by setting history_size to the maximum (7) by default.
# See also the ThreadSanitizer docs (
# https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags ).
-set_sanitizer_default TSAN_OPTIONS history_size 7
+append_environment TSAN_OPTIONS history_size 7
# If GDB is built with ASAN (and because there are leaks), it will output a
# leak report when exiting as well as exit with a non-zero (failure) status.
# This can affect tests that are sensitive to what GDB prints on stderr or its
# exit status. Add `detect_leaks=0` to the ASAN_OPTIONS environment variable
# (which will affect any spawned sub-process) to avoid this.
-set_sanitizer_default ASAN_OPTIONS detect_leaks 0
+append_environment ASAN_OPTIONS detect_leaks 0
# List of procs to run in gdb_finish.
set gdb_finish_hooks [list]
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 02/12] gdbserver: Add optional runtime register set type.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
2024-12-20 20:04 ` [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-01-28 13:35 ` Guinevere Larsen
2024-12-20 20:04 ` [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description Schimpe, Christina
` (11 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
Some register sets can be activated and deactivated by the OS during the
runtime of a process. One example register is the Intel CET shadow stack
pointer. This adds a new type of register set to handle such cases. We
shouldn't deactivate these regsets and should not show a warning if we
fail to read them.
---
gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
gdbserver/linux-low.h | 7 ++++++-
2 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 50ce2b44927..355b28d9fe4 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
if (res < 0)
{
if (errno == EIO
- || (errno == EINVAL && regset->type == OPTIONAL_REGS))
+ || (errno == EINVAL
+ && (regset->type == OPTIONAL_REGS
+ || regset->type == OPTIONAL_RUNTIME_REGS)))
{
/* If we get EIO on a regset, or an EINVAL and the regset is
- optional, do not try it again for this process mode. */
+ optional, do not try it again for this process mode.
+ Even if the regset can be enabled at runtime it is safe
+ to deactivate the regset in case of EINVAL, as we know
+ the regset itself was the invalid argument of the ptrace
+ call. */
disable_regset (regsets_info, regset);
}
- else if (errno == ENODATA)
+ else if (errno == ENODATA
+ || (errno == ENODEV
+ && regset->type == OPTIONAL_RUNTIME_REGS)
+ || errno == ESRCH)
{
- /* ENODATA may be returned if the regset is currently
- not "active". This can happen in normal operation,
- so suppress the warning in this case. */
- }
- else if (errno == ESRCH)
- {
- /* At this point, ESRCH should mean the process is
- already gone, in which case we simply ignore attempts
- to read its registers. */
+ /* ENODATA or ENODEV may be returned if the regset is
+ currently not "active". For ENODEV we additionally check
+ if the register set is of type OPTIONAL_RUNTIME_REGS.
+ This can happen in normal operation, so suppress the
+ warning in this case.
+ ESRCH should mean the process is already gone at this
+ point, in which case we simply ignore attempts to read
+ its registers. */
}
else
{
@@ -5111,6 +5119,14 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
optional, do not try it again for this process mode. */
disable_regset (regsets_info, regset);
}
+ else if (errno == ENODEV
+ && regset->type == OPTIONAL_RUNTIME_REGS)
+ {
+ /* If we get ENODEV on a regset and the regset can be
+ enabled at runtime try it again for this process mode.
+ This can happen in normal operation, so suppress the
+ warning in this case. */
+ }
else if (errno == ESRCH)
{
/* At this point, ESRCH should mean the process is
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index 5be00b8c98c..da5aa26a993 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -42,7 +42,12 @@ enum regset_type {
GENERAL_REGS,
FP_REGS,
EXTENDED_REGS,
- OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */
+ OPTIONAL_REGS, /* Do not error if the regset cannot be accessed.
+ Disable the regset instead. */
+ OPTIONAL_RUNTIME_REGS, /* Some optional regsets can only be accessed
+ dependent on the execution flow. For such
+ access errors don't show a warning and don't
+ disable the regset. */
};
/* The arch's regsets array initializer must be terminated with a NULL
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
2024-12-20 20:04 ` [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment Schimpe, Christina
2024-12-20 20:04 ` [PATCH 02/12] gdbserver: Add optional runtime register set type Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-02-06 3:00 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch Schimpe, Christina
` (10 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
On x86 the PTRACE_GETREGSET request is currently only used for the xstate regset.
The size of the xstate regset is initialized to 0 such that it can be reset to
the appropriate size once we know it is supported for the current target
in x86_linux_read_description.
However, this configuration would not just affect the xstate regset but any regset
with PTRACE_GETREGSET request that is added in the future. The new regset would be
misconfigured with the xstate regset size. To avoid this we add an assert for
unsupported regsets and check explicitly for the note type of the register set.
---
gdbserver/linux-x86-low.cc | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index 6c2688d3678..b023b34a0a4 100644
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -894,7 +894,12 @@ x86_linux_read_description ()
regset++)
{
if (regset->get_request == PTRACE_GETREGSET)
- regset->size = xsave_len;
+ {
+ if (regset->nt_type == NT_X86_XSTATE)
+ regset->size = xsave_len;
+ else
+ gdb_assert_not_reached ("invalid regset type.");
+ }
else if (regset->type != GENERAL_REGS)
regset->size = 0;
}
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (2 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-02-06 3:03 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86 Schimpe, Christina
` (9 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
This is required for a later commit which requires "bit_SHSTK".
---
gdb/nat/x86-gcc-cpuid.h | 153 ++++++++++++++++++++++++++++++++--------
1 file changed, 122 insertions(+), 31 deletions(-)
diff --git a/gdb/nat/x86-gcc-cpuid.h b/gdb/nat/x86-gcc-cpuid.h
index b0f2d239af3..a571eb8a734 100644
--- a/gdb/nat/x86-gcc-cpuid.h
+++ b/gdb/nat/x86-gcc-cpuid.h
@@ -1,5 +1,5 @@
/*
- * Helper cpuid.h file copied from gcc-6.0.0. Code in gdb should not
+ * Helper cpuid.h file copied from gcc-14-2-0. Code in gdb should not
* include this directly, but pull in x86-cpuid.h and use that func.
*/
@@ -55,7 +55,7 @@
#define bit_SSE (1 << 25)
#define bit_SSE2 (1 << 26)
-/* Extended Features */
+/* Extended Features (%eax == 0x80000001) */
/* %ecx */
#define bit_LAHF_LM (1 << 0)
#define bit_ABM (1 << 5)
@@ -68,29 +68,28 @@
#define bit_MWAITX (1 << 29)
/* %edx */
-#define bit_AVX5124VNNIW (1 << 2)
-#define bit_AVX5124FMAPS (1 << 3)
#define bit_MMXEXT (1 << 22)
#define bit_LM (1 << 29)
#define bit_3DNOWP (1 << 30)
-#define bit_3DNOW (1 << 31)
+#define bit_3DNOW (1u << 31)
-/* %ebx. */
+/* %ebx */
#define bit_CLZERO (1 << 0)
+#define bit_WBNOINVD (1 << 9)
-/* Extended Features (%eax == 7) */
+/* Extended Features Leaf (%eax == 7, %ecx == 0) */
/* %ebx */
#define bit_FSGSBASE (1 << 0)
-#define bit_BMI (1 << 3)
-#define bit_HLE (1 << 4)
+#define bit_SGX (1 << 2)
+#define bit_BMI (1 << 3)
+#define bit_HLE (1 << 4)
#define bit_AVX2 (1 << 5)
#define bit_BMI2 (1 << 8)
-#define bit_RTM (1 << 11)
-#define bit_MPX (1 << 14)
+#define bit_RTM (1 << 11)
#define bit_AVX512F (1 << 16)
#define bit_AVX512DQ (1 << 17)
#define bit_RDSEED (1 << 18)
-#define bit_ADX (1 << 19)
+#define bit_ADX (1 << 19)
#define bit_AVX512IFMA (1 << 21)
#define bit_CLFLUSHOPT (1 << 23)
#define bit_CLWB (1 << 24)
@@ -99,23 +98,85 @@
#define bit_AVX512CD (1 << 28)
#define bit_SHA (1 << 29)
#define bit_AVX512BW (1 << 30)
-#define bit_AVX512VL (1 << 31)
+#define bit_AVX512VL (1u << 31)
/* %ecx */
-#define bit_PREFETCHWT1 (1 << 0)
+#define bit_PREFETCHWT1 (1 << 0)
#define bit_AVX512VBMI (1 << 1)
-#define bit_PKU (1 << 3)
+#define bit_PKU (1 << 3)
#define bit_OSPKE (1 << 4)
+#define bit_WAITPKG (1 << 5)
+#define bit_AVX512VBMI2 (1 << 6)
+#define bit_SHSTK (1 << 7)
+#define bit_GFNI (1 << 8)
+#define bit_VAES (1 << 9)
+#define bit_VPCLMULQDQ (1 << 10)
+#define bit_AVX512VNNI (1 << 11)
+#define bit_AVX512BITALG (1 << 12)
+#define bit_AVX512VPOPCNTDQ (1 << 14)
+#define bit_RDPID (1 << 22)
+#define bit_KL (1 << 23)
+#define bit_CLDEMOTE (1 << 25)
+#define bit_MOVDIRI (1 << 27)
+#define bit_MOVDIR64B (1 << 28)
+#define bit_ENQCMD (1 << 29)
-/* XFEATURE_ENABLED_MASK register bits (%eax == 13, %ecx == 0) */
-#define bit_BNDREGS (1 << 3)
-#define bit_BNDCSR (1 << 4)
+/* %edx */
+#define bit_AVX5124VNNIW (1 << 2)
+#define bit_AVX5124FMAPS (1 << 3)
+#define bit_UINTR (1 << 5)
+#define bit_AVX512VP2INTERSECT (1 << 8)
+#define bit_SERIALIZE (1 << 14)
+#define bit_TSXLDTRK (1 << 16)
+#define bit_PCONFIG (1 << 18)
+#define bit_IBT (1 << 20)
+#define bit_AMX_BF16 (1 << 22)
+#define bit_AVX512FP16 (1 << 23)
+#define bit_AMX_TILE (1 << 24)
+#define bit_AMX_INT8 (1 << 25)
+
+/* Extended Features Sub-leaf (%eax == 7, %ecx == 1) */
+/* %eax */
+#define bit_SHA512 (1 << 0)
+#define bit_SM3 (1 << 1)
+#define bit_SM4 (1 << 2)
+#define bit_RAOINT (1 << 3)
+#define bit_AVXVNNI (1 << 4)
+#define bit_AVX512BF16 (1 << 5)
+#define bit_CMPCCXADD (1 << 7)
+#define bit_AMX_COMPLEX (1 << 8)
+#define bit_AMX_FP16 (1 << 21)
+#define bit_HRESET (1 << 22)
+#define bit_AVXIFMA (1 << 23)
-/* Extended State Enumeration Sub-leaf (%eax == 13, %ecx == 1) */
+/* %edx */
+#define bit_AVXVNNIINT8 (1 << 4)
+#define bit_AVXNECONVERT (1 << 5)
+#define bit_AVXVNNIINT16 (1 << 10)
+#define bit_PREFETCHI (1 << 14)
+#define bit_USER_MSR (1 << 15)
+#define bit_AVX10 (1 << 19)
+#define bit_APX_F (1 << 21)
+
+/* Extended State Enumeration Sub-leaf (%eax == 0xd, %ecx == 1) */
#define bit_XSAVEOPT (1 << 0)
#define bit_XSAVEC (1 << 1)
#define bit_XSAVES (1 << 3)
+/* PT sub leaf (%eax == 0x14, %ecx == 0) */
+/* %ebx */
+#define bit_PTWRITE (1 << 4)
+
+/* Keylocker leaf (%eax == 0x19) */
+/* %ebx */
+#define bit_AESKLE ( 1<<0 )
+#define bit_WIDEKL ( 1<<2 )
+
+/* AVX10 sub leaf (%eax == 0x24) */
+/* %ebx */
+#define bit_AVX10_256 (1 << 17)
+#define bit_AVX10_512 (1 << 18)
+
/* Signatures for different CPU implementations as returned in uses
of cpuid with level 0. */
#define signature_AMD_ebx 0x68747541
@@ -170,19 +231,40 @@
#define signature_VORTEX_ecx 0x436f5320
#define signature_VORTEX_edx 0x36387865
-#define __cpuid(level, a, b, c, d) \
- __asm__ ("cpuid\n\t" \
- : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
- : "0" (level))
+#define signature_SHANGHAI_ebx 0x68532020
+#define signature_SHANGHAI_ecx 0x20206961
+#define signature_SHANGHAI_edx 0x68676e61
-#define __cpuid_count(level, count, a, b, c, d) \
- __asm__ ("cpuid\n\t" \
- : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
- : "0" (level), "2" (count))
+#ifndef __x86_64__
+/* At least one cpu (Winchip 2) does not set %ebx and %ecx
+ for cpuid leaf 1. Forcibly zero the two registers before
+ calling cpuid as a precaution. */
+#define __cpuid(level, a, b, c, d) \
+ do { \
+ if (__builtin_constant_p (level) && (level) != 1) \
+ __asm__ __volatile__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level)); \
+ else \
+ __asm__ __volatile__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "1" (0), "2" (0)); \
+ } while (0)
+#else
+#define __cpuid(level, a, b, c, d) \
+ __asm__ __volatile__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+#endif
+
+#define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ __volatile__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
/* Return highest supported input value for cpuid instruction. ext can
- be either 0x0 or 0x8000000 to return highest supported value for
+ be either 0x0 or 0x80000000 to return highest supported value for
basic or extended cpuid information. Function returns 0 if cpuid
is not supported or whatever cpuid returns in eax register. If sig
pointer is non-null, then first four bytes of the signature
@@ -225,7 +307,7 @@ __get_cpuid_max (unsigned int __ext, unsigned int *__sig)
: "i" (0x00200000));
#endif
- if (!((__eax ^ __ebx) & 0x00200000))
+ if (__builtin_expect (!((__eax ^ __ebx) & 0x00200000), 0))
return 0;
#endif
@@ -249,8 +331,9 @@ __get_cpuid (unsigned int __leaf,
unsigned int *__ecx, unsigned int *__edx)
{
unsigned int __ext = __leaf & 0x80000000;
+ unsigned int __maxlevel = __get_cpuid_max (__ext, 0);
- if (__get_cpuid_max (__ext, 0) < __leaf)
+ if (__maxlevel == 0 || __maxlevel < __leaf)
return 0;
__cpuid (__leaf, *__eax, *__ebx, *__ecx, *__edx);
@@ -265,12 +348,20 @@ __get_cpuid_count (unsigned int __leaf, unsigned int __subleaf,
unsigned int *__ecx, unsigned int *__edx)
{
unsigned int __ext = __leaf & 0x80000000;
+ unsigned int __maxlevel = __get_cpuid_max (__ext, 0);
- if (__get_cpuid_max (__ext, 0) < __leaf)
+ if (__builtin_expect (__maxlevel == 0, 0) || __maxlevel < __leaf)
return 0;
__cpuid_count (__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx);
return 1;
}
+static __inline void
+__cpuidex (int __cpuid_info[4], int __leaf, int __subleaf)
+{
+ __cpuid_count (__leaf, __subleaf, __cpuid_info[0], __cpuid_info[1],
+ __cpuid_info[2], __cpuid_info[3]);
+}
+
#endif /* GDB_NAT_X86_GCC_CPUID_H */
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (3 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-01-30 14:51 ` Guinevere Larsen
2025-02-06 3:09 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register Schimpe, Christina
` (8 subsequent siblings)
13 siblings, 2 replies; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
The XSAVE features set is organized in state components, which are a set
of or parts of registers. So-called XSAVE-supported features are
organized using state-component bitmaps, each bit corresonding to a
single state component.
The SDM 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.
---
gdb/amd64-tdep.c | 14 ++++----
gdb/amd64-tdep.h | 8 +++--
gdb/arch/amd64-linux-tdesc.c | 33 ++++++++---------
gdb/arch/amd64-linux-tdesc.h | 7 ++--
gdb/arch/amd64.c | 15 ++++----
gdb/arch/amd64.h | 10 ++++--
gdb/arch/i386-linux-tdesc.c | 29 ++++++++-------
gdb/arch/i386-linux-tdesc.h | 5 +--
gdb/arch/i386.c | 15 ++++----
gdb/arch/i386.h | 8 ++++-
gdb/arch/x86-linux-tdesc-features.c | 55 +++++++++++++++--------------
gdb/arch/x86-linux-tdesc-features.h | 25 +++++++------
gdb/i386-tdep.c | 14 ++++----
gdb/i386-tdep.h | 7 ++--
gdb/nat/x86-linux-tdesc.c | 18 +++++-----
gdb/nat/x86-linux-tdesc.h | 7 ++--
gdb/x86-linux-nat.c | 11 ++++--
gdbserver/i387-fp.cc | 40 ++++++++++-----------
gdbserver/linux-amd64-ipa.cc | 10 +++---
gdbserver/linux-i386-ipa.cc | 6 ++--
gdbserver/linux-x86-low.cc | 9 +++--
gdbsupport/x86-xstate.h | 4 ++-
22 files changed, 196 insertions(+), 154 deletions(-)
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index e03180b08af..37a2e3b03d4 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -3353,23 +3353,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_mask, 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_mask & X86_XSTATE_AVX) ? 1 : 0]
+ [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0]
+ [(xstate_bv_mask & 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_mask, false,
+ false, segments);
return *tdesc;
}
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index 7439b6e2e20..e93e3931df3 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_MASK and SEGMENTS. */
+
+extern const struct target_desc *amd64_target_description
+ (uint64_t xstate_bv_mask, 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 e9c4a99806d..17dfcfeaee8 100644
--- a/gdb/arch/amd64-linux-tdesc.c
+++ b/gdb/arch/amd64-linux-tdesc.c
@@ -26,41 +26,42 @@
/* 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_mask, 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_mask 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_mask 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_mask value otherwise we might fail to find an existing
+ tdesc which has the same set of relevant bits set. */
+ xstate_bv_mask &= 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_mask);
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,
- true, true));
+ target_desc_up tdesc (amd64_create_target_description (xstate_bv_mask,
+ is_x32, true, true));
x86_linux_post_init_tdesc (tdesc.get (), true);
/* 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 ();
- tdesc_cache.emplace (xcr0, std::move (tdesc));
+ tdesc_cache.emplace (xstate_bv_mask, std::move (tdesc));
return ptr;
}
diff --git a/gdb/arch/amd64-linux-tdesc.h b/gdb/arch/amd64-linux-tdesc.h
index f6a424862bb..27a99efbe10 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_MASK
+ 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_mask, bool is_x32);
#endif /* GDB_ARCH_AMD64_LINUX_TDESC_H */
diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c
index 5fc9947d489..72bd96aff76 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 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_mask, 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_mask & X86_XSTATE_AVX)
regnum = create_feature_i386_64bit_avx (tdesc.get (), regnum);
- if (xcr0 & X86_XSTATE_AVX512)
+ if (xstate_bv_mask & X86_XSTATE_AVX512)
regnum = create_feature_i386_64bit_avx512 (tdesc.get (), regnum);
- if (xcr0 & X86_XSTATE_PKRU)
+ if (xstate_bv_mask & 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 1c7a2bb26e9..3ce1a5557b2 100644
--- a/gdb/arch/amd64.h
+++ b/gdb/arch/amd64.h
@@ -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_MASK. 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_mask,
+ 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 9f12e59d214..bae8741b210 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_mask)
{
- /* 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_mask 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_MASK 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_MASK value otherwise we might
+ fail to find an existing tdesc which has the same set of relevant
+ bits set. */
+ xstate_bv_mask &= x86_linux_i386_xstate_bv_feature_mask ();
- const auto it = i386_tdesc_cache.find (xcr0);
+ const auto it = i386_tdesc_cache.find (xstate_bv_mask);
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_mask, 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_mask, std::move (tdesc));
return ptr;
}
diff --git a/gdb/arch/i386-linux-tdesc.h b/gdb/arch/i386-linux-tdesc.h
index 4ecd674aa96..6970202ce4d 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_MASK. */
-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_mask);
#endif /* GDB_ARCH_I386_LINUX_TDESC_H */
diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c
index 2072eae88ad..4a39028a472 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 i386.h. */
target_desc *
-i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments)
+i386_create_target_description (uint64_t xstate_bv_mask, 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_mask & X86_XSTATE_X87)
regnum = create_feature_i386_32bit_core (tdesc.get (), regnum);
- if (xcr0 & X86_XSTATE_SSE)
+ if (xstate_bv_mask & 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_mask & X86_XSTATE_AVX)
regnum = create_feature_i386_32bit_avx (tdesc.get (), regnum);
- if (xcr0 & X86_XSTATE_AVX512)
+ if (xstate_bv_mask & X86_XSTATE_AVX512)
regnum = create_feature_i386_32bit_avx512 (tdesc.get (), regnum);
- if (xcr0 & X86_XSTATE_PKRU)
+ if (xstate_bv_mask & 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 1b5cc6e1095..89f8aa49b9d 100644
--- a/gdb/arch/i386.h
+++ b/gdb/arch/i386.h
@@ -21,7 +21,13 @@
#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_MASK. 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_mask,
+ 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 f6eb112f312..3f041ece6eb 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.
+ 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_mask
+ 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. */
+ only those xstate_bv_mask feature bits that are relevant, we can then
+ cache target descriptions based on the relevant feature bits. Two
+ xstate_bv_mask values might be different, but have the same relevant
+ feature bits. In this case we would expect the two xstate_bv_mask
+ 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_mask_to_tdesc_idx (uint64_t xstate_bv_mask)
{
/* 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_mask & 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_mask (int idx)
{
- uint64_t xcr0 = 0;
+ uint64_t xstate_bv_mask = 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_mask |= x86_linux_all_xstate_features[i].feature;
}
- return xcr0;
+ return xstate_bv_mask;
}
#endif /* IN_PROCESS_AGENT */
diff --git a/gdb/arch/x86-linux-tdesc-features.h b/gdb/arch/x86-linux-tdesc-features.h
index cf8351dea8e..a9dfdbc3068 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
+/* Convert an XSTATE_BV_MASK value into an integer. XSTATE_BV_MASK 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_xcr0 to get back the original xcr0 value. */
+ x86_linux_tdesc_idx_to_xstate_bv_mask to get back the original mask. */
-extern int x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0);
+
+extern int x86_linux_xstate_bv_mask_to_tdesc_idx (uint64_t xstate_bv_mask);
#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_mask_to_tdesc_idx) into an xstate_bv_mask
+ value which can then be used to create a target description.
+ The return mask 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_mask (int idx);
#endif /* IN_PROCESS_AGENT */
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index a552a2bee8f..54aa1294917 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8899,23 +8899,23 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
\f
-/* 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_mask, 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_mask & X86_XSTATE_SSE) ? 1 : 0]
+ [(xstate_bv_mask & X86_XSTATE_AVX) ? 1 : 0]
+ [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0]
+ [(xstate_bv_mask & 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_mask, false, segments);
return *tdesc;
}
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 680eb027a04..3f990e71abf 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -450,8 +450,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_MASK and SEGMENTS. */
+extern const struct target_desc *i386_target_description
+ (uint64_t xstate_bv_mask, 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 1824f57c70f..c5eac277bfd 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 2a2d8697cbe..548f2f10b65 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 2afa04f6288..d1fece717a7 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 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);
}
\f
diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
index 0bf57a3aa5d..3e9e823827e 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<uint64_t *, x86_xsave_layout *>
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 c53758a7dbe..9450a2114e4 100644
--- a/gdbserver/linux-amd64-ipa.cc
+++ b/gdbserver/linux-amd64-ipa.cc
@@ -170,7 +170,7 @@ supply_static_tracepoint_registers (struct regcache *regcache,
const struct target_desc *
get_ipa_tdesc (int idx)
{
- uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx);
+ uint64_t xstate_bv_mask = x86_linux_tdesc_idx_to_xstate_bv_mask (idx);
#if defined __ILP32__
bool is_x32 = true;
@@ -178,7 +178,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_mask, is_x32);
}
/* Allocate buffer for the jump pads. The branch instruction has a
@@ -247,9 +247,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_mask (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_mask (i), false);
#endif
}
diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc
index 2b363271ab6..ec06f16a2bf 100644
--- a/gdbserver/linux-i386-ipa.cc
+++ b/gdbserver/linux-i386-ipa.cc
@@ -251,9 +251,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_mask = x86_linux_tdesc_idx_to_xstate_bv_mask (idx);
- return i386_linux_read_description (xcr0);
+ return i386_linux_read_description (xstate_bv_mask);
}
/* Allocate buffer for the jump pads. On i386, we can reach an arbitrary
@@ -276,5 +276,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_mask (i));
}
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index b023b34a0a4..4575ea2fdc0 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_mask_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_mask_to_tdesc_idx (*storage.first);
}
/* The linux target ops object. */
diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
index 45300b2c18d..76932c765a7 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
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (4 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86 Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-02-06 3:13 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack Schimpe, Christina
` (7 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
This patch adds the user mode register PL3_SSP which is part of the
Intel(R) Control-Flow Enforcement Technology (CET) feature for support
of shadow stack.
For now, only native and remote debugging support for shadow stack
userspace on amd64 linux are covered by this patch including 64 bit and
x32 support. 32 bit support is not covered due to missing linux kernel
support.
This patch requires fixing the test gdb.base/inline-frame-cycle-unwind
which is failing in case the shadow stack pointer is unavailable.
Such a state is possible if shadow stack is disabled for the current thread
but supported by HW.
This test uses the Python unwinder inline-frame-cycle-unwind.py which fakes
the cyclic stack cycle by reading the pending frame's registers and adding
them to the unwinder:
~~~
for reg in pending_frame.architecture().registers("general"):
val = pending_frame.read_register(reg)
unwinder.add_saved_register(reg, val)
return unwinder
~~~
However, in case the python unwinder is used we add a register (pl3_ssp) that is
unavailable. This leads to a NOT_AVAILABLE_ERROR caught in
gdb/frame-unwind.c:frame_unwind_try_unwinder and it is continued with standard
unwinders. This destroys the faked cyclic behavior and the stack is
further unwinded after frame 5.
In the working scenario an error should be triggered:
~~~
bt
0 inline_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:49^M
1 normal_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:32^M
2 0x000055555555516e in inline_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:45^M
3 normal_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:32^M
4 0x000055555555516e in inline_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:45^M
5 normal_func () at /tmp/gdb.base/inline-frame-cycle-unwind.c:32^M
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) PASS: gdb.base/inline-frame-cycle-unwind.exp: cycle at level 5: backtrace when the unwind is broken at frame 5
~~~
To fix the Python unwinder, we simply skip the unavailable registers.
---
gdb/amd64-linux-nat.c | 17 +++++
gdb/amd64-linux-tdep.c | 1 +
gdb/amd64-tdep.c | 6 +-
gdb/amd64-tdep.h | 1 +
gdb/arch/amd64.c | 10 +++
gdb/arch/i386.c | 4 ++
gdb/arch/x86-linux-tdesc-features.c | 1 +
gdb/doc/gdb.texinfo | 4 ++
gdb/features/Makefile | 2 +
gdb/features/i386/32bit-ssp.c | 14 ++++
gdb/features/i386/32bit-ssp.xml | 11 +++
gdb/features/i386/64bit-ssp.c | 14 ++++
gdb/features/i386/64bit-ssp.xml | 11 +++
gdb/i386-tdep.c | 18 ++++-
gdb/i386-tdep.h | 4 ++
gdb/nat/x86-linux-tdesc.c | 2 +
gdb/nat/x86-linux.c | 55 +++++++++++++++
gdb/nat/x86-linux.h | 4 ++
gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 22 ++++++
gdb/testsuite/gdb.arch/amd64-ssp.exp | 50 ++++++++++++++
.../gdb.base/inline-frame-cycle-unwind.py | 4 ++
gdb/testsuite/lib/gdb.exp | 69 +++++++++++++++++++
gdb/x86-linux-nat.c | 50 ++++++++++++--
gdb/x86-linux-nat.h | 11 +++
gdb/x86-tdep.c | 22 ++++++
gdb/x86-tdep.h | 9 +++
gdbserver/linux-x86-low.cc | 28 +++++++-
gdbsupport/x86-xstate.h | 5 +-
28 files changed, 440 insertions(+), 9 deletions(-)
create mode 100644 gdb/features/i386/32bit-ssp.c
create mode 100644 gdb/features/i386/32bit-ssp.xml
create mode 100644 gdb/features/i386/64bit-ssp.c
create mode 100644 gdb/features/i386/64bit-ssp.xml
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack.c
create mode 100644 gdb/testsuite/gdb.arch/amd64-ssp.exp
diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index c3b7a19b5cb..df246408eaa 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -32,6 +32,7 @@
#include "amd64-tdep.h"
#include "amd64-linux-tdep.h"
#include "i386-linux-tdep.h"
+#include "x86-tdep.h"
#include "gdbsupport/x86-xstate.h"
#include "x86-linux-nat.h"
@@ -237,6 +238,14 @@ amd64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
+ if ((regnum == -1 && tdep->ssp_regnum > 0)
+ || (regnum != -1 && regnum == tdep->ssp_regnum))
+ {
+ x86_linux_fetch_ssp (regcache, tid);
+ if (regnum != -1)
+ return;
+ }
+
/* Pre-4.14 kernels have a bug (fixed by commit 0852b374173b
"x86/fpu: Add FPU state copying quirk to handle XRSTOR failure on
Intel Skylake CPUs") that sometimes causes the mxcsr location in
@@ -302,6 +311,14 @@ amd64_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
if (have_ptrace_getregset == TRIBOOL_TRUE)
{
gdb::byte_vector xstateregs (tdep->xsave_layout.sizeof_xsave);
+ if ((regnum == -1 && tdep->ssp_regnum > 0)
+ || (regnum != -1 && regnum == tdep->ssp_regnum))
+ {
+ x86_linux_store_ssp (regcache, tid);
+ if (regnum != -1)
+ return;
+ }
+
struct iovec iov;
iov.iov_base = xstateregs.data ();
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 2c76a1de5a8..8ed381e1a2c 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -105,6 +105,7 @@ int amd64_linux_gregset_reg_offset[] =
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, /* PKEYS register pkru */
+ -1, /* CET user mode register PL3_SSP. */
/* End of hardware registers */
21 * 8, 22 * 8, /* fs_base and gs_base. */
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 37a2e3b03d4..a298333e70a 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -3197,6 +3197,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
tdep->num_pkeys_regs = 1;
}
+ if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pl3_ssp") != nullptr)
+ tdep->ssp_regnum = AMD64_PL3_SSP_REGNUM;
+
tdep->num_byte_regs = 20;
tdep->num_word_regs = 16;
tdep->num_dword_regs = 16;
@@ -3359,12 +3362,13 @@ const struct target_desc *
amd64_target_description (uint64_t xstate_bv_mask, bool segments)
{
static target_desc *amd64_tdescs \
- [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {};
+ [2/*AVX*/][2/*AVX512*/][2/*PKRU*/][2/*CET_U*/][2/*segments*/] = {};
target_desc **tdesc;
tdesc = &amd64_tdescs[(xstate_bv_mask & X86_XSTATE_AVX) ? 1 : 0]
[(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0]
[(xstate_bv_mask & X86_XSTATE_PKRU) ? 1 : 0]
+ [(xstate_bv_mask & X86_XSTATE_CET_U) ? 1 : 0]
[segments ? 1 : 0];
if (*tdesc == NULL)
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index e93e3931df3..fad28649a5a 100644
--- a/gdb/amd64-tdep.h
+++ b/gdb/amd64-tdep.h
@@ -81,6 +81,7 @@ enum amd64_regnum
AMD64_ZMM0H_REGNUM,
AMD64_ZMM31H_REGNUM = AMD64_ZMM0H_REGNUM + 31,
AMD64_PKRU_REGNUM,
+ AMD64_PL3_SSP_REGNUM,
AMD64_FSBASE_REGNUM,
AMD64_GSBASE_REGNUM
};
diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c
index 72bd96aff76..2c45cb637ec 100644
--- a/gdb/arch/amd64.c
+++ b/gdb/arch/amd64.c
@@ -28,6 +28,8 @@
#include "../features/i386/64bit-sse.c"
#include "../features/i386/pkeys.c"
+#include "../features/i386/64bit-ssp.c"
+#include "../features/i386/32bit-ssp.c"
#include "../features/i386/x32-core.c"
/* See amd64.h. */
@@ -68,5 +70,13 @@ amd64_create_target_description (uint64_t xstate_bv_mask, bool is_x32,
if (xstate_bv_mask & X86_XSTATE_PKRU)
regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
+ if (xstate_bv_mask & X86_XSTATE_CET_U)
+ {
+ if (!is_x32)
+ regnum = create_feature_i386_64bit_ssp (tdesc.get (), regnum);
+ else
+ regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
+ }
+
return tdesc.release ();
}
diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c
index 4a39028a472..59daaa4c583 100644
--- a/gdb/arch/i386.c
+++ b/gdb/arch/i386.c
@@ -28,6 +28,7 @@
#include "../features/i386/32bit-avx512.c"
#include "../features/i386/32bit-segments.c"
#include "../features/i386/pkeys.c"
+#include "../features/i386/32bit-ssp.c"
/* See i386.h. */
@@ -66,5 +67,8 @@ i386_create_target_description (uint64_t xstate_bv_mask, bool is_linux,
if (xstate_bv_mask & X86_XSTATE_PKRU)
regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
+ if (xstate_bv_mask & X86_XSTATE_CET_U)
+ regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
+
return tdesc.release ();
}
diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c
index 3f041ece6eb..e57b6320ce7 100644
--- a/gdb/arch/x86-linux-tdesc-features.c
+++ b/gdb/arch/x86-linux-tdesc-features.c
@@ -65,6 +65,7 @@ struct x86_xstate_feature {
static constexpr x86_xstate_feature x86_linux_all_xstate_features[] = {
/* Feature, i386, amd64, x32. */
+ { X86_XSTATE_CET_U, false, true, true },
{ X86_XSTATE_PKRU, true, true, true },
{ X86_XSTATE_AVX512, true, true, true },
{ X86_XSTATE_AVX, true, true, true },
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7b6000abbea..c6c6fcaa17f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -49750,6 +49750,10 @@ The @samp{org.gnu.gdb.i386.pkeys} feature is optional. It should
describe a single register, @samp{pkru}. It is a 32-bit register
valid for i386 and amd64.
+The @samp{org.gnu.gdb.i386.pl3_ssp} feature is optional. It should describe the
+user mode register @samp{pl3_ssp} which has 64 bits on amd64. Following the
+restriction of the Linux kernel, only amd64 is supported for now.
+
@node LoongArch Features
@subsection LoongArch Features
@cindex target descriptions, LoongArch Features
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 7c10f203faa..5f918ca77e3 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -223,6 +223,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
i386/32bit-avx.xml \
i386/32bit-avx512.xml \
i386/32bit-segments.xml \
+ i386/32bit-ssp.xml \
i386/64bit-avx512.xml \
i386/64bit-core.xml \
i386/64bit-segments.xml \
@@ -230,6 +231,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
i386/64bit-linux.xml \
i386/64bit-sse.xml \
i386/pkeys.xml \
+ i386/64bit-ssp.xml \
i386/x32-core.xml \
loongarch/base32.xml \
loongarch/base64.xml \
diff --git a/gdb/features/i386/32bit-ssp.c b/gdb/features/i386/32bit-ssp.c
new file mode 100644
index 00000000000..991bae3c1e6
--- /dev/null
+++ b/gdb/features/i386/32bit-ssp.c
@@ -0,0 +1,14 @@
+/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
+ Original: 32bit-ssp.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_i386_32bit_ssp (struct target_desc *result, long regnum)
+{
+ struct tdesc_feature *feature;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.i386.pl3_ssp");
+ tdesc_create_reg (feature, "pl3_ssp", regnum++, 1, NULL, 32, "data_ptr");
+ return regnum;
+}
diff --git a/gdb/features/i386/32bit-ssp.xml b/gdb/features/i386/32bit-ssp.xml
new file mode 100644
index 00000000000..d17e7004eec
--- /dev/null
+++ b/gdb/features/i386/32bit-ssp.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.pl3_ssp">
+ <reg name="pl3_ssp" bitsize="32" type="data_ptr"/>
+</feature>
diff --git a/gdb/features/i386/64bit-ssp.c b/gdb/features/i386/64bit-ssp.c
new file mode 100644
index 00000000000..5468099ddf6
--- /dev/null
+++ b/gdb/features/i386/64bit-ssp.c
@@ -0,0 +1,14 @@
+/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
+ Original: 64bit-ssp.xml */
+
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_i386_64bit_ssp (struct target_desc *result, long regnum)
+{
+ struct tdesc_feature *feature;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.i386.pl3_ssp");
+ tdesc_create_reg (feature, "pl3_ssp", regnum++, 1, NULL, 64, "data_ptr");
+ return regnum;
+}
diff --git a/gdb/features/i386/64bit-ssp.xml b/gdb/features/i386/64bit-ssp.xml
new file mode 100644
index 00000000000..a0688d018a5
--- /dev/null
+++ b/gdb/features/i386/64bit-ssp.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.pl3_ssp">
+ <reg name="pl3_ssp" bitsize="64" type="data_ptr"/>
+</feature>
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 54aa1294917..b338029d990 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -8353,7 +8353,8 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
const struct tdesc_feature *feature_core;
const struct tdesc_feature *feature_sse, *feature_avx, *feature_avx512,
- *feature_pkeys, *feature_segments;
+ *feature_pkeys, *feature_segments,
+ *feature_pl3_ssp;
int i, num_regs, valid_p;
if (! tdesc_has_registers (tdesc))
@@ -8379,6 +8380,9 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
/* Try PKEYS */
feature_pkeys = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys");
+ /* Try Shadow Stack. */
+ feature_pl3_ssp = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pl3_ssp");
+
valid_p = 1;
/* The XCR0 bits. */
@@ -8494,6 +8498,15 @@ i386_validate_tdesc_p (i386_gdbarch_tdep *tdep,
tdep->pkeys_register_names[i]);
}
+ if (feature_pl3_ssp != nullptr)
+ {
+ if (tdep->ssp_regnum < 0)
+ tdep->ssp_regnum = I386_PL3_SSP_REGNUM;
+
+ valid_p &= tdesc_numbered_register (feature_pl3_ssp, tdesc_data,
+ tdep->ssp_regnum, "pl3_ssp");
+ }
+
return valid_p;
}
@@ -8785,6 +8798,9 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* No segment base registers. */
tdep->fsbase_regnum = -1;
+ /* No shadow stack pointer register. */
+ tdep->ssp_regnum = -1;
+
tdesc_arch_data_up tdesc_data = tdesc_data_alloc ();
set_gdbarch_relocate_instruction (gdbarch, i386_relocate_instruction);
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 3f990e71abf..8912a72cc6e 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -191,6 +191,9 @@ struct i386_gdbarch_tdep : gdbarch_tdep_base
/* PKEYS register names. */
const char * const *pkeys_register_names = nullptr;
+ /* Shadow stack pointer register. */
+ int ssp_regnum = 0;
+
/* Register number for %fsbase. Set this to -1 to indicate the
absence of segment base registers. */
int fsbase_regnum = 0;
@@ -293,6 +296,7 @@ enum i386_regnum
I386_ZMM0H_REGNUM, /* %zmm0h */
I386_ZMM7H_REGNUM = I386_ZMM0H_REGNUM + 7,
I386_PKRU_REGNUM,
+ I386_PL3_SSP_REGNUM,
I386_FSBASE_REGNUM,
I386_GSBASE_REGNUM
};
diff --git a/gdb/nat/x86-linux-tdesc.c b/gdb/nat/x86-linux-tdesc.c
index c5eac277bfd..60ab23eb795 100644
--- a/gdb/nat/x86-linux-tdesc.c
+++ b/gdb/nat/x86-linux-tdesc.c
@@ -110,6 +110,8 @@ x86_linux_tdesc_for_tid (int tid, uint64_t *xstate_bv_storage,
= x86_fetch_xsave_layout (xcr0, x86_xsave_length ());
*xstate_bv_storage = xcr0;
+ if (x86_check_ssp_support (tid))
+ *xstate_bv_storage |= X86_XSTATE_CET_U;
}
}
diff --git a/gdb/nat/x86-linux.c b/gdb/nat/x86-linux.c
index ad3ed3c2289..0b3a0d438dd 100644
--- a/gdb/nat/x86-linux.c
+++ b/gdb/nat/x86-linux.c
@@ -17,6 +17,12 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "elf/common.h"
+#include "gdbsupport/common-defs.h"
+#include "nat/gdb_ptrace.h"
+#include "nat/linux-ptrace.h"
+#include "nat/x86-cpuid.h"
+#include <sys/uio.h>
#include "x86-linux.h"
#include "x86-linux-dregs.h"
#include "nat/gdb_ptrace.h"
@@ -126,3 +132,52 @@ x86_linux_ptrace_get_arch_size (int tid)
return x86_linux_arch_size (false, false);
#endif
}
+
+bool
+x86_check_ssp_support (const int tid)
+{
+ /* It's not enough to check shadow stack support with the ptrace call
+ below only, as we cannot distinguish between shadow stack not enabled
+ for the current thread and shadow stack is not supported by HW. In
+ both scenarios the ptrace call fails with ENODEV. In case shadow
+ stack is not enabled for the current thread, we still want to return
+ true. */
+ unsigned int eax, ebx, ecx, edx;
+
+ __get_cpuid_count (7, 0, &eax, &ebx, &ecx, &edx);
+
+ if ((ecx & bit_SHSTK) == 0)
+ return false;
+
+ /* Further check for NT_X86_SHSTK kernel support. */
+ uint64_t ssp;
+ iovec iov {&ssp, sizeof (ssp) };
+
+ errno = 0;
+ int res = ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov);
+ if (res < 0)
+ {
+ if (errno == EINVAL)
+ {
+ /* The errno EINVAL for a PTRACE_GETREGSET call indicates that
+ kernel support is not available. */
+ return false;
+ }
+ else if (errno == ENODEV)
+ {
+ /* At this point, since we already checked CPUID, the errno
+ ENODEV for a PTRACE_GETREGSET call indicates that shadow
+ stack is not enabled for the current thread. As it could be
+ enabled later, we still want to return true here. */
+ return true;
+ }
+ else
+ {
+ warning (_("Unknown ptrace error for NT_X86_SHSTK: %s"),
+ safe_strerror (errno));
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/gdb/nat/x86-linux.h b/gdb/nat/x86-linux.h
index 7c0ac7718b6..e0df4effcde 100644
--- a/gdb/nat/x86-linux.h
+++ b/gdb/nat/x86-linux.h
@@ -75,4 +75,8 @@ struct x86_linux_arch_size
extern x86_linux_arch_size x86_linux_ptrace_get_arch_size (int tid);
+/* Check shadow stack hardware and kernel support. */
+
+extern bool x86_check_ssp_support (const int tid);
+
#endif /* GDB_NAT_X86_LINUX_H */
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
new file mode 100644
index 00000000000..643ef2d5f56
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2018-2024 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+int
+main ()
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-ssp.exp b/gdb/testsuite/gdb.arch/amd64-ssp.exp
new file mode 100644
index 00000000000..6ddc875b9a3
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-ssp.exp
@@ -0,0 +1,50 @@
+# Copyright 2018-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test accessing the shadow stack pointer register.
+
+require allow_ssp_tests
+
+standard_testfile amd64-shadow-stack.c
+
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ additional_flags="-fcf-protection=return"] } {
+ return -1
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ # Read PL3_SSP register.
+ set ssp_main [get_hexadecimal_valueof "\$pl3_ssp" "read pl3_ssp value"]
+
+ # Write PL3_SSP register.
+ gdb_test "print /x \$pl3_ssp = 0x12345678" "= 0x12345678" "set pl3_ssp value"
+ gdb_test "print /x \$pl3_ssp" "= 0x12345678" "read pl3_ssp value after setting"
+
+ # Restore original value.
+ gdb_test "print /x \$pl3_ssp = $ssp_main" "= $ssp_main" "restore original pl3_ssp"
+
+ # Potential CET violations often only occur after resuming normal execution.
+ # Therefore, it is important to test normal program continuation after
+ # configuring the shadow stack pointer.
+ gdb_continue_to_end
+}
+
diff --git a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py
index 278fa857d5d..94d553a8cce 100644
--- a/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py
+++ b/gdb/testsuite/gdb.base/inline-frame-cycle-unwind.py
@@ -65,6 +65,10 @@ class TestUnwinder(Unwinder):
for reg in pending_frame.architecture().registers("general"):
val = pending_frame.read_register(reg)
+ # Having unavailable registers leads to a fall back to the standard
+ # unwinders. Don't add unavailable registers to avoid this.
+ if (str (val) == "<unavailable>"):
+ continue
unwinder.add_saved_register(reg, val)
return unwinder
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index a86f534528c..fc35456f1d3 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4225,6 +4225,75 @@ gdb_caching_proc allow_tsx_tests {} {
return $allow_tsx_tests
}
+# Run a test on the target to check if it supports x86 shadow stack. Return 1
+# if shadow stack is enabled, 0 otherwise.
+
+gdb_caching_proc allow_ssp_tests {} {
+ global srcdir subdir gdb_prompt hex
+
+ set me "allow_ssp_tests"
+
+ if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } {
+ verbose "$me: target known to not support shadow stack."
+ return 0
+ }
+
+ # There is no need to check the actual HW in addition to ptrace support.
+ # We need both checks and ptrace will tell us about the HW state.
+ set compile_flags "{additional_flags=-fcf-protection=return}"
+ set src { int main() { return 0; } }
+ if {![gdb_simple_compile $me $src executable $compile_flags]} {
+ return 0
+ }
+
+ save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ # No error message, compilation succeeded so now run it via gdb.
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load $obj
+ if {![runto_main]} {
+ return 0
+ }
+ set shadow_stack_disabled_re "(<unavailable>)"
+ if {[istarget *-*-linux*]} {
+ # Starting with v6.6., the Linux kernel supports CET shadow stack.
+ # Dependent on the target we can see a nullptr or "<unavailable>"
+ # when shadow stack is supported by HW and the linux kernel but
+ # not enabled for the current thread (for example due to a lack
+ # of compiler or glibc support for -fcf-protection).
+ set shadow_stack_disabled_re "$shadow_stack_disabled_re|(.*0x0)"
+ }
+
+ set allow_ssp_tests 0
+ gdb_test_multiple "print \$pl3_ssp" "test shadow stack support" {
+ -re -wrap "(.*$hex)((?!(.*0x0)).)" {
+ verbose -log "$me: Shadow stack support detected."
+ set allow_ssp_tests 1
+ }
+ -re -wrap $shadow_stack_disabled_re {
+ # In case shadow stack is not enabled (for example due to a
+ # lack of compiler or glibc support for -fcf-protection).
+ verbose -log "$me: Shadow stack is not enabled."
+ }
+ -re -wrap "void" {
+ # In case we don't have hardware or kernel support.
+ verbose -log "$me: No shadow stack support."
+ }
+ }
+
+ gdb_exit
+ }
+
+ remote_file build delete $obj
+
+ verbose "$me: returning $allow_ssp_tests" 2
+ return $allow_ssp_tests
+}
+
# Run a test on the target to see if it supports avx512bf16. Return 1 if so,
# 0 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite.
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index d1fece717a7..5bbd4640e30 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -41,6 +41,7 @@
#include "nat/x86-linux.h"
#include "nat/x86-linux-dregs.h"
#include "nat/linux-ptrace.h"
+#include "x86-tdep.h"
#include "nat/x86-linux-tdesc.h"
/* linux_nat_target::low_new_fork implementation. */
@@ -97,11 +98,10 @@ 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 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 XSTATE_BV_STORAGE will not be configured based on
- xcr0 only. */
+ called. Also it checks the enablement state of features which are
+ not configured in xcr0, such as CET shadow stack. Once the supported
+ features are identified, the XSTATE_BV_STORAGE value is configured
+ accordingly and preserved for subsequent calls of this function. */
static uint64_t xstate_bv_storage;
if (inferior_ptid == null_ptid)
@@ -215,6 +215,46 @@ x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr)
}
\f
+/* See x86-linux-nat.h. */
+
+void
+x86_linux_fetch_ssp (regcache *regcache, const int tid)
+{
+ uint64_t ssp = 0x0;
+ iovec iov {&ssp, sizeof (ssp)};
+
+ /* The shadow stack may be enabled and disabled at runtime. Reading the
+ ssp might fail as shadow stack was not activated for the current
+ thread. We don't want to show a warning but silently return. The
+ register will be shown as unavailable for the user. */
+ if (ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov) != 0)
+ return;
+
+ x86_supply_ssp (regcache, ssp);
+}
+
+/* See x86-linux-nat.h. */
+
+void
+x86_linux_store_ssp (const regcache *regcache, const int tid)
+{
+ uint64_t ssp = 0x0;
+ iovec iov {&ssp, sizeof (ssp)};
+ x86_collect_ssp (regcache, ssp);
+
+ /* Starting with v6.6., the Linux kernel supports CET shadow stack.
+ Dependent on the target the ssp register can be unavailable or
+ nullptr when shadow stack is supported by HW and the linux kernel but
+ not enabled for the current thread. In case of nullptr, GDB tries to
+ restore the shadow stack pointer after an inferior call. The ptrace
+ call with PTRACE_SETREGSET will fail here with errno ENODEV. We
+ don't want to throw an error in this case but silently continue. */
+ errno = 0;
+ if ((ptrace (PTRACE_SETREGSET, tid, NT_X86_SHSTK, &iov) != 0)
+ && (errno != ENODEV))
+ perror_with_name (_("Failed to write pl3_ssp register"));
+}
+
void _initialize_x86_linux_nat ();
void
_initialize_x86_linux_nat ()
diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h
index 3c2241bb0b6..d5dc1908090 100644
--- a/gdb/x86-linux-nat.h
+++ b/gdb/x86-linux-nat.h
@@ -92,4 +92,15 @@ struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
extern ps_err_e x86_linux_get_thread_area (pid_t pid, void *addr,
unsigned int *base_addr);
+/* Fetch the value of the shadow stack pointer register from process/thread
+ TID and store it to GDB's register cache. */
+
+extern void x86_linux_fetch_ssp (regcache *regcache, const int tid);
+
+/* Read the value of the shadow stack pointer from GDB's register cache
+ and store it in the shadow stack pointer register of process/thread TID.
+ Throw an error in case of failure. */
+
+extern void x86_linux_store_ssp (const regcache *regcache, const int tid);
+
#endif /* GDB_X86_LINUX_NAT_H */
diff --git a/gdb/x86-tdep.c b/gdb/x86-tdep.c
index e50b5fb9fa4..08fb0e8d82d 100644
--- a/gdb/x86-tdep.c
+++ b/gdb/x86-tdep.c
@@ -17,10 +17,32 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "defs.h"
+#include "i386-tdep.h"
#include "x86-tdep.h"
#include "symtab.h"
+/* See x86-tdep.h. */
+
+void
+x86_supply_ssp (regcache *regcache, const uint64_t ssp)
+{
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (regcache->arch ());
+ gdb_assert (tdep != nullptr && tdep->ssp_regnum > 0);
+ regcache->raw_supply (tdep->ssp_regnum, &ssp);
+}
+
+/* See x86-tdep.h. */
+
+void
+x86_collect_ssp (const regcache *regcache, uint64_t& ssp)
+{
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (regcache->arch ());
+ gdb_assert (tdep != nullptr && tdep->ssp_regnum > 0);
+ regcache->raw_collect (tdep->ssp_regnum, &ssp);
+}
+
/* Check whether NAME is included in NAMES[LO] (inclusive) to NAMES[HI]
(exclusive). */
diff --git a/gdb/x86-tdep.h b/gdb/x86-tdep.h
index 2b5853adb8a..fcb3909b33e 100644
--- a/gdb/x86-tdep.h
+++ b/gdb/x86-tdep.h
@@ -20,6 +20,15 @@
#ifndef GDB_X86_TDEP_H
#define GDB_X86_TDEP_H
+/* Fill SSP to the shadow stack pointer in GDB's REGCACHE. */
+
+extern void x86_supply_ssp (regcache *regcache, const uint64_t ssp);
+
+/* Collect the value of the shadow stack pointer in GDB's REGCACHE and
+ write it to SSP. */
+
+extern void x86_collect_ssp (const regcache *regcache, uint64_t& ssp);
+
/* Checks whether PC lies in an indirect branch thunk using registers
REGISTER_NAMES[LO] (inclusive) to REGISTER_NAMES[HI] (exclusive). */
diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
index 4575ea2fdc0..0e668c23b2a 100644
--- a/gdbserver/linux-x86-low.cc
+++ b/gdbserver/linux-x86-low.cc
@@ -253,7 +253,8 @@ static const int x86_64_regmap[] =
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
- -1 /* pkru */
+ -1, /* pkru */
+ -1 /* CET user mode register PL3_SSP. */
};
#define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0]))
@@ -405,6 +406,18 @@ x86_target::low_cannot_fetch_register (int regno)
return regno >= I386_NUM_REGS;
}
+static void
+x86_fill_ssp_reg (regcache *regcache, void *buf)
+{
+ collect_register_by_name (regcache, "pl3_ssp", buf);
+}
+
+static void
+x86_store_ssp_reg (regcache *regcache, const void *buf)
+{
+ supply_register_by_name (regcache, "pl3_ssp", buf);
+}
+
static void
collect_register_i386 (struct regcache *regcache, int regno, void *buf)
{
@@ -544,6 +557,8 @@ static struct regset_info x86_regsets[] =
x86_fill_gregset, x86_store_gregset },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_XSTATE, 0,
EXTENDED_REGS, x86_fill_xstateregset, x86_store_xstateregset },
+ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_SHSTK, 0,
+ OPTIONAL_RUNTIME_REGS, x86_fill_ssp_reg, x86_store_ssp_reg },
# ifndef __x86_64__
# ifdef HAVE_PTRACE_GETFPXREGS
{ PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, 0, sizeof (elf_fpxregset_t),
@@ -897,6 +912,17 @@ x86_linux_read_description ()
{
if (regset->nt_type == NT_X86_XSTATE)
regset->size = xsave_len;
+ else if (regset->nt_type == NT_X86_SHSTK)
+ {
+ /* We must configure the size of the NT_X86_SHSTK regset
+ from non-zero value to it's appropriate size, even though
+ the ptrace call is only tested for NT_X86_XSTATE request,
+ because the NT_X86_SHSTK regset is of type
+ OPTIONAL_RUNTIME_REGS. A ptrace call with NT_X86_SHSTK
+ request may only be successful later on, once shadow
+ stack is enabled for the current thread. */
+ regset->size = sizeof (CORE_ADDR);
+ }
else
gdb_assert_not_reached ("invalid regset type.");
}
diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
index 76932c765a7..9dbf3be6404 100644
--- a/gdbsupport/x86-xstate.h
+++ b/gdbsupport/x86-xstate.h
@@ -28,6 +28,7 @@
#define X86_XSTATE_ZMM_H_ID 6
#define X86_XSTATE_ZMM_ID 7
#define X86_XSTATE_PKRU_ID 9
+#define X86_XSTATE_CET_U_ID 11
/* The extended state feature bits. */
#define X86_XSTATE_X87 (1ULL << X86_XSTATE_X87_ID)
@@ -42,6 +43,7 @@
| X86_XSTATE_ZMM)
#define X86_XSTATE_PKRU (1ULL << X86_XSTATE_PKRU_ID)
+#define X86_XSTATE_CET_U (1ULL << X86_XSTATE_CET_U_ID)
/* Total size of the XSAVE area extended region and offsets of
register states within the region. Offsets are set to 0 to
@@ -86,7 +88,8 @@ constexpr bool operator!= (const x86_xsave_layout &lhs,
/* 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_ALL_MASK (X86_XSTATE_AVX_AVX512_PKU_MASK\
+ | X86_XSTATE_CET_U)
#define X86_XSTATE_SSE_SIZE 576
#define X86_XSTATE_AVX_SIZE 832
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (5 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-02-06 3:15 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux Schimpe, Christina
` (6 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
From: Felix Willgerodt <felix.willgerodt@intel.com>
Intel's Control-Flow Enforcement Technology (CET) provides the shadow
stack feature for the x86 architecture.
This commit adds support to write and read the shadow-stack node in
corefiles. This helps debugging return address violations post-mortem.
The format is synced with the linux kernel commit "x86: Add PTRACE
interface for shadow stack". As the linux kernel restricts shadow
stack support to 64-bit, apply the fix for amd64 only.
Co-Authored-By: Christina Schimpe <christina.schimpe@intel.com>
---
bfd/elf.c | 24 +++++++++
gdb/amd64-linux-tdep.c | 52 +++++++++++++++++--
.../gdb.arch/amd64-shadow-stack-corefile.exp | 50 ++++++++++++++++++
3 files changed, 122 insertions(+), 4 deletions(-)
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
diff --git a/bfd/elf.c b/bfd/elf.c
index 78394319bf0..23f1ebcd83c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -10365,6 +10365,12 @@ elfcore_grok_xstatereg (bfd *abfd, Elf_Internal_Note *note)
return elfcore_make_note_pseudosection (abfd, ".reg-xstate", note);
}
+static bool
+elfcore_grok_sspreg (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ssp", note);
+}
+
static bool
elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note)
{
@@ -11060,6 +11066,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
else
return true;
+ case NT_X86_SHSTK: /* Linux CET extension. */
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_sspreg (abfd, note);
+ else
+ return true;
+
case NT_PPC_VMX:
if (note->namesz == 6
&& strcmp (note->namedata, "LINUX") == 0)
@@ -12510,6 +12523,15 @@ elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz,
note_name, NT_X86_XSTATE, xfpregs, size);
}
+static char *
+elfcore_write_sspreg (bfd *abfd, char *buf, int *bufsiz,
+ const void *ssp, int size)
+{
+ const char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_X86_SHSTK, ssp, size);
+}
+
char *
elfcore_write_x86_segbases (bfd *abfd, char *buf, int *bufsiz,
const void *regs, int size)
@@ -13105,6 +13127,8 @@ elfcore_write_register_note (bfd *abfd,
return elfcore_write_xstatereg (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-x86-segbases") == 0)
return elfcore_write_x86_segbases (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ssp") == 0)
+ return elfcore_write_sspreg (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-ppc-vmx") == 0)
return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-ppc-vsx") == 0)
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 8ed381e1a2c..95f643b1217 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -44,6 +44,7 @@
#include "expop.h"
#include "arch/amd64-linux-tdesc.h"
#include "inferior.h"
+#include "x86-tdep.h"
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
@@ -1586,6 +1587,14 @@ amd64_linux_record_signal (struct gdbarch *gdbarch,
return 0;
}
+/* Get shadow stack pointer state from core dump. */
+
+static bool
+amd64_linux_core_read_ssp_state_p (bfd *abfd)
+{
+ return bfd_get_section_by_name (abfd, ".reg-ssp") != NULL;
+}
+
/* Get Linux/x86 target description from core dump. */
static const struct target_desc *
@@ -1595,11 +1604,14 @@ amd64_linux_core_read_description (struct gdbarch *gdbarch,
{
/* Linux/x86-64. */
x86_xsave_layout layout;
- uint64_t xcr0 = i386_linux_core_read_xsave_info (abfd, layout);
- if (xcr0 == 0)
- xcr0 = X86_XSTATE_SSE_MASK;
+ uint64_t xstate_bv_mask = i386_linux_core_read_xsave_info (abfd, layout);
+ if (xstate_bv_mask == 0)
+ xstate_bv_mask = X86_XSTATE_SSE_MASK;
+
+ if (amd64_linux_core_read_ssp_state_p (abfd))
+ xstate_bv_mask |= X86_XSTATE_CET_U;
- return amd64_linux_read_description (xcr0 & X86_XSTATE_ALL_MASK,
+ return amd64_linux_read_description (xstate_bv_mask & X86_XSTATE_ALL_MASK,
gdbarch_ptr_bit (gdbarch) == 32);
}
@@ -1630,6 +1642,30 @@ static const struct regset amd64_linux_xstateregset =
amd64_linux_collect_xstateregset
};
+static void
+amd64_linux_supply_ssp (const struct regset *regset,
+ struct regcache *regcache, int regnum,
+ const void *ssp, size_t len)
+{
+ x86_supply_ssp (regcache, *static_cast<const uint64_t *> (ssp));
+}
+
+static void
+amd64_linux_collect_ssp (const struct regset *regset,
+ const struct regcache *regcache, int regnum,
+ void *ssp, size_t len)
+{
+ x86_collect_ssp (regcache, *static_cast<uint64_t *> (ssp));
+}
+
+/* Shadow stack pointer register. */
+
+static const struct regset amd64_linux_ssp_register
+ {
+ NULL, amd64_linux_supply_ssp, amd64_linux_collect_ssp
+ };
+
+
/* Iterate over core file register note sections. */
static void
@@ -1646,6 +1682,14 @@ amd64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
cb (".reg-xstate", tdep->xsave_layout.sizeof_xsave,
tdep->xsave_layout.sizeof_xsave, &amd64_linux_xstateregset,
"XSAVE extended state", cb_data);
+
+ /* SSP can be unavailable. Thus, we need to check the register status
+ in case we write a core file (regcache != nullptr). */
+ if (tdep->ssp_regnum > 0
+ && (regcache == nullptr
+ || REG_VALID == regcache->get_register_status (tdep->ssp_regnum)))
+ cb (".reg-ssp", 8, 8, &amd64_linux_ssp_register,
+ "shadow stack pointer", cb_data);
}
/* The instruction sequences used in x86_64 machines for a
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
new file mode 100644
index 00000000000..25cc1529f0d
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
@@ -0,0 +1,50 @@
+# Copyright 2021-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test the shadow stack pointer note in core dumps.
+
+require allow_ssp_tests
+
+standard_testfile amd64-shadow-stack.c
+set gcorefile ${binfile}.gcore
+
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ additional_flags="-fcf-protection=return"] } {
+ return -1
+ }
+
+ if { ![runto_main] } {
+ return -1
+ }
+
+ # Save ssp for comparison in the corefile session.
+ set ssp [get_hexadecimal_valueof "\$pl3_ssp" ""]
+
+ if { ![gdb_gcore_cmd $gcorefile "save a corefile"] } {
+ return -1
+ }
+
+ # Now restart gdb and load the corefile.
+ clean_restart ${binfile}
+
+ gdb_test "core ${gcorefile}" \
+ "Core was generated by .*" "re-load generated corefile"
+
+ gdb_test "print /x \$pl3_ssp" "= $ssp"
+}
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (6 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-01-30 14:29 ` Guinevere Larsen
2025-02-06 3:30 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support Schimpe, Christina
` (5 subsequent siblings)
13 siblings, 2 replies; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
Unwind the $pl3_ssp register.
We now have an updated value for the shadow stack pointer when
moving up or down the frame level. Note that $pl3_ssp can
become unavailable when moving to a frame before the shadow
stack enablement. In the example below, shadow stack is enabled
in the function 'call1'. Thus, when moving to a frame level above
the function, $pl3_ssp will become unavaiable.
Following the restriction of the linux kernel, implement the unwinding
for amd64 linux only.
Before this patch:
~~~
Breakpoint 1, call2 (j=3) at sample.c:44
44 return 42;
(gdb) p $pl3_ssp
$1 = (void *) 0x7ffff79ffff8
(gdb) up
55 call2 (3);
(gdb) p $pl3_ssp
$2 = (void *) 0x7ffff79ffff8
(gdb) up
68 call1 (43);
(gdb) p $pl3_ssp
$3 = (void *) 0x7ffff79ffff8
~~~
After this patch:
~~~
Breakpoint 1, call2 (j=3) at sample.c:44
44 return 42;
(gdb) p $pl3_ssp
$1 = (void *) 0x7ffff79ffff8
(gdb) up
55 call2 (3);
(gdb) p $pl3_ssp
$2 = (void *) 0x7ffff7a00000
(gdb) up
68 call1 (43i);
(gdb) p $pl3_ssp
$3 = <unavailable>
~~~
As we now have an updated value for each selected frame, the
return command is now enabled for shadow stack enabled programs, too.
We therefore add a test for the return command and shadow stack support,
and for an updated shadow stack pointer after a frame level change.
---
gdb/amd64-linux-tdep.c | 69 +++++++++++++++
gdb/linux-tdep.c | 47 ++++++++++
gdb/linux-tdep.h | 7 ++
.../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++
gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
5 files changed, 224 insertions(+)
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 95f643b1217..895feac85e8 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -45,6 +45,8 @@
#include "arch/amd64-linux-tdesc.h"
#include "inferior.h"
#include "x86-tdep.h"
+#include "dwarf2/frame.h"
+#include "frame-unwind.h"
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
@@ -1873,6 +1875,72 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
return (addr & amd64_linux_lam_untag_mask ());
}
+static value *
+amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
+ void **this_cache, int regnum)
+{
+ value *v = frame_unwind_got_register (this_frame, regnum, regnum);
+ gdb_assert (v != nullptr);
+
+ gdbarch *gdbarch = get_frame_arch (this_frame);
+
+ if (v->entirely_available () && !v->optimized_out ())
+ {
+ int size = register_size (gdbarch, regnum);
+ bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
+ size, byte_order);
+
+ /* Starting with v6.6., the Linux kernel supports CET shadow stack.
+ Using /proc/PID/smaps we can only check if the current shadow
+ stack pointer SSP points to shadow stack memory. Only if this is
+ the case a valid previous shadow stack pointer can be
+ calculated. */
+ std::pair<CORE_ADDR, CORE_ADDR> range;
+ if (linux_address_in_shadow_stack_mem_range (ssp, &range))
+ {
+ /* The shadow stack grows downwards. To compute the previous
+ shadow stack pointer, we need to increment SSP.
+ For x32 the shadow stack elements are still 64-bit aligned.
+ Thus, we cannot use gdbarch_addr_bit to compute the new stack
+ pointer. */
+ const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
+ const int bytes_per_word
+ = (binfo->bits_per_word / binfo->bits_per_byte);
+ CORE_ADDR new_ssp = ssp + bytes_per_word;
+
+ /* If NEW_SSP points to the end of or before (<=) the current
+ shadow stack memory range we consider NEW_SSP as valid (but
+ empty). */
+ if (new_ssp <= range.second)
+ return frame_unwind_got_address (this_frame, regnum, new_ssp);
+ }
+ }
+
+ /* Return a value which is marked as unavailable in case we could not
+ calculate a valid previous shadow stack pointer. */
+ value *retval
+ = value::allocate_register (get_next_frame_sentinel_okay (this_frame),
+ regnum, register_type (gdbarch, regnum));
+ retval->mark_bytes_unavailable (0, retval->type ()->length ());
+ return retval;
+}
+
+static void
+amd64_init_reg (gdbarch *gdbarch, int regnum, dwarf2_frame_state_reg *reg,
+ const frame_info_ptr &this_frame)
+{
+ if (regnum == gdbarch_pc_regnum (gdbarch))
+ reg->how = DWARF2_FRAME_REG_RA;
+ else if (regnum == gdbarch_sp_regnum (gdbarch))
+ reg->how = DWARF2_FRAME_REG_CFA;
+ else if (regnum == AMD64_PL3_SSP_REGNUM)
+ {
+ reg->how = DWARF2_FRAME_REG_FN;
+ reg->loc.fn = amd64_linux_dwarf2_prev_ssp;
+ }
+}
+
static void
amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
int num_disp_step_buffers)
@@ -1927,6 +1995,7 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
set_gdbarch_remove_non_address_bits_watchpoint
(gdbarch, amd64_linux_remove_non_address_bits_watchpoint);
+ dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg);
}
static void
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index d3452059ce2..3a20b12c3d7 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -47,6 +47,7 @@
#include <ctype.h>
#include <unordered_map>
+#include <algorithm>
/* This enum represents the values that the user can choose when
informing the Linux kernel about which memory mappings will be
@@ -96,6 +97,10 @@ struct smaps_vmflags
/* Memory map has memory tagging enabled. */
unsigned int memory_tagging : 1;
+
+ /* Memory map used for shadow stack. */
+
+ unsigned int shadow_stack_memory : 1;
};
/* Data structure that holds the information contained in the
@@ -537,6 +542,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
v->shared_mapping = 1;
else if (strcmp (s, "mt") == 0)
v->memory_tagging = 1;
+ else if (strcmp (s, "ss") == 0)
+ v->shadow_stack_memory = 1;
}
}
@@ -2744,6 +2751,46 @@ show_dump_excluded_mappings (struct ui_file *file, int from_tty,
" flag is %s.\n"), value);
}
+/* See linux-tdep.h. */
+
+bool
+linux_address_in_shadow_stack_mem_range
+ (CORE_ADDR addr, std::pair<CORE_ADDR, CORE_ADDR> *range)
+{
+ if (!target_has_execution () || current_inferior ()->fake_pid_p)
+ return false;
+
+ const int pid = current_inferior ()->pid;
+
+ std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
+
+ gdb::unique_xmalloc_ptr<char> data
+ = target_fileio_read_stralloc (nullptr, smaps_file.c_str ());
+
+ if (data == nullptr)
+ return false;
+
+ const std::vector<smaps_data> smaps
+ = parse_smaps_data (data.get (), std::move (smaps_file));
+
+ auto find_addr_mem_range = [&addr] (const smaps_data &map)
+ {
+ bool addr_in_mem_range
+ = (addr >= map.start_address && addr < map.end_address);
+ return (addr_in_mem_range && map.vmflags.shadow_stack_memory);
+ };
+ auto it = std::find_if (smaps.begin (), smaps.end (), find_addr_mem_range);
+
+ if (it != smaps.end ())
+ {
+ range->first = it->start_address;
+ range->second = it->end_address;
+ return true;
+ }
+
+ return false;
+}
+
/* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types.
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
index bf4220bf75b..97dcc75a79c 100644
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -117,4 +117,11 @@ extern CORE_ADDR linux_get_hwcap2 ();
extern struct link_map_offsets *linux_ilp32_fetch_link_map_offsets ();
extern struct link_map_offsets *linux_lp64_fetch_link_map_offsets ();
+/* Returns true if ADDR belongs to a shadow stack memory range. If this
+ is the case, assign the shadow stack memory range to RANGE
+ [start_address, end_address). */
+
+extern bool linux_address_in_shadow_stack_mem_range
+ (CORE_ADDR addr, std::pair<CORE_ADDR, CORE_ADDR> *range);
+
#endif /* GDB_LINUX_TDEP_H */
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
new file mode 100644
index 00000000000..17f32ce3964
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
@@ -0,0 +1,88 @@
+# Copyright 2018-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test shadow stack enabling for frame level update and the return command.
+
+require allow_ssp_tests
+
+standard_testfile amd64-shadow-stack.c
+
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ {debug additional_flags="-fcf-protection=return"}] } {
+ return -1
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+
+ set call1_line [ gdb_get_line_number "break call1" ]
+ set call2_line [ gdb_get_line_number "break call2" ]
+
+ # Extract shadow stack pointer inside main, call1 and call2 function.
+ gdb_breakpoint $call1_line
+ gdb_breakpoint $call2_line
+ set ssp_main [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in main"]
+ gdb_continue_to_breakpoint "break call1" ".*break call1.*"
+ set ssp_call1 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call1"]
+ gdb_continue_to_breakpoint "break call2" ".*break call2.*"
+ set ssp_call2 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call2"]
+
+ with_test_prefix "test frame level update" {
+ gdb_test "up" "call1.*" "move to frame 1"
+ gdb_test "print /x \$pl3_ssp" "= $ssp_call1" "check pl3_ssp of frame 1"
+ gdb_test "up" "main.*" "move to frame 2"
+ gdb_test "print /x \$pl3_ssp" "= $ssp_main" "check pl3_ssp of frame 2"
+ gdb_test "frame 0" "call2.*" "move to frame 0"
+ gdb_test "print /x \$pl3_ssp" "= $ssp_call2" "check pl3_ssp of frame 0"
+ }
+
+ with_test_prefix "test return from current frame" {
+ gdb_test "return (int) 1" "#0.*call1.*" \
+ "Test shadow stack return from current frame" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ # Potential CET violations often only occur after resuming normal execution.
+ # Therefore, it is important to test normal program continuation after
+ # testing the return command.
+ gdb_continue_to_end
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+
+ with_test_prefix "test return from past frame" {
+ gdb_breakpoint $call2_line
+ gdb_continue_to_breakpoint "break call2" ".*break call2.*"
+
+ gdb_test "frame 1" ".*in call1.*"
+
+ gdb_test "return (int) 1" "#0.*main.*" \
+ "Test shadow stack return from past frame" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ # Potential CET violations often only occur after resuming normal execution.
+ # Therefore, it is important to test normal program continuation after
+ # testing the return command.
+ gdb_continue_to_end
+ }
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
index 643ef2d5f56..80389730bc2 100644
--- a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
@@ -15,8 +15,21 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+static int
+call2 ()
+{
+ return 42; /* break call2. */
+}
+
+static int
+call1 ()
+{
+ return call2 (); /* break call1. */
+}
+
int
main ()
{
+ call1 (); /* break main. */
return 0;
}
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (7 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-02-06 3:31 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls Schimpe, Christina
` (4 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
Inferior calls in GDB reset the current PC to the beginning of the function
that is called. As no call instruction is executed the new return address
needs to be pushed to the shadow stack and the shadow stack pointer needs
to be updated.
This commit adds a new gdbarch method to push an address on the shadow
stack. The method is used to adapt the function 'call_function_by_hand_dummy'
for inferior call shadow stack support.
---
gdb/gdbarch-gen.c | 32 ++++++++++++++++++++++++++++++++
gdb/gdbarch-gen.h | 14 ++++++++++++++
gdb/gdbarch_components.py | 16 ++++++++++++++++
gdb/infcall.c | 6 ++++++
4 files changed, 68 insertions(+)
diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c
index d05c7a3cbdf..c33c476dfdb 100644
--- a/gdb/gdbarch-gen.c
+++ b/gdb/gdbarch-gen.c
@@ -260,6 +260,7 @@ struct gdbarch
gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags;
gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes;
+ gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr;
};
/* Create a new ``struct gdbarch'' based on information provided by
@@ -531,6 +532,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of get_pc_address_flags, invalid_p == 0. */
/* Skip verify of read_core_file_mappings, invalid_p == 0. */
/* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */
+ /* Skip verify of shadow_stack_push, has predicate. */
if (!log.empty ())
internal_error (_("verify_gdbarch: the following are invalid ...%s"),
log.c_str ());
@@ -1396,6 +1398,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: use_target_description_from_corefile_notes = <%s>\n",
host_address_to_string (gdbarch->use_target_description_from_corefile_notes));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_shadow_stack_push_p() = %d\n",
+ gdbarch_shadow_stack_push_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: shadow_stack_push = <%s>\n",
+ host_address_to_string (gdbarch->shadow_stack_push));
if (gdbarch->dump_tdep != NULL)
gdbarch->dump_tdep (gdbarch, file);
}
@@ -5507,3 +5515,27 @@ set_gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch,
{
gdbarch->use_target_description_from_corefile_notes = use_target_description_from_corefile_notes;
}
+
+bool
+gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->shadow_stack_push != NULL;
+}
+
+void
+gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->shadow_stack_push != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_shadow_stack_push called\n");
+ gdbarch->shadow_stack_push (gdbarch, new_addr);
+}
+
+void
+set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch,
+ gdbarch_shadow_stack_push_ftype shadow_stack_push)
+{
+ gdbarch->shadow_stack_push = shadow_stack_push;
+}
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index 9fda85f860f..ff14a3666b9 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -1778,3 +1778,17 @@ extern void set_gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, gdbarc
typedef bool (gdbarch_use_target_description_from_corefile_notes_ftype) (struct gdbarch *gdbarch, struct bfd *corefile_bfd);
extern bool gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, struct bfd *corefile_bfd);
extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbarch *gdbarch, gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes);
+
+/* Some targets support special hardware-assisted control-flow protection
+ technologies. For example, Intel's Control-flow Enforcement Technology (CET)
+ provides a shadow stack and indirect branch tracking.
+ To enable inferior calls the function shadow_stack_push has to be provided.
+
+ Push the address NEW_ADDR on the shadow stack and update the shadow stack
+ pointer. */
+
+extern bool gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_shadow_stack_push_ftype) (struct gdbarch *gdbarch, CORE_ADDR new_addr);
+extern void gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr);
+extern void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stack_push_ftype *shadow_stack_push);
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index cc7c6d8677b..52f265e8e0e 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -2815,3 +2815,19 @@ The corefile's bfd is passed through COREFILE_BFD.
predefault="default_use_target_description_from_corefile_notes",
invalid=False,
)
+
+Method(
+ comment="""
+Some targets support special hardware-assisted control-flow protection
+technologies. For example, Intel's Control-flow Enforcement Technology (CET)
+provides a shadow stack and indirect branch tracking.
+To enable inferior calls the function shadow_stack_push has to be provided.
+
+Push the address NEW_ADDR on the shadow stack and update the shadow stack
+pointer.
+""",
+ type="void",
+ name="shadow_stack_push",
+ params=[("CORE_ADDR", "new_addr")],
+ predicate=True,
+)
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 6399278c6ae..3a4f1e35a2f 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -1453,6 +1453,12 @@ call_function_by_hand_dummy (struct value *function,
bp_addr, args.size (), args.data (),
sp, return_method, struct_addr);
+ /* Push the return address of the inferior (bp_addr) on the shadow stack
+ and update the shadow stack pointer. As we don't execute a call
+ instruction to start the inferior we need to handle this manually. */
+ if (gdbarch_shadow_stack_push_p (gdbarch))
+ gdbarch_shadow_stack_push (gdbarch, bp_addr);
+
/* Set up a frame ID for the dummy frame so we can pass it to
set_momentary_breakpoint. We need to give the breakpoint a frame
ID so that the breakpoint code can correctly re-identify the
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (8 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support Schimpe, Christina
@ 2024-12-20 20:04 ` Schimpe, Christina
2025-02-06 3:34 ` Thiago Jung Bauermann
2024-12-20 20:05 ` [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer Schimpe, Christina
` (3 subsequent siblings)
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:04 UTC (permalink / raw)
To: gdb-patches
This patch enables inferior calls to support Intel's Control-Flow
Enforcement Technology (CET), which provides the shadow stack feature
for the x86 architecture.
Following the restriction of the linux kernel, enable inferior calls
for amd64 only.
---
gdb/amd64-linux-tdep.c | 89 +++++++++++++++++--
gdb/doc/gdb.texinfo | 29 ++++++
.../gdb.arch/amd64-shadow-stack-cmds.exp | 55 +++++++++++-
3 files changed, 164 insertions(+), 9 deletions(-)
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 895feac85e8..ef59cfcb7e4 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -1875,6 +1875,82 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
return (addr & amd64_linux_lam_untag_mask ());
}
+/* Read the shadow stack pointer register and return its value, if
+ possible. */
+
+static std::optional<CORE_ADDR>
+amd64_linux_get_shadow_stack_pointer (gdbarch *gdbarch)
+{
+ const i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+
+ if (tdep == nullptr || tdep->ssp_regnum < 0)
+ return {};
+
+ CORE_ADDR ssp;
+ regcache *regcache = get_thread_regcache (inferior_thread ());
+ if (regcache_raw_read_unsigned (regcache, tdep->ssp_regnum, &ssp)
+ != REG_VALID)
+ return {};
+
+ /* Starting with v6.6., the Linux kernel supports CET shadow stack.
+ Dependent on the target the ssp register can be invalid or nullptr
+ when shadow stack is supported by HW and the linux kernel but not
+ enabled for the current thread. */
+ if (ssp == 0x0)
+ return {};
+
+ return ssp;
+}
+
+/* Return the number of bytes required to update the shadow stack pointer
+ by one element. For x32 the shadow stack elements are still 64-bit
+ aligned. Thus, gdbarch_addr_bit cannot be used to compute the new
+ stack pointer. */
+
+static inline int
+amd64_linux_shadow_stack_element_size_aligned (gdbarch *gdbarch)
+{
+ const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
+ return (binfo->bits_per_word / binfo->bits_per_byte);
+}
+
+
+/* If shadow stack is enabled, push the address NEW_ADDR on the shadow
+ stack and increment the shadow stack pointer accordingly. */
+
+static void
+amd64_linux_shadow_stack_push (gdbarch *gdbarch, CORE_ADDR new_addr)
+{
+ std::optional<CORE_ADDR> ssp = amd64_linux_get_shadow_stack_pointer (gdbarch);
+ if (!ssp.has_value ())
+ return;
+
+ /* The shadow stack grows downwards. To push addresses on the stack,
+ we need to decrement SSP. */
+ const int element_size
+ = amd64_linux_shadow_stack_element_size_aligned (gdbarch);
+ const CORE_ADDR new_ssp = *ssp - element_size;
+
+ /* Starting with v6.6., the Linux kernel supports CET shadow stack.
+ Using /proc/PID/smaps we can only check if NEW_SSP points to shadow
+ stack memory. If it doesn't, we assume the stack is full. */
+ std::pair<CORE_ADDR, CORE_ADDR> memrange;
+ if (!linux_address_in_shadow_stack_mem_range (new_ssp, &memrange))
+ error (_("No space left on the shadow stack."));
+
+ /* On x86 there can be a shadow stack token at bit 63. For x32, the
+ address size is only 32 bit. Thus, we must use ELEMENT_SIZE (and
+ not gdbarch_addr_bit) to determine the width of the address to be
+ written. */
+ const bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ write_memory_unsigned_integer (new_ssp, element_size, byte_order,
+ (ULONGEST) new_addr);
+
+ i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
+ regcache *regcache = get_thread_regcache (inferior_thread ());
+ regcache_raw_write_unsigned (regcache, tdep->ssp_regnum, new_ssp);
+}
+
static value *
amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
void **this_cache, int regnum)
@@ -1900,14 +1976,9 @@ amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
if (linux_address_in_shadow_stack_mem_range (ssp, &range))
{
/* The shadow stack grows downwards. To compute the previous
- shadow stack pointer, we need to increment SSP.
- For x32 the shadow stack elements are still 64-bit aligned.
- Thus, we cannot use gdbarch_addr_bit to compute the new stack
- pointer. */
- const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
- const int bytes_per_word
- = (binfo->bits_per_word / binfo->bits_per_byte);
- CORE_ADDR new_ssp = ssp + bytes_per_word;
+ shadow stack pointer, we need to increment SSP. */
+ CORE_ADDR new_ssp
+ = ssp + amd64_linux_shadow_stack_element_size_aligned (gdbarch);
/* If NEW_SSP points to the end of or before (<=) the current
shadow stack memory range we consider NEW_SSP as valid (but
@@ -1995,6 +2066,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
set_gdbarch_remove_non_address_bits_watchpoint
(gdbarch, amd64_linux_remove_non_address_bits_watchpoint);
+
+ set_gdbarch_shadow_stack_push (gdbarch, amd64_linux_shadow_stack_push);
dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg);
}
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c6c6fcaa17f..4bed63cb0a1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -26836,6 +26836,35 @@ registers
@end itemize
+@subsubsection Intel @dfn{Control-flow Enforcement Technology} (CET).
+@cindex Intel Control-flow Enforcement Technology (CET).
+
+Control-flow Enforcement Technology (CET) provides two capabilities to defend
+against ``Return-oriented Programming'' and ``call/jmp-oriented
+programming'' style control-flow attacks:
+
+@itemize @bullet
+@item Shadow Stack:
+A shadow stack is a second stack for a program. It holds the return
+addresses pushed by the call instruction. The @code{RET} instruction pops the
+return addresses from both call and shadow stack. If the return addresses from
+the two stacks do not match, the processor signals a control protection
+exception.
+@item Indirect Branch Tracking (IBT):
+When IBT is enabled, the CPU implements a state machine that tracks indirect
+@code{JMP} and @code{CALL} instructions. The state machine can be either IDLE
+or WAIT_FOR_ENDBRANCH. In WAIT_FOR_ENDBRANCH state the next instruction in
+the program stream must be an @code{ENDBR} instruction, otherwise the
+processor signals a control protection exception.
+@end itemize
+
+Impact on Call/Print:
+Inferior calls in @value{GDBN} reset the current PC to the beginning of the
+function that is called. No call instruction is executed, but the @code{RET}
+instruction actually is. To avoid a control protection exception due to the
+missing return address on the shadow stack, @value{GDBN} pushes the new return
+address to the shadow stack and updates the shadow stack pointer.
+
@node Alpha
@subsection Alpha
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
index 17f32ce3964..df654f9db5d 100644
--- a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
@@ -13,12 +13,29 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# Test shadow stack enabling for frame level update and the return command.
+# Test shadow stack enabling for frame level update, the return and the
+# call command.
+# As potential CET violations often only occur after resuming normal
+# execution, test normal program continuation after each return or call
+# command.
require allow_ssp_tests
standard_testfile amd64-shadow-stack.c
+proc restart_and_run_infcall_call2 {} {
+ global binfile
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+ set inside_infcall_str "The program being debugged stopped while in a function called from GDB"
+ gdb_breakpoint [ gdb_get_line_number "break call2" ]
+ gdb_continue_to_breakpoint "break call2" ".*break call2.*"
+ gdb_test "call (int) call2()" \
+ "Breakpoint \[0-9\]*, call2.*$inside_infcall_str.*"
+}
+
save_vars { ::env(GLIBC_TUNABLES) } {
append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
@@ -33,6 +50,42 @@ save_vars { ::env(GLIBC_TUNABLES) } {
return -1
}
+ with_test_prefix "test inferior call and continue" {
+ gdb_breakpoint [ gdb_get_line_number "break call1" ]
+ gdb_continue_to_breakpoint "break call1" ".*break call1.*"
+
+ gdb_test "call (int) call2()" "= 42"
+
+ gdb_continue_to_end
+ }
+
+ with_test_prefix "test return inside an inferior call" {
+ restart_and_run_infcall_call2
+
+ gdb_test "return" "\#0.*call2.*" \
+ "Test shadow stack return inside an inferior call" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+ }
+
+ with_test_prefix "test return 'above' an inferior call" {
+ restart_and_run_infcall_call2
+
+ gdb_test "frame 2" "call2 ().*" "move to frame 'above' inferior call"
+
+ gdb_test "return" "\#0.*call1.*" \
+ "Test shadow stack return 'above' an inferior call" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+
set call1_line [ gdb_get_line_number "break call1" ]
set call2_line [ gdb_get_line_number "break call2" ]
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (9 preceding siblings ...)
2024-12-20 20:04 ` [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls Schimpe, Christina
@ 2024-12-20 20:05 ` Schimpe, Christina
2025-01-28 20:27 ` Guinevere Larsen
2025-02-06 3:35 ` Thiago Jung Bauermann
2024-12-20 20:05 ` [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux Schimpe, Christina
` (2 subsequent siblings)
13 siblings, 2 replies; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:05 UTC (permalink / raw)
To: gdb-patches
This patch is required by the following commit.
---
gdb/arch-utils.c | 8 ++++++++
gdb/arch-utils.h | 5 +++++
gdb/gdbarch-gen.c | 22 ++++++++++++++++++++++
gdb/gdbarch-gen.h | 6 ++++++
gdb/gdbarch_components.py | 10 ++++++++++
5 files changed, 51 insertions(+)
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index a2ed2a2c011..3aedb3f2600 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -1218,6 +1218,14 @@ default_gdbarch_return_value
readbuf, writebuf);
}
+/* See arch-utils.h. */
+
+std::optional<CORE_ADDR>
+default_get_shadow_stack_pointer (gdbarch *gdbarch)
+{
+ return {};
+}
+
obstack *gdbarch_obstack (gdbarch *arch)
{
return &arch->obstack;
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index b59e2ad70c2..471be9c282d 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -325,4 +325,9 @@ extern enum return_value_convention default_gdbarch_return_value
struct regcache *regcache, struct value **read_value,
const gdb_byte *writebuf);
+/* Default implementation of gdbarch default_get_shadow_stack_pointer
+ method. */
+extern std::optional<CORE_ADDR> default_get_shadow_stack_pointer
+ (gdbarch *gdbarch);
+
#endif /* GDB_ARCH_UTILS_H */
diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c
index c33c476dfdb..72638f01ad7 100644
--- a/gdb/gdbarch-gen.c
+++ b/gdb/gdbarch-gen.c
@@ -261,6 +261,7 @@ struct gdbarch
gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes;
gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr;
+ gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer = default_get_shadow_stack_pointer;
};
/* Create a new ``struct gdbarch'' based on information provided by
@@ -533,6 +534,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of read_core_file_mappings, invalid_p == 0. */
/* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */
/* Skip verify of shadow_stack_push, has predicate. */
+ /* Skip verify of get_shadow_stack_pointer, invalid_p == 0. */
if (!log.empty ())
internal_error (_("verify_gdbarch: the following are invalid ...%s"),
log.c_str ());
@@ -1404,6 +1406,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: shadow_stack_push = <%s>\n",
host_address_to_string (gdbarch->shadow_stack_push));
+ gdb_printf (file,
+ "gdbarch_dump: get_shadow_stack_pointer = <%s>\n",
+ host_address_to_string (gdbarch->get_shadow_stack_pointer));
if (gdbarch->dump_tdep != NULL)
gdbarch->dump_tdep (gdbarch, file);
}
@@ -5539,3 +5544,20 @@ set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch,
{
gdbarch->shadow_stack_push = shadow_stack_push;
}
+
+std::optional<CORE_ADDR>
+gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_shadow_stack_pointer != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_get_shadow_stack_pointer called\n");
+ return gdbarch->get_shadow_stack_pointer (gdbarch);
+}
+
+void
+set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch,
+ gdbarch_get_shadow_stack_pointer_ftype get_shadow_stack_pointer)
+{
+ gdbarch->get_shadow_stack_pointer = get_shadow_stack_pointer;
+}
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index ff14a3666b9..ff511b4a9e0 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -1783,6 +1783,8 @@ extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbar
technologies. For example, Intel's Control-flow Enforcement Technology (CET)
provides a shadow stack and indirect branch tracking.
To enable inferior calls the function shadow_stack_push has to be provided.
+ The method get_shadow_stack_pointer has to be provided to enable displaced
+ stepping.
Push the address NEW_ADDR on the shadow stack and update the shadow stack
pointer. */
@@ -1792,3 +1794,7 @@ extern bool gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch);
typedef void (gdbarch_shadow_stack_push_ftype) (struct gdbarch *gdbarch, CORE_ADDR new_addr);
extern void gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr);
extern void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stack_push_ftype *shadow_stack_push);
+
+typedef std::optional<CORE_ADDR> (gdbarch_get_shadow_stack_pointer_ftype) (struct gdbarch *gdbarch);
+extern std::optional<CORE_ADDR> gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch);
+extern void set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer);
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index 52f265e8e0e..df70cb082a4 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -2822,6 +2822,8 @@ Some targets support special hardware-assisted control-flow protection
technologies. For example, Intel's Control-flow Enforcement Technology (CET)
provides a shadow stack and indirect branch tracking.
To enable inferior calls the function shadow_stack_push has to be provided.
+The method get_shadow_stack_pointer has to be provided to enable displaced
+stepping.
Push the address NEW_ADDR on the shadow stack and update the shadow stack
pointer.
@@ -2831,3 +2833,11 @@ pointer.
params=[("CORE_ADDR", "new_addr")],
predicate=True,
)
+
+Method(
+ type="std::optional<CORE_ADDR>",
+ name="get_shadow_stack_pointer",
+ params=[],
+ predefault="default_get_shadow_stack_pointer",
+ invalid=False,
+)
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux.
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (10 preceding siblings ...)
2024-12-20 20:05 ` [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer Schimpe, Christina
@ 2024-12-20 20:05 ` Schimpe, Christina
2024-12-20 20:14 ` Eli Zaretskii
2025-02-06 3:37 ` Thiago Jung Bauermann
2025-01-16 14:01 ` [PING][PATCH 00/12] Add CET shadow stack support Schimpe, Christina
2025-01-30 15:01 ` [PATCH " Guinevere Larsen
13 siblings, 2 replies; 72+ messages in thread
From: Schimpe, Christina @ 2024-12-20 20:05 UTC (permalink / raw)
To: gdb-patches
This patch enables displaced stepping to support Intel's Control-Flow
Enforcement Technology (CET), which provides the shadow stack feature
for the x86 architecture.
Following the restriction of the linux kernel, enable displaced stepping
for amd64 only.
If displaced stepping is active and the single stepped instruction is a
call instruction, the return address atop the stack is the address following
the copied instruction. However, to allow normal program execution it has
to be the address following the original instruction. Due to that reason,
the return address is corrected in amd64_displaced_step_fixup and
i386_displaced_step_fixup.
To avoid a control-protection exception if shadow stack is active,
the shadow stack top address must be corrected as well.
---
gdb/amd64-linux-tdep.c | 2 +
gdb/amd64-tdep.c | 12 +++
gdb/doc/gdb.texinfo | 11 ++-
gdb/i386-tdep.c | 12 +++
.../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 +++++++++++++++++++
5 files changed, 120 insertions(+), 1 deletion(-)
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index ef59cfcb7e4..a034d75dd52 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -2068,6 +2068,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
(gdbarch, amd64_linux_remove_non_address_bits_watchpoint);
set_gdbarch_shadow_stack_push (gdbarch, amd64_linux_shadow_stack_push);
+ set_gdbarch_get_shadow_stack_pointer (gdbarch,
+ amd64_linux_get_shadow_stack_pointer);
dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg);
}
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index a298333e70a..988a4cb285b 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -1747,6 +1747,18 @@ amd64_displaced_step_fixup (struct gdbarch *gdbarch,
displaced_debug_printf ("relocated return addr at %s to %s",
paddress (gdbarch, rsp),
paddress (gdbarch, retaddr));
+
+ /* If shadow stack is enabled, we need to correct the return address
+ on the shadow stack too. */
+ std::optional<CORE_ADDR> ssp = gdbarch_get_shadow_stack_pointer (gdbarch);
+ if (ssp.has_value ())
+ {
+ write_memory_unsigned_integer (*ssp, retaddr_len, byte_order,
+ retaddr);
+ displaced_debug_printf ("relocated shadow stack return addr at %s "
+ "to %s", paddress (gdbarch, *ssp),
+ paddress (gdbarch, retaddr));
+ }
}
}
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4bed63cb0a1..022c944ea5c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -26858,12 +26858,20 @@ the program stream must be an @code{ENDBR} instruction, otherwise the
processor signals a control protection exception.
@end itemize
-Impact on Call/Print:
+Impact on GDB commands:
+@itemize @bullet
+@item Call/Print:
Inferior calls in @value{GDBN} reset the current PC to the beginning of the
function that is called. No call instruction is executed, but the @code{RET}
instruction actually is. To avoid a control protection exception due to the
missing return address on the shadow stack, @value{GDBN} pushes the new return
address to the shadow stack and updates the shadow stack pointer.
+@item Step:
+With displaced stepping, @value{GDBN} may run an out of line copy of a call
+instruction. In this case, the wrong return address is pushed on the shadow
+stack. @value{GDBN} corrects this value to avoid a control protection
+exception. For more details on displaced stepping, see @ref{displaced-stepping}.
+@end itemize
@node Alpha
@subsection Alpha
@@ -41579,6 +41587,7 @@ GLOBAL Disassembler_2 (Matches current architecture)
@cindex out-of-line single-stepping
@item set displaced-stepping
@itemx show displaced-stepping
+@anchor{displaced-stepping}
Control whether or not @value{GDBN} will do @dfn{displaced stepping}
if the target supports it. Displaced stepping is a way to single-step
over breakpoints without removing them from the inferior, by executing
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index b338029d990..ec98b52c649 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -899,6 +899,18 @@ i386_displaced_step_fixup (struct gdbarch *gdbarch,
displaced_debug_printf ("relocated return addr at %s to %s",
paddress (gdbarch, esp),
paddress (gdbarch, retaddr));
+
+ /* If shadow stack is enabled, we need to correct the return address
+ on the shadow stack too. */
+ std::optional<CORE_ADDR> ssp = gdbarch_get_shadow_stack_pointer (gdbarch);
+ if (ssp.has_value ())
+ {
+ write_memory_unsigned_integer (*ssp, retaddr_len, byte_order,
+ retaddr);
+ displaced_debug_printf ("relocated shadow stack return addr at %s "
+ "to %s", paddress (gdbarch, *ssp),
+ paddress (gdbarch, retaddr));
+ }
}
}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
new file mode 100644
index 00000000000..493ca0100cb
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
@@ -0,0 +1,84 @@
+# Copyright 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test continue from call instructions with shadow stack and displaced
+# stepping being enabled.
+
+require allow_ssp_tests support_displaced_stepping
+
+standard_testfile amd64-shadow-stack.c
+
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ additional_flags="-fcf-protection=return"] } {
+ return -1
+ }
+
+ # Enable displaced stepping.
+ gdb_test_no_output "set displaced-stepping on"
+ gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*"
+
+ if { ![runto_main] } {
+ return -1
+ }
+
+ # Get the address of the call1 instruction.
+ set call1_addr -1
+ gdb_test_multiple "disassemble main" "" {
+ -re -wrap "($hex) <\\+($decimal)>:\\s*call\\s*0x.*<call1>.*" {
+ set call1_addr $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ if { $call1_addr == -1 } {
+ return -1
+ }
+
+ # Get the address of the call2 instruction.
+ set call2_addr -1
+ gdb_test_multiple "disassemble call1" "" {
+ -re -wrap "($hex) <\\+($decimal)>:\\s*call\\s*0x.*<call2>.*" {
+ set call2_addr $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ if { $call2_addr == -1 } {
+ return -1
+ }
+
+ gdb_test "break *$call1_addr" \
+ "Breakpoint $decimal at $hex.*" \
+ "break at the address of the call1 instruction"
+
+ gdb_test "break *$call2_addr" \
+ "Breakpoint $decimal at $hex.*" \
+ "break at the address of the call2 instruction"
+
+ gdb_test "continue" \
+ "Breakpoint $decimal, $call1_addr in main ().*" \
+ "continue until call1 instruction"
+
+ # Test continue from breakpoint at call1 and call2 instructions.
+ gdb_test "continue" \
+ "Breakpoint $decimal, $call2_addr in call1 ().*" \
+ "continue from call1 instruction"
+
+ gdb_continue_to_end "continue from call2 instruction"
+}
--
2.34.1
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux.
2024-12-20 20:05 ` [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux Schimpe, Christina
@ 2024-12-20 20:14 ` Eli Zaretskii
2025-01-02 9:04 ` Schimpe, Christina
2025-02-06 3:37 ` Thiago Jung Bauermann
1 sibling, 1 reply; 72+ messages in thread
From: Eli Zaretskii @ 2024-12-20 20:14 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
> From: "Schimpe, Christina" <christina.schimpe@intel.com>
> Date: Fri, 20 Dec 2024 20:05:01 +0000
>
> gdb/amd64-linux-tdep.c | 2 +
> gdb/amd64-tdep.c | 12 +++
> gdb/doc/gdb.texinfo | 11 ++-
> gdb/i386-tdep.c | 12 +++
> .../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 +++++++++++++++++++
> 5 files changed, 120 insertions(+), 1 deletion(-)
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
Thanks, the documentation part is okay.
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux.
2024-12-20 20:14 ` Eli Zaretskii
@ 2025-01-02 9:04 ` Schimpe, Christina
2025-01-02 9:15 ` Eli Zaretskii
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-02 9:04 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
Hi Eli,
Thanks a lot for your quick feedback.
Does your review apply to the documentation of the entire series or just to the patch
"gdb: Enable displaced stepping with shadow stack on amd64 linux." ?
Christina
> -----Original Message-----
> From: Eli Zaretskii <eliz@gnu.org>
> Sent: Friday, December 20, 2024 9:14 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on
> amd64 linux.
>
> > From: "Schimpe, Christina" <christina.schimpe@intel.com>
> > Date: Fri, 20 Dec 2024 20:05:01 +0000
> >
> > gdb/amd64-linux-tdep.c | 2 +
> > gdb/amd64-tdep.c | 12 +++
> > gdb/doc/gdb.texinfo | 11 ++-
> > gdb/i386-tdep.c | 12 +++
> > .../gdb.arch/amd64-shadow-stack-disp-step.exp | 84
> > +++++++++++++++++++
> > 5 files changed, 120 insertions(+), 1 deletion(-) create mode 100644
> > gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
>
> Thanks, the documentation part is okay.
>
> Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux.
2025-01-02 9:04 ` Schimpe, Christina
@ 2025-01-02 9:15 ` Eli Zaretskii
0 siblings, 0 replies; 72+ messages in thread
From: Eli Zaretskii @ 2025-01-02 9:15 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
> From: "Schimpe, Christina" <christina.schimpe@intel.com>
> CC: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
> Date: Thu, 2 Jan 2025 09:04:20 +0000
>
> Hi Eli,
>
> Thanks a lot for your quick feedback.
> Does your review apply to the documentation of the entire series or just to the patch
> "gdb: Enable displaced stepping with shadow stack on amd64 linux." ?
All of them.
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PING][PATCH 00/12] Add CET shadow stack support
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (11 preceding siblings ...)
2024-12-20 20:05 ` [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux Schimpe, Christina
@ 2025-01-16 14:01 ` Schimpe, Christina
2025-01-27 9:44 ` [PING*2][PATCH " Schimpe, Christina
2025-01-30 15:01 ` [PATCH " Guinevere Larsen
13 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-16 14:01 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
> -----Original Message-----
> From: Schimpe, Christina <christina.schimpe@intel.com>
> Sent: Friday, December 20, 2024 9:05 PM
> To: gdb-patches@sourceware.org
> Subject: [PATCH 00/12] Add CET shadow stack support
>
> Hi all,
>
> this is a series to add amd64 shadow stack support to GDB on linux.
> Shadow stack is part of the Control-flow Enforcement Technology (CET) by Intel.
>
> Intel's CET provides the two capabilities to defend against ROP/COP/JOP style
> control-flow subversion attacks: shadow stack and indirect branch tracking (IBT).
>
> While there is linux kernel support for CET shadow stack in userspace, there is no
> linux kernel support available for userspace IBT, yet.
> This series therefore focuses on CET shadow stack only.
>
> I am looking forward to your feedback!
>
> Regards,
> Christina
>
>
> Felix Willgerodt (1):
> gdb, bfd: amd64 linux coredump support with shadow stack.
>
> Schimpe, Christina (11):
> gdb, testsuite: Rename set_sanitizer_default to append_environment.
> gdbserver: Add optional runtime register set type.
> gdbserver: Add assert in x86_linux_read_description.
> gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
> gdb, gdbserver: Use xstate_bv for target description creation on x86.
> gdb, gdbserver: Add support of Intel shadow stack pointer register.
> gdb: Handle shadow stack pointer register unwinding for amd64 linux.
> gdb, gdbarch: Enable inferior calls for shadow stack support.
> gdb: Implement amd64 linux shadow stack support for inferior calls.
> gdb, gdbarch: Introduce gdbarch method to get the shadow stack
> pointer.
> gdb: Enable displaced stepping with shadow stack on amd64 linux.
>
> bfd/elf.c | 24 +++
> gdb/amd64-linux-nat.c | 17 ++
> gdb/amd64-linux-tdep.c | 197 +++++++++++++++++-
> gdb/amd64-tdep.c | 32 ++-
> gdb/amd64-tdep.h | 9 +-
> gdb/arch-utils.c | 8 +
> gdb/arch-utils.h | 5 +
> gdb/arch/amd64-linux-tdesc.c | 33 +--
> gdb/arch/amd64-linux-tdesc.h | 7 +-
> gdb/arch/amd64.c | 25 ++-
> gdb/arch/amd64.h | 10 +-
> gdb/arch/i386-linux-tdesc.c | 29 +--
> gdb/arch/i386-linux-tdesc.h | 5 +-
> gdb/arch/i386.c | 19 +-
> gdb/arch/i386.h | 8 +-
> gdb/arch/x86-linux-tdesc-features.c | 56 ++---
> gdb/arch/x86-linux-tdesc-features.h | 25 ++-
> gdb/doc/gdb.texinfo | 42 ++++
> gdb/features/Makefile | 2 +
> gdb/features/i386/32bit-ssp.c | 14 ++
> gdb/features/i386/32bit-ssp.xml | 11 +
> gdb/features/i386/64bit-ssp.c | 14 ++
> gdb/features/i386/64bit-ssp.xml | 11 +
> gdb/gdbarch-gen.c | 54 +++++
> gdb/gdbarch-gen.h | 20 ++
> gdb/gdbarch_components.py | 26 +++
> gdb/i386-tdep.c | 44 +++-
> gdb/i386-tdep.h | 11 +-
> gdb/infcall.c | 6 +
> gdb/linux-tdep.c | 47 +++++
> gdb/linux-tdep.h | 7 +
> gdb/nat/x86-gcc-cpuid.h | 153 +++++++++++---
> gdb/nat/x86-linux-tdesc.c | 20 +-
> gdb/nat/x86-linux-tdesc.h | 7 +-
> gdb/nat/x86-linux.c | 55 +++++
> gdb/nat/x86-linux.h | 4 +
> .../gdb.arch/amd64-shadow-stack-cmds.exp | 141 +++++++++++++
> .../gdb.arch/amd64-shadow-stack-corefile.exp | 50 +++++
> .../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 ++++++++
> gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 35 ++++
> gdb/testsuite/gdb.arch/amd64-ssp.exp | 50 +++++
> .../gdb.base/inline-frame-cycle-unwind.py | 4 +
> gdb/testsuite/gdb.base/libsegfault.exp | 2 +-
> .../gdb.threads/attach-slow-waitpid.exp | 2 +-
> gdb/testsuite/lib/gdb.exp | 77 ++++++-
> gdb/x86-linux-nat.c | 51 ++++-
> gdb/x86-linux-nat.h | 11 +
> gdb/x86-tdep.c | 22 ++
> gdb/x86-tdep.h | 9 +
> gdbserver/i387-fp.cc | 40 ++--
> gdbserver/linux-amd64-ipa.cc | 10 +-
> gdbserver/linux-i386-ipa.cc | 6 +-
> gdbserver/linux-low.cc | 40 ++--
> gdbserver/linux-low.h | 7 +-
> gdbserver/linux-x86-low.cc | 44 +++-
> gdbsupport/x86-xstate.h | 7 +-
> 56 files changed, 1537 insertions(+), 212 deletions(-) create mode 100644
> gdb/features/i386/32bit-ssp.c create mode 100644 gdb/features/i386/32bit-
> ssp.xml create mode 100644 gdb/features/i386/64bit-ssp.c create mode 100644
> gdb/features/i386/64bit-ssp.xml create mode 100644
> gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-
> step.exp
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack.c
> create mode 100644 gdb/testsuite/gdb.arch/amd64-ssp.exp
>
> --
> 2.34.1
>
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de
> Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
> Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
Kindly pinging for feedback.
Best Regards,
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PING*2][PATCH 00/12] Add CET shadow stack support
2025-01-16 14:01 ` [PING][PATCH 00/12] Add CET shadow stack support Schimpe, Christina
@ 2025-01-27 9:44 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-27 9:44 UTC (permalink / raw)
To: gdb-patches
> -----Original Message-----
> From: Schimpe, Christina
> Sent: Thursday, January 16, 2025 3:02 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: RE: [PING][PATCH 00/12] Add CET shadow stack support
>
> > -----Original Message-----
> > From: Schimpe, Christina <christina.schimpe@intel.com>
> > Sent: Friday, December 20, 2024 9:05 PM
> > To: gdb-patches@sourceware.org
> > Subject: [PATCH 00/12] Add CET shadow stack support
> >
> > Hi all,
> >
> > this is a series to add amd64 shadow stack support to GDB on linux.
> > Shadow stack is part of the Control-flow Enforcement Technology (CET) by Intel.
> >
> > Intel's CET provides the two capabilities to defend against
> > ROP/COP/JOP style control-flow subversion attacks: shadow stack and indirect
> branch tracking (IBT).
> >
> > While there is linux kernel support for CET shadow stack in userspace,
> > there is no linux kernel support available for userspace IBT, yet.
> > This series therefore focuses on CET shadow stack only.
> >
> > I am looking forward to your feedback!
> >
> > Regards,
> > Christina
> >
> >
> > Felix Willgerodt (1):
> > gdb, bfd: amd64 linux coredump support with shadow stack.
> >
> > Schimpe, Christina (11):
> > gdb, testsuite: Rename set_sanitizer_default to append_environment.
> > gdbserver: Add optional runtime register set type.
> > gdbserver: Add assert in x86_linux_read_description.
> > gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
> > gdb, gdbserver: Use xstate_bv for target description creation on x86.
> > gdb, gdbserver: Add support of Intel shadow stack pointer register.
> > gdb: Handle shadow stack pointer register unwinding for amd64 linux.
> > gdb, gdbarch: Enable inferior calls for shadow stack support.
> > gdb: Implement amd64 linux shadow stack support for inferior calls.
> > gdb, gdbarch: Introduce gdbarch method to get the shadow stack
> > pointer.
> > gdb: Enable displaced stepping with shadow stack on amd64 linux.
> >
> > bfd/elf.c | 24 +++
> > gdb/amd64-linux-nat.c | 17 ++
> > gdb/amd64-linux-tdep.c | 197 +++++++++++++++++-
> > gdb/amd64-tdep.c | 32 ++-
> > gdb/amd64-tdep.h | 9 +-
> > gdb/arch-utils.c | 8 +
> > gdb/arch-utils.h | 5 +
> > gdb/arch/amd64-linux-tdesc.c | 33 +--
> > gdb/arch/amd64-linux-tdesc.h | 7 +-
> > gdb/arch/amd64.c | 25 ++-
> > gdb/arch/amd64.h | 10 +-
> > gdb/arch/i386-linux-tdesc.c | 29 +--
> > gdb/arch/i386-linux-tdesc.h | 5 +-
> > gdb/arch/i386.c | 19 +-
> > gdb/arch/i386.h | 8 +-
> > gdb/arch/x86-linux-tdesc-features.c | 56 ++---
> > gdb/arch/x86-linux-tdesc-features.h | 25 ++-
> > gdb/doc/gdb.texinfo | 42 ++++
> > gdb/features/Makefile | 2 +
> > gdb/features/i386/32bit-ssp.c | 14 ++
> > gdb/features/i386/32bit-ssp.xml | 11 +
> > gdb/features/i386/64bit-ssp.c | 14 ++
> > gdb/features/i386/64bit-ssp.xml | 11 +
> > gdb/gdbarch-gen.c | 54 +++++
> > gdb/gdbarch-gen.h | 20 ++
> > gdb/gdbarch_components.py | 26 +++
> > gdb/i386-tdep.c | 44 +++-
> > gdb/i386-tdep.h | 11 +-
> > gdb/infcall.c | 6 +
> > gdb/linux-tdep.c | 47 +++++
> > gdb/linux-tdep.h | 7 +
> > gdb/nat/x86-gcc-cpuid.h | 153 +++++++++++---
> > gdb/nat/x86-linux-tdesc.c | 20 +-
> > gdb/nat/x86-linux-tdesc.h | 7 +-
> > gdb/nat/x86-linux.c | 55 +++++
> > gdb/nat/x86-linux.h | 4 +
> > .../gdb.arch/amd64-shadow-stack-cmds.exp | 141 +++++++++++++
> > .../gdb.arch/amd64-shadow-stack-corefile.exp | 50 +++++
> > .../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 ++++++++
> > gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 35 ++++
> > gdb/testsuite/gdb.arch/amd64-ssp.exp | 50 +++++
> > .../gdb.base/inline-frame-cycle-unwind.py | 4 +
> > gdb/testsuite/gdb.base/libsegfault.exp | 2 +-
> > .../gdb.threads/attach-slow-waitpid.exp | 2 +-
> > gdb/testsuite/lib/gdb.exp | 77 ++++++-
> > gdb/x86-linux-nat.c | 51 ++++-
> > gdb/x86-linux-nat.h | 11 +
> > gdb/x86-tdep.c | 22 ++
> > gdb/x86-tdep.h | 9 +
> > gdbserver/i387-fp.cc | 40 ++--
> > gdbserver/linux-amd64-ipa.cc | 10 +-
> > gdbserver/linux-i386-ipa.cc | 6 +-
> > gdbserver/linux-low.cc | 40 ++--
> > gdbserver/linux-low.h | 7 +-
> > gdbserver/linux-x86-low.cc | 44 +++-
> > gdbsupport/x86-xstate.h | 7 +-
> > 56 files changed, 1537 insertions(+), 212 deletions(-) create mode
> > 100644 gdb/features/i386/32bit-ssp.c create mode 100644
> > gdb/features/i386/32bit- ssp.xml create mode 100644
> > gdb/features/i386/64bit-ssp.c create mode 100644
> > gdb/features/i386/64bit-ssp.xml create mode 100644
> > gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> > create mode 100644
> > gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
> > create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-
> > step.exp
> > create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack.c
> > create mode 100644 gdb/testsuite/gdb.arch/amd64-ssp.exp
> >
> > --
> > 2.34.1
> >
> > Intel Deutschland GmbH
> > Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> > Tel: +49 89 99 8853-0, www.intel.de
> > Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon
> > Silva Chairperson of the Supervisory Board: Nicole Lau Registered
> > Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928
>
> Kindly pinging for feedback.
>
> Best Regards,
> Christina
Kindly pinging ^2.
Best Regards,
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
2024-12-20 20:04 ` [PATCH 02/12] gdbserver: Add optional runtime register set type Schimpe, Christina
@ 2025-01-28 13:35 ` Guinevere Larsen
2025-01-30 10:28 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-28 13:35 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> Some register sets can be activated and deactivated by the OS during the
> runtime of a process. One example register is the Intel CET shadow stack
> pointer. This adds a new type of register set to handle such cases. We
> shouldn't deactivate these regsets and should not show a warning if we
> fail to read them.
> ---
> gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
> gdbserver/linux-low.h | 7 ++++++-
> 2 files changed, 34 insertions(+), 13 deletions(-)
>
> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
> index 50ce2b44927..355b28d9fe4 100644
> --- a/gdbserver/linux-low.cc
> +++ b/gdbserver/linux-low.cc
> @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
> if (res < 0)
> {
> if (errno == EIO
> - || (errno == EINVAL && regset->type == OPTIONAL_REGS))
> + || (errno == EINVAL
> + && (regset->type == OPTIONAL_REGS
> + || regset->type == OPTIONAL_RUNTIME_REGS)))
> {
> /* If we get EIO on a regset, or an EINVAL and the regset is
> - optional, do not try it again for this process mode. */
> + optional, do not try it again for this process mode.
> + Even if the regset can be enabled at runtime it is safe
> + to deactivate the regset in case of EINVAL, as we know
> + the regset itself was the invalid argument of the ptrace
> + call. */
> disable_regset (regsets_info, regset);
I'm somewhat confused by this patch.
The commit message and other comments here say that
optional_runtime_regs shouldn't be disabled. However, in here, if we get
EINVAL we *will* disable the regset. Did you mean to use != instead of == ?
I'll be honest, I don't know enough about the regset subsystem to know
which is the correct option, I just think it has to be consistent.
--
Cheers,
Guinevere Larsen
She/Her/Hers
> }
> - else if (errno == ENODATA)
> + else if (errno == ENODATA
> + || (errno == ENODEV
> + && regset->type == OPTIONAL_RUNTIME_REGS)
> + || errno == ESRCH)
> {
> - /* ENODATA may be returned if the regset is currently
> - not "active". This can happen in normal operation,
> - so suppress the warning in this case. */
> - }
> - else if (errno == ESRCH)
> - {
> - /* At this point, ESRCH should mean the process is
> - already gone, in which case we simply ignore attempts
> - to read its registers. */
> + /* ENODATA or ENODEV may be returned if the regset is
> + currently not "active". For ENODEV we additionally check
> + if the register set is of type OPTIONAL_RUNTIME_REGS.
> + This can happen in normal operation, so suppress the
> + warning in this case.
> + ESRCH should mean the process is already gone at this
> + point, in which case we simply ignore attempts to read
> + its registers. */
> }
> else
> {
> @@ -5111,6 +5119,14 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
> optional, do not try it again for this process mode. */
> disable_regset (regsets_info, regset);
> }
> + else if (errno == ENODEV
> + && regset->type == OPTIONAL_RUNTIME_REGS)
> + {
> + /* If we get ENODEV on a regset and the regset can be
> + enabled at runtime try it again for this process mode.
> + This can happen in normal operation, so suppress the
> + warning in this case. */
> + }
> else if (errno == ESRCH)
> {
> /* At this point, ESRCH should mean the process is
> diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
> index 5be00b8c98c..da5aa26a993 100644
> --- a/gdbserver/linux-low.h
> +++ b/gdbserver/linux-low.h
> @@ -42,7 +42,12 @@ enum regset_type {
> GENERAL_REGS,
> FP_REGS,
> EXTENDED_REGS,
> - OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */
> + OPTIONAL_REGS, /* Do not error if the regset cannot be accessed.
> + Disable the regset instead. */
> + OPTIONAL_RUNTIME_REGS, /* Some optional regsets can only be accessed
> + dependent on the execution flow. For such
> + access errors don't show a warning and don't
> + disable the regset. */
> };
>
> /* The arch's regsets array initializer must be terminated with a NULL
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment.
2024-12-20 20:04 ` [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment Schimpe, Christina
@ 2025-01-28 13:45 ` Guinevere Larsen
2025-01-30 13:07 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-28 13:45 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> The procedure set_sanitizer_default has been used for the configuration
> of ASAN specific environment variables. However, it is actually a
> generic function. Rename it to append_environment so that its purpose
> is more clear.
I think this is a good change, but in that case we should also rename
set_sanitizer_1 and set_sanitizer. I think the conversion should be:
set_sanitizer -> append_environment
set_sanitizer_1 -> append_environment_1
set_sanitizer_default -> append_environment_default
Also, I can see that patch 12 (and maybe others) use the
append_environment call. If the user had already set GLIBC_TUNABLES, the
test wouldn't update the value if I understand the TCL code correctly.
Is that the expected outcome? If not, I would suggest the alternative of
renaming set_sanitizer_1 to append_environment, so that set_sanitizer*
can continue to work as is, and you can manually set the environment
variables in a more obvious way.
--
Cheers,
Guinevere Larsen
She/Her/Hers
> ---
> gdb/testsuite/gdb.base/libsegfault.exp | 2 +-
> gdb/testsuite/gdb.threads/attach-slow-waitpid.exp | 2 +-
> gdb/testsuite/lib/gdb.exp | 8 ++++----
> 3 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/gdb/testsuite/gdb.base/libsegfault.exp b/gdb/testsuite/gdb.base/libsegfault.exp
> index 2c16fe8932a..fb62bdb8746 100644
> --- a/gdb/testsuite/gdb.base/libsegfault.exp
> +++ b/gdb/testsuite/gdb.base/libsegfault.exp
> @@ -42,7 +42,7 @@ proc gdb_spawn_with_ld_preload {lib cmdline_opts} {
> # ASan runtime does not come first in initial library list; you should
> # either link runtime to your application or manually preload it with
> # LD_PRELOAD.
> - set_sanitizer_default ASAN_OPTIONS verify_asan_link_order 0
> + append_environment ASAN_OPTIONS verify_asan_link_order 0
>
> gdb_spawn_with_cmdline_opts $cmdline_opts
> }
> diff --git a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
> index 28d70daad8c..abe8d434558 100644
> --- a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
> +++ b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
> @@ -83,7 +83,7 @@ proc gdb_spawn_with_ld_preload {lib} {
> # ASan runtime does not come first in initial library list; you should
> # either link runtime to your application or manually preload it with
> # LD_PRELOAD.
> - set_sanitizer_default ASAN_OPTIONS verify_asan_link_order 0
> + append_environment ASAN_OPTIONS verify_asan_link_order 0
>
> gdb_start
> }
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 7ee2043f0f8..a86f534528c 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -76,11 +76,11 @@ proc set_sanitizer { env_var var_id val } {
>
> # Add VAR_ID=VAL to ENV_VAR, unless ENV_VAR already contains a VAR_ID setting.
>
> -proc set_sanitizer_default { env_var var_id val } {
> +proc append_environment { env_var var_id val } {
> set_sanitizer_1 $env_var $var_id $val 1
> }
>
> -set_sanitizer_default TSAN_OPTIONS suppressions \
> +append_environment TSAN_OPTIONS suppressions \
> $srcdir/../tsan-suppressions.txt
>
> # When using ThreadSanitizer we may run into the case that a race is detected,
> @@ -89,14 +89,14 @@ set_sanitizer_default TSAN_OPTIONS suppressions \
> # Try to prevent this by setting history_size to the maximum (7) by default.
> # See also the ThreadSanitizer docs (
> # https://github.com/google/sanitizers/wiki/ThreadSanitizerFlags ).
> -set_sanitizer_default TSAN_OPTIONS history_size 7
> +append_environment TSAN_OPTIONS history_size 7
>
> # If GDB is built with ASAN (and because there are leaks), it will output a
> # leak report when exiting as well as exit with a non-zero (failure) status.
> # This can affect tests that are sensitive to what GDB prints on stderr or its
> # exit status. Add `detect_leaks=0` to the ASAN_OPTIONS environment variable
> # (which will affect any spawned sub-process) to avoid this.
> -set_sanitizer_default ASAN_OPTIONS detect_leaks 0
> +append_environment ASAN_OPTIONS detect_leaks 0
>
> # List of procs to run in gdb_finish.
> set gdb_finish_hooks [list]
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2024-12-20 20:05 ` [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer Schimpe, Christina
@ 2025-01-28 20:27 ` Guinevere Larsen
2025-01-30 10:33 ` Luis Machado
2025-02-06 3:35 ` Thiago Jung Bauermann
1 sibling, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-28 20:27 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 12/20/24 5:05 PM, Schimpe, Christina wrote:
> This patch is required by the following commit.
> ---
Maybe others disagree (in which case go with their suggestion), but my
opinion is that, because you're only adding gdbarch functionality but no
one uses it yet, there's basically no chance this commit could
inadvertently break something, so it is fine to merge with the next one
where you make use of the feature.
If these are split, I would like to have some explanation as to why it
is required, but I imagine the explanation finds a better home in the
next commit anyway, which is another reason why I'd join both commits.
--
Cheers,
Guinevere Larsen
She/Her/Hers
> gdb/arch-utils.c | 8 ++++++++
> gdb/arch-utils.h | 5 +++++
> gdb/gdbarch-gen.c | 22 ++++++++++++++++++++++
> gdb/gdbarch-gen.h | 6 ++++++
> gdb/gdbarch_components.py | 10 ++++++++++
> 5 files changed, 51 insertions(+)
>
> diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
> index a2ed2a2c011..3aedb3f2600 100644
> --- a/gdb/arch-utils.c
> +++ b/gdb/arch-utils.c
> @@ -1218,6 +1218,14 @@ default_gdbarch_return_value
> readbuf, writebuf);
> }
>
> +/* See arch-utils.h. */
> +
> +std::optional<CORE_ADDR>
> +default_get_shadow_stack_pointer (gdbarch *gdbarch)
> +{
> + return {};
> +}
> +
> obstack *gdbarch_obstack (gdbarch *arch)
> {
> return &arch->obstack;
> diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
> index b59e2ad70c2..471be9c282d 100644
> --- a/gdb/arch-utils.h
> +++ b/gdb/arch-utils.h
> @@ -325,4 +325,9 @@ extern enum return_value_convention default_gdbarch_return_value
> struct regcache *regcache, struct value **read_value,
> const gdb_byte *writebuf);
>
> +/* Default implementation of gdbarch default_get_shadow_stack_pointer
> + method. */
> +extern std::optional<CORE_ADDR> default_get_shadow_stack_pointer
> + (gdbarch *gdbarch);
> +
> #endif /* GDB_ARCH_UTILS_H */
> diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c
> index c33c476dfdb..72638f01ad7 100644
> --- a/gdb/gdbarch-gen.c
> +++ b/gdb/gdbarch-gen.c
> @@ -261,6 +261,7 @@ struct gdbarch
> gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
> gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes;
> gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr;
> + gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer = default_get_shadow_stack_pointer;
> };
>
> /* Create a new ``struct gdbarch'' based on information provided by
> @@ -533,6 +534,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
> /* Skip verify of read_core_file_mappings, invalid_p == 0. */
> /* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */
> /* Skip verify of shadow_stack_push, has predicate. */
> + /* Skip verify of get_shadow_stack_pointer, invalid_p == 0. */
> if (!log.empty ())
> internal_error (_("verify_gdbarch: the following are invalid ...%s"),
> log.c_str ());
> @@ -1404,6 +1406,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
> gdb_printf (file,
> "gdbarch_dump: shadow_stack_push = <%s>\n",
> host_address_to_string (gdbarch->shadow_stack_push));
> + gdb_printf (file,
> + "gdbarch_dump: get_shadow_stack_pointer = <%s>\n",
> + host_address_to_string (gdbarch->get_shadow_stack_pointer));
> if (gdbarch->dump_tdep != NULL)
> gdbarch->dump_tdep (gdbarch, file);
> }
> @@ -5539,3 +5544,20 @@ set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch,
> {
> gdbarch->shadow_stack_push = shadow_stack_push;
> }
> +
> +std::optional<CORE_ADDR>
> +gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != NULL);
> + gdb_assert (gdbarch->get_shadow_stack_pointer != NULL);
> + if (gdbarch_debug >= 2)
> + gdb_printf (gdb_stdlog, "gdbarch_get_shadow_stack_pointer called\n");
> + return gdbarch->get_shadow_stack_pointer (gdbarch);
> +}
> +
> +void
> +set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch,
> + gdbarch_get_shadow_stack_pointer_ftype get_shadow_stack_pointer)
> +{
> + gdbarch->get_shadow_stack_pointer = get_shadow_stack_pointer;
> +}
> diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
> index ff14a3666b9..ff511b4a9e0 100644
> --- a/gdb/gdbarch-gen.h
> +++ b/gdb/gdbarch-gen.h
> @@ -1783,6 +1783,8 @@ extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbar
> technologies. For example, Intel's Control-flow Enforcement Technology (CET)
> provides a shadow stack and indirect branch tracking.
> To enable inferior calls the function shadow_stack_push has to be provided.
> + The method get_shadow_stack_pointer has to be provided to enable displaced
> + stepping.
>
> Push the address NEW_ADDR on the shadow stack and update the shadow stack
> pointer. */
> @@ -1792,3 +1794,7 @@ extern bool gdbarch_shadow_stack_push_p (struct gdbarch *gdbarch);
> typedef void (gdbarch_shadow_stack_push_ftype) (struct gdbarch *gdbarch, CORE_ADDR new_addr);
> extern void gdbarch_shadow_stack_push (struct gdbarch *gdbarch, CORE_ADDR new_addr);
> extern void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stack_push_ftype *shadow_stack_push);
> +
> +typedef std::optional<CORE_ADDR> (gdbarch_get_shadow_stack_pointer_ftype) (struct gdbarch *gdbarch);
> +extern std::optional<CORE_ADDR> gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch);
> +extern void set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer);
> diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
> index 52f265e8e0e..df70cb082a4 100644
> --- a/gdb/gdbarch_components.py
> +++ b/gdb/gdbarch_components.py
> @@ -2822,6 +2822,8 @@ Some targets support special hardware-assisted control-flow protection
> technologies. For example, Intel's Control-flow Enforcement Technology (CET)
> provides a shadow stack and indirect branch tracking.
> To enable inferior calls the function shadow_stack_push has to be provided.
> +The method get_shadow_stack_pointer has to be provided to enable displaced
> +stepping.
>
> Push the address NEW_ADDR on the shadow stack and update the shadow stack
> pointer.
> @@ -2831,3 +2833,11 @@ pointer.
> params=[("CORE_ADDR", "new_addr")],
> predicate=True,
> )
> +
> +Method(
> + type="std::optional<CORE_ADDR>",
> + name="get_shadow_stack_pointer",
> + params=[],
> + predefault="default_get_shadow_stack_pointer",
> + invalid=False,
> +)
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 02/12] gdbserver: Add optional runtime register set type.
2025-01-28 13:35 ` Guinevere Larsen
@ 2025-01-30 10:28 ` Schimpe, Christina
2025-01-30 13:53 ` Guinevere Larsen
2025-02-06 2:59 ` Thiago Jung Bauermann
0 siblings, 2 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 10:28 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Tuesday, January 28, 2025 2:35 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
>
> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> > Some register sets can be activated and deactivated by the OS during
> > the runtime of a process. One example register is the Intel CET
> > shadow stack pointer. This adds a new type of register set to handle
> > such cases. We shouldn't deactivate these regsets and should not show
> > a warning if we fail to read them.
> > ---
> > gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
> > gdbserver/linux-low.h | 7 ++++++-
> > 2 files changed, 34 insertions(+), 13 deletions(-)
> >
> > diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index
> > 50ce2b44927..355b28d9fe4 100644
> > --- a/gdbserver/linux-low.cc
> > +++ b/gdbserver/linux-low.cc
> > @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct
> regsets_info *regsets_info,
> > if (res < 0)
> > {
> > if (errno == EIO
> > - || (errno == EINVAL && regset->type == OPTIONAL_REGS))
> > + || (errno == EINVAL
> > + && (regset->type == OPTIONAL_REGS
> > + || regset->type == OPTIONAL_RUNTIME_REGS)))
> > {
> > /* If we get EIO on a regset, or an EINVAL and the regset is
> > - optional, do not try it again for this process mode. */
> > + optional, do not try it again for this process mode.
> > + Even if the regset can be enabled at runtime it is safe
> > + to deactivate the regset in case of EINVAL, as we know
> > + the regset itself was the invalid argument of the ptrace
> > + call. */
> > disable_regset (regsets_info, regset);
>
> I'm somewhat confused by this patch.
>
> The commit message and other comments here say that optional_runtime_regs
> shouldn't be disabled. However, in here, if we get EINVAL we *will* disable the
> regset. Did you mean to use != instead of == ?
>
> I'll be honest, I don't know enough about the regset subsystem to know which is
> the correct option, I just think it has to be consistent.
>
Hi Guinevere,
Thank you for the review.
For the errno EINVAL we want to disable the regset, as we don't want to call ptrace
using NT_X86_SHSTK again. This specific errno can happen if the kernel does not
support ptrace using NT_X86_SHSTK (older linux kernels). I tried to explain that here:
> > + Even if the regset can be enabled at runtime it is safe
> > + to deactivate the regset in case of EINVAL, as we know
> > + the regset itself was the invalid argument of the ptrace
> > + call. */
In case shadow stack is just not active but supported by the kernel we see
ENODEV and we don't disable the regset, which I explained in another
comment for the corresponding code area:
/* ENODATA or ENODEV may be returned if the regset is
currently not "active". For ENODEV we additionally check
if the register set is of type OPTIONAL_RUNTIME_REGS.
This can happen in normal operation, so suppress the
warning in this case.
I didn't want to be too specific here to make the commit generic.
Is there something I could add to make it more understandable or maybe
there is just some information missing in the commit message?
BR,
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-01-28 20:27 ` Guinevere Larsen
@ 2025-01-30 10:33 ` Luis Machado
2025-01-30 12:34 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Luis Machado @ 2025-01-30 10:33 UTC (permalink / raw)
To: Guinevere Larsen, Schimpe, Christina, gdb-patches
On 1/28/25 20:27, Guinevere Larsen wrote:
> On 12/20/24 5:05 PM, Schimpe, Christina wrote:
>> This patch is required by the following commit.
>> ---
>
> Maybe others disagree (in which case go with their suggestion), but my opinion is that, because you're only adding gdbarch functionality but no one uses it yet, there's basically no chance this commit could inadvertently break something, so it is fine to merge with the next one where you make use of the feature.
>
> If these are split, I would like to have some explanation as to why it is required, but I imagine the explanation finds a better home in the next commit anyway, which is another reason why I'd join both commits.
>
As a counterpoint, I suppose it is fine to do it this way for simplicity of reviewing, as it is broken up into smaller bits. Things will potentially be pushed as part of a series anyway.
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-01-30 10:33 ` Luis Machado
@ 2025-01-30 12:34 ` Schimpe, Christina
2025-01-30 13:42 ` Guinevere Larsen
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 12:34 UTC (permalink / raw)
To: Luis Machado, Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Luis Machado <luis.machado@arm.com>
> Sent: Thursday, January 30, 2025 11:34 AM
> To: Guinevere Larsen <guinevere@redhat.com>; Schimpe, Christina
> <christina.schimpe@intel.com>; gdb-patches@sourceware.org
> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the
> shadow stack pointer.
>
> On 1/28/25 20:27, Guinevere Larsen wrote:
> > On 12/20/24 5:05 PM, Schimpe, Christina wrote:
> >> This patch is required by the following commit.
> >> ---
> >
> > Maybe others disagree (in which case go with their suggestion), but my opinion
> is that, because you're only adding gdbarch functionality but no one uses it yet,
> there's basically no chance this commit could inadvertently break something, so it
> is fine to merge with the next one where you make use of the feature.
> >
> > If these are split, I would like to have some explanation as to why it is required,
> but I imagine the explanation finds a better home in the next commit anyway,
> which is another reason why I'd join both commits.
> >
>
> As a counterpoint, I suppose it is fine to do it this way for simplicity of reviewing,
> as it is broken up into smaller bits. Things will potentially be pushed as part of a
> series anyway.
Thanks for the feedback!
In my opinion, splitting the commits simplifies the review, especially if the commits are bigger.
Also I thought it's good to keep target independent code separate.
For the commit " gdb, gdbarch: Enable inferior calls for shadow stack support.", for instance,
I do not have 2 commits for the gdbarch function and it's usage, as in this case the gdbarch
function is called in target independent code only. I only have the implementation in a separate
commit "gdb: Implement amd64 linux shadow stack support for inferior calls.".
But I understand Guinevere's suggestion here, especially because the commit that uses
gdbarch_get_shadow_stack_pointer is only called in a patch which isn't really too big to review.
So I have mixed feelings about that and would be happy about a guideline.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment.
2025-01-28 13:45 ` Guinevere Larsen
@ 2025-01-30 13:07 ` Schimpe, Christina
2025-01-30 14:27 ` Tom de Vries
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 13:07 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches; +Cc: Tom de Vries
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Tuesday, January 28, 2025 2:45 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to
> append_environment.
>
> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> > The procedure set_sanitizer_default has been used for the
> > configuration of ASAN specific environment variables. However, it is
> > actually a generic function. Rename it to append_environment so that
> > its purpose is more clear.
>
> I think this is a good change, but in that case we should also rename
> set_sanitizer_1 and set_sanitizer. I think the conversion should be:
>
> set_sanitizer -> append_environment
> set_sanitizer_1 -> append_environment_1
> set_sanitizer_default -> append_environment_default
>
> Also, I can see that patch 12 (and maybe others) use the append_environment
> call. If the user had already set GLIBC_TUNABLES, the test wouldn't update the
> value if I understand the TCL code correctly.
> Is that the expected outcome? If not, I would suggest the alternative of renaming
> set_sanitizer_1 to append_environment, so that set_sanitizer* can continue to
> work as is, and you can manually set the environment variables in a more obvious
> way.
Thank you for the feedback. Yes, if the environment variable is already configured we
don't configure it by calling set_sanitizer_default/append_environment_default, in
contrast to set_sanitizer_1. I think set_sanitizer_1 was introduced later, that's why I
probably missed it.
So I totally agree, we should rename all functions and your suggestion
> set_sanitizer -> append_environment
> set_sanitizer_1 -> append_environment_1
> set_sanitizer_default -> append_environment_default
makes sense to me.
This patch is actually independent of this series and wonder if I could post it separately, as I expect to merge it sooner then.
I am adding Tom to this conversation who introduced these procedures. Does the renaming as suggested above make sense to you?
Thanks!
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-01-30 12:34 ` Schimpe, Christina
@ 2025-01-30 13:42 ` Guinevere Larsen
0 siblings, 0 replies; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-30 13:42 UTC (permalink / raw)
To: Schimpe, Christina, Luis Machado, gdb-patches
On 1/30/25 9:34 AM, Schimpe, Christina wrote:
>> -----Original Message-----
>> From: Luis Machado <luis.machado@arm.com>
>> Sent: Thursday, January 30, 2025 11:34 AM
>> To: Guinevere Larsen <guinevere@redhat.com>; Schimpe, Christina
>> <christina.schimpe@intel.com>; gdb-patches@sourceware.org
>> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the
>> shadow stack pointer.
>>
>> On 1/28/25 20:27, Guinevere Larsen wrote:
>>> On 12/20/24 5:05 PM, Schimpe, Christina wrote:
>>>> This patch is required by the following commit.
>>>> ---
>>> Maybe others disagree (in which case go with their suggestion), but my opinion
>> is that, because you're only adding gdbarch functionality but no one uses it yet,
>> there's basically no chance this commit could inadvertently break something, so it
>> is fine to merge with the next one where you make use of the feature.
>>> If these are split, I would like to have some explanation as to why it is required,
>> but I imagine the explanation finds a better home in the next commit anyway,
>> which is another reason why I'd join both commits.
>> As a counterpoint, I suppose it is fine to do it this way for simplicity of reviewing,
>> as it is broken up into smaller bits. Things will potentially be pushed as part of a
>> series anyway.
> Thanks for the feedback!
>
> In my opinion, splitting the commits simplifies the review, especially if the commits are bigger.
> Also I thought it's good to keep target independent code separate.
>
> For the commit " gdb, gdbarch: Enable inferior calls for shadow stack support.", for instance,
> I do not have 2 commits for the gdbarch function and it's usage, as in this case the gdbarch
> function is called in target independent code only. I only have the implementation in a separate
> commit "gdb: Implement amd64 linux shadow stack support for inferior calls.".
>
> But I understand Guinevere's suggestion here, especially because the commit that uses
> gdbarch_get_shadow_stack_pointer is only called in a patch which isn't really too big to review.
>
> So I have mixed feelings about that and would be happy about a guideline.
Yeah having had the time to read patch 12, I do think they'd go best
together, but I don't know if there is any unified guidance on this.
Whatever you decide is fine, though, I don't have too strong an opinion
on this.
--
Cheers,
Guinevere Larsen
She/Her/Hers
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
2025-01-30 10:28 ` Schimpe, Christina
@ 2025-01-30 13:53 ` Guinevere Larsen
2025-01-30 17:43 ` Schimpe, Christina
2025-02-06 2:59 ` Thiago Jung Bauermann
1 sibling, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-30 13:53 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 1/30/25 7:28 AM, Schimpe, Christina wrote:
>> -----Original Message-----
>> From: Guinevere Larsen <guinevere@redhat.com>
>> Sent: Tuesday, January 28, 2025 2:35 PM
>> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
>> patches@sourceware.org
>> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
>>
>> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
>>> Some register sets can be activated and deactivated by the OS during
>>> the runtime of a process. One example register is the Intel CET
>>> shadow stack pointer. This adds a new type of register set to handle
>>> such cases. We shouldn't deactivate these regsets and should not show
>>> a warning if we fail to read them.
>>> ---
>>> gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
>>> gdbserver/linux-low.h | 7 ++++++-
>>> 2 files changed, 34 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index
>>> 50ce2b44927..355b28d9fe4 100644
>>> --- a/gdbserver/linux-low.cc
>>> +++ b/gdbserver/linux-low.cc
>>> @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct
>> regsets_info *regsets_info,
>>> if (res < 0)
>>> {
>>> if (errno == EIO
>>> - || (errno == EINVAL && regset->type == OPTIONAL_REGS))
>>> + || (errno == EINVAL
>>> + && (regset->type == OPTIONAL_REGS
>>> + || regset->type == OPTIONAL_RUNTIME_REGS)))
>>> {
>>> /* If we get EIO on a regset, or an EINVAL and the regset is
>>> - optional, do not try it again for this process mode. */
>>> + optional, do not try it again for this process mode.
>>> + Even if the regset can be enabled at runtime it is safe
>>> + to deactivate the regset in case of EINVAL, as we know
>>> + the regset itself was the invalid argument of the ptrace
>>> + call. */
>>> disable_regset (regsets_info, regset);
>> I'm somewhat confused by this patch.
>>
>> The commit message and other comments here say that optional_runtime_regs
>> shouldn't be disabled. However, in here, if we get EINVAL we *will* disable the
>> regset. Did you mean to use != instead of == ?
>>
>> I'll be honest, I don't know enough about the regset subsystem to know which is
>> the correct option, I just think it has to be consistent.
>>
> Hi Guinevere,
>
> Thank you for the review.
>
> For the errno EINVAL we want to disable the regset, as we don't want to call ptrace
> using NT_X86_SHSTK again. This specific errno can happen if the kernel does not
> support ptrace using NT_X86_SHSTK (older linux kernels). I tried to explain that here:
>
>>> + Even if the regset can be enabled at runtime it is safe
>>> + to deactivate the regset in case of EINVAL, as we know
>>> + the regset itself was the invalid argument of the ptrace
>>> + call. */
> In case shadow stack is just not active but supported by the kernel we see
> ENODEV and we don't disable the regset, which I explained in another
> comment for the corresponding code area:
>
> /* ENODATA or ENODEV may be returned if the regset is
> currently not "active". For ENODEV we additionally check
> if the register set is of type OPTIONAL_RUNTIME_REGS.
> This can happen in normal operation, so suppress the
> warning in this case.
>
> I didn't want to be too specific here to make the commit generic.
>
> Is there something I could add to make it more understandable or maybe
> there is just some information missing in the commit message?
Yeah, ok, so the commit message needs an update.
Maybe something like:
Some register sets can be activated and deactivated by the OS during the
runtime of a process. One example register is the Intel CET shadow stack
pointer. This adds a new type of register set to handle such cases. When
reading them, we shouldn't deactivate these regsets and should not show a
warning if they are deactivated, but should deactivate them if they are
unsupported by the kernel. That can be deciphered based on the error
returned by the ptrace call, if we fail to read the registered.
Or something similar.
I think it is important to explain in the commit message that one error
means "inactive" while other means "unsupported", so that in 5-10 years
we can look back at this commit and be sure the disable wasn't added
incorrectly.
--
Cheers,
Guinevere Larsen
She/Her/Hers
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment.
2025-01-30 13:07 ` Schimpe, Christina
@ 2025-01-30 14:27 ` Tom de Vries
2025-01-30 16:39 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Tom de Vries @ 2025-01-30 14:27 UTC (permalink / raw)
To: Schimpe, Christina, Guinevere Larsen, gdb-patches
On 1/30/25 14:07, Schimpe, Christina wrote:
>> -----Original Message-----
>> From: Guinevere Larsen <guinevere@redhat.com>
>> Sent: Tuesday, January 28, 2025 2:45 PM
>> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
>> patches@sourceware.org
>> Subject: Re: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to
>> append_environment.
>>
>> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
>>> The procedure set_sanitizer_default has been used for the
>>> configuration of ASAN specific environment variables. However, it is
>>> actually a generic function. Rename it to append_environment so that
>>> its purpose is more clear.
>>
>> I think this is a good change, but in that case we should also rename
>> set_sanitizer_1 and set_sanitizer. I think the conversion should be:
>>
>> set_sanitizer -> append_environment
>> set_sanitizer_1 -> append_environment_1
>> set_sanitizer_default -> append_environment_default
>>
>> Also, I can see that patch 12 (and maybe others) use the append_environment
>> call. If the user had already set GLIBC_TUNABLES, the test wouldn't update the
>> value if I understand the TCL code correctly.
>> Is that the expected outcome? If not, I would suggest the alternative of renaming
>> set_sanitizer_1 to append_environment, so that set_sanitizer* can continue to
>> work as is, and you can manually set the environment variables in a more obvious
>> way.
>
> Thank you for the feedback. Yes, if the environment variable is already configured we
> don't configure it by calling set_sanitizer_default/append_environment_default, in
> contrast to set_sanitizer_1. I think set_sanitizer_1 was introduced later, that's why I
> probably missed it.
>
> So I totally agree, we should rename all functions and your suggestion
>
>> set_sanitizer -> append_environment
>> set_sanitizer_1 -> append_environment_1
>> set_sanitizer_default -> append_environment_default
>
> makes sense to me.
>
> This patch is actually independent of this series and wonder if I could post it separately, as I expect to merge it sooner then.
> I am adding Tom to this conversation who introduced these procedures. Does the renaming as suggested above make sense to you?
>
Hi Christina,
yes, the renaming is fine.
I think it's not a bad idea to post this independently.
Thanks,
- Tom
> Thanks!
> Christina
> Intel Deutschland GmbH
> Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
> Tel: +49 89 99 8853-0, www.intel.de
> Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Office: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2024-12-20 20:04 ` [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux Schimpe, Christina
@ 2025-01-30 14:29 ` Guinevere Larsen
2025-01-30 16:11 ` Schimpe, Christina
2025-02-06 3:30 ` Thiago Jung Bauermann
1 sibling, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-30 14:29 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> Unwind the $pl3_ssp register.
> We now have an updated value for the shadow stack pointer when
> moving up or down the frame level. Note that $pl3_ssp can
> become unavailable when moving to a frame before the shadow
> stack enablement. In the example below, shadow stack is enabled
> in the function 'call1'. Thus, when moving to a frame level above
> the function, $pl3_ssp will become unavaiable.
> Following the restriction of the linux kernel, implement the unwinding
> for amd64 linux only.
>
> Before this patch:
> ~~~
> Breakpoint 1, call2 (j=3) at sample.c:44
> 44 return 42;
> (gdb) p $pl3_ssp
> $1 = (void *) 0x7ffff79ffff8
> (gdb) up
> 55 call2 (3);
> (gdb) p $pl3_ssp
> $2 = (void *) 0x7ffff79ffff8
> (gdb) up
> 68 call1 (43);
> (gdb) p $pl3_ssp
> $3 = (void *) 0x7ffff79ffff8
> ~~~
>
> After this patch:
> ~~~
> Breakpoint 1, call2 (j=3) at sample.c:44
> 44 return 42;
> (gdb) p $pl3_ssp
> $1 = (void *) 0x7ffff79ffff8
> (gdb) up
> 55 call2 (3);
> (gdb) p $pl3_ssp
> $2 = (void *) 0x7ffff7a00000
> (gdb) up
> 68 call1 (43i);
> (gdb) p $pl3_ssp
> $3 = <unavailable>
> ~~~
>
> As we now have an updated value for each selected frame, the
> return command is now enabled for shadow stack enabled programs, too.
>
> We therefore add a test for the return command and shadow stack support,
> and for an updated shadow stack pointer after a frame level change.
> ---
> gdb/amd64-linux-tdep.c | 69 +++++++++++++++
> gdb/linux-tdep.c | 47 ++++++++++
> gdb/linux-tdep.h | 7 ++
> .../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++
> gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
> 5 files changed, 224 insertions(+)
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
>
> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
> index 95f643b1217..895feac85e8 100644
> --- a/gdb/amd64-linux-tdep.c
> +++ b/gdb/amd64-linux-tdep.c
> @@ -45,6 +45,8 @@
> #include "arch/amd64-linux-tdesc.h"
> #include "inferior.h"
> #include "x86-tdep.h"
> +#include "dwarf2/frame.h"
> +#include "frame-unwind.h"
>
> /* The syscall's XML filename for i386. */
> #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
> @@ -1873,6 +1875,72 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
> return (addr & amd64_linux_lam_untag_mask ());
> }
>
> +static value *
> +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
> + void **this_cache, int regnum)
> +{
> + value *v = frame_unwind_got_register (this_frame, regnum, regnum);
> + gdb_assert (v != nullptr);
> +
> + gdbarch *gdbarch = get_frame_arch (this_frame);
> +
> + if (v->entirely_available () && !v->optimized_out ())
> + {
> + int size = register_size (gdbarch, regnum);
> + bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
> + size, byte_order);
> +
> + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> + Using /proc/PID/smaps we can only check if the current shadow
> + stack pointer SSP points to shadow stack memory. Only if this is
> + the case a valid previous shadow stack pointer can be
> + calculated. */
> + std::pair<CORE_ADDR, CORE_ADDR> range;
> + if (linux_address_in_shadow_stack_mem_range (ssp, &range))
> + {
> + /* The shadow stack grows downwards. To compute the previous
> + shadow stack pointer, we need to increment SSP.
> + For x32 the shadow stack elements are still 64-bit aligned.
> + Thus, we cannot use gdbarch_addr_bit to compute the new stack
> + pointer. */
> + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
> + const int bytes_per_word
> + = (binfo->bits_per_word / binfo->bits_per_byte);
In patch 10 of this series, you introduce
amd64_linux_shadow_stack_element_size_aligned to simplify this
calculation. is there any reason you didn't introduce it here?
--
Cheers,
Guinevere Larsen
She/Her/Hers
> + CORE_ADDR new_ssp = ssp + bytes_per_word;
> +
> + /* If NEW_SSP points to the end of or before (<=) the current
> + shadow stack memory range we consider NEW_SSP as valid (but
> + empty). */
> + if (new_ssp <= range.second)
> + return frame_unwind_got_address (this_frame, regnum, new_ssp);
> + }
> + }
> +
> + /* Return a value which is marked as unavailable in case we could not
> + calculate a valid previous shadow stack pointer. */
> + value *retval
> + = value::allocate_register (get_next_frame_sentinel_okay (this_frame),
> + regnum, register_type (gdbarch, regnum));
> + retval->mark_bytes_unavailable (0, retval->type ()->length ());
> + return retval;
> +}
> +
> +static void
> +amd64_init_reg (gdbarch *gdbarch, int regnum, dwarf2_frame_state_reg *reg,
> + const frame_info_ptr &this_frame)
> +{
> + if (regnum == gdbarch_pc_regnum (gdbarch))
> + reg->how = DWARF2_FRAME_REG_RA;
> + else if (regnum == gdbarch_sp_regnum (gdbarch))
> + reg->how = DWARF2_FRAME_REG_CFA;
> + else if (regnum == AMD64_PL3_SSP_REGNUM)
> + {
> + reg->how = DWARF2_FRAME_REG_FN;
> + reg->loc.fn = amd64_linux_dwarf2_prev_ssp;
> + }
> +}
> +
> static void
> amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
> int num_disp_step_buffers)
> @@ -1927,6 +1995,7 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
>
> set_gdbarch_remove_non_address_bits_watchpoint
> (gdbarch, amd64_linux_remove_non_address_bits_watchpoint);
> + dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg);
> }
>
> static void
> diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
> index d3452059ce2..3a20b12c3d7 100644
> --- a/gdb/linux-tdep.c
> +++ b/gdb/linux-tdep.c
> @@ -47,6 +47,7 @@
>
> #include <ctype.h>
> #include <unordered_map>
> +#include <algorithm>
>
> /* This enum represents the values that the user can choose when
> informing the Linux kernel about which memory mappings will be
> @@ -96,6 +97,10 @@ struct smaps_vmflags
> /* Memory map has memory tagging enabled. */
>
> unsigned int memory_tagging : 1;
> +
> + /* Memory map used for shadow stack. */
> +
> + unsigned int shadow_stack_memory : 1;
> };
>
> /* Data structure that holds the information contained in the
> @@ -537,6 +542,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
> v->shared_mapping = 1;
> else if (strcmp (s, "mt") == 0)
> v->memory_tagging = 1;
> + else if (strcmp (s, "ss") == 0)
> + v->shadow_stack_memory = 1;
> }
> }
>
> @@ -2744,6 +2751,46 @@ show_dump_excluded_mappings (struct ui_file *file, int from_tty,
> " flag is %s.\n"), value);
> }
>
> +/* See linux-tdep.h. */
> +
> +bool
> +linux_address_in_shadow_stack_mem_range
> + (CORE_ADDR addr, std::pair<CORE_ADDR, CORE_ADDR> *range)
> +{
> + if (!target_has_execution () || current_inferior ()->fake_pid_p)
> + return false;
> +
> + const int pid = current_inferior ()->pid;
> +
> + std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
> +
> + gdb::unique_xmalloc_ptr<char> data
> + = target_fileio_read_stralloc (nullptr, smaps_file.c_str ());
> +
> + if (data == nullptr)
> + return false;
> +
> + const std::vector<smaps_data> smaps
> + = parse_smaps_data (data.get (), std::move (smaps_file));
> +
> + auto find_addr_mem_range = [&addr] (const smaps_data &map)
> + {
> + bool addr_in_mem_range
> + = (addr >= map.start_address && addr < map.end_address);
> + return (addr_in_mem_range && map.vmflags.shadow_stack_memory);
> + };
> + auto it = std::find_if (smaps.begin (), smaps.end (), find_addr_mem_range);
> +
> + if (it != smaps.end ())
> + {
> + range->first = it->start_address;
> + range->second = it->end_address;
> + return true;
> + }
> +
> + return false;
> +}
> +
> /* To be called from the various GDB_OSABI_LINUX handlers for the
> various GNU/Linux architectures and machine types.
>
> diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
> index bf4220bf75b..97dcc75a79c 100644
> --- a/gdb/linux-tdep.h
> +++ b/gdb/linux-tdep.h
> @@ -117,4 +117,11 @@ extern CORE_ADDR linux_get_hwcap2 ();
> extern struct link_map_offsets *linux_ilp32_fetch_link_map_offsets ();
> extern struct link_map_offsets *linux_lp64_fetch_link_map_offsets ();
>
> +/* Returns true if ADDR belongs to a shadow stack memory range. If this
> + is the case, assign the shadow stack memory range to RANGE
> + [start_address, end_address). */
> +
> +extern bool linux_address_in_shadow_stack_mem_range
> + (CORE_ADDR addr, std::pair<CORE_ADDR, CORE_ADDR> *range);
> +
> #endif /* GDB_LINUX_TDEP_H */
> diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> new file mode 100644
> index 00000000000..17f32ce3964
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> @@ -0,0 +1,88 @@
> +# Copyright 2018-2024 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test shadow stack enabling for frame level update and the return command.
> +
> +require allow_ssp_tests
> +
> +standard_testfile amd64-shadow-stack.c
> +
> +save_vars { ::env(GLIBC_TUNABLES) } {
> +
> + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
> +
> + if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
> + {debug additional_flags="-fcf-protection=return"}] } {
> + return -1
> + }
> +
> + clean_restart ${binfile}
> + if { ![runto_main] } {
> + return -1
> + }
> +
> + set call1_line [ gdb_get_line_number "break call1" ]
> + set call2_line [ gdb_get_line_number "break call2" ]
> +
> + # Extract shadow stack pointer inside main, call1 and call2 function.
> + gdb_breakpoint $call1_line
> + gdb_breakpoint $call2_line
> + set ssp_main [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in main"]
> + gdb_continue_to_breakpoint "break call1" ".*break call1.*"
> + set ssp_call1 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call1"]
> + gdb_continue_to_breakpoint "break call2" ".*break call2.*"
> + set ssp_call2 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call2"]
> +
> + with_test_prefix "test frame level update" {
> + gdb_test "up" "call1.*" "move to frame 1"
> + gdb_test "print /x \$pl3_ssp" "= $ssp_call1" "check pl3_ssp of frame 1"
> + gdb_test "up" "main.*" "move to frame 2"
> + gdb_test "print /x \$pl3_ssp" "= $ssp_main" "check pl3_ssp of frame 2"
> + gdb_test "frame 0" "call2.*" "move to frame 0"
> + gdb_test "print /x \$pl3_ssp" "= $ssp_call2" "check pl3_ssp of frame 0"
> + }
> +
> + with_test_prefix "test return from current frame" {
> + gdb_test "return (int) 1" "#0.*call1.*" \
> + "Test shadow stack return from current frame" \
> + "Make.*return now\\? \\(y or n\\) " "y"
> +
> + # Potential CET violations often only occur after resuming normal execution.
> + # Therefore, it is important to test normal program continuation after
> + # testing the return command.
> + gdb_continue_to_end
> + }
> +
> + clean_restart ${binfile}
> + if { ![runto_main] } {
> + return -1
> + }
> +
> + with_test_prefix "test return from past frame" {
> + gdb_breakpoint $call2_line
> + gdb_continue_to_breakpoint "break call2" ".*break call2.*"
> +
> + gdb_test "frame 1" ".*in call1.*"
> +
> + gdb_test "return (int) 1" "#0.*main.*" \
> + "Test shadow stack return from past frame" \
> + "Make.*return now\\? \\(y or n\\) " "y"
> +
> + # Potential CET violations often only occur after resuming normal execution.
> + # Therefore, it is important to test normal program continuation after
> + # testing the return command.
> + gdb_continue_to_end
> + }
> +}
> diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
> index 643ef2d5f56..80389730bc2 100644
> --- a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
> +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
> @@ -15,8 +15,21 @@
> You should have received a copy of the GNU General Public License
> along with this program. If not, see <http://www.gnu.org/licenses/>. */
>
> +static int
> +call2 ()
> +{
> + return 42; /* break call2. */
> +}
> +
> +static int
> +call1 ()
> +{
> + return call2 (); /* break call1. */
> +}
> +
> int
> main ()
> {
> + call1 (); /* break main. */
> return 0;
> }
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86.
2024-12-20 20:04 ` [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86 Schimpe, Christina
@ 2025-01-30 14:51 ` Guinevere Larsen
2025-01-30 16:45 ` Schimpe, Christina
2025-02-06 3:09 ` Thiago Jung Bauermann
1 sibling, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-30 14:51 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> The XSAVE features set is organized in state components, which are a set
> of or parts of registers. So-called XSAVE-supported features are
I think the phrasing "are a set of or parts of registers" is a bit
confusing.
I would find it more readable if it said something like "are a set of
registers, or parts of registers".
> organized using state-component bitmaps, each bit corresonding to a
typo, corresponding.
> single state component.
>
> The SDM 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.
All this stuff is absolute magic to me, so I can't really give a review
on the code....
--
Cheers,
Guinevere Larsen
She/Her/Hers
> ---
> gdb/amd64-tdep.c | 14 ++++----
> gdb/amd64-tdep.h | 8 +++--
> gdb/arch/amd64-linux-tdesc.c | 33 ++++++++---------
> gdb/arch/amd64-linux-tdesc.h | 7 ++--
> gdb/arch/amd64.c | 15 ++++----
> gdb/arch/amd64.h | 10 ++++--
> gdb/arch/i386-linux-tdesc.c | 29 ++++++++-------
> gdb/arch/i386-linux-tdesc.h | 5 +--
> gdb/arch/i386.c | 15 ++++----
> gdb/arch/i386.h | 8 ++++-
> gdb/arch/x86-linux-tdesc-features.c | 55 +++++++++++++++--------------
> gdb/arch/x86-linux-tdesc-features.h | 25 +++++++------
> gdb/i386-tdep.c | 14 ++++----
> gdb/i386-tdep.h | 7 ++--
> gdb/nat/x86-linux-tdesc.c | 18 +++++-----
> gdb/nat/x86-linux-tdesc.h | 7 ++--
> gdb/x86-linux-nat.c | 11 ++++--
> gdbserver/i387-fp.cc | 40 ++++++++++-----------
> gdbserver/linux-amd64-ipa.cc | 10 +++---
> gdbserver/linux-i386-ipa.cc | 6 ++--
> gdbserver/linux-x86-low.cc | 9 +++--
> gdbsupport/x86-xstate.h | 4 ++-
> 22 files changed, 196 insertions(+), 154 deletions(-)
>
> diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
> index e03180b08af..37a2e3b03d4 100644
> --- a/gdb/amd64-tdep.c
> +++ b/gdb/amd64-tdep.c
> @@ -3353,23 +3353,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_mask, 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_mask & X86_XSTATE_AVX) ? 1 : 0]
> + [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0]
> + [(xstate_bv_mask & 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_mask, false,
> + false, segments);
>
> return *tdesc;
> }
> diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
> index 7439b6e2e20..e93e3931df3 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_MASK and SEGMENTS. */
> +
> +extern const struct target_desc *amd64_target_description
> + (uint64_t xstate_bv_mask, 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 e9c4a99806d..17dfcfeaee8 100644
> --- a/gdb/arch/amd64-linux-tdesc.c
> +++ b/gdb/arch/amd64-linux-tdesc.c
> @@ -26,41 +26,42 @@
> /* 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_mask, 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_mask 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_mask 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_mask value otherwise we might fail to find an existing
> + tdesc which has the same set of relevant bits set. */
> + xstate_bv_mask &= 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_mask);
> 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,
> - true, true));
> + target_desc_up tdesc (amd64_create_target_description (xstate_bv_mask,
> + is_x32, true, true));
> x86_linux_post_init_tdesc (tdesc.get (), true);
>
> /* 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 ();
> - tdesc_cache.emplace (xcr0, std::move (tdesc));
> + tdesc_cache.emplace (xstate_bv_mask, std::move (tdesc));
> return ptr;
> }
> diff --git a/gdb/arch/amd64-linux-tdesc.h b/gdb/arch/amd64-linux-tdesc.h
> index f6a424862bb..27a99efbe10 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_MASK
> + 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_mask, bool is_x32);
>
> #endif /* GDB_ARCH_AMD64_LINUX_TDESC_H */
> diff --git a/gdb/arch/amd64.c b/gdb/arch/amd64.c
> index 5fc9947d489..72bd96aff76 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 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_mask, 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_mask & X86_XSTATE_AVX)
> regnum = create_feature_i386_64bit_avx (tdesc.get (), regnum);
>
> - if (xcr0 & X86_XSTATE_AVX512)
> + if (xstate_bv_mask & X86_XSTATE_AVX512)
> regnum = create_feature_i386_64bit_avx512 (tdesc.get (), regnum);
>
> - if (xcr0 & X86_XSTATE_PKRU)
> + if (xstate_bv_mask & 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 1c7a2bb26e9..3ce1a5557b2 100644
> --- a/gdb/arch/amd64.h
> +++ b/gdb/arch/amd64.h
> @@ -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_MASK. 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_mask,
> + 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 9f12e59d214..bae8741b210 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_mask)
> {
> - /* 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_mask 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_MASK 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_MASK value otherwise we might
> + fail to find an existing tdesc which has the same set of relevant
> + bits set. */
> + xstate_bv_mask &= x86_linux_i386_xstate_bv_feature_mask ();
>
> - const auto it = i386_tdesc_cache.find (xcr0);
> + const auto it = i386_tdesc_cache.find (xstate_bv_mask);
> 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_mask, 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_mask, std::move (tdesc));
> return ptr;
> }
> diff --git a/gdb/arch/i386-linux-tdesc.h b/gdb/arch/i386-linux-tdesc.h
> index 4ecd674aa96..6970202ce4d 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_MASK. */
>
> -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_mask);
>
> #endif /* GDB_ARCH_I386_LINUX_TDESC_H */
> diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c
> index 2072eae88ad..4a39028a472 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 i386.h. */
>
> target_desc *
> -i386_create_target_description (uint64_t xcr0, bool is_linux, bool segments)
> +i386_create_target_description (uint64_t xstate_bv_mask, 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_mask & X86_XSTATE_X87)
> regnum = create_feature_i386_32bit_core (tdesc.get (), regnum);
>
> - if (xcr0 & X86_XSTATE_SSE)
> + if (xstate_bv_mask & 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_mask & X86_XSTATE_AVX)
> regnum = create_feature_i386_32bit_avx (tdesc.get (), regnum);
>
> - if (xcr0 & X86_XSTATE_AVX512)
> + if (xstate_bv_mask & X86_XSTATE_AVX512)
> regnum = create_feature_i386_32bit_avx512 (tdesc.get (), regnum);
>
> - if (xcr0 & X86_XSTATE_PKRU)
> + if (xstate_bv_mask & 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 1b5cc6e1095..89f8aa49b9d 100644
> --- a/gdb/arch/i386.h
> +++ b/gdb/arch/i386.h
> @@ -21,7 +21,13 @@
> #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_MASK. 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_mask,
> + 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 f6eb112f312..3f041ece6eb 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.
> + 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_mask
> + 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. */
> + only those xstate_bv_mask feature bits that are relevant, we can then
> + cache target descriptions based on the relevant feature bits. Two
> + xstate_bv_mask values might be different, but have the same relevant
> + feature bits. In this case we would expect the two xstate_bv_mask
> + 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_mask_to_tdesc_idx (uint64_t xstate_bv_mask)
> {
> /* 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_mask & 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_mask (int idx)
> {
> - uint64_t xcr0 = 0;
> + uint64_t xstate_bv_mask = 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_mask |= x86_linux_all_xstate_features[i].feature;
> }
>
> - return xcr0;
> + return xstate_bv_mask;
> }
>
> #endif /* IN_PROCESS_AGENT */
> diff --git a/gdb/arch/x86-linux-tdesc-features.h b/gdb/arch/x86-linux-tdesc-features.h
> index cf8351dea8e..a9dfdbc3068 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
> +/* Convert an XSTATE_BV_MASK value into an integer. XSTATE_BV_MASK 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_xcr0 to get back the original xcr0 value. */
> + x86_linux_tdesc_idx_to_xstate_bv_mask to get back the original mask. */
>
> -extern int x86_linux_xcr0_to_tdesc_idx (uint64_t xcr0);
> +
> +extern int x86_linux_xstate_bv_mask_to_tdesc_idx (uint64_t xstate_bv_mask);
>
> #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_mask_to_tdesc_idx) into an xstate_bv_mask
> + value which can then be used to create a target description.
> + The return mask 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_mask (int idx);
>
> #endif /* IN_PROCESS_AGENT */
>
> diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
> index a552a2bee8f..54aa1294917 100644
> --- a/gdb/i386-tdep.c
> +++ b/gdb/i386-tdep.c
> @@ -8899,23 +8899,23 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
>
> \f
>
> -/* 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_mask, 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_mask & X86_XSTATE_SSE) ? 1 : 0]
> + [(xstate_bv_mask & X86_XSTATE_AVX) ? 1 : 0]
> + [(xstate_bv_mask & X86_XSTATE_AVX512) ? 1 : 0]
> + [(xstate_bv_mask & 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_mask, false, segments);
>
> return *tdesc;
> }
> diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
> index 680eb027a04..3f990e71abf 100644
> --- a/gdb/i386-tdep.h
> +++ b/gdb/i386-tdep.h
> @@ -450,8 +450,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_MASK and SEGMENTS. */
> +extern const struct target_desc *i386_target_description
> + (uint64_t xstate_bv_mask, 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 1824f57c70f..c5eac277bfd 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 2a2d8697cbe..548f2f10b65 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 2afa04f6288..d1fece717a7 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 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);
> }
> \f
>
> diff --git a/gdbserver/i387-fp.cc b/gdbserver/i387-fp.cc
> index 0bf57a3aa5d..3e9e823827e 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<uint64_t *, x86_xsave_layout *>
> 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 c53758a7dbe..9450a2114e4 100644
> --- a/gdbserver/linux-amd64-ipa.cc
> +++ b/gdbserver/linux-amd64-ipa.cc
> @@ -170,7 +170,7 @@ supply_static_tracepoint_registers (struct regcache *regcache,
> const struct target_desc *
> get_ipa_tdesc (int idx)
> {
> - uint64_t xcr0 = x86_linux_tdesc_idx_to_xcr0 (idx);
> + uint64_t xstate_bv_mask = x86_linux_tdesc_idx_to_xstate_bv_mask (idx);
>
> #if defined __ILP32__
> bool is_x32 = true;
> @@ -178,7 +178,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_mask, is_x32);
> }
>
> /* Allocate buffer for the jump pads. The branch instruction has a
> @@ -247,9 +247,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_mask (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_mask (i), false);
> #endif
> }
> diff --git a/gdbserver/linux-i386-ipa.cc b/gdbserver/linux-i386-ipa.cc
> index 2b363271ab6..ec06f16a2bf 100644
> --- a/gdbserver/linux-i386-ipa.cc
> +++ b/gdbserver/linux-i386-ipa.cc
> @@ -251,9 +251,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_mask = x86_linux_tdesc_idx_to_xstate_bv_mask (idx);
>
> - return i386_linux_read_description (xcr0);
> + return i386_linux_read_description (xstate_bv_mask);
> }
>
> /* Allocate buffer for the jump pads. On i386, we can reach an arbitrary
> @@ -276,5 +276,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_mask (i));
> }
> diff --git a/gdbserver/linux-x86-low.cc b/gdbserver/linux-x86-low.cc
> index b023b34a0a4..4575ea2fdc0 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_mask_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_mask_to_tdesc_idx (*storage.first);
> }
>
> /* The linux target ops object. */
> diff --git a/gdbsupport/x86-xstate.h b/gdbsupport/x86-xstate.h
> index 45300b2c18d..76932c765a7 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
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 00/12] Add CET shadow stack support
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
` (12 preceding siblings ...)
2025-01-16 14:01 ` [PING][PATCH 00/12] Add CET shadow stack support Schimpe, Christina
@ 2025-01-30 15:01 ` Guinevere Larsen
2025-01-30 17:46 ` Schimpe, Christina
13 siblings, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-30 15:01 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> Hi all,
>
> this is a series to add amd64 shadow stack support to GDB on linux.
> Shadow stack is part of the Control-flow Enforcement Technology (CET) by
> Intel.
>
> Intel's CET provides the two capabilities to defend against ROP/COP/JOP
> style control-flow subversion attacks: shadow stack and indirect branch
> tracking (IBT).
>
> While there is linux kernel support for CET shadow stack in userspace,
> there is no linux kernel support available for userspace IBT, yet.
> This series therefore focuses on CET shadow stack only.
>
> I am looking forward to your feedback!
Hi Christina, thanks for the incredible work in this series!
I looked over all the patches, and sent all my comments inlined, the
other patches look alright to me. I don't know if I understand enough of
the code to give a review tag, and I don't have a machine with shadow
stack support to test the series, so I hope this series gets some
attention from global maintainers soon, I'd love to see this work merged!
--
Cheers,
Guinevere Larsen
She/Her/Hers
>
> Regards,
> Christina
>
>
> Felix Willgerodt (1):
> gdb, bfd: amd64 linux coredump support with shadow stack.
>
> Schimpe, Christina (11):
> gdb, testsuite: Rename set_sanitizer_default to append_environment.
> gdbserver: Add optional runtime register set type.
> gdbserver: Add assert in x86_linux_read_description.
> gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
> gdb, gdbserver: Use xstate_bv for target description creation on x86.
> gdb, gdbserver: Add support of Intel shadow stack pointer register.
> gdb: Handle shadow stack pointer register unwinding for amd64 linux.
> gdb, gdbarch: Enable inferior calls for shadow stack support.
> gdb: Implement amd64 linux shadow stack support for inferior calls.
> gdb, gdbarch: Introduce gdbarch method to get the shadow stack
> pointer.
> gdb: Enable displaced stepping with shadow stack on amd64 linux.
>
> bfd/elf.c | 24 +++
> gdb/amd64-linux-nat.c | 17 ++
> gdb/amd64-linux-tdep.c | 197 +++++++++++++++++-
> gdb/amd64-tdep.c | 32 ++-
> gdb/amd64-tdep.h | 9 +-
> gdb/arch-utils.c | 8 +
> gdb/arch-utils.h | 5 +
> gdb/arch/amd64-linux-tdesc.c | 33 +--
> gdb/arch/amd64-linux-tdesc.h | 7 +-
> gdb/arch/amd64.c | 25 ++-
> gdb/arch/amd64.h | 10 +-
> gdb/arch/i386-linux-tdesc.c | 29 +--
> gdb/arch/i386-linux-tdesc.h | 5 +-
> gdb/arch/i386.c | 19 +-
> gdb/arch/i386.h | 8 +-
> gdb/arch/x86-linux-tdesc-features.c | 56 ++---
> gdb/arch/x86-linux-tdesc-features.h | 25 ++-
> gdb/doc/gdb.texinfo | 42 ++++
> gdb/features/Makefile | 2 +
> gdb/features/i386/32bit-ssp.c | 14 ++
> gdb/features/i386/32bit-ssp.xml | 11 +
> gdb/features/i386/64bit-ssp.c | 14 ++
> gdb/features/i386/64bit-ssp.xml | 11 +
> gdb/gdbarch-gen.c | 54 +++++
> gdb/gdbarch-gen.h | 20 ++
> gdb/gdbarch_components.py | 26 +++
> gdb/i386-tdep.c | 44 +++-
> gdb/i386-tdep.h | 11 +-
> gdb/infcall.c | 6 +
> gdb/linux-tdep.c | 47 +++++
> gdb/linux-tdep.h | 7 +
> gdb/nat/x86-gcc-cpuid.h | 153 +++++++++++---
> gdb/nat/x86-linux-tdesc.c | 20 +-
> gdb/nat/x86-linux-tdesc.h | 7 +-
> gdb/nat/x86-linux.c | 55 +++++
> gdb/nat/x86-linux.h | 4 +
> .../gdb.arch/amd64-shadow-stack-cmds.exp | 141 +++++++++++++
> .../gdb.arch/amd64-shadow-stack-corefile.exp | 50 +++++
> .../gdb.arch/amd64-shadow-stack-disp-step.exp | 84 ++++++++
> gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 35 ++++
> gdb/testsuite/gdb.arch/amd64-ssp.exp | 50 +++++
> .../gdb.base/inline-frame-cycle-unwind.py | 4 +
> gdb/testsuite/gdb.base/libsegfault.exp | 2 +-
> .../gdb.threads/attach-slow-waitpid.exp | 2 +-
> gdb/testsuite/lib/gdb.exp | 77 ++++++-
> gdb/x86-linux-nat.c | 51 ++++-
> gdb/x86-linux-nat.h | 11 +
> gdb/x86-tdep.c | 22 ++
> gdb/x86-tdep.h | 9 +
> gdbserver/i387-fp.cc | 40 ++--
> gdbserver/linux-amd64-ipa.cc | 10 +-
> gdbserver/linux-i386-ipa.cc | 6 +-
> gdbserver/linux-low.cc | 40 ++--
> gdbserver/linux-low.h | 7 +-
> gdbserver/linux-x86-low.cc | 44 +++-
> gdbsupport/x86-xstate.h | 7 +-
> 56 files changed, 1537 insertions(+), 212 deletions(-)
> create mode 100644 gdb/features/i386/32bit-ssp.c
> create mode 100644 gdb/features/i386/32bit-ssp.xml
> create mode 100644 gdb/features/i386/64bit-ssp.c
> create mode 100644 gdb/features/i386/64bit-ssp.xml
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack.c
> create mode 100644 gdb/testsuite/gdb.arch/amd64-ssp.exp
>
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2025-01-30 14:29 ` Guinevere Larsen
@ 2025-01-30 16:11 ` Schimpe, Christina
2025-01-30 16:13 ` Guinevere Larsen
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 16:11 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Thursday, January 30, 2025 3:29 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding
> for amd64 linux.
>
> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> > Unwind the $pl3_ssp register.
> > We now have an updated value for the shadow stack pointer when moving
> > up or down the frame level. Note that $pl3_ssp can become unavailable
> > when moving to a frame before the shadow stack enablement. In the
> > example below, shadow stack is enabled in the function 'call1'. Thus,
> > when moving to a frame level above the function, $pl3_ssp will become
> > unavaiable.
> > Following the restriction of the linux kernel, implement the unwinding
> > for amd64 linux only.
> >
> > Before this patch:
> > ~~~
> > Breakpoint 1, call2 (j=3) at sample.c:44
> > 44 return 42;
> > (gdb) p $pl3_ssp
> > $1 = (void *) 0x7ffff79ffff8
> > (gdb) up
> > 55 call2 (3);
> > (gdb) p $pl3_ssp
> > $2 = (void *) 0x7ffff79ffff8
> > (gdb) up
> > 68 call1 (43);
> > (gdb) p $pl3_ssp
> > $3 = (void *) 0x7ffff79ffff8
> > ~~~
> >
> > After this patch:
> > ~~~
> > Breakpoint 1, call2 (j=3) at sample.c:44
> > 44 return 42;
> > (gdb) p $pl3_ssp
> > $1 = (void *) 0x7ffff79ffff8
> > (gdb) up
> > 55 call2 (3);
> > (gdb) p $pl3_ssp
> > $2 = (void *) 0x7ffff7a00000
> > (gdb) up
> > 68 call1 (43i);
> > (gdb) p $pl3_ssp
> > $3 = <unavailable>
> > ~~~
> >
> > As we now have an updated value for each selected frame, the return
> > command is now enabled for shadow stack enabled programs, too.
> >
> > We therefore add a test for the return command and shadow stack
> > support, and for an updated shadow stack pointer after a frame level change.
> > ---
> > gdb/amd64-linux-tdep.c | 69 +++++++++++++++
> > gdb/linux-tdep.c | 47 ++++++++++
> > gdb/linux-tdep.h | 7 ++
> > .../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++
> > gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
> > 5 files changed, 224 insertions(+)
> > create mode 100644
> > gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> >
> > diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index
> > 95f643b1217..895feac85e8 100644
> > --- a/gdb/amd64-linux-tdep.c
> > +++ b/gdb/amd64-linux-tdep.c
> > @@ -45,6 +45,8 @@
> > #include "arch/amd64-linux-tdesc.h"
> > #include "inferior.h"
> > #include "x86-tdep.h"
> > +#include "dwarf2/frame.h"
> > +#include "frame-unwind.h"
> >
> > /* The syscall's XML filename for i386. */
> > #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
> > @@ -1873,6 +1875,72 @@
> amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
> > return (addr & amd64_linux_lam_untag_mask ());
> > }
> >
> > +static value *
> > +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
> > + void **this_cache, int regnum) {
> > + value *v = frame_unwind_got_register (this_frame, regnum, regnum);
> > + gdb_assert (v != nullptr);
> > +
> > + gdbarch *gdbarch = get_frame_arch (this_frame);
> > +
> > + if (v->entirely_available () && !v->optimized_out ())
> > + {
> > + int size = register_size (gdbarch, regnum);
> > + bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> > + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
> > + size, byte_order);
> > +
> > + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> > + Using /proc/PID/smaps we can only check if the current shadow
> > + stack pointer SSP points to shadow stack memory. Only if this is
> > + the case a valid previous shadow stack pointer can be
> > + calculated. */
> > + std::pair<CORE_ADDR, CORE_ADDR> range;
> > + if (linux_address_in_shadow_stack_mem_range (ssp, &range))
> > + {
> > + /* The shadow stack grows downwards. To compute the previous
> > + shadow stack pointer, we need to increment SSP.
> > + For x32 the shadow stack elements are still 64-bit aligned.
> > + Thus, we cannot use gdbarch_addr_bit to compute the new stack
> > + pointer. */
> > + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
> > + const int bytes_per_word
> > + = (binfo->bits_per_word / binfo->bits_per_byte);
> In patch 10 of this series, you introduce
> amd64_linux_shadow_stack_element_size_aligned to simplify this calculation. is
> there any reason you didn't introduce it here?
Thanks a lot for looking at this.
The reason is that at this state of the series I only had one occurrence of this
particular code line and its comment. To avoid duplication I decided to make a
small function for it in patch 10, but before it seemed to introduce more
overhead. Would that make sense to you?
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2025-01-30 16:11 ` Schimpe, Christina
@ 2025-01-30 16:13 ` Guinevere Larsen
2025-01-30 16:40 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Guinevere Larsen @ 2025-01-30 16:13 UTC (permalink / raw)
To: Schimpe, Christina, gdb-patches
On 1/30/25 1:11 PM, Schimpe, Christina wrote:
>> -----Original Message-----
>> From: Guinevere Larsen <guinevere@redhat.com>
>> Sent: Thursday, January 30, 2025 3:29 PM
>> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
>> patches@sourceware.org
>> Subject: Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding
>> for amd64 linux.
>>
>> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
>>> Unwind the $pl3_ssp register.
>>> We now have an updated value for the shadow stack pointer when moving
>>> up or down the frame level. Note that $pl3_ssp can become unavailable
>>> when moving to a frame before the shadow stack enablement. In the
>>> example below, shadow stack is enabled in the function 'call1'. Thus,
>>> when moving to a frame level above the function, $pl3_ssp will become
>>> unavaiable.
>>> Following the restriction of the linux kernel, implement the unwinding
>>> for amd64 linux only.
>>>
>>> Before this patch:
>>> ~~~
>>> Breakpoint 1, call2 (j=3) at sample.c:44
>>> 44 return 42;
>>> (gdb) p $pl3_ssp
>>> $1 = (void *) 0x7ffff79ffff8
>>> (gdb) up
>>> 55 call2 (3);
>>> (gdb) p $pl3_ssp
>>> $2 = (void *) 0x7ffff79ffff8
>>> (gdb) up
>>> 68 call1 (43);
>>> (gdb) p $pl3_ssp
>>> $3 = (void *) 0x7ffff79ffff8
>>> ~~~
>>>
>>> After this patch:
>>> ~~~
>>> Breakpoint 1, call2 (j=3) at sample.c:44
>>> 44 return 42;
>>> (gdb) p $pl3_ssp
>>> $1 = (void *) 0x7ffff79ffff8
>>> (gdb) up
>>> 55 call2 (3);
>>> (gdb) p $pl3_ssp
>>> $2 = (void *) 0x7ffff7a00000
>>> (gdb) up
>>> 68 call1 (43i);
>>> (gdb) p $pl3_ssp
>>> $3 = <unavailable>
>>> ~~~
>>>
>>> As we now have an updated value for each selected frame, the return
>>> command is now enabled for shadow stack enabled programs, too.
>>>
>>> We therefore add a test for the return command and shadow stack
>>> support, and for an updated shadow stack pointer after a frame level change.
>>> ---
>>> gdb/amd64-linux-tdep.c | 69 +++++++++++++++
>>> gdb/linux-tdep.c | 47 ++++++++++
>>> gdb/linux-tdep.h | 7 ++
>>> .../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++
>>> gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
>>> 5 files changed, 224 insertions(+)
>>> create mode 100644
>>> gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
>>>
>>> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index
>>> 95f643b1217..895feac85e8 100644
>>> --- a/gdb/amd64-linux-tdep.c
>>> +++ b/gdb/amd64-linux-tdep.c
>>> @@ -45,6 +45,8 @@
>>> #include "arch/amd64-linux-tdesc.h"
>>> #include "inferior.h"
>>> #include "x86-tdep.h"
>>> +#include "dwarf2/frame.h"
>>> +#include "frame-unwind.h"
>>>
>>> /* The syscall's XML filename for i386. */
>>> #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
>>> @@ -1873,6 +1875,72 @@
>> amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
>>> return (addr & amd64_linux_lam_untag_mask ());
>>> }
>>>
>>> +static value *
>>> +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
>>> + void **this_cache, int regnum) {
>>> + value *v = frame_unwind_got_register (this_frame, regnum, regnum);
>>> + gdb_assert (v != nullptr);
>>> +
>>> + gdbarch *gdbarch = get_frame_arch (this_frame);
>>> +
>>> + if (v->entirely_available () && !v->optimized_out ())
>>> + {
>>> + int size = register_size (gdbarch, regnum);
>>> + bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>>> + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
>>> + size, byte_order);
>>> +
>>> + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
>>> + Using /proc/PID/smaps we can only check if the current shadow
>>> + stack pointer SSP points to shadow stack memory. Only if this is
>>> + the case a valid previous shadow stack pointer can be
>>> + calculated. */
>>> + std::pair<CORE_ADDR, CORE_ADDR> range;
>>> + if (linux_address_in_shadow_stack_mem_range (ssp, &range))
>>> + {
>>> + /* The shadow stack grows downwards. To compute the previous
>>> + shadow stack pointer, we need to increment SSP.
>>> + For x32 the shadow stack elements are still 64-bit aligned.
>>> + Thus, we cannot use gdbarch_addr_bit to compute the new stack
>>> + pointer. */
>>> + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
>>> + const int bytes_per_word
>>> + = (binfo->bits_per_word / binfo->bits_per_byte);
>> In patch 10 of this series, you introduce
>> amd64_linux_shadow_stack_element_size_aligned to simplify this calculation. is
>> there any reason you didn't introduce it here?
> Thanks a lot for looking at this.
>
> The reason is that at this state of the series I only had one occurrence of this
> particular code line and its comment. To avoid duplication I decided to make a
> small function for it in patch 10, but before it seemed to introduce more
> overhead. Would that make sense to you?
>
This makes sense, but in that case I think it's better to just create
this function at this point, so that code doesn't get created and
deleted unnecessarily.
--
Cheers,
Guinevere Larsen
She/Her/Hers
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment.
2025-01-30 14:27 ` Tom de Vries
@ 2025-01-30 16:39 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 16:39 UTC (permalink / raw)
To: Tom de Vries, Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Tom de Vries <tdevries@suse.de>
> Sent: Thursday, January 30, 2025 3:27 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; Guinevere Larsen
> <guinevere@redhat.com>; gdb-patches@sourceware.org
> Subject: Re: [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to
> append_environment.
>
> On 1/30/25 14:07, Schimpe, Christina wrote:
> >> -----Original Message-----
> >> From: Guinevere Larsen <guinevere@redhat.com>
> >> Sent: Tuesday, January 28, 2025 2:45 PM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> >> patches@sourceware.org
> >> Subject: Re: [PATCH 01/12] gdb, testsuite: Rename
> >> set_sanitizer_default to append_environment.
> >>
> >> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> >>> The procedure set_sanitizer_default has been used for the
> >>> configuration of ASAN specific environment variables. However, it
> >>> is actually a generic function. Rename it to append_environment so
> >>> that its purpose is more clear.
> >>
> >> I think this is a good change, but in that case we should also rename
> >> set_sanitizer_1 and set_sanitizer. I think the conversion should be:
> >>
> >> set_sanitizer -> append_environment
> >> set_sanitizer_1 -> append_environment_1 set_sanitizer_default ->
> >> append_environment_default
> >>
> >> Also, I can see that patch 12 (and maybe others) use the
> >> append_environment call. If the user had already set GLIBC_TUNABLES,
> >> the test wouldn't update the value if I understand the TCL code correctly.
> >> Is that the expected outcome? If not, I would suggest the alternative
> >> of renaming
> >> set_sanitizer_1 to append_environment, so that set_sanitizer* can
> >> continue to work as is, and you can manually set the environment
> >> variables in a more obvious way.
> >
> > Thank you for the feedback. Yes, if the environment variable is
> > already configured we don't configure it by calling
> > set_sanitizer_default/append_environment_default, in contrast to
> > set_sanitizer_1. I think set_sanitizer_1 was introduced later, that's why I
> probably missed it.
> >
> > So I totally agree, we should rename all functions and your suggestion
> >
> >> set_sanitizer -> append_environment
> >> set_sanitizer_1 -> append_environment_1 set_sanitizer_default ->
> >> append_environment_default
> >
> > makes sense to me.
> >
> > This patch is actually independent of this series and wonder if I could post it
> separately, as I expect to merge it sooner then.
> > I am adding Tom to this conversation who introduced these procedures. Does
> the renaming as suggested above make sense to you?
> >
>
> Hi Christina,
>
> yes, the renaming is fine.
>
> I think it's not a bad idea to post this independently.
>
> Thanks,
> - Tom
Thank you for the quick feedback. I posted the patch now separately:
https://sourceware.org/pipermail/gdb-patches/2025-January/215097.html
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2025-01-30 16:13 ` Guinevere Larsen
@ 2025-01-30 16:40 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 16:40 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Thursday, January 30, 2025 5:14 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding
> for amd64 linux.
>
> On 1/30/25 1:11 PM, Schimpe, Christina wrote:
> >> -----Original Message-----
> >> From: Guinevere Larsen <guinevere@redhat.com>
> >> Sent: Thursday, January 30, 2025 3:29 PM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> >> patches@sourceware.org
> >> Subject: Re: [PATCH 08/12] gdb: Handle shadow stack pointer register
> >> unwinding for amd64 linux.
> >>
> >> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> >>> Unwind the $pl3_ssp register.
> >>> We now have an updated value for the shadow stack pointer when
> >>> moving up or down the frame level. Note that $pl3_ssp can become
> >>> unavailable when moving to a frame before the shadow stack
> >>> enablement. In the example below, shadow stack is enabled in the
> >>> function 'call1'. Thus, when moving to a frame level above the
> >>> function, $pl3_ssp will become unavaiable.
> >>> Following the restriction of the linux kernel, implement the
> >>> unwinding for amd64 linux only.
> >>>
> >>> Before this patch:
> >>> ~~~
> >>> Breakpoint 1, call2 (j=3) at sample.c:44
> >>> 44 return 42;
> >>> (gdb) p $pl3_ssp
> >>> $1 = (void *) 0x7ffff79ffff8
> >>> (gdb) up
> >>> 55 call2 (3);
> >>> (gdb) p $pl3_ssp
> >>> $2 = (void *) 0x7ffff79ffff8
> >>> (gdb) up
> >>> 68 call1 (43);
> >>> (gdb) p $pl3_ssp
> >>> $3 = (void *) 0x7ffff79ffff8
> >>> ~~~
> >>>
> >>> After this patch:
> >>> ~~~
> >>> Breakpoint 1, call2 (j=3) at sample.c:44
> >>> 44 return 42;
> >>> (gdb) p $pl3_ssp
> >>> $1 = (void *) 0x7ffff79ffff8
> >>> (gdb) up
> >>> 55 call2 (3);
> >>> (gdb) p $pl3_ssp
> >>> $2 = (void *) 0x7ffff7a00000
> >>> (gdb) up
> >>> 68 call1 (43i);
> >>> (gdb) p $pl3_ssp
> >>> $3 = <unavailable>
> >>> ~~~
> >>>
> >>> As we now have an updated value for each selected frame, the return
> >>> command is now enabled for shadow stack enabled programs, too.
> >>>
> >>> We therefore add a test for the return command and shadow stack
> >>> support, and for an updated shadow stack pointer after a frame level change.
> >>> ---
> >>> gdb/amd64-linux-tdep.c | 69 +++++++++++++++
> >>> gdb/linux-tdep.c | 47 ++++++++++
> >>> gdb/linux-tdep.h | 7 ++
> >>> .../gdb.arch/amd64-shadow-stack-cmds.exp | 88
> +++++++++++++++++++
> >>> gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
> >>> 5 files changed, 224 insertions(+)
> >>> create mode 100644
> >>> gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> >>>
> >>> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index
> >>> 95f643b1217..895feac85e8 100644
> >>> --- a/gdb/amd64-linux-tdep.c
> >>> +++ b/gdb/amd64-linux-tdep.c
> >>> @@ -45,6 +45,8 @@
> >>> #include "arch/amd64-linux-tdesc.h"
> >>> #include "inferior.h"
> >>> #include "x86-tdep.h"
> >>> +#include "dwarf2/frame.h"
> >>> +#include "frame-unwind.h"
> >>>
> >>> /* The syscall's XML filename for i386. */
> >>> #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
> >>> @@ -1873,6 +1875,72 @@
> >> amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
> >>> return (addr & amd64_linux_lam_untag_mask ());
> >>> }
> >>>
> >>> +static value *
> >>> +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
> >>> + void **this_cache, int regnum) {
> >>> + value *v = frame_unwind_got_register (this_frame, regnum,
> >>> +regnum);
> >>> + gdb_assert (v != nullptr);
> >>> +
> >>> + gdbarch *gdbarch = get_frame_arch (this_frame);
> >>> +
> >>> + if (v->entirely_available () && !v->optimized_out ())
> >>> + {
> >>> + int size = register_size (gdbarch, regnum);
> >>> + bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> >>> + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
> >>> + size, byte_order);
> >>> +
> >>> + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> >>> + Using /proc/PID/smaps we can only check if the current shadow
> >>> + stack pointer SSP points to shadow stack memory. Only if this is
> >>> + the case a valid previous shadow stack pointer can be
> >>> + calculated. */
> >>> + std::pair<CORE_ADDR, CORE_ADDR> range;
> >>> + if (linux_address_in_shadow_stack_mem_range (ssp, &range))
> >>> + {
> >>> + /* The shadow stack grows downwards. To compute the previous
> >>> + shadow stack pointer, we need to increment SSP.
> >>> + For x32 the shadow stack elements are still 64-bit aligned.
> >>> + Thus, we cannot use gdbarch_addr_bit to compute the new stack
> >>> + pointer. */
> >>> + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
> >>> + const int bytes_per_word
> >>> + = (binfo->bits_per_word / binfo->bits_per_byte);
> >> In patch 10 of this series, you introduce
> >> amd64_linux_shadow_stack_element_size_aligned to simplify this
> >> calculation. is there any reason you didn't introduce it here?
> > Thanks a lot for looking at this.
> >
> > The reason is that at this state of the series I only had one
> > occurrence of this particular code line and its comment. To avoid
> > duplication I decided to make a small function for it in patch 10, but
> > before it seemed to introduce more overhead. Would that make sense to you?
> >
> This makes sense, but in that case I think it's better to just create this function at
> this point, so that code doesn't get created and deleted unnecessarily.
Mh right, that's also true. I will apply your feedback in the next version of this series.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86.
2025-01-30 14:51 ` Guinevere Larsen
@ 2025-01-30 16:45 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 16:45 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Thursday, January 30, 2025 3:52 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description
> creation on x86.
>
> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> > The XSAVE features set is organized in state components, which are a
> > set of or parts of registers. So-called XSAVE-supported features are
>
> I think the phrasing "are a set of or parts of registers" is a bit confusing.
>
> I would find it more readable if it said something like "are a set of registers, or
> parts of registers".
>
> > organized using state-component bitmaps, each bit corresonding to a
> typo, corresponding.
> > single state component.
> >
> > The SDM 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.
> All this stuff is absolute magic to me, so I can't really give a review on the code....
Thanks again for the review. 😊 I will apply your feedback for the commit message
in the next version of this series. But for now I will wait a couple more days to get
more feedback on this.
Christina
.
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 02/12] gdbserver: Add optional runtime register set type.
2025-01-30 13:53 ` Guinevere Larsen
@ 2025-01-30 17:43 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 17:43 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Thursday, January 30, 2025 2:54 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
>
> On 1/30/25 7:28 AM, Schimpe, Christina wrote:
> >> -----Original Message-----
> >> From: Guinevere Larsen <guinevere@redhat.com>
> >> Sent: Tuesday, January 28, 2025 2:35 PM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> >> patches@sourceware.org
> >> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
> >>
> >> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> >>> Some register sets can be activated and deactivated by the OS during
> >>> the runtime of a process. One example register is the Intel CET
> >>> shadow stack pointer. This adds a new type of register set to
> >>> handle such cases. We shouldn't deactivate these regsets and should
> >>> not show a warning if we fail to read them.
> >>> ---
> >>> gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
> >>> gdbserver/linux-low.h | 7 ++++++-
> >>> 2 files changed, 34 insertions(+), 13 deletions(-)
> >>>
> >>> diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index
> >>> 50ce2b44927..355b28d9fe4 100644
> >>> --- a/gdbserver/linux-low.cc
> >>> +++ b/gdbserver/linux-low.cc
> >>> @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct
> >> regsets_info *regsets_info,
> >>> if (res < 0)
> >>> {
> >>> if (errno == EIO
> >>> - || (errno == EINVAL && regset->type == OPTIONAL_REGS))
> >>> + || (errno == EINVAL
> >>> + && (regset->type == OPTIONAL_REGS
> >>> + || regset->type == OPTIONAL_RUNTIME_REGS)))
> >>> {
> >>> /* If we get EIO on a regset, or an EINVAL and the regset is
> >>> - optional, do not try it again for this process mode. */
> >>> + optional, do not try it again for this process mode.
> >>> + Even if the regset can be enabled at runtime it is safe
> >>> + to deactivate the regset in case of EINVAL, as we know
> >>> + the regset itself was the invalid argument of the ptrace
> >>> + call. */
> >>> disable_regset (regsets_info, regset);
> >> I'm somewhat confused by this patch.
> >>
> >> The commit message and other comments here say that
> >> optional_runtime_regs shouldn't be disabled. However, in here, if we
> >> get EINVAL we *will* disable the regset. Did you mean to use != instead of ==
> ?
> >>
> >> I'll be honest, I don't know enough about the regset subsystem to
> >> know which is the correct option, I just think it has to be consistent.
> >>
> > Hi Guinevere,
> >
> > Thank you for the review.
> >
> > For the errno EINVAL we want to disable the regset, as we don't want
> > to call ptrace using NT_X86_SHSTK again. This specific errno can
> > happen if the kernel does not support ptrace using NT_X86_SHSTK (older linux
> kernels). I tried to explain that here:
> >
> >>> + Even if the regset can be enabled at runtime it is safe
> >>> + to deactivate the regset in case of EINVAL, as we know
> >>> + the regset itself was the invalid argument of the ptrace
> >>> + call. */
> > In case shadow stack is just not active but supported by the kernel we
> > see ENODEV and we don't disable the regset, which I explained in
> > another comment for the corresponding code area:
> >
> > /* ENODATA or ENODEV may be returned if the regset is
> > currently not "active". For ENODEV we additionally check
> > if the register set is of type OPTIONAL_RUNTIME_REGS.
> > This can happen in normal operation, so suppress the
> > warning in this case.
> >
> > I didn't want to be too specific here to make the commit generic.
> >
> > Is there something I could add to make it more understandable or maybe
> > there is just some information missing in the commit message?
>
> Yeah, ok, so the commit message needs an update.
>
> Maybe something like:
>
> Some register sets can be activated and deactivated by the OS during the runtime
> of a process. One example register is the Intel CET shadow stack pointer. This
> adds a new type of register set to handle such cases. When reading them, we
> shouldn't deactivate these regsets and should not show a warning if they are
> deactivated, but should deactivate them if they are unsupported by the kernel.
> That can be deciphered based on the error returned by the ptrace call, if we fail to
> read the registered.
>
> Or something similar.
>
> I think it is important to explain in the commit message that one error means
> "inactive" while other means "unsupported", so that in 5-10 years we can look
> back at this commit and be sure the disable wasn't added incorrectly.
I agree, I should improve the commit message. I like your suggestion for a new version,
but I also noticed that we can probably deactivate the register set if we try to write them, too
(on a system with older kernel) or I don't remember why I didn't cover this scenario yet.
So I will double check and apply this in the next version of this series, where I will also enhance the
commit message.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 00/12] Add CET shadow stack support
2025-01-30 15:01 ` [PATCH " Guinevere Larsen
@ 2025-01-30 17:46 ` Schimpe, Christina
2025-02-04 3:57 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-01-30 17:46 UTC (permalink / raw)
To: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Guinevere Larsen <guinevere@redhat.com>
> Sent: Thursday, January 30, 2025 4:01 PM
> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> patches@sourceware.org
> Subject: Re: [PATCH 00/12] Add CET shadow stack support
>
> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> > Hi all,
> >
> > this is a series to add amd64 shadow stack support to GDB on linux.
> > Shadow stack is part of the Control-flow Enforcement Technology (CET)
> > by Intel.
> >
> > Intel's CET provides the two capabilities to defend against
> > ROP/COP/JOP style control-flow subversion attacks: shadow stack and
> > indirect branch tracking (IBT).
> >
> > While there is linux kernel support for CET shadow stack in userspace,
> > there is no linux kernel support available for userspace IBT, yet.
> > This series therefore focuses on CET shadow stack only.
> >
> > I am looking forward to your feedback!
>
> Hi Christina, thanks for the incredible work in this series!
>
> I looked over all the patches, and sent all my comments inlined, the other patches
> look alright to me. I don't know if I understand enough of the code to give a
> review tag, and I don't have a machine with shadow stack support to test the
> series, so I hope this series gets some attention from global maintainers soon, I'd
> love to see this work merged!
Hi Guinivere,
Thanks a lot for looking at this !
My plan is to wait until I receive bit more feedback for this series and until patch #1 is merged,
which I posted now separately.
Best Regards,
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 00/12] Add CET shadow stack support
2025-01-30 17:46 ` Schimpe, Christina
@ 2025-02-04 3:57 ` Thiago Jung Bauermann
2025-02-04 9:40 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-04 3:57 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: Guinevere Larsen, gdb-patches
Hello Christina,
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Guinevere Larsen <guinevere@redhat.com>
>> Sent: Thursday, January 30, 2025 4:01 PM
>> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
>> patches@sourceware.org
>> Subject: Re: [PATCH 00/12] Add CET shadow stack support
>>
>> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
>> > Hi all,
>> >
>> > this is a series to add amd64 shadow stack support to GDB on linux.
>> > Shadow stack is part of the Control-flow Enforcement Technology (CET)
>> > by Intel.
>> >
>> > Intel's CET provides the two capabilities to defend against
>> > ROP/COP/JOP style control-flow subversion attacks: shadow stack and
>> > indirect branch tracking (IBT).
>> >
>> > While there is linux kernel support for CET shadow stack in userspace,
>> > there is no linux kernel support available for userspace IBT, yet.
>> > This series therefore focuses on CET shadow stack only.
>> >
>> > I am looking forward to your feedback!
>>
>> Hi Christina, thanks for the incredible work in this series!
>>
>> I looked over all the patches, and sent all my comments inlined, the other patches
>> look alright to me. I don't know if I understand enough of the code to give a
>> review tag, and I don't have a machine with shadow stack support to test the
>> series, so I hope this series gets some attention from global maintainers soon, I'd
>> love to see this work merged!
>
> Hi Guinivere,
>
> Thanks a lot for looking at this !
>
> My plan is to wait until I receive bit more feedback for this series
> and until patch #1 is merged, which I posted now separately.
I'm almost finished reviewing this patch series. I think I'll be able to
send some review comments tomorrow.
In the meantime, one question: do you still plan to add a "bt -shadow"
command, or any other shadow stack related command as discussed in the
thread below?
https://inbox.sourceware.org/gdb/SN7PR11MB7638DE1337F8F0F0282EBD56F996A@SN7PR11MB7638.namprd11.prod.outlook.com/
I ask because for AArch64 Guarded Control Stack (which is equivalent to
Intel Shadow Stack) I'll need to add commands to enable/disable shadow
stacks, and also to see which GCS-specific features are enabled and
locked in the inferior.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 00/12] Add CET shadow stack support
2025-02-04 3:57 ` Thiago Jung Bauermann
@ 2025-02-04 9:40 ` Schimpe, Christina
2025-02-06 3:44 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-04 9:40 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Tuesday, February 4, 2025 4:58 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: Guinevere Larsen <guinevere@redhat.com>; gdb-patches@sourceware.org
> Subject: Re: [PATCH 00/12] Add CET shadow stack support
>
>
> Hello Christina,
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> >> -----Original Message-----
> >> From: Guinevere Larsen <guinevere@redhat.com>
> >> Sent: Thursday, January 30, 2025 4:01 PM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> >> patches@sourceware.org
> >> Subject: Re: [PATCH 00/12] Add CET shadow stack support
> >>
> >> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> >> > Hi all,
> >> >
> >> > this is a series to add amd64 shadow stack support to GDB on linux.
> >> > Shadow stack is part of the Control-flow Enforcement Technology
> >> > (CET) by Intel.
> >> >
> >> > Intel's CET provides the two capabilities to defend against
> >> > ROP/COP/JOP style control-flow subversion attacks: shadow stack and
> >> > indirect branch tracking (IBT).
> >> >
> >> > While there is linux kernel support for CET shadow stack in
> >> > userspace, there is no linux kernel support available for userspace IBT, yet.
> >> > This series therefore focuses on CET shadow stack only.
> >> >
> >> > I am looking forward to your feedback!
> >>
> >> Hi Christina, thanks for the incredible work in this series!
> >>
> >> I looked over all the patches, and sent all my comments inlined, the
> >> other patches look alright to me. I don't know if I understand enough
> >> of the code to give a review tag, and I don't have a machine with
> >> shadow stack support to test the series, so I hope this series gets
> >> some attention from global maintainers soon, I'd love to see this work merged!
> >
> > Hi Guinivere,
> >
> > Thanks a lot for looking at this !
> >
> > My plan is to wait until I receive bit more feedback for this series
> > and until patch #1 is merged, which I posted now separately.
>
> I'm almost finished reviewing this patch series. I think I'll be able to send some
> review comments tomorrow.
>
> In the meantime, one question: do you still plan to add a "bt -shadow"
> command, or any other shadow stack related command as discussed in the
> thread below?
>
> https://inbox.sourceware.org/gdb/SN7PR11MB7638DE1337F8F0F0282EBD56F99
> 6A@SN7PR11MB7638.namprd11.prod.outlook.com/
>
> I ask because for AArch64 Guarded Control Stack (which is equivalent to Intel
> Shadow Stack) I'll need to add commands to enable/disable shadow stacks, and
> also to see which GCS-specific features are enabled and locked in the inferior.
Hi Thiago,
Thanks a lot for looking at this.
Yes, I implemented "bt shadow" as subcommand of the ordinary backtrace command.
I planned to submit it as follow up series once this one is merged.
If you already want to have a look, the most important commits are:
https://github.com/intel/gdb/commit/7fbb0757af87d490225f91d3950eee7180acf6ad
https://github.com/intel/gdb/commit/e10103076ef3e4c75df91e2246637c2af3ba870a
https://github.com/intel/gdb/commit/c3386a341940e34263e7c396143d784d7fe924be
https://github.com/intel/gdb/commit/16c22643967e1b9d41a317b0bd02d3530f5d9f70
But it also required a number of commits to refactor the backtrace command in general,
which is the reason why I split it up in 2 series.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
2025-01-30 10:28 ` Schimpe, Christina
2025-01-30 13:53 ` Guinevere Larsen
@ 2025-02-06 2:59 ` Thiago Jung Bauermann
2025-02-06 12:15 ` Schimpe, Christina
1 sibling, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 2:59 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: Guinevere Larsen, gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Guinevere Larsen <guinevere@redhat.com>
>> Sent: Tuesday, January 28, 2025 2:35 PM
>> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
>> patches@sourceware.org
>> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
>>
>> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
>> > Some register sets can be activated and deactivated by the OS during
>> > the runtime of a process. One example register is the Intel CET
>> > shadow stack pointer. This adds a new type of register set to handle
>> > such cases. We shouldn't deactivate these regsets and should not show
>> > a warning if we fail to read them.
>> > ---
>> > gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
>> > gdbserver/linux-low.h | 7 ++++++-
>> > 2 files changed, 34 insertions(+), 13 deletions(-)
>> >
>> > diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index
>> > 50ce2b44927..355b28d9fe4 100644
>> > --- a/gdbserver/linux-low.cc
>> > +++ b/gdbserver/linux-low.cc
>> > @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct
>> regsets_info *regsets_info,
>> > if (res < 0)
>> > {
>> > if (errno == EIO
>> > - || (errno == EINVAL && regset->type == OPTIONAL_REGS))
>> > + || (errno == EINVAL
>> > + && (regset->type == OPTIONAL_REGS
>> > + || regset->type == OPTIONAL_RUNTIME_REGS)))
>> > {
>> > /* If we get EIO on a regset, or an EINVAL and the regset is
>> > - optional, do not try it again for this process mode. */
>> > + optional, do not try it again for this process mode.
>> > + Even if the regset can be enabled at runtime it is safe
>> > + to deactivate the regset in case of EINVAL, as we know
>> > + the regset itself was the invalid argument of the ptrace
>> > + call. */
>> > disable_regset (regsets_info, regset);
>>
>> I'm somewhat confused by this patch.
>>
>> The commit message and other comments here say that optional_runtime_regs
>> shouldn't be disabled. However, in here, if we get EINVAL we *will* disable the
>> regset. Did you mean to use != instead of == ?
>>
>> I'll be honest, I don't know enough about the regset subsystem to know which is
>> the correct option, I just think it has to be consistent.
>>
>
> Hi Guinevere,
>
> Thank you for the review.
>
> For the errno EINVAL we want to disable the regset, as we don't want to call ptrace
> using NT_X86_SHSTK again. This specific errno can happen if the kernel does not
> support ptrace using NT_X86_SHSTK (older linux kernels). I tried to explain that here:
>
>> > + Even if the regset can be enabled at runtime it is safe
>> > + to deactivate the regset in case of EINVAL, as we know
>> > + the regset itself was the invalid argument of the ptrace
>> > + call. */
I agree with Guinevere's remarks, and also with the suggestion of
improving the commit message.
But I would also like to suggest being a bit more direct in the comment
above. At least the way I read it, I thought that EINVAL was a normal
thing for ptrace to return if shadow stack was disabled for the
process. What about something like:
Even if the regset can be enabled at runtime it is safe
to deactivate the regset in case of EINVAL, as we know
the regset itself was the invalid argument of the ptrace
call which means that it's unsupported by the kernel. */
> In case shadow stack is just not active but supported by the kernel we see
> ENODEV and we don't disable the regset, which I explained in another
> comment for the corresponding code area:
>
> /* ENODATA or ENODEV may be returned if the regset is
> currently not "active". For ENODEV we additionally check
> if the register set is of type OPTIONAL_RUNTIME_REGS.
> This can happen in normal operation, so suppress the
> warning in this case.
>
> I didn't want to be too specific here to make the commit generic.
>
> Is there something I could add to make it more understandable or maybe
> there is just some information missing in the commit message?
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description.
2024-12-20 20:04 ` [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description Schimpe, Christina
@ 2025-02-06 3:00 ` Thiago Jung Bauermann
0 siblings, 0 replies; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:00 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> On x86 the PTRACE_GETREGSET request is currently only used for the xstate regset.
> The size of the xstate regset is initialized to 0 such that it can be reset to
> the appropriate size once we know it is supported for the current target
> in x86_linux_read_description.
>
> However, this configuration would not just affect the xstate regset but any regset
> with PTRACE_GETREGSET request that is added in the future. The new regset would be
> misconfigured with the xstate regset size. To avoid this we add an assert for
> unsupported regsets and check explicitly for the note type of the register set.
> ---
> gdbserver/linux-x86-low.cc | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
2024-12-20 20:04 ` [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch Schimpe, Christina
@ 2025-02-06 3:03 ` Thiago Jung Bauermann
2025-02-06 12:23 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:03 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> This is required for a later commit which requires "bit_SHSTK".
> ---
> gdb/nat/x86-gcc-cpuid.h | 153 ++++++++++++++++++++++++++++++++--------
> 1 file changed, 122 insertions(+), 31 deletions(-)
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> diff --git a/gdb/nat/x86-gcc-cpuid.h b/gdb/nat/x86-gcc-cpuid.h
> index b0f2d239af3..a571eb8a734 100644
> --- a/gdb/nat/x86-gcc-cpuid.h
> +++ b/gdb/nat/x86-gcc-cpuid.h
> @@ -1,5 +1,5 @@
> /*
> - * Helper cpuid.h file copied from gcc-6.0.0. Code in gdb should not
> + * Helper cpuid.h file copied from gcc-14-2-0. Code in gdb should not
> * include this directly, but pull in x86-cpuid.h and use that func.
> */
Incredibly nitty nit: any particular reason for changing from
dot-separated version number to dash-separated?
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86.
2024-12-20 20:04 ` [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86 Schimpe, Christina
2025-01-30 14:51 ` Guinevere Larsen
@ 2025-02-06 3:09 ` Thiago Jung Bauermann
2025-02-06 12:33 ` Schimpe, Christina
1 sibling, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:09 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> The XSAVE features set is organized in state components, which are a set
> of or parts of registers. So-called XSAVE-supported features are
> organized using state-component bitmaps, each bit corresonding to a
Typo: "corresponding"
> single state component.
>
> The SDM 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.
> ---
> gdb/amd64-tdep.c | 14 ++++----
> gdb/amd64-tdep.h | 8 +++--
> gdb/arch/amd64-linux-tdesc.c | 33 ++++++++---------
> gdb/arch/amd64-linux-tdesc.h | 7 ++--
> gdb/arch/amd64.c | 15 ++++----
> gdb/arch/amd64.h | 10 ++++--
> gdb/arch/i386-linux-tdesc.c | 29 ++++++++-------
> gdb/arch/i386-linux-tdesc.h | 5 +--
> gdb/arch/i386.c | 15 ++++----
> gdb/arch/i386.h | 8 ++++-
> gdb/arch/x86-linux-tdesc-features.c | 55 +++++++++++++++--------------
> gdb/arch/x86-linux-tdesc-features.h | 25 +++++++------
> gdb/i386-tdep.c | 14 ++++----
> gdb/i386-tdep.h | 7 ++--
> gdb/nat/x86-linux-tdesc.c | 18 +++++-----
> gdb/nat/x86-linux-tdesc.h | 7 ++--
> gdb/x86-linux-nat.c | 11 ++++--
> gdbserver/i387-fp.cc | 40 ++++++++++-----------
> gdbserver/linux-amd64-ipa.cc | 10 +++---
> gdbserver/linux-i386-ipa.cc | 6 ++--
> gdbserver/linux-x86-low.cc | 9 +++--
> gdbsupport/x86-xstate.h | 4 ++-
> 22 files changed, 196 insertions(+), 154 deletions(-)
Just some minor suggestions in comments.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> diff --git a/gdb/arch/x86-linux-tdesc-features.c b/gdb/arch/x86-linux-tdesc-features.c
> index f6eb112f312..3f041ece6eb 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.
> + the caching we're discussing here is Linux only. Currently for linux,
Nit: "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_mask
> + value, which has the same format than the state component bitmap.
>
> In order to ensure the cache functions correctly we need to filter out
I think this should read "filter" rather than "filter out". I understand
the latter to mean that xstate_bv_mask feature bits that are relevant
should be ignored, which isn't what the code does.
> @@ -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_mask_to_tdesc_idx) into an xstate_bv_mask
> + value which can then be used to create a target description.
> + The return mask same format than the state component bitmap and does
Missing words: "The return mask has the same format ..."
> + 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_mask (int idx);
>
> #endif /* IN_PROCESS_AGENT */
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register.
2024-12-20 20:04 ` [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register Schimpe, Christina
@ 2025-02-06 3:13 ` Thiago Jung Bauermann
2025-02-06 14:33 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:13 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> This patch adds the user mode register PL3_SSP which is part of the
> Intel(R) Control-Flow Enforcement Technology (CET) feature for support
> of shadow stack.
> For now, only native and remote debugging support for shadow stack
> userspace on amd64 linux are covered by this patch including 64 bit and
> x32 support. 32 bit support is not covered due to missing linux kernel
Nit: Linux (uppercase l)
> support.
<snip>
> diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c
> index 4a39028a472..59daaa4c583 100644
> --- a/gdb/arch/i386.c
> +++ b/gdb/arch/i386.c
> @@ -28,6 +28,7 @@
> #include "../features/i386/32bit-avx512.c"
> #include "../features/i386/32bit-segments.c"
> #include "../features/i386/pkeys.c"
> +#include "../features/i386/32bit-ssp.c"
>
> /* See i386.h. */
>
> @@ -66,5 +67,8 @@ i386_create_target_description (uint64_t xstate_bv_mask, bool is_linux,
> if (xstate_bv_mask & X86_XSTATE_PKRU)
> regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
>
> + if (xstate_bv_mask & X86_XSTATE_CET_U)
> + regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
> +
> return tdesc.release ();
> }
The patch description mentions that "32 bit support is not covered due
to missing linux kernel support". Is this change useful, or is it
unreachable code?
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index a86f534528c..fc35456f1d3 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -4225,6 +4225,75 @@ gdb_caching_proc allow_tsx_tests {} {
> return $allow_tsx_tests
> }
>
> +# Run a test on the target to check if it supports x86 shadow stack. Return 1
> +# if shadow stack is enabled, 0 otherwise.
> +
> +gdb_caching_proc allow_ssp_tests {} {
> + global srcdir subdir gdb_prompt hex
> +
> + set me "allow_ssp_tests"
> +
> + if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } {
> + verbose "$me: target known to not support shadow stack."
> + return 0
> + }
> +
> + # There is no need to check the actual HW in addition to ptrace support.
> + # We need both checks and ptrace will tell us about the HW state.
> + set compile_flags "{additional_flags=-fcf-protection=return}"
> + set src { int main() { return 0; } }
> + if {![gdb_simple_compile $me $src executable $compile_flags]} {
> + return 0
> + }
> +
> + save_vars { ::env(GLIBC_TUNABLES) } {
> +
> + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
> +
> + # No error message, compilation succeeded so now run it via gdb.
> + gdb_exit
> + gdb_start
> + gdb_reinitialize_dir $srcdir/$subdir
> + gdb_load $obj
> + if {![runto_main]} {
> + return 0
There should be a call to "remote_file build delete $obj" here as well.
> + }
> + set shadow_stack_disabled_re "(<unavailable>)"
> + if {[istarget *-*-linux*]} {
> + # Starting with v6.6., the Linux kernel supports CET shadow stack.
> + # Dependent on the target we can see a nullptr or "<unavailable>"
> + # when shadow stack is supported by HW and the linux kernel but
Nit: Linux
> + # not enabled for the current thread (for example due to a lack
> + # of compiler or glibc support for -fcf-protection).
> + set shadow_stack_disabled_re "$shadow_stack_disabled_re|(.*0x0)"
> + }
<snip>
> diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
> index d1fece717a7..5bbd4640e30 100644
> --- a/gdb/x86-linux-nat.c
> +++ b/gdb/x86-linux-nat.c
> @@ -41,6 +41,7 @@
> #include "nat/x86-linux.h"
> #include "nat/x86-linux-dregs.h"
> #include "nat/linux-ptrace.h"
> +#include "x86-tdep.h"
> #include "nat/x86-linux-tdesc.h"
>
> /* linux_nat_target::low_new_fork implementation. */
> @@ -97,11 +98,10 @@ 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 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 XSTATE_BV_STORAGE will not be configured based on
> - xcr0 only. */
> + called. Also it checks the enablement state of features which are
> + not configured in xcr0, such as CET shadow stack. Once the supported
The "not" above should be removed.
> + features are identified, the XSTATE_BV_STORAGE value is configured
> + accordingly and preserved for subsequent calls of this function. */
> static uint64_t xstate_bv_storage;
>
> if (inferior_ptid == null_ptid)
> @@ -215,6 +215,46 @@ x86_linux_get_thread_area (pid_t pid, void *addr, unsigned int *base_addr)
> }
> \f
>
> +/* See x86-linux-nat.h. */
> +
> +void
> +x86_linux_fetch_ssp (regcache *regcache, const int tid)
> +{
> + uint64_t ssp = 0x0;
> + iovec iov {&ssp, sizeof (ssp)};
> +
> + /* The shadow stack may be enabled and disabled at runtime. Reading the
> + ssp might fail as shadow stack was not activated for the current
> + thread. We don't want to show a warning but silently return. The
> + register will be shown as unavailable for the user. */
> + if (ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov) != 0)
> + return;
In case the ptrace fails and there is already an old value for ssp in
regcache, shouldn't it be removed from it?
> +
> + x86_supply_ssp (regcache, ssp);
> +}
> +
> +/* See x86-linux-nat.h. */
> +
> +void
> +x86_linux_store_ssp (const regcache *regcache, const int tid)
> +{
> + uint64_t ssp = 0x0;
> + iovec iov {&ssp, sizeof (ssp)};
> + x86_collect_ssp (regcache, ssp);
> +
> + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> + Dependent on the target the ssp register can be unavailable or
> + nullptr when shadow stack is supported by HW and the linux kernel but
Nit: Linux
> + not enabled for the current thread. In case of nullptr, GDB tries to
> + restore the shadow stack pointer after an inferior call. The ptrace
> + call with PTRACE_SETREGSET will fail here with errno ENODEV. We
> + don't want to throw an error in this case but silently continue. */
> + errno = 0;
> + if ((ptrace (PTRACE_SETREGSET, tid, NT_X86_SHSTK, &iov) != 0)
> + && (errno != ENODEV))
> + perror_with_name (_("Failed to write pl3_ssp register"));
Same question here: if the ptrace call fails shouldn't the ssp value in
regcache be removed?
> +}
> +
> void _initialize_x86_linux_nat ();
> void
> _initialize_x86_linux_nat ()
> diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h
> index 3c2241bb0b6..d5dc1908090 100644
> --- a/gdb/x86-linux-nat.h
> +++ b/gdb/x86-linux-nat.h
> @@ -92,4 +92,15 @@ struct x86_linux_nat_target : public x86_nat_target<linux_nat_target>
> extern ps_err_e x86_linux_get_thread_area (pid_t pid, void *addr,
> unsigned int *base_addr);
>
> +/* Fetch the value of the shadow stack pointer register from process/thread
> + TID and store it to GDB's register cache. */
> +
> +extern void x86_linux_fetch_ssp (regcache *regcache, const int tid);
> +
> +/* Read the value of the shadow stack pointer from GDB's register cache
> + and store it in the shadow stack pointer register of process/thread TID.
> + Throw an error in case of failure. */
> +
> +extern void x86_linux_store_ssp (const regcache *regcache, const int tid);
> +
> #endif /* GDB_X86_LINUX_NAT_H */
> diff --git a/gdb/x86-tdep.c b/gdb/x86-tdep.c
> index e50b5fb9fa4..08fb0e8d82d 100644
> --- a/gdb/x86-tdep.c
> +++ b/gdb/x86-tdep.c
> @@ -17,10 +17,32 @@
> You should have received a copy of the GNU General Public License
> along with this program. If not, see <http://www.gnu.org/licenses/>. */
>
> +#include "defs.h"
defs.h is now included in all GDB files via the gcc command line, and
shouldn't be #included anymore. See commit 18d2988e5da8 ("gdb,
gdbserver, gdbsupport: remove includes of early headers") and commit
ab7daea3ad0d ("gdb, gdbserver, gdbsupport: include early header files
with `-include`").
> +#include "i386-tdep.h"
> #include "x86-tdep.h"
> #include "symtab.h"
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack.
2024-12-20 20:04 ` [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack Schimpe, Christina
@ 2025-02-06 3:15 ` Thiago Jung Bauermann
2025-02-07 11:54 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:15 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> From: Felix Willgerodt <felix.willgerodt@intel.com>
>
> Intel's Control-Flow Enforcement Technology (CET) provides the shadow
> stack feature for the x86 architecture.
>
> This commit adds support to write and read the shadow-stack node in
> corefiles. This helps debugging return address violations post-mortem.
> The format is synced with the linux kernel commit "x86: Add PTRACE
> interface for shadow stack". As the linux kernel restricts shadow
> stack support to 64-bit, apply the fix for amd64 only.
>
> Co-Authored-By: Christina Schimpe <christina.schimpe@intel.com>
> ---
> bfd/elf.c | 24 +++++++++
I don't know what is current practice: should BFD changes be sent
separately to the binutils mailing list, or in the same patch or patch
series as the GDB changes that use them?
If the latter, then the binutils mailing list needs to at least be
on Cc:
> gdb/amd64-linux-tdep.c | 52 +++++++++++++++++--
> .../gdb.arch/amd64-shadow-stack-corefile.exp | 50 ++++++++++++++++++
> 3 files changed, 122 insertions(+), 4 deletions(-)
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
Just some minor comments.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> @@ -1630,6 +1642,30 @@ static const struct regset amd64_linux_xstateregset =
> amd64_linux_collect_xstateregset
> };
>
> +static void
> +amd64_linux_supply_ssp (const struct regset *regset,
> + struct regcache *regcache, int regnum,
> + const void *ssp, size_t len)
> +{
> + x86_supply_ssp (regcache, *static_cast<const uint64_t *> (ssp));
> +}
> +
> +static void
> +amd64_linux_collect_ssp (const struct regset *regset,
> + const struct regcache *regcache, int regnum,
> + void *ssp, size_t len)
> +{
> + x86_collect_ssp (regcache, *static_cast<uint64_t *> (ssp));
> +}
These functions should have documentation comments.
> +
> +/* Shadow stack pointer register. */
> +
> +static const struct regset amd64_linux_ssp_register
> + {
> + NULL, amd64_linux_supply_ssp, amd64_linux_collect_ssp
> + };
> +
> +
Just one line of separation between functions is enough.
> /* Iterate over core file register note sections. */
>
> static void
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2024-12-20 20:04 ` [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux Schimpe, Christina
2025-01-30 14:29 ` Guinevere Larsen
@ 2025-02-06 3:30 ` Thiago Jung Bauermann
2025-02-06 14:40 ` Schimpe, Christina
1 sibling, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:30 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> Unwind the $pl3_ssp register.
> We now have an updated value for the shadow stack pointer when
> moving up or down the frame level. Note that $pl3_ssp can
> become unavailable when moving to a frame before the shadow
> stack enablement. In the example below, shadow stack is enabled
> in the function 'call1'. Thus, when moving to a frame level above
> the function, $pl3_ssp will become unavaiable.
> Following the restriction of the linux kernel, implement the unwinding
> for amd64 linux only.
>
> Before this patch:
> ~~~
> Breakpoint 1, call2 (j=3) at sample.c:44
> 44 return 42;
> (gdb) p $pl3_ssp
> $1 = (void *) 0x7ffff79ffff8
> (gdb) up
> 55 call2 (3);
> (gdb) p $pl3_ssp
> $2 = (void *) 0x7ffff79ffff8
> (gdb) up
> 68 call1 (43);
> (gdb) p $pl3_ssp
> $3 = (void *) 0x7ffff79ffff8
> ~~~
>
> After this patch:
> ~~~
> Breakpoint 1, call2 (j=3) at sample.c:44
> 44 return 42;
> (gdb) p $pl3_ssp
> $1 = (void *) 0x7ffff79ffff8
> (gdb) up
> 55 call2 (3);
> (gdb) p $pl3_ssp
> $2 = (void *) 0x7ffff7a00000
> (gdb) up
> 68 call1 (43i);
> (gdb) p $pl3_ssp
> $3 = <unavailable>
> ~~~
>
> As we now have an updated value for each selected frame, the
> return command is now enabled for shadow stack enabled programs, too.
>
> We therefore add a test for the return command and shadow stack support,
> and for an updated shadow stack pointer after a frame level change.
> ---
> gdb/amd64-linux-tdep.c | 69 +++++++++++++++
> gdb/linux-tdep.c | 47 ++++++++++
> gdb/linux-tdep.h | 7 ++
> .../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++
> gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
> 5 files changed, 224 insertions(+)
> create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
Just some minor comments.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
> index 95f643b1217..895feac85e8 100644
> --- a/gdb/amd64-linux-tdep.c
> +++ b/gdb/amd64-linux-tdep.c
> @@ -45,6 +45,8 @@
> #include "arch/amd64-linux-tdesc.h"
> #include "inferior.h"
> #include "x86-tdep.h"
> +#include "dwarf2/frame.h"
> +#include "frame-unwind.h"
>
> /* The syscall's XML filename for i386. */
> #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
> @@ -1873,6 +1875,72 @@ amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
> return (addr & amd64_linux_lam_untag_mask ());
> }
>
> +static value *
> +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
> + void **this_cache, int regnum)
> +{
Add documentation comment to this function.
> + value *v = frame_unwind_got_register (this_frame, regnum, regnum);
> + gdb_assert (v != nullptr);
> +
> + gdbarch *gdbarch = get_frame_arch (this_frame);
> +
> + if (v->entirely_available () && !v->optimized_out ())
> + {
> + int size = register_size (gdbarch, regnum);
> + bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
> + size, byte_order);
> +
> + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> + Using /proc/PID/smaps we can only check if the current shadow
> + stack pointer SSP points to shadow stack memory. Only if this is
> + the case a valid previous shadow stack pointer can be
> + calculated. */
> + std::pair<CORE_ADDR, CORE_ADDR> range;
> + if (linux_address_in_shadow_stack_mem_range (ssp, &range))
> + {
> + /* The shadow stack grows downwards. To compute the previous
> + shadow stack pointer, we need to increment SSP.
> + For x32 the shadow stack elements are still 64-bit aligned.
> + Thus, we cannot use gdbarch_addr_bit to compute the new stack
> + pointer. */
> + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
> + const int bytes_per_word
> + = (binfo->bits_per_word / binfo->bits_per_byte);
> + CORE_ADDR new_ssp = ssp + bytes_per_word;
I agree with Guinevere's comment about introducing
amd64_linux_shadow_stack_element_size_aligned in this patch.
> + /* If NEW_SSP points to the end of or before (<=) the current
> + shadow stack memory range we consider NEW_SSP as valid (but
> + empty). */
> + if (new_ssp <= range.second)
> + return frame_unwind_got_address (this_frame, regnum, new_ssp);
> + }
> + }
> +
> + /* Return a value which is marked as unavailable in case we could not
> + calculate a valid previous shadow stack pointer. */
> + value *retval
> + = value::allocate_register (get_next_frame_sentinel_okay (this_frame),
> + regnum, register_type (gdbarch, regnum));
> + retval->mark_bytes_unavailable (0, retval->type ()->length ());
> + return retval;
> +}
> +
> +static void
> +amd64_init_reg (gdbarch *gdbarch, int regnum, dwarf2_frame_state_reg *reg,
> + const frame_info_ptr &this_frame)
> +{
> + if (regnum == gdbarch_pc_regnum (gdbarch))
> + reg->how = DWARF2_FRAME_REG_RA;
> + else if (regnum == gdbarch_sp_regnum (gdbarch))
> + reg->how = DWARF2_FRAME_REG_CFA;
> + else if (regnum == AMD64_PL3_SSP_REGNUM)
> + {
> + reg->how = DWARF2_FRAME_REG_FN;
> + reg->loc.fn = amd64_linux_dwarf2_prev_ssp;
> + }
> +}
Add documentation comment to this function.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support.
2024-12-20 20:04 ` [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support Schimpe, Christina
@ 2025-02-06 3:31 ` Thiago Jung Bauermann
2025-02-06 15:07 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:31 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> diff --git a/gdb/infcall.c b/gdb/infcall.c
> index 6399278c6ae..3a4f1e35a2f 100644
> --- a/gdb/infcall.c
> +++ b/gdb/infcall.c
> @@ -1453,6 +1453,12 @@ call_function_by_hand_dummy (struct value *function,
> bp_addr, args.size (), args.data (),
> sp, return_method, struct_addr);
>
> + /* Push the return address of the inferior (bp_addr) on the shadow stack
> + and update the shadow stack pointer. As we don't execute a call
> + instruction to start the inferior we need to handle this manually. */
> + if (gdbarch_shadow_stack_push_p (gdbarch))
> + gdbarch_shadow_stack_push (gdbarch, bp_addr);
> +
For AArch64's Guarded Control Stack, instead of adding a new gdbarch
method I added this change to aarch64_push_dummy_call:
if (aarch64_gcs_is_enabled (regcache))
aarch64_push_gcs_entry (regcache, bp_addr);
To implement aarch64_gcs_is_enabled I did add a new method to
aarch64_gdbarch_tdep so that OS-independent code in aarch64-tdep.c could call
Linux-specific logic in aarch64-linux-tdep.c:
static bool
aarch64_gcs_is_enabled (regcache *regs)
{
gdbarch *arch = regs->arch ();
aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (arch);
if (tdep->gcs_is_enabled == nullptr)
return false;
return tdep->gcs_is_enabled (regs);
}
Wouldn't a similar approach work for amd64?
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls.
2024-12-20 20:04 ` [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls Schimpe, Christina
@ 2025-02-06 3:34 ` Thiago Jung Bauermann
2025-02-07 11:55 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:34 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> This patch enables inferior calls to support Intel's Control-Flow
> Enforcement Technology (CET), which provides the shadow stack feature
> for the x86 architecture.
> Following the restriction of the linux kernel, enable inferior calls
> for amd64 only.
> ---
> gdb/amd64-linux-tdep.c | 89 +++++++++++++++++--
> gdb/doc/gdb.texinfo | 29 ++++++
> .../gdb.arch/amd64-shadow-stack-cmds.exp | 55 +++++++++++-
> 3 files changed, 164 insertions(+), 9 deletions(-)
Just a small nit below.
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> index 17f32ce3964..df654f9db5d 100644
> --- a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> @@ -13,12 +13,29 @@
> # You should have received a copy of the GNU General Public License
> # along with this program. If not, see <http://www.gnu.org/licenses/>.
>
> -# Test shadow stack enabling for frame level update and the return command.
> +# Test shadow stack enabling for frame level update, the return and the
> +# call command.
"command" should be plural above.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2024-12-20 20:05 ` [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer Schimpe, Christina
2025-01-28 20:27 ` Guinevere Larsen
@ 2025-02-06 3:35 ` Thiago Jung Bauermann
2025-02-07 12:01 ` Schimpe, Christina
1 sibling, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:35 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
> index 52f265e8e0e..df70cb082a4 100644
> --- a/gdb/gdbarch_components.py
> +++ b/gdb/gdbarch_components.py
> @@ -2822,6 +2822,8 @@ Some targets support special hardware-assisted control-flow protection
> technologies. For example, Intel's Control-flow Enforcement Technology (CET)
> provides a shadow stack and indirect branch tracking.
> To enable inferior calls the function shadow_stack_push has to be provided.
> +The method get_shadow_stack_pointer has to be provided to enable displaced
> +stepping.
>
> Push the address NEW_ADDR on the shadow stack and update the shadow stack
> pointer.
> @@ -2831,3 +2833,11 @@ pointer.
> params=[("CORE_ADDR", "new_addr")],
> predicate=True,
> )
> +
> +Method(
> + type="std::optional<CORE_ADDR>",
> + name="get_shadow_stack_pointer",
> + params=[],
> + predefault="default_get_shadow_stack_pointer",
> + invalid=False,
> +)
Ideally, there should be a comment on this method entry.
This method is only used in amd64-tdep.c and i386-tdep.c. IMHO it would
be better to put it in i386_gdbarch_tdep instead.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux.
2024-12-20 20:05 ` [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux Schimpe, Christina
2024-12-20 20:14 ` Eli Zaretskii
@ 2025-02-06 3:37 ` Thiago Jung Bauermann
1 sibling, 0 replies; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:37 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
I don't have much to say about this patch because depending on the
answer to my question to patch 11 it could change a bit. Just one small
comment below.
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> This patch enables displaced stepping to support Intel's Control-Flow
> Enforcement Technology (CET), which provides the shadow stack feature
> for the x86 architecture.
> Following the restriction of the linux kernel, enable displaced stepping
Nit: Linux
> for amd64 only.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 00/12] Add CET shadow stack support
2025-02-04 9:40 ` Schimpe, Christina
@ 2025-02-06 3:44 ` Thiago Jung Bauermann
0 siblings, 0 replies; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-06 3:44 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: Guinevere Larsen, gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Sent: Tuesday, February 4, 2025 4:58 AM
>> To: Schimpe, Christina <christina.schimpe@intel.com>
>> Cc: Guinevere Larsen <guinevere@redhat.com>; gdb-patches@sourceware.org
>> Subject: Re: [PATCH 00/12] Add CET shadow stack support
>>
>> In the meantime, one question: do you still plan to add a "bt -shadow"
>> command, or any other shadow stack related command as discussed in the
>> thread below?
>>
>> https://inbox.sourceware.org/gdb/SN7PR11MB7638DE1337F8F0F0282EBD56F99
>> 6A@SN7PR11MB7638.namprd11.prod.outlook.com/
>>
>> I ask because for AArch64 Guarded Control Stack (which is equivalent to Intel
>> Shadow Stack) I'll need to add commands to enable/disable shadow stacks, and
>> also to see which GCS-specific features are enabled and locked in the inferior.
>
> Hi Thiago,
>
> Thanks a lot for looking at this.
>
> Yes, I implemented "bt shadow" as subcommand of the ordinary backtrace command.
> I planned to submit it as follow up series once this one is merged.
>
> If you already want to have a look, the most important commits are:
> https://github.com/intel/gdb/commit/7fbb0757af87d490225f91d3950eee7180acf6ad
> https://github.com/intel/gdb/commit/e10103076ef3e4c75df91e2246637c2af3ba870a
> https://github.com/intel/gdb/commit/c3386a341940e34263e7c396143d784d7fe924be
> https://github.com/intel/gdb/commit/16c22643967e1b9d41a317b0bd02d3530f5d9f70
Thank you for the references. I'll look into those commits.
> But it also required a number of commits to refactor the backtrace command in general,
> which is the reason why I split it up in 2 series.
Good idea.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 02/12] gdbserver: Add optional runtime register set type.
2025-02-06 2:59 ` Thiago Jung Bauermann
@ 2025-02-06 12:15 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-06 12:15 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Guinevere Larsen, gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:00 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: Guinevere Larsen <guinevere@redhat.com>; gdb-patches@sourceware.org
> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> >> -----Original Message-----
> >> From: Guinevere Larsen <guinevere@redhat.com>
> >> Sent: Tuesday, January 28, 2025 2:35 PM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>; gdb-
> >> patches@sourceware.org
> >> Subject: Re: [PATCH 02/12] gdbserver: Add optional runtime register set type.
> >>
> >> On 12/20/24 5:04 PM, Schimpe, Christina wrote:
> >> > Some register sets can be activated and deactivated by the OS
> >> > during the runtime of a process. One example register is the Intel
> >> > CET shadow stack pointer. This adds a new type of register set to
> >> > handle such cases. We shouldn't deactivate these regsets and
> >> > should not show a warning if we fail to read them.
> >> > ---
> >> > gdbserver/linux-low.cc | 40 ++++++++++++++++++++++++++++------------
> >> > gdbserver/linux-low.h | 7 ++++++-
> >> > 2 files changed, 34 insertions(+), 13 deletions(-)
> >> >
> >> > diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index
> >> > 50ce2b44927..355b28d9fe4 100644
> >> > --- a/gdbserver/linux-low.cc
> >> > +++ b/gdbserver/linux-low.cc
> >> > @@ -5007,23 +5007,31 @@ regsets_fetch_inferior_registers (struct
> >> regsets_info *regsets_info,
> >> > if (res < 0)
> >> > {
> >> > if (errno == EIO
> >> > - || (errno == EINVAL && regset->type == OPTIONAL_REGS))
> >> > + || (errno == EINVAL
> >> > + && (regset->type == OPTIONAL_REGS
> >> > + || regset->type == OPTIONAL_RUNTIME_REGS)))
> >> > {
> >> > /* If we get EIO on a regset, or an EINVAL and the regset is
> >> > - optional, do not try it again for this process mode. */
> >> > + optional, do not try it again for this process mode.
> >> > + Even if the regset can be enabled at runtime it is safe
> >> > + to deactivate the regset in case of EINVAL, as we know
> >> > + the regset itself was the invalid argument of the ptrace
> >> > + call. */
> >> > disable_regset (regsets_info, regset);
> >>
> >> I'm somewhat confused by this patch.
> >>
> >> The commit message and other comments here say that
> >> optional_runtime_regs shouldn't be disabled. However, in here, if we
> >> get EINVAL we *will* disable the regset. Did you mean to use != instead of ==
> ?
> >>
> >> I'll be honest, I don't know enough about the regset subsystem to
> >> know which is the correct option, I just think it has to be consistent.
> >>
> >
> > Hi Guinevere,
> >
> > Thank you for the review.
> >
> > For the errno EINVAL we want to disable the regset, as we don't want
> > to call ptrace using NT_X86_SHSTK again. This specific errno can
> > happen if the kernel does not support ptrace using NT_X86_SHSTK (older linux
> kernels). I tried to explain that here:
> >
> >> > + Even if the regset can be enabled at runtime it is safe
> >> > + to deactivate the regset in case of EINVAL, as we know
> >> > + the regset itself was the invalid argument of the ptrace
> >> > + call. */
>
> I agree with Guinevere's remarks, and also with the suggestion of improving the
> commit message.
>
> But I would also like to suggest being a bit more direct in the comment above. At
> least the way I read it, I thought that EINVAL was a normal thing for ptrace to
> return if shadow stack was disabled for the process. What about something like:
>
> Even if the regset can be enabled at runtime it is safe
> to deactivate the regset in case of EINVAL, as we know
> the regset itself was the invalid argument of the ptrace
> call which means that it's unsupported by the kernel. */
Hi Thiago,
Thank you for the review.
I think we can add that sentence "which means that it's unsupported by the kernel", if it is generic behaviour for any regset.
This seems to be the case: https://github.com/torvalds/linux/blob/master/kernel/ptrace.c#L895
So I'd enhance the commit message but also the comment for the next version.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch.
2025-02-06 3:03 ` Thiago Jung Bauermann
@ 2025-02-06 12:23 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-06 12:23 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:04 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14
> branch.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > This is required for a later commit which requires "bit_SHSTK".
> > ---
> > gdb/nat/x86-gcc-cpuid.h | 153
> > ++++++++++++++++++++++++++++++++--------
> > 1 file changed, 122 insertions(+), 31 deletions(-)
>
> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>
> > diff --git a/gdb/nat/x86-gcc-cpuid.h b/gdb/nat/x86-gcc-cpuid.h index
> > b0f2d239af3..a571eb8a734 100644
> > --- a/gdb/nat/x86-gcc-cpuid.h
> > +++ b/gdb/nat/x86-gcc-cpuid.h
> > @@ -1,5 +1,5 @@
> > /*
> > - * Helper cpuid.h file copied from gcc-6.0.0. Code in gdb should not
> > + * Helper cpuid.h file copied from gcc-14-2-0. Code in gdb should
> > + not
> > * include this directly, but pull in x86-cpuid.h and use that func.
> > */
>
> Incredibly nitty nit: any particular reason for changing from dot-separated version
> number to dash-separated?
No, I'll change it to dot-separated again for the next version.
Thanks!
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86.
2025-02-06 3:09 ` Thiago Jung Bauermann
@ 2025-02-06 12:33 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-06 12:33 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
Hi Thiago,
Please see my comments below.
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:10 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description
> creation on x86.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > The XSAVE features set is organized in state components, which are a
> > set of or parts of registers. So-called XSAVE-supported features are
> > organized using state-component bitmaps, each bit corresonding to a
>
> Typo: "corresponding"
Will fix.
> > single state component.
> >
> > The SDM 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.
> > ---
> > gdb/amd64-tdep.c | 14 ++++----
> > gdb/amd64-tdep.h | 8 +++--
> > gdb/arch/amd64-linux-tdesc.c | 33 ++++++++---------
> > gdb/arch/amd64-linux-tdesc.h | 7 ++--
> > gdb/arch/amd64.c | 15 ++++----
> > gdb/arch/amd64.h | 10 ++++--
> > gdb/arch/i386-linux-tdesc.c | 29 ++++++++-------
> > gdb/arch/i386-linux-tdesc.h | 5 +--
> > gdb/arch/i386.c | 15 ++++----
> > gdb/arch/i386.h | 8 ++++-
> > gdb/arch/x86-linux-tdesc-features.c | 55
> > +++++++++++++++-------------- gdb/arch/x86-linux-tdesc-features.h | 25
> +++++++------
> > gdb/i386-tdep.c | 14 ++++----
> > gdb/i386-tdep.h | 7 ++--
> > gdb/nat/x86-linux-tdesc.c | 18 +++++-----
> > gdb/nat/x86-linux-tdesc.h | 7 ++--
> > gdb/x86-linux-nat.c | 11 ++++--
> > gdbserver/i387-fp.cc | 40 ++++++++++-----------
> > gdbserver/linux-amd64-ipa.cc | 10 +++---
> > gdbserver/linux-i386-ipa.cc | 6 ++--
> > gdbserver/linux-x86-low.cc | 9 +++--
> > gdbsupport/x86-xstate.h | 4 ++-
> > 22 files changed, 196 insertions(+), 154 deletions(-)
>
> Just some minor suggestions in comments.
>
> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>
> > diff --git a/gdb/arch/x86-linux-tdesc-features.c
> > b/gdb/arch/x86-linux-tdesc-features.c
> > index f6eb112f312..3f041ece6eb 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.
> > + the caching we're discussing here is Linux only. Currently for
> > + linux,
>
> Nit: "Linux"
Will fix.
> > + the only thing that has an impact on target description creation are
> > + the supported features in xsave which are modelled by a xstate_bv_mask
> > + value, which has the same format than the state component bitmap.
> >
> > In order to ensure the cache functions correctly we need to filter
> > out
>
> I think this should read "filter" rather than "filter out". I understand the latter to
> mean that xstate_bv_mask feature bits that are relevant should be ignored, which
> isn't what the code does.
I think you are right.
I could even make it a separate generic patch since "to filter out" was used
before already. But I think it's also ok, to just fix it with that patch.
> > @@ -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_mask_to_tdesc_idx) into an xstate_bv_mask
> > + value which can then be used to create a target description.
> > + The return mask same format than the state component bitmap and
> > +does
>
> Missing words: "The return mask has the same format ..."
Will fix this and all your comments above for the next version.
Also I'll add your Reviewed-by tag.
Thanks!
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register.
2025-02-06 3:13 ` Thiago Jung Bauermann
@ 2025-02-06 14:33 ` Schimpe, Christina
2025-02-08 3:44 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-06 14:33 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
Hi Thiago,
Thank you for the review. Please see my comments to your feedback below.
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:14 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack
> pointer register.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > This patch adds the user mode register PL3_SSP which is part of the
> > Intel(R) Control-Flow Enforcement Technology (CET) feature for support
> > of shadow stack.
> > For now, only native and remote debugging support for shadow stack
> > userspace on amd64 linux are covered by this patch including 64 bit
> > and
> > x32 support. 32 bit support is not covered due to missing linux
> > kernel
>
> Nit: Linux (uppercase l)
>
> > support.
Will fix.
> <snip>
>
> > diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c index
> > 4a39028a472..59daaa4c583 100644
> > --- a/gdb/arch/i386.c
> > +++ b/gdb/arch/i386.c
> > @@ -28,6 +28,7 @@
> > #include "../features/i386/32bit-avx512.c"
> > #include "../features/i386/32bit-segments.c"
> > #include "../features/i386/pkeys.c"
> > +#include "../features/i386/32bit-ssp.c"
> >
> > /* See i386.h. */
> >
> > @@ -66,5 +67,8 @@ i386_create_target_description (uint64_t
> xstate_bv_mask, bool is_linux,
> > if (xstate_bv_mask & X86_XSTATE_PKRU)
> > regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
> >
> > + if (xstate_bv_mask & X86_XSTATE_CET_U)
> > + regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
> > +
> > return tdesc.release ();
> > }
>
> The patch description mentions that "32 bit support is not covered due to missing
> linux kernel support". Is this change useful, or is it unreachable code?
I think I consistently did not implement 32 bit linux support, but added the code
for 32 bit support in locations which are not linux dependent, as preparation for
other OS. But for now yes, this should be unreachable code.
Should I (1) Remove the code or (2) improve the commit message ?
I'd be in favour of (2), would that be acceptable?
> > diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> > index a86f534528c..fc35456f1d3 100644
> > --- a/gdb/testsuite/lib/gdb.exp
> > +++ b/gdb/testsuite/lib/gdb.exp
> > @@ -4225,6 +4225,75 @@ gdb_caching_proc allow_tsx_tests {} {
> > return $allow_tsx_tests
> > }
> >
> > +# Run a test on the target to check if it supports x86 shadow stack.
> > +Return 1 # if shadow stack is enabled, 0 otherwise.
> > +
> > +gdb_caching_proc allow_ssp_tests {} {
> > + global srcdir subdir gdb_prompt hex
> > +
> > + set me "allow_ssp_tests"
> > +
> > + if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } {
> > + verbose "$me: target known to not support shadow stack."
> > + return 0
> > + }
> > +
> > + # There is no need to check the actual HW in addition to ptrace support.
> > + # We need both checks and ptrace will tell us about the HW state.
> > + set compile_flags "{additional_flags=-fcf-protection=return}"
> > + set src { int main() { return 0; } }
> > + if {![gdb_simple_compile $me $src executable $compile_flags]} {
> > + return 0
> > + }
> > +
> > + save_vars { ::env(GLIBC_TUNABLES) } {
> > +
> > + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
> > +
> > + # No error message, compilation succeeded so now run it via gdb.
> > + gdb_exit
> > + gdb_start
> > + gdb_reinitialize_dir $srcdir/$subdir
> > + gdb_load $obj
> > + if {![runto_main]} {
> > + return 0
>
> There should be a call to "remote_file build delete $obj" here as well.
Thanks for catching that. I'll fix it.
> > + }
> > + set shadow_stack_disabled_re "(<unavailable>)"
> > + if {[istarget *-*-linux*]} {
> > + # Starting with v6.6., the Linux kernel supports CET shadow stack.
> > + # Dependent on the target we can see a nullptr or "<unavailable>"
> > + # when shadow stack is supported by HW and the linux kernel but
>
> Nit: Linux
Will fix.
> > + # not enabled for the current thread (for example due to a lack
> > + # of compiler or glibc support for -fcf-protection).
> > + set shadow_stack_disabled_re "$shadow_stack_disabled_re|(.*0x0)"
> > + }
>
> <snip>
>
> > diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index
> > d1fece717a7..5bbd4640e30 100644
> > --- a/gdb/x86-linux-nat.c
> > +++ b/gdb/x86-linux-nat.c
> > @@ -41,6 +41,7 @@
> > #include "nat/x86-linux.h"
> > #include "nat/x86-linux-dregs.h"
> > #include "nat/linux-ptrace.h"
> > +#include "x86-tdep.h"
> > #include "nat/x86-linux-tdesc.h"
> >
> > /* linux_nat_target::low_new_fork implementation. */ @@ -97,11
> > +98,10 @@ 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 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 XSTATE_BV_STORAGE will not be configured based on
> > - xcr0 only. */
> > + called. Also it checks the enablement state of features which are
> > + not configured in xcr0, such as CET shadow stack. Once the
> > + supported
>
> The "not" above should be removed.
You mean the "not" in this sentence?
"Also it checks the enablement state of features which are not configured in xcr0, such as CET shadow stack. "
This should be correct in that context. CET shadow stack is not configured in xcr0.
> > + features are identified, the XSTATE_BV_STORAGE value is configured
> > + accordingly and preserved for subsequent calls of this function.
> > + */
> > static uint64_t xstate_bv_storage;
> >
> > if (inferior_ptid == null_ptid)
> > @@ -215,6 +215,46 @@ x86_linux_get_thread_area (pid_t pid, void *addr,
> > unsigned int *base_addr) }
> >
>
>
> >
> > +/* See x86-linux-nat.h. */
> > +
> > +void
> > +x86_linux_fetch_ssp (regcache *regcache, const int tid) {
> > + uint64_t ssp = 0x0;
> > + iovec iov {&ssp, sizeof (ssp)};
> > +
> > + /* The shadow stack may be enabled and disabled at runtime. Reading the
> > + ssp might fail as shadow stack was not activated for the current
> > + thread. We don't want to show a warning but silently return. The
> > + register will be shown as unavailable for the user. */ if
> > + (ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov) != 0)
> > + return;
>
> In case the ptrace fails and there is already an old value for ssp in regcache,
> shouldn't it be removed from it?
Hm, it doesn't seem to be a problem. I ran a test using inline enablement of shadow stack:
~~~
(gdb) p $pl3_ssp
$1 = (void *) 0x7ffff7c00000
(gdb) n
54 if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {
(gdb) n
58 return ret;
(gdb) p $pl3_ssp
$2 = <unavailable>
~~~
So it should be fine from my perspective. Or do you see another potential issue?
> > +
> > + x86_supply_ssp (regcache, ssp);
> > +}
> > +
> > +/* See x86-linux-nat.h. */
> > +
> > +void
> > +x86_linux_store_ssp (const regcache *regcache, const int tid) {
> > + uint64_t ssp = 0x0;
> > + iovec iov {&ssp, sizeof (ssp)};
> > + x86_collect_ssp (regcache, ssp);
> > +
> > + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> > + Dependent on the target the ssp register can be unavailable or
> > + nullptr when shadow stack is supported by HW and the linux
> > + kernel but
>
> Nit: Linux
Will fix.
> > + not enabled for the current thread. In case of nullptr, GDB tries to
> > + restore the shadow stack pointer after an inferior call. The ptrace
> > + call with PTRACE_SETREGSET will fail here with errno ENODEV. We
> > + don't want to throw an error in this case but silently continue.
> > + */ errno = 0; if ((ptrace (PTRACE_SETREGSET, tid, NT_X86_SHSTK,
> > + &iov) != 0)
> > + && (errno != ENODEV))
> > + perror_with_name (_("Failed to write pl3_ssp register"));
>
> Same question here: if the ptrace call fails shouldn't the ssp value in regcache be
> removed?
Please see my answer above.
> > +}
> > +
> > void _initialize_x86_linux_nat ();
> > void
> > _initialize_x86_linux_nat ()
> > diff --git a/gdb/x86-linux-nat.h b/gdb/x86-linux-nat.h index
> > 3c2241bb0b6..d5dc1908090 100644
> > --- a/gdb/x86-linux-nat.h
> > +++ b/gdb/x86-linux-nat.h
> > @@ -92,4 +92,15 @@ struct x86_linux_nat_target : public
> > x86_nat_target<linux_nat_target> extern ps_err_e x86_linux_get_thread_area
> (pid_t pid, void *addr,
> > unsigned int *base_addr);
> >
> > +/* Fetch the value of the shadow stack pointer register from process/thread
> > + TID and store it to GDB's register cache. */
> > +
> > +extern void x86_linux_fetch_ssp (regcache *regcache, const int tid);
> > +
> > +/* Read the value of the shadow stack pointer from GDB's register cache
> > + and store it in the shadow stack pointer register of process/thread TID.
> > + Throw an error in case of failure. */
> > +
> > +extern void x86_linux_store_ssp (const regcache *regcache, const int
> > +tid);
> > +
> > #endif /* GDB_X86_LINUX_NAT_H */
> > diff --git a/gdb/x86-tdep.c b/gdb/x86-tdep.c index
> > e50b5fb9fa4..08fb0e8d82d 100644
> > --- a/gdb/x86-tdep.c
> > +++ b/gdb/x86-tdep.c
> > @@ -17,10 +17,32 @@
> > You should have received a copy of the GNU General Public License
> > along with this program. If not, see
> > <http://www.gnu.org/licenses/>. */
> >
> > +#include "defs.h"
>
> defs.h is now included in all GDB files via the gcc command line, and shouldn't be
> #included anymore. See commit 18d2988e5da8 ("gdb, gdbserver, gdbsupport:
> remove includes of early headers") and commit ab7daea3ad0d ("gdb, gdbserver,
> gdbsupport: include early header files with `-include`").
Will fix, thanks for pointing that out.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux.
2025-02-06 3:30 ` Thiago Jung Bauermann
@ 2025-02-06 14:40 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-06 14:40 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:30 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding
> for amd64 linux.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > Unwind the $pl3_ssp register.
> > We now have an updated value for the shadow stack pointer when moving
> > up or down the frame level. Note that $pl3_ssp can become unavailable
> > when moving to a frame before the shadow stack enablement. In the
> > example below, shadow stack is enabled in the function 'call1'. Thus,
> > when moving to a frame level above the function, $pl3_ssp will become
> > unavaiable.
> > Following the restriction of the linux kernel, implement the unwinding
> > for amd64 linux only.
> >
> > Before this patch:
> > ~~~
> > Breakpoint 1, call2 (j=3) at sample.c:44
> > 44 return 42;
> > (gdb) p $pl3_ssp
> > $1 = (void *) 0x7ffff79ffff8
> > (gdb) up
> > 55 call2 (3);
> > (gdb) p $pl3_ssp
> > $2 = (void *) 0x7ffff79ffff8
> > (gdb) up
> > 68 call1 (43);
> > (gdb) p $pl3_ssp
> > $3 = (void *) 0x7ffff79ffff8
> > ~~~
> >
> > After this patch:
> > ~~~
> > Breakpoint 1, call2 (j=3) at sample.c:44
> > 44 return 42;
> > (gdb) p $pl3_ssp
> > $1 = (void *) 0x7ffff79ffff8
> > (gdb) up
> > 55 call2 (3);
> > (gdb) p $pl3_ssp
> > $2 = (void *) 0x7ffff7a00000
> > (gdb) up
> > 68 call1 (43i);
> > (gdb) p $pl3_ssp
> > $3 = <unavailable>
> > ~~~
> >
> > As we now have an updated value for each selected frame, the return
> > command is now enabled for shadow stack enabled programs, too.
> >
> > We therefore add a test for the return command and shadow stack
> > support, and for an updated shadow stack pointer after a frame level change.
> > ---
> > gdb/amd64-linux-tdep.c | 69 +++++++++++++++
> > gdb/linux-tdep.c | 47 ++++++++++
> > gdb/linux-tdep.h | 7 ++
> > .../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++++++++++++++++++
> > gdb/testsuite/gdb.arch/amd64-shadow-stack.c | 13 +++
> > 5 files changed, 224 insertions(+)
> > create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
>
> Just some minor comments.
>
> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>
> > diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index
> > 95f643b1217..895feac85e8 100644
> > --- a/gdb/amd64-linux-tdep.c
> > +++ b/gdb/amd64-linux-tdep.c
> > @@ -45,6 +45,8 @@
> > #include "arch/amd64-linux-tdesc.h"
> > #include "inferior.h"
> > #include "x86-tdep.h"
> > +#include "dwarf2/frame.h"
> > +#include "frame-unwind.h"
> >
> > /* The syscall's XML filename for i386. */ #define
> > XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
> > @@ -1873,6 +1875,72 @@
> amd64_linux_remove_non_address_bits_watchpoint (gdbarch *gdbarch,
> > return (addr & amd64_linux_lam_untag_mask ()); }
> >
> > +static value *
> > +amd64_linux_dwarf2_prev_ssp (const frame_info_ptr &this_frame,
> > + void **this_cache, int regnum) {
>
> Add documentation comment to this function.
>
> > + value *v = frame_unwind_got_register (this_frame, regnum, regnum);
> > + gdb_assert (v != nullptr);
> > +
> > + gdbarch *gdbarch = get_frame_arch (this_frame);
> > +
> > + if (v->entirely_available () && !v->optimized_out ())
> > + {
> > + int size = register_size (gdbarch, regnum);
> > + bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> > + CORE_ADDR ssp = extract_unsigned_integer (v->contents_all ().data (),
> > + size, byte_order);
> > +
> > + /* Starting with v6.6., the Linux kernel supports CET shadow stack.
> > + Using /proc/PID/smaps we can only check if the current shadow
> > + stack pointer SSP points to shadow stack memory. Only if this is
> > + the case a valid previous shadow stack pointer can be
> > + calculated. */
> > + std::pair<CORE_ADDR, CORE_ADDR> range;
> > + if (linux_address_in_shadow_stack_mem_range (ssp, &range))
> > + {
> > + /* The shadow stack grows downwards. To compute the previous
> > + shadow stack pointer, we need to increment SSP.
> > + For x32 the shadow stack elements are still 64-bit aligned.
> > + Thus, we cannot use gdbarch_addr_bit to compute the new stack
> > + pointer. */
> > + const bfd_arch_info *binfo = gdbarch_bfd_arch_info (gdbarch);
> > + const int bytes_per_word
> > + = (binfo->bits_per_word / binfo->bits_per_byte);
> > + CORE_ADDR new_ssp = ssp + bytes_per_word;
>
> I agree with Guinevere's comment about introducing
> amd64_linux_shadow_stack_element_size_aligned in this patch.
>
> > + /* If NEW_SSP points to the end of or before (<=) the current
> > + shadow stack memory range we consider NEW_SSP as valid (but
> > + empty). */
> > + if (new_ssp <= range.second)
> > + return frame_unwind_got_address (this_frame, regnum, new_ssp);
> > + }
> > + }
> > +
> > + /* Return a value which is marked as unavailable in case we could not
> > + calculate a valid previous shadow stack pointer. */
> > + value *retval
> > + = value::allocate_register (get_next_frame_sentinel_okay (this_frame),
> > + regnum, register_type (gdbarch, regnum));
> > + retval->mark_bytes_unavailable (0, retval->type ()->length ());
> > + return retval;
> > +}
> > +
> > +static void
> > +amd64_init_reg (gdbarch *gdbarch, int regnum, dwarf2_frame_state_reg
> *reg,
> > + const frame_info_ptr &this_frame)
> > +{
> > + if (regnum == gdbarch_pc_regnum (gdbarch))
> > + reg->how = DWARF2_FRAME_REG_RA;
> > + else if (regnum == gdbarch_sp_regnum (gdbarch))
> > + reg->how = DWARF2_FRAME_REG_CFA;
> > + else if (regnum == AMD64_PL3_SSP_REGNUM)
> > + {
> > + reg->how = DWARF2_FRAME_REG_FN;
> > + reg->loc.fn = amd64_linux_dwarf2_prev_ssp;
> > + }
> > +}
>
> Add documentation comment to this function.
>
> --
> Thiago
Thank you for the review. I'll apply all your comments in the next version.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support.
2025-02-06 3:31 ` Thiago Jung Bauermann
@ 2025-02-06 15:07 ` Schimpe, Christina
2025-02-08 3:57 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-06 15:07 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:32 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack
> support.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > diff --git a/gdb/infcall.c b/gdb/infcall.c index
> > 6399278c6ae..3a4f1e35a2f 100644
> > --- a/gdb/infcall.c
> > +++ b/gdb/infcall.c
> > @@ -1453,6 +1453,12 @@ call_function_by_hand_dummy (struct value
> *function,
> > bp_addr, args.size (), args.data (),
> > sp, return_method, struct_addr);
> >
> > + /* Push the return address of the inferior (bp_addr) on the shadow stack
> > + and update the shadow stack pointer. As we don't execute a call
> > + instruction to start the inferior we need to handle this
> > + manually. */ if (gdbarch_shadow_stack_push_p (gdbarch))
> > + gdbarch_shadow_stack_push (gdbarch, bp_addr);
> > +
>
> For AArch64's Guarded Control Stack, instead of adding a new gdbarch method I
> added this change to aarch64_push_dummy_call:
>
> if (aarch64_gcs_is_enabled (regcache))
> aarch64_push_gcs_entry (regcache, bp_addr);
>
> To implement aarch64_gcs_is_enabled I did add a new method to
> aarch64_gdbarch_tdep so that OS-independent code in aarch64-tdep.c could call
> Linux-specific logic in aarch64-linux-tdep.c:
>
> static bool
> aarch64_gcs_is_enabled (regcache *regs)
> {
> gdbarch *arch = regs->arch ();
> aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (arch);
>
> if (tdep->gcs_is_enabled == nullptr)
> return false;
>
> return tdep->gcs_is_enabled (regs);
> }
>
> Wouldn't a similar approach work for amd64?
Hi Thiago,
Thank you for the feedback!
I think I could also fix it in amd64_push_dummy_call by implementing it in a similar way than you do.
But isn't it better to keep the code generic ?
Generic code for handling shadow stacks is also required for the implementation of "bt shadow",
as I tried to provide an implementation that can be used by other architectures as well.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack.
2025-02-06 3:15 ` Thiago Jung Bauermann
@ 2025-02-07 11:54 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-07 11:54 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:15 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow
> stack.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > From: Felix Willgerodt <felix.willgerodt@intel.com>
> >
> > Intel's Control-Flow Enforcement Technology (CET) provides the shadow
> > stack feature for the x86 architecture.
> >
> > This commit adds support to write and read the shadow-stack node in
> > corefiles. This helps debugging return address violations post-mortem.
> > The format is synced with the linux kernel commit "x86: Add PTRACE
> > interface for shadow stack". As the linux kernel restricts shadow
> > stack support to 64-bit, apply the fix for amd64 only.
> >
> > Co-Authored-By: Christina Schimpe <christina.schimpe@intel.com>
> > ---
> > bfd/elf.c | 24 +++++++++
>
> I don't know what is current practice: should BFD changes be sent separately to
> the binutils mailing list, or in the same patch or patch series as the GDB changes
> that use them?
>
> If the latter, then the binutils mailing list needs to at least be on Cc:
Right, I think I should post it in the binutils mailing list. Thanks for pointing that out.
I will fix your comments and post it then there.
Christina
> > gdb/amd64-linux-tdep.c | 52 +++++++++++++++++--
> > .../gdb.arch/amd64-shadow-stack-corefile.exp | 50 ++++++++++++++++++
> > 3 files changed, 122 insertions(+), 4 deletions(-) create mode
> > 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
>
> Just some minor comments.
>
> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>
> > @@ -1630,6 +1642,30 @@ static const struct regset amd64_linux_xstateregset
> =
> > amd64_linux_collect_xstateregset
> > };
> >
> > +static void
> > +amd64_linux_supply_ssp (const struct regset *regset,
> > + struct regcache *regcache, int regnum,
> > + const void *ssp, size_t len)
> > +{
> > + x86_supply_ssp (regcache, *static_cast<const uint64_t *> (ssp)); }
> > +
> > +static void
> > +amd64_linux_collect_ssp (const struct regset *regset,
> > + const struct regcache *regcache, int regnum,
> > + void *ssp, size_t len)
> > +{
> > + x86_collect_ssp (regcache, *static_cast<uint64_t *> (ssp)); }
>
> These functions should have documentation comments.
>
> > +
> > +/* Shadow stack pointer register. */
> > +
> > +static const struct regset amd64_linux_ssp_register
> > + {
> > + NULL, amd64_linux_supply_ssp, amd64_linux_collect_ssp
> > + };
> > +
> > +
>
> Just one line of separation between functions is enough.
>
> > /* Iterate over core file register note sections. */
> >
> > static void
>
> --
> Thiago
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls.
2025-02-06 3:34 ` Thiago Jung Bauermann
@ 2025-02-07 11:55 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-07 11:55 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:34 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 10/12] gdb: Implement amd64 linux shadow stack support
> for inferior calls.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > This patch enables inferior calls to support Intel's Control-Flow
> > Enforcement Technology (CET), which provides the shadow stack feature
> > for the x86 architecture.
> > Following the restriction of the linux kernel, enable inferior calls
> > for amd64 only.
> > ---
> > gdb/amd64-linux-tdep.c | 89 +++++++++++++++++--
> > gdb/doc/gdb.texinfo | 29 ++++++
> > .../gdb.arch/amd64-shadow-stack-cmds.exp | 55 +++++++++++-
> > 3 files changed, 164 insertions(+), 9 deletions(-)
>
> Just a small nit below.
>
> Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>
> > diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> > b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> > index 17f32ce3964..df654f9db5d 100644
> > --- a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> > +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
> > @@ -13,12 +13,29 @@
> > # You should have received a copy of the GNU General Public License
> > # along with this program. If not, see <http://www.gnu.org/licenses/>.
> >
> > -# Test shadow stack enabling for frame level update and the return command.
> > +# Test shadow stack enabling for frame level update, the return and
> > +the # call command.
>
> "command" should be plural above.
Will fix. Thank you for the review.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-06 3:35 ` Thiago Jung Bauermann
@ 2025-02-07 12:01 ` Schimpe, Christina
2025-02-08 4:03 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-07 12:01 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Thursday, February 6, 2025 4:35 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the
> shadow stack pointer.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> > diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
> > index 52f265e8e0e..df70cb082a4 100644
> > --- a/gdb/gdbarch_components.py
> > +++ b/gdb/gdbarch_components.py
> > @@ -2822,6 +2822,8 @@ Some targets support special hardware-assisted
> > control-flow protection technologies. For example, Intel's
> > Control-flow Enforcement Technology (CET) provides a shadow stack and
> indirect branch tracking.
> > To enable inferior calls the function shadow_stack_push has to be provided.
> > +The method get_shadow_stack_pointer has to be provided to enable
> > +displaced stepping.
> >
> > Push the address NEW_ADDR on the shadow stack and update the shadow
> > stack pointer.
> > @@ -2831,3 +2833,11 @@ pointer.
> > params=[("CORE_ADDR", "new_addr")],
> > predicate=True,
> > )
> > +
> > +Method(
> > + type="std::optional<CORE_ADDR>",
> > + name="get_shadow_stack_pointer",
> > + params=[],
> > + predefault="default_get_shadow_stack_pointer",
> > + invalid=False,
> > +)
>
> Ideally, there should be a comment on this method entry.
>
> This method is only used in amd64-tdep.c and i386-tdep.c. IMHO it would be
> better to put it in i386_gdbarch_tdep instead.
Hi Thiago,
Thank you for the review.
As also discussed here: https://sourceware.org/pipermail/gdb-patches/2025-February/215266.html,
I wonder if it's better to keep the code generic.
And I plan to use the gdbarch method gdbarch_get_shadow_stack_pointer in a future series for "bt shadow".
I shared the commits in this comment:
https://sourceware.org/pipermail/gdb-patches/2025-February/215178.html,
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register.
2025-02-06 14:33 ` Schimpe, Christina
@ 2025-02-08 3:44 ` Thiago Jung Bauermann
0 siblings, 0 replies; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-08 3:44 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
> Hi Thiago,
>
> Thank you for the review. Please see my comments to your feedback below.
>
>> -----Original Message-----
>> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Sent: Thursday, February 6, 2025 4:14 AM
>> To: Schimpe, Christina <christina.schimpe@intel.com>
>> Cc: gdb-patches@sourceware.org
>> Subject: Re: [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack
>> pointer register.
>>
>>
>> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>>
>> > diff --git a/gdb/arch/i386.c b/gdb/arch/i386.c index
>> > 4a39028a472..59daaa4c583 100644
>> > --- a/gdb/arch/i386.c
>> > +++ b/gdb/arch/i386.c
>> > @@ -28,6 +28,7 @@
>> > #include "../features/i386/32bit-avx512.c"
>> > #include "../features/i386/32bit-segments.c"
>> > #include "../features/i386/pkeys.c"
>> > +#include "../features/i386/32bit-ssp.c"
>> >
>> > /* See i386.h. */
>> >
>> > @@ -66,5 +67,8 @@ i386_create_target_description (uint64_t
>> xstate_bv_mask, bool is_linux,
>> > if (xstate_bv_mask & X86_XSTATE_PKRU)
>> > regnum = create_feature_i386_pkeys (tdesc.get (), regnum);
>> >
>> > + if (xstate_bv_mask & X86_XSTATE_CET_U)
>> > + regnum = create_feature_i386_32bit_ssp (tdesc.get (), regnum);
>> > +
>> > return tdesc.release ();
>> > }
>>
>> The patch description mentions that "32 bit support is not covered due to missing
>> linux kernel support". Is this change useful, or is it unreachable code?
>
> I think I consistently did not implement 32 bit linux support, but added the code
> for 32 bit support in locations which are not linux dependent, as preparation for
> other OS. But for now yes, this should be unreachable code.
> Should I (1) Remove the code or (2) improve the commit message ?
> I'd be in favour of (2), would that be acceptable?
In the general case, I lean towards (1), but in this case it's just two
simple lines, and also in an arch-specific corner of GDB so it's not
really a problem. It's certainly acceptable in my view.
>> > diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index
>> > d1fece717a7..5bbd4640e30 100644
>> > --- a/gdb/x86-linux-nat.c
>> > +++ b/gdb/x86-linux-nat.c
>> > @@ -41,6 +41,7 @@
>> > #include "nat/x86-linux.h"
>> > #include "nat/x86-linux-dregs.h"
>> > #include "nat/linux-ptrace.h"
>> > +#include "x86-tdep.h"
>> > #include "nat/x86-linux-tdesc.h"
>> >
>> > /* linux_nat_target::low_new_fork implementation. */ @@ -97,11
>> > +98,10 @@ 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 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 XSTATE_BV_STORAGE will not be configured based on
>> > - xcr0 only. */
>> > + called. Also it checks the enablement state of features which are
>> > + not configured in xcr0, such as CET shadow stack. Once the
>> > + supported
>>
>> The "not" above should be removed.
>
> You mean the "not" in this sentence?
> "Also it checks the enablement state of features which are not configured in xcr0, such as
> CET shadow stack. "
>
> This should be correct in that context. CET shadow stack is not configured in xcr0.
Ah, I see. Sorry, I had misread the comment.
>> > + features are identified, the XSTATE_BV_STORAGE value is configured
>> > + accordingly and preserved for subsequent calls of this function.
>> > + */
>> > static uint64_t xstate_bv_storage;
>> >
>> > if (inferior_ptid == null_ptid)
>> > @@ -215,6 +215,46 @@ x86_linux_get_thread_area (pid_t pid, void *addr,
>> > unsigned int *base_addr) }
>> >
>>
>>
>> >
>> > +/* See x86-linux-nat.h. */
>> > +
>> > +void
>> > +x86_linux_fetch_ssp (regcache *regcache, const int tid) {
>> > + uint64_t ssp = 0x0;
>> > + iovec iov {&ssp, sizeof (ssp)};
>> > +
>> > + /* The shadow stack may be enabled and disabled at runtime. Reading the
>> > + ssp might fail as shadow stack was not activated for the current
>> > + thread. We don't want to show a warning but silently return. The
>> > + register will be shown as unavailable for the user. */ if
>> > + (ptrace (PTRACE_GETREGSET, tid, NT_X86_SHSTK, &iov) != 0)
>> > + return;
>>
>> In case the ptrace fails and there is already an old value for ssp in regcache,
>> shouldn't it be removed from it?
>
> Hm, it doesn't seem to be a problem. I ran a test using inline enablement of shadow stack:
> ~~~
> (gdb) p $pl3_ssp
> $1 = (void *) 0x7ffff7c00000
> (gdb) n
> 54 if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {
> (gdb) n
> 58 return ret;
> (gdb) p $pl3_ssp
> $2 = <unavailable>
> ~~~
> So it should be fine from my perspective. Or do you see another potential issue?
Each time the inferior continues, GDB drops the existing regcaches and
builds new ones, so the values from $1 and $2 in the output above come
from different regcache instances.
I made the comment thinking that if GDB knows that ssp is unavailable
then it should strive to make sure that is reflected in the
regcache. But come to think of it, if the inferior is stopped then
whether ssp is available or not won't change until it runs again and the
scenario I was considering can't happen. Sorry about the false alarm.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support.
2025-02-06 15:07 ` Schimpe, Christina
@ 2025-02-08 3:57 ` Thiago Jung Bauermann
2025-02-10 8:37 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-08 3:57 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Sent: Thursday, February 6, 2025 4:32 AM
>> To: Schimpe, Christina <christina.schimpe@intel.com>
>> Cc: gdb-patches@sourceware.org
>> Subject: Re: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack
>> support.
>>
>>
>> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>>
>> > diff --git a/gdb/infcall.c b/gdb/infcall.c index
>> > 6399278c6ae..3a4f1e35a2f 100644
>> > --- a/gdb/infcall.c
>> > +++ b/gdb/infcall.c
>> > @@ -1453,6 +1453,12 @@ call_function_by_hand_dummy (struct value
>> *function,
>> > bp_addr, args.size (), args.data (),
>> > sp, return_method, struct_addr);
>> >
>> > + /* Push the return address of the inferior (bp_addr) on the shadow stack
>> > + and update the shadow stack pointer. As we don't execute a call
>> > + instruction to start the inferior we need to handle this
>> > + manually. */ if (gdbarch_shadow_stack_push_p (gdbarch))
>> > + gdbarch_shadow_stack_push (gdbarch, bp_addr);
>> > +
>>
>> For AArch64's Guarded Control Stack, instead of adding a new gdbarch method I
>> added this change to aarch64_push_dummy_call:
>>
>> if (aarch64_gcs_is_enabled (regcache))
>> aarch64_push_gcs_entry (regcache, bp_addr);
>>
>> To implement aarch64_gcs_is_enabled I did add a new method to
>> aarch64_gdbarch_tdep so that OS-independent code in aarch64-tdep.c could call
>> Linux-specific logic in aarch64-linux-tdep.c:
>>
>> static bool
>> aarch64_gcs_is_enabled (regcache *regs)
>> {
>> gdbarch *arch = regs->arch ();
>> aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (arch);
>>
>> if (tdep->gcs_is_enabled == nullptr)
>> return false;
>>
>> return tdep->gcs_is_enabled (regs);
>> }
>>
>> Wouldn't a similar approach work for amd64?
>
> Hi Thiago,
>
> Thank you for the feedback!
>
> I think I could also fix it in amd64_push_dummy_call by implementing it in a similar way
> than you do.
> But isn't it better to keep the code generic ?
>
> Generic code for handling shadow stacks is also required for the implementation of "bt
> shadow",
> as I tried to provide an implementation that can be used by other architectures as well.
Yes, that is a good point. I'm on the fence on this one. On the one
hand, there's value in keeping generic code simpler if something can be
handled just as well by arch-specific code, but also it's good to share
code between architectures.
My suggestion for this gdbarch hook then is that it should also accept a
regcache as argument. call_function_by_hand_dummy already obtains it so
that it can call gdbarch_push_dummy_call, so it avoids another call to
inferior_thread deeper in the stack since the hook implementation will
need it.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-07 12:01 ` Schimpe, Christina
@ 2025-02-08 4:03 ` Thiago Jung Bauermann
2025-02-10 8:58 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-08 4:03 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Sent: Thursday, February 6, 2025 4:35 AM
>> To: Schimpe, Christina <christina.schimpe@intel.com>
>> Cc: gdb-patches@sourceware.org
>> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the
>> shadow stack pointer.
>>
>>
>> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>>
>> > diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
>> > index 52f265e8e0e..df70cb082a4 100644
>> > --- a/gdb/gdbarch_components.py
>> > +++ b/gdb/gdbarch_components.py
>> > @@ -2822,6 +2822,8 @@ Some targets support special hardware-assisted
>> > control-flow protection technologies. For example, Intel's
>> > Control-flow Enforcement Technology (CET) provides a shadow stack and
>> indirect branch tracking.
>> > To enable inferior calls the function shadow_stack_push has to be provided.
>> > +The method get_shadow_stack_pointer has to be provided to enable
>> > +displaced stepping.
>> >
>> > Push the address NEW_ADDR on the shadow stack and update the shadow
>> > stack pointer.
>> > @@ -2831,3 +2833,11 @@ pointer.
>> > params=[("CORE_ADDR", "new_addr")],
>> > predicate=True,
>> > )
>> > +
>> > +Method(
>> > + type="std::optional<CORE_ADDR>",
>> > + name="get_shadow_stack_pointer",
>> > + params=[],
>> > + predefault="default_get_shadow_stack_pointer",
>> > + invalid=False,
>> > +)
>>
>> Ideally, there should be a comment on this method entry.
>>
>> This method is only used in amd64-tdep.c and i386-tdep.c. IMHO it would be
>> better to put it in i386_gdbarch_tdep instead.
>
> Hi Thiago,
>
> Thank you for the review.
>
> As also discussed here:
> https://sourceware.org/pipermail/gdb-patches/2025-February/215266.html,
> I wonder if it's better to keep the code generic.
Indeed, that's a good point. In the case of this method, I have an
additional concern though: its callers assume that if
gdbarch_get_shadow_stack_pointer returns a value, then it means that
shadow stacks are enabled in the inferior. But this is an x86
particularity. On AArch64, if the processor supports shadow stacks then
the shadow stack register is always available, even if shadow stacks are
turned off.
So I think that there should be an additional method to indicate whether
shadow stacks are enabled in the inferior.
> And I plan to use the gdbarch method gdbarch_get_shadow_stack_pointer in a future series
> for "bt shadow".
> I shared the commits in this comment:
> https://sourceware.org/pipermail/gdb-patches/2025-February/215178.html,
Indeed. I see the same assumption in that code as well. Which makes a
lot of sense since it only needs to support x86. But that will need to
be adapted when posted upstream.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support.
2025-02-08 3:57 ` Thiago Jung Bauermann
@ 2025-02-10 8:37 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-10 8:37 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Saturday, February 8, 2025 4:58 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow
> stack support.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> >> -----Original Message-----
> >> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> >> Sent: Thursday, February 6, 2025 4:32 AM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>
> >> Cc: gdb-patches@sourceware.org
> >> Subject: Re: [PATCH 09/12] gdb, gdbarch: Enable inferior calls for
> >> shadow stack support.
> >>
> >>
> >> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
> >>
> >> > diff --git a/gdb/infcall.c b/gdb/infcall.c index
> >> > 6399278c6ae..3a4f1e35a2f 100644
> >> > --- a/gdb/infcall.c
> >> > +++ b/gdb/infcall.c
> >> > @@ -1453,6 +1453,12 @@ call_function_by_hand_dummy (struct value
> >> *function,
> >> > bp_addr, args.size (), args.data (),
> >> > sp, return_method, struct_addr);
> >> >
> >> > + /* Push the return address of the inferior (bp_addr) on the shadow
> stack
> >> > + and update the shadow stack pointer. As we don't execute a call
> >> > + instruction to start the inferior we need to handle this
> >> > + manually. */ if (gdbarch_shadow_stack_push_p (gdbarch))
> >> > + gdbarch_shadow_stack_push (gdbarch, bp_addr);
> >> > +
> >>
> >> For AArch64's Guarded Control Stack, instead of adding a new gdbarch
> >> method I added this change to aarch64_push_dummy_call:
> >>
> >> if (aarch64_gcs_is_enabled (regcache))
> >> aarch64_push_gcs_entry (regcache, bp_addr);
> >>
> >> To implement aarch64_gcs_is_enabled I did add a new method to
> >> aarch64_gdbarch_tdep so that OS-independent code in aarch64-tdep.c
> >> could call Linux-specific logic in aarch64-linux-tdep.c:
> >>
> >> static bool
> >> aarch64_gcs_is_enabled (regcache *regs) {
> >> gdbarch *arch = regs->arch ();
> >> aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep>
> >> (arch);
> >>
> >> if (tdep->gcs_is_enabled == nullptr)
> >> return false;
> >>
> >> return tdep->gcs_is_enabled (regs); }
> >>
> >> Wouldn't a similar approach work for amd64?
> >
> > Hi Thiago,
> >
> > Thank you for the feedback!
> >
> > I think I could also fix it in amd64_push_dummy_call by implementing
> > it in a similar way than you do.
> > But isn't it better to keep the code generic ?
> >
> > Generic code for handling shadow stacks is also required for the
> > implementation of "bt shadow", as I tried to provide an implementation
> > that can be used by other architectures as well.
>
> Yes, that is a good point. I'm on the fence on this one. On the one hand,
> there's value in keeping generic code simpler if something can be handled just
> as well by arch-specific code, but also it's good to share code between
> architectures.
Ok, let's hope for more feedback on this open.
> My suggestion for this gdbarch hook then is that it should also accept a
> regcache as argument. call_function_by_hand_dummy already obtains it so
> that it can call gdbarch_push_dummy_call, so it avoids another call to
> inferior_thread deeper in the stack since the hook implementation will need it.
Good point. This shouldn't be a problem.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-08 4:03 ` Thiago Jung Bauermann
@ 2025-02-10 8:58 ` Schimpe, Christina
2025-02-11 1:53 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-10 8:58 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Saturday, February 8, 2025 5:04 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the
> shadow stack pointer.
>
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> >> -----Original Message-----
> >> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> >> Sent: Thursday, February 6, 2025 4:35 AM
> >> To: Schimpe, Christina <christina.schimpe@intel.com>
> >> Cc: gdb-patches@sourceware.org
> >> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to
> >> get the shadow stack pointer.
> >>
> >>
> >> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
> >>
> >> > diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
> >> > index 52f265e8e0e..df70cb082a4 100644
> >> > --- a/gdb/gdbarch_components.py
> >> > +++ b/gdb/gdbarch_components.py
> >> > @@ -2822,6 +2822,8 @@ Some targets support special
> >> > hardware-assisted control-flow protection technologies. For
> >> > example, Intel's Control-flow Enforcement Technology (CET)
> >> > provides a shadow stack and
> >> indirect branch tracking.
> >> > To enable inferior calls the function shadow_stack_push has to be provided.
> >> > +The method get_shadow_stack_pointer has to be provided to enable
> >> > +displaced stepping.
> >> >
> >> > Push the address NEW_ADDR on the shadow stack and update the
> >> > shadow stack pointer.
> >> > @@ -2831,3 +2833,11 @@ pointer.
> >> > params=[("CORE_ADDR", "new_addr")],
> >> > predicate=True,
> >> > )
> >> > +
> >> > +Method(
> >> > + type="std::optional<CORE_ADDR>",
> >> > + name="get_shadow_stack_pointer",
> >> > + params=[],
> >> > + predefault="default_get_shadow_stack_pointer",
> >> > + invalid=False,
> >> > +)
> >>
> >> Ideally, there should be a comment on this method entry.
> >>
> >> This method is only used in amd64-tdep.c and i386-tdep.c. IMHO it
> >> would be better to put it in i386_gdbarch_tdep instead.
> >
> > Hi Thiago,
> >
> > Thank you for the review.
> >
> > As also discussed here:
> > https://sourceware.org/pipermail/gdb-patches/2025-February/215266.html
> > , I wonder if it's better to keep the code generic.
>
> Indeed, that's a good point. In the case of this method, I have an additional
> concern though: its callers assume that if gdbarch_get_shadow_stack_pointer
> returns a value, then it means that shadow stacks are enabled in the inferior. But
> this is an x86 particularity. On AArch64, if the processor supports shadow stacks
> then the shadow stack register is always available, even if shadow stacks are
> turned off.
Ah ok, I did not know.
> So I think that there should be an additional method to indicate whether shadow
> stacks are enabled in the inferior.
Yes, that makes sense. But I want to avoid that we call ptrace twice on x86, once in the method
to check the enablement state and once to get the shadow stack pointer.
Would something like that be acceptable as well?
Method(
comment="""
If possible, return the shadow stack pointer. On some architectures, the shadow stack
pointer is available even if the feature is disabled. To return the shadow stack
enablement state configure SHADOW_STACK_ENABLED.
""",
type="std::optional<CORE_ADDR>",
name="get_shadow_stack_pointer",
params=[("bool &", "shadow_stack_enabled")],
predefault="default_get_shadow_stack_pointer",
invalid=False,
)
> > And I plan to use the gdbarch method gdbarch_get_shadow_stack_pointer
> > in a future series for "bt shadow".
> > I shared the commits in this comment:
> > https://sourceware.org/pipermail/gdb-patches/2025-February/215178.html
> > ,
>
> Indeed. I see the same assumption in that code as well. Which makes a lot of
> sense since it only needs to support x86. But that will need to be adapted when
> posted upstream.
Yes, I agree.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-10 8:58 ` Schimpe, Christina
@ 2025-02-11 1:53 ` Thiago Jung Bauermann
2025-02-15 3:45 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-11 1:53 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Sent: Saturday, February 8, 2025 5:04 AM
>> To: Schimpe, Christina <christina.schimpe@intel.com>
>> Cc: gdb-patches@sourceware.org
>> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the
>> shadow stack pointer.
>>
>>
>> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>>
>> >> -----Original Message-----
>> >> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> >> Sent: Thursday, February 6, 2025 4:35 AM
>> >> To: Schimpe, Christina <christina.schimpe@intel.com>
>> >> Cc: gdb-patches@sourceware.org
>> >> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to
>> >> get the shadow stack pointer.
>> >>
>> >>
>> >> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> >>
>> >> > diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
>> >> > index 52f265e8e0e..df70cb082a4 100644
>> >> > --- a/gdb/gdbarch_components.py
>> >> > +++ b/gdb/gdbarch_components.py
>> >> > @@ -2822,6 +2822,8 @@ Some targets support special
>> >> > hardware-assisted control-flow protection technologies. For
>> >> > example, Intel's Control-flow Enforcement Technology (CET)
>> >> > provides a shadow stack and
>> >> indirect branch tracking.
>> >> > To enable inferior calls the function shadow_stack_push has to be provided.
>> >> > +The method get_shadow_stack_pointer has to be provided to enable
>> >> > +displaced stepping.
>> >> >
>> >> > Push the address NEW_ADDR on the shadow stack and update the
>> >> > shadow stack pointer.
>> >> > @@ -2831,3 +2833,11 @@ pointer.
>> >> > params=[("CORE_ADDR", "new_addr")],
>> >> > predicate=True,
>> >> > )
>> >> > +
>> >> > +Method(
>> >> > + type="std::optional<CORE_ADDR>",
>> >> > + name="get_shadow_stack_pointer",
>> >> > + params=[],
>> >> > + predefault="default_get_shadow_stack_pointer",
>> >> > + invalid=False,
>> >> > +)
>> >>
>> >> Ideally, there should be a comment on this method entry.
>> >>
>> >> This method is only used in amd64-tdep.c and i386-tdep.c. IMHO it
>> >> would be better to put it in i386_gdbarch_tdep instead.
>> >
>> > Hi Thiago,
>> >
>> > Thank you for the review.
>> >
>> > As also discussed here:
>> > https://sourceware.org/pipermail/gdb-patches/2025-February/215266.html
>> > , I wonder if it's better to keep the code generic.
>>
>> Indeed, that's a good point. In the case of this method, I have an additional
>> concern though: its callers assume that if gdbarch_get_shadow_stack_pointer
>> returns a value, then it means that shadow stacks are enabled in the inferior. But
>> this is an x86 particularity. On AArch64, if the processor supports shadow stacks
>> then the shadow stack register is always available, even if shadow stacks are
>> turned off.
>
> Ah ok, I did not know.
>
>> So I think that there should be an additional method to indicate whether shadow
>> stacks are enabled in the inferior.
>
> Yes, that makes sense. But I want to avoid that we call ptrace twice on x86, once in the method
> to check the enablement state and once to get the shadow stack pointer.
Ok, makes sense.
> Would something like that be acceptable as well?
>
> Method(
> comment="""
> If possible, return the shadow stack pointer. On some architectures, the shadow stack
> pointer is available even if the feature is disabled. To return the shadow stack
> enablement state configure SHADOW_STACK_ENABLED.
> """,
> type="std::optional<CORE_ADDR>",
> name="get_shadow_stack_pointer",
> params=[("bool &", "shadow_stack_enabled")],
> predefault="default_get_shadow_stack_pointer",
> invalid=False,
> )
Yes, this looks good.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-11 1:53 ` Thiago Jung Bauermann
@ 2025-02-15 3:45 ` Thiago Jung Bauermann
2025-02-16 10:45 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-15 3:45 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
Hello Christina,
Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
>> Would something like that be acceptable as well?
>>
>> Method(
>> comment="""
>> If possible, return the shadow stack pointer. On some architectures, the shadow stack
>> pointer is available even if the feature is disabled. To return the shadow stack
>> enablement state configure SHADOW_STACK_ENABLED.
>> """,
>> type="std::optional<CORE_ADDR>",
>> name="get_shadow_stack_pointer",
>> params=[("bool &", "shadow_stack_enabled")],
>> predefault="default_get_shadow_stack_pointer",
>> invalid=False,
>> )
>
> Yes, this looks good.
I was rebasing my Guarded Control Stack code on top of this series, and
noticed that I will need to access the thread's regcache for the aarch64
implementation of this gdbarch method. Then I noticed that the x86_64
version also needs it, and calls "get_thread_regcache (inferior_thread ())".
It would be better to pass the regcache as an argument instead.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-15 3:45 ` Thiago Jung Bauermann
@ 2025-02-16 10:45 ` Schimpe, Christina
2025-02-20 8:48 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-16 10:45 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Saturday, February 15, 2025 4:45 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get
> the shadow stack pointer.
>
> Hello Christina,
>
> Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:
>
> > "Schimpe, Christina" <christina.schimpe@intel.com> writes:
> >
> >> Would something like that be acceptable as well?
> >>
> >> Method(
> >> comment="""
> >> If possible, return the shadow stack pointer. On some architectures,
> >> the shadow stack pointer is available even if the feature is
> >> disabled. To return the shadow stack enablement state configure
> SHADOW_STACK_ENABLED.
> >> """,
> >> type="std::optional<CORE_ADDR>",
> >> name="get_shadow_stack_pointer",
> >> params=[("bool &", "shadow_stack_enabled")],
> >> predefault="default_get_shadow_stack_pointer",
> >> invalid=False,
> >> )
> >
> > Yes, this looks good.
>
> I was rebasing my Guarded Control Stack code on top of this series, and
> noticed that I will need to access the thread's regcache for the aarch64
> implementation of this gdbarch method. Then I noticed that the x86_64
> version also needs it, and calls "get_thread_regcache (inferior_thread ())".
> It would be better to pass the regcache as an argument instead.
Hi Thiago,
Do you mean instead or in addition?
I thought you also need the parameter ("bool &", "shadow_stack_enabled").
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-16 10:45 ` Schimpe, Christina
@ 2025-02-20 8:48 ` Schimpe, Christina
2025-02-21 5:10 ` Thiago Jung Bauermann
0 siblings, 1 reply; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-20 8:48 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Schimpe, Christina
> Sent: Sunday, February 16, 2025 11:45 AM
> To: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Cc: gdb-patches@sourceware.org
> Subject: RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get
> the shadow stack pointer.
>
> > -----Original Message-----
> > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> > Sent: Saturday, February 15, 2025 4:45 AM
> > To: Schimpe, Christina <christina.schimpe@intel.com>
> > Cc: gdb-patches@sourceware.org
> > Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to
> > get the shadow stack pointer.
> >
> > Hello Christina,
> >
> > Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:
> >
> > > "Schimpe, Christina" <christina.schimpe@intel.com> writes:
> > >
> > >> Would something like that be acceptable as well?
> > >>
> > >> Method(
> > >> comment="""
> > >> If possible, return the shadow stack pointer. On some
> > >> architectures, the shadow stack pointer is available even if the
> > >> feature is disabled. To return the shadow stack enablement state
> > >> configure
> > SHADOW_STACK_ENABLED.
> > >> """,
> > >> type="std::optional<CORE_ADDR>",
> > >> name="get_shadow_stack_pointer",
> > >> params=[("bool &", "shadow_stack_enabled")],
> > >> predefault="default_get_shadow_stack_pointer",
> > >> invalid=False,
> > >> )
> > >
> > > Yes, this looks good.
> >
> > I was rebasing my Guarded Control Stack code on top of this series,
> > and noticed that I will need to access the thread's regcache for the
> > aarch64 implementation of this gdbarch method. Then I noticed that the
> > x86_64 version also needs it, and calls "get_thread_regcache
> (inferior_thread ())".
> > It would be better to pass the regcache as an argument instead.
>
> Hi Thiago,
>
> Do you mean instead or in addition?
> I thought you also need the parameter ("bool &", "shadow_stack_enabled").
>
> Christina
Hi Thiago,
Since you wrote instead I now have the regcache argument only in the v2 of this series.
https://sourceware.org/pipermail/gdb-patches/2025-February/215650.html
Please let me know if you see any problems with that.
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
* Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-20 8:48 ` Schimpe, Christina
@ 2025-02-21 5:10 ` Thiago Jung Bauermann
2025-02-21 9:41 ` Schimpe, Christina
0 siblings, 1 reply; 72+ messages in thread
From: Thiago Jung Bauermann @ 2025-02-21 5:10 UTC (permalink / raw)
To: Schimpe, Christina; +Cc: gdb-patches
Hello Christina,
"Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> -----Original Message-----
>> From: Schimpe, Christina
>> Sent: Sunday, February 16, 2025 11:45 AM
>> To: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> Cc: gdb-patches@sourceware.org
>> Subject: RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get
>> the shadow stack pointer.
>>
>> > -----Original Message-----
>> > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
>> > Sent: Saturday, February 15, 2025 4:45 AM
>> > To: Schimpe, Christina <christina.schimpe@intel.com>
>> > Cc: gdb-patches@sourceware.org
>> > Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to
>> > get the shadow stack pointer.
>> >
>> > Hello Christina,
>> >
>> > Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:
>> >
>> > > "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>> > >
>> > >> Would something like that be acceptable as well?
>> > >>
>> > >> Method(
>> > >> comment="""
>> > >> If possible, return the shadow stack pointer. On some
>> > >> architectures, the shadow stack pointer is available even if the
>> > >> feature is disabled. To return the shadow stack enablement state
>> > >> configure
>> > SHADOW_STACK_ENABLED.
>> > >> """,
>> > >> type="std::optional<CORE_ADDR>",
>> > >> name="get_shadow_stack_pointer",
>> > >> params=[("bool &", "shadow_stack_enabled")],
>> > >> predefault="default_get_shadow_stack_pointer",
>> > >> invalid=False,
>> > >> )
>> > >
>> > > Yes, this looks good.
>> >
>> > I was rebasing my Guarded Control Stack code on top of this series,
>> > and noticed that I will need to access the thread's regcache for the
>> > aarch64 implementation of this gdbarch method. Then I noticed that the
>> > x86_64 version also needs it, and calls "get_thread_regcache
>> (inferior_thread ())".
>> > It would be better to pass the regcache as an argument instead.
>>
>> Hi Thiago,
>>
>> Do you mean instead or in addition?
>> I thought you also need the parameter ("bool &", "shadow_stack_enabled").
Sorry for not answering your previous email. I switched my focus to the
variable-length registers thread and forgot that I hadn't answered this
question yet.
> Since you wrote instead I now have the regcache argument only in the v2 of this series.
I wrote "instead" meaning "instead of calling get_thread_regcache inside
of the method implementation". Sorry for being unclear.
> https://sourceware.org/pipermail/gdb-patches/2025-February/215650.html
Strange, for some reason the threading on the patch series got broken up
into three parts. I thought I had missed some of the patches but now
I see I received the whole series.
> Please let me know if you see any problems with that.
For AArch64 GCS I need the shadow_stack_enabled argument so that callers
can tell whether the shadow stack is enabled or disabled.
--
Thiago
^ permalink raw reply [flat|nested] 72+ messages in thread
* RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer.
2025-02-21 5:10 ` Thiago Jung Bauermann
@ 2025-02-21 9:41 ` Schimpe, Christina
0 siblings, 0 replies; 72+ messages in thread
From: Schimpe, Christina @ 2025-02-21 9:41 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches
> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Friday, February 21, 2025 6:11 AM
> To: Schimpe, Christina <christina.schimpe@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get
> the shadow stack pointer.
>
> Hello Christina,
>
> "Schimpe, Christina" <christina.schimpe@intel.com> writes:
>
> >> -----Original Message-----
> >> From: Schimpe, Christina
> >> Sent: Sunday, February 16, 2025 11:45 AM
> >> To: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> >> Cc: gdb-patches@sourceware.org
> >> Subject: RE: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to
> >> get the shadow stack pointer.
> >>
> >> > -----Original Message-----
> >> > From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> >> > Sent: Saturday, February 15, 2025 4:45 AM
> >> > To: Schimpe, Christina <christina.schimpe@intel.com>
> >> > Cc: gdb-patches@sourceware.org
> >> > Subject: Re: [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method
> >> > to get the shadow stack pointer.
> >> >
> >> > Hello Christina,
> >> >
> >> > Thiago Jung Bauermann <thiago.bauermann@linaro.org> writes:
> >> >
> >> > > "Schimpe, Christina" <christina.schimpe@intel.com> writes:
> >> > >
> >> > >> Would something like that be acceptable as well?
> >> > >>
> >> > >> Method(
> >> > >> comment="""
> >> > >> If possible, return the shadow stack pointer. On some
> >> > >> architectures, the shadow stack pointer is available even if the
> >> > >> feature is disabled. To return the shadow stack enablement
> >> > >> state configure
> >> > SHADOW_STACK_ENABLED.
> >> > >> """,
> >> > >> type="std::optional<CORE_ADDR>",
> >> > >> name="get_shadow_stack_pointer", params=[("bool &",
> >> > >> "shadow_stack_enabled")],
> >> > >> predefault="default_get_shadow_stack_pointer",
> >> > >> invalid=False,
> >> > >> )
> >> > >
> >> > > Yes, this looks good.
> >> >
> >> > I was rebasing my Guarded Control Stack code on top of this series,
> >> > and noticed that I will need to access the thread's regcache for
> >> > the
> >> > aarch64 implementation of this gdbarch method. Then I noticed that
> >> > the
> >> > x86_64 version also needs it, and calls "get_thread_regcache
> >> (inferior_thread ())".
> >> > It would be better to pass the regcache as an argument instead.
> >>
> >> Hi Thiago,
> >>
> >> Do you mean instead or in addition?
> >> I thought you also need the parameter ("bool &",
> "shadow_stack_enabled").
>
> Sorry for not answering your previous email. I switched my focus to the
> variable-length registers thread and forgot that I hadn't answered this
> question yet.
>
> > Since you wrote instead I now have the regcache argument only in the v2 of
> this series.
>
> I wrote "instead" meaning "instead of calling get_thread_regcache inside of
> the method implementation". Sorry for being unclear.
>
> > https://sourceware.org/pipermail/gdb-patches/2025-February/215650.html
>
> Strange, for some reason the threading on the patch series got broken up
> into three parts. I thought I had missed some of the patches but now I see I
> received the whole series.
>
> > Please let me know if you see any problems with that.
>
> For AArch64 GCS I need the shadow_stack_enabled argument so that callers
> can tell whether the shadow stack is enabled or disabled.
Ah ok, no problem. It will be part of the next version then. 😊
Christina
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 72+ messages in thread
end of thread, other threads:[~2025-02-21 9:42 UTC | newest]
Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-12-20 20:04 [PATCH 00/12] Add CET shadow stack support Schimpe, Christina
2024-12-20 20:04 ` [PATCH 01/12] gdb, testsuite: Rename set_sanitizer_default to append_environment Schimpe, Christina
2025-01-28 13:45 ` Guinevere Larsen
2025-01-30 13:07 ` Schimpe, Christina
2025-01-30 14:27 ` Tom de Vries
2025-01-30 16:39 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 02/12] gdbserver: Add optional runtime register set type Schimpe, Christina
2025-01-28 13:35 ` Guinevere Larsen
2025-01-30 10:28 ` Schimpe, Christina
2025-01-30 13:53 ` Guinevere Larsen
2025-01-30 17:43 ` Schimpe, Christina
2025-02-06 2:59 ` Thiago Jung Bauermann
2025-02-06 12:15 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 03/12] gdbserver: Add assert in x86_linux_read_description Schimpe, Christina
2025-02-06 3:00 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 04/12] gdb: Sync up x86-gcc-cpuid.h with cpuid.h from gcc 14 branch Schimpe, Christina
2025-02-06 3:03 ` Thiago Jung Bauermann
2025-02-06 12:23 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 05/12] gdb, gdbserver: Use xstate_bv for target description creation on x86 Schimpe, Christina
2025-01-30 14:51 ` Guinevere Larsen
2025-01-30 16:45 ` Schimpe, Christina
2025-02-06 3:09 ` Thiago Jung Bauermann
2025-02-06 12:33 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 06/12] gdb, gdbserver: Add support of Intel shadow stack pointer register Schimpe, Christina
2025-02-06 3:13 ` Thiago Jung Bauermann
2025-02-06 14:33 ` Schimpe, Christina
2025-02-08 3:44 ` Thiago Jung Bauermann
2024-12-20 20:04 ` [PATCH 07/12] gdb, bfd: amd64 linux coredump support with shadow stack Schimpe, Christina
2025-02-06 3:15 ` Thiago Jung Bauermann
2025-02-07 11:54 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 08/12] gdb: Handle shadow stack pointer register unwinding for amd64 linux Schimpe, Christina
2025-01-30 14:29 ` Guinevere Larsen
2025-01-30 16:11 ` Schimpe, Christina
2025-01-30 16:13 ` Guinevere Larsen
2025-01-30 16:40 ` Schimpe, Christina
2025-02-06 3:30 ` Thiago Jung Bauermann
2025-02-06 14:40 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 09/12] gdb, gdbarch: Enable inferior calls for shadow stack support Schimpe, Christina
2025-02-06 3:31 ` Thiago Jung Bauermann
2025-02-06 15:07 ` Schimpe, Christina
2025-02-08 3:57 ` Thiago Jung Bauermann
2025-02-10 8:37 ` Schimpe, Christina
2024-12-20 20:04 ` [PATCH 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls Schimpe, Christina
2025-02-06 3:34 ` Thiago Jung Bauermann
2025-02-07 11:55 ` Schimpe, Christina
2024-12-20 20:05 ` [PATCH 11/12] gdb, gdbarch: Introduce gdbarch method to get the shadow stack pointer Schimpe, Christina
2025-01-28 20:27 ` Guinevere Larsen
2025-01-30 10:33 ` Luis Machado
2025-01-30 12:34 ` Schimpe, Christina
2025-01-30 13:42 ` Guinevere Larsen
2025-02-06 3:35 ` Thiago Jung Bauermann
2025-02-07 12:01 ` Schimpe, Christina
2025-02-08 4:03 ` Thiago Jung Bauermann
2025-02-10 8:58 ` Schimpe, Christina
2025-02-11 1:53 ` Thiago Jung Bauermann
2025-02-15 3:45 ` Thiago Jung Bauermann
2025-02-16 10:45 ` Schimpe, Christina
2025-02-20 8:48 ` Schimpe, Christina
2025-02-21 5:10 ` Thiago Jung Bauermann
2025-02-21 9:41 ` Schimpe, Christina
2024-12-20 20:05 ` [PATCH 12/12] gdb: Enable displaced stepping with shadow stack on amd64 linux Schimpe, Christina
2024-12-20 20:14 ` Eli Zaretskii
2025-01-02 9:04 ` Schimpe, Christina
2025-01-02 9:15 ` Eli Zaretskii
2025-02-06 3:37 ` Thiago Jung Bauermann
2025-01-16 14:01 ` [PING][PATCH 00/12] Add CET shadow stack support Schimpe, Christina
2025-01-27 9:44 ` [PING*2][PATCH " Schimpe, Christina
2025-01-30 15:01 ` [PATCH " Guinevere Larsen
2025-01-30 17:46 ` Schimpe, Christina
2025-02-04 3:57 ` Thiago Jung Bauermann
2025-02-04 9:40 ` Schimpe, Christina
2025-02-06 3:44 ` Thiago Jung Bauermann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox