From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9DC69C7EE21 for ; Mon, 1 May 2023 20:05:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232434AbjEAUFI (ORCPT ); Mon, 1 May 2023 16:05:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50816 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233310AbjEAUE4 (ORCPT ); Mon, 1 May 2023 16:04:56 -0400 Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 02EDB170E for ; Mon, 1 May 2023 13:04:51 -0700 (PDT) Received: from pps.filterd (m0246617.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 341JnEXc030039; Mon, 1 May 2023 20:04:46 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : content-transfer-encoding : content-type : mime-version; s=corp-2023-03-30; bh=UuEUHUWmTs1Thx9J8McODvVkt2j6t8yyOrRtMd2G9ec=; b=JbAoVATulueKUMm7g301CnYbSxiMFuvSNffgps+sNZMDiPjbNVMz6E/Jd1B9Wbb4+puo NWmECFMtttnFV5HHpOoq54apoRzcVO4QAb92id5viq1C4rWhItHty2g0to7YRJ9tbIYu V1Snkp081/L5m5vAhA+gCqQ9+SJpfJ/2/Hy6G+421gyt/mw/EmjA3J2EOaXAq5z5SNor 5Pre4EfdL6l9nyC2bLtAAJ34pfvDZilFXUAAvwC0qhfSU8jW5s3C2c+VpZIr/ClTWBP5 GHfxP1rRAGrazmpxmqFGV/jHAZMLucOMnGQyD8ab3fEVLXumncJ7CtLn/wr2lnxmh/Qf pw== Received: from phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta01.appoci.oracle.com [138.1.114.2]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3q8usuu3uf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 01 May 2023 20:04:46 +0000 Received: from pps.filterd (phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 341JhW5U036176; Mon, 1 May 2023 20:04:45 GMT Received: from nam10-mw2-obe.outbound.protection.outlook.com (mail-mw2nam10lp2103.outbound.protection.outlook.com [104.47.55.103]) by phxpaimrmta01.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3q8sp4uw7x-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 01 May 2023 20:04:45 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ersiqMra8EdlJ2j0FTmoUsj1LVnFhrnOAe24rjReAx7xThmVjGbC9c7VD1b3GYChCixQxZmxAlm1XDCRn4P7K+pI0Ivl98oNLKMPwKOQVfMaoq5+uUk1TsaY2+/Cu1uej3RSbCFZL39fXdauW/2dbzWMqgviqQssk/Vr6JjqHYEYUaXznm+8CeeldmuzTI/zHzI9yfi8n3tUWkEcGyCAyU8Ym/Riv4hvfmVjTL4+lPcCviDNiQRkgsxwb9vlhrE4VUxvJdRLp7BUmWCCKXvYzmcwzksW2t5cPP7NHHvtXif76GrCwO7prW+FHfZTDisbLj5QZ210zjLFcjCHoYqAUQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=UuEUHUWmTs1Thx9J8McODvVkt2j6t8yyOrRtMd2G9ec=; b=cQOCXXaKMzRJkrJ/lOPUYmY2wCHTayF9+1zgB0g4f4Z+qc/GrCoWZe9zmR1ycnkzEMhBV09LIJTd5aJzGR+GNzPKSft1yNeS5CfzgTTl58Vb6YVthHPI3VgtABf+weCJQ65GpXHkCmDxsCWAzXAyf2eq7UD3185ectPAp2vh2aQXM8S85jRFa+AiATh4rx0/EIld5yyaipkiWVTWPsEJQIPlMN88QMIwYuCLw475AFdRW+/IW3/76Cyi9h3mO9Ah5dVbev7E0ISp5dtyhM8ihjKfito5+u3+Lg9aeXXmcn4GQW0CzcS9Efyt2oUUo3qDxASbfU6eqs+7joXw2KDgKA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=oracle.com; dmarc=pass action=none header.from=oracle.com; dkim=pass header.d=oracle.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.onmicrosoft.com; s=selector2-oracle-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=UuEUHUWmTs1Thx9J8McODvVkt2j6t8yyOrRtMd2G9ec=; b=VeXYAUN6rYy3dDUZbkLBMOfAvW4jFiaaWxXWIQNiy19vVVSoj5KWMaaLKmcbt5f/U4JfRfPxpwGvpYGvPy2G9zlWU/9mRj4g8L1fVMZUzfnQLPUZ4mfiZOuNK8+eu9R8jivmiiJCO/ZI9aBH6AighnLEB+t3wvXDIC+AWP8IYdA= Received: from MWHPR1001MB2158.namprd10.prod.outlook.com (2603:10b6:301:2d::17) by DM6PR10MB4218.namprd10.prod.outlook.com (2603:10b6:5:222::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6340.30; Mon, 1 May 2023 20:04:42 +0000 Received: from MWHPR1001MB2158.namprd10.prod.outlook.com ([fe80::ff1c:f1fb:8db9:22e2]) by MWHPR1001MB2158.namprd10.prod.outlook.com ([fe80::ff1c:f1fb:8db9:22e2%6]) with mapi id 15.20.6340.030; Mon, 1 May 2023 20:04:42 +0000 From: Indu Bhagat To: linux-toolchains@vger.kernel.org Cc: daandemeyer@meta.com, andrii@kernel.org, rostedt@goodmis.org, kris.van.hees@oracle.com, elena.zannoni@oracle.com, nick.alcock@oracle.com, Indu Bhagat Subject: [POC 3/5] sframe: add new SFrame library Date: Mon, 1 May 2023 13:04:08 -0700 Message-Id: <20230501200410.3973453-4-indu.bhagat@oracle.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230501200410.3973453-1-indu.bhagat@oracle.com> References: <20230501200410.3973453-1-indu.bhagat@oracle.com> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: MW4PR04CA0193.namprd04.prod.outlook.com (2603:10b6:303:86::18) To MWHPR1001MB2158.namprd10.prod.outlook.com (2603:10b6:301:2d::17) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: MWHPR1001MB2158:EE_|DM6PR10MB4218:EE_ X-MS-Office365-Filtering-Correlation-Id: fc0e961d-102d-461e-9304-08db4a7f4d4a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: VXOUWUh/WXQjMdNNu5cbKP1pz8YhJzZ7i28XZEGC99aY+qSYHkvn+xkIBEWh0Heqtu02sbP7SWgTJNtDG3OnivXxQT/kxWzi6PdMs0o6KFYVAK+O+Xx9jsbaojEAr0YKAolCyJj49C9/2W07jemussHY4tPmW5Yub6mEBCTvmpMR0TRSiinv/8t/UBLhY5vP0eU5wTMXePMnb9B49m9678j9EVK7MJ7tmMTjiEAtUEN+zRnWgE8HELVvY2vUr65TdNmY4rv1oLlAQB4BsBd+LVuje8Es+XM8xqiAK5FU1VF3PWU2A/owd0tJHygukKJgXvo1mvWxKZTEXSl6Nal5C+eOo0Qr5qPeSfkz9BD/xVwAVzBMwGvEG+hwjwRLnRHzwElWPdadEzTsHT3l13ekATwbGvQjcQobngL5N0v9gBJKNMBD8CkWNhXgwMwRQnWUP5Lc76iJnavjFVlZsO1FEUgAxOzn4mLmK8pjAJahFJjRLL2Cb/pBBCdsDXD2xPlNd+cKpO93BOF7lUsR0txXkvIJziW5OJBql9tktWLQ4QU= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:MWHPR1001MB2158.namprd10.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230028)(366004)(39860400002)(396003)(346002)(376002)(136003)(451199021)(30864003)(2906002)(478600001)(66476007)(66946007)(41300700001)(4326008)(6916009)(316002)(66556008)(5660300002)(8936002)(8676002)(44832011)(6512007)(38100700002)(6506007)(107886003)(83380400001)(2616005)(36756003)(86362001)(966005)(6666004)(6486002)(1076003)(186003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?0MNDAsnVXTvyowgQNsDKU5nqDxK0cW7NL/12H8tZx7vKN8B1bYHh57qIHfuS?= =?us-ascii?Q?yYxT+lauQ5tH3bUGGWpLbTJZp+WuD7Bo+SvrC4rNEdDKR5T+T/H8pd5qmuKr?= =?us-ascii?Q?TGstjo9etnxqMY8TG8U1U61GebB1LzXqxCVcIZ2iTU/y2fiwo4X1rpuusmFB?= =?us-ascii?Q?SG1wMd7I3h2LiXEplw7EsaHVHGqJ7TskAKvEOoeGbr9N7ZFLQa2Ch9QJdVU+?= =?us-ascii?Q?7ABWUqs9G5C5nButlJdNUnhguND/hc76/LrNfIOhwd4cgTINH9YsVjZgzmIR?= =?us-ascii?Q?IXZX7QkIQGQGbvV427pTXM8VIfNHQxZAems4nZzX9PVoy7MWcc/rsddShCQs?= =?us-ascii?Q?H4FsQEH8m0F/vEj//zLuarHi7unfVaJ24BRBx2/YQN3HzOEPu34UjiOHNt78?= =?us-ascii?Q?1hqXA9fRr27tnXbfUaDOZMGzXS6uvuzl2l0yhqVZ+6Bh20nefro4O642XXMR?= =?us-ascii?Q?5kR7rtvz+Mz4av1EdxQF80QcwOUPS77FDPSJBkAKcFAOwCFk4/k0oZJy2Dyx?= =?us-ascii?Q?sa9WqYEKjAfnBr6+uQWxyf8WqwJFNnPJYAHa2lbUMsd038jHI9gSBa2lGk/U?= =?us-ascii?Q?xIC4h5IIgnRX0NxoahgcqKpCKzizbJngwyWK1CbT01svpMY5Gj/0fgfu78Dc?= =?us-ascii?Q?esYaSF3pO+rgTkA5VmhIsa43RYjq02qIwqbT8wyXN4DbrE6aa9k/wMYJQYak?= =?us-ascii?Q?Qa7wbgHpe46kaU3YbWTzjIQNMA4r6TiBp9ZFhaHwl9JGtZey2Lu05iI2w8yy?= =?us-ascii?Q?IE/kTxRX3X3/cCDMdkx0VlQhE7qC7qJXl9HyJAIbjIelKUA5p3dz21ALKWkm?= =?us-ascii?Q?+TOfZFbhgdR3qmiB+fkqqvHU8JoiR/wZDXW1RIxHlOhfBgJsB+inmAqVUgXj?= =?us-ascii?Q?E4eUW425KZ6EQcsUqdjUv3XQcDQWuyxWivVNpJ9vuba9phaa0WfnpXBUv7zd?= =?us-ascii?Q?QJnstrnwRqhzFU0NBDNm18kyeXzVZ5bX7AoyU9TNxrA6MUVggQRC1WcLwLaN?= =?us-ascii?Q?pBRfQbDvKB6v/cYt223bof64QTG6GiHWj6Zm11FwCFY6L7UpVeH3hVqkk3BM?= =?us-ascii?Q?0N6FESrokiQJ/hkoYIj16fQaeNK/4j3rqKRQbdR/whWYqhl/Fl7UregxaFQf?= =?us-ascii?Q?0AoJe/cZJbSIxHxy1So4SimjcZKjhXSVzwjFCbHQ73pUCEBiQEfJA9u6Ht2M?= =?us-ascii?Q?AzOU0yyDvl2fQjQ3q/WwHEhbqyE+cRygzzS8ejmX20Hb6iPwdkIPCpYGbzXE?= =?us-ascii?Q?6DtxN4zXZrHjiwBrMAeVTbPrr6b6zvF8LHHv46MxQbh9+Vg1pRSPiq/fi9M5?= =?us-ascii?Q?RtZb6yKnA7/I83gzK60jR6oB8vlSX2fwM8CQ1FMxMtFCbFVOylSbYuwZkykn?= =?us-ascii?Q?iAk5M3Qo+wy7G2hlTGusuGdX7WW9nbECtFQQQEy4YS49CIvmgB3OkkJjvPd0?= =?us-ascii?Q?lxim0P19avKyLRm8ytV3kq8D44MPQ2P897Ie504W0SliTcFzy1EE1aE1FMmE?= =?us-ascii?Q?jHL8qfg+jl64U9n1+JKxwaw+HmGHAIceSVswwWuTQie+dxg7KkIuwerlvZxD?= =?us-ascii?Q?IZYl5cQH5RJFqZ3t9hrUO8DTFOWdxNVH7ghqLpKmPc1+UQD6v4gapv+i7R5m?= =?us-ascii?Q?6o1zQUxVgqxYKeU4x/qEgz4=3D?= X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: hA8oj4GaFIqhWqAMXBzuo1fgofkp8cLJXwy31czwBn3w4f9jFDs5iQDiVeklaSRYxzMpoMEWmopRR5kD+Tg6d+5u3yHaiFM4NoZk3gKLHa6KM0daSFL9+tbKtZqpKJte0llSxDtHZSrTcyrbAAdlLcX/CN+9XKOmke/bYBAQBv3GNkYXgWwrzLfnETFWg1KDZ2V/Ho+Zu2+J56Hfq7uYThZC71QQLFHqsOnvxpfC7+32uXWIKmd9vy2cfiI8J1bQm9Gn/mUYD+5IubcgnfE0hln7RWbHZAH7+gUdqnUT58qulei2w9YC63ouhZpyWWd1jmWeqT2CbvvfPOUPVRaYWosIkpILpE7z+KnmeVQ8BYQcWrqcsAravqXequ8aiPM7DXwY42UDlq0ag98QjybbfCjqZuGvNlImZcLux0M1sTus82HOO7g8Gv705kxl7b5uoL1h9rxjQKLFP7kFJQxsOVoUqPGAKrB62ZOBKXuc2KG9rzAE3sqorUhNQLzm+EgOoHFCV+NE+KE9ivi4VAD7sdJ4+iGgWL+z2O26WNLPjX1A+1reJq5tSzvT0kZVdpXGmc1USTWfnmAVvI7joM88L9kqM7nImDmKOs7XzF5MzR3nDmR0TeMM5qqHPk5BUfn/4pmpDShAysVaqBY5fD2IEwLFbCRaOoh+gmRysEj9jfgIt1bhmGvGfdfKgUF1IC1fw5BsL6LzYqIWagG6gaeGXAP937v1Ywg7vsS/ntLfV2H1HUSAxG1Gd/f7MS/E1IY5z2U9ZbP45cG74lKE6FpYEOA4a/zCA0Cxa5goJrO246XOaKvqcK8/GW6QdeN3OA5iGxIANZmoBC/s7b2ylISr9Q== X-OriginatorOrg: oracle.com X-MS-Exchange-CrossTenant-Network-Message-Id: fc0e961d-102d-461e-9304-08db4a7f4d4a X-MS-Exchange-CrossTenant-AuthSource: MWHPR1001MB2158.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 May 2023 20:04:42.6023 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4e2c6054-71cb-48f1-bd6c-3a9705aca71b X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 5SZT4YM1i0AGRXwQCh8BqohEa9d7hzFjsFhezO0qiLWmfU23NhfVXqcsdjb30ne7ovLOdCskRQbCjtO4CjZ4Ig== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR10MB4218 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.254,Aquarius:18.0.942,Hydra:6.0.573,FMLib:17.11.170.22 definitions=2023-05-01_12,2023-04-27_01,2023-02-09_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 bulkscore=0 mlxscore=0 spamscore=0 mlxlogscore=999 phishscore=0 malwarescore=0 adultscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2303200000 definitions=main-2305010161 X-Proofpoint-ORIG-GUID: XOVyp1ssfyhkgpzioTAWRVkOBRKMUaOc X-Proofpoint-GUID: XOVyp1ssfyhkgpzioTAWRVkOBRKMUaOc Precedence: bulk List-ID: X-Mailing-List: linux-toolchains@vger.kernel.org This patch adds an implementation to read SFrame stack trace data from a .sframe section. Some APIs are also provided to find stack tracing information per PC, e.g., given a PC, find the SFrame FRE. These routines are provided in the sframe_read.h and sframe_read.c. This implmentation is malloc-free. Signed-off-by: Indu Bhagat --- lib/Makefile | 1 + lib/sframe/Makefile | 5 + lib/sframe/sframe.h | 263 +++++++++++++++++++++ lib/sframe/sframe_read.c | 498 +++++++++++++++++++++++++++++++++++++++ lib/sframe/sframe_read.h | 75 ++++++ 5 files changed, 842 insertions(+) create mode 100644 lib/sframe/Makefile create mode 100644 lib/sframe/sframe.h create mode 100644 lib/sframe/sframe_read.c create mode 100644 lib/sframe/sframe_read.h diff --git a/lib/Makefile b/lib/Makefile index 876fcdeae34e..cb02d16dbffd 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -198,6 +198,7 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/ obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ +obj-$(CONFIG_USER_UNWINDER_SFRAME) += sframe/ lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o diff --git a/lib/sframe/Makefile b/lib/sframe/Makefile new file mode 100644 index 000000000000..4e4291d9294f --- /dev/null +++ b/lib/sframe/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +################################## +obj-$(CONFIG_USER_UNWINDER_SFRAME) += sframe_read.o \ + +CFLAGS_sframe_read.o += -I $(srctree)/lib/sframe/ diff --git a/lib/sframe/sframe.h b/lib/sframe/sframe.h new file mode 100644 index 000000000000..b1290e92839a --- /dev/null +++ b/lib/sframe/sframe.h @@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023, Oracle and/or its affiliates. + */ + +#ifndef SFRAME_H +#define SFRAME_H + +#include + +/* This file contains definitions for the SFrame stack tracing format, which is + * documented at https://sourceware.org/binutils/docs */ + +#define SFRAME_VERSION_1 1 +#define SFRAME_MAGIC 0xdee2 +#define SFRAME_VERSION SFRAME_VERSION_1 + +/* Function Descriptor Entries are sorted on PC. */ +#define SFRAME_F_FDE_SORTED 0x1 +/* Frame-pointer based stack tracing. Defined, but not set. */ +#define SFRAME_F_FRAME_POINTER 0x2 + +#define SFRAME_CFA_FIXED_FP_INVALID 0 +#define SFRAME_CFA_FIXED_RA_INVALID 0 + +/* Supported ABIs/Arch. */ +#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. */ + +/* SFrame FRE types. */ +#define SFRAME_FRE_TYPE_ADDR1 0 +#define SFRAME_FRE_TYPE_ADDR2 1 +#define SFRAME_FRE_TYPE_ADDR4 2 + +/* + * SFrame Function Descriptor Entry types. + * + * The SFrame format has two possible representations for functions. The + * choice of which type to use is made according to the instruction patterns + * in the relevant program stub. + */ + +/* Unwinders perform a (PC >= FRE_START_ADDR) to look up a matching FRE. */ +#define SFRAME_FDE_TYPE_PCINC 0 +/* + * Unwinders perform a (PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK) + * to look up a matching FRE. Typical usecases are pltN entries, trampolines + * etc. + */ +#define SFRAME_FDE_TYPE_PCMASK 1 + +struct sframe_preamble +{ + /* Magic number (SFRAME_MAGIC). */ + uint16_t magic; + /* Data format version number (SFRAME_VERSION). */ + uint8_t version; + /* Various flags. */ + uint8_t flags; +} __packed; + +struct sframe_header +{ + struct sframe_preamble preamble; + /* Information about the arch (endianness) and ABI. */ + uint8_t abi_arch; + /* + * Offset for the Frame Pointer (FP) from CFA may be fixed for some + * ABIs (e.g, in AMD64 when -fno-omit-frame-pointer is used). When fixed, + * this field specifies the fixed stack frame offset and the individual + * FREs do not need to track it. When not fixed, it is set to + * SFRAME_CFA_FIXED_FP_INVALID, and the individual FREs may provide + * the applicable stack frame offset, if any. + */ + int8_t cfa_fixed_fp_offset; + /* + * Offset for the Return Address from CFA is fixed for some ABIs + * (e.g., AMD64 has it as CFA-8). When fixed, the header specifies the + * fixed stack frame offset and the individual FREs do not track it. When + * not fixed, it is set to SFRAME_CFA_FIXED_RA_INVALID, and individual + * FREs provide the applicable stack frame offset, if any. + */ + int8_t cfa_fixed_ra_offset; + /* + * Number of bytes making up the auxiliary header, if any. + * Some ABI/arch, in the future, may use this space for extending the + * information in SFrame header. Auxiliary header is contained in + * bytes sequentially following the sframe_header. + */ + uint8_t auxhdr_len; + /* Number of SFrame FDEs in this SFrame section. */ + uint32_t num_fdes; + /* Number of SFrame Frame Row Entries. */ + uint32_t num_fres; + /* Number of bytes in the SFrame Frame Row Entry section. */ + uint32_t fre_len; + /* Offset of SFrame Function Descriptor Entry section. */ + uint32_t fdeoff; + /* Offset of SFrame Frame Row Entry section. */ + uint32_t freoff; +} __packed; + +#define SFRAME_V1_HDR_SIZE(sframe_hdr) \ + ((sizeof (struct sframe_header) + (sframe_hdr).auxhdr_len)) + +/* Two possible keys for executable (instruction) pointers signing. */ +#define SFRAME_AARCH64_PAUTH_KEY_A 0 /* Key A. */ +#define SFRAME_AARCH64_PAUTH_KEY_B 1 /* Key B. */ + +struct sframe_func_desc_entry +{ + /* + * Function start address. Encoded as a signed offset, relative to the + * beginning of the current FDE. + */ + int32_t func_start_address; + /* Size of the function in bytes. */ + uint32_t func_size; + /* + * Offset of the first SFrame Frame Row Entry of the function, relative to the + * beginning of the SFrame Frame Row Entry sub-section. + */ + uint32_t func_start_fre_off; + /* Number of frame row entries for the function. */ + uint32_t func_num_fres; + /* + * Additional information for deciphering the unwind information for the + * function. + * - 4-bits: Identify the FRE type used for the function. + * - 1-bit: Identify the FDE type of the function - mask or inc. + * - 1-bit: PAC authorization A/B key (aarch64). + * - 2-bits: Unused. + * -------------------------------------------------------------------------- + * | Unused | PAC auth A/B key (aarch64) | FDE type | FRE type | + * | | Unused (amd64) | | | + * -------------------------------------------------------------------------- + * 8 6 5 4 0 + */ + uint8_t func_info; +} __packed; + +/* Note: Set PAC auth key to SFRAME_AARCH64_PAUTH_KEY_A by default. */ +#define SFRAME_V1_FUNC_INFO(fde_type, fre_enc_type) \ + (((SFRAME_AARCH64_PAUTH_KEY_A & 0x1) << 5) | \ + (((fde_type) & 0x1) << 4) | ((fre_enc_type) & 0xf)) + +#define SFRAME_V1_FUNC_FRE_TYPE(data) ((data) & 0xf) +#define SFRAME_V1_FUNC_FDE_TYPE(data) (((data) >> 4) & 0x1) +#define SFRAME_V1_FUNC_PAUTH_KEY(data) (((data) >> 5) & 0x1) + +/* + * Size of stack frame offsets in an SFrame Frame Row Entry. A single + * SFrame FRE has all offsets of the same size. Offset size may vary + * across frame row entries. + */ +#define SFRAME_FRE_OFFSET_1B 0 +#define SFRAME_FRE_OFFSET_2B 1 +#define SFRAME_FRE_OFFSET_4B 2 + +/* An SFrame Frame Row Entry can be SP or FP based. */ +#define SFRAME_BASE_REG_FP 0 +#define SFRAME_BASE_REG_SP 1 + +/* + * The index at which a specific offset is presented in the variable length + * bytes of an FRE. + */ +#define SFRAME_FRE_CFA_OFFSET_IDX 0 +/* + * The RA stack offset, if present, will always be at index 1 in the variable + * length bytes of the FRE. + */ +#define SFRAME_FRE_RA_OFFSET_IDX 1 +/* + * The FP stack offset may appear at offset 1 or 2, depending on the ABI as RA + * may or may not be tracked. + */ +#define SFRAME_FRE_FP_OFFSET_IDX 2 + +struct sframe_fre_info +{ + /* Information about + * - 1 bit: base reg for CFA + * - 4 bits: Number of offsets (N). A value of upto 3 is allowed to track + * all three of CFA, FP and RA (fixed implicit order). + * - 2 bits: information about size of the offsets (S) in bytes. + * Valid values are SFRAME_FRE_OFFSET_1B, SFRAME_FRE_OFFSET_2B, + * SFRAME_FRE_OFFSET_4B + * - 1 bit: Mangled RA state bit (aarch64 only). + * ----------------------------------------------------------------------------------- + * | Mangled-RA (aarch64) | Size of offsets | Number of offsets | base_reg | + * | Unused (amd64) | | | | + * ----------------------------------------------------------------------------------- + * 8 7 5 1 0 + */ + uint8_t fre_info; +}; + +/* Macros to compose and decompose FRE info. */ + +/* Note: Set mangled_ra_p to zero by default. */ +#define SFRAME_V1_FRE_INFO(base_reg_id, offset_num, offset_size) \ + (((0 & 0x1) << 7) | (((offset_size) & 0x3) << 5) | \ + (((offset_num) & 0xf) << 1) | ((base_reg_id) & 0x1)) + +/* Set the mangled_ra_p bit as indicated. */ +#define SFRAME_V1_FRE_INFO_UPDATE_MANGLED_RA_P(mangled_ra_p, fre_info) \ + ((((mangled_ra_p) & 0x1) << 7) | ((fre_info) & 0x7f)) + +#define SFRAME_V1_FRE_CFA_BASE_REG_ID(data) ((data) & 0x1) +#define SFRAME_V1_FRE_OFFSET_COUNT(data) (((data) >> 1) & 0xf) +#define SFRAME_V1_FRE_OFFSET_SIZE(data) (((data) >> 5) & 0x3) +#define SFRAME_V1_FRE_MANGLED_RA_P(data) (((data) >> 7) & 0x1) + +/* SFrame Frame Row Entry definitions. */ + +/* + * Used when SFRAME_FRE_TYPE_ADDR1 is specified as FRE type. + * Upper limit of start address in sframe_frame_row_entry_addr1 if 0x100 (not + * inclusive). + */ +struct sframe_frame_row_entry_addr1 +{ + /* + * Start address of the frame row entry. Encoded as an 1-byte unsigned + * offset, relative to the start address of the function. + */ + uint8_t fre_start_ip_offset; + struct sframe_fre_info fre_info; +} __packed; + +/* + * Used when SFRAME_FRE_TYPE_ADDR2 is specified as FRE type. + * Upper limit of start address in sframe_frame_row_entry_addr2 is 0x10000 (not + * inclusive). + */ +struct sframe_frame_row_entry_addr2 +{ + /* + * Start address of the frame row entry. Encoded as an 2-byte unsigned + * offset, relative to the start address of the function. + */ + uint16_t fre_start_ip_offset; + struct sframe_fre_info fre_info; +} __packed; + +/* + * Used when SFRAME_FRE_TYPE_ADDR4 is specified as FRE type. + * Upper limit of start address in sframe_frame_row_entry_addr2 + * is 0x100000000 (not inclusive). + */ +struct sframe_frame_row_entry_addr4 +{ + /* + * Start address of the frame row entry. Encoded as a 4-byte unsigned + * offset, relative to the start address of the function. + */ + uint32_t fre_start_ip_offset; + struct sframe_fre_info fre_info; +} __packed; + +#endif /* SFRAME_H */ diff --git a/lib/sframe/sframe_read.c b/lib/sframe/sframe_read.c new file mode 100644 index 000000000000..9d6558d62c54 --- /dev/null +++ b/lib/sframe/sframe_read.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023, Oracle and/or its affiliates. + */ + +#include + +#include "sframe_read.h" + +struct sframe_sec { + /* SFrame header. */ + struct sframe_header header; + /* SFrame Function Desc Entries. */ + void *fdes; + /* SFrame Frame Row Entries. */ + void *fres; + /* Number of bytes needed for SFrame FREs. */ + uint32_t fre_nbytes; +}; + +static int sframe_set_errno(int *errp, int error) +{ + if (errp != NULL) + *errp = error; + return SFRAME_ERR; +} + +static uint32_t sframe_sec_get_hdr_size(struct sframe_header *sfh) +{ + return SFRAME_V1_HDR_SIZE(*sfh); +} + +static unsigned int sframe_fre_get_offset_count(unsigned char fre_info) +{ + return SFRAME_V1_FRE_OFFSET_COUNT(fre_info); +} + +static unsigned int sframe_fre_get_offset_size(unsigned char fre_info) +{ + return SFRAME_V1_FRE_OFFSET_SIZE(fre_info); +} + +static unsigned int sframe_get_fre_type(struct sframe_func_desc_entry *fdep) +{ + return (fdep) ? SFRAME_V1_FUNC_FRE_TYPE(fdep->func_info) : 0; +} + +static unsigned int sframe_get_fde_type(struct sframe_func_desc_entry *fdep) +{ + return (fdep) ? SFRAME_V1_FUNC_FDE_TYPE(fdep->func_info) : 0; +} + +static bool sframe_header_sanity_check_p(struct sframe_header *hp) +{ + unsigned char all_flags = SFRAME_F_FDE_SORTED | SFRAME_F_FRAME_POINTER; + /* Check that the preamble is valid. */ + if ((hp->preamble.magic != SFRAME_MAGIC) + || (hp->preamble.version != SFRAME_VERSION) + || ((hp->preamble.flags | all_flags) != all_flags)) + return false; + + /* Check that the offsets are valid. */ + if (hp->fdeoff > hp->freoff) + return false; + + return true; +} + +static bool sframe_fre_sanity_check_p(struct sframe_fre *frep) +{ + unsigned int offset_size, offset_cnt; + + if (frep == NULL) + return false; + + offset_size = sframe_fre_get_offset_size(frep->fre_info); + + if (offset_size != SFRAME_FRE_OFFSET_1B + && offset_size != SFRAME_FRE_OFFSET_2B + && offset_size != SFRAME_FRE_OFFSET_4B) + return false; + + offset_cnt = sframe_fre_get_offset_count(frep->fre_info); + if (offset_cnt > MAX_NUM_STACK_OFFSETS) + return false; + + return true; +} + +static int32_t sframe_get_fre_offset(struct sframe_fre *frep, uint32_t idx, + int *errp) +{ + int offset_cnt, offset_size; + + if (frep == NULL || !sframe_fre_sanity_check_p(frep)) + return sframe_set_errno(errp, SFRAME_ERR_FRE_INVAL); + + offset_cnt = sframe_fre_get_offset_count(frep->fre_info); + offset_size = sframe_fre_get_offset_size(frep->fre_info); + + if (offset_cnt < idx + 1) + return sframe_set_errno(errp, SFRAME_ERR_FREOFFSET_NOPRESENT); + + if (errp != NULL) + *errp = 0; /* Offset Valid. */ + + if (offset_size == SFRAME_FRE_OFFSET_1B) { + int8_t *stack_offsets = (int8_t *)frep->fre_offsets; + return stack_offsets[idx]; + } else if (offset_size == SFRAME_FRE_OFFSET_2B) { + int16_t *stack_offsets = (int16_t *)frep->fre_offsets; + return stack_offsets[idx]; + } else { + int32_t *stack_offsets = (int32_t *)frep->fre_offsets; + return stack_offsets[idx]; + } +} + +static struct sframe_header *sframe_sec_get_header(struct sframe_sec *sfsec) +{ + return sfsec ? &sfsec->header : NULL; +} + +static int sframe_fre_copy(struct sframe_fre *dst, + struct sframe_fre *src) +{ + if (dst == NULL || src == NULL) + return SFRAME_ERR; + + memcpy(dst, src, sizeof(struct sframe_fre)); + return 0; +} + +static int sframe_decode_start_ip_offset(const char *fre_buf, + uint32_t *start_ip_offset, + unsigned int fre_type) +{ + uint32_t saddr = 0; + + if (fre_type == SFRAME_FRE_TYPE_ADDR1) { + uint8_t *uc = (uint8_t *)fre_buf; + saddr = (uint32_t)*uc; + } else if (fre_type == SFRAME_FRE_TYPE_ADDR2) { + uint16_t *ust = (uint16_t *)fre_buf; + saddr = (uint32_t)*ust; + } else if (fre_type == SFRAME_FRE_TYPE_ADDR4) { + uint32_t *uit = (uint32_t *)fre_buf; + saddr = (uint32_t)*uit; + } else { + return SFRAME_ERR_INVAL; + } + + *start_ip_offset = saddr; + return 0; +} + +/* Get the total size in bytes for the stack offsets. */ +static size_t sframe_fre_stack_offsets_size(unsigned char fre_info) +{ + unsigned int offset_size, offset_cnt; + + offset_size = sframe_fre_get_offset_size(fre_info); + offset_cnt = sframe_fre_get_offset_count(fre_info); + + if (offset_size == SFRAME_FRE_OFFSET_2B + || offset_size == SFRAME_FRE_OFFSET_4B) /* 2 or 4 bytes. */ + return (offset_cnt * (offset_size * 2)); + + return offset_cnt; +} + +static size_t sframe_fre_get_start_address_tsize(unsigned int fre_type) +{ + /* Type size of the start_addr in an FRE. */ + size_t saddr_tsize = 0; + + switch (fre_type) { + case SFRAME_FRE_TYPE_ADDR1: + saddr_tsize = sizeof(uint8_t); + break; + case SFRAME_FRE_TYPE_ADDR2: + saddr_tsize = sizeof(uint16_t); + break; + case SFRAME_FRE_TYPE_ADDR4: + saddr_tsize = sizeof(uint32_t); + break; + default: + /* No other value is expected. */ + break; + } + return saddr_tsize; +} + +static size_t sframe_fre_vlen_size(struct sframe_fre *frep, + unsigned int fre_type) +{ + unsigned char fre_info; + size_t ip_offset_tsize; + + if (frep == NULL) + return 0; + + fre_info = frep->fre_info; + ip_offset_tsize = sframe_fre_get_start_address_tsize(fre_type); + + /* + * An SFrame FRE is a variable length structure. It includes the start + * IP offset, FRE info field, and all trailing the stack offsets. + */ + return (ip_offset_tsize + sizeof(fre_info) + + sframe_fre_stack_offsets_size(fre_info)); +} + +/* + * Read an SFrame FRE which starts at location FRE_BUF. The function + * updates FRE_SIZE to the size of the FRE as stored in the binary format. + * + * Returns SFRAME_ERR if failure. + */ +static int sframe_sec_read_fre(const char *fre_buf, struct sframe_fre *frep, + unsigned int fre_type, size_t *fre_size) +{ + void *stack_offsets; + size_t stack_offsets_sz; + size_t ip_offset_tsize; + size_t esz; + + if (fre_buf == NULL || frep == NULL || fre_size == NULL) + return SFRAME_ERR_INVAL; + + /* Copy over the FRE start address. */ + sframe_decode_start_ip_offset(fre_buf, &frep->start_ip_offset, + fre_type); + + ip_offset_tsize = sframe_fre_get_start_address_tsize(fre_type); + /* PS: Note how this API works closely with SFrame binary format. */ + frep->fre_info = *(unsigned char *)(fre_buf + ip_offset_tsize); + + memset(frep->fre_offsets, 0, MAX_STACK_OFFSET_NBYTES); + /* Get stack offsets. */ + stack_offsets_sz = sframe_fre_stack_offsets_size(frep->fre_info); + stack_offsets = ((unsigned char *)fre_buf + ip_offset_tsize + + sizeof(frep->fre_info)); + memcpy(frep->fre_offsets, stack_offsets, stack_offsets_sz); + + esz = sframe_fre_vlen_size(frep, fre_type); + *fre_size = esz; + + return 0; +} + +static struct sframe_func_desc_entry * +sframe_sec_find_fde(struct sframe_sec *sfsec, int32_t addr, int *errp) +{ + struct sframe_header *header; + struct sframe_func_desc_entry *fde; + int low, high, cnt; + + if (sfsec == NULL) { + sframe_set_errno(errp, SFRAME_ERR_INVAL); + return NULL; + } + + header = sframe_sec_get_header(sfsec); + if (header == NULL || header->num_fdes == 0 || sfsec->fdes == NULL) { + sframe_set_errno(errp, SFRAME_ERR_INIT_INVAL); + return NULL; + } + /* + * Skip binary search if FDE sub-section is not sorted on PCs. GNU ld + * sorts the FDEs on start PC by default though. + */ + if ((header->preamble.flags & SFRAME_F_FDE_SORTED) == 0) { + sframe_set_errno(errp, SFRAME_ERR_FDE_NOTSORTED); + return NULL; + } + + /* Find the FDE that may contain the addr. */ + fde = (struct sframe_func_desc_entry *)sfsec->fdes; + low = 0; + high = header->num_fdes; + cnt = high; + while (low <= high) { + int mid = low + (high - low) / 2; + + if (fde[mid].func_start_address == addr) + return fde + mid; + + if (fde[mid].func_start_address < addr) { + if (mid == (cnt - 1)) + return fde + (cnt - 1); + else if (fde[mid+1].func_start_address > addr) + return fde + mid; + low = mid + 1; + } else + high = mid - 1; + } + + sframe_set_errno(errp, SFRAME_ERR_FDE_NOTFOUND); + return NULL; +} + +static int8_t sframe_sec_get_fixed_fp_offset(struct sframe_sec *sfsec) +{ + struct sframe_header *header = sframe_sec_get_header(sfsec); + return header->cfa_fixed_fp_offset; +} + +static int8_t sframe_sec_get_fixed_ra_offset(struct sframe_sec *sfsec) +{ + struct sframe_header *header = sframe_sec_get_header(sfsec); + return header->cfa_fixed_ra_offset; +} + +size_t sframe_sec_sizeof(void) +{ + return sizeof (struct sframe_sec); +} + +int sframe_sec_init(struct sframe_sec *sfsec, const char *sf_buf, + size_t sf_size) +{ + char *frame_buf; + const struct sframe_preamble *preamble; + struct sframe_header *header; + + if ((sf_buf == NULL) || (sf_size < sizeof(struct sframe_header))) + return SFRAME_ERR_INVAL; + + /* Check for foreign endianness. */ + preamble = (const struct sframe_preamble *) sf_buf; + if (preamble->magic != SFRAME_MAGIC) + return SFRAME_ERR_INVAL; + + /* Reset the SFrame section object. */ + memset(sfsec, 0, sizeof(struct sframe_sec)); + + frame_buf = (char *)sf_buf; + + /* Initialize the reference to the SFrame header. */ + sfsec->header = *(struct sframe_header *) frame_buf; + header = &sfsec->header; + if (!sframe_header_sanity_check_p(header)) + return SFRAME_ERR_INVAL; + + /* Initialize the referece to the SFrame FDE section. */ + frame_buf += sframe_sec_get_hdr_size(header); + sfsec->fdes = frame_buf; + + /* Initialize the reference to the the SFrame FRE section. */ + frame_buf += (header->num_fdes * sizeof(struct sframe_func_desc_entry)); + sfsec->fres = frame_buf; + + sfsec->fre_nbytes = header->fre_len; + + return 0; +} + +/* + * Find the SFrame Frame Row Entry which contains the PC. + * Returns error code if failure. + */ +int sframe_sec_find_fre(struct sframe_sec *sfsec, int32_t pc, + struct sframe_fre *frep) +{ + struct sframe_func_desc_entry *fdep; + uint32_t start_address, i; + struct sframe_fre cur_fre, next_fre; + unsigned char *fres; + unsigned int fre_type, fde_type; + size_t esz; + int err = 0; + size_t size = 0; + /* + * For regular FDEs(i.e. fde_type SFRAME_FDE_TYPE_PCINC), + * where the start address in the FRE is an offset from start pc, + * use a bitmask with all bits set so that none of the address bits are + * ignored. In this case, we need to return the FRE where + * (PC >= FRE_START_ADDR). + */ + uint64_t bitmask = 0xffffffff; + + if ((sfsec == NULL) || (frep == NULL)) + return SFRAME_ERR_INVAL; + + /* Find the FDE which contains the PC, then scan its FRE entries. */ + fdep = sframe_sec_find_fde(sfsec, pc, &err); + if (fdep == NULL || sfsec->fres == NULL) + return SFRAME_ERR_INIT_INVAL; + + fre_type = sframe_get_fre_type(fdep); + fde_type = sframe_get_fde_type(fdep); + + /* + * For FDEs for repetitive pattern of insns, we need to return the FRE + * such that(PC & FRE_START_ADDR_AS_MASK >= FRE_START_ADDR_AS_MASK). + * so, update the bitmask to the start address. + */ + /* FIXME - the bitmask. */ + if (fde_type == SFRAME_FDE_TYPE_PCMASK) + bitmask = 0xff; + + fres = (unsigned char *)sfsec->fres + fdep->func_start_fre_off; + for (i = 0; i < fdep->func_num_fres; i++) { + err = sframe_sec_read_fre((const char *)fres, &next_fre, + fre_type, &esz); + start_address = next_fre.start_ip_offset; + + if (((fdep->func_start_address + + (int32_t)start_address) & bitmask) <= (pc & bitmask)) { + sframe_fre_copy(&cur_fre, &next_fre); + + /* Get the next FRE in sequence. */ + if (i < fdep->func_num_fres - 1) { + fres += esz; + err = sframe_sec_read_fre((const char *)fres, + &next_fre, + fre_type, &esz); + + /* Sanity check the next FRE. */ + if (!sframe_fre_sanity_check_p(&next_fre)) + return SFRAME_ERR_FRE_INVAL; + + size = next_fre.start_ip_offset; + } else { + size = fdep->func_size; + } + + if (((fdep->func_start_address + + (int32_t)size) & bitmask) > (pc & bitmask)) { + /* Cur FRE contains the PC, return it. */ + sframe_fre_copy(frep, &cur_fre); + return 0; + } + } else { + return SFRAME_ERR_FRE_INVAL; + } + } + return SFRAME_ERR_FDE_INVAL; +} + +unsigned int sframe_fre_get_base_reg_id(struct sframe_fre *frep, + int *errp) +{ + if (!frep) + return sframe_set_errno(errp, SFRAME_ERR_FRE_INVAL); + + return SFRAME_V1_FRE_CFA_BASE_REG_ID(frep->fre_info); +} + +int32_t sframe_fre_get_cfa_offset(struct sframe_sec *sfsec __always_unused, + struct sframe_fre *frep, int *errp) +{ + return sframe_get_fre_offset(frep, SFRAME_FRE_CFA_OFFSET_IDX, errp); +} + +int32_t sframe_fre_get_fp_offset(struct sframe_sec *sfsec, + struct sframe_fre *frep, int *errp) +{ + uint32_t fp_offset_idx = 0; + int8_t fp_offset = sframe_sec_get_fixed_fp_offset(sfsec); + /* + * If the FP offset is not being tracked, return the fixed FP offset + * from the SFrame header. + */ + if (fp_offset != SFRAME_CFA_FIXED_FP_INVALID) { + *errp = 0; + return fp_offset; + } + + /* + * In some ABIs, the stack offset to recover RA (using the CFA) from is + * fixed (like AMD64). In such cases, the stack offset to recover FP + * will appear at the second index. + */ + fp_offset_idx = ((sframe_sec_get_fixed_ra_offset(sfsec) + != SFRAME_CFA_FIXED_RA_INVALID) + ? SFRAME_FRE_RA_OFFSET_IDX + : SFRAME_FRE_FP_OFFSET_IDX); + return sframe_get_fre_offset(frep, fp_offset_idx, errp); +} + +int32_t sframe_fre_get_ra_offset(struct sframe_sec *sfsec, + struct sframe_fre *frep, int *errp) +{ + int8_t ra_offset = sframe_sec_get_fixed_ra_offset(sfsec); + /* + * If the RA offset was not being tracked, return the fixed RA offset + * from the SFrame header. + */ + if (ra_offset != SFRAME_CFA_FIXED_RA_INVALID) { + *errp = 0; + return ra_offset; + } + + /* Otherwise, get the RA offset from the FRE. */ + return sframe_get_fre_offset(frep, SFRAME_FRE_RA_OFFSET_IDX, errp); +} diff --git a/lib/sframe/sframe_read.h b/lib/sframe/sframe_read.h new file mode 100644 index 000000000000..6632fb76d8b1 --- /dev/null +++ b/lib/sframe/sframe_read.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023, Oracle and/or its affiliates. + */ + +#ifndef SFRAME_READ_H +#define SFRAME_READ_H + +#include + +#include "sframe.h" + +struct sframe_sec; + +#define MAX_NUM_STACK_OFFSETS 3 + +#define MAX_STACK_OFFSET_NBYTES \ + ((SFRAME_FRE_OFFSET_4B * 2 * MAX_NUM_STACK_OFFSETS)) + +/* + * SFrame Frame Row Entry for the SFrame reader. + * Providing such an abstraction helps decouple stack tracer from the + * binary format representation of the same. + */ +struct sframe_fre { + uint32_t start_ip_offset; + unsigned char fre_offsets[MAX_STACK_OFFSET_NBYTES]; + unsigned char fre_info; +}; + +#define SFRAME_ERR ((int) -1) + +/* SFrame version not supported. */ +#define SFRAME_ERR_VERSION_INVAL (-2000) +/* Corrupt SFrame. */ +#define SFRAME_ERR_INVAL (-2001) +/* SFrame Section Initialization Error. */ +#define SFRAME_ERR_INIT_INVAL (-2002) +/* Corrupt FDE. */ +#define SFRAME_ERR_FDE_INVAL (-2003) +/* Corrupt FRE. */ +#define SFRAME_ERR_FRE_INVAL (-2004) +/* FDE not found. */ +#define SFRAME_ERR_FDE_NOTFOUND (-2005) +/* FDEs not sorted. */ +#define SFRAME_ERR_FDE_NOTSORTED (-2006) +/* FRE not found. */ +#define SFRAME_ERR_FRE_NOTFOUND (-2007) +/* FRE offset not present. */ +#define SFRAME_ERR_FREOFFSET_NOPRESENT (-2008) + +extern size_t sframe_sec_sizeof(void); + +extern int sframe_sec_init(struct sframe_sec *sfsec, const char *cf_buf, + size_t cf_size); + +extern int sframe_sec_find_fre(struct sframe_sec *ctx, int32_t pc, + struct sframe_fre *frep); + +extern unsigned int sframe_fre_get_base_reg_id(struct sframe_fre *fre, + int *errp); +extern int32_t sframe_fre_get_cfa_offset(struct sframe_sec *dtcx, + struct sframe_fre *fre, + int *errp); +extern int32_t sframe_fre_get_fp_offset(struct sframe_sec *sfsec, + struct sframe_fre *fre, + int *errp); +extern int32_t sframe_fre_get_ra_offset(struct sframe_sec *sfsec, + struct sframe_fre *fre, + int *errp); +extern bool sframe_fre_get_ra_mangled_p(struct sframe_sec *sfsec, + struct sframe_fre *fre, + int *errp); + +#endif /* SFRAME_READ_H */ -- 2.39.2