From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id +ZAeDcagS2pOwSkAWB0awg (envelope-from ) for ; Mon, 06 Jul 2026 08:34:14 -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=QTAAzW95; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 2FE971E070; Mon, 06 Jul 2026 08:34:14 -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 [IPv6:2620:52:6:3111::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 281771E070 for ; Mon, 06 Jul 2026 08:34:13 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C27174BA2E07 for ; Mon, 6 Jul 2026 12:34:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C27174BA2E07 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=QTAAzW95 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) by sourceware.org (Postfix) with ESMTPS id 3EC664BA2E21 for ; Mon, 6 Jul 2026 12:32:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3EC664BA2E21 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 3EC664BA2E21 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783341171; cv=none; b=t4XCfrgsPqvZkR/RTKSfnmTS0wSEnbFIgw0lYUdb7m3L3Zyi6U1520xedpjJaPUZZK0oNDX1Y4dXA6G++/MXRlF5MRUWEvgsWj3HmN5vl7/JD4i1TLkkATSoQeBJUkgFEX5R4UQm8q1epihlajjixQgP19dcK1WB5QJ3ZdFiKN8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783341171; c=relaxed/simple; bh=s0/M6P9LKmY47YZ/V5BtKBQ7DamXxw+G7rx46PkkVuY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=lJ9xz5nQ8kxHCq7/Dl98wi7wgHbhZUPl3pRB/E1/kfHGz9qwMzJyciq53HW8DbkS5NMsMFfFUwTjoIKvzsM+JTMLGkLQSmwVEcb3QR4RnXKSTQA7ONxLaS0nZOHWGe9uCe1PeNnFBzuXsGi1FtjgaVYnwu2FTbgzlypQADY41II= 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=QTAAzW95 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3EC664BA2E21 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1783341171; x=1814877171; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=s0/M6P9LKmY47YZ/V5BtKBQ7DamXxw+G7rx46PkkVuY=; b=QTAAzW95G//WFq56b4fgEd83j3hhz+L5BWoq6lx/8aJM0BCXp9Mb8hIf 2Dkptn3E1CXrmjlihQNiV6g0pOn7ymA4/l8+cf9ZXgZMUMZnt5TtXbLUZ Dw5fTdjh4bhJaZpNF6+6H4Ntkdec8ILeBFq4UNJqTywMn6GeOqgNaqDZb B0xZPgrg/z27vqZpoV9UXo2n9x7ndw/DQ32wuOnUrZwlGTNOp66nXBdlb /P0kAf1b4rS6MEgpM3yceFcboWLOzDxbr3abHAA2Rbpx+LDrAMvzf3iyj 1gG+s4/7I+FuooK4N5II4Ga9siPUXLuLz44yPAKemHSeL/YrLsUicQoEo A==; X-CSE-ConnectionGUID: e/McPeohSDqGR1WbjZKJxg== X-CSE-MsgGUID: xTbVYxzrT+S+FwJyRXjKcg== X-IronPort-AV: E=McAfee;i="6800,10657,11838"; a="94332692" X-IronPort-AV: E=Sophos;i="6.25,149,1779174000"; d="scan'208";a="94332692" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2026 05:32:51 -0700 X-CSE-ConnectionGUID: 7VPF1vECTei7XvE2MUC4Jg== X-CSE-MsgGUID: 1xZLC75sRGy3s79xmWV56A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,149,1779174000"; d="scan'208";a="247309680" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2026 05:32:49 -0700 From: Christina Schimpe To: gdb-patches@sourceware.org Cc: tom@tromey.com, thiago.bauermann@linaro.org Subject: [PATCH v3 11/12] gdb: Enable signal trampolines in the shadow stack backtrace. Date: Mon, 6 Jul 2026 12:31:32 +0000 Message-Id: <20260706123133.1990441-12-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260706123133.1990441-1-christina.schimpe@intel.com> References: <20260706123133.1990441-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