Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
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


  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