From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id GD9hIQC3q2qCDxYAWB0awg (envelope-from ) for ; Thu, 17 Sep 2026 05:46:40 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TFkVgL1q; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 580541E06B; Thu, 17 Sep 2026 05:46:40 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 052E81E01F for ; Thu, 17 Sep 2026 05:46:38 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C858E4BA79B6 for ; Thu, 17 Sep 2026 09:46:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C858E4BA79B6 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TFkVgL1q Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 1734F4BA2E1A for ; Thu, 17 Sep 2026 09:46:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1734F4BA2E1A Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1734F4BA2E1A Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1789638368; cv=none; b=TNPPSkbqr9Kvc9Yfuprc8coi5YCUftzwUE/TqmfPsbixgBXTY3GgWhYlsUUfCCj7YPS12u+FoQVARnLvSDbf+Q+dvKW2fpdF6PAC9AVYy48UM7zZaxWR4jQBSn8/5uY1DbUChk6CDlSVCCZV6Wu1I6psRYswbQMc24E3D3H32pQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1789638368; c=relaxed/simple; bh=7kgFaLLpAvpDVdrfq1XVgIDf2q7kZEIVN6lBtXukN9I=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=US1uzmWjRnkYT/OXHBaySsJLweatlRMbazdb6u25hJGyIlXW1bF3O8ujInqP9DbJhjUNOpx+RLKdWEaEWrBZdta+nAY7Idba8OsQpBR0uKRVJRVbTNC5WTDlW9vIQNAIODEvS5X1Pwk4PmP+2/zLqG0/8YjceBSFVhy7+BHwefc= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=TFkVgL1q DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1734F4BA2E1A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1789638367; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=TTlvIbJy3OpXqWNfSykctJSRLvk2rhs1TOJkdlS4ilY=; b=TFkVgL1qIhA9XWdL9g22KXcNrkDRyDwn2ophnqfr+5hZNFVp/FFLdqy/PoRfLCy8WdkBsK DWLhR3lcI0rva3K8n0JrZeL2C2S5OFFRvRvKR6oq6S84RGc0bwV1t6LpPmnch9fTaeGCUP bkSb+NQdNj0dC+MKozAe6aBUaBcybxw= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-73-42_nNb5GOXm9rUklO6MlQw-1; Thu, 17 Sep 2026 05:46:05 -0400 X-MC-Unique: 42_nNb5GOXm9rUklO6MlQw-1 X-Mimecast-MFC-AGG-ID: 42_nNb5GOXm9rUklO6MlQw_1789638364 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-4870a0fe60fso359824f8f.2 for ; Thu, 17 Sep 2026 02:46:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789638364; x=1790243164; h=content-transfer-encoding:content-type:mime-version:message-id:date :references:in-reply-to:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=LSCSxc5c7yfZ5wJKK74NuX3CxCHjtx3LJo9aS2fn96o=; b=K+CuLJzOHWpXXHM0joacRTtYvAxALIZd6OIle0I4+vp7hsQ/PXa1H8SB9kp+v003dB FtMsqLn1pYXy4xtUar+e0J9xl7HkXGlsG4mA2KAogpYgQFmYgeRXr43ia7oFxS7ZTnPR LAGNxhwSvwE42i/okj0Av+VkyQUdqJtPSH1lFbyuNwqJZM5sSyoYkUv0M+tyJ8N0pTxY DUd4X5s46QCkrIiVytl6tQFimrD6jP3DSFpELoVd64AQO3i+cTOKFCpFDqWGHLuJVTp6 G+s6TjikGGLamnzFhiXaHha6H0h2ShQN68Cj9XbcyQaeBnaqWnyYawqWDj0o0pTxI4hg Y4PA== X-Forwarded-Encrypted: i=1; AKwUvBxlVWQtGv+sI+A0I5EPuRnC9TWdgL9HEQN5jaGkwLwfEzRJKn2Qoadze1s6PuO2hmiGSC19FYF74cGF+w==@sourceware.org X-Gm-Message-State: AFuF++m3B9vtL8vpu7+8/vANAnpYILcOT+5EoQCyfs6QRXf9kovayNW+ 24TUmVok53sfo5GrhCM0t8FGzr7mSAauy79XXsRMRQrHcdD2JyjnWwqNuj9PKrdYC/R7yBhfvkD k4JJaU6JlTC5MNhTZ3xXngWwDYwMh8Pkn4W8G+C5E2DYHZnzMAjMIoc+rOz6UGU0= X-Gm-Gg: AYBFou0fCEp9OWkIIiBQAm1SQW+UDDkTKdAb6CIx7UC7vDCUXnDpng/ISG+c/cBARLA VWqZ+mii/4a0ARPfhKyxC7bJ6NOV+NnHMM80wc+3bkk+hvREV1RbIyJjzGqHEXAVfZjoKgRv8Zq Uo3DEbcafAYoe4KqP5BuhfxatbEWfuQYf25E/RJ/1eJx7UhRmYXIBPsxWrHhBNTMPpVwdhlpFAF nPFhbjMUDNMBt1Kw7yib4TbGQSDSV1FlRm8fYTFSH+h3sESaGYxcZdiTBLKGKGaN9SfmYHPIp+G V3CZoPw+xVfLMGXAFLhdkhnRNL8pOnvhbX+tf6Dmte4hpT34fANTRsj89hvCpX/0D6bF5YbU X-Received: by 2002:a05:600c:1c19:b0:49c:fc6e:a3d7 with SMTP id 5b1f17b1804b1-49eb732cce6mr94369535e9.22.1789638363767; Thu, 17 Sep 2026 02:46:03 -0700 (PDT) X-Received: by 2002:a05:600c:1c19:b0:49c:fc6e:a3d7 with SMTP id 5b1f17b1804b1-49eb732cce6mr94368865e9.22.1789638363068; Thu, 17 Sep 2026 02:46:03 -0700 (PDT) Received: from localhost ([83.216.138.214]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49fbd2160c2sm63608175e9.6.2026.09.17.02.46.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Sep 2026 02:46:02 -0700 (PDT) From: Andrew Burgess To: Alexandra =?utf-8?B?SMOhamtvdsOh?= , gdb-patches@sourceware.org Cc: ahajkova@redhat.com Subject: Re: [PATCH v11] gdb: Add source-tracking breakpoints feature In-Reply-To: <20260902182701.54089-1-ahajkova@redhat.com> References: <20260902182701.54089-1-ahajkova@redhat.com> Date: Thu, 17 Sep 2026 10:46:01 +0100 Message-ID: <87ld90b486.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ovCLZwCLB38aNMxfQXINTDyj_9LRrq969xI7Ja2p5Yk_1789638364 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Alexandra H=C3=A1jkov=C3=A1 writes: > When we rerun the executable after changing its source files, > GDB would re-set all previously set breakpoints. The > breakpoints set to the function names would remain at their initial > locations. But the breakpoints which used filename:line notation would > be silently shifted following the source code changes. > > To address this, GDB now optionally captures a small window of source > code lines around each breakpoint set with filename:line notation, > when it is first set. When the binary is reloaded, GDB detects the BFD > change and tries to locate the same source context in the new file, > and if successful, re-sets the breakpoint to the matched source code > line. > > The breakpoint_source structure stores captured source code lines > around a breakpoint location, along with a reference to the BFD > that was current when the source was captured. > > When source tracking is enabled (via 'set breakpoint source-tracking > enabled on'), GDB captures 3 lines of source context > (BREAKPOINT_SRC_CTX_LINES) along with the current BFD when a > breakpoint is first set. On executable reload (detected by comparing > BFDs), it searches within a 12-line window > (BREAKPOINT_SRC_CTX_LINES * BREAKPOINT_SRC_SEARCH_MULTIPLIER) for > the best match and adjusts the breakpoint location if needed. > > If source tracking is disabled after breakpoints have been tracked, > all existing source tracking information is discarded and a message > is printed. > > Tests added: > gdb.base/adjust_breakpoint.exp > gdb.base/adjust_breakpoint-missing-source.exp > gdb.base/source-tracking-inline.exp > gdb.base/test_source_tracking.exp > > adjust_breakpoint.exp covers four scenarios: > - adjust the breakpoint when lines are deleted > - adjust the breakpoint when lines are inserted > - the tracked line disappears entirely > - verify the tracking can be disabled > > adjust_breakpoint-missing-source.exp covers the edge case where source > files are unavailable, verifying GDB falls back to non-tracking breakpoin= ts. > > source-tracking-inline.exp covers source tracking with inline functions. > > test_source_tracking.exp verifies that source context is correctly captur= ed > when the breakpoint is on the last line of the file. > > Add maintenance command to print tracked source code. > Add documentation for the new source-tracking breakpoints feature. > > Limitations of the current implementation: > > Source tracking is not enabled for pending breakpoints that become > non-pending. When a breakpoint is created pending (e.g. with 'set > breakpoint pending on'), source context is not captured at creation > time since no symtab is available yet. When the breakpoint later > resolves to a location, re_set_default() only updates existing tracked > breakpoints and does not initiate tracking for newly resolved ones. > This could be fixed in the future by initiating source tracking in > re_set_default() when a breakpoint transitions from pending to > non-pending. > > Source tracking for ranged breakpoints is not currently supported. > Ranged breakpoints have a start and end location spec, and tracking > both independently raises questions about whether to preserve the > range length or track each end separately. For now, ranged > breakpoints will never be source-tracked. > > Reviewed-By: Eli Zaretskii Hi Alexandra, Thanks for your continued work on this feature. I think this might be the last round of feedback. There's a few really minor issues, there are a couple that really need addressing before this can be merged, but it's looking really close now. > diff --git a/gdb/NEWS b/gdb/NEWS > index 10c182067f9..a111b3c6ea8 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -3,6 +3,25 @@ > =20 > *** Changes since GDB 18 > =20 > +* GDB now supports source-tracking breakpoints, which automatically > + adjust their location when source code changes between rebuilds. > + When enabled, file and line breakpoints capture the surrounding > + source code context and use it to adjust the breakpoint line if the > + source is modified. Source tracking can be enabled with 'set > + breakpoint source-tracking enabled on'. > + > +* New commands > + > +set breakpoint source-tracking enabled [on|off] > +show breakpoint source-tracking enabled > + Enable or disable source-tracking for file and line breakpoints. > + When enabled, breakpoints capture surrounding source code and > + automatically adjust their location when the source changes between > + recompilations. > +maintenance info source-tracking-context BPNUM You should place a blank line before the 'maintenance info source-tracking-context BPNUM' line. > + Displays the captured source context that GDB uses to track and > + adjust a breakpoint when source changes. > + > *** Changes in GDB 18 > =20 > * Support for the Common Trace Format (CTF) has been removed. GDB now > @@ -143,6 +162,16 @@ unset local-environment > environment. The local environment is used by "shell", "pipe", and > other commands that launch a subprocess other than an inferior. > =20 > +set breakpoint source-tracking enabled [on|off] > +show breakpoint source-tracking enabled > + Enable or disable source-tracking for file and line breakpoints. > + When enabled, breakpoints capture surrounding source code and > + automatically adjust their location when the source changes between > + recompilations. > +maintenance info source-tracking-context BPNUM > + Displays the captured source context that GDB uses to track and > + adjust a breakpoint when source changes. > + > save history FILENAME > Save the command history to the given file. > This is a duplicate and should be deleted. > +/* Search for the best match of BP_SOURCE's captured context lines withi= n > + TMP_SOURCE's larger search window. For each candidate position where > + the breakpoint line matches, compare all BREAKPOINT_SRC_CTX_LINES > + captured context lines and track the position with the highest match > + score. Only accept the match if a majority of the context lines > + matched. > + > + Returns new breakpoint line on success or -1 on failure. */ > + > +static int > +sliding_window_match (breakpoint_source *bp_source, > +=09=09 breakpoint_source *tmp_source) Both of these arguments can be 'const breakpoint_source *' as neither are updated. But if you're changing this then it would be nice to update these arguments to 'const breakpoint_source &' -- references rather than pointers. This removes the possibility of either being NULL. You'll need to update the function body to replace '->' with '.', and the calling line becomes: int new_bp_line =3D sliding_window_match (*bp_source.get (), tmp_source); But that would be neater. > +/* See breakpoint.h. */ > + > +void > +code_breakpoint::adjust_bp_for_source_tracking > + (program_space *filter_pspace, > + std::vector &expanded) > +{ > + if (expanded.empty () || expanded[0].symtab =3D=3D nullptr > + || !breakpoint_source_is_tracked (bp_source.get ())) > + return; > + > + struct compunit_symtab &cust =3D expanded[0].symtab->compunit (); > + if (cust.objfile () =3D=3D nullptr) > + return; > + > + bfd *current_bfd =3D cust.objfile ()->obfd.get (); > + if (bp_source->source_bfd.get () =3D=3D current_bfd) > + return; > + > + /* BFD changed - executable was reloaded. */ > + if (expanded.size () !=3D 1) > + { > + warning (_("Breakpoint %d now has multiple locations after reload,= " > +=09=09 "disabling source tracking."), number); > + bp_source.reset (); > + return; > + } > + > + /* If this fails then the location spec has changed since the > + breakpoint's source tracking was initially setup. */ Nit: 'setup' -> 'set up'. > + gdb_assert (breakpoint_locspec_suitable_for_tracking (locspec.get ()))= ; > + > + std::string line; > + scoped_restore restore_styling =3D make_scoped_restore (&source_stylin= g, false); > + if (!g_source_cache.get_source_lines (expanded[0].symtab, > +=09=09=09=09=09expanded[0].line, > +=09=09=09=09=09expanded[0].line, &line)) > + { > + /* Source is unreadable after reload - drop tracking. */ > + bp_source.reset (); > + warning (_("could not re-capture source lines, " > +=09=09 "breakpoint %d no longer source tracked"), > +=09 number); > + return; > + } > + > + if (line =3D=3D bp_source->source_lines[bp_source->bp_line_stored]) > + { > + /* Line unchanged - just refresh the capture with the new BFD. */ > + bp_source =3D std::make_unique > +=09(breakpoint_source_capture (expanded, BREAKPOINT_SRC_CTX_LINES)); > + return; This call to breakpoint_source_capture could, in theory, fail, though I don't know why it ever would. But still, you should handle this case like you do all the other breakpoint_source_capture calls: if (!breakpoint_source_is_tracked (b->bp_source.get ())) { warning (_("unable to refresh source tracking for breakpoint %d, " "source tracking disabled"), number); b->bp_source.reset (); } > + } > + > + breakpoint_source tmp_source > + =3D breakpoint_source_capture (expanded, > +=09=09=09=09 BREAKPOINT_SRC_CTX_LINES > +=09=09=09=09 * BREAKPOINT_SRC_SEARCH_MULTIPLIER); > + int new_bp_line =3D sliding_window_match (bp_source.get (), &tmp_sourc= e); > + if (new_bp_line =3D=3D -1) > + { > + warning (_("Breakpoint %d source code not found " > +=09=09 "after reload, keeping original location."), number); > + bp_source.reset (); > + return; > + } > + > + explicit_location_spec *explicit_loc =3D as_explicit_location_spec (lo= cspec.get ()); > + location_spec_up new_locspec =3D explicit_loc->clone (); > + explicit_location_spec *new_explicit =3D as_explicit_location_spec (ne= w_locspec.get ()); > + new_explicit->line_offset.offset =3D new_bp_line; > + new_explicit->line_offset.sign =3D LINE_OFFSET_NONE; > + /* Invalidate the cached display string. */ > + new_explicit->set_string (""); > + > + int found; > + std::vector new_expanded =3D location_spec_to_sals (n= ew_locspec.get (), > +=09=09=09=09=09=09=09=09 filter_pspace, &found); > + if (!found) > + { > + warning (_("Breakpoint %d adjusted to line %d but location could n= ot " > +=09=09"be resolved; keeping original location."), number, new_bp_line); > + bp_source.reset (); > + return; > + } > + expanded =3D std::move (new_expanded); > + locspec =3D std::move (new_locspec); > + if (new_bp_line !=3D bp_source->bp_line) > + { > + gdb_printf (_("Breakpoint %d adjusted from line %d to line %d.\n")= , > +=09=09 number, bp_source->bp_line, new_bp_line); > + notify_breakpoint_modified (this); > + } > + > + bp_source =3D std::make_unique > + (breakpoint_source_capture (expanded, BREAKPOINT_SRC_CTX_LINES)); > + if (!breakpoint_source_is_tracked (bp_source.get ())) > + warning (_("failed to capture breakpoint source context, " > +=09 "disabling source tracking for breakpoint %d"), > +=09 number); In other places where you disable source tracking you reset bp_source, but not here. I think this should be made consistent. > diff --git a/gdb/testsuite/gdb.base/source-tracking-inline.exp b/gdb/test= suite/gdb.base/source-tracking-inline.exp > new file mode 100644 > index 00000000000..96849dd1bb6 > --- /dev/null > +++ b/gdb/testsuite/gdb.base/source-tracking-inline.exp > @@ -0,0 +1,80 @@ > +# Copyright 2026 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 of the source tracking breakpoint feature when trying to place > +# a breakpoint on inline functions. As the breakpoint resolves to > +# multiple locations we don't currently source track these > +# breakpoints. > + > +standard_testfile -1.c -2.c > + > +set build_srcfile [standard_output_file ${testfile}.c] > + > +remote_exec build "cp $srcdir/$subdir/$srcfile $build_srcfile" > +if { [prepare_for_testing "failed to prepare" $testfile $build_srcfile] = } { > + return > +} > + > +if {![runto_main]} { > + return > +} > + > +gdb_test_no_output "set breakpoint source-tracking enabled on" \ > + "enable source tracking breakpoints" > + > +set lineno [gdb_get_line_number "Breakpoint here." $build_srcfile] > + > +# The breakpoint is on an inline function called from two places, > +# so it resolves to 2 locations. > +gdb_test "break ${testfile}.c:$lineno" \ > + "^Breakpoint $decimal at $hex: ${testfile}.c:$lineno\\. \\(2 locatio= ns\\)" > + > +# Check that we are tracking the expected number of lines. > +# > +# With the multi-location fix, this breakpoint should NOT be tracked > +# because it has 2 locations (inline function called from two places). > +# The output should show but NOT "source-tracking enabled". > +gdb_test_multiple "info breakpoints" \ > + "multi-location breakpoint not tracked" { > + -re -wrap "source-tracking enabled.*" { > + fail "$gdb_test_name (tracking incorrectly enabled)" > + } > + -re -wrap ".*" { > + pass $gdb_test_name > + } > +} > + > +sleep 1 > +remote_exec build "cp $srcdir/$subdir/$srcfile2 $build_srcfile" > +if { [build_executable "failed to build" $testfile $build_srcfile] } { > + return > +} The two files: gdb/testsuite/gdb.base/source-tracking-inline-1.c gdb/testsuite/gdb.base/source-tracking-inline-2.c are identical, so there's no reason to ship these two different files. The point of this particular test is to ensure that we don't start tracking a multi-location breakpoint, so you cannot change the source too much, but given the nature of the test, it might be nice if there was some actual change. Thanks, Andrew