From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from NAM11-CO1-obe.outbound.protection.outlook.com (mail-co1nam11on2040.outbound.protection.outlook.com [40.107.220.40]) by sourceware.org (Postfix) with ESMTPS id C778D3858D32 for ; Tue, 23 Aug 2022 15:01:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C778D3858D32 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=gCQWP8x04UfGEQslJ4IoEQbWYlJMAxARkHoyA4b+vBSF8XsUt/p94m1hJE4r35vVAsCoRidhrVx7r5Ldc8VqfHsqq9Ojt8iVta4jKT1n5vlXEpkK8OAfsVs0koYXpJ0kEy/BXxk22pJdw1mB9YAUD141w69wNc2h5viWLYEzRTMhtvZj5thBWctx3pyFIkSxAC5C3rkeNvZkZItk7KLjyaM8wzae1e7v5c8+9RjXOoc4Itvb5syC+S9efQodN3UbalBGxy1MpLRnrWqXYyj+rS5FRQYtKuj2mEA1FKlLdOK3FFaJI7AVuRNovt1b0kd9G5MwfznKCPFN+dfAznkcPw== 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=RNhsv7sKMB/4ICnkCw4xpZ3hFMTyVHOO4Fy1TMtvZyc=; b=gOLrpRgZ6L6YAzXNDEGzTGk0ofAJp2bDQj2vkQ176UaW8kcxoloouojlaxMEqEShxWBBwk0KEp3Ci2kc+NuBZK55bh14kTaW+laVD0k83N8hbRbJiSNeKYbU8FnxMDcaAy0GxwoOPAq/F55cZjHAZWXO4vxErh0JfLzEMqDEtoYfp6u3mx18wn9l9SVTYI7VEiCUix2yeehi9BWWDpckXlczEy9wQjn5468VTosMQle0IMZFNiXn+NBprHof2YyJF//UTfXnriKtfcE3rNa/ONpTWTF2RFNnKxZrTInSsAU0FZkSOtcC41QmJP6RlPn5EMej3jAwjULpipoYBvj3dg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=amd.com; dmarc=pass action=none header.from=amd.com; dkim=pass header.d=amd.com; arc=none Received: from DM4PR12MB5745.namprd12.prod.outlook.com (2603:10b6:8:5c::7) by PH8PR12MB7110.namprd12.prod.outlook.com (2603:10b6:510:22e::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5546.22; Tue, 23 Aug 2022 15:01:12 +0000 Received: from DM4PR12MB5745.namprd12.prod.outlook.com ([fe80::9155:e480:2c04:aed1]) by DM4PR12MB5745.namprd12.prod.outlook.com ([fe80::9155:e480:2c04:aed1%3]) with mapi id 15.20.5546.023; Tue, 23 Aug 2022 15:01:12 +0000 Message-ID: Date: Tue, 23 Aug 2022 16:01:05 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.11.0 Subject: [PING^2] [PATCH] gdb/linespec: Improve sliding breakpoints Content-Language: en-US To: "gdb-patches@sourceware.org" Cc: "lsix@lancelotsix.com" References: From: Lancelot SIX In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-ClientProxiedBy: AS9P250CA0022.EURP250.PROD.OUTLOOK.COM (2603:10a6:20b:532::28) To DM4PR12MB5745.namprd12.prod.outlook.com (2603:10b6:8:5c::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 0572244e-af9a-4a62-a952-08da8518516d X-MS-TrafficTypeDiagnostic: PH8PR12MB7110:EE_ X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: xpzSyCSAC4g1k59Pk8ApIOVURlVEnKcE1SwjTEftPaexRfPRaBWLb4Cn93DkWMHZBjQrkkSsvPp6p6tx/eUPvHwmfNdhXT/fb/5sAxEvlC0bJHo9RoPDUxkEe6VrD+aCkikSJcnLaa/lUB3Rz0rHswfgne+nSwiQ1WbZAsWFTHeRdAr1417TJCITGsEWSKR6mbVFMfnJwTwfNb87wwXYGpBEIYJfZ/S5mlDx/5nO//d3VRCb7EQRDQR7EB4MEWnx1n6flmqM11DaXB+bg3KH08eiohfvB/RqeewYrJuVQrPy4J4MX4S0pTE4wU3tA8tJG0OJWNgAV1m1P5I4uDEXAKJ42HNh3puvKAvs0DnHjx1p6cz8Fn/An9LECALOkJ/zHaxZbsW0sLCzlps9d8Q+frwNwXmF4AL+Q6tYuLI1/8j58+1L0GAmcKnYlg3RSZVULvAPfkbgOz5ocQ+smzPcefMtC/vjJDvn8YbAFFdyERgqgWt0UEZQzihbb3glGSFV3nCN5fnP0dSdhwiwwCheFcO0obmej7CLfpPOhWCq4t8vJbvUPwhizxQe5GJwY+hqt8OCSSe8mP8PIfM2Z5p2WJcB/FqLgmHP65jteWCGw+YBYtrHhDGniqr7o6b390TWVuCqTZKLvl7ODdPAr+6HCMU77c7gStCWSJFXPvi6EG+jxgC4Jnlb7duYQvSGA6rSmQMWwfU1d9GEeOJSL86qkFD+bPuDu3qI5h7HF90TGvjmPZEt3D3KXjy1iSGR/D3nH8wlVC7SKRLvLuV2JRJK2y8Yryj5dyYOsQeSQh5UauQRW3pMSto9sj5nwql5oquxVIkurWMfMD1ugmMUe7W8moy/Eg+FFqXb4alv01/42SluoK9rAyZGI6ntU31LwqsFHr4y967hXcvbIV+oUzpDkQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:DM4PR12MB5745.namprd12.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230016)(4636009)(366004)(136003)(376002)(39860400002)(396003)(346002)(6916009)(316002)(6666004)(8936002)(36756003)(2616005)(53546011)(2906002)(186003)(41300700001)(5660300002)(30864003)(6506007)(26005)(6512007)(86362001)(31696002)(83380400001)(31686004)(66476007)(66946007)(66556008)(4326008)(478600001)(6486002)(8676002)(38100700002)(966005)(81973001)(2004002)(43740500002)(45980500001); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?TlJnNmo5YVFXMW5FQnJaMkZ0SW5sdFd1Nkdzam94R2JLVXVzZkZoVytINE0w?= =?utf-8?B?eGlnZ1BTdUhkbnlyWTdrVHZXcG9hbWFKcjZYQjJYSk1wU2VFNkRCQWRSS3hB?= =?utf-8?B?M2xzbS9TZjk1NzhqRHkyV0szS0ZSU3g2R2JxUXJEVWliYlNSazNRYjV3T3Er?= =?utf-8?B?NFhQQWN1ZFp5RWxYMkl3VUlLQmtjcnhZdnRZRmUrSGMyYUVxaW56SGtaZG9Z?= =?utf-8?B?VjJnMUtNSk85RWM4ekcxOFRUVW5sMFptRXZiK0dNaENnYmdDUWx4TllPcFpR?= =?utf-8?B?VE80T2N4K3l6WlpETWJuMnJFdjdJSURERnJ0dDVmYzlHZXlUMkVISDhSSnZw?= =?utf-8?B?UkNEU2VzbWJrcGNIZDZnTktOc0pKc1NBNlI1dU1MNkdxaFdXVmxHbzhmNHJG?= =?utf-8?B?WlhyWm50WnpMWGZBbWUxQTdkRWJyd2FSTnVvcmtwNmN5eTZ4SVM4aW9uL25W?= =?utf-8?B?dWViMlVqdTM4bCtPdDdDK0NKczYvaWNlcE43Y2MrQ0Qzdjg3VVNOczlkaGk0?= =?utf-8?B?OWJTb1dZam5MQit5OCtpQ0VSQnpickhtbmlUdlZJcGtybThqdndLQVBGdE42?= =?utf-8?B?eXR6OFNieUxxeExGRU40QXYweFVxOWc3clZuNmhRdTN5d3VSODFvajdobUVF?= =?utf-8?B?RUYrU0NMbUVOblcwSVVYWTNuQ0dYWndZZjBoYTVPdzllY0cvQUFlRFJFSWJX?= =?utf-8?B?eHUvTjlSUFdJSHNOcDNUNVJxVmVSV1F1WEN0N1g5TnBLU1k3M3A3dm8yMGcy?= =?utf-8?B?dW9XdTB5d0dqYmtnbFkrRmQzaHE5dWlRMGdsbjBpY3lJVXhVWURyRVNuVnIr?= =?utf-8?B?eis1NkF0SFRLNm95Q3pFYWVzODBKWUF0cFdUSFNZWDA3RTM4NnM1UWtKVFJS?= =?utf-8?B?S0plSTlGY3pGSWdwcmpVbkJuQnB2VFBXRnNQN3k5QVdVT1dBYmVucHJFL1VD?= =?utf-8?B?MS9ydEdMQXhWSFFXVUs0N3dVRVJWZ0RwS0dqS1hISTNVQ3FrUnA5QklML09t?= =?utf-8?B?K2x2azBDdXN1RVdwQUQ5R1Y4WFFkN21PMXFIM1RuWVRzV3c3bDJXZHV6SWtv?= =?utf-8?B?bHRzYVBwRkpQNWx1OGFJVjFON3dncmtpZi9QdkpYRUNDakttMzg0ZmRFNkJm?= =?utf-8?B?K3l3V1NCNjdxTVB0Q0tiRWNXQnBSTTdTZWR0ZVVqN2dRajJPU0FFUHVhYzlB?= =?utf-8?B?NmNPR2NQWEZUbm5QdWU3K0hHMTg3QWlIVnpiNUZGUFRCdEJwSzBpenU3b0Jx?= =?utf-8?B?RWhKbW4zRUVLQXJuaWtnclg0aUhLempocHA1Mm53M2UvajJhYXRrVkU2dHNu?= =?utf-8?B?RUh1RW5pSEZGN0RBR0xlZHRxS2U4Y3BPamRacTZ3VVdVcit3NzVuV0MwWlNG?= =?utf-8?B?Q1dmU0J6WnhTUTk4OWJRYkZyYTBqcmw3QUkzNmFzYXJHVDg4L3RZZU1Nb2k2?= =?utf-8?B?MFdmSFFVRmVBVWJKRHNlSHNyY3FHdmRMZTNpMDJLVFkrMEVBQk53aG55WFhs?= =?utf-8?B?bUZyOUFEOC9DU04rYnpVUzVGWXJDMGZxUDhFZzRuc1FKbjV2eWZ5Rk8xaExu?= =?utf-8?B?L0YwSDdLc1RqK1dXTG9YaGsxYUZROS9PR0dSZmp5MnJSVS9DNjExRWkxWjdT?= =?utf-8?B?UnJzRExtQVMyV2REZHVuQVNibFNxbkNZaUhBL2hqek1PUVBYeW9HMk1HTWxr?= =?utf-8?B?dHdwdnp4UEw1ZU9IWmVNOExBTWxmOWU0U3RnTHFaYWpVbzBQVGVPS2ZYeUxi?= =?utf-8?B?cWxvNjE3anhydzFYM3VIWGJZRVVLYUJTZ08rSUg5WVFPZ0R3QnVGSkFlRUgz?= =?utf-8?B?QkttVngwSXEyK2J6U2J4MFNHMUlGN0VmUUhqSjN1UlNtU3A0K2NNYlp1YnN0?= =?utf-8?B?UU9FOEVEcDFUb051YThXaGhLaE9tLzhDYjU1ZDJVYjZzK3A0WnV5TDROL05v?= =?utf-8?B?SFJwZk0xc3BubFdkUVcyZWI4S2JEdWF6Zm5zYWxTOVlJUUl0OG1uMVhndG5I?= =?utf-8?B?dWV4R25JMEN1YWZJMVdGODgrWG1qb3NzNWwwR3ZzaEpkdnlYTGZmWndBeWI3?= =?utf-8?B?bGtjcUtQbm5YM2RqYnUycXdEOC9HaDVnYkw1S3Uzb1hkbDRSTlZqTWlZdmhG?= =?utf-8?Q?HGT3/zeOC3xlBKlEbFQYfLwrY?= X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-Network-Message-Id: 0572244e-af9a-4a62-a952-08da8518516d X-MS-Exchange-CrossTenant-AuthSource: DM4PR12MB5745.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Aug 2022 15:01:12.0852 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 0yPlhLojdgrGzYO+SeZfy3PKgjH1UeaCs394bMBNF9kCcjTPSgeTEBIWSSupIUWyk1nMUu0YLrtLpSKJw6oWXA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR12MB7110 X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 Aug 2022 15:01:24 -0000 Kindly pinging for thoughts and feedbacks. Best, Lancelot. On 27/07/2022 14:11, Six, Lancelot wrote: > [Public] > > Hi > > I was wondering if anyone has comments and or opinions about the change proposed in this patch. > > Best, > Lancelot. > >> -----Original Message----- >> From: Six, Lancelot >> Sent: 17 June 2022 17:08 >> To: gdb-patches@sourceware.org >> Cc: lsix@lancelotsix.com; Six, Lancelot >> Subject: [PATCH] gdb/linespec: Improve sliding breakpoints >> >> Hi, >> >> Here is proposition to slightly update the breakpoint sliding algorithm >> in GDB. >> >> This patch must be applied on top of >> https://sourceware.org/pipermail/gdb-patches/2022-April/187686.html >> which was submitted by Simon Marchi a couple of months. This needs >> small updates as the BLOCK_ENTRY_PC and SYMBOL_BLOCK_VALUE are no >> longer used. As a consequence >> >> BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym)) >> >> should be replaced with >> >> sym->value_block ()->entry_pc () >> >> This patch have been regression tested on x86_64-Linux. All comments >> and feedbacks are welcome. >> >> Best, >> Lancelot. >> >> --- >> >> The algorithm used to place a breakpoint by line approximately goes as >> follow: >> >> - Look for all the PCs which maps directly to the desired line >> - If any PC is found, place a breakpoint at each found PC. >> - If no PC maps to the desired line: >> - Search for the lower line number in the line table which is higher >> than the desired line, and has some object code associated to it. >> - List all PCs which maps to this line number. >> - Place a breakpoint at each PC in the list above. >> >> There are situations where this heuristic is not sufficient. If we >> consider the following c++ code: >> >> 12 template >> 13 T func (T a, T b) >> 14 { >> 15 /* Break here. */ >> 16 if constexpr (std::is_integral_t) >> 17 return a; >> 18 else >> 19 return b; >> 20 } >> >> Given the current algorithm, if the user tries to set a breakpoint at >> line 15, here is what happens: >> >> - Search PCs mapping to L15, there is none ; >> - Search for the first line number above L16 with code, this is L17 ; >> - List all PCs mapping to L17 and a breakpoints at insert a breakpoint at >> each ; >> >> Now lets suppose that this templated function has been instantiated both >> for an integral type (int) and non-integral type (float). If we follow >> the algorithm, no breakpoint will ever be inserted in func, >> while there will be a breakpoint in func. >> >> I came across a less obvious variation of this case where an inlined >> function had different optimization opportunities for different instances. >> As a consequence, some instances had the first actual line of code >> different than the other, making the breakpoint be missed and the user >> confused. To add to the confusion, the instances which have code mapped >> to the lowest line above the user specified linespec only appeared in a >> shared library conditionally loaded, making the breakpoint stop depend on >> whether or not the said shared library was loaded or not. >> >> This patch is a proposition to adapt the algorithm in order to cover the >> scenario exposed above. To do so, this patch ends up scanning >> independently for the best candidate in the various blocks composing >> the line table structures (a block being a succession of >> linetable_entries terminated by an entry with line == 0). >> >> The line table for the example program above looks something like: >> >> (gdb) maintenance info line-table missed >> symtab: /[...]/missed_pb.cc ((struct symtab *) 0x6210000f0500) >> linetable: ((struct linetable *) 0x6210001a1220): >> INDEX LINE ADDRESS IS-STMT PROLOGUE-END >> ... >> 17 END 0x00000000000011d3 Y >> 18 13 0x00000000000011d3 Y <-- func >> 19 19 0x00000000000011e5 Y >> 20 20 0x00000000000011ea Y >> 21 END 0x00000000000011ec Y >> 22 13 0x00000000000011ec Y <-- func >> 23 17 0x00000000000011fa Y >> 24 20 0x00000000000011fd Y >> 25 END 0x00000000000011ff Y >> >> The first block listed (starting at 0x11d3) is func, and the >> second starting at 0x11ec is func. >> >> The proposed algorithm analyzes each block independently. The first step >> is to decide if a block contains the line the user is interested in (a.k.a >> the target). In our example, this is L15. A block is considered to match >> if it contains at least one instruction mapped to a line before the target >> and at least one instruction mapped to a line after the target. In other >> words this means that will select all blocks where: >> >> - there is at least one instruction mapped to a line L such as L <= target >> - there is at least one instruction mapped to a line M such as M >= target >> >> For each block which satisfies this condition, we select the lowest line >> number above our target, and select all instructions mapping to this line >> number (there might be multiple). In our example the func block >> satisfies the condition (we have line 13 and 19), so we insert breakpoints >> at the PCs mapped to L19. Similarly, the func block is selected >> (thanks to L13 and L17), and we insert breakpoints at all PCs mapped to >> L17. >> >> The core of this heuristic is implemented in find_best_le_for_symtab_line. >> >> There are however some cases which are still problematic, where the >> first line after the target is the first line of the block we are >> looking for. In such situation the algorithm would find nothing where >> we would want to select 0x11d3 and 0x11ec (both mapping to L13). In >> order to solve this, the algorithm first looks for the lowest line >> number following the user specified target as this is done before this >> patch (here the first line with associated code following L12 which is >> L13). Once this is figured out, this new target (L13) is passed to the >> algorithm above (find_best_le_for_symtab_line). >> >> This is safe to do because we know that there is no line between the user >> target (included) and this new target. Therefore, whatever >> find_best_le_for_symtab_line returns, it must map to lines numbers above >> (inclusive) the new target. >> >> Finally, the testsuite showed an interesting regression. Let's suppose >> we have: >> >> 1 struct Foo { Foo () {} }; >> 2 Foo f1; >> 3 void bar () >> 4 { >> 5 /* break here. */ >> 6 do_something (); >> 7 } >> 8 Foo f2; >> >> Inspecting the linetable, we have a code block containing L2 and L8 (so >> over line 5). If a user was to insert a breakpoint somewhere in L5, the >> algorithm shown above would also insert a breakpoint at L8. To solve >> this, this patch uses the fact that L2 and L8 are, from dwarf's >> perspective in a artificial block which corresponds to the static >> initialization. So if among multiple candidates, some are part of a >> virtual function and some are not, we only keep the ones in the non >> virtual function. >> >> This proposed new algorithm will not solve all possible cases. For >> example, if the func function is inlined multiple times in the same block >> for different template parameters, the lookup will process all of those as >> part of the same scope. Solving such situation would require heavier >> works. I think that this change, while not covering every scenarios is >> still a step in the right direction. >> >> All feedbacks and thoughts are welcome. >> >> Regression tested on x86_64 GNU/Linux. >> >> Change-Id: I8291f9e1a3522934a0f418dfc565cebb86cff730 >> --- >> gdb/linespec.c | 93 ++++++++++++++++++- >> gdb/symtab.c | 45 +++++++++ >> gdb/symtab.h | 14 +++ >> .../gdb.linespec/breakpoint-sliding.cc | 70 ++++++++++++++ >> .../gdb.linespec/breakpoint-sliding.exp | 82 ++++++++++++++++ >> 5 files changed, 301 insertions(+), 3 deletions(-) >> create mode 100644 gdb/testsuite/gdb.linespec/breakpoint-sliding.cc >> create mode 100644 gdb/testsuite/gdb.linespec/breakpoint-sliding.exp >> >> diff --git a/gdb/linespec.c b/gdb/linespec.c >> index da9e35c5035..1e8679cd027 100644 >> --- a/gdb/linespec.c >> +++ b/gdb/linespec.c >> @@ -2092,9 +2092,42 @@ create_sals_line_offset (struct linespec_state >> *self, >> if (intermediate_results.empty () && best_entry != NULL) >> { >> was_exact = false; >> - intermediate_results = decode_digits_ordinary (self, ls, >> - best_entry->line, >> - &best_entry); >> + /* We did not find an exact match for the line we are looking for. >> + As a consequence, we are now looking for the next best line. >> + However, the next best line does not have to be the same across >> + the entire program. If we consider the following code: >> + >> + 12 template >> + 13 T select (T a, T b) >> + 14 { >> + 15 // Break here. >> + 16 if constexpr (std::is_integral_t) >> + 17 return a; >> + 18 else >> + 19 return b; >> + 20 } >> + >> + For a function like the above, the next best line is L17 if T is >> + an integral type, but should be L19 if T is not. As a >> + consequence we try to search for the next best line independently >> + in each code block (a code block being a contiguous section of a >> + line table terminated by an entry with line == 0). */ >> + for (const auto &elt : ls->file_symtabs) >> + { >> + program_space *pspace = elt->compunit ()->objfile ()->pspace; >> + for (const linetable_entry *le >> + : find_best_le_for_symtab_line (elt->linetable (), >> + best_entry->line)) >> + { >> + symtab_and_line sal; >> + sal.pspace = pspace; >> + sal.symtab = elt; >> + sal.line = le->line; >> + sal.explicit_line = true; >> + sal.pc = le->pc; >> + intermediate_results.push_back (std::move (sal)); >> + } >> + } >> } >> >> /* For optimized code, the compiler can scatter one source line >> @@ -2110,6 +2143,25 @@ create_sals_line_offset (struct linespec_state >> *self, >> gdb::def_vector filter (intermediate_results.size ()); >> gdb::def_vector blocks (intermediate_results.size ()); >> >> + /* Artificial code blocks can produce false positives. Consider >> + >> + 1 struct Foo { Foo () {} }; >> + 2 Foo f1; >> + 3 void bar () >> + 4 { >> + 5 // break here. >> + 6 do_something (); >> + 7 } >> + 8 Foo f2; >> + >> + In this example, if the user asked for a breakpoint in L5, the above >> + algorithm will select L6 and L8. L6 is selected because the we have >> + an artificial block (marked by DW_AT_artificial) generated to cover >> + the static initializations and this block covers code from line 2 to >> + line 8. To avoid this false positive, reject candidates in artificial >> + blocks if we also have candidates in non artificial blocks. */ >> + bool any_nonartificial = false; >> + >> for (i = 0; i < intermediate_results.size (); ++i) >> { >> set_current_program_space (intermediate_results[i].pspace); >> @@ -2117,6 +2169,13 @@ create_sals_line_offset (struct linespec_state >> *self, >> filter[i] = 1; >> blocks[i] = block_for_pc_sect (intermediate_results[i].pc, >> intermediate_results[i].section); >> + >> + if (!any_nonartificial && blocks[i] != nullptr) >> + { >> + struct symbol *func = block_containing_function (blocks[i]); >> + any_nonartificial >> + = (func != nullptr && !func->is_artificial ()); >> + } >> } >> >> for (i = 0; i < intermediate_results.size (); ++i) >> @@ -2171,6 +2230,34 @@ create_sals_line_offset (struct linespec_state >> *self, >> && val.line < sym->line ()) >> continue; >> >> + /* If we did not find an exact match, the above heuristic might >> + find some false positives. >> + >> + Lets consider (with Foo having a non trivial ctor): >> + >> + 9 struct Foo { Foo () {} }; >> + 10 Foo f1; >> + 11 int bar () >> + 12 { >> + 13 // Break here. >> + 14 return 42; >> + 15 } >> + 16 Foo f2; >> + >> + When the user tries to insert a breakpoint it L13, the >> + algorithm sees a code path from L10 to L16 (in static >> + initialization), and will consider L16 as a candidate. >> + However the user clearly intended to break in bar. >> Therefore, >> + if we see that there is at least 1 breakpoint in a non >> + artificial function (bar), ignore the hit in the static >> + initialization. >> + */ >> + if (!was_exact >> + && any_nonartificial >> + && sym != nullptr >> + && sym->is_artificial ()) >> + continue; >> + >> if (self->funfirstline) >> skip_prologue_sal (sal); >> >> diff --git a/gdb/symtab.c b/gdb/symtab.c >> index 03aa2a96b87..1b03e6fce8e 100644 >> --- a/gdb/symtab.c >> +++ b/gdb/symtab.c >> @@ -3541,6 +3541,51 @@ find_pcs_for_symtab_line (struct symtab >> *symtab, int line, >> return result; >> } >> >> +/* See symtab.h. */ >> + >> +std::vector >> +find_best_le_for_symtab_line (struct linetable *lt, int line) >> +{ >> + std::vector res; >> + >> + if (lt == nullptr || line < 0) >> + return res; >> + >> + /* Tells if in the current block we found at least one PC mapping to a line >> + before LINE. */ >> + bool found_preceding = false; >> + const int nitems = lt->nitems; >> + std::vector best_candidates; >> + >> + for (int i = 0; i < nitems; ++i) >> + { >> + struct linetable_entry &item = lt->item[i]; >> + found_preceding >> + = found_preceding || (item.line > 0 && item.line <= line); >> + >> + if (item.is_stmt && item.line >= line >> + && (best_candidates.empty () >> + || item.line <= best_candidates.front ()->line)) >> + { >> + if (!best_candidates.empty () >> + && item.line < best_candidates.front ()->line) >> + best_candidates.clear (); >> + best_candidates.push_back (&item); >> + } >> + else if (item.line == 0) >> + { >> + if (found_preceding) >> + res.insert (res.end (), best_candidates.begin (), >> + best_candidates.end ()); >> + >> + found_preceding = false; >> + best_candidates.clear (); >> + } >> + } >> + >> + return res; >> +} >> + >> >> >> >> /* Set the PC value for a given source file and line number and return true. >> Returns false for invalid line number (and sets the PC to 0). >> diff --git a/gdb/symtab.h b/gdb/symtab.h >> index ac902a4cbbe..94bea02cb43 100644 >> --- a/gdb/symtab.h >> +++ b/gdb/symtab.h >> @@ -2624,6 +2624,20 @@ void iterate_over_symtabs (const char *name, >> std::vector find_pcs_for_symtab_line >> (struct symtab *symtab, int line, struct linetable_entry **best_entry); >> >> +/* Given a linetable, look for entries which can map to line LINE. >> + >> + The result is the set of entries which: >> + 1) Are part of a block (i.e. a sequence of entries terminated by an entry >> + with line == 0) containing at least one statement entry with line above >> + or equal to LINE, and at least one statement entry with line below or >> + equal to LINE. >> + 2) Are statement entries (is_stmt == 1) >> + 3) Have line equal to the lowest statement line number greater or equal to >> + LINE within the block they are part of. */ >> + >> +std::vector find_best_le_for_symtab_line >> + (struct linetable *lt, int line); >> + >> /* Prototype for callbacks for LA_ITERATE_OVER_SYMBOLS. The callback >> is called once per matching symbol SYM. The callback should return >> true to indicate that LA_ITERATE_OVER_SYMBOLS should continue >> diff --git a/gdb/testsuite/gdb.linespec/breakpoint-sliding.cc >> b/gdb/testsuite/gdb.linespec/breakpoint-sliding.cc >> new file mode 100644 >> index 00000000000..3ae6b563cdf >> --- /dev/null >> +++ b/gdb/testsuite/gdb.linespec/breakpoint-sliding.cc >> @@ -0,0 +1,70 @@ >> +/* This testcase is part of GDB, the GNU debugger. >> + >> + Copyright (C) 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 . */ >> + >> +#if __cplusplus >= 201703L >> +#include >> + >> +template >> +T >> +foo (T a, T b) >> +{ >> + T ret; >> + /* In foo break here. */ >> + if constexpr (std::is_integral_v) >> + ret = a; /* break in foo. */ >> + else >> + ret = b; /* break in foo. */ >> + >> + return ret; >> +} >> + >> +struct NonIntegral >> +{ >> + int m; >> +}; >> + >> +#endif >> + >> +struct St >> +{ >> + St () >> + { /* Empty. */ } >> +}; >> + >> +St st1; >> + >> +static int >> +between_static_init () >> +{ >> + /* between_static_init break here. */ >> + return 42; /* break in between_static_init. */ >> +} >> + >> +St st2; >> + >> +int main () >> +{ >> + >> +#if __cplusplus >= 201703L >> + foo (1, 2); >> + foo ({ 1 }, { 2 }); >> +#endif >> + >> + between_static_init (); >> + >> + return 0; >> +} >> diff --git a/gdb/testsuite/gdb.linespec/breakpoint-sliding.exp >> b/gdb/testsuite/gdb.linespec/breakpoint-sliding.exp >> new file mode 100644 >> index 00000000000..9b79c419e9b >> --- /dev/null >> +++ b/gdb/testsuite/gdb.linespec/breakpoint-sliding.exp >> @@ -0,0 +1,82 @@ >> +# Copyright (C) 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 . >> + >> +# This testcase exercises breakpoint sliding when the user tries to set >> +# a breakpoint at a line number which has no code associated to it. GDB >> +# should then place breakpoint at the first line following the one given >> +# by the user in each code block composing the program space, given that >> +# the code block "covers" the line asked by the user. >> + >> +if { [skip_cplus_tests] } { >> + return -1 >> +} >> + >> +standard_testfile .cc >> + >> +# Part of the test require c++17. If the used compiler does not support >> +# it, fallback only doing part of the tests. >> +set skip_cpp17 0 >> + >> +if {[prepare_for_testing "failed to prepare with c++17" $testfile \ >> + $srcfile {debug c++ additional_flags=-std=c++17}]} { >> + set skip_cpp17 1 >> + if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ >> + {debug c++}]} { >> + return -1 >> + } >> +} >> + >> +proc_with_prefix test_sliding_per_block {} { >> + if {$::skip_cpp17} { >> + return >> + } >> + >> + set loc [gdb_get_line_number "In foo break here."] >> + gdb_test "break $loc" \ >> + "Breakpoint $::decimal.* \\(2 locations\\)" \ >> + "slide to if constexpr" >> + >> + set loc_in_int_instance [gdb_get_line_number "break in foo"] >> + set loc_in_struct_instance [gdb_get_line_number "break in >> foo"] >> + set seen_int_pb 0 >> + set seen_struct_bp 0 >> + gdb_test_multiple "info breakpoint" "info breakpoint" { >> + -re "in foo\\(int, int\\) at >> \[^\n\r\]*$::srcfile:$loc_in_int_instance" { >> + set seen_int_pb 1 >> + verbose -log "found int" >> + exp_continue >> + } >> + -re "in foo\\(NonIntegral, NonIntegral\\) at >> \[^\n\r\]*$::srcfile:$loc_in_struct_instance" { >> + set seen_struct_bp 1 >> + verbose -log "found struct" >> + exp_continue >> + } >> + -re -wrap "" { >> + gdb_assert {$seen_int_pb && $seen_struct_bp} $gdb_test_name >> + } >> + } >> +} >> + >> +proc_with_prefix test_ignore_artificial_block {} { >> + set loc [gdb_get_line_number "between_static_init break here"] >> + set expected_loc [gdb_get_line_number "break in between_static_init."] >> + gdb_test "break $loc" \ >> + "Breakpoint $::decimal at $::hex: file .*/$::srcfile, line >> $expected_loc\\." \ >> + "ignore static block" >> +} >> + >> +clean_restart $::binfile >> +test_sliding_per_block >> +test_ignore_artificial_block >> >> base-commit: 5fb28d2607a8325559b44a5dc0c8760236c81218 >> prerequisite-patch-id: 695c74160156ff2c66b3a88462be22a36c32f141 >> -- >> 2.25.1