From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id eQanGzVhTmqwcCwAWB0awg (envelope-from ) for ; Wed, 08 Jul 2026 10:39:49 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=XaC1WmsR; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 6D3361E098; Wed, 08 Jul 2026 10:39:49 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 7AA371E024 for ; Wed, 08 Jul 2026 10:39:48 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1D85E4BA2E1E for ; Wed, 8 Jul 2026 14:39:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1D85E4BA2E1E Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=XaC1WmsR Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.19]) by sourceware.org (Postfix) with ESMTPS id 463B84BA2E2F for ; Wed, 8 Jul 2026 14:38:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 463B84BA2E2F Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 463B84BA2E2F Authentication-Results: sourceware.org; arc=none smtp.remote-ip=198.175.65.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783521498; cv=none; b=u2NDRHt7cSSUiFlELxBa20I57ROdwBshpUqs4eDSq5Bu9ViMLJ2/qiDZvTmIXeHtZqnvibsOOsQibyFvOA6wnpeYJO3Jr+tpoCJsCI3yj2H2YFVTwL/m1C//iK4LJssMZX/QBJF6nh3GkZkao4/DW67Q1br2hrnwDbk9cQxLK6o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783521498; c=relaxed/simple; bh=s0/M6P9LKmY47YZ/V5BtKBQ7DamXxw+G7rx46PkkVuY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=nCOfQWsUjNGWGd4rVH/hIf949eUnJtmhXKHgmplNndE0B//g5DLPrcFHvUuRcA0TDkehRgHZ3pEwmq08xWYV81GXPFoLgfSEDzonpokdzO/qY6+5wvG+S/PHBvQFHej6U7IOhkMmrHNEyuxmUAcUcv4yeVkSbVZEqlm18J+m9eI= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=XaC1WmsR DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 463B84BA2E2F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783521498; x=1815057498; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=s0/M6P9LKmY47YZ/V5BtKBQ7DamXxw+G7rx46PkkVuY=; b=XaC1WmsRF5yM8ul3SaU485NbLZh+sI03P7F1+CdCvkSkRNbN3fIQIr2i KcftubWoK1YlP/hnyZke/jD5IwOukHJ3iah6gPrcLdGTESUYjV5qzmD0Z QZ7ASba/gW4KO3GdDzhjdOwl210sSc0fP0b/nQk+3ffcOqWpsBtoSk+iV 3tTWM0h//1Po5ZaTU+5nnnJo7hfMz0K81bCYN4Rga3KkaTFUiA4HExZQR CdpZM/Q/TeS1KdaBut/qb+ejPI+PQ3BbRWN9xh7YDD8bhggxMnSFvEOCa HNYaVTTtqt5uUD5VOcQ1TKNBUVq0/uAhUaXYmorq6PMphLUSRZXHTi1O7 w==; X-CSE-ConnectionGUID: C3AlyMwATL+PGH5dO/buPg== X-CSE-MsgGUID: th7F+WlSSSWOHQCuS2YksQ== X-IronPort-AV: E=McAfee;i="6800,10657,11841"; a="84158941" X-IronPort-AV: E=Sophos;i="6.25,153,1779174000"; d="scan'208";a="84158941" Received: from fmviesa007.fm.intel.com ([10.60.135.147]) by orvoesa111.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jul 2026 07:38:17 -0700 X-CSE-ConnectionGUID: SlW5cvNHSPuS0c8S061L7w== X-CSE-MsgGUID: /r7NrbwxTIO1buyRt8cQBg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,153,1779174000"; d="scan'208";a="250945915" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jul 2026 07:38:16 -0700 From: Christina Schimpe To: gdb-patches@sourceware.org Cc: tom@tromey.com, thiago.bauermann@linaro.org Subject: [PATCH v4 12/13] gdb: Enable signal trampolines in the shadow stack backtrace. Date: Wed, 8 Jul 2026 14:36:38 +0000 Message-Id: <20260708143639.2214689-13-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260708143639.2214689-1-christina.schimpe@intel.com> References: <20260708143639.2214689-1-christina.schimpe@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Similar to the normal backtrace we now print "" in the shadow stack backtrace, too. ~~~ (gdb) bt -shadow /#0 /#1 /#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 /#2 __pthread_kill_implementation (no_tid=0, signo=10, threadid=) at ./nptl/pthread_kill.c:44 /#3 __pthread_kill_internal (signo=10, threadid=) at ./nptl/pthread_kill.c:78 /#4 __GI___pthread_kill (threadid=, 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 ~~~ --- 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 d98415b8989..ab3b65ed4b8 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 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 . */ #define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40 @@ -2024,7 +2030,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); @@ -2082,6 +2088,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 e93afff34b1..c0b882563c1 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 791324777dd..31500ee104d 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1808,3 +1808,14 @@ bool gdbarch_is_no_return_shadow_stack_address_p (struct gdbarch *gdbarch); using gdbarch_is_no_return_shadow_stack_address_ftype = std::optional (struct gdbarch *gdbarch, const CORE_ADDR ssp, const CORE_ADDR value, const unsigned long level); std::optional 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 0435b1b5eca..fce705c33a1 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2864,3 +2864,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 94062034bd3..6515d4b182d 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 = ""; + else if (frame.type == ssp_frame_type::sigtramp_frame) + str = ""; 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 + ({ssp, value, level, sal_arch, sal, + ssp_frame_type::sigtramp_frame, {}, + ssp_unwind_stop_reason::no_error}); + } + return std::optional ({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 . gdb_test "bt -shadow" \ [multi_line \ - "#0\[ \t\]*$hex in \[^\r\n\]+" \ + "#0\[ \t\]*" \ "#1\[ \t\]*" \ "#2\[ \t\]*$hex in \[^\r\n\]+" \ ".*" ] \ -- 2.34.1 Intel Deutschland GmbH Registered Address: Dornacher Strasse 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 Muenchen HRB 186928