[PATCH v2 0/9] Add new command to print the shadow stack backtrace

Christina Schimpe
2026-01-23T08:06:26Z

Hi all,

this is my v2 for the series
"Add new command to print the shadow stack backtrace".

v1 of this series can be found here:
https://sourceware.org/pipermail/gdb-patches/2025-September/221141.html

Not all opens are resolved, but this version already contains several
changes (and I'll be out for ~3 weeks), so I decided to post v2 anyway.

For the implementation of -past-main, I already have a prototype available,
but it's not ready yet to be included in this version. I will add it in v3
of this series.

Changes since v1:
- Changed from the subcommand "bt shadow" to the command option "bt -shadow"
The discussion for this decision is summarized here:
https://sourceware.org/pipermail/gdb-patches/2025-November/222374.html.
- Changed the interface of the gdbarch hook is_no_return_shadow_stack_address,
so that we can configure a string that should be displayed instead of the
non-return address on the shadow stack. For Intel CET, we now display
<sigframe token> instead of the sigframe token on the shadow stack.
- A number of changes to make this command work with ARM GCS, as discussed
with Thiago:
* a new gdbarch hook get_shadow_stack_size, since for ARM'S GCS the
calculation based on the shadow stack range is different
* additional calls to the gdbarch hook top_addr_empty_shadow_stack in
various locations.
- amd64 implementation for the gdbarch hook top_addr_empty_shadow_stack,
since it turned out that we need it for CET shadow stacks as well.
- Fixed a number of issues reported by Thiago, such as:
* problems with a negative COUNT parameter (thanks again for catching
that!)
* issues with the target independent unwinding function for SSP
(shadow-stack.c::dwarf2_prev_ssp).
- Changed the printing of line numbers so that it is now consistent with the
normal backtrace. Previously, we always printed the line corresponding to
the return address; now we print the line containing the call.
- Added checks at the beginning of the command function to verify that all
necessary gdbarch hooks required to print the shadow stack backtrace are
implemented, so we now fail with an appropriate error message if any are
missing.
- Updated the NEWS and documentation parts for the changes described above.

Opens:
1) Thiago suggested changing the frame numbering so that it always starts
at #1, since for the shadow stack we don't have frame #0 printed by the
normal backtrace.
2) Or, consider printing frame arguments and frame #0 similarly to what
the normal backtrace does.
3) For non-return addresses on the shadow stack, we want to display a string,
as already implemented for signals. For inferior calls, we also want to
display <function called by GDB>. The return address for inferior calls
is pushed onto the shadow stack by GDB, but we currently don’t have a way
to distinguish this address from normal return addresses. Thiago suggested
pushing the return address together with a marker, but it’s still unclear
how this marker should look like.
4) For signals, we also want to print <signal handler called>, as in the
normal backtrace. Since in this case we have a normal return address on
the shadow stack, it’s not yet clear to me how to implement this.
5) Remove annotations. Based on Tom's input, I think we should drop them,
but I am not yet sure how exactly. Please see my latest response here:
https://sourceware.org/pipermail/gdb-patches/2025-October/221652.html

My latest reply regarding items 1-4 can be found here:
https://sourceware.org/pipermail/gdb-patches/2026-January/224054.html

Note that this version is still breaking GCS support, since for patch #1,
I don't have the aarch64 implementation of top_addr_empty_shadow_stack
included. It will be part of v3 of this series, once I receive Thiago's
input.

Thiago also indicated that he wants to introduce additional commands for GCS
"info shadow-stack enabled/locked". However, for CET shadow stacks we
currently don’t see a need for this; please see my latest response on this
topic:
https://sourceware.org/pipermail/gdb-patches/2025-November/222408.html

This is an example shadow stack backtrace on amd64:
~~~
(gdb) bt -shadow
#0 0x000055555555514a in call1 at tmp/amd64-shadow-stack.c:27
#1 0x000055555555515f in main at tmp/amd64-shadow-stack.c:38
#2 0x00007ffff7c2a1ca in __libc_start_call_main at ../sysdeps/nptl/libc_start_call_main.h:58
#3 0x00007ffff7c2a28b in __libc_start_main_impl at ../csu/libc-start.c:360
#4 0x0000555555555065 in _start
~~~

