From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id sZa6CBMih2rngjIAWB0awg (envelope-from ) for ; Thu, 20 Aug 2026 11:49:39 -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=TABOS9jU; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 1E23A1E0A3; Thu, 20 Aug 2026 11:49:39 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.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 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 6216E1E033 for ; Thu, 20 Aug 2026 11:49:37 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A908F4BA9023 for ; Thu, 20 Aug 2026 15:49:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A908F4BA9023 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=TABOS9jU 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 D91474BA2E04 for ; Thu, 20 Aug 2026 15:49:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D91474BA2E04 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 D91474BA2E04 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=1787240946; cv=none; b=qtO2RhzBjEoYwD92v9reiNnmeyK2lBF7KYefFj1wyYVOQ4KT1XcV2he/uJDasaPf52VVsHGc1ieXuFRHlTkJWPSmCYmtoTr9ArK5GjUXV2P69s9qQjcIrZ03QV/RzwIEj74V2ZWThw9PGRmD7Sp4gbELdxt5mMGh8ysYKcGff1w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787240946; c=relaxed/simple; bh=/FSlJBS0z5elsQbvSB52vUiskAldq43QkYZ7Z304oBs=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Y0sHieT1+DUgXXlcpz4e+btfwLoqiBWhZZNrV2/Mi8nR8Y1lnOjnFrcj0O+jayuuwGrhzY1VgXpiigeVmtIcuijarK7G2S80t67uIfMrtHVZQ+pL2nZjtp9qGSN+brKYmkWgOk7o4YibKzztisihQTlnP2jDmhRb2QaGCjbz3rU= 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=TABOS9jU DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D91474BA2E04 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1787240945; 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=W0PDdY0XpSJSretvA5nLIIZrD6xmxyOKEOY+SNzlL3o=; b=TABOS9jUi1Fs1Mvl2NhbCC7WyR/+5AySrG/G1OtV3SiutwhAASHBxW+7zzyKOE61sl6Isn tmPOAMLMRGvtuWth7hZXVNeo2lY4YbOyZJ8qDMaP1ybc1hKcO3MPqc67rlt9Pa9C+qkbgw R6YfRS5oemxGmCCxCegq+ty8d3s4l/s= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-235-jkBfusvENQSvRSkqUzzV4w-1; Thu, 20 Aug 2026 11:49:02 -0400 X-MC-Unique: jkBfusvENQSvRSkqUzzV4w-1 X-Mimecast-MFC-AGG-ID: jkBfusvENQSvRSkqUzzV4w_1787240941 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4954fd771baso6487965e9.0 for ; Thu, 20 Aug 2026 08:49:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787240941; x=1787845741; 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=+zaFV8qUj/p8x2tkJv1jp1GJlQceDYTVKlOz8DfONxo=; b=rkdxed/oVhlnbZsBAh2M10Fr6qoboymFelYq3Yi1zyCITSSHWXieNW53eDJ86oGzwv Iaj5RI621q84+ZtF14sjTvqWhRAPRWv1DeIJP9m5PP7vurmtf6DarvfYzghjMkOcWQVg qXFum72/vAXGgOKzeyR0SQdyVLvwLezS5QmMt1AevksoZNgodNyEirKuG5ldFNjwfhLq y8x1FNP0eoHV5Pj/KytpsuQVNeQGmxVJ0vvNBRapojLqbeKEUCzuqftuLEEi00n0gQxp w5Dyx3IF06ZaWW1FDkK0/p+zxN9Sgm3MYyUcWXkto33paZ9ZDjrNK0DUCuBEAj7onlVH U0fQ== X-Forwarded-Encrypted: i=1; AHgh+Rq5k5Pn+ULtn3nEYRlc6BWHlY76y5cy1qONP+NKcvT3eYRCQ05fvn7Wsfb8Nk/cfvGkSFkOlOXZrF0y/w==@sourceware.org X-Gm-Message-State: AOJu0YzXjAaHC3JMP3BQokQOJWb2s/X91mKBuVpbvhNcn+XZO2jaRjrQ I16DOhBBuv9K6wcijG7GcjP3jzrY5cJA0VW4efR2KAPBMRphovjHlz7aNM8v1NqZc89zTsZnlV3 TqRhsJyu9+GMg5meEUOUUqHkoT0ihg47oyf6CxrWnvgkGSLw5vbBpjAMrjjenyxUhh/Kje2g= X-Gm-Gg: AR+sD12qDhEJL4w9yE5g98TBy3fB0IC1D7nbyMafctkxy/Rjg9V6s8q+K7VBvClBooM 6a+UI86UWlAl8RU/qp2qCE2agd2ffPyxJ99PMP+cOJ1CJmAnYfPZOA13ju+ZwwGfeskDXhAQPBF lbCKVhE7c96eJmGanVnh+J0TQG3gyeGhb9TkaD/OkzDgEPiqFj12myxAc/ZDDvqaXGI9Q2tL8im b7yUluQCVFGgN1/cFPF9yxDCsGYppv7SHj2vVwPxJZUF9vwt/R8zMISZ9wa5Q/f56OWRx8a/5mF Lw+fcvHXIL5wMW8hFwdPqj3T1ZZ5BArvFZB1KoVi5MlYA7Mbrh6RCePYeyaSZKmg0mkFo4PXp+D aYg70CIAjL4hfVZwUKQBDpyptfTE= X-Received: by 2002:a05:600c:674a:b0:499:5f80:83ac with SMTP id 5b1f17b1804b1-499b06cbaf2mr121420725e9.7.1787240940466; Thu, 20 Aug 2026 08:49:00 -0700 (PDT) X-Received: by 2002:a05:600c:674a:b0:499:5f80:83ac with SMTP id 5b1f17b1804b1-499b06cbaf2mr121419115e9.7.1787240939684; Thu, 20 Aug 2026 08:48:59 -0700 (PDT) Received: from localhost (128.223.159.143.dyn.plus.net. [143.159.223.128]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-499aa17f202sm142390335e9.13.2026.08.20.08.48.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2026 08:48:59 -0700 (PDT) From: Andrew Burgess To: Alexandra =?utf-8?B?SMOhamtvdsOh?= , gdb-patches@sourceware.org Cc: ahajkova@redhat.com Subject: Re: [PATCH v10] gdb: Add source-tracking breakpoints feature In-Reply-To: <20260820110025.517438-1-ahajkova@redhat.com> References: <20260820110025.517438-1-ahajkova@redhat.com> Date: Thu, 20 Aug 2026 16:48:58 +0100 Message-ID: <87a4qg23o5.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: RjR2wrcACkGvUN_8pgrKRCU6ClrNQT6wYVAOuW_nmvI_1787240941 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 Hi Alexandra, I think this is looking amazing now! Thank you for continuing to work on this feature. I do have some more feedback, but it really is getting super minor now, and I don't think there are any bugs that I've found, the worst I've got is a couple of missing warnings, where GDB will stop tracking a breakpoint but not tell the user. Then there's some typos and style issues, but unless anyone else has feedback, I hope V11 will be ready to merge. Again, thanks for your amazing work on this. I'm excited to see this merged, and how it might develop in the future. 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 > --- > v10:=20 > - update the comment > - catch the result location_spec_to_sals to the temporary variable > > gdb/NEWS | 17 + > gdb/breakpoint.c | 487 ++++++++++++++++++ > gdb/breakpoint.h | 15 + > gdb/doc/gdb.texinfo | 44 ++ > .../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 | 167 ++++++ > .../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 | 42 ++ > 15 files changed, 1181 insertions(+) > 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-sour= ce.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 10c182067f9..17f522bc71f 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -8,6 +8,13 @@ > * Support for the Common Trace Format (CTF) has been removed. GDB now > saves trace information exclusively in its own "tfile" format. > =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'. Now that GDB 18 has branched this needs moving into the "Changes since GDB 18" section. > + > * Support for .gdb_index sections with version less than 7 has been > removed. > =20 > @@ -143,6 +150,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. > + And these will need moving too. > save history FILENAME > Save the command history to the given file. > =20 > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index 6ca196133fd..b23e43502b3 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -69,6 +69,8 @@ > #include "cli/cli-style.h" > #include "cli/cli-decode.h" > #include "break-cond-parse.h" > +#include "source-cache.h" > +#include "gdb_bfd.h" > =20 > /* readline defines this. */ > #undef savestring > @@ -582,6 +621,60 @@ show_always_inserted_mode (struct ui_file *file, int= from_tty, > =09 value); > } > =20 > +/* When true file and line breakpoints are created as source-tracking > + breakpoints. */ Missing a comma, should be "When true, file and line ....". > @@ -593,6 +686,176 @@ show_debug_breakpoint (struct ui_file *file, int fr= om_tty, > gdb_printf (file, _("Breakpoint location debugging is %s.\n"), value); > } > =20 > +/* Return true if the breakpoint source is being tracked. */ > + > +static bool > +breakpoint_source_is_tracked (const breakpoint_source *src) > +{ > + if (src =3D=3D nullptr) > + return false; > + return !src->source_lines.empty () && src->bp_line > 0; > +} > + > +/* Calculate the starting line number for captured source. */ > + > +static int > +breakpoint_source_get_start_line (const breakpoint_source *src) > +{ > + if (!breakpoint_source_is_tracked (src)) > + return 0; > + return src->bp_line - src->bp_line_stored; > +} > + > +/* Return true if SPEC is suitable for source tracking, otherwise false.= A > + location spec is suitable for tracking if it is an explicit location > + spec, and the line offset is an absolute line number. We also don't > + allow for SPEC to be function or label based. Most of these > + restrictions could be lifted, but this would likely require additiona= l > + work to support these changes, especially when updating the location > + spec. */ > + > +static bool > +breakpoint_locspec_suitable_for_tracking (const location_spec *spec) > +{ > + if (spec->type () !=3D EXPLICIT_LOCATION_SPEC) > + return false; > + > + const explicit_location_spec *explicit_loc > + =3D as_explicit_location_spec (spec); > + > + if (explicit_loc->function_name.get () !=3D nullptr > + || explicit_loc->label_name.get () !=3D nullptr > + || explicit_loc->source_filename.get () =3D=3D nullptr) > + return false; > + > + if (explicit_loc->line_offset.sign !=3D LINE_OFFSET_NONE) > + return false; > + > + return explicit_loc->line_offset.offset > 0; > +} > + > +/* Print captured source lines, marking the breakpoint line with '>'. *= / > + > +static void > +breakpoint_source_print (const breakpoint_source *src) > +{ > + if (!breakpoint_source_is_tracked (src)) > + return; > + > + int start_line =3D breakpoint_source_get_start_line (src); > + for (std::size_t j =3D 0; j < src->source_lines.size (); j++) > + { > + int line_num =3D start_line + (int) j; > + char prefix; > + if (j =3D=3D src->bp_line_stored) > +=09prefix =3D '>'; > + else > +=09prefix =3D ' '; > + gdb_printf ("%c %ps %s", prefix, > +=09=09 styled_string (line_number_style.style (), > +=09=09=09=09 plongest (line_num)), > +=09=09 src->source_lines[j].c_str ()); > + if (src->source_lines[j].empty () > +=09 || src->source_lines[j].back () !=3D '\n') > +=09gdb_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 =3D=3D nullptr || *args =3D=3D '\0') > + error (_("Breakpoint number required.")); > + > + /* Parse the breakpoint number. */ > + const char *end =3D args; > + int num =3D get_number_trailer (&end, 0); > + > + if (num <=3D 0) > + error (_("Invalid breakpoint number '%s'."), args); > + > + /* Find the breakpoint. */ > + breakpoint *b =3D nullptr; > + for (breakpoint &bp : all_breakpoints ()) > + { > + if (bp.number =3D=3D num) > +=09{ > +=09 b =3D &bp; > +=09 break; > +=09} > + } > + > + if (b =3D=3D nullptr) > + error (_("No breakpoint number %d."), num); There's a helper for this! You can write: breakpoint *b =3D get_breakpoint (num); if (b =3D=3D nullptr) error (_("No breakpoint number %d."), num); > @@ -13181,6 +13485,154 @@ code_breakpoint::location_spec_to_sals (locatio= n_spec *locspec, > return sals; > } > =20 > +/* 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) > +{ > + /* The index into BP_SOURCE's lines where the breakpoint was placed. = */ > + int bp_stored =3D (int) bp_source->bp_line_stored; > + int bp_size =3D (int) bp_source->source_lines.size (); > + > + /* Now search TMP_SOURCE for the breakpoint line. */ > + int tmp_size =3D (int) tmp_source->source_lines.size (); > + > + int best_score =3D 0; > + int best_pos =3D -1; > + > + for (int i =3D 0; i < tmp_size; i++) > + { > + /* Fast filter: breakpoint line must match. */ > + if (bp_source->source_lines[bp_stored] !=3D tmp_source->source_lin= es[i]) > +=09continue; > + > + int match =3D 0; > + for (int j =3D 0; j < bp_size; j++) > +=09{ > +=09 int idx =3D i - bp_stored + j; > +=09 if (idx >=3D 0 && idx < tmp_size > +=09 && bp_source->source_lines[j] > +=09 =3D=3D tmp_source->source_lines[idx]) > +=09 match++; > +=09} > + > + if (match > best_score) > +=09{ > +=09 best_score =3D match; > +=09 best_pos =3D i; > +=09} > + } > + > + /* Only accept the match if a majority of the context lines matched. = */ > + if (best_pos >=3D 0 && best_score > bp_size / 2) > + return tmp_source->bp_line + best_pos - tmp_source->bp_line_stored; > + > + /* The updated breakpoint location has not been found in TMP_SOURCE. = */ > + return -1; > +} > + > +/* 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. */ > + gdb_assert (breakpoint_locspec_suitable_for_tracking (locspec.get ()))= ; > + > + std::string line; > + auto restore_styling =3D make_scoped_restore (&source_styling, 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 (); Should we not issue a warning at this point: warning (_("could not re-capture source lines, " "breakpoint %d no longer source tracked"), 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; > + } > + > + 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; > + } > + > + auto *explicit_loc =3D as_explicit_location_spec (locspec.get ()); > + location_spec_up new_locspec =3D explicit_loc->clone (); > + auto *new_explicit =3D as_explicit_location_spec (new_locspec.get ()); I'm really not a fan of this use of `auto` and until I'm told otherwise, I'm on a mission to try and stop these creeping into GDB. My reasoning is that code is written once and read many times. These `auto` make the code quicker to write, but harder to read as you need to go and lookup what type this actually is. Please replace the `auto` here with `const explicit_location_spec`. > + 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; > + auto new_expanded =3D location_spec_to_sals (new_locspec.get (), filte= r_pspace, &found); And here, `auto` should be `std::vector` (IMHO). > + 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 this call to breakpoint_source_capture fails, and returns an empty breakpoint_source, then this breakpoint will stop being tracked. This could confuse a user as the breakpoint _was_ tracked, and we _did_ just update its location. It's pretty unlikely that this call would fail given all of the above, but if it did it might be worth adding a check after this line: if (!breakpoint_source_is_tracked (bp_source.get ())) warning (_("failed to capture breakpoint source context, " "disabling source tracking for breakpoint %d"), number); > +} > + > /* The default re_set method, for typical hardware or software > breakpoints. Reevaluate the breakpoint and recreate its > locations. */ > diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h > index 722d75390fa..ba6189ec504 100644 > --- a/gdb/breakpoint.h > +++ b/gdb/breakpoint.h > @@ -27,6 +27,7 @@ > #include "probe.h" > #include "location.h" > #include > +#include This extra include is not needed as this is already pulled in (indirectly) via GDB's defs.h file, which is included in every file compiled under gdb/. > #include "gdbsupport/array-view.h" > #include "gdbsupport/filtered-iterator.h" > #include "gdbsupport/iterator-range.h" > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 0030698dcee..7aa64054fad 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -4661,6 +4661,27 @@ program. > On some systems, you can set breakpoints in shared libraries before > the executable is run. > =20 > +@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 Use @kbd not @code here please. > +enabled on}, breakpoints set by file and line number capture a small > +window of surrounding source lines centered on the breakpoint line. > +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 the best match. For each candidate > +line that matches the original breakpoint line, @value{GDBN} compares > +all captured context lines at their corresponding offsets and scores the > +match by how many lines agree. The candidate with the highest score is > +selected, provided a majority of the context lines match, reducing false > +positives from short or repeated lines. If no match meets the threshold= , > +@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 > @@ -42065,6 +42086,13 @@ Shared library events. > =20 > @end table > =20 > +@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. > + > @kindex maint info btrace > @item maint info btrace > Pint information about raw branch tracing data. > @@ -42933,6 +42961,22 @@ Control whether to show all non zero areas withi= n a 1k block starting > at thread local base, when using the @samp{info w32 thread-information-b= lock} > command. > =20 > +@kindex set breakpoint source-tracking enabled > +@kindex show breakpoint source-tracking enabled > +@item set breakpoint source-tracking enabled @r{[}on@r{|}off@r{]} > +@itemx show breakpoint source-tracking enabled > +Control whether to enable source-tracking for breakpoints set by file an= d > +line number. Use @code{on} to enable, @code{off} to disable. When > +enabled, @value{GDBN} captures a window of source lines around each > +new file:line breakpoint and uses it to relocate the breakpoint if the > +source is modified and the executable is rebuilt. @xref{Breakpoints}, > +for a full description of the matching algorithm and its limitations. > +The default is @code{off}. Breakpoints set by function name or address > +are not affected by this setting. > + > +If this setting is changed from @code{on} to @code{off}, then any > +existing source tracking information will be discarded. In the above use @samp instead of @code when wrapping on/off please. > + > @kindex maint set target-async > @kindex maint show target-async > @item maint set target-async > diff --git a/gdb/testsuite/gdb.base/source-tracking-inline-2.c b/gdb/test= suite/gdb.base/source-tracking-inline-2.c > new file mode 100644 > index 00000000000..ab95a312c6a > --- /dev/null > +++ b/gdb/testsuite/gdb.base/source-tracking-inline-2.c > @@ -0,0 +1,49 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + 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 .= */ > +volatile int global_var =3D 0; There should be a blank line before the "volatile int global_var =3D 0;" li= ne. Thanks, Andrew