{"id":136854,"date":"2026-04-15T16:33:47","date_gmt":"2026-04-15T16:33:47","guid":{"rendered":"https:\/\/fedoramagazine.org\/?p=43159"},"modified":"2026-04-15T16:33:47","modified_gmt":"2026-04-15T16:33:47","slug":"gdb-source-tracking-breakpoints","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2026\/04\/15\/gdb-source-tracking-breakpoints\/","title":{"rendered":"GDB source-tracking breakpoints"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"127\" src=\"https:\/\/sickgaming.net\/blog\/wp-content\/uploads\/2026\/04\/gdb-source-tracking-breakpoints.jpg\" class=\"webfeedsFeaturedVisual wp-post-image\" alt=\"\" style=\"margin: auto;margin-bottom: 5px;max-width: 100%\" \/><\/p>\n<p>One of the main abilities of a debugger is setting breakpoints.<br \/><a href=\"https:\/\/www.gnu.org\/software\/gdb\/\" target=\"_blank\" rel=\"noreferrer noopener\">GDB: The GNU Project Debugger<\/a> now introduces an experimental feature<br \/>called source-tracking breakpoints that tracks the source line a breakpoint<br \/>was set to. <\/p>\n<p> <span id=\"more-43159\"><\/span> <\/p>\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n<p>Imagine you are debugging: you set breakpoints on a bunch of<br \/>source lines, inspect some values, and get ideas about how to change your<br \/>code. You edit the source and recompile, but keep your GDB session running<br \/>and type run to reload the newly compiled executable. Because you changed<br \/>the source, the breakpoint line numbers shifted. Right now, you have to<br \/>disable the existing breakpoints and set new ones.<\/p>\n<p>GDB source-tracking breakpoints change this situation. When you set a<br \/>breakpoint using <em>file:line<\/em> notation, when this feature is enabled, GDB<br \/>captures a small window of the surrounding source code. When you recompile<br \/>and reload the executable, GDB adjusts any breakpoints whose lines shifted<br \/>due to source changes. This is especially helpful in ad-hoc debug sessions<br \/>where you want to keep debugging without manually resetting breakpoints<br \/>after each edit-compile cycle.<\/p>\n<h2 class=\"wp-block-heading\">Setting a source-tracking breakpoint<\/h2>\n<p>To enable the source-tracking feature, run:<\/p>\n<p>(gdb) <kbd>set breakpoint source-tracking enabled on<\/kbd><\/p>\n<p>Set a breakpoint using file:line notation:<\/p>\n<p>(gdb) <kbd>break myfile.c:42<\/kbd><br \/><em>Breakpoint 1 at 0x401234: file myfile.c, line 42.<\/em><\/p>\n<p>GDB now tracks the source around this line. The info breakpoints command<br \/>shows whether a breakpoint is tracked:<\/p>\n<p>(gdb) <kbd>info breakpoints<\/kbd><br \/><em>Num Type Disp Enb Address What<br \/>1 breakpoint keep y 0x0000000000401234 in calculate at myfile.c:42<br \/>source-tracking enabled (tracking 3 lines around line 42)<\/em><\/p>\n<p>Now edit the source \u2014 say a few lines are added above the breakpoint,<br \/>shifting it from line 42 to line 45. After recompiling and reloading the<br \/>executable with run, GDB resets the breakpoint to the new line and displays:<\/p>\n<p><em>Breakpoint 1 adjusted from line 42 to line 45.<\/em><\/p>\n<p>Run info breakpoints again to confirm the new location:<\/p>\n<p>(gdb) <kbd>info breakpoints<br \/><\/kbd><em>Num Type Disp Enb Address What<br \/>1 breakpoint keep y 0x0000000000401256 in calculate at myfile.c:45<br \/>source-tracking enabled (tracking 3 lines around line 45)<\/em><\/p>\n<p>As you can see, GDB updated the breakpoint line to match the new location.<\/p>\n<h2 class=\"wp-block-heading\">Limitations<\/h2>\n<p>The matching algorithm requires an exact string match of the captured source<br \/>lines. Whitespace-only changes or trivial reformatting of the tracked lines<br \/>will confuse the matcher and may cause the breakpoint not to be found.<\/p>\n<p>GDB only searches within a 12-line window around the original location. If<br \/>the code shifted by more than that \u2014 for example, because a large block was<br \/>inserted above \u2014 the breakpoint will not be found. GDB will keep the<br \/>original location and print a warning:<\/p>\n<p><em>warning: Breakpoint 1 source code not found after reload, keeping original<br \/>location.<\/em><\/p>\n<p>Source context cannot be captured when a breakpoint is created pending<br \/>(e.g., with set breakpoint pending on), because no symbol table is available<br \/>yet. When the breakpoint later resolves to a location, it will not be<br \/>source-tracked.<\/p>\n<p>Source tracking is not supported for ranged breakpoints (set with<br \/>break-range).<\/p>\n<p>Breakpoints on inline functions that expand to multiple locations are not<br \/>source-tracked, as each location may have moved differently.<\/p>\n<h2 class=\"wp-block-heading\">How to try this experimental feature<\/h2>\n<p>This feature is not yet available in a stable GDB release. There are two<br \/>ways to try it.<\/p>\n<h3 class=\"wp-block-heading\">Install from COPR (for Fedora users)<\/h3>\n<p>A pre-built package is available through a COPR repository. Enable it and<br \/>install:<\/p>\n<p><kbd>sudo dnf copr enable ahajkova\/GDB-source-tracking-breakpoints<br \/>sudo dnf upgrade gdb<\/kbd><\/p>\n<p>To disable the repository again after testing:<\/p>\n<p><kbd>sudo dnf copr disable ahajkova\/GDB-source-tracking-breakpoints<\/kbd><\/p>\n<p>The COPR project page is at:<br \/><a href=\"https:\/\/copr.fedorainfracloud.org\/coprs\/ahajkova\/GDB-source-tracking-breakpo\nints\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/copr.fedorainfracloud.org\/coprs\/ahajkova\/GDB-source-tracking-breakpo<br \/>ints\/<\/a><\/p>\n<h3 class=\"wp-block-heading\">Build from source<\/h3>\n<ol class=\"wp-block-list\">\n<li>Clone the GDB repository:<br \/><kbd>git clone git:\/\/sourceware.org\/git\/binutils-gdb.git<br \/>cd binutils-gdb<\/kbd><\/li>\n<li>Download and apply the patch from the upstream mailing list:<br \/><a href=\"https:\/\/sourceware.org\/pipermail\/gdb-patches\/2026-April\/226349.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/sourceware.org\/pipermail\/gdb-patches\/2026-April\/226349.html<\/a><\/li>\n<li>Build GDB:<br \/><kbd>mkdir build &amp;&amp; cd build<br \/>..\/configure --prefix=\/usr\/local<br \/>make -j$(nproc) all-gdb<\/kbd><\/li>\n<li>Run the newly built GDB:<br \/><kbd>.\/gdb\/gdb<\/kbd><\/li>\n<\/ol>\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n<p>GDB source-tracking breakpoints are an experimental feature currently under<br \/>upstream review and not yet available in a stable GDB release. This link<br \/><a href=\"https:\/\/sourceware.org\/gdb\/current\/onlinedocs\/gdb.html\/Set-Breaks.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/sourceware.org\/gdb\/current\/onlinedocs\/gdb.html\/Set-Breaks.html<\/a><br \/>covers all available breakpoint commands. If you try this feature out and<br \/>hit any kind of unexpected behavior, feedback is very welcome \u2014 you can<br \/>follow and respond to the upstream patch discussion on the GDB mailing list<br \/>at <a href=\"https:\/\/sourceware.org\/pipermail\/gdb-patches\/2026-April\/226349.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/sourceware.org\/pipermail\/gdb-patches\/2026-April\/226349.html<\/a><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the main abilities of a debugger is setting breakpoints.GDB: The GNU Project Debugger now introduces an experimental featurecalled source-tracking breakpoints that tracks the source line a breakpointwas set to. Introduction Imagine you are debugging: you set breakpoints on a bunch ofsource lines, inspect some values, and get ideas about how to change yourcode. [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":136855,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48],"tags":[45,61,1578,46,47],"class_list":["post-136854","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-fedora-os","tag-fedora","tag-fedora-project-community","tag-gdb","tag-magazine","tag-news"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/136854","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=136854"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/136854\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media\/136855"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=136854"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=136854"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=136854"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}