For comparison, this is the normal backtrace (with and without -past-main):
~~~
(gdb) bt
#0 call2 () at tmp/amd64-shadow-stack.c:21
#1 0x000055555555514a in call1 () at tmp/amd64-shadow-stack.c:27
#2 0x000055555555515f in main () at tmp/amd64-shadow-stack.c:38
(gdb) bt -past-main
#0 call2 () at tmp/amd64-shadow-stack.c:21
#1 0x000055555555514a in call1 () at tmp/amd64-shadow-stack.c:27
#2 0x000055555555515f in main () at tmp/amd64-shadow-stack.c:38
#3 0x00007ffff7c2a1ca in __libc_start_call_main (main=main@entry=0x55555555514c , argc=argc@entry=1,
argv=argv@entry=0x7fffffffe228) at ../sysdeps/nptl/libc_start_call_main.h:58
#4 0x00007ffff7c2a28b in __libc_start_main_impl (main=0x55555555514c , argc=1, argv=0x7fffffffe228, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe218) at ../csu/libc-start.c:360
#5 0x0000555555555065 in _start ()
~~~

I am happy about your feedback!

Christina

Christina Schimpe (9):
gdb: Generalize handling of the shadow stack pointer.
gdb: Refactor 'stack.c:print_frame'.
gdb: Introduce 'stack.c:print_pc' function without frame argument.
gdb: Refactor 'find_symbol_funname' and 'info_frame_command_core' in
stack.c.
gdb: Refactor 'stack.c:print_frame_info'.
gdb: Add command option 'bt -shadow' to print the shadow stack
backtrace.
gdb: Provide gdbarch hook to distinguish shadow stack backtrace
elements.
gdb: Implement the hook 'is_no_return_shadow_stack_address' for amd64
linux.
gdb, mi: Add -shadow-stack-list-frames command

gdb/Makefile.in | 2 +
gdb/NEWS | 13 +
gdb/aarch64-linux-tdep.c | 51 +-
gdb/aarch64-tdep.c | 46 +-
gdb/amd64-linux-tdep.c | 188 +++---
gdb/amd64-tdep.c | 20 +
gdb/annotate.c | 93 ++-
gdb/annotate.h | 18 +-
gdb/doc/gdb.texinfo | 94 +++
gdb/gdbarch-gen.c | 190 +++++-
gdb/gdbarch-gen.h | 93 ++-
gdb/gdbarch.h | 1 +
gdb/gdbarch_components.py | 120 +++-
gdb/infcall.c | 4 +-
gdb/linux-tdep.c | 9 +-
gdb/mi/mi-cmd-stack.c | 142 ++++
gdb/mi/mi-cmds.c | 2 +
gdb/mi/mi-cmds.h | 1 +
gdb/shadow-stack.c | 633 ++++++++++++++++++
gdb/shadow-stack.h | 95 +++
gdb/stack.c | 323 +++++----
gdb/stack.h | 55 ++
.../amd64-shadow-stack-backtrace-signal.exp | 49 ++
.../gdb.arch/amd64-shadow-stack-cmds.exp | 88 +++
.../gdb.arch/amd64-shadow-stack-signal.c | 31 +
gdb/testsuite/gdb.base/options.exp | 2 +-
.../gdb.mi/mi-shadow-stack-signal.exp | 69 ++
gdb/testsuite/gdb.mi/mi-shadow-stack.exp | 65 ++
28 files changed, 2097 insertions(+), 400 deletions(-)
create mode 100644 gdb/shadow-stack.c
create mode 100644 gdb/shadow-stack.h
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-backtrace-signal.exp
create mode 100644 gdb/testsuite/gdb.arch/amd64-shadow-stack-signal.c
create mode 100644 gdb/testsuite/gdb.mi/mi-shadow-stack-signal.exp
create mode 100644 gdb/testsuite/gdb.mi/mi-shadow-stack.exp

--
2.34.1

Intel Deutschland GmbH
Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht München HRB 186928