From patchwork Fri Jun 27 13:38:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jens Remus X-Patchwork-Id: 115199 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 2737F3857BB6 for ; Fri, 27 Jun 2025 13:43:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2737F3857BB6 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=HG6WRII8 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 828763857015 for ; Fri, 27 Jun 2025 13:39:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 828763857015 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 828763857015 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=1751031557; cv=none; b=VaFJxJ7NNCuD1bzmY/nw1f/nD/WE04JpiW0/rl92hH8mZ6uuA6BlGOIhRbAohJiYhNwtWRpivp0uPU1TWaJsJf2JZf+G8bllU548z4C7kcXbHvnaCMyRtsXsqboYOC3U46CaoJu9A8ywh9DeGgzK13N+3P8YCa3LAE1OoSpyysU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1751031557; c=relaxed/simple; bh=vtPV9jxc1lisfWXGz2BevKL2kKn9uSChTgW0tDWAVHM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=aq1xPfqDOPgpTs/zK57UszAy0rOd7712nTl7LSlya1V3knqBumouB8EOeXkjGY3D9WthjSlIfhGG41RbbZfV97s2Y2GEb26G3oReQ2RWOwqfyaHFfjEv6yqoH5oHVCKf4l1qNJV0P/dIPAQ7bAa7FKACsTiANS+78EReQ99an+c= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 828763857015 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 55RBGoxR015880; Fri, 27 Jun 2025 13:38:30 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=C+CwQqdvAPoO9ZNcG 66cC6UXZeunfNlkRSZ4F0fyNEw=; b=HG6WRII8TBJp4NQNAqzUmHMtylAA4iMGr KB0/Q38OgYx+VPAJrGLtmOEQwUxGw6f9UhWJbabrcY58+IEzBlsbjhf4jBzuYqmU qSY68Adw7ZUh4V9+0siZU26lo5EeKJYiVpwp0OHsyAb7qzzJPM0mw6Lr7XYSV/vB D54SRsFtiLJ9R17W4W7mVt/Mw1Sw03YmASGVJQ+pR9P8W0Cc0CfU2AtWPbtVg25b IGNWNKV6kRMTMNnLun9P1/Ul6IlBPeonTE6guaaaHOcVLNwigbVN/eIVS0mtZioO e675+ECF2aoO5J0ZPzgm8HnL0zBc+7a8FyDve/AKILErNMUKIPdwA== Received: from ppma22.wdc07v.mail.ibm.com (5c.69.3da9.ip4.static.sl-reverse.com [169.61.105.92]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 47dm8jwpwf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 27 Jun 2025 13:38:30 +0000 (GMT) Received: from pps.filterd (ppma22.wdc07v.mail.ibm.com [127.0.0.1]) by ppma22.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 55RCVkbL031277; Fri, 27 Jun 2025 13:38:29 GMT Received: from smtprelay07.fra02v.mail.ibm.com ([9.218.2.229]) by ppma22.wdc07v.mail.ibm.com (PPS) with ESMTPS id 47e7f0ceny-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 27 Jun 2025 13:38:28 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay07.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 55RDcPuP47448530 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 27 Jun 2025 13:38:25 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 02F8720040; Fri, 27 Jun 2025 13:38:25 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CB6CA2004D; Fri, 27 Jun 2025 13:38:24 +0000 (GMT) Received: from tuxmaker.lnxne.boe (unknown [9.152.85.9]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Fri, 27 Jun 2025 13:38:24 +0000 (GMT) From: Jens Remus To: libc-alpha@sourceware.org, Stefan Liebler , Claudiu Zissulescu-Ianculescu , Florian Weimer Cc: Jens Remus , Ulrich Weigand , Indu Bhagat , Elena Zannoni Subject: [RFC PATCH v2 1/2] elf: Start SFrame stack trace from PC and CFA Date: Fri, 27 Jun 2025 15:38:12 +0200 Message-ID: <20250627133813.2198784-2-jremus@linux.ibm.com> X-Mailer: git-send-email 2.48.1 In-Reply-To: <20250627133813.2198784-1-jremus@linux.ibm.com> References: <20250627133813.2198784-1-jremus@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUwNjI3MDExMCBTYWx0ZWRfX6KltGYSP6tPo H4BEGTj3o6PlpA81BLYbeqO1XQqxPFxm8M4lYdbpvWM19Mf/H2shW0heyDS9/A4vYpHAShOzSsB rkKF2r6ueUh2wKlHANTrrL9vus3Zb7l/uFsBqqkM1BjVOjeY1EZ2/1iB5/44YFfkQ2qMp5tIxb5 Wt8rvRtkaj+qq1UmNd5PuZd4+LDFCphBr7e+n9bgaD6hDZfXphbHk7zSf7Cpbn+HAk66ZGrBcOG n5e+5niUhd1azZcQrH2ezt+epRSn64xGlc/Wg8R25tLeGCiUA0THl/v8zIlUqYT0J0HKrvllimx 2wzHXsFQjCKPxzkPQg+Der2PaqItqHDEgItKLrlmin+LXrV/7JEqlpOTB+2GOXPt4zJmWhXzhFC Bb3hitjoAXG6zsJsOACwvIGWvO0h7nWbtYL6l3XWihuvJLftXr0kUVss4kT2rYJweVTZ2p0t X-Proofpoint-GUID: _ssZjVp-MtRLHbAoy4uM41XCq8sQ6hAf X-Proofpoint-ORIG-GUID: _ssZjVp-MtRLHbAoy4uM41XCq8sQ6hAf X-Authority-Analysis: v=2.4 cv=combk04i c=1 sm=1 tr=0 ts=685e9ed6 cx=c_pps a=5BHTudwdYE3Te8bg5FgnPg==:117 a=5BHTudwdYE3Te8bg5FgnPg==:17 a=6IFa9wvqVegA:10 a=VnNF1IyMAAAA:8 a=sHT5ADAqCMadcyeYHTcA:9 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1099,Hydra:6.1.7,FMLib:17.12.80.40 definitions=2025-06-27_04,2025-06-26_05,2025-03-28_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 spamscore=0 adultscore=0 mlxlogscore=999 clxscore=1011 impostorscore=0 suspectscore=0 mlxscore=0 phishscore=0 lowpriorityscore=0 bulkscore=0 classifier=spam authscore=0 authtc=n/a authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.19.0-2505280000 definitions=main-2506270110 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 (frame): 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: 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 | 6 ++++-- sysdeps/generic/sframe.c | 46 ++++++++++++++++++++++------------------ sysdeps/generic/sframe.h | 5 +---- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/debug/backtrace.c b/debug/backtrace.c index aca0b5ade9c2..d42b1cc6bbcb 100644 --- a/debug/backtrace.c +++ b/debug/backtrace.c @@ -45,9 +45,11 @@ struct trace_arg { \ int cnt; \ frame frame; \ + __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; \ cnt = stacktrace_sframe (ARRAY, SIZE, &frame); \ if (cnt > 1) \ return cnt; \ diff --git a/sysdeps/generic/sframe.c b/sysdeps/generic/sframe.c index abdda07defd4..e3d0cee27d6b 100644 --- a/sysdeps/generic/sframe.c +++ b/sysdeps/generic/sframe.c @@ -117,16 +117,24 @@ stacktrace_sframe (void **ra_lst, int count, frame *frame) return 0; } - /* 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. */ @@ -146,7 +154,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. */ @@ -155,6 +168,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; @@ -175,13 +189,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 ce8f6cdf7f49..198045539542 100644 --- a/sysdeps/generic/sframe.h +++ b/sysdeps/generic/sframe.h @@ -344,6 +344,7 @@ typedef struct sframe_frame_row_entry_addr4 typedef struct cframe { _Unwind_Ptr pc; + _Unwind_Ptr cfa; _Unwind_Ptr sp; _Unwind_Ptr fp; } frame; @@ -356,10 +357,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