From patchwork Wed Jul 23 14:23:46 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jens Remus X-Patchwork-Id: 116836 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6EB303858C78 for ; Wed, 23 Jul 2025 14:30:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6EB303858C78 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=Dlox6JQW X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 954003858C41 for ; Wed, 23 Jul 2025 14:24:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 954003858C41 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linux.ibm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 954003858C41 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1753280647; cv=none; b=DnwiWj/2uwt8cQClOup0v6RpIQZ5qA2wgw/cHT1jaPg2wlXr2jsSQ0mTi7wsnLLfoJt0IkoHg/BGS++xO+yMFNtDlEXMptUkSsGgl2/3uQngFqujre0+KGHuVPUgOkPYs0KxBQ2qma20eoNL5af8W7/EJGBdnDN4TWbcbfv0KaQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1753280647; c=relaxed/simple; bh=omIkEHZwDKw+SpfKscW7Lsize80Qtor+NzP7LERQ8DU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=a9Y8ls4jyTOdc540PN8M5gGKudi/DQOHg8dfRoCLFQKdmAJURulgq8Pvcb/1/Hcex1FQmqBP/hridNEUNR1MtCJX2Huq7rRamoKmon05COwcEPGPcy/1iv3FXByblsP8VPwYIPN2x3tZi9xkGC9zvAB/VGO8cbL99CgPU3//rH4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 954003858C41 Received: from pps.filterd (m0360083.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 56NDTBBF021834; Wed, 23 Jul 2025 14:24:01 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=TaE/8Tn9/5JkIbHd5 PuKyMd5rKmaQy8sfi8CzSN47yk=; b=Dlox6JQWfQvv0stpaGib0ZglRTesf06IQ 5/Ljbs87HVhacxR4TnmxOEFQN3vz/LSj/GTS9nPNstSZyWyv04yOiQ653MnyVnLw jEwyzaP1h9d01Yy7sAL2PYzZSgEsC8wOgZlwUulZtF8RS0O8vN+z17AXmKj6xcxB Qk+2lPtbJttxZkEHVqZM4szFlkTk64lM+FMPFI+bEbRm5tUKLA6kxm0ZVaiclyPg UhQxV2Z1+jOvqptsedaL6PmZ1yhepRiXB3KSHTtdHiVazcqYtf6RDmuVblshmJj3 dcBa4N6qfM3fykcoVpHZlUClXxoPYoUj4PYyN1qW4GFJSIzmUbhDg== Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 482ffbdaq4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 23 Jul 2025 14:24:00 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 56NC9G55005486; Wed, 23 Jul 2025 14:24:00 GMT Received: from smtprelay05.fra02v.mail.ibm.com ([9.218.2.225]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 480tvqyd7c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 23 Jul 2025 14:23:59 +0000 Received: from smtpav02.fra02v.mail.ibm.com (smtpav02.fra02v.mail.ibm.com [10.20.54.101]) by smtprelay05.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 56NENuKl45547994 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 23 Jul 2025 14:23:56 GMT Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 5858F20043; Wed, 23 Jul 2025 14:23:56 +0000 (GMT) Received: from smtpav02.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 256D42005A; Wed, 23 Jul 2025 14:23:56 +0000 (GMT) Received: from tuxmaker.lnxne.boe (unknown [9.152.85.9]) by smtpav02.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 23 Jul 2025 14:23:56 +0000 (GMT) From: Jens Remus To: libc-alpha@sourceware.org, Stefan Liebler , Claudiu Zissulescu-Ianculescu Cc: Jens Remus , Indu Bhagat , Elena Zannoni , Adhemerval Zanella , Florian Weimer , Ulrich Weigand Subject: [RFC PATCH v3 2/3] sframe: Start stack trace from PC and CFA Date: Wed, 23 Jul 2025 16:23:46 +0200 Message-ID: <20250723142347.2159793-3-jremus@linux.ibm.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250723142347.2159793-1-jremus@linux.ibm.com> References: <20250723142347.2159793-1-jremus@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: uCYPKRH2H7crkBTlSB0D5uEU2YgKhvib X-Authority-Analysis: v=2.4 cv=De8XqutW c=1 sm=1 tr=0 ts=6880f081 cx=c_pps a=AfN7/Ok6k8XGzOShvHwTGQ==:117 a=AfN7/Ok6k8XGzOShvHwTGQ==:17 a=Wb1JkmetP80A:10 a=CCpqsmhAAAAA:8 a=KKAkSRfTAAAA:8 a=VnNF1IyMAAAA:8 a=uiZiMkIqLlmwgNZYY4MA:9 a=ul9cdbp4aOFLsgKbc677:22 a=cvBusfyB2V15izCimMoJ:22 X-Proofpoint-GUID: uCYPKRH2H7crkBTlSB0D5uEU2YgKhvib X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwNzIzMDEyMiBTYWx0ZWRfXyjGYXMlxEjbq TCrt8VYsr5zT7NGWuIKOJbC3G6fKbBF/pG1zuQ8k2Q2ireobF5/0KGvqC7el1uok87kUxQoUrSa cGdEbOEqYvBu103JGIhnoNXjyfw9MrFllwGS+FWwt/We5x6I7qK43o0oLGiQ1Q+npKdtnHVrnKE Ue1N+j41C+5+gCptmlBV6ocpLU2vpyFMxRBGuijNNv59/fGRtkp4BGmw1Yak9W/H0L5mWgIT3cw nSMcGhrygRf4xg7OB7NhJq8rrWvqDy+zrZJuPfZLq2FTeml/SBvKvp3xSvAHCEso59xcSTVfV9O sAJFp1nlvfkbr5ZGjCxIJC9fTEZ6JoATp7aPCMoFBTPp1YkHzInfvWwX6VCfR+qRm/K0A6nLXNS Mi/qJpFikw0jkvIYmqRq2rTb+1XPVSjQwTEVsQxpl8WkcgZwbVsfFY5PLvFRfGlOI33R1W7g X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.9,FMLib:17.12.80.40 definitions=2025-07-23_02,2025-07-23_01,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 bulkscore=0 lowpriorityscore=0 mlxscore=0 mlxlogscore=999 suspectscore=0 priorityscore=1501 clxscore=1015 phishscore=0 adultscore=0 malwarescore=0 impostorscore=0 classifier=spam authscore=0 authtc=n/a authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2505280000 definitions=main-2507230122 X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Stack tracing in backtrace using SFrame stack trace information starts with a PC (program counter) in backtrace and the related SP (stack pointer) and FP (frame pointer) values. The following are then derived using SFrame information: - CFA (Canonical Frame Address): Using the tracked CFA base register (SP or FP) and tracked CFA offset from CFA base register - SP: Using the CFA (the CFA is defined as SP at call site on most architectures) - RA (return address): Using the CFA and the tracked RA stack slot offset from CFA - FP: Using CFA and the tracked FP stack slot offset from CFA, otherwise it remains unchanged If the CFA is based on the FP or if the FP is not saved then the initial value of the FP is important. Either because it is required to determine the CFA (and from that the SP, FP, and RA) or because is not restored from its stack slot and thus needs to be known. On x86-64 and Aarch64 the initial FP (in backtrace) can be obtained using __builtin_frame_address (0). On s390-64 (s390x) this does not work as __builtin_frame_address (0) does not return the FP register value, even if a FP register is used (e.g. due to dynamic stack allocation). Instead __builtin_frame_address (0) always returns the SP register value at function entry. This is because GCC and Clang on s390x setup a FP register only as late as possible, for instance after static stack allocation, which makes the FP register value meaningless for FP-based stack tracing purposes. Stack tracing in backtrace always starts in backtrace itself. Therefore use __builtin_unwind_init to enforce saving of FP and RA, obtain the CFA using __builtin_dwarf_cfa, and determine the caller's SP, FP, and RA using that CFA and the SFrame FP and RA stack slot offsets, as those are now guaranteed to be saved. This avoids the need to obtain the initial SP and FP values at all. debug/ * backtrace.c (do_sframe_backtrace): Call __builtin_unwind_init, obtain the CFA using __builtin_dwarf_cfa, and initialize SP and FP with NULL. sysdeps/generic/ * sframe.h (struct cframe): Add field cfa, used for startup of SFrame stack trace. (__getSP): Remove helper. * sframe.c (__stacktrace_sframe): Use CFA from frame in topmost frame to startup SFrame stack trace. Treat FP not saved in topmost frame as error. Update CFA in frame. (__getSP): Remove helper. Suggested-by: Ulrich Weigand Signed-off-by: Jens Remus --- Notes: Changes in v3: - Rebase on top of Adhemerval's series "[PATCH v2 0/2] sframe: Disable by default and support SFRAME_F_FDE_FUNC_START_PCREL": https://inbox.sourceware.org/libc-alpha/20250721234236.1434590-1-adhemerval.zanella@linaro.org/ - Reword commit subject and GNU ChangeLog. Following are two options to resolve the SFrame strack trace startup issue on s390 64-bit (s390x): Option A: Introduce a helper macro that returns the FP value. The generic implementation (used on e.g. x86-64 and AArch64) would resolve to __builtin_frame_address (0). This is why is needs to be a macro. The s390 implementation would resolve to a new inline helper function s390_getFP (), that uses inline assembly to return the preferred FP register r11 value. Option B: Use __builtin_unwind_init to enforce saving of SP and FP at function entry and use __builtin_dwarf_cfa instead of SFrame information to obtain the initial CFA in the topmost frame (i.e. backtrace). This no longer requires the initial SP and FP values. The SP, FP, and RA of the caller are then obtained using the CFA (SP) and SFrame information from the stack register save slots (FP and RA). This patch implements Option B. debug/backtrace.c | 9 +++++--- sysdeps/generic/sframe.c | 47 +++++++++++++++++++++------------------- sysdeps/generic/sframe.h | 5 +---- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/debug/backtrace.c b/debug/backtrace.c index ea7ac4ddf0a4..d72f725d7da9 100644 --- a/debug/backtrace.c +++ b/debug/backtrace.c @@ -55,16 +55,19 @@ struct trace_arg backtracer can fall back to using the DWARF unwinder. This function must be always inline. Otherwise the - __builtin_frame_address and the __getXX helper functions will not + __builtin_dwarf_cfa and the __getPC helper functions will not return the right addresses. */ static inline int __attribute__ ((always_inline)) do_sframe_backtrace (void **array, int size) { frame frame; + /* Force saving of FP and RA on stack. */ + __builtin_unwind_init (); frame.pc = __getPC (); - frame.sp = __getSP (); - frame.fp = (_Unwind_Ptr) __builtin_frame_address (0); + frame.cfa = (_Unwind_Ptr) __builtin_dwarf_cfa (); + frame.sp = (_Unwind_Ptr) NULL; + frame.fp = (_Unwind_Ptr) NULL; return __stacktrace_sframe (array, size, &frame); } #endif diff --git a/sysdeps/generic/sframe.c b/sysdeps/generic/sframe.c index 0dff78a9cacc..67e019e3e773 100644 --- a/sysdeps/generic/sframe.c +++ b/sysdeps/generic/sframe.c @@ -124,16 +124,24 @@ __stacktrace_sframe (void **ra_lst, int count, frame *frame) return i; } - /* Get the CFA offset from the FRE. If offset is unavailable, - sets err. */ - cfa_offset = __sframe_fre_get_cfa_offset (dctx, frep, &err); - if (err != _URC_NO_REASON) - /* Force fallback to DWARF stacktracer. */ - return 0; - - /* Get CFA using base reg id from the FRE info. */ - cfa = ((__sframe_fre_get_base_reg_id (frep) - == SFRAME_BASE_REG_SP) ? frame->sp : frame->fp) + cfa_offset; + if (i == 0) + /* The caller (i.e. backtrace) provided its CFA value and ensured + to save its FP and RA at entry, so that the caller's SP, FP, and + RA at entry can be determined using the CFA. */ + cfa = frame->cfa; + else + { + /* Get the CFA offset from the FRE. If offset is unavailable, + sets err. */ + cfa_offset = __sframe_fre_get_cfa_offset (dctx, frep, &err); + if (err != _URC_NO_REASON) + /* Force fallback to DWARF stacktracer. */ + return 0; + + /* Get CFA using base reg id from the FRE info. */ + cfa = ((__sframe_fre_get_base_reg_id (frep) == SFRAME_BASE_REG_SP) + ? frame->sp : frame->fp) + cfa_offset; + } /* Get the RA offset from the FRE. If the offset is unavailable, sets err. */ @@ -153,7 +161,12 @@ __stacktrace_sframe (void **ra_lst, int count, frame *frame) unavailable, sets err. */ fp_offset = __sframe_fre_get_fp_offset (dctx, frep, &err); frame_ptr = frame->fp; - if (err == _URC_NO_REASON) + /* The FP must be saved in the topmost frame, as backtrace called + __builtin_unwind_init, which guarantees this. */ + if (i == 0 && err != _URC_NO_REASON) + /* Force fallback to DWARF stacktracer. */ + return 0; + else if (err == _URC_NO_REASON) { /* FP offset is available, get the value stored in the stack location. */ @@ -162,6 +175,7 @@ __stacktrace_sframe (void **ra_lst, int count, frame *frame) } /* Set up for the next frame. */ + frame->cfa = cfa; frame->fp = frame_ptr; frame->sp = cfa + SFRAME_SP_VAL_OFFSET; frame->pc = return_addr; @@ -181,14 +195,3 @@ __getPC (void) } libc_hidden_def (__getPC); - -/* A noinline helper used to obtain the caller's current SP. It - mimics gcc14's __builtin_stack_address() functionality. */ - -_Unwind_Ptr __attribute__ ((noinline)) -__getSP (void) -{ - return (_Unwind_Ptr) __builtin_dwarf_cfa() + SFRAME_SP_VAL_OFFSET; -} - -libc_hidden_def (__getSP); diff --git a/sysdeps/generic/sframe.h b/sysdeps/generic/sframe.h index 6225eda5d6dc..9cedcad257a2 100644 --- a/sysdeps/generic/sframe.h +++ b/sysdeps/generic/sframe.h @@ -362,6 +362,7 @@ typedef struct sframe_frame_row_entry_addr4 typedef struct cframe { _Unwind_Ptr pc; + _Unwind_Ptr cfa; _Unwind_Ptr sp; _Unwind_Ptr fp; } frame; @@ -374,10 +375,6 @@ libc_hidden_proto (__stacktrace_sframe); _Unwind_Ptr __getPC (void); libc_hidden_proto (__getPC); -/* Helper used by SFrame tracing algorithm. */ -_Unwind_Ptr __getSP (void); -libc_hidden_proto (__getSP); - #ifdef __cplusplus } #endif