From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR03-AM7-obe.outbound.protection.outlook.com (mail-am7eur03on2042.outbound.protection.outlook.com [40.107.105.42]) by sourceware.org (Postfix) with ESMTPS id DF8373858D3C for ; Fri, 24 Nov 2023 12:26:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DF8373858D3C Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=arm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DF8373858D3C Authentication-Results: server2.sourceware.org; arc=pass smtp.remote-ip=40.107.105.42 ARC-Seal: i=3; a=rsa-sha256; d=sourceware.org; s=key; t=1700828817; cv=pass; b=r5/6f3z1/SNLB8eBf+izv748GSSU+40hIAnsKfS7CLY0xsnh5uzFgj0UoAhc8zZGUwcT6Jll6hKgNbaAMPSeScwuGNd+PLf8QAohVxP5I3gHRnt81bhAmPD8mL9eZUDsAjdAAG05X65kwe8J3WOx9tzBh4cMKQPAtV56uVqXMcg= ARC-Message-Signature: i=3; a=rsa-sha256; d=sourceware.org; s=key; t=1700828817; c=relaxed/simple; bh=KO/dzynRv1sDSbtMGIZKa8SeuYgyas2eDpLLYDxVyC0=; h=DKIM-Signature:DKIM-Signature:Message-ID:Date:Subject:To:From: MIME-Version; b=RhTFA5OjgD7MjbMoDbTZzMzvo6A4ho3zMpD9w4z12YPw7tmCylNNQrIpWs0iQb1qtnnoumoRrfeI37tri2X37hYM4KhY0SieokC5E5r9OfQZJiRC8xhduU1ROBbtu1liyP+LO3ot7w4L2Rb+FgJi1YekFFi22SR1PVsoQPiyIMY= ARC-Authentication-Results: i=3; server2.sourceware.org ARC-Seal: i=2; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=pass; b=kK8OeJr7F4fbjlS6+f/8KWA2CIzxjXA9qRzN9BHl4DshCJUyXdfll9Mlff3T+VuNj3Wrd/NOXfaP3R2cWTrx1fiOnTkt9SA6ATNyWXkx+1bFOZvyPgmWv9ZbOX5rD8JythlER4RNdi5J0qs5c6NaRwcO36O1Q61btUDVDdggt+eWN8aylexxkxM0BNzIqQ7ATUq4zJygg9Em9j5u7MBEmLE6gE5L/+NfkP+PhBtIyfj/PJNNxIZaTzOtpzu8rfQJ/g4CrmvGbGM1MLr0HtNOrbjXam4Z4VavLEtsuGsrBjR5TFNu/GOUvaByEECHHoSIF1G+VBH6j6QgSmu6waHHfA== ARC-Message-Signature: i=2; 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=wR9rXVBX5mA2JHyQ2TuqophpQKef7qyeJ1ljFdcU6WA=; b=GWV9HXbHyppZbvao3v1/ymn6wo/6qNk2O5gay457Qfot2V/PUmSpfL3TmWzMtQ+5BMiwJghQFsymjiSQN2Piop+5y9JKvdUNxQY6lh1EvH3LcXOoHbyK8c0qlAKUqTJgOtoMel4clld+tTTILSJQSkehujsnX5bGLXfNf8DTTo8cKfB3XL9PSaU3OIa8mPf7tcaJUI4qqOPY/QvmGQ2VyoE+9+EyvgFzphBA5PzSbw+rvw9zpSg07Cf+RnOVBc+MuDVFYRCq9uSyViTmmXj4L41WgKau/YXTBay+NQd1NfFtXamUJA8yo8RuviiuHCivX/TBmkuMALGiMPkOkzVXFw== ARC-Authentication-Results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 63.35.35.123) smtp.rcpttodomain=sourceware.org smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com]) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=wR9rXVBX5mA2JHyQ2TuqophpQKef7qyeJ1ljFdcU6WA=; b=OQpOu0/IMmSsTJaX5B7h0fsztEVRicRnLIz4p9ceY/bUJxiHh8KZHI7AmlwBcm3uOeILXr0b/BhTzsQgB5Bwr4+1H1Pxw9IiiSzXt5XJFspuFqhqtIeHqxCLeBPhoNCDstBliQp6MzPw6ddWHtp3kvpbxaPe7Hszb/rIWZd0xVk= Received: from AS4P195CA0003.EURP195.PROD.OUTLOOK.COM (2603:10a6:20b:5e2::9) by AS2PR08MB9643.eurprd08.prod.outlook.com (2603:10a6:20b:608::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7025.21; Fri, 24 Nov 2023 12:26:47 +0000 Received: from AMS0EPF00000194.eurprd05.prod.outlook.com (2603:10a6:20b:5e2:cafe::4b) by AS4P195CA0003.outlook.office365.com (2603:10a6:20b:5e2::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7025.21 via Frontend Transport; Fri, 24 Nov 2023 12:26:47 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; pr=C Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by AMS0EPF00000194.mail.protection.outlook.com (10.167.16.214) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7025.13 via Frontend Transport; Fri, 24 Nov 2023 12:26:47 +0000 Received: ("Tessian outbound 7671e7ddc218:v228"); Fri, 24 Nov 2023 12:26:46 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: d09367a9b566cbba X-CR-MTA-TID: 64aa7808 Received: from 7bdabf9cca0d.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id 2ABE39C2-D7F4-48A6-BFA2-1960CF1488AA.1; Fri, 24 Nov 2023 12:26:39 +0000 Received: from EUR03-DBA-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 7bdabf9cca0d.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Fri, 24 Nov 2023 12:26:39 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=ID/UUWTUdUa/nPIWIWcBHO5at/uQt/AhOeXBCQBrIcifJvGrFuWu3cumMt9WW7LXqoaBhodc5tUn1Mrh4BBRpcOiWpLxb7m2WDF7pWivaPUr7gbapl59jOdq4Nvde0m4Kxc2rK0l8ZRynZZK4/krDuIT6nW5mE6J0g74icgS5ckgrg59MK/Cq0CWfOfI80MMLIza/vJmML9ia7mGVGt2jet6ln2bqfbnJXpxKWWXZs7z82LiBhA7hE1wmoD3wLEpfRtVJyMKzoXbkx461E6Xwq2GTAM1c4NQAb4ut9JlqKL+MmM7TOmlTy2g4EMoOKKrIIUIBvJ1evhIv5NPH/+cvQ== 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=wR9rXVBX5mA2JHyQ2TuqophpQKef7qyeJ1ljFdcU6WA=; b=ntVl5T9OFcImtM5r82LhO1/6EC2X/szsHD4j+e7xKKrwTQXiNgBH2uZkgu92EuwwpS8fI37jf1wY8XJsYl62FnrcSddSNIyeswXfTry7INBPDKPgV55Rlbop9J1X93Ldc+NeR7eUGQkyB9SjEaLx6nNEW4c9b/Jf/xd0u9IWtXqJYoyqBJKUicO+UDUbXylHyMyUYWPU0rBvNcdjBraoYO7OVditADgtc/b89jjTiVdz/kd0mH2W/8vnBzS2HggYEKlwZTtRzXiSXZrAHFSOHUVNsTs+PNH1NIln7aCvjtN9vPjmATOIyBCYgno4aiAradyqSJ9NtK0YUsGBqocS9Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector2-armh-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=wR9rXVBX5mA2JHyQ2TuqophpQKef7qyeJ1ljFdcU6WA=; b=OQpOu0/IMmSsTJaX5B7h0fsztEVRicRnLIz4p9ceY/bUJxiHh8KZHI7AmlwBcm3uOeILXr0b/BhTzsQgB5Bwr4+1H1Pxw9IiiSzXt5XJFspuFqhqtIeHqxCLeBPhoNCDstBliQp6MzPw6ddWHtp3kvpbxaPe7Hszb/rIWZd0xVk= Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Received: from VI1PR08MB3919.eurprd08.prod.outlook.com (2603:10a6:803:c4::31) by GVXPR08MB7680.eurprd08.prod.outlook.com (2603:10a6:150:6e::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7025.20; Fri, 24 Nov 2023 12:26:36 +0000 Received: from VI1PR08MB3919.eurprd08.prod.outlook.com ([fe80::e05e:c012:f1f9:eb51]) by VI1PR08MB3919.eurprd08.prod.outlook.com ([fe80::e05e:c012:f1f9:eb51%4]) with mapi id 15.20.7025.021; Fri, 24 Nov 2023 12:26:36 +0000 Message-ID: <7c764242-f056-47ee-b059-e4cee2f76207@arm.com> Date: Fri, 24 Nov 2023 12:26:31 +0000 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v3] gdb/testsuite: add test for backtracing for threaded inferiors from a corefile Content-Language: en-US To: Guinevere Larsen , gdb-patches@sourceware.org Cc: Andrew Burgess References: <20231025114253.259603-2-blarsen@redhat.com> From: Luis Machado In-Reply-To: <20231025114253.259603-2-blarsen@redhat.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-ClientProxiedBy: LO4P123CA0334.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:18c::15) To VI1PR08MB3919.eurprd08.prod.outlook.com (2603:10a6:803:c4::31) MIME-Version: 1.0 X-MS-TrafficTypeDiagnostic: VI1PR08MB3919:EE_|GVXPR08MB7680:EE_|AMS0EPF00000194:EE_|AS2PR08MB9643:EE_ X-MS-Office365-Filtering-Correlation-Id: da577a54-3264-4fec-4a6d-08dbece8a07c x-checkrecipientrouted: true NoDisclaimer: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: HZahEhPCsIJ85oCSt0Mljg64isatuTWLcruCAhLO0pQKPVQOROyMjz/DVysFL0q97/v8ZspFkRrSde8xesCWHTw+TGkbnXA2zLahV28Yf93TX2khybjinxCUqh3hBPH1OAgu0bpoRWaHoJa3VfGH1rYvx2Ao34pbKb1xVY99I+3r5xpo5Zj86pTY//CuWfymDhTNOg/+yiOCnhCLhswN5hApg2yOY5TgaDwEitBda4y8jKY3yOswBYw2U9D2uhKM0EFOTTseFcn5tsi7Xid5zX9aqQdh7WVmtyhfEnjPuWgYggzVk/iNWvSK/UpLwWr0aoNRSjdxlmr6MS08CB00FQLKSS/KrQaICElgbU56+6c2qjc6VRtN1vEw5GREN44L39oPJDnJ4PuJxMzJyzN4RW4uYzCf1agcKQXfF2YCQy1ygbXapfuIkl3nV+dVOiLCUn40c8asm95FOYrfDWxPZNGw/duGUk8d5o3gbWfakTU/Yn1lK7K+1yAxed3jZpKvaeudf4StNHkdax6RE2vS0kg1FIazL1KfPnsjZqEZAmns6hPJQrQcKX3KQ0gq5/i2hiDhRTHcMBotWbuuO+TeSL5LCflEwvaqLPIAnx/I5blYogQdqBpxifTaTkIxbG9AeoYEHQxVwHx6977MnNQNm2SfyuKN8TkWzvUMbEzfJMw= X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI1PR08MB3919.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230031)(39860400002)(136003)(366004)(396003)(346002)(376002)(230922051799003)(186009)(64100799003)(451199024)(1800799012)(83380400001)(38100700002)(86362001)(31696002)(36756003)(66556008)(66476007)(316002)(8936002)(4326008)(8676002)(41300700001)(5660300002)(2906002)(30864003)(44832011)(66946007)(31686004)(26005)(53546011)(6512007)(2616005)(478600001)(6666004)(6486002)(6506007)(2004002)(45980500001)(43740500002);DIR:OUT;SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: GVXPR08MB7680 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: AMS0EPF00000194.eurprd05.prod.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: 0b197d7c-2ff4-4cb8-4510-08dbece899a7 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: RqzLy8BgakmDEEK1bb86VgAgv3wRqztCiI2rnlOdL9UIJDmnEl554ByZmeOmkAUFtRdvz8+B/yYXTgaKGZ+G3OFG4eCH5M1g9DAmJ2ut9MR8oNtO0iYdJetxb0TKUs0GW+IXip4UjNal/GoG+YTZ2JeiDf+1JrDnaYbvqOp9BEGx9csRLL561oR7mb1hLC1w0mpUZVlOWbZxkvAum6Rd6ii1wwoixcClD6W/4N+tvfhSDdYeXVyyNWqu7RlfsyIZDmsG21lF5QluwL1QJD6ZNOA8TBQ9aOxSjNvmyyaSrxTnWdaY//BgxbCwFzWBigo7S1rf2l1tpPK2Sa5WPY9bJmRT0qzgmer3Lc41uWBdvsWy/PZigKzLFmsebJGtFRKPMSHMBQziNAvpxbbtV5Pqc0apJFiGXMbSKAJduki3EHcrue38Mb0ZJ9siJsp55gCmlWe0iP08n9L3J1vI4FROlqEi2hM19lTGNZjFYAGUuQ7XmXy8Ja2xRCA5ig8XBMREPAVihBciMDCC+SxigjY9l2j6GLxV8gl95nDZjYF3PGjlySyN0VbkzmIy8DHbs8buYIKmtH7r0Kl6hgfq/z9ARrAof1Pb5Kik+SvMQnfKyC59zuvkZOZmG3x0ClLjD5KZUEKUNhDpa6A6+kgCpgNEJ9xwJmPn3B8Pp9fz6EZsUiYJZpH1a9S6nnqmdg0SZxuTpPN1nZeGKKd5jXZQvoXKM7yZXN25moBFyH43FHuSr9Py6TnANruHcvYfoDzXQ8wD3mVlyy5A2BjMhc8oFZHeRZ5ZHpOdKS8/T7yQtWg5wuI= X-Forefront-Antispam-Report: CIP:63.35.35.123;CTRY:IE;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:64aa7808-outbound-1.mta.getcheckrecipient.com;PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com;CAT:NONE;SFS:(13230031)(4636009)(376002)(346002)(396003)(136003)(39860400002)(230922051799003)(82310400011)(64100799003)(186009)(451199024)(1800799012)(40470700004)(46966006)(36840700001)(2906002)(6486002)(336012)(30864003)(5660300002)(40460700003)(6666004)(6506007)(36860700001)(31696002)(53546011)(36756003)(41300700001)(47076005)(107886003)(2616005)(86362001)(26005)(6512007)(478600001)(83380400001)(70586007)(70206006)(316002)(81166007)(8676002)(8936002)(40480700001)(356005)(31686004)(4326008)(82740400003)(44832011)(2004002)(43740500002);DIR:OUT;SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Nov 2023 12:26:47.1187 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: da577a54-3264-4fec-4a6d-08dbece8a07c X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: AMS0EPF00000194.eurprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS2PR08MB9643 X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,FORGED_SPF_HELO,GIT_PATCH_0,KAM_DMARC_NONE,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_PASS,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE,UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 10/25/23 12:42, Guinevere Larsen wrote: > This patch is based on an out-of-tree patch that fedora has been > carrying for a while. It tests if GDB is able to properly unwind a > threaded program in the following situations: > * regular threads > * in a signal handler > * in a signal handler executing on an alternate stack > > And the final frame can either be in a syscall or in an infinite loop. > > The test works by running the inferior until a crash to generate a > corefile, or until right before the crash. Then applies a backtrace to > all threads to see if any frame can't be identified, and the order of > the threads in GDB. Finally, it goes thread by thread and tries to > collect a large part of the backtrace, to confirm that everything is > being unwound correctly. > > Co-Authored-By: Andrew Burgess > --- > > Changes for v3: > * Resolved Lancelot's comment > * undid early exit in favor of more readable gdb_test usage to load the > corefile > > Changes for v2: > * Linaro CI identified an issue with the test, which made the test fail > when using read1. Fixed here > * Also added early exit on corefile tests, if the corefile isn't > properly loaded > > --- > gdb/testsuite/gdb.threads/threadcrash.c | 443 ++++++++++++++++++++++ > gdb/testsuite/gdb.threads/threadcrash.exp | 209 ++++++++++ > 2 files changed, 652 insertions(+) > create mode 100644 gdb/testsuite/gdb.threads/threadcrash.c > create mode 100644 gdb/testsuite/gdb.threads/threadcrash.exp > > diff --git a/gdb/testsuite/gdb.threads/threadcrash.c b/gdb/testsuite/gdb.threads/threadcrash.c > new file mode 100644 > index 00000000000..e476ae7b07d > --- /dev/null > +++ b/gdb/testsuite/gdb.threads/threadcrash.c > @@ -0,0 +1,443 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2023 Free Software Foundation, Inc. > + > + 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 > +#include > +#include > +#include > +#include > + > +/* The delay that the main thread gives once all the worker threads have > + reached the barrier before the main thread enters the function on which > + GDB will have placed a breakpoint. */ > + > +#define MAIN_THREAD_DELAY 2 > + > +/* The maximum time we allow this test program to run for before an alarm > + signal is sent and everything will exit. */ > +#define WATCHDOG_ALARM_TIME 600 > + > +/* Aliases for the signals used within this script. Each signal > + corresponds to an action (from the FINAL_ACTION enum) that the signal > + handler will perform. */ > + > +#define SPIN_SIGNAL SIGUSR1 > +#define SYSCALL_SIGNAL SIGUSR2 > + > +/* Describe the final action that a thread should perform. */ > + > +enum final_action > + { > + /* Thread should spin in an infinite loop. */ > + SPIN = 0, > + > + /* Thread should block in a syscall. */ > + SYSCALL, > + > + /* This is just a marker to allow for looping over the enum. */ > + LAST_ACTION > + }; > + > +/* Where should the thread perform this action? */ > + > +enum exec_location > + { > + /* Just a normal thread, on a normal stack. */ > + NORMAL = 0, > + > + /* In a signal handler, but use the normal stack. */ > + SIGNAL_HANDLER, > + > + /* In a signal handler using an alternative stack. */ > + SIGNAL_ALT_STACK, > + > + /* This is just a marker to allow for looping over the enum. */ > + LAST_LOCACTION > + }; > + > +/* A descriptor for a single thread job. We create a new thread for each > + job_description. */ > + > +struct job_description > +{ > + /* What action should this thread perform. */ > + enum final_action action; > + > + /* Where should the thread perform the action. */ > + enum exec_location location; > + > + /* The actual thread handle, so we can join with the thread. */ > + pthread_t thread; > +}; > + > +/* A pthread barrier, used to (try) and synchronise the threads. */ > +pthread_barrier_t global_barrier; > + > +/* Return a list of jobs, and place the length of the list in *COUNT. */ > + > +struct job_description * > +get_job_list (int *count) > +{ > + /* The number of jobs. */ > + int num = LAST_ACTION * LAST_LOCACTION; > + > + /* The uninitialised array of jobs. */ > + struct job_description *list > + = malloc (num * sizeof (struct job_description)); > + assert (list != NULL); > + > + /* Fill the array with all possible jobs. */ > + for (int i = 0; i < (int) LAST_ACTION; ++i) > + for (int j = 0; j < (int) LAST_LOCACTION; ++j) > + { > + int idx = (i * LAST_LOCACTION) + j; > + list[idx].action = (enum final_action) i; > + list[idx].location = (enum exec_location) j; > + } > + > + /* Return the array of jobs. */ > + *count = num; > + return list; > +} > + > +/* This function should never be called. If it is then an assertion will > + trigger. */ > + > +void > +assert_not_reached (void) > +{ > + assert (0); > +} > + > +/* The function for a SPIN action. Just spins in a loop. The LOCATION > + argument exists so GDB can identify the expected context for this > + function. */ > + > +void > +do_spin_task (enum exec_location location) > +{ > + (void) location; > + > + /* Let everyone know that we're about to perform our action. */ > + int res = pthread_barrier_wait (&global_barrier); > + assert (res == PTHREAD_BARRIER_SERIAL_THREAD || res == 0); > + > + while (1) > + { > + /* Nothing. */ > + } > +} > + > +/* The function for a SYSCALL action. Just spins in a loop. The LOCATION > + argument exists so GDB can identify the expected context for this > + function. */ > + > +void > +do_syscall_task (enum exec_location location) > +{ > + (void) location; > + > + /* Let everyone know that we're about to perform our action. */ > + int res = pthread_barrier_wait (&global_barrier); > + assert (res == PTHREAD_BARRIER_SERIAL_THREAD || res == 0); > + > + sleep (600); > +} > + > +/* Return the required size for a sigaltstack. We start with a single > + page, but do check against the system defined minimums. We don't run > + much on the alternative stacks, so we don't need a huge one. */ > + > +size_t > +get_stack_size (void) > +{ > + size_t size = getpagesize (); /* Arbitrary starting size. */ > + if (size < SIGSTKSZ) > + size = SIGSTKSZ; > + if (size < MINSIGSTKSZ) > + size = MINSIGSTKSZ; > + return size; > +} > + > +/* A descriptor for an alternative stack. */ > + > +struct stack_descriptor > +{ > + /* The base address of the alternative stack. This is the address that > + must be freed to release the memory used by this stack. */ > + void *base; > + > + /* The size of this alternative stack. Tracked just so we can query this > + from GDB. */ > + size_t size; > +}; > + > +/* Install an alternative signal stack. Return a descriptor for the newly > + allocated alternative stack. */ > + > +struct stack_descriptor > +setup_alt_stack (void) > +{ > + size_t stack_size = get_stack_size (); > + > + void *stack_area = malloc (stack_size); > + > + stack_t stk; > + stk.ss_sp = stack_area; > + stk.ss_flags = 0; > + stk.ss_size = stack_size; > + > + int res = sigaltstack (&stk, NULL); > + assert (res == 0); > + > + struct stack_descriptor desc; > + desc.base = stack_area; > + desc.size = stack_size; > + > + return desc; > +} > + > +/* Return true (non-zero) if we are currently on the alternative stack, > + otherwise, return false (zero). */ > + > +int > +on_alt_stack_p (void) > +{ > + stack_t stk; > + int res = sigaltstack (NULL, &stk); > + assert (res == 0); > + > + return (stk.ss_flags & SS_ONSTACK) != 0; > +} > + > +/* The signal handler function. All signals call here, so we use SIGNO > + (the signal that was delivered) to decide what action to perform. This > + function might, or might not, have been called on an alternative signal > + stack. */ > + > +void > +signal_handler (int signo) > +{ > + enum exec_location location > + = on_alt_stack_p () ? SIGNAL_ALT_STACK : SIGNAL_HANDLER; > + > + switch (signo) > + { > + case SPIN_SIGNAL: > + do_spin_task (location); > + break; > + > + case SYSCALL_SIGNAL: > + do_syscall_task (location); > + break; > + > + default: > + assert_not_reached (); > + } > +} > + > +/* The thread worker function. ARG is a job_description pointer which > + describes what this thread is expected to do. This function always > + returns a NULL pointer. */ > + > +void * > +thread_function (void *arg) > +{ > + struct job_description *job = (struct job_description *) arg; > + struct stack_descriptor desc = { NULL, 0 }; > + int sa_flags = 0; > + > + switch (job->location) > + { > + case NORMAL: > + /* This thread performs the worker action on the current thread, > + select the correct worker function based on the requested > + action. */ > + switch (job->action) > + { > + case SPIN: > + do_spin_task (NORMAL); > + break; > + > + case SYSCALL: > + do_syscall_task (NORMAL); > + break; > + > + default: > + assert_not_reached (); > + } > + break; > + > + case SIGNAL_ALT_STACK: > + /* This thread is to perform its action in a signal handler on the > + alternative stack. Install the alternative stack now, and then > + fall through to the normal signal handler location code. */ > + desc = setup_alt_stack (); > + assert (desc.base != NULL); > + assert (desc.size > 0); > + sa_flags = SA_ONSTACK; > + > + /* Fall through. */ > + case SIGNAL_HANDLER: > + { > + /* This thread is to perform its action in a signal handler. We > + might have just installed an alternative signal stack. */ > + int signo, res; > + > + /* Select the correct signal number so that the signal handler will > + perform the required action. */ > + switch (job->action) > + { > + case SPIN: > + signo = SPIN_SIGNAL; > + break; > + > + case SYSCALL: > + signo = SYSCALL_SIGNAL; > + break; > + > + default: > + assert_not_reached (); > + } > + > + /* Now setup the signal handler. */ > + struct sigaction sa; > + sa.sa_handler = signal_handler; > + sigfillset (&sa.sa_mask); > + sa.sa_flags = sa_flags; > + res = sigaction (signo, &sa, NULL); > + assert (res == 0); > + > + /* Send the signal to this thread. */ > + res = pthread_kill (job->thread, signo); > + assert (res == 0); > + } > + break; > + > + default: > + assert_not_reached (); > + }; > + > + /* Free the alt-stack if we allocated one, if not DESC.BASE will be > + NULL so this call is fine. */ > + free (desc.base); > + > + /* Thread complete. */ > + return NULL; > +} > + > +void > +start_job (struct job_description *job) > +{ > + int res; > + > + res = pthread_create (&job->thread, NULL, thread_function, job); > + assert (res == 0); > +} > + > +/* Join with the thread for JOB. This will block until the thread for JOB > + has finished. */ > + > +void > +finalise_job (struct job_description *job) > +{ > + int res; > + void *retval; > + > + res = pthread_join (job->thread, &retval); > + assert (res == 0); > + assert (retval == NULL); > +} > + > +/* Function that GDB can place a breakpoint on. */ > + > +void > +breakpt (void) > +{ > + /* Nothing. */ > +} > + > +/* Function that triggers a crash, if the user has setup their environment > + correctly this will dump a core file, which GDB can then examine. */ > + > +void > +crash_function (void) > +{ > + volatile int *p = 0; > + volatile int n = *p; > + (void) n; > +} > + > +/* Entry point. */ > + > +int > +main () > +{ > + int job_count, res; > + struct job_description *jobs = get_job_list (&job_count); > + > + /* This test is going to park some threads inside infinite loops. Just > + in case this program is left running, install an alarm that will cause > + everything to exit. */ > + alarm (WATCHDOG_ALARM_TIME); > + > + /* We want each worker thread (of which there are JOB_COUNT) plus the > + main thread (hence + 1) to wait at the barrier. */ > + res = pthread_barrier_init (&global_barrier, NULL, job_count + 1); > + assert (res == 0); > + > + /* Start all the jobs. */ > + for (int i = 0; i < job_count; ++i) > + start_job (&jobs[i]); > + > + /* Notify all the worker threads that we're waiting for them. */ > + res = pthread_barrier_wait (&global_barrier); > + assert (res == PTHREAD_BARRIER_SERIAL_THREAD || res == 0); > + > + /* All we know at this point is that all the worker threads have reached > + the barrier, which is just before they perform their action. But we > + really want them to start their action. > + > + There's really no way we can be 100% certain that the worker threads > + have started their action, all we can do is wait for a short while and > + hope that the machine we're running on is not too slow. */ > + sleep (MAIN_THREAD_DELAY); > + > + /* A function that GDB can place a breakpoint on. By the time we get > + here we are as sure as we can be that all of the worker threads have > + started and are in their worker action (spinning, or syscall). */ > + breakpt (); > + > + /* If GDB is not attached then this function will cause a crash, which > + can be used to dump a core file, which GDB can then analyse. */ > + crash_function (); > + > + /* Due to the crash we never expect to get here. Plus the worker actions > + never terminate. But for completeness, here's where we join with all > + the worker threads. */ > + for (int i = 0; i < job_count; ++i) > + finalise_job (&jobs[i]); > + > + /* Cleanup the barrier. */ > + res = pthread_barrier_destroy (&global_barrier); > + assert (res == 0); > + > + /* And clean up the jobs list. */ > + free (jobs); > + > + return 0; > +} > diff --git a/gdb/testsuite/gdb.threads/threadcrash.exp b/gdb/testsuite/gdb.threads/threadcrash.exp > new file mode 100644 > index 00000000000..ee81b5c32f2 > --- /dev/null > +++ b/gdb/testsuite/gdb.threads/threadcrash.exp > @@ -0,0 +1,209 @@ > +# This testcase is part of GDB, the GNU debugger. > + > +# Copyright 2023 Free Software Foundation, Inc. > + > +# 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 . > + > +# This test case looks at GDB's ability to get correct backtraces for a > +# crashed inferior, recreating it from a live inferior, a corefile and > +# a gcore. > + > + > +# First check that we have 7 threads. > + > +proc test_thread_count {} { > + set thread_count 0 > + > + gdb_test_multiple "info threads" "getting thread count" -lbl { > + -re "Thread" { > + incr thread_count > + exp_continue > + } > + -re "$::gdb_prompt " { > + gdb_assert {$thread_count == 7} > + } > + } > + > + return $thread_count > +} > + > +# Apply all to quickly check if all expected states are > +# present. Then, save the full desired backtrace in a list > +# so we can check full backtraces later. > + > +proc thread_apply_all {} { > + global test_list > + > + set unwind_fail false > + > + gdb_test_multiple "thread apply all backtrace" \ > + "Get thread information" -lbl { > + -re "#\[0-9\]+\\\?\\\?\[^\n\]*" { > + set unwind_fail true > + exp_continue > + } > + -re "\[^\n\]*syscall_task .location=SIGNAL_ALT_STACK\[^\n\]*" { > + set test_list [linsert $test_list end [multi_line ".*sleep.*" \ > + ".*do_syscall_task .location=SIGNAL_ALT_STACK.*" \ > + ".*signal_handler.*" \ > + ".*signal handler called.*" \ > + ".*pthread_kill.*" \ > + ".*thread_function.*"]] > + exp_continue > + } > + -re "\[^\n\]*syscall_task .location=SIGNAL_HANDLER\[^\n\]*" { > + set test_list [linsert $test_list end [multi_line ".*sleep.*" \ > + ".*do_syscall_task .location=SIGNAL_HANDLER.*" \ > + ".*signal_handler.*" \ > + ".*signal handler called.*" \ > + ".*pthread_kill.*" \ > + ".*thread_function.*"]] > + exp_continue > + } > + -re "\[^\n\]*syscall_task .location=NORMAL\[^\n\]*" { > + set test_list [linsert $test_list end [multi_line ".*sleep.*" \ > + ".*do_syscall_task .location=NORMAL.*" \ > + ".*thread_function.*"]] > + exp_continue > + } > + -re "\[^\n\]*spin_task .location=SIGNAL_ALT_STACK\[^\n\]*" { > + set test_list [linsert $test_list end [multi_line ".*do_spin_task .location=SIGNAL_ALT_STACK.*" \ > + ".*signal_handler.*" \ > + ".*signal handler called.*" \ > + ".*pthread_kill.*" \ > + ".*thread_function.*"]] > + exp_continue > + } > + -re "\[^\n\]*spin_task .location=SIGNAL_HANDLER\[^\n\]*" { > + set test_list [linsert $test_list end [multi_line ".*do_spin_task .location=SIGNAL_HANDLER.*" \ > + ".*signal_handler.*" \ > + ".*signal handler called.*" \ > + ".*pthread_kill.*" \ > + ".*thread_function.*"]] > + exp_continue > + } > + -re "\[^\n\]*spin_task .location=NORMAL\[^\n\]*" { > + set test_list [linsert $test_list end [multi_line ".*do_spin_task .location=NORMAL..*" \ > + ".*thread_function.*"]] > + exp_continue > + } > + -re "\[^\n\]*main\[^\n\]*" { > + set test_list [linsert $test_list end ".*main.*"] > + exp_continue > + } > + -re "$::gdb_prompt " { > + pass $gdb_test_name > + } > + } > + > + gdb_assert {$unwind_fail == false} > +} > + > +proc do_full_test {} { > + global test_list > + set thread_count [test_thread_count] > + > + thread_apply_all > + > + gdb_assert {$thread_count == [llength $test_list]} > + > + for {set i 0} {$i < $thread_count } {incr i} { > + set thread_num [expr [llength $test_list] - $i] > + > + gdb_test "thread apply $thread_num backtrace" [lindex $test_list $i] > + } > +} > + > +proc_with_prefix test_corefile {} { > + set corefile [core_find $::binfile] > + if { $corefile == "" } { > + untested "couldn't generate corefile" > + return > + } > + set corefile [gdb_remote_download host $corefile] > + > + gdb_test "core-file $corefile" \ > + "" \ > + "loading_corefile" \ > + "A program is being debugged already\\\. Kill it\\\? \\\(y or n\\\) " \ > + "y" > + > + do_full_test > +} > + > +proc_with_prefix test_gcore {} { > + > + clean_restart "$::binfile" > + > + gdb_test "handle SIGUSR1 nostop print pass" \ > + ".*SIGUSR1.*No.*Yes.*Yes.*User defined signal 1" \ > + "setup SIGUSR1" > + gdb_test "handle SIGUSR2 nostop print pass" \ > + ".*SIGUSR2.*No.*Yes.*Yes.*User defined signal 2" \ > + "setup SIGUSR2" > + > + gdb_test "run" ".*Segmentation fault.*" "continue to crash" > + > + set gcore_name "${::binfile}.gcore" > + set gcore_supported [gdb_gcore_cmd "$gcore_name" "saving gcore"] > + > + if {!$gcore_supported} { > + unsupported "couldn't generate gcore file" > + return > + } > + > + set corefile [gdb_remote_download host $gcore_name] > + > + gdb_test "core-file $corefile" \ > + "" \ > + "loading_corefile" \ > + "A program is being debugged already\\\. Kill it\\\? \\\(y or n\\\) " \ > + "y" > + > + do_full_test > +} > + > +standard_testfile > + > +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { > + return -1 > +} > + > +clean_restart ${binfile} > + > +gdb_test_no_output "set backtrace limit unlimited" > + > +set test_list { } > + > +with_test_prefix "live inferior" { > + gdb_test "handle SIGUSR1 nostop print pass" \ > + ".*SIGUSR1.*No.*Yes.*Yes.*User defined signal 1" \ > + "setup SIGUSR1" > + gdb_test "handle SIGUSR2 nostop print pass" \ > + ".*SIGUSR2.*No.*Yes.*Yes.*User defined signal 2" \ > + "setup SIGUSR2" > + > + gdb_breakpoint "breakpt" > + gdb_test "run" ".*breakpt.*" "run to break function" > + > + do_full_test > +} > + > +set test_list { } > + > +test_corefile > + > +set test_list { } > + > +test_gcore I gave this a try on aarch64-linux arm-linux and it works as expected. Unless others have further objections, I think this looks good. Reviewed-By: Luis Machado