From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by sourceware.org (Postfix) with ESMTPS id 3F08B3858CDA for ; Fri, 20 Jan 2023 08:50:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3F08B3858CDA Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1674204654; x=1705740654; h=from:to:subject:date:message-id:references:in-reply-to: mime-version:content-transfer-encoding; bh=wy3rNkVRZFFZhsu8FmqfoECnBUBrFnDycwhHyq/JX8M=; b=IgdhjB3WsdLzmMXu3Y6L+njm+Eh3ryPghp01o8bJl6m6iM1WZBLAj4qA zjHrYPQqCuPaUKetX00eTw4Keo6cAcK8P922NnS7mWHjCxi/P/N766RSp mQ2MZO5r0C/rwckaT6ban7SkaHwuNhpUawLKHsTf8Otuqeh1foN46AIzC hctjYdjVWFB49SpOPB4p65w28eM6y6tAxy4f44M5X2LftHTjzuoEZHg/E NSbkryQRvQ0/pje+4glsfuIwvBBUNooJKVVkwwbYPlSPqmePY9MMfczDR a7fvUaInhu+r8e/MF98fmbV6X6Me+aBNDvCV0etNtyb06wMrOUGXl2IS+ Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10595"; a="324219733" X-IronPort-AV: E=Sophos;i="5.97,231,1669104000"; d="scan'208";a="324219733" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 20 Jan 2023 00:50:52 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10595"; a="989337793" X-IronPort-AV: E=Sophos;i="5.97,231,1669104000"; d="scan'208";a="989337793" Received: from orsmsx602.amr.corp.intel.com ([10.22.229.15]) by fmsmga005.fm.intel.com with ESMTP; 20 Jan 2023 00:50:52 -0800 Received: from orsmsx602.amr.corp.intel.com (10.22.229.15) by ORSMSX602.amr.corp.intel.com (10.22.229.15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.16; Fri, 20 Jan 2023 00:50:51 -0800 Received: from ORSEDG602.ED.cps.intel.com (10.7.248.7) by orsmsx602.amr.corp.intel.com (10.22.229.15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.16 via Frontend Transport; Fri, 20 Jan 2023 00:50:51 -0800 Received: from NAM12-MW2-obe.outbound.protection.outlook.com (104.47.66.44) by edgegateway.intel.com (134.134.137.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.16; Fri, 20 Jan 2023 00:50:51 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=dMxzBGk2mtHOe08xnKqPn1SBTef8Ltep1QSRxBDSS52Zqja/AyCyK4KiLiByOlkcEtysvJCMiJMySwYbsiCYubX9fztT0AYO9mtqb72Ie8uxUjEaKD0zdmHqDUpXwzicIkPvuA4dJlUYzeDi0jAlT9aRVykBEe2zL+yq0mNjbmILtPGqOsRajeFrlEEDe5RGgakOTsePLsOyBWvgLcU+vKFd0mFE+W7vMcEOMkTKvSN4f3tO/wcvLvCjp8u7aikcZecybRfNrQH3MfDQ1cXJkb77GeOv9dP0GOh1RcvVOoQCZ4Yhnsug78EesaRGTuQpCnYWvk6V3ABCrfEIwwY45A== 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=GEzvn6MqKysTcgJVUTZsyFFV19jzpfM4ElWAsxAA/x0=; b=PFS+n3KFGwshfiHZhjJoR5nKJ8JHM2BgrqAuhtD1R+4E5DlDpNtFN2tJMojXWLdUHJj9iGVmY6tTDbO3yVxzzf9na9cesRbQ+LV4WUFFJNMk28W8Ja9mimN10pMe4kkU5hi4o2+QIN4nyvcXlOwCAm+uZ/k4amp20IpQz+dUbrVzuZ0E3TT2muiSQ2RVpyezRPfTCP9bWEA7tw0nYa8l1gb/BWv3i42wGQKPfSQuU88wknYNre/C4CUaSotVbCwQ0AV4gK6NImW9q8JqNSmD4RsEYr+xOKIqjxB/SD01bsWbplzW0lYiW/qSflreoxkEepWXmUcRZQwySAcpThgPKA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none Received: from DM4PR11MB7303.namprd11.prod.outlook.com (2603:10b6:8:108::21) by BN9PR11MB5321.namprd11.prod.outlook.com (2603:10b6:408:136::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6002.27; Fri, 20 Jan 2023 08:50:49 +0000 Received: from DM4PR11MB7303.namprd11.prod.outlook.com ([fe80::dec6:d57d:f767:c5f2]) by DM4PR11MB7303.namprd11.prod.outlook.com ([fe80::dec6:d57d:f767:c5f2%4]) with mapi id 15.20.6002.026; Fri, 20 Jan 2023 08:50:49 +0000 From: "Aktemur, Tankut Baris" To: Andrew Burgess , "gdb-patches@sourceware.org" Subject: RE: [PATCHv2 10/13] gdb: add timeouts for inferior function calls Thread-Topic: [PATCHv2 10/13] gdb: add timeouts for inferior function calls Thread-Index: AQHZK1ixSxSaum/QWUiGg14aulbp566m5xpQ Date: Fri, 20 Jan 2023 08:50:48 +0000 Message-ID: References: <9008dc2605a09477a5978381c107a33f8b6760a9.1674058360.git.aburgess@redhat.com> In-Reply-To: <9008dc2605a09477a5978381c107a33f8b6760a9.1674058360.git.aburgess@redhat.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=intel.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: DM4PR11MB7303:EE_|BN9PR11MB5321:EE_ x-ms-office365-filtering-correlation-id: 425e5bfa-5a15-4cbb-1da2-08dafac36d48 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: fCSjnBsofp0VnqUBvZqGazssH46QWmd8uHY7GA12WChZiJmEB2BWPbBvQTGTL+q2mlBV5XM3D2v1R17llu72jzRxKiOUIZ/z0V0zgtV+3N+/V7bREyfHhLzU7D2QqZR8rjovhrpOn1/ItAnSIzxecNBUa8XycrP0CuHog1GDnpvjP8L9YGZQU7mpQASJPzSnTagvxjxCVkpyqkkWz7/n19Fp4iGQGobH4/Kf9JgQeBSd6whVR1jmryMgaUmxGlfXQNhfww9GXhrvkNzf1mbvoH89iMe+cw4IoH8Imah+cWFAkMXNiObg7dopgEY1JdePrOOGgHY9gGrdw4rwT+ioU8ILEScn9/Y64MwQXLu46Jjd5qCLRj3utSsBLIl4nxSCHgdLkbo5XFJXpCtfNJvpCpOn2lKGGmztWM4EPYGA53zfWieF7cU5AInSI0jkPP/iCzib2CDpo385s9RU6HZcejSXHTMsQcFLDCpp3EVPqQhmyTJtwFEjzJeegr1IEMseX/Ovr3bzyj/66wRiU6imUk0XqgabFEgTKzOTWphf/O6rZh+F6ZIDGNlUVDdYJ41nHtxR+6TL9JRkgLIGLTIuwfNhGiSorYD8v5wmPZS1vQmgL7+JW8kfTtwj1atnZjMK8sUB2TjFUQjjxUAk0JMLBPTwI0CAh2BF710ipqlcp6swt+AFsjlHtrFuxYqP/PZmYY6M+VNl9Xvo5+6N++AcbrHm7UycLPqNt4U11NbrZ8FAe+RuKMo/6ui95Gf+6XrO x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DM4PR11MB7303.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230022)(346002)(39860400002)(136003)(366004)(376002)(396003)(451199015)(316002)(110136005)(76116006)(122000001)(82960400001)(5660300002)(8936002)(41300700001)(38100700002)(26005)(9686003)(186003)(8676002)(52536014)(66556008)(30864003)(83380400001)(66476007)(64756008)(66946007)(66446008)(33656002)(38070700005)(55016003)(86362001)(2906002)(6506007)(7696005)(478600001)(53546011)(71200400001)(84970400001)(2004002)(579004)(559001);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?SR2nrX1S2/uhUV0nikt4phRETTYsOCnZxZm+MmEql7aWIXCAdpKM4A3gYqIm?= =?us-ascii?Q?EINKK+7fxcMwzmQqgSqCYN0KglXvZjH9+TQj5JZJTynSA17heudTUJ6qy6/M?= =?us-ascii?Q?/MwoMOAaU3Uc5qMzE+5NcWT+PVs8i97zYNXV5d3s6r0603D336x+EXdbZ+uC?= =?us-ascii?Q?Lw68XHb8DIfaOz8Y4r/AglmQ0PSXTDmloh9saYdr6Imp0U0No+NEjov7+kH5?= =?us-ascii?Q?DKs5tNPJc5VjISF5vTjlA9d1VIFO2k/5OmEiA3840NdNwEBQJksJrxuKihs3?= =?us-ascii?Q?B8yrnkG6HPYGyXeZNPZ7DtC8EQqpgKn1nMw9++qBasPr0tTgTbgjWWt+imWZ?= =?us-ascii?Q?CEOHoyVYrKkxMqukrFoQpIB3junoQcKSEqLErnMqtQfNm+HFNR4mU611azip?= =?us-ascii?Q?BFdN/XBqlDlOCr1gyYlymFLJmGWz4W+2YiqFUDc+d0RWLbCdmbzJtPfrqCNN?= =?us-ascii?Q?FnAvVkIP+vsQvRLb5V/B+AQqa6yf/g12nJGnrBs8dJX96aN6pElh38DkGpSW?= =?us-ascii?Q?SZkIhM/561K9Qp1wtdC36YSAcDKwwn/8coZAqSOZnQTfwK/Z8Tvgd09DAA/u?= =?us-ascii?Q?3RJPM72O97LjGK7BGHnd0KLJ3uawTl0epefc+hq3xI9JY1tR/xQYHqsdXGTH?= =?us-ascii?Q?K5UsxGCuk+9duJX7u1m3s1kJgrSz6TBI4sLHCa3NfmO+7FKCOkFLkyGUYka6?= =?us-ascii?Q?XTFYFHnDN02b5HbEmSZxufOCMHqW8CoUT9Z/IXtxbPXi/IgpvCvwc5O5ZKxt?= =?us-ascii?Q?ilGfCtX6aqUMyzCOxfeyYvzhbnmRHowuL/O0P6tzmYPMLxuQHdiVBhixWUoF?= =?us-ascii?Q?hogZIowIceISvomEFKBSC1hWvV/YkodPFQeVNPfTdvhbBpvi39cx/jxa0/QH?= =?us-ascii?Q?uO2PfS2JhSTcNkLAZdWvVVn70DNlrRxi4CfyrtQteObtzDvG0JkPtxQy0g1v?= =?us-ascii?Q?vpdZFUfBudDgh0Z6cyJFJRroqyJYoQRRB+DG4X6/eKJArivt274V9S3F0G3T?= =?us-ascii?Q?WEl1lnGD644vF+m0cFAzNVft7iv17vLHx4OVWUfn1HAWBcse2UaN+bXzM/uY?= =?us-ascii?Q?Q+2/l3X8qCsxogQppgCGEPomcIXF8YfKPiBTTufF8AP/vNVR6LH4l8sIG9Hr?= =?us-ascii?Q?T5Pul25heqh8WSOe7LUOUAmx26aNKUb82dbcRuOKA+io+lb3K+zibHHL2461?= =?us-ascii?Q?2AXrfNmN04Itv3PjN/gwc0dXl/UCogzqdb2bU9VdEI17RqyC1uZfpYMUwH2Z?= =?us-ascii?Q?GJp1prDqqWKXQLBPw54u/Nqjn3vdKFRaPkVOmsWs3IqIluLDNXTcmhC9A4p4?= =?us-ascii?Q?kXeNIIkfIGaiiyRZlnWdbSVXO7zxs5od036UURR0Ge/95EVGKIersTHbdQz1?= =?us-ascii?Q?UC9fZTPDb3jTrhtC7vywz2zp2UkkztoII93N6ZhvU2dEvZVzlZsQnPVHyQ1G?= =?us-ascii?Q?q7v6fLDP6xcyGbKhkh9krE0dYt2BtcQBGHwa7oqyMIJ8XizWjV6U7ySCEpPu?= =?us-ascii?Q?GG7ykW267cdlU6bWuHWK3N59wYCnDM7lF88f/VJ6n++tyrkIB2b+xamnKP3Y?= =?us-ascii?Q?3rZT7691xv1Ljf3RpCiy4yEopstEkjh2eQBSZgTMCCyU8ckEdwycHfAiXZvm?= =?us-ascii?Q?kQ=3D=3D?= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: DM4PR11MB7303.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 425e5bfa-5a15-4cbb-1da2-08dafac36d48 X-MS-Exchange-CrossTenant-originalarrivaltime: 20 Jan 2023 08:50:48.5199 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: QrZJgSWKMbQjuqQJd9axK06c3tdpdwXE+p5koEEaHyp8dVH+WOCu7G+uhcfoNLnxXJEXDQlUVqL5MQ74XOOKZIws8Ik+nSef59OjLaehCP0= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN9PR11MB5321 X-OriginatorOrg: intel.com Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,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 List-Id: On Wednesday, January 18, 2023 5:18 PM, Andrew Burgess wrote: > In the previous commits I have been working on improving inferior > function call support. One thing that worries me about using inferior > function calls from a conditional breakpoint is: what happens if the > inferior function call fails? > = > If the failure is obvious, e.g. the thread performing the call > crashes, or hits a breakpoint, then this case is already well handled, > and the error is reported to the user. > = > But what if the thread performing the inferior call just deadlocks? > If the user made the call from a 'print' or 'call' command, then the > user might have some expectation of when the function call should > complete, and, when this time limit is exceeded, the user > will (hopefully) interrupt GDB and regain control of the debug > session. > = > But, when the inferior function call is from a breakpoint condition it > is much harder to understand that GDB is deadlocked within an inferior > call. Maybe the breakpoint hasn't been hit yet? Or maybe the > condition was always false? Or maybe GDB is deadlocked in an inferior > call? The only way to know for sure is to periodically interrupt GDB, > check on all the threads, and then continue. > = > Additionally, the focus of the previous commit was inferior function > calls, from a conditional breakpoint, in a multi-threaded inferior. > This opens up a whole new set of potential failure conditions. For > example, what if the function called relies on interaction with some > other thread, and the other thread crashes? Or hits a breakpoint? > Given how inferior function calls work - in a synchronous manor, a manor -> manner > stop event in some other thread is going to be ignored when the > inferior function call is being done as part of a breakpoint > condition, and this means that GDB could get stuck waiting for the > original condition thread, which will now never complete. > = > In this commit I propose a solution to this problem. A timeout. For > targets that support async-mode we can install an event-loop timer > before starting the inferior function call. When the timer expires we > will stop the thread performing the inferior function call. With this > mechanism in place a user can be sure that any inferior call they make > will either complete, or timeout eventually. > = > Adding a timer like this is obviously a change in behaviour for the > more common 'call' and 'print' uses of inferior function calls, so, in > this patch, I propose having two different timers. One I call the > 'direct-call-timeout', which is used for 'call' and 'print' commands. > This timeout is by default set to unlimited, which, not surprisingly, > means there is no timeout in place. > = > A second timer, which I've called 'indirect-call-timeout', is used for > inferior function calls from breakpoint conditions. This timeout has > a default value of 300 seconds. This is still a pretty substantial > time to be waiting for a single inferior call to complete, but I > didn't want to be too aggressive with the value I selected. A user > can, of course, still use Ctrl-c to interrupt an inferior function > call, but this limit will ensure that GDB will stop at some point. > = > The new commands added by this commit are: > = > set direct-call-timeout SECONDS > show direct-call-timeout > set indirect-call-timeout SECONDS > show indirect-call-timeout > = > These new timeouts do depend on async-mode, so, if async-mode is > disabled (maint set target-async off), or not supported (e.g. target > sim), then the timeout is treated as unlimited (that is, no timeout is > set). > = > For targets that "fake" non-async mode, e.g. Linux native, where > non-async mode is really just async mode, but then we park the target > in a sissuspend, we could easily fix things so that the timeouts still > work, however, for targets that really are not async aware, like the > simulator, fixing things so that timeouts work correctly would be a > much bigger task - that effort would be better spent just making the > target async-aware. And so, I'm happy for now that this feature will > only work on async targets. > = > The two new show commands will display slightly different text if the > current target is a non-async target, which should allow users to > understand what's going on. > = > There's a somewhat random test adjustment needed in gdb.base/help.exp, > the test uses a regexp with the apropos command, and expects to find a > single result. Turns out the new settings I added also matched the > regexp, which broke the test. I've updated the regexp a little to > exclude my new settings. > --- > gdb/NEWS | 18 ++ > gdb/doc/gdb.texinfo | 66 ++++++ > gdb/infcall.c | 210 +++++++++++++++++- > gdb/testsuite/gdb.base/help.exp | 2 +- > gdb/testsuite/gdb.base/infcall-timeout.c | 36 +++ > gdb/testsuite/gdb.base/infcall-timeout.exp | 82 +++++++ > .../infcall-from-bp-cond-timeout.c | 169 ++++++++++++++ > .../infcall-from-bp-cond-timeout.exp | 156 +++++++++++++ > 8 files changed, 734 insertions(+), 5 deletions(-) > create mode 100644 gdb/testsuite/gdb.base/infcall-timeout.c > create mode 100644 gdb/testsuite/gdb.base/infcall-timeout.exp > create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeou= t.c > create mode 100644 gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeou= t.exp > = > diff --git a/gdb/NEWS b/gdb/NEWS > index c0aac212e30..2689569a8f3 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -17,6 +17,24 @@ maintenance print record-instruction [ N ] > prints how GDB would undo the N-th previous instruction, and if N is > positive, it prints how GDB will redo the N-th following instruction. > = > +set direct-call-timeout SECONDS > +show direct-call-timeout > +set indirect-call-timeout SECONDS > +show indirect-call-timeout > + These new settings can be used to limit how long GDB will wait for > + an inferior function call to complete. The direct timeout is used > + for inferior function calls from e.g. 'call' and 'print' commands, > + while the indirect timeout is used for inferior function calls from > + within a conditional breakpoint expression. > + > + The default for the direct timeout is unlimited, while the default > + for the indirect timeout is 30 seconds. > + > + These timeouts will only have an effect for targets that are > + operating in async mode. For non-async targets the timeouts are > + ignored, GDB will wait indefinitely for an inferior function to > + complete, unless interrupted by the user using Ctrl-C. > + > * MI changes > = > ** mi now reports 'no-history' as a stop reason when hitting the end of = the > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 6ea173b5d0b..9eb8b1db00e 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -20772,6 +20772,72 @@ > @code{step}, etc). In this case, when the inferior finally returns to > the dummy-frame, @value{GDBN} will once again halt the inferior. > = > +On targets that support asynchronous execution (@pxref{Background > +Execution}) @value{GDBN} can place a timeout on any functions called > +from @value{GDBN}. If the timeout expires and the function call is > +still ongoing, then @value{GDBN} will interrupt the program. > + > +For targets that don't support asynchronous execution > +(@pxref{Background Execution}) then timeouts for functions called from > +@value{GDBN} are not supported, the timeout settings described below > +will be treated as @code{unlimited}, meaning @value{GDBN} will wait > +indefinitely for function call to complete, unless interrupted by the > +user using @kbd{Ctrl-C}. > + > +@table @code > +@item set direct-call-timeout @var{seconds} > +@kindex set direct-call-timeout > +@cindex timeout for called functions > +Set the timeout used when calling functions in the program to > +@var{seconds}, which should be an integer greater than zero, or the > +special value @code{unlimited}, which indicates no timeout should be > +used. The default for this setting is @code{unlimited}. > + > +This setting is used when the user calls a function directly from the > +command prompt, for example with a @code{call} or @code{print} > +command. > + > +This setting only works for targets that support asynchronous > +execution (@pxref{Background Execution}), for any other target the > +setting is treated as @code{unlimited}. > + > +@item show direct-call-timeout > +@kindex show direct-call-timeout > +@cindex timeout for called functions > +Show the timeout used when calling functions in the program with a > +@code{call} or @code{print} command. > +@end table > + > +It is also possible to call functions within the program from the > +condition of a conditional breakpoint (@pxref{Conditions, ,Break > +Conditions}). A different setting controls the timeout used for > +function calls made from a breakpoint condition. > + > +@table @code > +@item set indirect-call-timeout @var{seconds} > +@kindex set indirect-call-timeout > +@cindex timeout for called functions > +Set the timeout used when calling functions in the program from a > +breakpoint or watchpoint condition to @var{seconds}, which should be > +an integer greater than zero, or the special value @code{unlimited}, > +which indicates no timeout should be used. The default for this > +setting is @code{30} seconds. > + > +This setting only works for targets that support asynchronous > +execution (@pxref{Background Execution}), for any other target the > +setting is treated as @code{unlimited}. > + > +If a function called from a breakpoint or watchpoint condition times > +out, then @value{GDBN} will stop at the point where the timeout > +occurred. The breakpoint condition evaluation will be abandoned. > + > +@item show indirect-call-timeout > +@kindex show indirect-call-timeout > +@cindex timeout for called functions > +Show the timeout used when calling functions in the program from a > +breakpoint or watchpoint condition. > +@end table > + > @subsection Calling functions with no debug info > = > @cindex no debug info functions > diff --git a/gdb/infcall.c b/gdb/infcall.c > index 8a48909bc2c..9afca4f5bc6 100644 > --- a/gdb/infcall.c > +++ b/gdb/infcall.c > @@ -95,6 +95,53 @@ show_may_call_functions_p (struct ui_file *file, int f= rom_tty, > value); > } > = > +/* A timeout (in seconds) for direct inferior calls. A direct inferior > + call is one the user triggers from the prompt, e.g. with a 'call' or > + 'print' command. Compare with the definition of indirect calls below= . */ > + > +static unsigned int direct_call_timeout =3D UINT_MAX; > + > +/* Implement 'show direct-call-timeout'. */ > + > +static void > +show_direct_call_timeout (struct ui_file *file, int from_tty, > + struct cmd_list_element *c, const char *value) > +{ > + if (target_has_execution () && !target_can_async_p ()) > + gdb_printf (file, _("Current target does not support async mode, tim= eout " > + "for direct inferior calls is \"unlimited\".\n")); > + else if (direct_call_timeout =3D=3D UINT_MAX) > + gdb_printf (file, _("Timeout for direct inferior function calls " > + "is \"unlimited\".\n")); > + else > + gdb_printf (file, _("Timeout for direct inferior function calls " > + "is \"%s seconds\".\n"), value); > +} > + > +/* A timeout (in seconds) for indirect inferior calls. An indirect infe= rior > + call is one that originates from within GDB, for example, when > + evaluating an expression for a conditional breakpoint. Compare with > + the definition of direct calls above. */ > + > +static unsigned int indirect_call_timeout =3D 30; > + > +/* Implement 'show indirect-call-timeout'. */ > + > +static void > +show_indirect_call_timeout (struct ui_file *file, int from_tty, > + struct cmd_list_element *c, const char *value) > +{ > + if (target_has_execution () && !target_can_async_p ()) > + gdb_printf (file, _("Current target does not support async mode, tim= eout " > + "for indirect inferior calls is \"unlimited\".\n")); > + else if (indirect_call_timeout =3D=3D UINT_MAX) > + gdb_printf (file, _("Timeout for indirect inferior function calls " > + "is \"unlimited\".\n")); > + else > + gdb_printf (file, _("Timeout for indirect inferior function calls " > + "is \"%s seconds\".\n"), value); > +} > + > /* How you should pass arguments to a function depends on whether it > was defined in K&R style or prototype style. If you define a > function using the K&R syntax that takes a `float' argument, then > @@ -589,6 +636,85 @@ call_thread_fsm::should_notify_stop () > return true; > } > = > +/* A class to control creation of a timer that will interrupt a thread > + during an inferior call. */ > +struct infcall_timer_controller > +{ > + /* Setup an event-loop timer that will interrupt PTID if the inferior > + call takes too long. DIRECT_CALL_P is true when this inferior call= is > + a result of the user using a 'print' or 'call' command, and false w= hen > + this inferior call is a result of e.g. a conditional breakpoint > + expression, this is used to select which timeout to use. */ > + infcall_timer_controller (ptid_t ptid, bool direct_call_p) > + : m_ptid (ptid) > + { > + unsigned int timeout > + =3D direct_call_p ? direct_call_timeout : indirect_call_timeout; > + if (timeout < UINT_MAX && target_can_async_p ()) > + { > + int ms =3D timeout * 1000; > + int id =3D create_timer (ms, infcall_timer_controller::timed_out, this); > + m_timer_id.emplace (id); > + infcall_debug_printf ("Setting up infcall timeout timer for " > + "ptid %s: %d milliseconds", > + m_ptid.to_string ().c_str (), ms); > + } > + } > + > + /* Destructor. Ensure that the timer is removed from the event loop. = */ > + ~infcall_timer_controller () > + { > + /* If the timer has already triggered, then it will have already been > + deleted from the event loop. If the timer has not triggered, then > + delete it now. */ > + if (m_timer_id.has_value () && !m_triggered) > + delete_timer (*m_timer_id); > + > + /* Just for clarity, discard the timer id now. */ > + m_timer_id.reset (); > + } > + > + /* Return true if there was a timer in place, and the timer triggered, > + otherwise, return false. */ > + bool triggered_p () > + { > + gdb_assert (!m_triggered || m_timer_id.has_value ()); > + return m_triggered; > + } > + > +private: > + /* The thread we should interrupt. */ > + ptid_t m_ptid; > + > + /* Set true when the timer is triggered. */ > + bool m_triggered =3D false; > + > + /* Given a value when a timer is in place. */ > + gdb::optional m_timer_id; > + > + /* Callback for the timer, forwards to ::trigger below. */ > + static void > + timed_out (gdb_client_data context) > + { > + infcall_timer_controller *ctrl > + =3D static_cast (context); > + ctrl->trigger (); > + } > + > + /* Called when the timer goes off. Stop thread m_ptid. */ > + void > + trigger () > + { > + m_triggered =3D true; > + > + scoped_disable_commit_resumed disable_commit_resumed ("infcall timeo= ut"); > + > + infcall_debug_printf ("Stopping thread %s", > + m_ptid.to_string ().c_str ()); > + target_stop (m_ptid); > + } > +}; > + > /* Subroutine of call_function_by_hand to simplify it. > Start up the inferior and wait for it to stop. > Return the exception if there's an error, or an exception with > @@ -599,13 +725,15 @@ call_thread_fsm::should_notify_stop () > = > static struct gdb_exception > run_inferior_call (std::unique_ptr sm, > - struct thread_info *call_thread, CORE_ADDR real_pc) > + struct thread_info *call_thread, CORE_ADDR real_pc, > + bool *timed_out_p) > { > INFCALL_SCOPED_DEBUG_ENTER_EXIT; > = > struct gdb_exception caught_error; > ptid_t call_thread_ptid =3D call_thread->ptid; > int was_running =3D call_thread->state =3D=3D THREAD_RUNNING; > + *timed_out_p =3D false; > = > infcall_debug_printf ("call function at %s in thread %s, was_running = =3D %d", > core_addr_to_string (real_pc), > @@ -650,11 +778,23 @@ run_inferior_call (std::unique_ptr= sm, > infrun_debug_show_threads ("non-exited threads after proceed for i= nferior-call", > all_non_exited_threads ()); > = > + /* Setup a timer (if possible, and if the settings allow) to preve= nt > + the inferior call running forever. */ > + bool direct_call_p =3D !call_thread->control.in_cond_eval; > + infcall_timer_controller infcall_timer (inferior_ptid, direct_call= _p); > + > /* Inferior function calls are always synchronous, even if the > target supports asynchronous execution. */ > wait_sync_command_done (); > = > - infcall_debug_printf ("inferior call completed successfully"); > + /* If the timer triggered then the inferior call failed. */ > + if (infcall_timer.triggered_p ()) > + { > + infcall_debug_printf ("inferior call timed out"); > + *timed_out_p =3D true; > + } > + else > + infcall_debug_printf ("inferior call completed successfully"); > } > catch (gdb_exception &e) > { > @@ -1311,6 +1451,10 @@ call_function_by_hand_dummy (struct value *functio= n, > scoped_restore restore_stopped_by_random_signal > =3D make_scoped_restore (&stopped_by_random_signal, 0); > = > + /* Set to true by the call to run_inferior_call below if the inferior > + call is artificially interrupted by GDB due to taking too long. */ > + bool timed_out_p =3D false; > + > /* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - > If you're looking to implement asynchronous dummy-frames, then > just below is the place to chop this function in two.. */ > @@ -1337,7 +1481,8 @@ call_function_by_hand_dummy (struct value *function, > struct_addr); > { > std::unique_ptr sm_up (sm); > - e =3D run_inferior_call (std::move (sm_up), call_thread.get (), re= al_pc); > + e =3D run_inferior_call (std::move (sm_up), call_thread.get (), re= al_pc, > + &timed_out_p); > } > = > if (e.reason < 0) > @@ -1489,7 +1634,10 @@ When the function is done executing, GDB will sile= ntly stop."), > std::string name =3D get_function_name (funaddr, name_buf, > sizeof (name_buf)); > = > - if (stopped_by_random_signal) > + /* If the inferior call timed out then it will have been interrupt= ed > + by a signal, but we want to report this differently to the user, > + which is done later in this function. */ > + if (stopped_by_random_signal && !timed_out_p) > { > /* We stopped inside the FUNCTION because of a random > signal. Further execution of the FUNCTION is not > @@ -1533,6 +1681,36 @@ GDB remains in the frame where the signal was rece= ived.\n\ > To change this behavior use \"set unwindonsignal on\".\n\ > Evaluation of the expression containing the function\n\ > (%s) will be abandoned.\n\ > +When the function is done executing, GDB will silently stop."), > + name.c_str ()); > + } > + } > + > + if (timed_out_p) > + { > + /* A timeout results in a signal being sent to the inferior. */ > + gdb_assert (stopped_by_random_signal); > + > + /* Indentation is weird here. A later patch is going to move the > + following block into an if/else, so I'm leaving the indentation > + here to minimise the later patch. > + > + Also, the error message used below refers to 'set > + unwind-on-timeout' which doesn't exist yet. This will be added > + in a later commit, I'm leaving this in for now to minimise the > + churn caused by the commit that adds unwind-on-timeout. */ > + { > + /* The user wants to stay in the frame where we stopped > + (default). Discard inferior status, we're not at the same > + point we started at. */ > + discard_infcall_control_state (inf_status.release ()); > + > + error (_("\ > +The program being debugged timed out while in a function called from GDB= .\n\ > +GDB remains in the frame where the timeout occurred.\n\ > +To change this behavior use \"set unwind-on-timeout on\".\n\ > +Evaluation of the expression containing the function\n\ > +(%s) will be abandoned.\n\ > When the function is done executing, GDB will silently stop."), > name.c_str ()); > } > @@ -1646,6 +1824,30 @@ The default is to unwind the frame."), > show_unwind_on_terminating_exception_p, > &setlist, &showlist); > = > + add_setshow_uinteger_cmd ("direct-call-timeout", no_class, > + &direct_call_timeout, _("\ > +Set the timeout, for direct calls to inferior function calls."), _("\ > +Show the timeout, for direct calls to inferior function calls."), _("\ > +If running on a target that supports, and is running in, async mode\n\ > +then this timeout is used for any inferior function calls triggered\n\ > +directly from the prompt, i.e. from a 'call' or 'print' command. The\n\ > +timeout is specified in seconds."), > + nullptr, > + show_direct_call_timeout, > + &setlist, &showlist); > + > + add_setshow_uinteger_cmd ("indirect-call-timeout", no_class, > + &indirect_call_timeout, _("\ > +Set the timeout, for indirect calls to inferior function calls."), _("\ > +Show the timeout, for indirect calls to inferior function calls."), _("\ > +If running on a target that supports, and is running in, async mode\n\ > +then this timeout is used for any inferior function calls triggered\n\ > +indirectly, i.e. being made as part of a breakpoint, or watchpoint,\n\ > +condition expression. The timeout is specified in seconds."), > + nullptr, > + show_indirect_call_timeout, > + &setlist, &showlist); > + > add_setshow_boolean_cmd > ("infcall", class_maintenance, &debug_infcall, > _("Set inferior call debugging."), > diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/hel= p.exp > index 87919a819ab..504bf90cc15 100644 > --- a/gdb/testsuite/gdb.base/help.exp > +++ b/gdb/testsuite/gdb.base/help.exp > @@ -121,7 +121,7 @@ gdb_test "help info bogus-gdb-command" "Undefined inf= o command: \"bogus- > gdb-comm > gdb_test "help gotcha" "Undefined command: \"gotcha\"\. Try \"help\"\." > = > # Test apropos regex. > -gdb_test "apropos \\\(print\[\^\[ bsiedf\\\".-\]\\\)" "handle -- Specify= how to handle > signals\." > +gdb_test "apropos \\\(print\[\^\[ bsiedf\\\"'.-\]\\\)" "handle -- Specif= y how to handle > signals\." > # Test apropos >1 word string. > gdb_test "apropos handle signal" "handle -- Specify how to handle signal= s\." > # Test apropos apropos. > diff --git a/gdb/testsuite/gdb.base/infcall-timeout.c b/gdb/testsuite/gdb= .base/infcall- > timeout.c > new file mode 100644 > index 00000000000..895e8a36d59 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/infcall-timeout.c > @@ -0,0 +1,36 @@ > +/* Copyright 2022 Free Software Foundation, Inc. 2022-2023? > + > + This file is part of GDB. > + > + 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 > + > +/* This function is called from GDB. */ > +int > +function_that_never_returns () > +{ > + while (1) > + sleep (1); > + > + return 0; > +} > + > +int > +main () > +{ > + alarm (300); > + > + return 0; > +} > diff --git a/gdb/testsuite/gdb.base/infcall-timeout.exp b/gdb/testsuite/g= db.base/infcall- > timeout.exp > new file mode 100644 > index 00000000000..a5b0111ed04 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/infcall-timeout.exp > @@ -0,0 +1,82 @@ > +# Copyright 2022 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 . > + > +# Test GDB's direct-call-timeout setting, that is, ensure that if an > +# inferior function call, invoked from e.g. a 'print' command, takes > +# too long, then GDB can interrupt it, and return control to the user. > + > +standard_testfile > + > +if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \ > + {debug}] =3D=3D -1 } { > + return > +} > + > +# Start GDB according to TARGET_ASYNC and TARGET_NON_STOP, then adjust > +# the direct-call-timeout, and make an inferior function call that > +# will never return. GDB should eventually timeout and stop the > +# inferior. > +proc_with_prefix run_test { target_async target_non_stop } { > + save_vars { ::GDBFLAGS } { > + append ::GDBFLAGS \ > + " -ex \"maint set target-non-stop $target_non_stop\"" > + append ::GDBFLAGS \ > + " -ex \"maintenance set target-async ${target_async}\"" > + > + clean_restart ${::binfile} > + } > + > + if {![runto_main]} { > + fail "run to main" > + return > + } > + > + gdb_test_no_output "set direct-call-timeout 5" > + > + # When non-stop mode is off we get slightly different output from GD= B. > + if { [gdb_is_remote_or_extended_remote_target] && $target_non_stop = =3D=3D "off" } { Use 'eq' instead of '=3D=3D' for string comparison? Or maybe even just '!$target_non_stop', since "off" is treated as a boolean= false. > + set stopped_line_pattern "Program received signal SIGINT, Interrupt\\." > + } else { > + set stopped_line_pattern "Program stopped\\." > + } > + > + gdb_test "print function_that_never_returns ()" \ > + [multi_line \ > + $stopped_line_pattern \ > + ".*" \ > + "The program being debugged timed out while in a function called f= rom GDB\\." \ > + "GDB remains in the frame where the timeout occurred\\." \ > + "To change this behavior use \"set unwind-on-timeout on\"\\." \ > + "Evaluation of the expression containing the function" \ > + "\\(function_that_never_returns\\) will be abandoned\\." \ > + "When the function is done executing, GDB will silently stop\\."] > + > + gdb_test "bt" ".* function_that_never_returns .*.*" > +} > + > +foreach_with_prefix target_async { "on" "off" } { > + > + if { $target_async =3D=3D "off" } { Same comment about string comparison here, too. > + # GDB can't timeout while waiting for a thread if the target > + # runs with async-mode turned off; once the target is running > + # GDB is effectively blocked until the target stops for some > + # reason. > + continue > + } > + > + foreach_with_prefix target_non_stop { "on" "off" } { > + run_test $target_async $target_non_stop > + } > +} > diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.c > b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.c > new file mode 100644 > index 00000000000..3bd91d7377d > --- /dev/null > +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.c > @@ -0,0 +1,169 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2022 Free Software Foundation, Inc. 2022-2023? > + > + 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 > +#include > + > +#define NUM_THREADS 5 > + > +/* Semaphores, used to track when threads have started, and to control > + when the threads finish. */ > +sem_t startup_semaphore; > +sem_t finish_semaphore; > +sem_t thread_1_semaphore; > +sem_t thread_2_semaphore; > + > +/* Mutex to control when the first worker thread hit a breakpoint > + location. */ > +pthread_mutex_t mutex =3D PTHREAD_MUTEX_INITIALIZER; > + > +/* Global variable to poke, just so threads have something to do. */ > +volatile int global_var =3D 0; > + > +int > +condition_func () > +{ > + /* Let thread 2 run. */ > + if (sem_post (&thread_2_semaphore) !=3D 0) > + abort (); > + > + /* Wait for thread 2 to complete its actions. */ > + if (sem_wait (&thread_1_semaphore) !=3D 0) > + abort (); > + > + return 1; > +} > + > +void > +do_segfault () > +{ > + volatile int *p =3D 0; > + *p =3D 0; /* Segfault here. */ > +} > + > +void * > +worker_func (void *arg) > +{ > + int tid =3D *((int *) arg); > + > + /* Let the main thread know that this worker has started. */ > + if (sem_post (&startup_semaphore) !=3D 0) > + abort (); > + > + switch (tid) > + { > + case 0: > + /* Wait for MUTEX to become available, then pass through the > + conditional breakpoint location. */ > + if (pthread_mutex_lock (&mutex) !=3D 0) > + abort (); > + global_var =3D 99; /* Conditional breakpoint here. */ > + if (pthread_mutex_unlock (&mutex) !=3D 0) > + abort (); > + break; > + > + case 1: > + if (sem_wait (&thread_2_semaphore) !=3D 0) > + abort (); > + do_segfault (); > + if (sem_post (&thread_1_semaphore) !=3D 0) > + abort (); > + > + /* Fall through. */ > + default: > + /* Wait until we are allowed to finish. */ > + if (sem_wait (&finish_semaphore) !=3D 0) > + abort (); > + break; > + } > +} > + > +void > +stop_marker () > +{ > + global_var =3D 99; /* Stop marker. */ > +} > + > +/* The main program entry point. */ > + > +int > +main () > +{ > + pthread_t threads[NUM_THREADS]; > + int args[NUM_THREADS]; > + void *retval; > + > + /* An alarm, just in case the thread deadlocks. */ > + alarm (300); > + > + /* Semaphore initialization. */ > + if (sem_init (&startup_semaphore, 0, 0) !=3D 0) > + abort (); > + if (sem_init (&finish_semaphore, 0, 0) !=3D 0) > + abort (); > + if (sem_init (&thread_1_semaphore, 0, 0) !=3D 0) > + abort (); > + if (sem_init (&thread_2_semaphore, 0, 0) !=3D 0) > + abort (); > + > + /* Lock MUTEX, this prevents the first worker thread from rushing ahea= d. */ > + if (pthread_mutex_lock (&mutex) !=3D 0) > + abort (); > + > + /* Worker thread creation. */ > + for (int i =3D 0; i < NUM_THREADS; i++) > + { > + args[i] =3D i; > + pthread_create (&threads[i], NULL, worker_func, &args[i]); > + } > + > + /* Wait for every thread to start. */ > + for (int i =3D 0; i < NUM_THREADS; i++) > + { > + if (sem_wait (&startup_semaphore) !=3D 0) > + abort (); > + } > + > + /* Unlock the first thread so it can proceed. */ > + if (pthread_mutex_unlock (&mutex) !=3D 0) > + abort (); > + > + /* Wait for the first thread only. */ > + pthread_join (threads[0], &retval); > + > + /* Now post FINISH_SEMAPHORE to allow all the other threads to finish.= */ > + for (int i =3D 1; i < NUM_THREADS; i++) > + sem_post (&finish_semaphore); > + > + /* Now wait for the remaining threads to complete. */ > + for (int i =3D 1; i < NUM_THREADS; i++) > + pthread_join (threads[i], &retval); > + > + /* Semaphore cleanup. */ > + sem_destroy (&finish_semaphore); > + sem_destroy (&startup_semaphore); > + sem_destroy (&thread_1_semaphore); > + sem_destroy (&thread_2_semaphore); > + > + stop_marker (); > + > + return 0; > +} > diff --git a/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp > b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp > new file mode 100644 > index 00000000000..3341ff33f19 > --- /dev/null > +++ b/gdb/testsuite/gdb.threads/infcall-from-bp-cond-timeout.exp > @@ -0,0 +1,156 @@ > +# Copyright 2020 Free Software Foundation, Inc. Please note the copyright year. > + > +# 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 . > + > +# Tests inferior calls executed from a breakpoint condition in > +# a multi-threaded program. > +# > +# This test has the inferior function call timeout, and checks how GDB > +# handles this situation. > + > +standard_testfile > + > +if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \ > + {debug pthreads}] } { > + return > +} > + > +set cond_bp_line [gdb_get_line_number "Conditional breakpoint here"] > +set final_bp_line [gdb_get_line_number "Stop marker"] > +set segfault_line [gdb_get_line_number "Segfault here"] > + > +# Setup GDB based on TARGET_ASYNC and TARGET_NON_STOP. Setup some > +# breakpoints in the inferior, one of which has an inferior call > +# within its condition. > +# > +# Continue GDB, the breakpoint with inferior call will be hit, but the > +# inferior call will never return. We expect GDB to timeout. > +# > +# The reason that the inferior call never completes is that a second > +# thread, on which the inferior call relies, either hits a breakpoint > +# (when OTHER_THREAD_BP is true), or crashes (when OTHER_THREAD_BP is > +# false). > +proc run_test { target_async target_non_stop other_thread_bp } { > + save_vars { ::GDBFLAGS } { > + append ::GDBFLAGS " -ex \"maint set target-non-stop $target_non_stop\"" > + append ::GDBFLAGS " -ex \"maintenance set target-async ${target_async}\= "" > + > + clean_restart ${::binfile} > + } > + > + if {![runto_main]} { > + fail "run to main" > + return > + } > + > + # The default timeout for indirect inferior calls (e.g. inferior > + # calls for conditional breakpoint expressions) is pretty high. > + # We don't want the test to take too long, so reduce this. > + # > + # However, the test relies on a second thread hitting some event > + # (either a breakpoint or signal) before this timeout expires. > + # > + # There is a chance that on a really slow system this might not > + # happen, in which case the test might fail. > + # > + # However, we still allocate 5 seconds, which feels like it should > + # be enough time in most cases, but maybe we need to do something > + # smarter here? Possibly we could have some initial run where the > + # inferior doesn't timeout, but does do the same interaction Typo: "does do" > + # between threads, we could time that, and use that as the basis > + # for this timeout. For now though, we just hope 5 seconds is > + # enough. > + gdb_test_no_output "set indirect-call-timeout 5" > + > + gdb_breakpoint \ > + "${::srcfile}:${::cond_bp_line} if (condition_func ())" > + set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ > + "get number for conditional breakpoint"] > + > + gdb_breakpoint "${::srcfile}:${::final_bp_line}" > + set final_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ > + "get number for final breakpoint"] > + > + # The thread performing an inferior call relies on a second > + # thread. The second thread will segfault unless it hits a > + # breakpoint first. In either case the initial thread will not > + # complete its inferior call. > + if { $other_thread_bp } { > + gdb_breakpoint "${::srcfile}:${::segfault_line}" > + set segfault_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \ > + "get number for segfault breakpoint"] > + } > + > + # When non-stop mode is off we get slightly different output from GD= B. > + if { [gdb_is_remote_or_extended_remote_target] && $target_non_stop = =3D=3D "off" } { String comparison comment applies here, too. > + set stopped_line_pattern "Thread ${::decimal} \"\[^\r\n\"\]+\" received= signal > SIGINT, Interrupt\\." > + } else { > + set stopped_line_pattern "Thread ${::decimal} \"\[^\r\n\"\]+\" stopped\= \." > + } > + > + gdb_test "continue" \ > + [multi_line \ > + $stopped_line_pattern \ > + ".*" \ > + "Error in testing condition for breakpoint ${bp_num}:" \ > + "The program being debugged timed out while in a function called f= rom GDB\\." \ > + "GDB remains in the frame where the timeout occurred\\." \ > + "To change this behavior use \"set unwind-on-timeout on\"\\." \ > + "Evaluation of the expression containing the function" \ > + "\\(condition_func\\) will be abandoned\\." \ > + "When the function is done executing, GDB will silently stop\\."] \ > + "expected timeout waiting for inferior call to complete" > + > + # Remember that other thread that either crashed (with a segfault) > + # or hit a breakpoint? Now that the inferior call has timed out, > + # if we try to resume then we should see the pending event from > + # that other thread. > + if { $other_thread_bp } { > + gdb_test "continue" \ > + [multi_line \ > + "Continuing\\." \ > + ".*" \ > + "" \ > + "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${segfault_bp_nu= m}, > do_segfault \[^\r\n\]+:${::segfault_line}" \ > + "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+"] \ > + "hit the segfault breakpoint" > + } else { > + gdb_test "continue" \ > + [multi_line \ > + "Continuing\\." \ > + ".*" \ > + "Thread ${::decimal} \"infcall-from-bp\" received signal SIGSEGV, > Segmentation fault\\." \ > + "\\\[Switching to Thread \[^\r\n\]+\\\]" \ > + "${::hex} in do_segfault \\(\\) at \[^\r\n\]+:${::segfault_line}" \ > + "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+"] \ > + "hit the segfault" > + } > +} > + > +foreach_with_prefix target_async {"on" "off" } { > + > + if { $target_async =3D=3D "off" } { And here, again. > + # GDB can't timeout while waiting for a thread if the target > + # runs with async-mode turned off; once the target is running > + # GDB is effectively blocked until the target stops for some > + # reason. > + continue > + } > + > + foreach_with_prefix target_non_stop {"off" "on"} { > + foreach_with_prefix other_thread_bp { true false } { > + run_test $target_async $target_non_stop $other_thread_bp > + } > + } > +} > -- > 2.25.4 Regards -Baris Intel Deutschland GmbH Registered Address: Am Campeon 10, 85579 Neubiberg, Germany Tel: +49 89 99 8853-0, www.intel.de Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva = Chairperson of the Supervisory Board: Nicole Lau Registered Office: Munich Commercial Register: Amtsgericht Muenchen HRB 186928