From patchwork Thu Apr 17 15:07:06 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jens Remus X-Patchwork-Id: 110617 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 7DAB23857007 for ; Thu, 17 Apr 2025 15:08:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7DAB23857007 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=avBSpqi6 X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id 7CC90385770D for ; Thu, 17 Apr 2025 15:07:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7CC90385770D 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 7CC90385770D Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1744902449; cv=none; b=sfx8MFXmVs6mqwPS4UN+dRhejaAWbNxYVnXocsl0hhmuOlue4An9eZ1moo1ztEeik1beX+EqnrE3BRDhuLwqlR12szI2Rzu32SR8CYib56sFGR+edVYo75fE+rhJPtRq7I6LE0Aj+M+5STnGS9g8nlUeySP3ZUHXKhsrxp+UUTs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1744902449; c=relaxed/simple; bh=/RXnOdeuSqF5BniJRlfLfrUY5KuIN2smw/8u7IIvpWk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=ZTVdW+1mm/GvDjtqxOfZsPExzSCe8RMmzZYQlJUaZ0xp1u1ZDSi5Kxczu7ibI0Y9FKaxo62bIovH1v52dP/usdv75IF5tPqtCZ3e2cPWgs4ARWoEFuGm6vFJSckMrRZ7RBogCO5mXMoUHXeKybW76aAmVuJtDXF415ZT6uQXr7o= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7CC90385770D Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 53HAgZKV016020; Thu, 17 Apr 2025 15:07:27 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=8dywdPJfNHmEYNTSf dYDwFR1Dr/vEJTY36eOBoR39Ao=; b=avBSpqi6eW59upZaititWaWRlDmLywFTU 5HfNaVKZbayqRtPRfwxfME2/ZnAjix8UT0QZ1aUphpnkJK/pSMtTZ80oYIOAegah T8DMAkeE2pJYR8bk4P+dlopOQeQq4cNyrwIID4WoS65/Pr40kdvRfaPIRWgYFeG3 CdOORnMOm2BCr5uzbgEg/W75jGlERU/nT6ObDeR1GM4iSrv6feMOkFS2ViDmdLO7 cCBOm929ImXgJYDbVeLw36niB8s+giY6F2J9q4X27VycgjycRACVgOv7W0ltVPg8 1MqTjmk5Zyt6m+WyOcC261jD+3AH6/r5PoTnBezdyf4oc4FFlYNjA== Received: from ppma21.wdc07v.mail.ibm.com (5b.69.3da9.ip4.static.sl-reverse.com [169.61.105.91]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 462mpv443c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 17 Apr 2025 15:07:26 +0000 (GMT) Received: from pps.filterd (ppma21.wdc07v.mail.ibm.com [127.0.0.1]) by ppma21.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 53HDalcX030911; Thu, 17 Apr 2025 15:07:26 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 4603gnx81w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 17 Apr 2025 15:07:25 +0000 Received: from smtpav04.fra02v.mail.ibm.com (smtpav04.fra02v.mail.ibm.com [10.20.54.103]) by smtprelay03.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 53HF7JW054788488 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 17 Apr 2025 15:07:19 GMT Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 486E420043; Thu, 17 Apr 2025 15:07:19 +0000 (GMT) Received: from smtpav04.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E9A962004B; Thu, 17 Apr 2025 15:07:18 +0000 (GMT) Received: from tuxmaker.lnxne.boe (unknown [9.152.85.9]) by smtpav04.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 17 Apr 2025 15:07:18 +0000 (GMT) From: Jens Remus To: libc-alpha@sourceware.org, Stefan Liebler , Claudiu Zissulescu-Ianculescu Cc: Jens Remus , Ulrich Weigand , Andreas Arnez , Indu Bhagat , Elena Zannoni Subject: [RFC PATCH 1/2] elf: Start SFrame stack trace from PC and CFA Date: Thu, 17 Apr 2025 17:07:06 +0200 Message-ID: <20250417150707.2544710-2-jremus@linux.ibm.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250417150707.2544710-1-jremus@linux.ibm.com> References: <20250417150707.2544710-1-jremus@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=KJVaDEFo c=1 sm=1 tr=0 ts=6801192e cx=c_pps a=GFwsV6G8L6GxiO2Y/PsHdQ==:117 a=GFwsV6G8L6GxiO2Y/PsHdQ==:17 a=XR8D0OoHHMoA:10 a=VnNF1IyMAAAA:8 a=sHT5ADAqCMadcyeYHTcA:9 X-Proofpoint-GUID: OEInETSroMNT9kVQ6m_HzbMudD1U21ro X-Proofpoint-ORIG-GUID: OEInETSroMNT9kVQ6m_HzbMudD1U21ro X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1095,Hydra:6.0.680,FMLib:17.12.68.34 definitions=2025-04-17_04,2025-04-17_01,2024-11-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 clxscore=1015 priorityscore=1501 adultscore=0 lowpriorityscore=0 bulkscore=0 impostorscore=0 suspectscore=0 spamscore=0 malwarescore=0 mlxlogscore=999 phishscore=0 classifier=spam authscore=0 adjust=0 reason=mlx scancount=1 engine=8.19.0-2502280000 definitions=main-2504170112 X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, 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: @Uli: Would you mind if Claudiu would merge this into his SFrame stack trace series? Following are two options to resolve the SFrame strack trace startup issue on s390-64 (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-64 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 | 43 +++++++++++++++++++++------------------- sysdeps/generic/sframe.h | 5 +---- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/debug/backtrace.c b/debug/backtrace.c index b41bc9513f6a..37f1d474580e 100644 --- a/debug/backtrace.c +++ b/debug/backtrace.c @@ -42,9 +42,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 b68eae1d3d85..187b8b5ad8e4 100644 --- a/sysdeps/generic/sframe.c +++ b/sysdeps/generic/sframe.c @@ -109,15 +109,23 @@ 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) - return i; - - /* 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) + return i; + + /* 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. */ @@ -136,7 +144,11 @@ 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) + if (i == 0 && err != _URC_NO_REASON) + /* The FP must be saved in the topmost frame, as backtrace called + __builtin_unwind_init, which guarantees this. */ + return i; + else if (err == _URC_NO_REASON) { /* FP offset is available, get the value stored in the stack location. */ @@ -145,6 +157,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; @@ -165,13 +178,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