From: Andrew Burgess <aburgess@redhat.com>
To: "Alexandra Hájková" <ahajkova@redhat.com>, gdb-patches@sourceware.org
Cc: ahajkova@redhat.com
Subject: Re: [PATCH v8] gdb: Add source-tracking breakpoints feature
Date: Tue, 14 Jul 2026 12:23:11 +0100 [thread overview]
Message-ID: <87cxwperxc.fsf@redhat.com> (raw)
In-Reply-To: <20260714094241.178097-1-ahajkova@redhat.com>
Hi Alexandra,
I took a look through this and have a small number of very minor nits
left to clean up. Thanks for continuing to work on this project.
Alexandra Hájková <ahajkova@redhat.com> 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 breakpoints.
>
> source-tracking-inline.exp covers source tracking with inline functions.
You list 4 new tests and then describe 3 of them. Adding a sentence for
the new test would be great:
test_source_tracking.exp verifies that source context is
correctly captured 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 <eliz@gnu.org>
> ---
> v8:
> - Fix off-by-one error in breakpoint_source_capture and
> add gdb.base/test_source_tracking.exp to test this corner case
> - Fix API drift: symtab::compunit() now returns compunit_symtab &
> - Fix locspec assignment ordering in adjust_bp_for_source_tracking
> - Move the breakpoint_source struct definition from breakpoint.h to breakpoint.c
>
> gdb/NEWS | 14 +
> gdb/breakpoint.c | 487 ++++++++++++++++++
> gdb/breakpoint.h | 16 +-
> gdb/doc/gdb.texinfo | 45 ++
> .../gdb.base/adjust_breakpoint-2.cpp | 39 ++
> .../gdb.base/adjust_breakpoint-3.cpp | 41 ++
> .../gdb.base/adjust_breakpoint-4.cpp | 37 ++
> .../adjust_breakpoint-missing-source.exp | 55 ++
> gdb/testsuite/gdb.base/adjust_breakpoint.cpp | 40 ++
> gdb/testsuite/gdb.base/adjust_breakpoint.exp | 168 ++++++
> .../gdb.base/source-tracking-inline-1.c | 50 ++
> .../gdb.base/source-tracking-inline-2.c | 49 ++
> .../gdb.base/source-tracking-inline.exp | 80 +++
> gdb/testsuite/gdb.base/test_source_tracking.c | 18 +
> .../gdb.base/test_source_tracking.exp | 43 ++
> 15 files changed, 1181 insertions(+), 1 deletion(-)
> create mode 100644 gdb/testsuite/gdb.base/adjust_breakpoint-2.cpp
> create mode 100644 gdb/testsuite/gdb.base/adjust_breakpoint-3.cpp
> create mode 100644 gdb/testsuite/gdb.base/adjust_breakpoint-4.cpp
> create mode 100644 gdb/testsuite/gdb.base/adjust_breakpoint-missing-source.exp
> create mode 100644 gdb/testsuite/gdb.base/adjust_breakpoint.cpp
> create mode 100644 gdb/testsuite/gdb.base/adjust_breakpoint.exp
> create mode 100644 gdb/testsuite/gdb.base/source-tracking-inline-1.c
> create mode 100644 gdb/testsuite/gdb.base/source-tracking-inline-2.c
> create mode 100644 gdb/testsuite/gdb.base/source-tracking-inline.exp
> create mode 100644 gdb/testsuite/gdb.base/test_source_tracking.c
> create mode 100644 gdb/testsuite/gdb.base/test_source_tracking.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index ec9b5a33787..553d8c49ff6 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -6,6 +6,13 @@
> * Support for the Common Trace Format (CTF) has been removed. GDB now
> saves trace information exclusively in its own "tfile" format.
>
> +* 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'.
> +
> * Support for .gdb_index sections with version less than 7 has been
> removed.
>
> @@ -141,6 +148,13 @@ unset local-environment
> environment. The local environment is used by "shell", "pipe", and
> other commands that launch a subprocess other than an inferior.
>
> +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.
> +
The following new command needs adding to the NEWS file:
maint info source-tracking-context
...
> save history FILENAME
> Save the command history to the given file.
>
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index e4df4df04a7..0d116a217cf 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> +
> +/* Print captured source lines to stdout, marking the breakpoint line with '>'. */
> +
> +static void
> +breakpoint_source_print (const breakpoint_source *src)
> +{
> + if (!breakpoint_source_is_tracked (src))
> + return;
> +
> + int start_line = breakpoint_source_get_start_line (src);
> + for (std::size_t j = 0; j < src->source_lines.size (); j++)
> + {
> + int line_num = start_line + (int) j;
> + char prefix;
> + if (j == src->bp_line_stored)
> + prefix = '>';
> + else
> + prefix = ' ';
> + gdb_printf ("%c %ps %s", prefix,
> + styled_string (line_number_style.style (),
> + pulongest (line_num)),
As LINE_NUM is signed, `plongest` would be a better choice here.
There's an unfortunate mix of calls throughout GDB with some using
pulongest and some plongest. But if we consider the
ui_out::field_signed calls, I think plongest is the most common, and
feels like the correct choice for signed values.
> + src->source_lines[j].c_str ());
> + if (src->source_lines[j].empty ()
> + || src->source_lines[j].back () != '\n')
> + gdb_putc ('\n');
> + }
> +}
> +
> +/* Implement the "maintenance info source-tracking-context" command. */
> +
> +static void
> +maintenance_info_source_tracking_context (const char *args, int from_tty)
> +{
> + if (args == nullptr || *args == '\0')
> + error (_("Breakpoint number required."));
> +
> + /* Parse the breakpoint number. */
> + const char *end = args;
> + int num = get_number_trailer (&end, 0);
> +
> + if (num <= 0)
> + error (_("Invalid breakpoint number '%s'."), args);
> +
> + /* Find the breakpoint. */
> + breakpoint *b = nullptr;
> + for (breakpoint &bp : all_breakpoints ())
> + {
> + if (bp.number == num)
> + {
> + b = &bp;
> + break;
> + }
> + }
> +
> + if (b == nullptr)
> + error (_("No breakpoint number %d."), num);
> +
> + /* Check if source tracking is enabled for this breakpoint. */
> + if (!breakpoint_source_is_tracked (b->bp_source.get ()))
> + {
> + gdb_printf (_("Breakpoint %d does not have source tracking enabled.\n"), num);
> + return;
The documentation for this command says:
For source-tracking breakpoints (*note Breakpoints::), print the
tracked source code context for breakpoint NUM. If breakpoint NUM
is not source tracked, or NUM is not a valid breakpoint number,
then the command gives an error.
Except for non-tracked breakpoints you don't give an error, you print a
message and return. You should either update the documentation to
match the implementation, or the implementation to match the docs, I
think either choice would be fine. I've left a comment below where the
docs are inconsistent.
> @@ -8926,6 +9204,32 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
> enabled, flags,
> display_canonical);
>
> + /* Only capture source lines for file:line breakpoints when source
> + tracking is enabled. We check explicit_line to ensure the user
> + explicitly specified a line number (e.g., "break file.c:23" or
> + "break 23"), as opposed to "break function_name" or temporary
> + breakpoints set by commands like "start".
> +
> + We also only track single-location breakpoints. Multi-location
> + breakpoints (e.g., breakpoints on inline functions that are inlined
> + in multiple places) are too complex to track reliably as each location
> + may have moved differently. */
> + if (source_tracking_breakpoints && sals.size () == 1
> + && sals[0].explicit_line
> + && breakpoint_locspec_suitable_for_tracking (b->locspec.get ()))
> + {
> + /* Capture source if we have valid symtab and line info.
> + This works for both "b file:line" and "b line" formats.
> + We capture BREAKPOINT_SRC_CTX_LINES lines to provide
> + context around the breakpoint location. */
> + b->bp_source = std::make_unique<breakpoint_source>
> + (breakpoint_source_capture (sals, BREAKPOINT_SRC_CTX_LINES));
> +
> + if (!breakpoint_source_is_tracked (b->bp_source.get ()))
> + warning (_("Source file not available; breakpoint will not be "
> + "source-tracked."));
Optional: you could change this to:
if (!breakpoint_source_is_tracked (b->bp_source.get ()))
{
warning (_("Source file not available; breakpoint will not be "
"source-tracked."));
b->bp_source.reset ();
}
this would discard the empty breakpoint_source object, saving a small
amount of memory. Not discarding it is harmless, it just uses a little
memory, but it's not a leak, and an empty breakpoint_source still
returns false for breakpoint_source_is_tracked, so not deleting is
functionally correct, this is really up to you.
> + }
> +
> install_breakpoint (internal, std::move (b), 0);
> }
>
> @@ -13183,6 +13487,154 @@ code_breakpoint::location_spec_to_sals (location_spec *locspec,
> return sals;
> }
>
> +/* Match BREAKPOINT_SRC_CTX_LINES lines of the initially stored source in a
> + BREAKPOINT_SRC_CTX_LINES * BREAKPOINT_SRC_SEARCH_MULTIPLIER lines current
> + source window.
> +
> + Returns new breakpoint line on success or -1 on failure. */
> +
> +static int
> +sliding_window_match (breakpoint_source *bp_source,
> + breakpoint_source *tmp_source)
> +{
> + /* The index into BP_SOURCE's lines where the breakpoint was placed. */
> + size_t bp_stored = bp_source->bp_line_stored;
> + size_t bp_size = bp_source->source_lines.size ();
> +
> + /* An empty string, used if the breakpoint line is at the start or end of
> + the context window. */
> + static std::string empty_string;
This could also be const, so `static const std::string emptry_string`.
> +
> +/* See breakpoint.h. */
> +
> +void
> +code_breakpoint::adjust_bp_for_source_tracking
> + (program_space *filter_pspace,
> + std::vector<symtab_and_line> &expanded)
> +{
> + if (expanded.empty () || expanded[0].symtab == nullptr
> + || !breakpoint_source_is_tracked (bp_source.get ()))
> + return;
> +
> + struct compunit_symtab &cust = expanded[0].symtab->compunit ();
> + if (cust.objfile () == nullptr)
> + return;
> +
> + bfd *current_bfd = cust.objfile ()->obfd.get ();
> + if (bp_source->source_bfd.get () == current_bfd)
> + return;
> +
> + /* BFD changed — executable was reloaded. */
This is a non ASCII dash character. Can you replace it with a standard
ASCII dash please. Ideally comments should be complete sentences, so
rewriting to remove the need for a dash would be best.
> + if (expanded.size () != 1)
> + {
> + warning (_("Breakpoint %d now has multiple locations after reload, "
> + "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. */
> + gdb_assert (breakpoint_locspec_suitable_for_tracking (locspec.get ()));
> +
> + std::string line;
> + auto restore_styling = make_scoped_restore (&source_styling, false);
> + if (!g_source_cache.get_source_lines (expanded[0].symtab,
> + expanded[0].line,
> + expanded[0].line, &line))
> + {
> + /* Source is unreadable after reload — drop tracking. */
Non ASCII dash again.
> + bp_source.reset ();
> + return;
> + }
> +
> + if (line == bp_source->source_lines[bp_source->bp_line_stored])
> + {
> + /* Line unchanged — just refresh the capture with the new BFD. */
Non ASCII dash again.
> + bp_source = std::make_unique<breakpoint_source>
> + (breakpoint_source_capture (expanded, BREAKPOINT_SRC_CTX_LINES));
> + return;
> + }
> +
> + breakpoint_source tmp_source
> + = breakpoint_source_capture (expanded,
> + BREAKPOINT_SRC_CTX_LINES
> + * BREAKPOINT_SRC_SEARCH_MULTIPLIER);
> + int new_bp_line = sliding_window_match (bp_source.get (), &tmp_source);
> + if (new_bp_line == -1)
> + {
> + warning (_("Breakpoint %d source code not found "
> + "after reload, keeping original location."), number);
> + bp_source.reset ();
> + return;
> + }
> +
> + auto *explicit_loc = as_explicit_location_spec (locspec.get ());
> + location_spec_up new_locspec = explicit_loc->clone ();
> + auto *new_explicit = as_explicit_location_spec (new_locspec.get ());
> + new_explicit->line_offset.offset = new_bp_line;
> + new_explicit->line_offset.sign = LINE_OFFSET_NONE;
> + new_explicit->set_string (""); /* Invalidate the cached display string. */
Sorry to be a pain, but GDB style is to place comments before the source
line, not trailing at the end. Can you move this comment to a line of
its own please.
> +
> + int found;
> + expanded = location_spec_to_sals (new_locspec.get (), filter_pspace, &found);
> + if (!found)
> + {
> + warning (_("Breakpoint %d adjusted to line %d but location could not "
> + "be resolved; keeping original location."), number, new_bp_line);
This line needs indenting with tabs. If you use 'git check' it should
point out these white space issues for you.
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index 722d75390fa..2698fc4d441 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -27,6 +27,7 @@
> #include "probe.h"
> #include "location.h"
> #include <vector>
> +#include <memory>
> #include "gdbsupport/array-view.h"
> #include "gdbsupport/filtered-iterator.h"
> #include "gdbsupport/iterator-range.h"
> @@ -34,7 +35,6 @@
> #include "gdbsupport/safe-iterator.h"
> #include "cli/cli-script.h"
> #include "target/waitstatus.h"
> -
Unnecessary white space change, please revert.
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index a698b2b8451..d304f885def 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -4661,6 +4661,28 @@ program.
> On some systems, you can set breakpoints in shared libraries before
> the executable is run.
>
> +@cindex source-tracking breakpoints
> +@cindex breakpoints, automatic adjustment when source changes
> +@value{GDBN} supports @dfn{source-tracking breakpoints}, which
> +automatically adjust their location when source code changes between
> +recompilations. When enabled with @code{set breakpoint source-tracking
> +enabled on}, breakpoints set by file and line number capture a small
> +window of surrounding source lines: the line immediately before the
> +breakpoint, the breakpoint line itself, and the line immediately after
> +it. If the source file is modified and the executable is rebuilt,
> +@value{GDBN} searches a window of approximately 12 lines centered on the
> +breakpoint's original position for a match. A candidate line is
> +accepted when it matches the captured breakpoint line and both of
> +its immediate neighbors also match, reducing false positives from
> +short or repeated lines. @value{GDBN} uses the first such confirmed
> +match found, scanning from the top of the search window. If the same
> +code sequence appears more than once within the search window, the
> +earliest occurrence is chosen; code outside the search window is not
> +considered. If no match is found, @value{GDBN} issues a warning and
> +keeps the breakpoint at its original location, disabling source tracking
> +for that breakpoint. Note that breakpoints set by function name or
> +address are not affected by source tracking. @xref{Set Breaks}.
> +
> @cindex watchpoints
> @cindex data breakpoints
> @cindex memory tracing
> @@ -42017,6 +42039,13 @@ Shared library events.
>
> @end table
>
> +@kindex maint info source-tracking-context
> +@item maint info source-tracking-context @var{num}
> +For source-tracking breakpoints (@pxref{Breakpoints}), print the
> +tracked source code context for breakpoint @var{num}. If breakpoint
> +@var{num} is not source tracked, or @var{num} is not a valid
> +breakpoint number, then the command gives an error.
Here is the documentation inconsistency that I mentioned earlier.
Currently GDB doesn't give an error for non-source tracked breakpoints,
it just prints a message and returns.
> diff --git a/gdb/testsuite/gdb.base/adjust_breakpoint.exp b/gdb/testsuite/gdb.base/adjust_breakpoint.exp
> new file mode 100644
> index 00000000000..123c03d322d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/adjust_breakpoint.exp
> @@ -0,0 +1,168 @@
> +# 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 <http://www.gnu.org/licenses/>.
> +
> +# 1) Set the breakpoint to a certain line in $srcfile. Replace the $srcfile
> +# with tmp-$srcfile which is exactly the same except one line is missing,
> +# which changes the line where the breakpoint was initially set and moves
> +# the breakpoint one line backwards.
> +# Check if GDB adjusted the line correctly.
> +#
> +# 2) Do all the same but move the breakpoint a few lines forward by adding an
> +# additional line to the tmp2-$srcfile.
> +
> +standard_testfile .cpp -2.cpp -3.cpp -4.cpp
> +set build_srcfile ${testfile}-xxx.cpp
> +
> +set new_source_file [standard_output_file ${build_srcfile}]
> +remote_exec build "cp ${srcdir}/${subdir}/${srcfile} $new_source_file"
> +if { [prepare_for_testing "failed to prepare" $testfile $new_source_file] } {
> + return
> +}
> +
> +# Enable source tracking for breakpoints.
> +gdb_test_no_output "set breakpoint source-tracking enabled on" \
> + "enable source tracking breakpoints"
> +
> +# If a breakpoint is being source tracked, then turning source
> +# tracking off discards the tracking information and prints a message.
> +# If no breakpoints are being source tracked then disabling source
> +# tracking should be silent.
> +with_test_prefix "check disabling is silent" {
> + gdb_test_no_output "set breakpoint source-tracking enabled off" \
> + "disable"
> +
> + gdb_test_no_output "set breakpoint source-tracking enabled on" \
> + "enable"
> +}
> +
> +# Test that the breakpoint can be adjusted backward.
> +set lineno [gdb_get_line_number "var += i;" $new_source_file]
> +gdb_breakpoint ${build_srcfile}:$lineno
> +
> +# Sleep to ensure timestamp changes when we rebuild.
> +sleep 1
> +remote_exec build "cp ${srcdir}/${subdir}/${srcfile2} $new_source_file"
> +if {[build_executable "failed to prepare" $testfile $new_source_file] == -1} {
> + return
> +}
> +
> +set lineno [expr {$lineno - 1}]
> +gdb_test "run" "Breakpoint 1,.*$build_srcfile:$lineno\r\n$lineno\t.*" \
> + "run stops at adjusted breakpoint location"
> +gdb_test "info breakpoints" \
> + "breakpoint.*keep.*y.*$hex.*$build_srcfile:$lineno.*already hit 1 time" \
> + "info breakpoints show the breakpoint was adjusted one line backward"
> +
> +# Test that the breakpoint can be adjusted forward.
> +clean_restart ${testfile}
> +gdb_test_no_output "set breakpoint source-tracking enabled on" \
> + "enable source tracking breakpoints for part 2"
> +gdb_breakpoint ${build_srcfile}:$lineno
> +
> +# Sleep to ensure timestamp changes when we rebuild.
> +sleep 1
> +remote_exec build "cp ${srcdir}/${subdir}/${srcfile3} $new_source_file"
> +if {[build_executable "failed to prepare" $testfile $new_source_file] == -1} {
> + return
> +}
> +
> +set lineno [expr {$lineno + 2}]
> +gdb_test "run" "Breakpoint 1,.*$build_srcfile:$lineno\r\n$lineno\t.*" \
> + "run for the second time stops at adjusted breakpoint location"
> +gdb_test "info breakpoints" \
> + "breakpoint.*keep.*y.*$hex.*$build_srcfile:$lineno.*already hit 1 time" \
> + "info breakpoints show the breakpoint was adjusted forward"
> +
> +# Disable source tracking breakpoints, the existing tracking
> +# information is discarded.
> +gdb_test "set breakpoint source-tracking enabled off" \
> + "^Discarding existing source tracking information\\." \
> + "disable source tracking, existing tracking is discarded"
> +
> +gdb_test "info breakpoints" \
> + [multi_line \
> + "1\\s+breakpoint\\s+keep\\s+y\[^\r\n\]+" \
> + "\\s+breakpoint already hit \[^\r\n\]+"] \
> + "info breakpoints breakpoint no longer tracked"
> +
> +# Test what happens when the breakpoint line disappears.
> +clean_restart ${testfile}
> +gdb_test_no_output "set breakpoint source-tracking enabled on" \
> + "enable source tracking breakpoints for part 3"
> +set lineno [gdb_get_line_number "var += 10;" $new_source_file]
> +gdb_breakpoint ${build_srcfile}:$lineno
> +
> +# Sleep to ensure timestamp changes when we rebuild.
> +sleep 1
> +remote_exec build "cp ${srcdir}/${subdir}/${srcfile4} $new_source_file"
> +if {[build_executable "failed to prepare" $testfile $new_source_file] == -1} {
> + return
> +}
> +
> +# When the original line is removed and cannot be found in the search window,
> +# the breakpoint stays at the symbol-resolved location. Line 10 becomes blank
> +# in tmp3, so GDB resolves it to line 11 (return var;) or stays at line 10.
> +# We test that it doesn't move beyond the reasonable range.
> +set lineno_re "(?:$lineno|[expr {$lineno + 1}])"
> +gdb_test "run" "Breakpoint 1,.*$build_srcfile:$lineno_re\r\n$lineno_re\t.*" \
> + "run for the third time stops near original location"
> +gdb_test "info breakpoints" \
> + "breakpoint.*keep.*y.*$hex.*$build_srcfile:$lineno_re.*already hit 1 time" \
> + "the breakpoint stays near original location when line disappears"
> +
> +# Test that with source tracking disabled the breakpoint should not be
> +# adjusted.
> +clean_restart ${testfile}
> +# Don't enable source tracking - test that breakpoints don't adjust without it
> +set lineno [gdb_get_line_number "return var;" $new_source_file]
> +gdb_breakpoint ${build_srcfile}:$lineno
> +
> +# Sleep to ensure timestamp changes when we rebuild.
> +sleep 1
> +remote_exec build "cp ${srcdir}/${subdir}/${srcfile2} $new_source_file"
> +if {[build_executable "failed to prepare" $testfile $new_source_file] == -1} {
> + return
> +}
> +
> +gdb_test "run" "Breakpoint 1,.*$build_srcfile:$lineno\r\n$lineno\t.*" \
> + "run for the fourth time stops at unadjusted location"
> +gdb_test "info breakpoints" \
> + "breakpoint.*keep.*y.*$hex.*$build_srcfile:$lineno.*already hit 1 time" \
> + "breakpoint not adjusted when tracking disabled"
> +
> +# Test that relative line breakpoints (e.g., "b +1") with source tracking
> +# enabled do not produce a spurious warning. Relative line offsets are not
> +# supported for source tracking, so the breakpoint should be created silently
> +# without any warning message.
> +clean_restart ${testfile}
> +gdb_test_no_output "set breakpoint source-tracking enabled on" \
> + "enable source tracking for relative line test"
> +
> +# Run to main so we have a current line context for relative breakpoints.
> +if {![runto_main]} {
> + return
> +}
> +
> +# "b +1" is a relative offset breakpoint — not trackable, but should be
Non ASCII dash again.
> +# created silently with no warning.
> +gdb_test_multiple "break +1" "relative line breakpoint creates no warning" {
> + -re -wrap "warning:.*source-track.*" {
> + fail "$gdb_test_name (unexpected warning)"
> + }
> + -re -wrap "Breakpoint $decimal at $hex.*" {
> + pass $gdb_test_name
> + }
> +}
> +
Blank line at end of file, please remove.
> diff --git a/gdb/testsuite/gdb.base/test_source_tracking.exp b/gdb/testsuite/gdb.base/test_source_tracking.exp
> new file mode 100644
> index 00000000000..597447aaa73
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/test_source_tracking.exp
> @@ -0,0 +1,43 @@
> +# 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 <http://www.gnu.org/licenses/>.
> +
> +# Test source-tracking correctly captures context when bp is on the last line.
> +# This covers an off-by-one in breakpoint_source_capture where the clipping
> +# formula excluded the last line of the file from the capture window.
> +
> +standard_testfile .c
> +
> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
> + return
> +}
> +
> +gdb_test_no_output "set breakpoint source-tracking enabled on"
> +
> +set lineno [gdb_get_line_number "BPLastLine" $srcfile]
> +gdb_breakpoint ${srcfile}:$lineno
> +
> +# The '>' marker should be on the actual breakpoint line, not the line before it.
> +# Use gdb_test_multiple so the pattern can match the '>' line anywhere in the
> +# multi-line output (gdb_test's -wrap prevents matching across newlines).
> +gdb_test_multiple "maint info source-tracking-context 1" \
> + "breakpoint line is correctly marked in captured context" {
> + -re "> \[0-9\]+ \[^\r\n\]*BPLastLine\[^\r\n\]*\r\n$gdb_prompt $" {
> + pass $gdb_test_name
> + }
> + -re "$gdb_prompt $" {
> + fail $gdb_test_name
> + }
> +}
> +
Blank line at end of the file, please remove.
Thanks,
Andrew
next prev parent reply other threads:[~2026-07-14 11:23 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 9:40 Alexandra Hájková
2026-07-14 11:23 ` Andrew Burgess [this message]
2026-07-14 12:22 ` Eli Zaretskii
2026-07-18 3:31 ` Kevin Buettner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87cxwperxc.fsf@redhat.com \
--to=aburgess@redhat.com \
--cc=ahajkova@redhat.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox