From patchwork Sun Oct 30 07:44:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Indu Bhagat X-Patchwork-Id: 12962 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1688234wru; Sun, 30 Oct 2022 00:55:22 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6r/k8s+yCph24pOiIrOjGilO1EdFiqph2puPSj1+stSejDsPUUSAxXS3MsLuwWYZl3HvIj X-Received: by 2002:a17:907:1b1f:b0:72f:56db:cce9 with SMTP id mp31-20020a1709071b1f00b0072f56dbcce9mr6844785ejc.605.1667116522596; Sun, 30 Oct 2022 00:55:22 -0700 (PDT) Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id r9-20020a1709063d6900b0078198611a45si3087772ejf.980.2022.10.30.00.55.22 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 30 Oct 2022 00:55:22 -0700 (PDT) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=U0X6bKGn; arc=fail (signature failed); spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C195E38582BB for ; Sun, 30 Oct 2022 07:51:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C195E38582BB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1667116294; bh=6yvQi14diKnHSYMx58VQ+44kA1omYq2sVyb0tNcXy9s=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=U0X6bKGngHvvrlcoYomhcXBHHJGBPoNgFs6VqWbyspMI5joHZEXVv64LUWQfnAtPS Gm0x3Hsbo79RqIoTg5jJOtGlC5LcGwA1YChQ8ZCPjida9LIz7rY4+dayylRw+W1leM lAlK8kSSFs463eh0qacBWNNk8VwGTy/rHY3TXZ6k= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mx0b-00069f02.pphosted.com (mx0b-00069f02.pphosted.com [205.220.177.32]) by sourceware.org (Postfix) with ESMTPS id B2D94385117E for ; Sun, 30 Oct 2022 07:45:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B2D94385117E Received: from pps.filterd (m0246632.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 29U3Zvaq011301 for ; Sun, 30 Oct 2022 07:45:47 GMT Received: from phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (phxpaimrmta03.appoci.oracle.com [138.1.37.129]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3kgusshc4p-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Sun, 30 Oct 2022 07:45:47 +0000 Received: from pps.filterd (phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com [127.0.0.1]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (8.17.1.5/8.17.1.5) with ESMTP id 29U6S3r3029354 for ; Sun, 30 Oct 2022 07:45:46 GMT Received: from nam12-dm6-obe.outbound.protection.outlook.com (mail-dm6nam12lp2172.outbound.protection.outlook.com [104.47.59.172]) by phxpaimrmta03.imrmtpd1.prodappphxaev1.oraclevcn.com (PPS) with ESMTPS id 3kgtm28s7y-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Sun, 30 Oct 2022 07:45:46 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=TXWpyhOXMW2W6/ptHmMloMdPajYxH5mUtRRLmik5eM8mX+0kSg8jcEwhnsTSRSXF+0407bL92H4/fREm703sCzLGWzjtC9ddYSQdGNibULcIP0Sf3lIfbOOfeYlVjggX/GY9ffgtVo2jnie4EYxJobgSGbC5L16pfBpRJjqd6T0gWtKgX3ZoOoEpVzScijAvgngx39SOVKQh53Ds2BKdGtTMaQwqPSqzGa3EQEA5mLfQ0xHwryZUcHhQXBuIC+wv5kumUHHO7pRrIT83p2AgZ1LxjahK9RVpIL5PwTvVNMJTBNemX9+aXXstvD6V8lP1h36vbfhLNKzcmSALzySLsw== 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=6yvQi14diKnHSYMx58VQ+44kA1omYq2sVyb0tNcXy9s=; b=D4nqpz/7UMSsDp+xTHuyRuIbo0GwmpKaEodTOfmGq7OQs92vNjqFGUiHQ/HrzzbVYB2gUJ0IDzon7c/Q2j1Mvuauuqe+S3e9aypO2Tfap/ggkZKjKCeLfYSkd3QecVKaN+3WU56l42TGtGaZMu8U1K/fyAD6fvVmBLYKp+1IuuIY2lLZzN83+QDvhxoSaLlCHD6qSCzko48p3Nx8wz/DMYoKHiDksF3YmAWNrM8GEUzh3Rg0jjGAgKYQcQYVTZOrirp4Xnfg6s9tgdnLX1ZfomTV7q3fpm+iWRY0wZOa0mtbxvN7S0KnT+F0TzBU54iI53on4wILPiKRTE77wIKMSw== 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 Received: from MWHPR1001MB2158.namprd10.prod.outlook.com (2603:10b6:301:2d::17) by BY5PR10MB4289.namprd10.prod.outlook.com (2603:10b6:a03:20c::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5769.19; Sun, 30 Oct 2022 07:45:43 +0000 Received: from MWHPR1001MB2158.namprd10.prod.outlook.com ([fe80::a505:15c2:a248:efa2]) by MWHPR1001MB2158.namprd10.prod.outlook.com ([fe80::a505:15c2:a248:efa2%7]) with mapi id 15.20.5723.033; Sun, 30 Oct 2022 07:45:43 +0000 To: binutils@sourceware.org Subject: [PATCH,V3 08/15] unwinder: generate backtrace using SFrame format Date: Sun, 30 Oct 2022 00:44:43 -0700 Message-Id: <20221030074450.1956074-9-indu.bhagat@oracle.com> X-Mailer: git-send-email 2.37.2 In-Reply-To: <20221030074450.1956074-1-indu.bhagat@oracle.com> References: <20221030074450.1956074-1-indu.bhagat@oracle.com> X-ClientProxiedBy: MW4PR03CA0097.namprd03.prod.outlook.com (2603:10b6:303:b7::12) To MWHPR1001MB2158.namprd10.prod.outlook.com (2603:10b6:301:2d::17) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: MWHPR1001MB2158:EE_|BY5PR10MB4289:EE_ X-MS-Office365-Filtering-Correlation-Id: 4985a191-de82-41a0-083e-08daba4abff0 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: /2Z6vZvKXxDhfL00iK0HJW83L3lhs1MieW7azYjD4Qo6Lg8aNAAMmx9Oy5XVxtHo0PpdIbR63ljYCYBQoivZtn8Ck1KhHZ0UmM358rithbtLEJB0UH00MeIWrIkeDwh5dfXtHN6qv/G0V+M4p51ue2jNWl2jP23cyUQxPPNKUteuhtZN6NUroelNl0ZHyZYaOCVk/2h5XA3X2peesNZR+CPwVFFp1eEyqx2Eqav7PfcT3PFPHyzDr/7KXPv/7gqEWPeLoGRLWTJcFIh/JfXTWQIJasmia90wHiEns7tS/kHkTbw75j25lW/B7q55aIwcXoBYG3e2kJB3d04j49X3CTy2Nc4ix3FpuZNkvs6cf5+uAhMnd84eqhJBnMkhZfaVkuBZCeBU0Mxmpb1of6HrMTJGFhqbTgNOFZc5V7HggObgUG12JCEk1ce7keIpV5jMkqF7e6syvIoZ3WySRGyv3A3oI5Z9A6jObdl+OuFPGOtk5xI21D2bapiye9R0sRZtkBJZbnjK9pDap7RlToiQGUyCeXNEos8BWcQ88cRwVUWsQctiznFBc6qrZRhjVrkzjjNgAEgGZcAdeq0Wgvfgl406CXB/qtwihdMSUPOn9zQ0bJfTxt8NgUJ3JHztj/MvPnRULtjZfSQbk0dgeS+Y2LkiMhEgi4PQFrOTxsz1lkHL5iqrNy1s9OmR/hqLUfkAgjC8fu+xEtuXtpX25JrHUbXbxiXtPwdHXtJ4mh5KW3HvxqAH8nouW5izHGLaMV9nvgDD0pCnAuv3SKVCqHMZRrPId6uUSpN6/AmSXcKTQEY= 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:(13230022)(396003)(366004)(39850400004)(376002)(346002)(136003)(451199015)(316002)(66556008)(4326008)(66476007)(36756003)(6916009)(66946007)(30864003)(6486002)(38100700002)(8936002)(41300700001)(86362001)(107886003)(478600001)(5660300002)(1076003)(186003)(83380400001)(8676002)(2616005)(44832011)(2906002)(6512007)(6506007)(2004002); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: BqVKQJ22vZdKfIoScB7xAJxkAuuPpnlUDTOJWDF1YghxXwyjkvE4QIJZeXBtLL0vrL0x7E5JUBYJXVXUVmvlKsZLYjZpvI9zM2bb+gtypNWEArBqaR3s/sBn7LztoeCRGwgx4KylvWpe99SYaU5VvvcRrqxP6TBMwTgEE+61lu0VXwek0JBGrlhua6EG5cBGAnTA7SQrCi7h4W17q9Lb7Azqx/orQtdiz5/BqSpVTuenWU8luDansSZnGdoMAedEFq9jxf0qvoageYsg99RiUd7oElNEAjR3WXJADS6r8y6+MzEXElVUKRh2Was+nJXUDiSJp7L9tv6n+TLDqVpvib8atvEG/2uqkQnl1iAq8ZUUmUhyDockMQ7f+yLkjeoRa1W+SfdHp1GkTg9sIUfNR8LfQ9xedKZ4PgZ9iBqjGRgS3JGFUniF0mya1JrrlvIq+ML0TeXaP9m/lXyykn4qdcfFnjcSgCrUfVKhOTx3PQfwUqhNaZ8C9XUVIlBzIiT7FvJ9V6G/wooXwjkJ0Z7GyKsGueu3KKCq8icnFBdo7RHf7IfEh6pdoVKJNmv+RtD5pi5mQCluRzJ+NGLIZiIii6cXrwk0CAWeCKKA+DijOxB4raeOcBdphaq8S3mhtZ08udWi4rzGFvnmaXV84tGOdHB5SEuGYlnvtCKicSwaRHAZzpnIV59d+9idFavAgvXPfucZMWc++jW8UlD4gKH2Cus/xxDm+J2F0lcAfmb3uez7QG0/1CDvXYFW9uz+Xe+RmIMhOk2GQFqegXXfLUEkJFG08UvpnYxbJkNUP0E8U0nVqoQXUiFLxm868hIaskTLMsIMtTcgMK2vjdMBQLbYgay4LEeO6pFa/mSIM290B/ljH2VZrr04QaPVyRCsDB6bZx9XZEFK8NwjHqPTsMZxncjIMR3mX1tVvTcdws4j07RW/3VncHhI6dgusGUUnZE7qFBPGe0GBv5s226nDmBcobt9Q9rayzewyYz51rthU6ru6GNhuDyN4SOgmKwZX5Sw3nYZVA1YZz+HqRVOz3uUPmo75yAamiifpktqq4KtepzF1BohEZqvRHg3rG/EkExhQ7Lat2Zdhpy+ne1RXK0hdXh5YxheszP8MyDPpDwamQEoZ77H7zwWmf1vmTz9wzy8VmxGWHJtlU2gvy8covroz+jaKBQnut6p3GJ3ZGOwIu4hQltGp1+qxgw9PBL48lEMiXDUjL/WOuJ0sYnBiV6VZlHQjNZatBxqpRyCLYQ7kJXyJOOrYRCTM/O0L+paXl31qY3Z8loLRh5Iqa9eCANmvWeAZix9u5NFsfp9NPjIPnIVajt35lfqsJOkIlqcCLn868ikpaxtmswPmH47camZHJLQUlsMCdQMh3mhyBdscjBh0yDxqfzPDUNORmSUwPz2KlFoyuEQOu+FVs9gVxPEuys5/sO+DW0wJg7GMRjsmnJ41kokL3G798PUlI2U6dHmq1GItJYVUruV4yVAGC94gYP3Mrx/UjQwz74ZFTucbI2kn5yTbui4p4MMmqpbcUwTRWyNZ2HrK3EPjXnFJPXcFm36tne1aePyj81832kQ+JG+HV3uHNfbT+FEjNj+/3szqBJj93trUVNzCKEDlshXcBrw7lGbUA3DGS/V1D+ATb8= X-OriginatorOrg: oracle.com X-MS-Exchange-CrossTenant-Network-Message-Id: 4985a191-de82-41a0-083e-08daba4abff0 X-MS-Exchange-CrossTenant-AuthSource: MWHPR1001MB2158.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2022 07:45:43.8746 (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: Lq9jawR1krIaDslbd1E6n4DnLx/blnhLsmEKIQZ97PGNd+WJ3EjNuzIsdWs+w95rvgpGlICM9AOoRE751IDC4A== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY5PR10MB4289 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.895,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2022-10-30_02,2022-10-27_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 spamscore=0 bulkscore=0 suspectscore=0 phishscore=0 malwarescore=0 mlxscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2210300049 X-Proofpoint-ORIG-GUID: Zl1eUpLBW8aaFtEDfzrZYaxPHq-EtGG5 X-Proofpoint-GUID: Zl1eUpLBW8aaFtEDfzrZYaxPHq-EtGG5 X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, 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: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Indu Bhagat via Binutils From: Indu Bhagat Reply-To: Indu Bhagat Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1748098375078754378?= X-GMAIL-MSGID: =?utf-8?q?1748098375078754378?= From: Weimin Pan [Changes in V3] - Use the updated APIs from libsframe. - Use sframe_decoder_get_fixed_ra_offset on AMD64 instead of magic number -8. [End of changes in V3] [Changes in V2] - Minor formatting fixes. [End of changes in V2] A simple unwinder based on SFrame format. The unwinder is made available via libsframebt library. Buildsystem changes have been made to build libsframebt only when --gsframe support is available in the assembler. These buildsystem changes are necessary because the SFrame based unwinder the SFrame unwind info for itself to work. PS: libsframe/configure has NOT been included in the patch. Please regenerate. config/ChangeLog: * sframe.m4: New file. include/ChangeLog: * sframe-backtrace-api.h: New file. ChangeLog: * libsframe/Makefile.am: Build backtrace functionality in its own library. Install libsframebt conditionally. * libsframe/Makefile.in: Regenerate. * libsframe/aclocal.m4: Regenerate. * libsframe/configure: Regenerate. <-- [REMOVED FROM THE PATCH. PLEASE REGENERATE. ] * libsframe/configure.ac: Check if gas supports --gsframe command line option. * libsframe/sframe-backtrace-err.c: New file. * libsframe/sframe-backtrace.c: New file. --- config/sframe.m4 | 16 + include/sframe-backtrace-api.h | 57 +++ libsframe/Makefile.am | 12 + libsframe/Makefile.in | 58 ++- libsframe/aclocal.m4 | 1 + libsframe/configure.ac | 7 + libsframe/sframe-backtrace-err.c | 46 +++ libsframe/sframe-backtrace.c | 626 +++++++++++++++++++++++++++++++ 8 files changed, 816 insertions(+), 7 deletions(-) create mode 100644 config/sframe.m4 create mode 100644 include/sframe-backtrace-api.h create mode 100644 libsframe/sframe-backtrace-err.c create mode 100644 libsframe/sframe-backtrace.c diff --git a/config/sframe.m4 b/config/sframe.m4 new file mode 100644 index 00000000000..9f149fda9ef --- /dev/null +++ b/config/sframe.m4 @@ -0,0 +1,16 @@ +# SFRAME_CHECK_AS_SFRAME +# ---------------------- +# Check whether the assembler supports generation of SFrame +# unwind information. +# +# Defines: +# ac_cv_have_sframe + +AC_DEFUN([SFRAME_CHECK_AS_SFRAME],[ + ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Wa,--gsframe" + AC_MSG_CHECKING([for as that supports --gsframe]) + AC_TRY_COMPILE([], [return 0;], [ac_cv_have_sframe=yes], [ac_cv_have_sframe=no]) + AC_MSG_RESULT($ac_cv_have_sframe) + CFLAGS="$ac_save_CFLAGS" +]) diff --git a/include/sframe-backtrace-api.h b/include/sframe-backtrace-api.h new file mode 100644 index 00000000000..ad8f6bed024 --- /dev/null +++ b/include/sframe-backtrace-api.h @@ -0,0 +1,57 @@ +/* Public API to SFrame backtrace. + + Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of libsframebt. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef _SFRAME_BACKTRACE_API_H +#define _SFRAME_BACKTRACE_API_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +enum sframe_bt_errcode +{ + SFRAME_BT_OK, + SFRAME_BT_ERR_NOTPRESENT, + SFRAME_BT_ERR_PHDR, + SFRAME_BT_ERR_ARG, + SFRAME_BT_ERR_MALLOC, + SFRAME_BT_ERR_REALLOC, + SFRAME_BT_ERR_OPEN, + SFRAME_BT_ERR_READLINK, + SFRAME_BT_ERR_LSEEK, + SFRAME_BT_ERR_READ, + SFRAME_BT_ERR_GETCONTEXT, + SFRAME_BT_ERR_DECODE, + SFRAME_BT_ERR_CFA_OFFSET, +}; + +/* Get the backtrace of the calling program by storing return addresses + in BUFFER. The SIZE argument specifies the maximum number of addresses + that can be stored in the buffer. Return the number of return addresses + collected or -1 if there is any error. */ +extern int sframe_backtrace (void **buffer, int size, int *errp); + +extern const char *sframe_bt_errmsg (enum sframe_bt_errcode ecode); + +#ifdef __cplusplus +} +#endif + +#endif /* _SFRAME_BACKTRACE_API_H */ diff --git a/libsframe/Makefile.am b/libsframe/Makefile.am index d8198a166c5..6b27ccdcdf6 100644 --- a/libsframe/Makefile.am +++ b/libsframe/Makefile.am @@ -36,4 +36,16 @@ endif libsframe_la_SOURCES = sframe.c sframe-dump.c sframe-error.c libsframe_la_CPPFLAGS = $(AM_CPPFLAGS) +if HAVE_SFRAME_AS + libsframebt_la_SOURCES = sframe-backtrace.c sframe-backtrace-err.c + libsframebt_la_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include + libsframebt_la_CFLAGS = -Wa,--gsframe +if INSTALL_LIBBFD + lib_LTLIBRARIES += libsframebt.la + include_HEADERS += $(INCDIR)/sframe-backtrace-api.h +else + noinst_LTLIBRARIES += libsframebt.la +endif +endif + include testsuite/local.mk diff --git a/libsframe/Makefile.in b/libsframe/Makefile.in index 340bfe88060..3d0b26000db 100644 --- a/libsframe/Makefile.in +++ b/libsframe/Makefile.in @@ -89,8 +89,11 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ +@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_1 = libsframebt.la +@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am__append_2 = $(INCDIR)/sframe-backtrace-api.h +@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am__append_3 = libsframebt.la check_PROGRAMS = $(am__EXEEXT_1) -@HAVE_COMPAT_DEJAGNU_TRUE@am__append_1 = testsuite/libsframe.decode/be-flipping \ +@HAVE_COMPAT_DEJAGNU_TRUE@am__append_4 = testsuite/libsframe.decode/be-flipping \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.decode/frecnt-1 \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.decode/frecnt-2 \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.encode/encode-1 @@ -103,6 +106,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \ $(top_srcdir)/../config/jobserver.m4 \ $(top_srcdir)/../config/lead-dot.m4 \ $(top_srcdir)/../config/override.m4 \ + $(top_srcdir)/../config/sframe.m4 \ $(top_srcdir)/../config/warnings.m4 \ $(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \ $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \ @@ -157,6 +161,20 @@ am__v_lt_0 = --silent am__v_lt_1 = @INSTALL_LIBBFD_FALSE@am_libsframe_la_rpath = @INSTALL_LIBBFD_TRUE@am_libsframe_la_rpath = -rpath $(libdir) +libsframebt_la_LIBADD = +am__libsframebt_la_SOURCES_DIST = sframe-backtrace.c \ + sframe-backtrace-err.c +@HAVE_SFRAME_AS_TRUE@am_libsframebt_la_OBJECTS = \ +@HAVE_SFRAME_AS_TRUE@ libsframebt_la-sframe-backtrace.lo \ +@HAVE_SFRAME_AS_TRUE@ libsframebt_la-sframe-backtrace-err.lo +libsframebt_la_OBJECTS = $(am_libsframebt_la_OBJECTS) +libsframebt_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libsframebt_la_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o \ + $@ +@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_FALSE@am_libsframebt_la_rpath = +@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@am_libsframebt_la_rpath = \ +@HAVE_SFRAME_AS_TRUE@@INSTALL_LIBBFD_TRUE@ -rpath $(libdir) @HAVE_COMPAT_DEJAGNU_TRUE@am__EXEEXT_1 = testsuite/libsframe.decode/be-flipping$(EXEEXT) \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.decode/frecnt-1$(EXEEXT) \ @HAVE_COMPAT_DEJAGNU_TRUE@ testsuite/libsframe.decode/frecnt-2$(EXEEXT) \ @@ -216,12 +234,13 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = -SOURCES = $(libsframe_la_SOURCES) \ +SOURCES = $(libsframe_la_SOURCES) $(libsframebt_la_SOURCES) \ $(testsuite_libsframe_decode_be_flipping_SOURCES) \ $(testsuite_libsframe_decode_frecnt_1_SOURCES) \ $(testsuite_libsframe_decode_frecnt_2_SOURCES) \ $(testsuite_libsframe_encode_encode_1_SOURCES) DIST_SOURCES = $(libsframe_la_SOURCES) \ + $(am__libsframebt_la_SOURCES_DIST) \ $(testsuite_libsframe_decode_be_flipping_SOURCES) \ $(testsuite_libsframe_decode_frecnt_1_SOURCES) \ $(testsuite_libsframe_decode_frecnt_2_SOURCES) \ @@ -231,7 +250,8 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac -am__include_HEADERS_DIST = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h +am__include_HEADERS_DIST = $(INCDIR)/sframe-backtrace-api.h \ + $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h HEADERS = $(include_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in @@ -423,12 +443,17 @@ INCDIR = $(srcdir)/../include # include libctf for swap.h AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../libctf AM_CFLAGS = @ac_libsframe_warn_cflags@ -@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libsframe.la -@INSTALL_LIBBFD_FALSE@include_HEADERS = -@INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/sframe.h $(INCDIR)/sframe-api.h -@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libsframe.la +@INSTALL_LIBBFD_TRUE@lib_LTLIBRARIES = libsframe.la $(am__append_1) +@INSTALL_LIBBFD_FALSE@include_HEADERS = $(am__append_2) +@INSTALL_LIBBFD_TRUE@include_HEADERS = $(INCDIR)/sframe.h \ +@INSTALL_LIBBFD_TRUE@ $(INCDIR)/sframe-api.h $(am__append_2) +@INSTALL_LIBBFD_FALSE@noinst_LTLIBRARIES = libsframe.la \ +@INSTALL_LIBBFD_FALSE@ $(am__append_3) libsframe_la_SOURCES = sframe.c sframe-dump.c sframe-error.c libsframe_la_CPPFLAGS = $(AM_CPPFLAGS) +@HAVE_SFRAME_AS_TRUE@libsframebt_la_SOURCES = sframe-backtrace.c sframe-backtrace-err.c +@HAVE_SFRAME_AS_TRUE@libsframebt_la_CPPFLAGS = -I$(srcdir) -I$(srcdir)/../include +@HAVE_SFRAME_AS_TRUE@libsframebt_la_CFLAGS = -Wa,--gsframe # Setup the testing framework EXPECT = expect @@ -550,6 +575,9 @@ clean-noinstLTLIBRARIES: libsframe.la: $(libsframe_la_OBJECTS) $(libsframe_la_DEPENDENCIES) $(EXTRA_libsframe_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(am_libsframe_la_rpath) $(libsframe_la_OBJECTS) $(libsframe_la_LIBADD) $(LIBS) +libsframebt.la: $(libsframebt_la_OBJECTS) $(libsframebt_la_DEPENDENCIES) $(EXTRA_libsframebt_la_DEPENDENCIES) + $(AM_V_CCLD)$(libsframebt_la_LINK) $(am_libsframebt_la_rpath) $(libsframebt_la_OBJECTS) $(libsframebt_la_LIBADD) $(LIBS) + clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ @@ -610,6 +638,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-dump.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe-error.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframe_la-sframe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframebt_la-sframe-backtrace-err.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsframebt_la-sframe-backtrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.decode/$(DEPDIR)/testsuite_libsframe_decode_be_flipping-be-flipping.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.decode/$(DEPDIR)/testsuite_libsframe_decode_frecnt_1-frecnt-1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@testsuite/libsframe.decode/$(DEPDIR)/testsuite_libsframe_decode_frecnt_2-frecnt-2.Po@am__quote@ @@ -660,6 +690,20 @@ libsframe_la-sframe-error.lo: sframe-error.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframe_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsframe_la-sframe-error.lo `test -f 'sframe-error.c' || echo '$(srcdir)/'`sframe-error.c +libsframebt_la-sframe-backtrace.lo: sframe-backtrace.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -MT libsframebt_la-sframe-backtrace.lo -MD -MP -MF $(DEPDIR)/libsframebt_la-sframe-backtrace.Tpo -c -o libsframebt_la-sframe-backtrace.lo `test -f 'sframe-backtrace.c' || echo '$(srcdir)/'`sframe-backtrace.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsframebt_la-sframe-backtrace.Tpo $(DEPDIR)/libsframebt_la-sframe-backtrace.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sframe-backtrace.c' object='libsframebt_la-sframe-backtrace.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -c -o libsframebt_la-sframe-backtrace.lo `test -f 'sframe-backtrace.c' || echo '$(srcdir)/'`sframe-backtrace.c + +libsframebt_la-sframe-backtrace-err.lo: sframe-backtrace-err.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -MT libsframebt_la-sframe-backtrace-err.lo -MD -MP -MF $(DEPDIR)/libsframebt_la-sframe-backtrace-err.Tpo -c -o libsframebt_la-sframe-backtrace-err.lo `test -f 'sframe-backtrace-err.c' || echo '$(srcdir)/'`sframe-backtrace-err.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsframebt_la-sframe-backtrace-err.Tpo $(DEPDIR)/libsframebt_la-sframe-backtrace-err.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sframe-backtrace-err.c' object='libsframebt_la-sframe-backtrace-err.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsframebt_la_CPPFLAGS) $(CPPFLAGS) $(libsframebt_la_CFLAGS) $(CFLAGS) -c -o libsframebt_la-sframe-backtrace-err.lo `test -f 'sframe-backtrace-err.c' || echo '$(srcdir)/'`sframe-backtrace-err.c + testsuite/libsframe.decode/testsuite_libsframe_decode_be_flipping-be-flipping.o: testsuite/libsframe.decode/be-flipping.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testsuite_libsframe_decode_be_flipping_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT testsuite/libsframe.decode/testsuite_libsframe_decode_be_flipping-be-flipping.o -MD -MP -MF testsuite/libsframe.decode/$(DEPDIR)/testsuite_libsframe_decode_be_flipping-be-flipping.Tpo -c -o testsuite/libsframe.decode/testsuite_libsframe_decode_be_flipping-be-flipping.o `test -f 'testsuite/libsframe.decode/be-flipping.c' || echo '$(srcdir)/'`testsuite/libsframe.decode/be-flipping.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) testsuite/libsframe.decode/$(DEPDIR)/testsuite_libsframe_decode_be_flipping-be-flipping.Tpo testsuite/libsframe.decode/$(DEPDIR)/testsuite_libsframe_decode_be_flipping-be-flipping.Po diff --git a/libsframe/aclocal.m4 b/libsframe/aclocal.m4 index b0cdd6b184d..1bceeeab5a3 100644 --- a/libsframe/aclocal.m4 +++ b/libsframe/aclocal.m4 @@ -1234,6 +1234,7 @@ m4_include([../config/depstand.m4]) m4_include([../config/jobserver.m4]) m4_include([../config/lead-dot.m4]) m4_include([../config/override.m4]) +m4_include([../config/sframe.m4]) m4_include([../config/warnings.m4]) m4_include([../libtool.m4]) m4_include([../ltoptions.m4]) diff --git a/libsframe/configure.ac b/libsframe/configure.ac index a6c1d26bbbb..2775fe88b68 100644 --- a/libsframe/configure.ac +++ b/libsframe/configure.ac @@ -59,6 +59,13 @@ AM_CONDITIONAL([HAVE_COMPAT_DEJAGNU], [test "x$ac_cv_dejagnu_compat" = "xyes"]) COMPAT_DEJAGNU=$ac_cv_dejagnu_compat AC_SUBST(COMPAT_DEJAGNU) +dnl The libsframebt library needs to be built with SFrame info. +dnl If the build assembler is not capable of generate SFrame then +dnl the library is not built. + +SFRAME_CHECK_AS_SFRAME +AM_CONDITIONAL([HAVE_SFRAME_AS], [test "x$ac_cv_have_sframe" = "xyes"]) + AM_MAINTAINER_MODE AM_INSTALL_LIBBFD diff --git a/libsframe/sframe-backtrace-err.c b/libsframe/sframe-backtrace-err.c new file mode 100644 index 00000000000..70bd55ccf35 --- /dev/null +++ b/libsframe/sframe-backtrace-err.c @@ -0,0 +1,46 @@ +/* sframe-backtrace-err.c - SFrame Backtrace Error table. + + Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of libsframebt. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "config.h" +#include "sframe-backtrace-api.h" + +/* SFrame backtrace error messages. */ +static const char *const sframe_bt_errlist[] = +{ + "", + "File does not contain SFrame data", + "Iterating shared object reading error", + "Failed to malloc memory space", + "Failed to realloc memory space", + "Failed to open file", + "Failed on resolve canonical file name", + "Failed to reposition file offset", + "Failed to read from a file descriptor", + "Failed to get the user context", + "Failed to set up decode data", + "Illegal CFA offset" +}; + +/* Return the error message associated with the error code. */ + +const char * +sframe_bt_errmsg (enum sframe_bt_errcode ecode) +{ + return sframe_bt_errlist[ecode]; +} diff --git a/libsframe/sframe-backtrace.c b/libsframe/sframe-backtrace.c new file mode 100644 index 00000000000..877bbccfba7 --- /dev/null +++ b/libsframe/sframe-backtrace.c @@ -0,0 +1,626 @@ +/* sframe-backtrace.c - The SFrame backtracer. + + Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of libsframebt. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ansidecl.h" +#include "sframe-api.h" +#include "sframe-backtrace-api.h" + +#ifndef PT_SFRAME +#define PT_SFRAME 0x6474e554 /* FIXME. */ +#endif + +#define _sf_printflike_(string_index,first_to_check) \ + __attribute__ ((__format__ (__printf__, (string_index), (first_to_check)))) + +static int _sframe_unwind_debug; /* Control for printing out debug info. */ +static int no_of_entries = 32; + +/* SFrame decode data for the main module or a DSO. */ +struct sframe_decode_data +{ + char *sfdd_data; /* SFrame decode data. */ + int sfdd_data_size; /* SFrame decode data size. */ + uint64_t sfdd_text_vma; /* Text segment's virtual address. */ + int sfdd_text_size; /* Text segment's size. */ + uint64_t sfdd_sframe_vma; /* SFrame segment's virtual address. */ + sframe_decoder_ctx *sfdd_sframe_ctx; /* SFrame decoder context. */ +}; + +/* List that holds SFrame info for the shared libraries. */ +struct dso_cfi_list +{ + int alloced; /* Entries allocated. */ + int used; /* Entries used. */ + struct sframe_decode_data *entry; /* DSO's decode data. */ +}; + +/* Data that's passed through sframe_callback. */ +struct sframe_unwind_info +{ + int sui_fd; /* File descriptor. */ + struct sframe_decode_data sui_ctx; /* The decode data. */ + struct dso_cfi_list sui_dsos; /* The DSO list. */ +}; + +static void +sframe_unwind_init_debug (void) +{ + static int inited; + + if (!inited) + { + _sframe_unwind_debug = getenv ("SFRAME_UNWIND_DEBUG") != NULL; + inited = 1; + } +} + +_sf_printflike_ (1, 2) +static void +debug_printf (const char *format, ...) +{ + if (_sframe_unwind_debug) + { + va_list args; + + va_start (args, format); + __builtin_vprintf (format, args); + va_end (args); + } +} + +/* sframe_bt_errno - Check if there is error code in ERRP. */ + +static int +sframe_bt_errno (int *errp) +{ + if (errp == NULL) + return 0; + + return (*errp != SFRAME_BT_OK); +} + +/* sframe_bt_set_errno - Store the specified error code ERROR into ERRP if + it is non-NULL. */ + +static void +sframe_bt_set_errno (int *errp, int error) +{ + if (errp != NULL) + *errp = error; +} + +/* sframe_add_dso - Add .sframe info in D_DATA, which is associated with + a dynamic shared object, to D_LIST. */ + +static void +sframe_add_dso (struct dso_cfi_list *d_list, + struct sframe_decode_data d_data, + int *errp) +{ + if (d_list->alloced == 0) + { + d_list->entry = malloc (no_of_entries * sizeof (struct sframe_decode_data)); + if (d_list->entry == NULL) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_MALLOC); + return; + } + memset (d_list->entry, 0, + no_of_entries * sizeof (struct sframe_decode_data)); + d_list->alloced = no_of_entries; + } + else if (d_list->used == d_list->alloced) + { + d_list->entry = realloc (d_list->entry, + ((d_list->alloced + no_of_entries) + * sizeof (struct sframe_decode_data))); + if (d_list->entry == NULL) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_REALLOC); + return; + } + + memset (&d_list->entry[d_list->alloced], 0, + no_of_entries * sizeof (struct sframe_decode_data)); + d_list->alloced += no_of_entries; + } + + sframe_bt_set_errno (errp, SFRAME_BT_OK); + d_list->entry[d_list->used++] = d_data; +} + +/* sframe_free_cfi - Free up space allocated for .sframe info for CF. */ + +static void +sframe_free_cfi (struct sframe_unwind_info *sf) +{ + struct dso_cfi_list *d_list; + int i; + + if (sf == NULL) + return; + + free (sf->sui_ctx.sfdd_data); + sframe_decoder_free (&sf->sui_ctx.sfdd_sframe_ctx); + close (sf->sui_fd); + + d_list = &sf-> sui_dsos; + if (d_list == NULL) + return; + + for (i = 0; i < d_list->used; ++i) + { + free (d_list->entry[i].sfdd_data); + sframe_decoder_free (&d_list->entry[i].sfdd_sframe_ctx); + } + + free (d_list->entry); +} + +/* sframe_find_context - Find the decode data that contains ADDR from CF. + Return the pointer to the decode data or NULL. */ + +static struct sframe_decode_data * +sframe_find_context (struct sframe_unwind_info *sf, uint64_t addr) +{ + struct dso_cfi_list *d_list; + struct sframe_decode_data sdec_data; + int i; + + if (sf == NULL) + return NULL; + + if (sf->sui_ctx.sfdd_text_vma < addr + && sf->sui_ctx.sfdd_text_vma + sf->sui_ctx.sfdd_text_size > addr) + return &sf->sui_ctx; + + d_list = &sf->sui_dsos; + for (i = 0; i < sf->sui_dsos.used; ++i) + { + sdec_data = d_list->entry[i]; + if ((sdec_data.sfdd_text_vma <= addr) + && (sdec_data.sfdd_text_vma + sdec_data.sfdd_text_size >= addr)) + return &d_list->entry[i]; + } + + return NULL; +} + +/* sframe_valid_addr - Check if ADDR is valid in CF. The address is considered + invalid, with regards to SFrame, if it's not in any address range of the + main module or any of its DSO's. Return 1 if valid, 0 otherwise. */ + +static int +sframe_valid_addr (struct sframe_unwind_info *sf, uint64_t addr) +{ + struct sframe_decode_data *cdp; + + if (sf == NULL) + return 0; + + cdp = sframe_find_context (sf, addr); + return cdp ? 1 : 0; +} + +/* sframe_load_ctx - Call decoder to create and set up the SFrame info for + either the main module or one of the DSOs from CF, based on the input + RADDR argument. Return the newly created decode context or NULL. */ + +static sframe_decoder_ctx * +sframe_load_ctx (struct sframe_unwind_info *sf, uint64_t raddr) +{ + sframe_decoder_ctx *nctx; + struct sframe_decode_data *cdp; + + if (sf == NULL) + return NULL; + + cdp = sframe_find_context (sf, raddr); + if (cdp == NULL) + return NULL; + + if (cdp->sfdd_sframe_ctx == NULL) + { + int err; + nctx = sframe_decode (cdp->sfdd_data, cdp->sfdd_data_size, &err); + if (nctx == NULL) + return NULL; + cdp->sfdd_sframe_ctx = nctx; + return nctx; + } + + return NULL; +} + +/* sframe_update_ctx - Check if need to do a decode context switch, based on + the input RADDR argument, from CF. A new decode context will be created + and set up if it isn't already done so. Return the new decode context in + CTX and vma in CFI_VMA. */ + +static void +sframe_update_ctx (struct sframe_unwind_info *sf, uint64_t raddr, + sframe_decoder_ctx **ctx, uint64_t *cfi_vma) +{ + sframe_decoder_ctx *nctx; + struct sframe_decode_data *cdp; + + cdp = sframe_find_context (sf, raddr); + if (cdp != NULL) + { + if (cdp->sfdd_sframe_ctx == NULL) + { + int err; + nctx = sframe_decode (cdp->sfdd_data, cdp->sfdd_data_size, &err); + if (nctx == NULL) + { + *ctx = NULL; + return; + } + cdp->sfdd_sframe_ctx = nctx; + } + *ctx = cdp->sfdd_sframe_ctx; + *cfi_vma = cdp->sfdd_sframe_vma; + } +} + +/* get_contents - Return contents at ADDR from file descriptor FD. */ + +static uint64_t +get_contents (int fd, uint64_t addr, int *errp) +{ + uint64_t data; + size_t sz; + + sframe_bt_set_errno (errp, SFRAME_BT_OK); + if (lseek (fd, addr, SEEK_SET) == -1) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_LSEEK); + return 0; + } + sz = read (fd, &data, sizeof (uint64_t)); + if (sz != sizeof (uint64_t)) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_READ); + return 0; + } + + return data; +} + +/* sframe_fd_open - Open /proc image associated with the process id and return + the file descriptor. */ + +static int +sframe_fd_open (int *errp) +{ + char filename[PATH_MAX]; + pid_t pid; + int fd; + + pid = getpid (); + snprintf (filename, sizeof filename, "/proc/%d/task/%d/mem", pid, pid); + if ((fd = open (filename, O_RDONLY)) == -1) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_OPEN); + return -1; + } + + return fd; +} + +/* sframe_callback - The callback from dl_iterate_phdr with header info + in INFO. + Return SFrame info for either the main module or a DSO in DATA. */ + +static int +sframe_callback (struct dl_phdr_info *info, + size_t size ATTRIBUTE_UNUSED, + void *data) +{ + struct sframe_unwind_info *sf = (struct sframe_unwind_info *) data; + int p_type, i, fd, sframe_err; + ssize_t len; + uint64_t text_vma = 0; + int text_size = 0; + + if (data == NULL || info == NULL) + return 1; + + debug_printf ("-- name: %s %14p\n", info->dlpi_name, (void *)info->dlpi_addr); + + for (i = 0; i < info->dlpi_phnum; i++) + { + debug_printf(" %2d: [%14p; memsz:%7lx] flags: 0x%x; \n", i, + (void *) info->dlpi_phdr[i].p_vaddr, + info->dlpi_phdr[i].p_memsz, + info->dlpi_phdr[i].p_flags); + + p_type = info->dlpi_phdr[i].p_type; + if (p_type == PT_LOAD && info->dlpi_phdr[i].p_flags & PF_X) + { + text_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; + text_size = info->dlpi_phdr[i].p_memsz; + continue; + } + if (p_type != PT_SFRAME) + continue; + + if (info->dlpi_name[0] == '\0') /* the main module. */ + { + fd = sframe_fd_open (&sframe_err); + if (fd == -1) + return 1; + if (lseek (fd, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, + SEEK_SET) == -1) + { + sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_LSEEK); + return 1; + } + + sf->sui_ctx.sfdd_data = (char *) malloc (info->dlpi_phdr[i].p_memsz); + if (sf->sui_ctx.sfdd_data == NULL) + { + sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_MALLOC); + return 1; + } + + len = read (fd, sf->sui_ctx.sfdd_data, info->dlpi_phdr[i].p_memsz); + if (len == -1 || len != (ssize_t) info->dlpi_phdr[i].p_memsz) + { + sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_READ); + return 1; + } + + assert (text_vma); + sf->sui_ctx.sfdd_data_size = len; + sf->sui_ctx.sfdd_sframe_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; + sf->sui_fd = fd; + sf->sui_ctx.sfdd_text_vma = text_vma; + sf->sui_ctx.sfdd_text_size = text_size; + text_vma = 0; + return 0; + } + else + { /* a dynamic shared object. */ + struct sframe_decode_data dt; + memset (&dt, 0, sizeof (struct sframe_decode_data)); + assert (sf->sui_fd); + if (lseek (sf->sui_fd, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, + SEEK_SET) == -1) + { + sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_LSEEK); + return 1; + } + + dt.sfdd_data = (char *) malloc (info->dlpi_phdr[i].p_memsz); + if (dt.sfdd_data == NULL) + { + sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_MALLOC); + return 1; + } + + len = read (sf->sui_fd, dt.sfdd_data, info->dlpi_phdr[i].p_memsz); + if (len == -1 || len != (ssize_t) info->dlpi_phdr[i].p_memsz) + { + sframe_bt_set_errno (&sframe_err, SFRAME_BT_ERR_READ); + return 1; + } + + assert (text_vma); + dt.sfdd_data_size = len; + dt.sfdd_sframe_vma = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; + dt.sfdd_text_vma = text_vma; + dt.sfdd_text_size = text_size; + text_vma = 0; + sframe_add_dso (&sf->sui_dsos, dt, &sframe_err); + if (sframe_err != SFRAME_BT_OK) + return 1; + return 0; + } + } + + return 0; +} + +/* sframe_unwind - Unwind the stack backtrace for CF. If successful, + store the return addresses in RA_LST. The RA_SIZE argument specifies + the maximum number of return addresses that can be stored in RA_LST + and contains the number of the addresses collected. */ + +static void +sframe_unwind (struct sframe_unwind_info *sf, void **ra_lst, + int *ra_size, int *errp) +{ + uint64_t cfa, return_addr, ra_stack_loc, rfp_stack_loc; + int8_t fixed_ra_offset; + sframe_decoder_ctx *ctx; + int cfa_offset, rfp_offset, errnum, i, count; + sframe_frame_row_entry fred, *frep = &fred; + uint64_t pc, rfp, rsp, cfi_vma; + ucontext_t context, *cp = &context; + + if (sf == NULL || ra_lst == NULL || ra_size == NULL) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_ARG); + return; + } + + /* Get the user context for its registers. */ + if (getcontext (cp) != 0) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_GETCONTEXT); + return; + } + sframe_bt_set_errno (errp, SFRAME_BT_OK); + +#ifdef __x86_64__ + pc = cp->uc_mcontext.gregs[REG_RIP]; + rsp = cp->uc_mcontext.gregs[REG_RSP]; + rfp = cp->uc_mcontext.gregs[REG_RBP]; +#else +#ifdef __aarch64__ +#define UNWIND_AARCH64_X29 29 /* 64-bit frame pointer. */ +#define UNWIND_AARCH64_X30 30 /* 64-bit link pointer. */ + pc = cp->uc_mcontext.pc; + rsp = cp->uc_mcontext.sp; + rfp = cp->uc_mcontext.regs[UNWIND_AARCH64_X29]; + uint64_t ra = cp->uc_mcontext.regs[UNWIND_AARCH64_X30]; +#endif +#endif + + /* Load and set up the decoder. */ + ctx = sframe_load_ctx (sf, pc); + if (ctx == NULL) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_DECODE); + return; + } + cfi_vma = sf->sui_ctx.sfdd_sframe_vma; + count = *ra_size; + + for (i = 0; i < count; ++i) + { + pc -= cfi_vma; + errnum = sframe_find_fre (ctx, pc, frep); + if (errnum == 0) + { + cfa_offset = sframe_fre_get_cfa_offset (ctx, frep, &errnum); + if (errnum == ESFRAME_FREOFFSET_NOPRESENT) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_CFA_OFFSET); + return; + } + + cfa = ((frep->fre_info & 0x1) == SFRAME_BASE_REG_SP + ? rsp : rfp) + cfa_offset; + +#ifdef __x86_64__ + /* For x86, read the return address from the fixed RA offset from + the SFrame header. RA must be at location CFA - 8. */ + fixed_ra_offset = sframe_decoder_get_fixed_ra_offset (ctx); + if (fixed_ra_offset == SFRAME_CFA_FIXED_RA_INVALID) + return; + + ra_stack_loc = cfa + fixed_ra_offset; + return_addr = get_contents (sf->sui_fd, ra_stack_loc, errp); + if (sframe_bt_errno (errp)) + return; +#else +#ifdef __aarch64__ + int ra_offset = sframe_fre_get_ra_offset (ctx, frep, &errnum); + if (errnum == 0) + { + ra_stack_loc = cfa + ra_offset; + return_addr = get_contents (sf->sui_fd, ra_stack_loc, errp); + if (sframe_bt_errno (errp)) + return; + } + else + return_addr = ra; +#endif +#endif + + /* Validate and add return address to the list. */ + if (sframe_valid_addr (sf, return_addr) == 0) + { + i -= 1; + goto find_fre_ra_err; + } + if (i != 0) /* exclude self. */ + ra_lst[i-1] = (void *)return_addr; + + /* Set up for the next frame. */ + rfp_offset = sframe_fre_get_fp_offset (ctx, frep, &errnum); + if (errnum == 0) + { + rfp_stack_loc = cfa + rfp_offset; + rfp = get_contents (sf->sui_fd, rfp_stack_loc, errp); + if (sframe_bt_errno (errp)) + return; + } + rsp = cfa; + pc = return_addr; + + /* Check if need to update the decoder context and vma. */ + sframe_update_ctx (sf, return_addr, &ctx, &cfi_vma); + if (ctx == NULL) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_DECODE); + return; + } + } + else + { + i -= 1; + goto find_fre_ra_err; + } + } + +find_fre_ra_err: + *ra_size = i; +} + +/* sframe_backtrace - Main API that user program calls to get a backtrace. + The BUFFER argument provides space for the list of the return addresses + and the SIZE argument specifies the maximum number of addresses that + can be stored in the buffer. Return the number of return addresses + collected or -1 if there is any error. */ + +int +sframe_backtrace (void **buffer, int size, int *errp) +{ + struct sframe_unwind_info sframeinfo; + + sframe_unwind_init_debug (); + + memset (&sframeinfo, 0, sizeof (struct sframe_unwind_info)); + + /* find and set up the .sframe sections. */ + (void) dl_iterate_phdr (sframe_callback, (void *)&sframeinfo); + if (sframeinfo.sui_fd == 0) + { + sframe_bt_set_errno (errp, SFRAME_BT_ERR_NOTPRESENT); + return -1; + } + + /* Do the stack unwinding. */ + sframe_unwind (&sframeinfo, buffer, &size, errp); + if (sframe_bt_errno (errp)) + return -1; + + sframe_free_cfi (&sframeinfo); + + return size; +}