* [PATCH 0/1] Fix block filter heuristic in linespec to preserve distinct code paths
@ 2026-04-21 13:31 Klaus Gerlicher
2026-04-21 13:31 ` [PATCH 1/1] gdb/linespec: relax block filter " Klaus Gerlicher
0 siblings, 1 reply; 3+ messages in thread
From: Klaus Gerlicher @ 2026-04-21 13:31 UTC (permalink / raw)
To: gdb-patches
Hi all,
This series tries to address a shortcoming in the block filter heuristic in
linespec.c that causes breakpoints in vectorized loops to silently miss
execution paths.
What is wrong?
==============
When a compiler vectorizes a loop (with -O2 -ftree-vectorize on GCC or -O2 on
ICX), it emits two separate machine code regions for the same source line: a
vectorized body and a scalar remainder. Both have is_stmt entries in the DWARF
line table and live in the same function block. The original heuristic kept only
the first entry per block, discarding the scalar remainder. Consequently, when
the trip count is small enough to execute only the scalar path, the breakpoint
is never hit.
How to maybe fix it?
====================
The general idea is to analyze the instruction stream for branches—specifically,
backward branches and unconditional exits. Instead of blindly keeping only the
first is_stmt entry per block, the fix now asks: "can execution fall through
from PC_A to PC_B in a straight line?" If not, the entriesrepresent distinct
code paths and both are preserved.
Two conditions indicate distinct code paths:
1. Unconditional exit: The last instruction before PC_B is an unconditional
jmp or ret
2. Backward branch: Any instruction in the range is a relative branch whose
target lies before PC_A (loop back-edge)
Notes
=====
A new gdbarch method gdbarch_insn_branch_target decodes the statically-known
target of relative branch instructions. It is currently implemented for amd64;
other architectures return a conservative default, preserving backward
compatibility. Architectures without instruction analysis support maintain the
original for-loop deduplication behavior, ensuring no regressions.
Testing
=======
The original heuristic had only one test case I found. Since compiler
optimization generates complex code patterns, comprehensive test coverage now
includes:
- for_loop_empty_body (-O0): Empty loop; expects 1 location
- for_loop_large_body (-O0): Large loop body exceeding former scan limits;
expects 1 location
- for_loop_vectorized (-O2 -ftree-vectorize): Vectorized loop; expects ≥2
locations with runtime reachability verification
- nested_vectorized_loops (-O2 -ftree-vectorize): Nested vectorization;
expects ≥2 locations
- loop_with_early_break (-O2): Loop with conditional break; expects ≥2 or
1 location
- ifelse_separate_lines (-O0): If-else with both branches on same line;
expects 2 locations (sanity check for potential false merges)
All tests are built with both -O0 and -O2 -ftree-vectorize flags. Behavioral
tests validate that the tuning setting "set linespec-extended-block-filter off"
actually changes breakpoint resolution behavior.
Limitations
===========
This can naturally be extended arbitrarily with more knowledge about what
compilers emit, but it's a heuristic nonetheless. Current limitations include:
- Indirect branches are not analyzed (statically unknown targets)
- Only relative branch encodings are decoded
- Architecture support is limited to amd64 initially
- Tested with GCC 11 and ICX 2025.2 on x86_64
Klaus Gerlicher (1):
gdb/linespec: relax block filter to preserve distinct code paths
gdb/NEWS | 11 +
gdb/amd64-tdep.c | 57 ++++
gdb/arch-utils.c | 10 +
gdb/arch-utils.h | 1 +
gdb/gdbarch-gen.c | 22 ++
gdb/gdbarch-gen.h | 10 +
gdb/gdbarch_components.py | 15 ++
gdb/linespec.c | 95 ++++++-
.../gdb.linespec/block-filter-cases.c | 126 +++++++++
.../gdb.linespec/block-filter-cases.exp | 248 ++++++++++++++++++
10 files changed, 592 insertions(+), 3 deletions(-)
create mode 100644 gdb/testsuite/gdb.linespec/block-filter-cases.c
create mode 100644 gdb/testsuite/gdb.linespec/block-filter-cases.exp
--
2.34.1
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/1] gdb/linespec: relax block filter to preserve distinct code paths
2026-04-21 13:31 [PATCH 0/1] Fix block filter heuristic in linespec to preserve distinct code paths Klaus Gerlicher
@ 2026-04-21 13:31 ` Klaus Gerlicher
2026-04-30 16:06 ` Schimpe, Christina
0 siblings, 1 reply; 3+ messages in thread
From: Klaus Gerlicher @ 2026-04-21 13:31 UTC (permalink / raw)
To: gdb-patches
The block-based duplicate filter in create_sals_line_offset keeps only
the first is_stmt line table entry per block. This heuristic reduces
multiple for-loop header entries (init/test/increment on same line) to
single breakpoint locations. However, it is too aggressive for
vectorized loops, where the compiler emits separate code regions for
the vectorized body and scalar remainder, both on the same source line.
The filter discards the scalar remainder entry, causing breakpoints to
be silently missed when only the scalar path executes.
The fix introduces range_has_unconditional_flow_control, which analyzes
the instruction stream for two conditions indicating distinct code paths:
1. Unconditional exit: The last instruction before the second PC is an
unconditional jmp or ret (execution cannot fall through).
2. Backward branch: Any instruction in the range is a relative branch
targeting before the first PC (loop back-edge indicating separate
loop bodies).
A new gdbarch method gdbarch_insn_branch_target decodes relative branch
targets. Implemented for amd64; other architectures default to
conservative behavior, preserving backward compatibility.
Testing covers:
- for_loop_empty_body (-O0): 1 location
- for_loop_large_body (-O0): 1 location (exceeds former scan limits)
- for_loop_vectorized (-O2): >= 2 locations with runtime verification
- nested_vectorized_loops (-O2): >= 2 locations
- loop_with_early_break (-O2): >= 2 or 1 location
- ifelse_separate_lines (-O0): 2 locations (sanity check)
Tested with GCC 11 and ICX 2025.2 on x86_64.
---
gdb/NEWS | 11 +
gdb/amd64-tdep.c | 57 ++++
gdb/arch-utils.c | 10 +
gdb/arch-utils.h | 1 +
gdb/gdbarch-gen.c | 22 ++
gdb/gdbarch-gen.h | 10 +
gdb/gdbarch_components.py | 15 ++
gdb/linespec.c | 95 ++++++-
.../gdb.linespec/block-filter-cases.c | 126 +++++++++
.../gdb.linespec/block-filter-cases.exp | 248 ++++++++++++++++++
10 files changed, 592 insertions(+), 3 deletions(-)
create mode 100644 gdb/testsuite/gdb.linespec/block-filter-cases.c
create mode 100644 gdb/testsuite/gdb.linespec/block-filter-cases.exp
diff --git a/gdb/NEWS b/gdb/NEWS
index 6b5c2f6a46a..9b85bd79944 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -61,6 +61,17 @@
This fixes an issue where GDB could fail to find a type when relying
on the index. Any existing indexes should be regenerated.
+* Breakpoint location resolution has been improved for vectorized loops.
+ Previously, when setting a breakpoint on a source line with vectorized
+ code (at -O2 with -ftree-vectorize), GDB's block filter heuristic would
+ discard the scalar remainder location, causing breakpoints to be missed
+ when only the scalar path executed. GDB now correctly preserves multiple
+ locations for vectorized and scalar loop paths, improving debuggability
+ of optimized code.
+
+ Use "set linespec-extended-block-filter off" to disable the new
+ heuristic and revert to the original behavior if needed.
+
* Support for Floating Point Mode Register (FPMR) in AArch64.
* When running on the Windows Terminal console, GDB now supports
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 0d23abb3164..76450775d45 100755
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -1822,6 +1822,62 @@ amd64_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
return amd64_classify_insn_at (gdbarch, addr, amd64_jmp_p);
}
+/* Return the statically-known target of a relative branch instruction
+ (conditional Jcc, JMP, LOOP, JCXZ). Return std::nullopt for non-branch,
+ indirect branches, or when memory cannot be read. */
+
+static std::optional<CORE_ADDR>
+amd64_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_byte buf[16];
+
+ /* Read enough bytes for the longest relative-branch encoding. */
+ if (target_read_memory (addr, buf, sizeof (buf)) != 0)
+ return std::nullopt;
+
+ /* Skip a single REX prefix byte (0x40-0x4F). */
+ int off = 0;
+ if ((buf[0] & 0xf0) == 0x40)
+ off = 1;
+
+ const gdb_byte opc = buf[off];
+
+ /* Short conditional Jcc: 7x cc (2 bytes, signed 8-bit displacement). */
+ if ((opc & 0xf0) == 0x70)
+ return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
+
+ /* Short unconditional JMP: EB cc (2 bytes). */
+ if (opc == 0xeb)
+ return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
+
+ /* LOOP/LOOPE/LOOPNE: E2/E1/E0 cc (2 bytes, signed 8-bit displacement). */
+ if ((opc & 0xfd) == 0xe0)
+ return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
+
+ /* JCXZ/JECXZ/JRCXZ: E3 cc (2 bytes, signed 8-bit displacement). */
+ if (opc == 0xe3)
+ return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
+
+ /* Near conditional Jcc: 0F 8x cc cc cc cc (6 bytes, signed 32-bit). */
+ if (opc == 0x0f && (buf[off + 1] & 0xf0) == 0x80)
+ {
+ int32_t disp;
+ memcpy (&disp, buf + off + 2, sizeof (disp));
+ return addr + off + 6 + (LONGEST) disp;
+ }
+
+ /* Near unconditional JMP: E9 cc cc cc cc (5 bytes, signed 32-bit). */
+ if (opc == 0xe9)
+ {
+ int32_t disp;
+ memcpy (&disp, buf + off + 1, sizeof (disp));
+ return addr + off + 5 + (LONGEST) disp;
+ }
+
+ /* Indirect or far branches: target cannot be determined statically. */
+ return std::nullopt;
+}
+
/* Fix up the state of registers and memory after having single-stepped
a displaced instruction. */
@@ -3643,6 +3699,7 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
set_gdbarch_insn_is_call (gdbarch, amd64_insn_is_call);
set_gdbarch_insn_is_ret (gdbarch, amd64_insn_is_ret);
set_gdbarch_insn_is_jump (gdbarch, amd64_insn_is_jump);
+ set_gdbarch_insn_branch_target (gdbarch, amd64_insn_branch_target);
set_gdbarch_in_indirect_branch_thunk (gdbarch,
amd64_in_indirect_branch_thunk);
diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c
index ea0b3c111f9..28a8d33d139 100644
--- a/gdb/arch-utils.c
+++ b/gdb/arch-utils.c
@@ -45,6 +45,8 @@
#include "dis-asm.h"
+#include <optional>
+
bool
default_displaced_step_hw_singlestep (struct gdbarch *gdbarch)
{
@@ -923,6 +925,14 @@ default_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
/* See arch-utils.h. */
+std::optional<CORE_ADDR>
+default_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return std::nullopt;
+}
+
+/* See arch-utils.h. */
+
bool
default_program_breakpoint_here_p (struct gdbarch *gdbarch,
CORE_ADDR address)
diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h
index d5772575c7a..2ec7e5900a7 100644
--- a/gdb/arch-utils.h
+++ b/gdb/arch-utils.h
@@ -327,6 +327,7 @@ extern bool default_return_in_first_hidden_param_p (struct gdbarch *,
extern bool default_insn_is_call (struct gdbarch *, CORE_ADDR);
extern bool default_insn_is_ret (struct gdbarch *, CORE_ADDR);
extern bool default_insn_is_jump (struct gdbarch *, CORE_ADDR);
+extern std::optional<CORE_ADDR> default_insn_branch_target (struct gdbarch *, CORE_ADDR);
/* Default implementation of gdbarch_program_breakpoint_here_p. */
extern bool default_program_breakpoint_here_p (struct gdbarch *gdbarch,
diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c
index 1a8f21091b2..d31ad84280c 100644
--- a/gdb/gdbarch-gen.c
+++ b/gdb/gdbarch-gen.c
@@ -234,6 +234,7 @@ struct gdbarch
gdbarch_insn_is_call_ftype *insn_is_call = default_insn_is_call;
gdbarch_insn_is_ret_ftype *insn_is_ret = default_insn_is_ret;
gdbarch_insn_is_jump_ftype *insn_is_jump = default_insn_is_jump;
+ gdbarch_insn_branch_target_ftype *insn_branch_target = default_insn_branch_target;
gdbarch_program_breakpoint_here_p_ftype *program_breakpoint_here_p = default_program_breakpoint_here_p;
gdbarch_auxv_parse_ftype *auxv_parse = nullptr;
gdbarch_print_auxv_entry_ftype *print_auxv_entry = default_print_auxv_entry;
@@ -494,6 +495,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of insn_is_call, invalid_p == 0. */
/* Skip verify of insn_is_ret, invalid_p == 0. */
/* Skip verify of insn_is_jump, invalid_p == 0. */
+ /* Skip verify of insn_branch_target, invalid_p == 0. */
/* Skip verify of program_breakpoint_here_p, invalid_p == 0. */
/* Skip verify of auxv_parse, has predicate. */
/* Skip verify of print_auxv_entry, invalid_p == 0. */
@@ -1276,6 +1278,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
gdb_printf (file,
"gdbarch_dump: insn_is_jump = <%s>\n",
host_address_to_string (gdbarch->insn_is_jump));
+ gdb_printf (file,
+ "gdbarch_dump: insn_branch_target = <%s>\n",
+ host_address_to_string (gdbarch->insn_branch_target));
gdb_printf (file,
"gdbarch_dump: program_breakpoint_here_p = <%s>\n",
host_address_to_string (gdbarch->program_breakpoint_here_p));
@@ -4950,6 +4955,23 @@ set_gdbarch_insn_is_jump (struct gdbarch *gdbarch,
gdbarch->insn_is_jump = insn_is_jump;
}
+std::optional<CORE_ADDR>
+gdbarch_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ gdb_assert (gdbarch != nullptr);
+ gdb_assert (gdbarch->insn_branch_target != nullptr);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_insn_branch_target called\n");
+ return gdbarch->insn_branch_target (gdbarch, addr);
+}
+
+void
+set_gdbarch_insn_branch_target (struct gdbarch *gdbarch,
+ gdbarch_insn_branch_target_ftype insn_branch_target)
+{
+ gdbarch->insn_branch_target = insn_branch_target;
+}
+
bool
gdbarch_program_breakpoint_here_p (struct gdbarch *gdbarch, CORE_ADDR address)
{
diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
index c1394978568..e31ddc6b741 100644
--- a/gdb/gdbarch-gen.h
+++ b/gdb/gdbarch-gen.h
@@ -1592,6 +1592,16 @@ using gdbarch_insn_is_jump_ftype = bool (struct gdbarch *gdbarch, CORE_ADDR addr
bool gdbarch_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr);
void set_gdbarch_insn_is_jump (struct gdbarch *gdbarch, gdbarch_insn_is_jump_ftype *insn_is_jump);
+/* For a relative branch instruction at ADDR (conditional or
+ unconditional), return the statically-known branch target address.
+ Return std::nullopt for non-branch instructions, indirect branches,
+ or when reading memory fails. This is used to detect backward
+ loop back-edges during DWARF line-table analysis. */
+
+using gdbarch_insn_branch_target_ftype = std::optional<CORE_ADDR> (struct gdbarch *gdbarch, CORE_ADDR addr);
+std::optional<CORE_ADDR> gdbarch_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr);
+void set_gdbarch_insn_branch_target (struct gdbarch *gdbarch, gdbarch_insn_branch_target_ftype *insn_branch_target);
+
/* Return true if there's a program/permanent breakpoint planted in
memory at ADDRESS, return false otherwise. */
diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
index 7a329d92166..4dcf595f229 100644
--- a/gdb/gdbarch_components.py
+++ b/gdb/gdbarch_components.py
@@ -2524,6 +2524,21 @@ Return true if the instruction at ADDR is a jump; false otherwise.
invalid=False,
)
+Method(
+ comment="""
+For a relative branch instruction at ADDR (conditional or
+unconditional), return the statically-known branch target address.
+Return std::nullopt for non-branch instructions, indirect branches,
+or when reading memory fails. This is used to detect backward
+loop back-edges during DWARF line-table analysis.
+""",
+ type="std::optional<CORE_ADDR>",
+ name="insn_branch_target",
+ params=[("CORE_ADDR", "addr")],
+ predefault="default_insn_branch_target",
+ invalid=False,
+)
+
Method(
comment="""
Return true if there's a program/permanent breakpoint planted in
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 45e12e09272..e6305ddeabb 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -43,9 +43,12 @@
#include "gdbsupport/function-view.h"
#include "gdbsupport/def-vector.h"
#include <algorithm>
+#include "disasm.h"
+#include "gdbarch.h"
#include "inferior.h"
#include "gdbsupport/unordered_set.h"
#include "cli/cli-style.h"
+#include "cli/cli-cmds.h"
/* An enumeration of the various things a user might attempt to
complete for a linespec location. */
@@ -431,6 +434,11 @@ static bool compare_msymbols (const bound_minimal_symbol &a,
previous parser. */
static const char linespec_quote_characters[] = "\"\'";
+/* Control whether the extended block-filter heuristic is enabled.
+ This heuristic improves breakpoint location resolution for vectorized
+ loops but can be disabled if it causes unexpected behavior. */
+static bool debug_linespec_extended_block_filter = true;
+
/* Lexer functions. */
/* Lex a number from the input in PARSER. This only supports
@@ -1979,6 +1987,48 @@ canonicalize_linespec (struct linespec_state *state, const linespec *ls)
explicit_loc->set_string (explicit_loc->to_linespec ());
}
+/* Return true if PC_TO is unreachable by fall-through from PC_FROM.
+ Two conditions are sufficient: (1) any ret in [PC_FROM, PC_TO), or
+ (2) unconditional jump/ret immediately before PC_TO. Only the last
+ instruction before PC_TO matters; mid-range branches are ignored to
+ preserve for-loop deduplication. */
+
+static bool
+range_has_unconditional_flow_control (struct gdbarch *gdbarch,
+ CORE_ADDR pc_from, CORE_ADDR pc_to)
+{
+ if (pc_from >= pc_to)
+ return false;
+
+ /* Return true if: last instruction before PC_TO is unconditional
+ jmp/ret, or any instruction in range is a backward branch
+ (indicating separate loop bodies). */
+
+ CORE_ADDR pc = pc_from;
+
+ while (pc < pc_to)
+ {
+ int len = gdb_insn_length (gdbarch, pc);
+ if (len <= 0)
+ return false;
+
+ /* Check for backward branch (loop back-edge). */
+ std::optional<CORE_ADDR> target = gdbarch_insn_branch_target (gdbarch,
+ pc);
+ if (target.has_value() && target.value() < pc_from)
+ return true;
+
+ /* Is this the last instruction before PC_TO? */
+ if (pc + len >= pc_to)
+ return gdbarch_insn_is_jump (gdbarch, pc)
+ || gdbarch_insn_is_ret (gdbarch, pc);
+
+ pc += len;
+ }
+
+ return false;
+}
+
/* Given a line offset in LS, construct the relevant SALs. */
static std::vector<symtab_and_line>
@@ -2077,13 +2127,35 @@ create_sals_line_offset (struct linespec_state *self,
for (i = 0; i < intermediate_results.size (); ++i)
{
- if (blocks[i] != NULL)
+ if (blocks[i] != NULL && filter[i])
for (j = i + 1; j < intermediate_results.size (); ++j)
{
- if (blocks[j] == blocks[i])
+ if (blocks[j] == blocks[i] && filter[j])
{
+ const symtab_and_line &sal_i = intermediate_results[i];
+ const symtab_and_line &sal_j = intermediate_results[j];
+
+ auto [pc_lo, pc_hi] = std::minmax (sal_i.pc, sal_j.pc);
+
+ /* Without symtab info, don't filter — we can't reliably
+ determine if these are distinct code paths. */
+ if (sal_i.symtab == nullptr || sal_j.symtab == nullptr)
+ continue;
+
+ if (sal_i.symtab != sal_j.symtab)
+ continue;
+
+ /* Check for unconditional flow control in the range
+ (extended heuristic; can be disabled). */
+ objfile *ofile = sal_i.symtab->compunit ()->objfile ();
+ gdbarch *gdbarch = ofile->arch ();
+
+ if (debug_linespec_extended_block_filter
+ && range_has_unconditional_flow_control (gdbarch,
+ pc_lo, pc_hi))
+ continue;
+
filter[j] = 0;
- break;
}
}
}
@@ -4330,3 +4402,20 @@ get_gdb_linespec_parser_quote_characters (void)
{
return linespec_quote_characters;
}
+
+/* Register linespec debugging commands. */
+
+INIT_GDB_FILE (linespec)
+{
+ add_setshow_boolean_cmd ("linespec-extended-block-filter",
+ class_support,
+ &debug_linespec_extended_block_filter, _("\
+Set whether the extended block-filter heuristic is enabled."), _("\
+Show whether the extended block-filter heuristic is enabled."), _("\
+The extended heuristic improves breakpoint location resolution for\n\
+vectorized loops at -O2. When off, breakpoints use only the original\n\
+heuristic, which may miss locations in vectorized code.\n\
+Default is on."),
+ nullptr, nullptr,
+ &setlist, &showlist);
+}
diff --git a/gdb/testsuite/gdb.linespec/block-filter-cases.c b/gdb/testsuite/gdb.linespec/block-filter-cases.c
new file mode 100644
index 00000000000..8cf834e95f4
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/block-filter-cases.c
@@ -0,0 +1,126 @@
+/* Test cases for the block-filter heuristic in create_sals_line_offset.
+
+ Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>.
+
+ One function per tested pattern. The accompanying .exp file verifies
+ the breakpoint location count for each pattern and, where vectorisation
+ is present, confirms that both the vectorized and scalar-remainder paths
+ are reachable at runtime.
+
+ argc > 1 -> for_loop_vectorized called with n=1024 (vectorized path)
+ argc == 1 -> for_loop_vectorized called with n=3 (scalar path only) */
+
+volatile int sink;
+
+/* for-loop with empty body (-O0). Expected: 1 location. */
+
+void __attribute__ ((noinline))
+for_loop_empty_body (int n)
+{
+ for (int i = 0; i < n; i++) {} /* empty-for-line */
+}
+
+/* for-loop with large body (-O0). Expected: 1 location. */
+
+void __attribute__ ((noinline))
+for_loop_large_body (volatile int *a, volatile int *b, volatile int *c,
+ int n)
+{
+ for (int i = 0; i < n; i++) { /* large-body-for-line */
+ sink = a[i] * 3 + b[i];
+ sink = sink ^ (sink >> 5);
+ sink += c[i] * 7 - a[i];
+ sink = (sink << 3) | (sink >> 29);
+ sink += a[i] + b[i] + c[i];
+ sink = sink * sink + a[i];
+ sink ^= b[i] * c[i];
+ sink += (a[i] | b[i]) & c[i];
+ sink = sink - a[i] * b[i];
+ sink += c[i] ^ (a[i] + b[i]);
+ sink += a[i] * 5 - b[i] * 3;
+ sink ^= (sink << 7) | (sink >> 25);
+ sink += c[i] * c[i] + a[i];
+ sink = sink / (a[i] + 1);
+ sink += b[i] * b[i] - c[i];
+ sink ^= a[i] ^ b[i] ^ c[i];
+ sink += (a[i] + b[i]) * (b[i] + c[i]);
+ sink = (sink >> 3) + a[i];
+ sink += c[i] * (a[i] - b[i]);
+ sink ^= sink >> 1;
+ }
+}
+
+/* Vectorized for-loop (-O2). Expected: >= 2 locations. */
+
+void __attribute__ ((noinline))
+for_loop_vectorized (int *arr, int n)
+{
+ for (int i = 0; i < n; i++)
+ arr[i] = i * 3; /* vec-loop-line */
+}
+
+/* Nested vectorized for-loops (-O2). Expected: >= 2 locations. */
+
+void __attribute__ ((noinline))
+nested_vectorized_loops (int *arr, int n)
+{
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < n; j++)
+ arr[i * n + j] = i * j; /* nested-vec-line */
+}
+
+/* For-loop with early break (-O2). Expected: >= 2 or 1 location. */
+
+void __attribute__ ((noinline))
+loop_with_early_break (int *arr, int n, int target)
+{
+ for (int i = 0; i < n; i++) {
+ arr[i] = i * 2; /* break-loop-line */
+ if (arr[i] == target)
+ break;
+ }
+}
+
+/* If-else with both branches on same line (-O0). Expected: 2 locations. */
+
+void __attribute__ ((noinline))
+ifelse_separate_lines (int x, int *result)
+{
+ if (x > 0)
+ *result = x * 2; else *result = -x; /* ifelse-line */
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int arr[1024];
+ volatile int a[4] = {1, 2, 3, 4};
+ volatile int b[4] = {4, 3, 2, 1};
+ volatile int c[4] = {1, 1, 1, 1};
+ int result = 0;
+
+ for_loop_empty_body (4);
+ for_loop_large_body (a, b, c, 4);
+ for_loop_vectorized (arr, argc > 1 ? 1024 : 3);
+ nested_vectorized_loops (arr, argc > 1 ? 32 : 3);
+ loop_with_early_break (arr, argc > 1 ? 1024 : 3, 42);
+ ifelse_separate_lines (argc > 1 ? 10 : -5, &result);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.linespec/block-filter-cases.exp b/gdb/testsuite/gdb.linespec/block-filter-cases.exp
new file mode 100644
index 00000000000..fa4ce5315c6
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/block-filter-cases.exp
@@ -0,0 +1,248 @@
+# Copyright (C) 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/>.
+
+# Verify the block-filter heuristic in create_sals_line_offset against
+# known patterns. The compiler is selected by the board file; this test
+# uses consistent expectations across compilers (GCC, ICX, etc.).
+
+standard_testfile
+
+if { [build_executable "failed to prepare (O0)" \
+ "${testfile}-O0" ${srcfile} { debug optimize=-O0 }] } {
+ return -1
+}
+
+if { [build_executable "failed to prepare (O2)" \
+ "${testfile}-O2" ${srcfile} \
+ { debug optimize=-O2 additional_flags=-ftree-vectorize }] } {
+ return -1
+}
+
+# Retrieve all target line numbers from the single shared source file.
+set line_empty_for [gdb_get_line_number "empty-for-line" ${srcfile}]
+set line_large_body_for [gdb_get_line_number "large-body-for-line" ${srcfile}]
+set line_vec_loop [gdb_get_line_number "vec-loop-line" ${srcfile}]
+set line_nested_vec [gdb_get_line_number "nested-vec-line" ${srcfile}]
+set line_break_loop [gdb_get_line_number "break-loop-line" ${srcfile}]
+set line_ifelse [gdb_get_line_number "ifelse-line" ${srcfile}]
+
+# Set breakpoint and return how many locations it resolves to.
+proc bp_nlocs { srcfile line desc } {
+ global gdb_prompt
+ set nlocs -1
+ gdb_test_multiple "break ${srcfile}:${line}" $desc {
+ -re "Breakpoint \[0-9\]+ at .*\\((\[0-9\]+) locations\\).*$gdb_prompt $" {
+ set nlocs $expect_out(1,string)
+ pass $desc
+ }
+ -re "Breakpoint \[0-9\]+ at .*$gdb_prompt $" {
+ set nlocs 1
+ pass $desc
+ }
+ }
+ return $nlocs
+}
+
+clean_restart "${testfile}-O0"
+
+# Verify the linespec-extended-block-filter setting exists and works.
+gdb_test "show linespec-extended-block-filter" \
+ "Whether the extended block-filter heuristic is enabled is on\\." \
+ "show default linespec-extended-block-filter (on)"
+
+gdb_test_no_output "set linespec-extended-block-filter off" \
+ "set linespec-extended-block-filter off"
+
+gdb_test "show linespec-extended-block-filter" \
+ "Whether the extended block-filter heuristic is enabled is off\\." \
+ "show linespec-extended-block-filter (off)"
+
+gdb_test_no_output "set linespec-extended-block-filter on" \
+ "set linespec-extended-block-filter on"
+
+gdb_test "show linespec-extended-block-filter" \
+ "Whether the extended block-filter heuristic is enabled is on\\." \
+ "show linespec-extended-block-filter re-enabled"
+
+with_test_prefix "for-loop empty body (-O0)" {
+ set nlocs [bp_nlocs ${srcfile} ${line_empty_for} "set breakpoint"]
+
+ if { $nlocs == 1 } {
+ pass "1 breakpoint location (correct)"
+ } else {
+ fail "expected 1 location, got $nlocs"
+ }
+
+ delete_breakpoints
+}
+
+with_test_prefix "for-loop exceeding scan limit (-O0)" {
+ set nlocs [bp_nlocs ${srcfile} ${line_large_body_for} "set breakpoint"]
+
+ if { $nlocs == 1 } {
+ pass "1 breakpoint location (correct)"
+ } else {
+ fail "expected 1 location, got $nlocs"
+ }
+
+ delete_breakpoints
+}
+
+with_test_prefix "if-else separate lines (-O0)" {
+ set nlocs [bp_nlocs ${srcfile} ${line_ifelse} "set breakpoint"]
+
+ if { $nlocs == 2 } {
+ pass "2 locations (if-else branches on same line, different blocks)"
+ } else {
+ fail "expected 2 locations, got $nlocs"
+ }
+
+ delete_breakpoints
+}
+
+clean_restart "${testfile}-O2"
+
+with_test_prefix "for-loop vectorized (-O2)" {
+ set nlocs [bp_nlocs ${srcfile} ${line_vec_loop} "set breakpoint"]
+
+ if { $nlocs < 2 } {
+ unsupported "compiler did not produce multiple locations;\
+ vectorization may not have fired"
+ } else {
+ pass "$nlocs locations preserved (vectorized + scalar paths)"
+ }
+
+ delete_breakpoints
+}
+
+with_test_prefix "nested vectorized loops (-O2)" {
+ set nlocs [bp_nlocs ${srcfile} ${line_nested_vec} "set breakpoint"]
+
+ if { $nlocs < 2 } {
+ unsupported "compiler did not produce multiple locations;\
+ nested vectorization may not have fired"
+ } else {
+ pass "$nlocs locations preserved (nested paths)"
+ }
+
+ delete_breakpoints
+}
+
+with_test_prefix "loop with early break (-O2)" {
+ set nlocs [bp_nlocs ${srcfile} ${line_break_loop} "set breakpoint"]
+
+ if { $nlocs >= 2 } {
+ pass "$nlocs locations preserved (normal and break paths)"
+ } else {
+ pass "$nlocs location (break path not separately compiled)"
+ }
+
+ delete_breakpoints
+}
+
+with_test_prefix "for-loop vectorized runtime (-O2)" {
+ clean_restart "${testfile}-O2"
+
+ set nlocs [bp_nlocs ${srcfile} ${line_vec_loop} "set breakpoint (probe)"]
+ delete_breakpoints
+
+ if { $nlocs < 2 } {
+ unsupported "only 1 location; skip reachability test"
+ } else {
+ with_test_prefix "scalar (n=3)" {
+ if { ![runto_main] } {
+ return -1
+ }
+
+ gdb_test "break ${srcfile}:${line_vec_loop}" \
+ "Breakpoint .* at .*" \
+ "set breakpoint"
+
+ gdb_test "continue" \
+ "Breakpoint .*, for_loop_vectorized .*" \
+ "hit breakpoint on scalar path"
+
+ delete_breakpoints
+ gdb_test "continue" ".*exited normally.*" "program exits cleanly"
+ }
+
+ clean_restart "${testfile}-O2"
+ gdb_test_no_output "set args foo" "set args for vectorized run"
+
+ if { ![runto_main] } {
+ return -1
+ }
+
+ with_test_prefix "vectorized (n=1024)" {
+ gdb_test "break ${srcfile}:${line_vec_loop}" \
+ "Breakpoint .* at .*" \
+ "set breakpoint"
+
+ gdb_test "continue" \
+ "Breakpoint .*, for_loop_vectorized .*" \
+ "hit breakpoint on vectorized path"
+
+ delete_breakpoints
+ gdb_test "continue" ".*exited normally.*" "program exits cleanly"
+ }
+ }
+}
+
+# Behavioral test: verify setting actually affects breakpoint resolution.
+with_test_prefix "behavioral: setting toggle affects resolution" {
+ clean_restart "${testfile}-O0"
+
+ # Test with extended filter ON (default).
+ gdb_test_no_output "set linespec-extended-block-filter on" \
+ "enable extended block-filter"
+
+ set nlocs_on [bp_nlocs ${srcfile} ${line_ifelse} \
+ "set breakpoint on if-else line with filter ON"]
+ delete_breakpoints
+
+ if { $nlocs_on == 2 } {
+ pass "if-else with extended filter ON: 2 locations"
+ } else {
+ fail "expected 2 locations with extended filter ON, got $nlocs_on"
+ }
+
+ # Test with extended filter OFF.
+ gdb_test_no_output "set linespec-extended-block-filter off" \
+ "disable extended block-filter"
+
+ set nlocs_off [bp_nlocs ${srcfile} ${line_ifelse} \
+ "set breakpoint on if-else line with filter OFF"]
+ delete_breakpoints
+
+ if { $nlocs_off == 1 } {
+ pass "if-else with extended filter OFF: 1 location"
+ } else {
+ fail "expected 1 location with extended filter OFF, got $nlocs_off"
+ }
+
+ # Verify toggling it back ON restores the two locations.
+ gdb_test_no_output "set linespec-extended-block-filter on" \
+ "re-enable extended block-filter"
+
+ set nlocs_on_again [bp_nlocs ${srcfile} ${line_ifelse} \
+ "set breakpoint on if-else line with filter re-enabled"]
+ delete_breakpoints
+
+ if { $nlocs_on_again == 2 } {
+ pass "if-else with extended filter re-enabled: 2 locations (verified)"
+ } else {
+ fail "expected 2 locations after re-enabling, got $nlocs_on_again"
+ }
+}
--
2.34.1
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 3+ messages in thread
* RE: [PATCH 1/1] gdb/linespec: relax block filter to preserve distinct code paths
2026-04-21 13:31 ` [PATCH 1/1] gdb/linespec: relax block filter " Klaus Gerlicher
@ 2026-04-30 16:06 ` Schimpe, Christina
0 siblings, 0 replies; 3+ messages in thread
From: Schimpe, Christina @ 2026-04-30 16:06 UTC (permalink / raw)
To: Gerlicher, Klaus, gdb-patches
> -----Original Message-----
> From: Klaus Gerlicher <klaus.gerlicher@intel.com>
> Sent: Dienstag, 21. April 2026 15:32
> To: gdb-patches@sourceware.org
> Subject: [PATCH 1/1] gdb/linespec: relax block filter to preserve distinct code
> paths
>
> The block-based duplicate filter in create_sals_line_offset keeps only the first
> is_stmt line table entry per block. This heuristic reduces multiple for-loop
> header entries (init/test/increment on same line) to single breakpoint
> locations. However, it is too aggressive for vectorized loops, where the
> compiler emits separate code regions for the vectorized body and scalar
> remainder, both on the same source line.
> The filter discards the scalar remainder entry, causing breakpoints to be
> silently missed when only the scalar path executes.
>
> The fix introduces range_has_unconditional_flow_control, which analyzes the
> instruction stream for two conditions indicating distinct code paths:
>
> 1. Unconditional exit: The last instruction before the second PC is an
> unconditional jmp or ret (execution cannot fall through).
>
> 2. Backward branch: Any instruction in the range is a relative branch
> targeting before the first PC (loop back-edge indicating separate
> loop bodies).
>
> A new gdbarch method gdbarch_insn_branch_target decodes relative branch
> targets. Implemented for amd64; other architectures default to conservative
> behavior, preserving backward compatibility.
>
> Testing covers:
> - for_loop_empty_body (-O0): 1 location
> - for_loop_large_body (-O0): 1 location (exceeds former scan limits)
> - for_loop_vectorized (-O2): >= 2 locations with runtime verification
> - nested_vectorized_loops (-O2): >= 2 locations
> - loop_with_early_break (-O2): >= 2 or 1 location
> - ifelse_separate_lines (-O0): 2 locations (sanity check)
>
> Tested with GCC 11 and ICX 2025.2 on x86_64.
> ---
> gdb/NEWS | 11 +
> gdb/amd64-tdep.c | 57 ++++
> gdb/arch-utils.c | 10 +
> gdb/arch-utils.h | 1 +
> gdb/gdbarch-gen.c | 22 ++
> gdb/gdbarch-gen.h | 10 +
> gdb/gdbarch_components.py | 15 ++
> gdb/linespec.c | 95 ++++++-
> .../gdb.linespec/block-filter-cases.c | 126 +++++++++
> .../gdb.linespec/block-filter-cases.exp | 248 ++++++++++++++++++
> 10 files changed, 592 insertions(+), 3 deletions(-) create mode 100644
> gdb/testsuite/gdb.linespec/block-filter-cases.c
> create mode 100644 gdb/testsuite/gdb.linespec/block-filter-cases.exp
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 6b5c2f6a46a..9b85bd79944 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -61,6 +61,17 @@
> This fixes an issue where GDB could fail to find a type when relying
> on the index. Any existing indexes should be regenerated.
>
> +* Breakpoint location resolution has been improved for vectorized loops.
> + Previously, when setting a breakpoint on a source line with
> +vectorized
> + code (at -O2 with -ftree-vectorize), GDB's block filter heuristic
> +would
> + discard the scalar remainder location, causing breakpoints to be
> +missed
> + when only the scalar path executed. GDB now correctly preserves
> +multiple
> + locations for vectorized and scalar loop paths, improving
> +debuggability
> + of optimized code.
> +
> + Use "set linespec-extended-block-filter off" to disable the new
> + heuristic and revert to the original behavior if needed.
> +
> * Support for Floating Point Mode Register (FPMR) in AArch64.
>
> * When running on the Windows Terminal console, GDB now supports diff --
> git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index
> 0d23abb3164..76450775d45 100755
> --- a/gdb/amd64-tdep.c
> +++ b/gdb/amd64-tdep.c
> @@ -1822,6 +1822,62 @@ amd64_insn_is_jump (struct gdbarch *gdbarch,
> CORE_ADDR addr)
> return amd64_classify_insn_at (gdbarch, addr, amd64_jmp_p); }
>
> +/* Return the statically-known target of a relative branch instruction
> + (conditional Jcc, JMP, LOOP, JCXZ). Return std::nullopt for non-branch,
> + indirect branches, or when memory cannot be read. */
> +
> +static std::optional<CORE_ADDR>
> +amd64_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr) {
> + gdb_byte buf[16];
> +
> + /* Read enough bytes for the longest relative-branch encoding. */
> + if (target_read_memory (addr, buf, sizeof (buf)) != 0)
> + return std::nullopt;
> +
> + /* Skip a single REX prefix byte (0x40-0x4F). */ int off = 0; if
> + ((buf[0] & 0xf0) == 0x40)
> + off = 1;
> +
> + const gdb_byte opc = buf[off];
> +
> + /* Short conditional Jcc: 7x cc (2 bytes, signed 8-bit
> + displacement). */ if ((opc & 0xf0) == 0x70)
> + return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
> +
> + /* Short unconditional JMP: EB cc (2 bytes). */ if (opc == 0xeb)
> + return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
> +
> + /* LOOP/LOOPE/LOOPNE: E2/E1/E0 cc (2 bytes, signed 8-bit
> + displacement). */ if ((opc & 0xfd) == 0xe0)
> + return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
> +
> + /* JCXZ/JECXZ/JRCXZ: E3 cc (2 bytes, signed 8-bit displacement). */
> + if (opc == 0xe3)
> + return addr + off + 2 + (LONGEST) (signed char) buf[off + 1];
> +
> + /* Near conditional Jcc: 0F 8x cc cc cc cc (6 bytes, signed 32-bit).
> + */ if (opc == 0x0f && (buf[off + 1] & 0xf0) == 0x80)
> + {
> + int32_t disp;
> + memcpy (&disp, buf + off + 2, sizeof (disp));
> + return addr + off + 6 + (LONGEST) disp;
> + }
> +
> + /* Near unconditional JMP: E9 cc cc cc cc (5 bytes, signed 32-bit).
> + */ if (opc == 0xe9)
> + {
> + int32_t disp;
> + memcpy (&disp, buf + off + 1, sizeof (disp));
> + return addr + off + 5 + (LONGEST) disp;
> + }
> +
> + /* Indirect or far branches: target cannot be determined statically.
> +*/
> + return std::nullopt;
> +}
> +
> /* Fix up the state of registers and memory after having single-stepped
> a displaced instruction. */
>
> @@ -3643,6 +3699,7 @@ amd64_init_abi (struct gdbarch_info info, struct
> gdbarch *gdbarch,
> set_gdbarch_insn_is_call (gdbarch, amd64_insn_is_call);
> set_gdbarch_insn_is_ret (gdbarch, amd64_insn_is_ret);
> set_gdbarch_insn_is_jump (gdbarch, amd64_insn_is_jump);
> + set_gdbarch_insn_branch_target (gdbarch, amd64_insn_branch_target);
>
> set_gdbarch_in_indirect_branch_thunk (gdbarch,
> amd64_in_indirect_branch_thunk);
> diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index
> ea0b3c111f9..28a8d33d139 100644
> --- a/gdb/arch-utils.c
> +++ b/gdb/arch-utils.c
> @@ -45,6 +45,8 @@
>
> #include "dis-asm.h"
>
> +#include <optional>
> +
> bool
> default_displaced_step_hw_singlestep (struct gdbarch *gdbarch) { @@ -
> 923,6 +925,14 @@ default_insn_is_jump (struct gdbarch *gdbarch,
> CORE_ADDR addr)
>
> /* See arch-utils.h. */
>
> +std::optional<CORE_ADDR>
> +default_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr) {
> + return std::nullopt;
> +}
> +
> +/* See arch-utils.h. */
> +
> bool
> default_program_breakpoint_here_p (struct gdbarch *gdbarch,
> CORE_ADDR address)
> diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index
> d5772575c7a..2ec7e5900a7 100644
> --- a/gdb/arch-utils.h
> +++ b/gdb/arch-utils.h
> @@ -327,6 +327,7 @@ extern bool default_return_in_first_hidden_param_p
> (struct gdbarch *, extern bool default_insn_is_call (struct gdbarch *,
> CORE_ADDR); extern bool default_insn_is_ret (struct gdbarch *,
> CORE_ADDR); extern bool default_insn_is_jump (struct gdbarch *,
> CORE_ADDR);
> +extern std::optional<CORE_ADDR> default_insn_branch_target (struct
> +gdbarch *, CORE_ADDR);
>
> /* Default implementation of gdbarch_program_breakpoint_here_p. */
> extern bool default_program_breakpoint_here_p (struct gdbarch *gdbarch,
> diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index
> 1a8f21091b2..d31ad84280c 100644
> --- a/gdb/gdbarch-gen.c
> +++ b/gdb/gdbarch-gen.c
> @@ -234,6 +234,7 @@ struct gdbarch
> gdbarch_insn_is_call_ftype *insn_is_call = default_insn_is_call;
> gdbarch_insn_is_ret_ftype *insn_is_ret = default_insn_is_ret;
> gdbarch_insn_is_jump_ftype *insn_is_jump = default_insn_is_jump;
> + gdbarch_insn_branch_target_ftype *insn_branch_target =
> + default_insn_branch_target;
> gdbarch_program_breakpoint_here_p_ftype *program_breakpoint_here_p
> = default_program_breakpoint_here_p;
> gdbarch_auxv_parse_ftype *auxv_parse = nullptr;
> gdbarch_print_auxv_entry_ftype *print_auxv_entry =
> default_print_auxv_entry; @@ -494,6 +495,7 @@ verify_gdbarch (struct
> gdbarch *gdbarch)
> /* Skip verify of insn_is_call, invalid_p == 0. */
> /* Skip verify of insn_is_ret, invalid_p == 0. */
> /* Skip verify of insn_is_jump, invalid_p == 0. */
> + /* Skip verify of insn_branch_target, invalid_p == 0. */
> /* Skip verify of program_breakpoint_here_p, invalid_p == 0. */
> /* Skip verify of auxv_parse, has predicate. */
> /* Skip verify of print_auxv_entry, invalid_p == 0. */ @@ -1276,6 +1278,9
> @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
> gdb_printf (file,
> "gdbarch_dump: insn_is_jump = <%s>\n",
> host_address_to_string (gdbarch->insn_is_jump));
> + gdb_printf (file,
> + "gdbarch_dump: insn_branch_target = <%s>\n",
> + host_address_to_string (gdbarch->insn_branch_target));
> gdb_printf (file,
> "gdbarch_dump: program_breakpoint_here_p = <%s>\n",
> host_address_to_string (gdbarch->program_breakpoint_here_p));
> @@ -4950,6 +4955,23 @@ set_gdbarch_insn_is_jump (struct gdbarch
> *gdbarch,
> gdbarch->insn_is_jump = insn_is_jump; }
>
> +std::optional<CORE_ADDR>
> +gdbarch_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr) {
> + gdb_assert (gdbarch != nullptr);
> + gdb_assert (gdbarch->insn_branch_target != nullptr);
> + if (gdbarch_debug >= 2)
> + gdb_printf (gdb_stdlog, "gdbarch_insn_branch_target called\n");
> + return gdbarch->insn_branch_target (gdbarch, addr); }
> +
> +void
> +set_gdbarch_insn_branch_target (struct gdbarch *gdbarch,
> + gdbarch_insn_branch_target_ftype
> insn_branch_target) {
> + gdbarch->insn_branch_target = insn_branch_target; }
> +
> bool
> gdbarch_program_breakpoint_here_p (struct gdbarch *gdbarch,
> CORE_ADDR address) { diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h
> index c1394978568..e31ddc6b741 100644
> --- a/gdb/gdbarch-gen.h
> +++ b/gdb/gdbarch-gen.h
> @@ -1592,6 +1592,16 @@ using gdbarch_insn_is_jump_ftype = bool (struct
> gdbarch *gdbarch, CORE_ADDR addr bool gdbarch_insn_is_jump (struct
> gdbarch *gdbarch, CORE_ADDR addr); void set_gdbarch_insn_is_jump (struct
> gdbarch *gdbarch, gdbarch_insn_is_jump_ftype *insn_is_jump);
>
> +/* For a relative branch instruction at ADDR (conditional or
> + unconditional), return the statically-known branch target address.
> + Return std::nullopt for non-branch instructions, indirect branches,
> + or when reading memory fails. This is used to detect backward
> + loop back-edges during DWARF line-table analysis. */
> +
> +using gdbarch_insn_branch_target_ftype = std::optional<CORE_ADDR>
> +(struct gdbarch *gdbarch, CORE_ADDR addr); std::optional<CORE_ADDR>
> +gdbarch_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr);
> +void set_gdbarch_insn_branch_target (struct gdbarch *gdbarch,
> +gdbarch_insn_branch_target_ftype *insn_branch_target);
> +
> /* Return true if there's a program/permanent breakpoint planted in
> memory at ADDRESS, return false otherwise. */
>
> diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py
> index 7a329d92166..4dcf595f229 100644
> --- a/gdb/gdbarch_components.py
> +++ b/gdb/gdbarch_components.py
> @@ -2524,6 +2524,21 @@ Return true if the instruction at ADDR is a jump;
> false otherwise.
> invalid=False,
> )
>
> +Method(
> + comment="""
> +For a relative branch instruction at ADDR (conditional or
> +unconditional), return the statically-known branch target address.
> +Return std::nullopt for non-branch instructions, indirect branches, or
> +when reading memory fails. This is used to detect backward loop
> +back-edges during DWARF line-table analysis.
> +""",
> + type="std::optional<CORE_ADDR>",
> + name="insn_branch_target",
> + params=[("CORE_ADDR", "addr")],
> + predefault="default_insn_branch_target",
> + invalid=False,
> +)
> +
> Method(
> comment="""
> Return true if there's a program/permanent breakpoint planted in diff --git
> a/gdb/linespec.c b/gdb/linespec.c index 45e12e09272..e6305ddeabb
> 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -43,9 +43,12 @@
> #include "gdbsupport/function-view.h"
> #include "gdbsupport/def-vector.h"
> #include <algorithm>
> +#include "disasm.h"
> +#include "gdbarch.h"
> #include "inferior.h"
> #include "gdbsupport/unordered_set.h"
> #include "cli/cli-style.h"
> +#include "cli/cli-cmds.h"
>
> /* An enumeration of the various things a user might attempt to
> complete for a linespec location. */ @@ -431,6 +434,11 @@ static bool
> compare_msymbols (const bound_minimal_symbol &a,
> previous parser. */
> static const char linespec_quote_characters[] = "\"\'";
>
> +/* Control whether the extended block-filter heuristic is enabled.
> + This heuristic improves breakpoint location resolution for vectorized
> + loops but can be disabled if it causes unexpected behavior. */
> +static bool debug_linespec_extended_block_filter = true;
> +
> /* Lexer functions. */
>
> /* Lex a number from the input in PARSER. This only supports @@ -1979,6
> +1987,48 @@ canonicalize_linespec (struct linespec_state *state, const
> linespec *ls)
> explicit_loc->set_string (explicit_loc->to_linespec ()); }
>
> +/* Return true if PC_TO is unreachable by fall-through from PC_FROM.
> + Two conditions are sufficient: (1) any ret in [PC_FROM, PC_TO), or
> + (2) unconditional jump/ret immediately before PC_TO. Only the last
> + instruction before PC_TO matters; mid-range branches are ignored to
> + preserve for-loop deduplication. */
> +
> +static bool
> +range_has_unconditional_flow_control (struct gdbarch *gdbarch,
> + CORE_ADDR pc_from, CORE_ADDR pc_to)
> {
> + if (pc_from >= pc_to)
> + return false;
> +
> + /* Return true if: last instruction before PC_TO is unconditional
> + jmp/ret, or any instruction in range is a backward branch
> + (indicating separate loop bodies). */
> +
> + CORE_ADDR pc = pc_from;
> +
> + while (pc < pc_to)
> + {
> + int len = gdb_insn_length (gdbarch, pc);
> + if (len <= 0)
> + return false;
> +
> + /* Check for backward branch (loop back-edge). */
> + std::optional<CORE_ADDR> target = gdbarch_insn_branch_target
> (gdbarch,
> + pc);
> + if (target.has_value() && target.value() < pc_from)
> + return true;
> +
> + /* Is this the last instruction before PC_TO? */
> + if (pc + len >= pc_to)
> + return gdbarch_insn_is_jump (gdbarch, pc)
> + || gdbarch_insn_is_ret (gdbarch, pc);
> +
> + pc += len;
> + }
> +
> + return false;
> +}
> +
> /* Given a line offset in LS, construct the relevant SALs. */
>
> static std::vector<symtab_and_line>
> @@ -2077,13 +2127,35 @@ create_sals_line_offset (struct linespec_state
> *self,
>
> for (i = 0; i < intermediate_results.size (); ++i)
> {
> - if (blocks[i] != NULL)
> + if (blocks[i] != NULL && filter[i])
> for (j = i + 1; j < intermediate_results.size (); ++j)
> {
> - if (blocks[j] == blocks[i])
> + if (blocks[j] == blocks[i] && filter[j])
> {
> + const symtab_and_line &sal_i = intermediate_results[i];
> + const symtab_and_line &sal_j = intermediate_results[j];
> +
> + auto [pc_lo, pc_hi] = std::minmax (sal_i.pc, sal_j.pc);
> +
> + /* Without symtab info, don't filter — we can't reliably
> + determine if these are distinct code paths. */
> + if (sal_i.symtab == nullptr || sal_j.symtab == nullptr)
> + continue;
> +
> + if (sal_i.symtab != sal_j.symtab)
> + continue;
> +
> + /* Check for unconditional flow control in the range
> + (extended heuristic; can be disabled). */
> + objfile *ofile = sal_i.symtab->compunit ()->objfile ();
> + gdbarch *gdbarch = ofile->arch ();
> +
> + if (debug_linespec_extended_block_filter
> + && range_has_unconditional_flow_control (gdbarch,
> + pc_lo, pc_hi))
> + continue;
> +
> filter[j] = 0;
> - break;
> }
> }
> }
> @@ -4330,3 +4402,20 @@ get_gdb_linespec_parser_quote_characters
> (void) {
> return linespec_quote_characters;
> }
> +
> +/* Register linespec debugging commands. */
> +
> +INIT_GDB_FILE (linespec)
> +{
> + add_setshow_boolean_cmd ("linespec-extended-block-filter",
> + class_support,
> + &debug_linespec_extended_block_filter, _("\ Set
> whether the
> +extended block-filter heuristic is enabled."), _("\ Show whether the
> +extended block-filter heuristic is enabled."), _("\ The extended
> +heuristic improves breakpoint location resolution for\n\ vectorized
> +loops at -O2. When off, breakpoints use only the original\n\ heuristic,
> +which may miss locations in vectorized code.\n\ Default is on."),
> + nullptr, nullptr,
> + &setlist, &showlist);
> +}
> diff --git a/gdb/testsuite/gdb.linespec/block-filter-cases.c
> b/gdb/testsuite/gdb.linespec/block-filter-cases.c
> new file mode 100644
> index 00000000000..8cf834e95f4
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/block-filter-cases.c
> @@ -0,0 +1,126 @@
> +/* Test cases for the block-filter heuristic in create_sals_line_offset.
> +
> + Copyright (C) 2026 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + 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/>.
> +
> + One function per tested pattern. The accompanying .exp file verifies
> + the breakpoint location count for each pattern and, where vectorisation
> + is present, confirms that both the vectorized and scalar-remainder paths
> + are reachable at runtime.
> +
> + argc > 1 -> for_loop_vectorized called with n=1024 (vectorized path)
> + argc == 1 -> for_loop_vectorized called with n=3 (scalar path only) */
> +
> +volatile int sink;
> +
> +/* for-loop with empty body (-O0). Expected: 1 location. */
> +
> +void __attribute__ ((noinline))
> +for_loop_empty_body (int n)
> +{
> + for (int i = 0; i < n; i++) {} /* empty-for-line */ }
> +
> +/* for-loop with large body (-O0). Expected: 1 location. */
> +
> +void __attribute__ ((noinline))
> +for_loop_large_body (volatile int *a, volatile int *b, volatile int *c,
> + int n)
> +{
> + for (int i = 0; i < n; i++) { /* large-body-for-line */
> + sink = a[i] * 3 + b[i];
> + sink = sink ^ (sink >> 5);
> + sink += c[i] * 7 - a[i];
> + sink = (sink << 3) | (sink >> 29);
> + sink += a[i] + b[i] + c[i];
> + sink = sink * sink + a[i];
> + sink ^= b[i] * c[i];
> + sink += (a[i] | b[i]) & c[i];
> + sink = sink - a[i] * b[i];
> + sink += c[i] ^ (a[i] + b[i]);
> + sink += a[i] * 5 - b[i] * 3;
> + sink ^= (sink << 7) | (sink >> 25);
> + sink += c[i] * c[i] + a[i];
> + sink = sink / (a[i] + 1);
> + sink += b[i] * b[i] - c[i];
> + sink ^= a[i] ^ b[i] ^ c[i];
> + sink += (a[i] + b[i]) * (b[i] + c[i]);
> + sink = (sink >> 3) + a[i];
> + sink += c[i] * (a[i] - b[i]);
> + sink ^= sink >> 1;
> + }
> +}
> +
> +/* Vectorized for-loop (-O2). Expected: >= 2 locations. */
> +
> +void __attribute__ ((noinline))
> +for_loop_vectorized (int *arr, int n)
> +{
> + for (int i = 0; i < n; i++)
> + arr[i] = i * 3; /* vec-loop-line */ }
> +
> +/* Nested vectorized for-loops (-O2). Expected: >= 2 locations. */
> +
> +void __attribute__ ((noinline))
> +nested_vectorized_loops (int *arr, int n) {
> + for (int i = 0; i < n; i++)
> + for (int j = 0; j < n; j++)
> + arr[i * n + j] = i * j; /* nested-vec-line */ }
> +
> +/* For-loop with early break (-O2). Expected: >= 2 or 1 location. */
> +
> +void __attribute__ ((noinline))
> +loop_with_early_break (int *arr, int n, int target) {
> + for (int i = 0; i < n; i++) {
> + arr[i] = i * 2; /* break-loop-line */
> + if (arr[i] == target)
> + break;
> + }
> +}
> +
> +/* If-else with both branches on same line (-O0). Expected: 2
> +locations. */
> +
> +void __attribute__ ((noinline))
> +ifelse_separate_lines (int x, int *result) {
> + if (x > 0)
> + *result = x * 2; else *result = -x; /* ifelse-line */ }
> +
> +
> +int
> +main (int argc, char *argv[])
> +{
> + int arr[1024];
> + volatile int a[4] = {1, 2, 3, 4};
> + volatile int b[4] = {4, 3, 2, 1};
> + volatile int c[4] = {1, 1, 1, 1};
> + int result = 0;
> +
> + for_loop_empty_body (4);
> + for_loop_large_body (a, b, c, 4);
> + for_loop_vectorized (arr, argc > 1 ? 1024 : 3);
> + nested_vectorized_loops (arr, argc > 1 ? 32 : 3);
> + loop_with_early_break (arr, argc > 1 ? 1024 : 3, 42);
> + ifelse_separate_lines (argc > 1 ? 10 : -5, &result);
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.linespec/block-filter-cases.exp
> b/gdb/testsuite/gdb.linespec/block-filter-cases.exp
> new file mode 100644
> index 00000000000..fa4ce5315c6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/block-filter-cases.exp
> @@ -0,0 +1,248 @@
> +# Copyright (C) 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/>.
> +
> +# Verify the block-filter heuristic in create_sals_line_offset against
> +# known patterns. The compiler is selected by the board file; this test
> +# uses consistent expectations across compilers (GCC, ICX, etc.).
> +
> +standard_testfile
> +
> +if { [build_executable "failed to prepare (O0)" \
> + "${testfile}-O0" ${srcfile} { debug optimize=-O0 }] } {
> + return -1
> +}
> +
> +if { [build_executable "failed to prepare (O2)" \
> + "${testfile}-O2" ${srcfile} \
> + { debug optimize=-O2 additional_flags=-ftree-vectorize }] } {
> + return -1
> +}
> +
> +# Retrieve all target line numbers from the single shared source file.
> +set line_empty_for [gdb_get_line_number "empty-for-line" ${srcfile}]
> +set line_large_body_for [gdb_get_line_number "large-body-for-line"
> ${srcfile}]
> +set line_vec_loop [gdb_get_line_number "vec-loop-line" ${srcfile}]
> +set line_nested_vec [gdb_get_line_number "nested-vec-line" ${srcfile}]
> +set line_break_loop [gdb_get_line_number "break-loop-line" ${srcfile}]
> +set line_ifelse [gdb_get_line_number "ifelse-line" ${srcfile}]
> +
> +# Set breakpoint and return how many locations it resolves to.
> +proc bp_nlocs { srcfile line desc } {
> + global gdb_prompt
> + set nlocs -1
> + gdb_test_multiple "break ${srcfile}:${line}" $desc {
> + -re "Breakpoint \[0-9\]+ at .*\\((\[0-9\]+) locations\\).*$gdb_prompt
> $" {
> + set nlocs $expect_out(1,string)
> + pass $desc
> + }
> + -re "Breakpoint \[0-9\]+ at .*$gdb_prompt $" {
> + set nlocs 1
> + pass $desc
> + }
> + }
> + return $nlocs
> +}
> +
> +clean_restart "${testfile}-O0"
> +
> +# Verify the linespec-extended-block-filter setting exists and works.
> +gdb_test "show linespec-extended-block-filter" \
> + "Whether the extended block-filter heuristic is enabled is on\\." \
> + "show default linespec-extended-block-filter (on)"
> +
> +gdb_test_no_output "set linespec-extended-block-filter off" \
> + "set linespec-extended-block-filter off"
> +
> +gdb_test "show linespec-extended-block-filter" \
> + "Whether the extended block-filter heuristic is enabled is off\\." \
> + "show linespec-extended-block-filter (off)"
> +
> +gdb_test_no_output "set linespec-extended-block-filter on" \
> + "set linespec-extended-block-filter on"
> +
> +gdb_test "show linespec-extended-block-filter" \
> + "Whether the extended block-filter heuristic is enabled is on\\." \
> + "show linespec-extended-block-filter re-enabled"
> +
> +with_test_prefix "for-loop empty body (-O0)" {
> + set nlocs [bp_nlocs ${srcfile} ${line_empty_for} "set breakpoint"]
> +
> + if { $nlocs == 1 } {
> + pass "1 breakpoint location (correct)"
> + } else {
> + fail "expected 1 location, got $nlocs"
> + }
> +
> + delete_breakpoints
> +}
> +
> +with_test_prefix "for-loop exceeding scan limit (-O0)" {
> + set nlocs [bp_nlocs ${srcfile} ${line_large_body_for} "set breakpoint"]
> +
> + if { $nlocs == 1 } {
> + pass "1 breakpoint location (correct)"
> + } else {
> + fail "expected 1 location, got $nlocs"
> + }
> +
> + delete_breakpoints
> +}
> +
> +with_test_prefix "if-else separate lines (-O0)" {
> + set nlocs [bp_nlocs ${srcfile} ${line_ifelse} "set breakpoint"]
> +
> + if { $nlocs == 2 } {
> + pass "2 locations (if-else branches on same line, different blocks)"
> + } else {
> + fail "expected 2 locations, got $nlocs"
> + }
> +
> + delete_breakpoints
> +}
> +
> +clean_restart "${testfile}-O2"
> +
> +with_test_prefix "for-loop vectorized (-O2)" {
> + set nlocs [bp_nlocs ${srcfile} ${line_vec_loop} "set breakpoint"]
> +
> + if { $nlocs < 2 } {
> + unsupported "compiler did not produce multiple locations;\
> + vectorization may not have fired"
> + } else {
> + pass "$nlocs locations preserved (vectorized + scalar paths)"
> + }
> +
> + delete_breakpoints
> +}
> +
> +with_test_prefix "nested vectorized loops (-O2)" {
> + set nlocs [bp_nlocs ${srcfile} ${line_nested_vec} "set breakpoint"]
> +
> + if { $nlocs < 2 } {
> + unsupported "compiler did not produce multiple locations;\
> + nested vectorization may not have fired"
> + } else {
> + pass "$nlocs locations preserved (nested paths)"
> + }
> +
> + delete_breakpoints
> +}
> +
> +with_test_prefix "loop with early break (-O2)" {
> + set nlocs [bp_nlocs ${srcfile} ${line_break_loop} "set breakpoint"]
> +
> + if { $nlocs >= 2 } {
> + pass "$nlocs locations preserved (normal and break paths)"
> + } else {
> + pass "$nlocs location (break path not separately compiled)"
> + }
> +
> + delete_breakpoints
> +}
> +
> +with_test_prefix "for-loop vectorized runtime (-O2)" {
> + clean_restart "${testfile}-O2"
> +
> + set nlocs [bp_nlocs ${srcfile} ${line_vec_loop} "set breakpoint (probe)"]
> + delete_breakpoints
> +
> + if { $nlocs < 2 } {
> + unsupported "only 1 location; skip reachability test"
> + } else {
> + with_test_prefix "scalar (n=3)" {
> + if { ![runto_main] } {
> + return -1
> + }
> +
> + gdb_test "break ${srcfile}:${line_vec_loop}" \
> + "Breakpoint .* at .*" \
> + "set breakpoint"
> +
> + gdb_test "continue" \
> + "Breakpoint .*, for_loop_vectorized .*" \
> + "hit breakpoint on scalar path"
> +
> + delete_breakpoints
> + gdb_test "continue" ".*exited normally.*" "program exits cleanly"
> + }
> +
> + clean_restart "${testfile}-O2"
> + gdb_test_no_output "set args foo" "set args for vectorized run"
> +
> + if { ![runto_main] } {
> + return -1
> + }
> +
> + with_test_prefix "vectorized (n=1024)" {
> + gdb_test "break ${srcfile}:${line_vec_loop}" \
> + "Breakpoint .* at .*" \
> + "set breakpoint"
> +
> + gdb_test "continue" \
> + "Breakpoint .*, for_loop_vectorized .*" \
> + "hit breakpoint on vectorized path"
> +
> + delete_breakpoints
> + gdb_test "continue" ".*exited normally.*" "program exits cleanly"
> + }
> + }
> +}
> +
> +# Behavioral test: verify setting actually affects breakpoint resolution.
> +with_test_prefix "behavioral: setting toggle affects resolution" {
> + clean_restart "${testfile}-O0"
> +
> + # Test with extended filter ON (default).
> + gdb_test_no_output "set linespec-extended-block-filter on" \
> + "enable extended block-filter"
> +
> + set nlocs_on [bp_nlocs ${srcfile} ${line_ifelse} \
> + "set breakpoint on if-else line with filter ON"]
> + delete_breakpoints
> +
> + if { $nlocs_on == 2 } {
> + pass "if-else with extended filter ON: 2 locations"
> + } else {
> + fail "expected 2 locations with extended filter ON, got $nlocs_on"
> + }
> +
> + # Test with extended filter OFF.
> + gdb_test_no_output "set linespec-extended-block-filter off" \
> + "disable extended block-filter"
> +
> + set nlocs_off [bp_nlocs ${srcfile} ${line_ifelse} \
> + "set breakpoint on if-else line with filter OFF"]
> + delete_breakpoints
> +
> + if { $nlocs_off == 1 } {
> + pass "if-else with extended filter OFF: 1 location"
> + } else {
> + fail "expected 1 location with extended filter OFF, got $nlocs_off"
> + }
> +
> + # Verify toggling it back ON restores the two locations.
> + gdb_test_no_output "set linespec-extended-block-filter on" \
> + "re-enable extended block-filter"
> +
> + set nlocs_on_again [bp_nlocs ${srcfile} ${line_ifelse} \
> + "set breakpoint on if-else line with filter re-enabled"]
> + delete_breakpoints
> +
> + if { $nlocs_on_again == 2 } {
> + pass "if-else with extended filter re-enabled: 2 locations (verified)"
> + } else {
> + fail "expected 2 locations after re-enabling, got $nlocs_on_again"
> + }
> +}
> --
> 2.34.1
>
> Intel Deutschland GmbH
> Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
> Tel: +49 89 991 430, www.intel.de
> Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
> Chairperson of the Supervisory Board: Nicole Lau
> Registered Seat: Munich
> Commercial Register: Amtsgericht Muenchen HRB 186928
Hi Klaus,
Thank you for working on this.
For your patch I see new errors for gcc and clang in the following tests:
- gdb.threads/detach-step-over.exp
- gdb.ada/type_coercion.exp
- gdb.ada/overload_menu_crash.exp
They all show a similar error message:
~~~
(gdb) break main.adb:20^M
Cannot access memory at address 0x267a^M
(gdb) FAIL: gdb.ada/overload_menu_crash.exp:
~~~
Compiler versions:
~~~
$ gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
$ clang --version
Ubuntu clang version 14.0.0-1ubuntu1.1
~~~
Besides that, I did not have the time to review this in more detail but wanted to share some of my findings already.
Christina
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-30 16:07 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-21 13:31 [PATCH 0/1] Fix block filter heuristic in linespec to preserve distinct code paths Klaus Gerlicher
2026-04-21 13:31 ` [PATCH 1/1] gdb/linespec: relax block filter " Klaus Gerlicher
2026-04-30 16:06 ` Schimpe, Christina
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox