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 From patchwork Thu Apr 17 15:07:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jens Remus X-Patchwork-Id: 110618 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 85F1F385735B for ; Thu, 17 Apr 2025 15:10:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 85F1F385735B 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=kpbZS3JC 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 1D45B3857348 for ; Thu, 17 Apr 2025 15:07:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1D45B3857348 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 1D45B3857348 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=1744902451; cv=none; b=Ndsl2prCQ5wb83CYAJ6YTsl57P0wC0r36Sn5thqMhYQwo0mN3FTKjO1BB9jFeIwxzkYnodCiZ/64ElzFPqp8lvJTP5mesLFP/gvkHqS/J/MSpi9F1S68Wy8ZTGa/AYa3GbhffdpVjtYV5AqzHHUrcOrYVZsAhJ3qhXk3ejV+2Tw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1744902451; c=relaxed/simple; bh=MKqkTHH/j1S5XmaH3UUISlQM2nKwS2tmpCuPVBOoXgQ=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=gO83+u2a696PdIqg456Fg8QgrBMqFBNInKkkgOxB0EWDKe8Yqn97IBAgxqi9uoDBUU7bDqMIoD3A2ioV1MAJrlXFeXhP22wybxC7qaoXrbof22H9P6qaB+r7cq12gZ/hHlhbXUzShh9Nzg0j+hTpJuQH0S6JxpD9OAl1q/z56ao= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1D45B3857348 Received: from pps.filterd (m0356517.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 53H9tVxQ016594; Thu, 17 Apr 2025 15:07:28 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=4R9pMlJ+Fd3Bav6oJ dgULe2Sqx8kdjygbwDVLmmAG3s=; b=kpbZS3JCC/yo1mjLFPiTYY/uL+wkHAiCn PML3HCmZnlVLuGa+YFx5HdV1XBZApXPCfyvHbmIcB7MZNlaY6tOWlSwgO0EbHgRJ Vku9+Vwk4vFYH+aZE0nAJ36+uAKo9tZlFowAp1TwrIhOl/9Lk7QumDy/5Vu0gzTk 3clRQ5p9fRhS2m7TO9byTeB6Jt4X95aDJFiorIzXplipIQajixHcr/NZwR1opGip Zp+2WYdqugMRKqJXYjoxr8pi8sjZ0EPx7aXhBP4Xpca2Nk5fXkTibm8WrV2mY6U8 gygnMfs6QC1EzG5LrrA/T4+1ItPlh6c2Xou85mEwI10evqwGYsgog== Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 462mn7v956-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 17 Apr 2025 15:07:28 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 53HBkIrL016746; Thu, 17 Apr 2025 15:07:27 GMT Received: from smtprelay03.fra02v.mail.ibm.com ([9.218.2.224]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 460572dtrf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Thu, 17 Apr 2025 15:07:27 +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 53HF7JkR59113746 (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 AC51220040; 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 5572B2004D; Thu, 17 Apr 2025 15:07:19 +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:19 +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 2/2] s390: Add SFrame support for s390-64 architecture Date: Thu, 17 Apr 2025 17:07:07 +0200 Message-ID: <20250417150707.2544710-3-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=ANnAolku c=1 sm=1 tr=0 ts=68011930 cx=c_pps a=aDMHemPKRhS1OARIsFnwRA==:117 a=aDMHemPKRhS1OARIsFnwRA==:17 a=XR8D0OoHHMoA:10 a=CCpqsmhAAAAA:8 a=VnNF1IyMAAAA:8 a=mDV3o1hIAAAA:8 a=41jt2ZzOyr5sWDfBgm0A:9 a=ul9cdbp4aOFLsgKbc677:22 X-Proofpoint-GUID: CwQJH7MoJ6Po6cQFQdEC73EqtWFkBZzg X-Proofpoint-ORIG-GUID: CwQJH7MoJ6Po6cQFQdEC73EqtWFkBZzg 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 malwarescore=0 mlxlogscore=999 adultscore=0 spamscore=0 mlxscore=0 bulkscore=0 suspectscore=0 phishscore=0 clxscore=1015 impostorscore=0 priorityscore=1501 lowpriorityscore=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.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_W, RCVD_IN_MSPIKE_H5, 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 Generation of SFrame stack trace information is supported on s390 64-bit (s390x) architecture. Enable stack tracing using SFrame on s390 64-bit too. Based on Claudiu Zissulescu's AArch64 patch "aarch64: Add SFrame support for aarch64 architecture". Adds support for s390-64 (s390x) specific SFrame stack trace format extensions: 1. The CFA offset is stored adjusted by an offset originating from the definition of the CFA and scaled down by an alignment factor to enable and improve the use of signed 8-bit SFrame offsets. 2. FP without RA saved (on stack or in a register) is represented using a padding RA offset value of zero (SFRAME_FRE_RA_OFFSET_INVALID). This may not occur in backtrace, as it is not a leaf function. Treat as error and stop the stack trace. 3. FP and RA may be saved in registers instead of on the stack in the topmost frame when in a leaf function. This may not occur in backtrace, as it is not a leaf function. Treat as error and stop the stack trace. Add support to unwind SP, FP, and RA from (RT) signal frames on s390-64 (s390x). sysdeps/generic/ * sframe.h (SFRAME_ABI_S390_ENDIAN_BIG, SFRAME_FRE_RA_OFFSET_INVALID, SFRAME_S390_CFA_OFFSET_ADJUSTMENT, SFRAME_S390_CFA_OFFSET_ALIGNMENT_FACTOR, SFRAME_V2_FRE_S390_CFA_OFFSET_ENCODE, SFRAME_V2_FRE_S390_CFA_OFFSET_DECODE, SFRAME_S390_SP_VAL_OFFSET, SFRAME_S390_OFFSET_IS_REGNUM, SFRAME_S390_OFFSET_ENCODE_REGNUM, SFRAME_S390_OFFSET_DECODE_REGNUM): Define. Copied from Binutils include/sframe.h). * sframe.c (stacktrace_sframe): Add support for s390-64 (s390x) specific SFrame extensions. sysdeps/s390/ (SFRAME_SP_VAL_OFFSET): Re-define to s390-64 specific SP value offset from CFA. sysdeps/unix/sysv/linux/s390/ * s390-64/uw-sigframe.h (s390_decode_signal_frame): New function. Unwind SP, FP, and RA if in a (RT) signal frame. (MD_DECODE_SIGNAL_FRAME): Wire up s390_decode_signal_frame. Signed-off-by: Jens Remus --- Notes: The s390 64-bit (s390x) support to generate SFrame in GNU assembler is still under review: Binutils patch series "[PATCH 0/8] s390: Support to generate .sframe in assembler and linker", https://inbox.sourceware.org/binutils/20250402161203.2935633-1-jremus@linux.ibm.com/ For the sake of simplicity the s390-64 (s390x) specific SFrame extensions are guarded by ifdefs. An alternative would be to introduce generic helpers, e.g. sframe_cfa_offset_decode and sframe_offset_is_regnum, that can be overridden by s390-64 specific ones. Note that the definitions in sysdeps/generic/sframe.h originate from Binutils include/sframe.h and should therefore only be modified if absolutely necessary. @Uli and @Andreas A.: This implementation assumes that saving of the frame pointer (FP) and return address (RA) registers in other registers (e.g. floating-point registers) is only valid in a leaf function on s390x. As backtrace() is known not to be a leaf function, as it calls stacktrace_sframe(), the current implementation rejects FP and RA saved in registers. If we want to stay flexible, I can change it to support saving of FP and RA in other registers in the topmost frame - regardless of whether that is a leaf function. @Stefan: struct kernel_sigframe and struct kernel_rt_sigframe are based on Kernel arch/s390/kernel/signal.c. From the Glibc test suite I can see that the tests debug/tst-backtrace4 and debug/tst-backtrace5 use sigreturn while debug/tst-backtrace6 uses rt_sigreturn. AArch64 and MIPS both have a separate Glibc header file for struct kernel_rt_sigframe: - sysdeps/unix/sysv/linux/mips/kernel_rt_sigframe.h - sysdeps/unix/sysv/linux/mips/kernel_rt_sigframe.h 1. Should we do the same and introduce sysdeps/unix/sysv/linux/s390/s390-64/kernel_rt_sigframe.h for struct kernel_rt_sigframe? If we do, should we then also introduce sysdeps/unix/sysv/linux/s390/s390-64/kernel_sigframe.h for struct kernel_sigframe? 2. The Kernel struct rt_sigframe contains a struct ucontext_extended instead of a struct ucontext, which currently only differs in an added _sigregs_ext uc_mcontext_ext field. Should we introduce struct ucontext_extended (and ucontext_ext[ended]_t?) in sysdeps/unix/sysv/linux/s390/sys/ucontext.h to align more closely to the Kernel structures? sysdeps/generic/sframe.c | 26 ++++++ sysdeps/generic/sframe.h | 62 ++++++++++++- sysdeps/s390/s390-64/sframe.h | 39 +++++++++ .../sysv/linux/s390/s390-64/uw-sigframe.h | 86 +++++++++++++++++++ 4 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 sysdeps/s390/s390-64/sframe.h create mode 100644 sysdeps/unix/sysv/linux/s390/s390-64/uw-sigframe.h diff --git a/sysdeps/generic/sframe.c b/sysdeps/generic/sframe.c index 187b8b5ad8e4..1e881cb45501 100644 --- a/sysdeps/generic/sframe.c +++ b/sysdeps/generic/sframe.c @@ -121,6 +121,11 @@ stacktrace_sframe (void **ra_lst, int count, frame *frame) cfa_offset = sframe_fre_get_cfa_offset (dctx, frep, &err); if (err != _URC_NO_REASON) return i; +# ifdef __s390x__ + /* On s390-64 (s390x) undo the adjustment and scaling down of + the CFA offset. */ + cfa_offset = SFRAME_V2_FRE_S390_CFA_OFFSET_DECODE (cfa_offset); +# endif /* Get CFA using base reg id from the FRE info. */ cfa = ((sframe_fre_get_base_reg_id (frep) == SFRAME_BASE_REG_SP) @@ -132,6 +137,19 @@ stacktrace_sframe (void **ra_lst, int count, frame *frame) ra_offset = sframe_fre_get_ra_offset (dctx, frep, &err); if (err != _URC_NO_REASON) return i; +# ifdef __s390x__ + /* On s390-64 (s390x) the RA offset may be invalid to represent + FP without RA saved. This may not occur in backtrace(), as + the RA must have been saved prior to calling getRA(). */ + if (ra_offset == SFRAME_FRE_RA_OFFSET_INVALID) + return i; + + /* On s390-64 (s390x) the RA may be saved in another register + only in the topmost frame when in a leaf function. This + may not occur in backtrace(), as it is not a leaf function. */ + if (SFRAME_S390_OFFSET_IS_REGNUM (ra_offset)) + return i; +# endif /* RA offset is available, get the value stored in the stack location. */ @@ -150,6 +168,14 @@ stacktrace_sframe (void **ra_lst, int count, frame *frame) return i; else if (err == _URC_NO_REASON) { +# ifdef __s390x__ + /* On s390-64 (s390x) the FP may be saved in another register + only in the topmost frame when in a leaf function. This + may not occur in backtrace(), as it is not a leaf function. */ + if (SFRAME_S390_OFFSET_IS_REGNUM (fp_offset)) + return i; +# endif + /* FP offset is available, get the value stored in the stack location. */ fp_stack_loc = cfa + fp_offset; diff --git a/sysdeps/generic/sframe.h b/sysdeps/generic/sframe.h index 198045539542..008baeae5952 100644 --- a/sysdeps/generic/sframe.h +++ b/sysdeps/generic/sframe.h @@ -91,6 +91,7 @@ extern "C" #define SFRAME_ABI_AARCH64_ENDIAN_BIG 1 /* AARCH64 big endian. */ #define SFRAME_ABI_AARCH64_ENDIAN_LITTLE 2 /* AARCH64 little endian. */ #define SFRAME_ABI_AMD64_ENDIAN_LITTLE 3 /* AMD64 little endian. */ +#define SFRAME_ABI_S390_ENDIAN_BIG 4 /* S390 big endian. */ /* SFrame FRE types. */ #define SFRAME_FRE_TYPE_ADDR1 0 @@ -188,7 +189,7 @@ typedef struct sframe_func_desc_entry - 2-bits: Unused. ------------------------------------------------------------------------ | Unused | PAC auth A/B key (aarch64) | FDE type | FRE type | - | | Unused (amd64) | | | + | | Unused (amd64, s390) | | | ------------------------------------------------------------------------ 8 6 5 4 0 */ uint8_t sfde_func_info; @@ -234,6 +235,9 @@ typedef struct sframe_func_desc_entry may or may not be tracked. */ #define SFRAME_FRE_FP_OFFSET_IDX 2 +/* Invalid RA offset. Used as padding to represent FP without RA on stack. */ +#define SFRAME_FRE_RA_OFFSET_INVALID 0 + typedef struct sframe_fre_info { /* Information about @@ -246,7 +250,7 @@ typedef struct sframe_fre_info - 1 bit: Mangled RA state bit (aarch64 only). ---------------------------------------------------------------------------------- | Mangled-RA (aarch64) | Size of offsets | Number of offsets | base_reg | - | Unused (amd64) | | | | + | Unused (amd64, s390) | | | | ---------------------------------------------------------------------------------- 8 7 5 1 0 @@ -272,7 +276,7 @@ typedef struct sframe_fre_info /* SFrame Frame Row Entry definitions. - Used for both AMD64 and AARCH64. + Used for AMD64, AARCH64, and S390. An SFrame Frame Row Entry is a self-sufficient record which contains information on how to generate the stack trace for the specified range of @@ -296,6 +300,24 @@ typedef struct sframe_fre_info fi Note that in AAPCS64, a frame record, if created, will save both FP and LR on stack. + + S390: + offset1 (interpreted as CFA = BASE_REG + offset1) + if RA is being tracked + offset2 (interpreted as RA = CFA + offset2; an offset value of + SFRAME_FRE_RA_OFFSET_INVALID indicates a dummy padding RA offset + to represent FP without RA saved on stack) + if FP is being tracked + offset3 (intrepreted as FP = CFA + offset3) + fi + else + if FP is being tracked + offset2 (intrepreted as FP = CFA + offset2) + fi + fi + Note that in S390, if a FP/RA offset2/offset3 value has the least- + significant bit set it represents a DWARF register number shifted to the + left by 1 to restore the FP/RA value from. */ /* Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type. */ @@ -340,6 +362,40 @@ typedef struct sframe_frame_row_entry_addr4 #define SFRAME_FRE_TYPE_ADDR4_LIMIT \ (1ULL << ((SFRAME_FRE_TYPE_ADDR4 * 2) * 8)) +/* On S390, the CFA offset from CFA base register is by definition a minimum + of 160. Store it adjusted by -160 to enable use of 8-bit SFrame offsets. + Additionally scale by an alignment factor of 8, as the SP and thus CFA + offset on S390 is always 8-byte aligned. */ +#define SFRAME_S390_CFA_OFFSET_ADJUSTMENT SFRAME_S390_SP_VAL_OFFSET +#define SFRAME_S390_CFA_OFFSET_ALIGNMENT_FACTOR 8 +#define SFRAME_V2_FRE_S390_CFA_OFFSET_ENCODE(offset) \ + (((offset) + SFRAME_S390_CFA_OFFSET_ADJUSTMENT) \ + / SFRAME_S390_CFA_OFFSET_ALIGNMENT_FACTOR) +#define SFRAME_V2_FRE_S390_CFA_OFFSET_DECODE(offset) \ + (((offset) * SFRAME_S390_CFA_OFFSET_ALIGNMENT_FACTOR) \ + - SFRAME_S390_CFA_OFFSET_ADJUSTMENT) + +/* On S390, the CFA is defined as SP at call site + 160. Therefore the + SP value offset from CFA is -160. */ +#define SFRAME_S390_SP_VAL_OFFSET -160 + +/* On S390, the FP and RA registers can be saved either on the stack or, + in case of leaf functions, in registers. Store DWARF register numbers + encoded as offset by using the least-significant bit (LSB) as indicator: + - LSB=0: Stack offset. The s390x ELF ABI mandates that stack register + slots must be 8-byte aligned. + - LSB=1: DWARF register number shifted to the left by one. */ +#define SFRAME_S390_OFFSET_IS_REGNUM(offset) \ + ((offset) & 1) +#define SFRAME_S390_OFFSET_ENCODE_REGNUM(regnum) \ + (((regnum) << 1) | 1) +#define SFRAME_S390_OFFSET_DECODE_REGNUM(offset) \ + ((offset) >> 1) + +/* Generic SP value offset from CFA. Applies to architectures that + define their CFA as SP at call site, such as AArch64 and x86-64. */ +#define SFRAME_SP_VAL_OFFSET 0 + /* Used to pass frame information to stack trace routine. */ typedef struct cframe { diff --git a/sysdeps/s390/s390-64/sframe.h b/sysdeps/s390/s390-64/sframe.h new file mode 100644 index 000000000000..e39eaea66f66 --- /dev/null +++ b/sysdeps/s390/s390-64/sframe.h @@ -0,0 +1,39 @@ +/* SFrame format description. + Copyright (C) 2025-2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not see + . */ + +#ifndef _S390_SFRAME_H +#define _S390_SFRAME_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* SP value offset from CFA. On s390-64 the CFA is defined as + SP at call site + 160. */ +#undef SFRAME_SP_VAL_OFFSET +#define SFRAME_SP_VAL_OFFSET SFRAME_S390_SP_VAL_OFFSET + +#ifdef __cplusplus +} +#endif + +#endif /* _S390_SFRAME_H */ + diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/uw-sigframe.h b/sysdeps/unix/sysv/linux/s390/s390-64/uw-sigframe.h new file mode 100644 index 000000000000..29acec9115c5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/s390/s390-64/uw-sigframe.h @@ -0,0 +1,86 @@ +/* Signal frame backtracing support for SFrame on s390-64. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This code is inspired from libgcc's MD_FALLBACK_FRAME_STATE_FOR + implementation. See libgcc/config/s390/linux-unwind.h */ + +#include +#include +#include + +#define MD_DECODE_SIGNAL_FRAME s390_decode_signal_frame + +static _Unwind_Reason_Code +s390_decode_signal_frame (frame *frame) +{ + /* Linux kernel's sigframe structure. */ + struct kernel_sigframe + { + unsigned char callee_used_stack[__SIGNAL_FRAMESIZE]; + struct sigcontext sc; + _sigregs sregs; + int signo; + _sigregs_ext sregs_ext; + unsigned short svc_insn; /* Offset of svc_insn is NOT fixed! */ + }; + + /* Linux kernel's rt_sigframe structure. */ + struct kernel_rt_sigframe + { + unsigned char callee_used_stack[__SIGNAL_FRAMESIZE]; + unsigned short svc_insn; + siginfo_t info; + ucontext_t uc; + }; + + unsigned char *pc = (unsigned char *) frame->pc; + _sigregs *sr; + +#define SVC_OPCODE 0x0a + + /* A signal frame will have a return address pointing to: + svc $__NR_sigreturn or svc $__NR_rt_sigreturn */ + if (pc[0] != SVC_OPCODE + || (pc[1] != __NR_sigreturn && pc[1] != __NR_rt_sigreturn)) + return _URC_END_OF_STACK; + + if (pc[1] == __NR_rt_sigreturn) + { + /* New-style RT frame. */ + struct kernel_rt_sigframe *rt_; + rt_ = (struct kernel_rt_sigframe *) frame->sp; + sr = (_sigregs *) &rt_->uc.uc_mcontext; + } + else + { + /* New-style non-RT frame. */ + struct kernel_sigframe *sf; + sf = (struct kernel_sigframe *) frame->sp; + sr = sf->sc.sregs; + } + +#define SP_REGNUM 15 +#define FP_REGNUM 11 + + frame->pc = (_Unwind_Ptr) sr->regs.psw.addr; + frame->sp = (_Unwind_Ptr) sr->regs.gprs[SP_REGNUM]; + frame->fp = (_Unwind_Ptr) sr->regs.gprs[FP_REGNUM]; + + return _URC_NO_REASON; +}