From: Christina Joos <christina.joos@intel.com>
To: gdb-patches@sourceware.org
Cc: thiago.bauermann@linaro.org, tom@tromey.com, luis.machado.foss@gmail.com
Subject: [PATCH v5 12/13] gdb: Enable signal trampolines in the shadow stack backtrace.
Date: Thu, 24 Sep 2026 10:33:09 +0200 [thread overview]
Message-ID: <20260924083311.1961530-13-christina.joos@intel.com> (raw)
In-Reply-To: <20260924083311.1961530-1-christina.joos@intel.com>
Similar to the normal backtrace we now print "<signal handler called>"
in the shadow stack backtrace, too.
~~~
(gdb) bt -shadow
/#0 <signal handler called>
/#1 <sigframe token>
/#2 0x00007ffff7c4527e in __GI_raise at ../sysdeps/posix/raise.c:26
/#3 0x0000555555555175 in main at /tmp/gdb.arch/amd64-shadow-stack-signal.c:29
(gdb) bt
/#0 handler (signo=10) at /tmp/amd64-shadow-stack-signal.c:23
/#1 <signal handler called>
/#2 __pthread_kill_implementation (no_tid=0, signo=10, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
/#3 __pthread_kill_internal (signo=10, threadid=<optimized out>) at ./nptl/pthread_kill.c:78
/#4 __GI___pthread_kill (threadid=<optimized out>, signo=signo@entry=10) at ./nptl/pthread_kill.c:89
/#5 0x00007ffff7c4527e in __GI_raise (sig=10) at ../sysdeps/posix/raise.c:26
/#6 0x0000555555555175 in main ()
at /tmp/amd64-shadow-stack-signal.c:29
~~~
Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
---
gdb/amd64-linux-tdep.c | 36 +++++++++++--------
gdb/gdbarch-gen.c | 32 +++++++++++++++++
gdb/gdbarch-gen.h | 11 ++++++
gdb/gdbarch_components.py | 13 +++++++
gdb/shadow-stack.c | 11 ++++++
gdb/shadow-stack.h | 5 +++
.../amd64-shadow-stack-backtrace-signal.exp | 2 +-
7 files changed, 95 insertions(+), 15 deletions(-)
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
index 49609e5ac94..8a7a1ed371c 100644
--- a/gdb/amd64-linux-tdep.c
+++ b/gdb/amd64-linux-tdep.c
@@ -147,12 +147,10 @@ static const gdb_byte amd64_x32_linux_sigtramp_code[] =
the routine. Otherwise, return 0. */
static CORE_ADDR
-amd64_linux_sigtramp_start (const frame_info_ptr &this_frame)
+amd64_linux_sigtramp_start (gdbarch *gdbarch, CORE_ADDR pc)
{
- struct gdbarch *gdbarch;
const gdb_byte *sigtramp_code;
- CORE_ADDR pc = get_frame_pc (this_frame);
- gdb_byte buf[LINUX_SIGTRAMP_LEN];
+ std::array<gdb_byte, LINUX_SIGTRAMP_LEN> buf {};
/* We only recognize a signal trampoline if PC is at the start of
one of the two instructions. We optimize for finding the PC at
@@ -161,7 +159,7 @@ amd64_linux_sigtramp_start (const frame_info_ptr &this_frame)
PC is not at the start of the instruction sequence, there will be
a few trailing readable bytes on the stack. */
- if (!safe_frame_unwind_memory (this_frame, pc, buf))
+ if (target_read_memory (pc, buf.data (), buf.size ()) != 0)
return 0;
if (buf[0] != LINUX_SIGTRAMP_INSN0)
@@ -170,28 +168,25 @@ amd64_linux_sigtramp_start (const frame_info_ptr &this_frame)
return 0;
pc -= LINUX_SIGTRAMP_OFFSET1;
- if (!safe_frame_unwind_memory (this_frame, pc, buf))
+ if (target_read_memory (pc, buf.data (), buf.size ()) != 0)
return 0;
}
- gdbarch = get_frame_arch (this_frame);
if (gdbarch_ptr_bit (gdbarch) == 32)
sigtramp_code = amd64_x32_linux_sigtramp_code;
else
sigtramp_code = amd64_linux_sigtramp_code;
- if (memcmp (buf, sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+ if (memcmp (buf.data (), sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
return 0;
return pc;
}
-/* Return whether THIS_FRAME corresponds to a GNU/Linux sigtramp
- routine. */
+/* Return whether PC is pointing to a GNU/Linux sigtramp routine. */
static int
-amd64_linux_sigtramp_p (const frame_info_ptr &this_frame)
+amd64_linux_is_sigtramp_pc (gdbarch* gdbarch, const CORE_ADDR pc)
{
- CORE_ADDR pc = get_frame_pc (this_frame);
const char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
@@ -203,11 +198,22 @@ amd64_linux_sigtramp_p (const frame_info_ptr &this_frame)
__sigaction, or __libc_sigaction (all aliases to the same
function). */
if (name == NULL || strstr (name, "sigaction") != NULL)
- return (amd64_linux_sigtramp_start (this_frame) != 0);
+ return (amd64_linux_sigtramp_start (gdbarch, pc) != 0);
return (streq ("__restore_rt", name));
}
+/* Return whether THIS_FRAME corresponds to a GNU/Linux sigtramp
+ routine. */
+
+static int
+amd64_linux_sigtramp_frame_p (const frame_info_ptr &this_frame)
+{
+ gdbarch *gdbarch = get_frame_arch (this_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
+ return amd64_linux_is_sigtramp_pc (gdbarch, pc);
+}
+
/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>. */
#define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
@@ -2026,7 +2032,7 @@ amd64_linux_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch,
linux_init_abi (info, gdbarch, num_disp_step_buffers);
- tdep->sigtramp_p = amd64_linux_sigtramp_p;
+ tdep->sigtramp_p = amd64_linux_sigtramp_frame_p;
tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
@@ -2084,6 +2090,8 @@ amd64_linux_init_abi_common (struct gdbarch_info info, struct gdbarch *gdbarch,
set_gdbarch_is_no_return_shadow_stack_address
(gdbarch, amd64_linux_is_no_return_shadow_stack_address);
+
+ set_gdbarch_is_sigtramp_pc (gdbarch, amd64_linux_is_sigtramp_pc);
}
static void
diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c
index 894522a7243..3d30a4e2902 100644
--- a/gdb/gdbarch-gen.c
+++ b/gdb/gdbarch-gen.c
@@ -257,6 +257,7 @@ struct gdbarch
gdbarch_top_addr_empty_shadow_stack_ftype *top_addr_empty_shadow_stack = nullptr;
int shadow_stack_element_size_aligned = 8;
gdbarch_is_no_return_shadow_stack_address_ftype *is_no_return_shadow_stack_address = nullptr;
+ gdbarch_is_sigtramp_pc_ftype *is_sigtramp_pc = nullptr;
};
/* Create a new ``struct gdbarch'' based on information provided by
@@ -521,6 +522,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of top_addr_empty_shadow_stack, has predicate. */
/* Skip verify of shadow_stack_element_size_aligned, invalid_p == 0. */
/* Skip verify of is_no_return_shadow_stack_address, has predicate. */
+ /* Skip verify of is_sigtramp_pc, has predicate. */
if (!log.empty ())
internal_error (_("verify_gdbarch: the following are invalid ...%s"),
log.c_str ());
@@ -1365,6 +1367,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: is_no_return_shadow_stack_address = <%s>\n",
host_address_to_string (gdbarch->is_no_return_shadow_stack_address));
+ gdb_printf (file,
+ "gdbarch_dump: gdbarch_is_sigtramp_pc_p() = %d\n",
+ gdbarch_is_sigtramp_pc_p (gdbarch));
+ gdb_printf (file,
+ "gdbarch_dump: is_sigtramp_pc = <%s>\n",
+ host_address_to_string (gdbarch->is_sigtramp_pc));
if (gdbarch->dump_tdep != nullptr)
gdbarch->dump_tdep (gdbarch, file);
}
@@ -5394,3 +5402,27 @@ set_gdbarch_is_no_return_shadow_stack_address (struct gdbarch *gdbarch,
{
gdbarch->is_no_return_shadow_stack_address = is_no_return_shadow_stack_address;
}
+
+bool
+gdbarch_is_sigtramp_pc_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != nullptr);
+ return gdbarch->is_sigtramp_pc != nullptr;
+}
+
+int
+gdbarch_is_sigtramp_pc (struct gdbarch *gdbarch, const CORE_ADDR pc)
+{
+ gdb_assert (gdbarch != nullptr);
+ gdb_assert (gdbarch->is_sigtramp_pc != nullptr);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_is_sigtramp_pc called\n");
+ return gdbarch->is_sigtramp_pc (gdbarch, pc);
+}
+
+void
+set_gdbarch_is_sigtramp_pc (struct gdbarch *gdbarch,
+ gdbarch_is_sigtramp_pc_ftype is_sigtramp_pc)
+{
+ gdbarch->is_sigtramp_pc = is_sigtramp_pc;
+}
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index 08358b18fcf..e78aad9a89b 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -1814,3 +1814,14 @@ bool gdbarch_is_no_return_shadow_stack_address_p (struct gdbarch *gdbarch);
using gdbarch_is_no_return_shadow_stack_address_ftype = std::optional<shadow_stack_frame_info> (struct gdbarch *gdbarch, const CORE_ADDR ssp, const CORE_ADDR value, const unsigned long level);
std::optional<shadow_stack_frame_info> gdbarch_is_no_return_shadow_stack_address (struct gdbarch *gdbarch, const CORE_ADDR ssp, const CORE_ADDR value, const unsigned long level);
void set_gdbarch_is_no_return_shadow_stack_address (struct gdbarch *gdbarch, gdbarch_is_no_return_shadow_stack_address_ftype *is_no_return_shadow_stack_address);
+
+/* Return whether PC is pointing to a sigtramp routine. This is needed in
+ addition to tdep->sigtramp_p, which requires a frame, because some callers
+ (e.g. the shadow stack backtrace command) only have a return address
+ available. */
+
+bool gdbarch_is_sigtramp_pc_p (struct gdbarch *gdbarch);
+
+using gdbarch_is_sigtramp_pc_ftype = int (struct gdbarch *gdbarch, const CORE_ADDR pc);
+int gdbarch_is_sigtramp_pc (struct gdbarch *gdbarch, const CORE_ADDR pc);
+void set_gdbarch_is_sigtramp_pc (struct gdbarch *gdbarch, gdbarch_is_sigtramp_pc_ftype *is_sigtramp_pc);
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index e8677d641bb..16737efe3a0 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -2872,3 +2872,16 @@ backtrace. Otherwise, return an empty optional.
],
predicate=True,
)
+
+Method(
+ comment="""
+Return whether PC is pointing to a sigtramp routine. This is needed in
+addition to tdep->sigtramp_p, which requires a frame, because some callers
+(e.g. the shadow stack backtrace command) only have a return address
+available.
+""",
+ type="int",
+ name="is_sigtramp_pc",
+ params=[("const CORE_ADDR", "pc")],
+ predicate=True,
+)
diff --git a/gdb/shadow-stack.c b/gdb/shadow-stack.c
index a31bb02bceb..86633cbcb49 100644
--- a/gdb/shadow-stack.c
+++ b/gdb/shadow-stack.c
@@ -267,6 +267,8 @@ do_print_shadow_stack_frame_info
}
else if (frame.type == ssp_frame_type::dummy_frame)
str = "<function called from gdb>";
+ else if (frame.type == ssp_frame_type::sigtramp_frame)
+ str = "<signal handler called>";
else
gdb_assert_not_reached ("Invalid shadow stack frame type.");
@@ -480,6 +482,15 @@ get_shadow_stack_frame_info
if (sal_arch == nullptr)
sal_arch = fallback_arch;
+ if (gdbarch_is_sigtramp_pc_p (sal_arch)
+ && gdbarch_is_sigtramp_pc (sal_arch, value))
+ {
+ return std::optional<shadow_stack_frame_info>
+ ({ssp, value, level, sal_arch, sal,
+ ssp_frame_type::sigtramp_frame, {},
+ ssp_unwind_stop_reason::no_error});
+ }
+
return std::optional<shadow_stack_frame_info>
({ssp, value, level, sal_arch, sal,
ssp_frame_type::normal_frame, {},
diff --git a/gdb/shadow-stack.h b/gdb/shadow-stack.h
index 225fd3996cd..d4b0d53acf3 100644
--- a/gdb/shadow-stack.h
+++ b/gdb/shadow-stack.h
@@ -80,6 +80,11 @@ enum class ssp_frame_type
/* A fake frame, created by GDB when performing an inferior function
call. */
dummy_frame,
+
+ /* A shadow stack frame containing a return address which is in a signal
+ handler, similar to the SIGTRAMP_FRAME frame type in
+ frame.h:frame_type. */
+ sigtramp_frame,
};
/* Information of a shadow stack frame belonging to a shadow stack element
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-backtrace-signal.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-backtrace-signal.exp
index 21373dc07f3..34559f0bd04 100644
--- a/gdb/testsuite/gdb.arch/amd64-shadow-stack-backtrace-signal.exp
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-backtrace-signal.exp
@@ -41,7 +41,7 @@ save_vars { ::env(GLIBC_TUNABLES) } {
# Test shadow stack backtrace including <sigframe token>.
gdb_test "bt -shadow" \
[multi_line \
- "#0\[ \t\]*$hex in \[^\r\n\]+" \
+ "#0\[ \t\]*<signal handler called>" \
"#1\[ \t\]*<sigframe token>" \
"#2\[ \t\]*$hex in \[^\r\n\]+" \
".*" ] \
--
2.53.0
________________________________________
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 (89) 99143-0
www.intel.de
Managing Directors: Candice Moore, Jeffrey Schneiderman, Ramachandran Sitaraman
Chairperson of the Supervisory Board: Sonja Pierer
Registered Seat: Munich Commercial Register B: Amtsgericht Munich HRB 186928
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
next prev parent reply other threads:[~2026-09-24 8:37 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 8:32 [PATCH v5 00/13] Add new command to print " Christina Joos
2026-09-24 8:32 ` [PATCH v5 01/13] gdb: Generalize handling of the shadow stack pointer Christina Joos
2026-09-24 21:03 ` Thiago Jung Bauermann
2026-09-24 8:32 ` [PATCH v5 02/13] aarch64: Implement gdbarch function top_addr_empty_shadow_stack Christina Joos
2026-09-24 21:04 ` Thiago Jung Bauermann
2026-09-24 8:33 ` [PATCH v5 03/13] gdb: Add get_main_func_start_pc to refactor frame.c:inside_main_func Christina Joos
2026-09-24 8:33 ` [PATCH v5 04/13] gdb: Refactor 'stack.c:print_frame' Christina Joos
2026-09-24 8:33 ` [PATCH v5 05/13] gdb: Introduce 'stack.c:print_pc' function without frame argument Christina Joos
2026-09-24 8:33 ` [PATCH v5 06/13] gdb: Refactor 'find_symbol_funname' and 'info_frame_command_core' in stack.c Christina Joos
2026-09-24 8:33 ` [PATCH v5 07/13] gdb: Refactor 'stack.c:print_frame_info' Christina Joos
2026-09-24 8:33 ` [PATCH v5 08/13] gdb: Add command option 'bt -shadow' to print the shadow stack backtrace Christina Joos
2026-09-24 9:37 ` Eli Zaretskii
2026-09-24 8:33 ` [PATCH v5 09/13] gdb: Provide gdbarch hook to distinguish shadow stack backtrace elements Christina Joos
2026-09-24 9:29 ` Eli Zaretskii
2026-09-24 13:10 ` Joos, Christina
2026-09-24 8:33 ` [PATCH v5 10/13] gdb: Implement the hook 'is_no_return_shadow_stack_address' for amd64 linux Christina Joos
2026-09-24 8:33 ` [PATCH v5 11/13] gdb: Enable inferior calls in the shadow stack backtrace Christina Joos
2026-09-24 8:33 ` Christina Joos [this message]
2026-09-24 8:33 ` [PATCH v5 13/13] gdb, mi: Add -shadow-stack-list-frames command Christina Joos
2026-09-24 9:39 ` Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260924083311.1961530-13-christina.joos@intel.com \
--to=christina.joos@intel.com \
--cc=gdb-patches@sourceware.org \
--cc=luis.machado.foss@gmail.com \
--cc=thiago.bauermann@linaro.org \
--cc=tom@tromey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox