From: Luis <luis.machado.foss@gmail.com>
To: Klaus Gerlicher <klaus.gerlicher@intel.com>,
gdb-patches@sourceware.org, christina.joos@intel.com
Subject: Re: [PATCH v3 1/1] gdb/linespec: relax block filter to preserve distinct code paths
Date: Sat, 25 Jul 2026 08:54:35 +0100 [thread overview]
Message-ID: <db7238d2-1628-44ff-949e-0c176ff6257b@gmail.com> (raw)
In-Reply-To: <20260722093654.30044-2-klaus.gerlicher@intel.com>
Hi,
Thanks for the patch.
Skimming through it, it looks fine to me for the aarch64 parts.
On 22/07/2026 10:36, Klaus Gerlicher wrote:
> From: "Gerlicher, Klaus" <klaus.gerlicher@intel.com>
>
> 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 old heuristic collapses all same-block SALs for a given line down to
> a single breakpoint location, while the new heuristic preserves additional
> SALs when the instruction range between them ends with an unconditional jump
> or return, indicating they lie on genuinely distinct, non-fall-through code
> paths.
>
> 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 and aarch64; other architectures default
> to conservative behavior, preserving backward compatibility.
>
> Existing gdbarch_insn_is_jump and gdbarch_insn_is_ret are now also
> implemented for aarch64, enabling the heuristic on that platform too.
> Predicate functions are added to allow for chosing viability of this extended
> heuristic. Implemented on x86_64 and aarch64.
>
> Testing covers:
> - for_loop_empty_body (-O0): 1 location
> - for_loop_large_body (-O0): 1 location
> - 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 on x86_64/aarch64, unsupported
> elsewhere
> - set/show linespec-extended-block-filter reports on/off and
> architecture support correctly
>
> Tested with GCC 11 and ICX 2025.2 on x86_64, and on aarch64 (raspi5).
> ---
> gdb/NEWS | 11 +
> gdb/aarch64-tdep.c | 91 ++++++
> gdb/amd64-tdep.c | 57 ++++
> gdb/arch-utils.c | 10 +
> gdb/arch-utils.h | 1 +
> gdb/arch/aarch64-insn.c | 23 ++
> gdb/arch/aarch64-insn.h | 2 +
> gdb/gdbarch-gen.c | 59 +++-
> gdb/gdbarch-gen.h | 16 +
> gdb/gdbarch_components.py | 18 ++
> gdb/linespec.c | 148 ++++++++-
> .../gdb.linespec/block-filter-cases.c | 126 ++++++++
> .../gdb.linespec/block-filter-cases.exp | 291 ++++++++++++++++++
> 13 files changed, 848 insertions(+), 5 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 8f40ca5cb11..b587ac87763 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -68,6 +68,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. This is supported currently on x86 and aarch64.
> +
> + Use "set linespec-extended-block-filter off" to disable the new
> + heuristic on supported platforms 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/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index a84da1fd59e..5b45efbf8b9 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -4433,6 +4433,92 @@ aarch64_initialize_sme_pseudo_names (struct gdbarch *gdbarch,
> }
> }
>
> +/* Return the statically-known target of a relative branch instruction.
> + Handles B <imm26>, B.cond <imm19>, CBZ/CBNZ <imm19>, TBZ/TBNZ <imm14>.
> + Returns std::nullopt for indirect branches (BR) or unreadable memory. */
> +
> +static std::optional<CORE_ADDR>
> +aarch64_insn_branch_target (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_byte buf[4];
> +
> + if (target_read_memory (addr, buf, 4) != 0)
> + return std::nullopt;
> +
> + enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
> + uint32_t insn = extract_unsigned_integer (buf, 4, byte_order);
> +
> + int is_bl;
> + int32_t offset;
> +
> + /* B <imm26> (but not BL, which is a call). */
> + if (aarch64_decode_b (addr, insn, &is_bl, &offset) && !is_bl)
> + return addr + offset;
> +
> + /* B.cond <imm19>. */
> + unsigned cond;
> + if (aarch64_decode_bcond (addr, insn, &cond, &offset))
> + return addr + offset;
> +
> + /* CBZ/CBNZ <imm19>. */
> + int is64, is_cbnz;
> + unsigned rn;
> + if (aarch64_decode_cb (addr, insn, &is64, &is_cbnz, &rn, &offset))
> + return addr + offset;
> +
> + /* TBZ/TBNZ <imm14>. */
> + int is_tbnz;
> + unsigned bit, rt;
> + if (aarch64_decode_tb (addr, insn, &is_tbnz, &bit, &rt, &offset))
> + return addr + offset;
> +
> + return std::nullopt;
> +}
> +
> +/* Return true if the instruction at ADDR is an unconditional branch.
> + Handles direct B <imm26> and indirect BR <Xn>. */
> +
> +static bool
> +aarch64_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_byte buf[4];
> +
> + if (target_read_memory (addr, buf, 4) != 0)
> + return false;
> +
> + enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
> + uint32_t insn = extract_unsigned_integer (buf, 4, byte_order);
> +
> + /* B <imm26> (but not BL, which is a call). */
> + int is_bl;
> + int32_t offset;
> + if (aarch64_decode_b (addr, insn, &is_bl, &offset) && !is_bl)
> + return true;
> +
> + /* BR <Xn>: bits[31:10] fixed, bits[9:5] = Xn, bits[4:0] = 0.
> + No shared decoder exists for indirect branches. */
> + if ((insn & 0xFFFFFC1F) == 0xD61F0000)
> + return true;
> +
> + return false;
> +}
> +
> +/* Return true if the instruction at ADDR is a return. */
> +
> +static bool
> +aarch64_insn_is_ret (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + gdb_byte buf[4];
> +
> + if (target_read_memory (addr, buf, 4) != 0)
> + return false;
> +
> + enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
> + uint32_t insn = extract_unsigned_integer (buf, 4, byte_order);
> +
> + return aarch64_decode_ret (addr, insn);
> +}
> +
> /* Initialize the current architecture based on INFO. If possible,
> reuse an architecture from ARCHES, which is a list of
> architectures already created during this debugging session.
> @@ -4861,6 +4947,11 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> set_gdbarch_program_breakpoint_here_p (gdbarch,
> aarch64_program_breakpoint_here_p);
>
> + /* Instruction stream analysis. */
> + set_gdbarch_insn_is_jump (gdbarch, aarch64_insn_is_jump);
> + set_gdbarch_insn_is_ret (gdbarch, aarch64_insn_is_ret);
> + set_gdbarch_insn_branch_target (gdbarch, aarch64_insn_branch_target);
> +
> /* Add some default predicates. */
> frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);
> dwarf2_append_unwinders (gdbarch);
> diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
> index a982e610642..726bc475256 100644
> --- 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 e959788bd3b..f73d1581f09 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 06902050043..46d9d89e668 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/arch/aarch64-insn.c b/gdb/arch/aarch64-insn.c
> index f6089092eca..3ab28e6dd4b 100644
> --- a/gdb/arch/aarch64-insn.c
> +++ b/gdb/arch/aarch64-insn.c
> @@ -201,6 +201,29 @@ aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz,
> return 0;
> }
>
> +/* Decode an opcode if it represents a RET instruction.
> +
> + ADDR specifies the address of the opcode.
> + INSN specifies the opcode to test.
> +
> + Return 1 if the opcodes matches and is decoded, otherwise 0. */
> +
> +int
> +aarch64_decode_ret (CORE_ADDR addr, uint32_t insn)
> +{
> + /* ret b1101 0110 0100 nnnn n000 0000 0000 0000 */
> + if (decode_masked_match (insn, 0xFFE0FFFF, 0xD6400000))
> + {
> + unsigned int rn = (insn >> 15) & 0x1f;
> +
> + aarch64_debug_printf ("decode: 0x%s 0x%x x%u",
> + core_addr_to_string_nz (addr), insn,
> + rn);
> + return 1;
> + }
> + return 0;
> +}
> +
> /* Decode an opcode if it represents an LDR or LDRSW instruction taking a
> literal offset from the current PC.
>
> diff --git a/gdb/arch/aarch64-insn.h b/gdb/arch/aarch64-insn.h
> index 428e53c3858..aafbe3c0d6b 100644
> --- a/gdb/arch/aarch64-insn.h
> +++ b/gdb/arch/aarch64-insn.h
> @@ -200,6 +200,8 @@ int aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz,
> int aarch64_decode_ldr_literal (CORE_ADDR addr, uint32_t insn, int *is_w,
> int *is64, unsigned *rt, int32_t *offset);
>
> +int aarch64_decode_ret (CORE_ADDR addr, uint32_t insn);
> +
> /* Data passed to each method of aarch64_insn_visitor. */
>
> struct aarch64_insn_data
> diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c
> index f424fa2a86e..1cbb6459f87 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;
> @@ -492,8 +493,9 @@ verify_gdbarch (struct gdbarch *gdbarch)
> /* Skip verify of core_info_proc, has predicate. */
> /* Skip verify of ravenscar_ops, invalid_p == 0. */
> /* 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_is_ret, has predicate. */
> + /* Skip verify of insn_is_jump, has predicate. */
> + /* Skip verify of insn_branch_target, has predicate. */
> /* 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. */
> @@ -1270,12 +1272,24 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
> gdb_printf (file,
> "gdbarch_dump: insn_is_call = <%s>\n",
> host_address_to_string (gdbarch->insn_is_call));
> + gdb_printf (file,
> + "gdbarch_dump: gdbarch_insn_is_ret_p() = %d\n",
> + gdbarch_insn_is_ret_p (gdbarch));
> gdb_printf (file,
> "gdbarch_dump: insn_is_ret = <%s>\n",
> host_address_to_string (gdbarch->insn_is_ret));
> + gdb_printf (file,
> + "gdbarch_dump: gdbarch_insn_is_jump_p() = %d\n",
> + gdbarch_insn_is_jump_p (gdbarch));
> gdb_printf (file,
> "gdbarch_dump: insn_is_jump = <%s>\n",
> host_address_to_string (gdbarch->insn_is_jump));
> + gdb_printf (file,
> + "gdbarch_dump: gdbarch_insn_branch_target_p() = %d\n",
> + gdbarch_insn_branch_target_p (gdbarch));
> + 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));
> @@ -4916,11 +4930,19 @@ set_gdbarch_insn_is_call (struct gdbarch *gdbarch,
> gdbarch->insn_is_call = insn_is_call;
> }
>
> +bool
> +gdbarch_insn_is_ret_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != nullptr);
> + return gdbarch->insn_is_ret != default_insn_is_ret;
> +}
> +
> bool
> gdbarch_insn_is_ret (struct gdbarch *gdbarch, CORE_ADDR addr)
> {
> gdb_assert (gdbarch != nullptr);
> gdb_assert (gdbarch->insn_is_ret != nullptr);
> + /* Do not check predicate: gdbarch->insn_is_ret != default_insn_is_ret, allow call. */
> if (gdbarch_debug >= 2)
> gdb_printf (gdb_stdlog, "gdbarch_insn_is_ret called\n");
> return gdbarch->insn_is_ret (gdbarch, addr);
> @@ -4933,11 +4955,19 @@ set_gdbarch_insn_is_ret (struct gdbarch *gdbarch,
> gdbarch->insn_is_ret = insn_is_ret;
> }
>
> +bool
> +gdbarch_insn_is_jump_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != nullptr);
> + return gdbarch->insn_is_jump != default_insn_is_jump;
> +}
> +
> bool
> gdbarch_insn_is_jump (struct gdbarch *gdbarch, CORE_ADDR addr)
> {
> gdb_assert (gdbarch != nullptr);
> gdb_assert (gdbarch->insn_is_jump != nullptr);
> + /* Do not check predicate: gdbarch->insn_is_jump != default_insn_is_jump, allow call. */
> if (gdbarch_debug >= 2)
> gdb_printf (gdb_stdlog, "gdbarch_insn_is_jump called\n");
> return gdbarch->insn_is_jump (gdbarch, addr);
> @@ -4950,6 +4980,31 @@ set_gdbarch_insn_is_jump (struct gdbarch *gdbarch,
> gdbarch->insn_is_jump = insn_is_jump;
> }
>
> +bool
> +gdbarch_insn_branch_target_p (struct gdbarch *gdbarch)
> +{
> + gdb_assert (gdbarch != nullptr);
> + return gdbarch->insn_branch_target != default_insn_branch_target;
> +}
> +
> +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);
> + /* Do not check predicate: gdbarch->insn_branch_target != default_insn_branch_target, allow call. */
> + 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 678b308fba5..6a6e9ed40f1 100644
> --- a/gdb/gdbarch-gen.h
> +++ b/gdb/gdbarch-gen.h
> @@ -1582,16 +1582,32 @@ void set_gdbarch_insn_is_call (struct gdbarch *gdbarch, gdbarch_insn_is_call_fty
>
> /* Return true if the instruction at ADDR is a return; false otherwise. */
>
> +bool gdbarch_insn_is_ret_p (struct gdbarch *gdbarch);
> +
> using gdbarch_insn_is_ret_ftype = bool (struct gdbarch *gdbarch, CORE_ADDR addr);
> bool gdbarch_insn_is_ret (struct gdbarch *gdbarch, CORE_ADDR addr);
> void set_gdbarch_insn_is_ret (struct gdbarch *gdbarch, gdbarch_insn_is_ret_ftype *insn_is_ret);
>
> /* Return true if the instruction at ADDR is a jump; false otherwise. */
>
> +bool gdbarch_insn_is_jump_p (struct gdbarch *gdbarch);
> +
> 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. */
> +
> +bool gdbarch_insn_branch_target_p (struct gdbarch *gdbarch);
> +
> +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 b9304d3036d..df5ddefffcb 100644
> --- a/gdb/gdbarch_components.py
> +++ b/gdb/gdbarch_components.py
> @@ -2509,6 +2509,7 @@ Return true if the instruction at ADDR is a return; false otherwise.
> type="bool",
> name="insn_is_ret",
> params=[("CORE_ADDR", "addr")],
> + predicate=True,
> predefault="default_insn_is_ret",
> invalid=False,
> )
> @@ -2520,10 +2521,27 @@ Return true if the instruction at ADDR is a jump; false otherwise.
> type="bool",
> name="insn_is_jump",
> params=[("CORE_ADDR", "addr")],
> + predicate=True,
> predefault="default_insn_is_jump",
> 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")],
> + predicate=True,
> + 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 b6505ba283d..1992fc62e4a 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -44,9 +44,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. */
> @@ -432,6 +435,9 @@ 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. */
> +static bool debug_linespec_extended_block_filter = true;
> +
> /* Lexer functions. */
>
> /* Lex a number from the input in PARSER. This only supports
> @@ -1986,6 +1992,52 @@ 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 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)
> +{
> + /* 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)
> + {
> + try
> + {
> + 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;
> + }
> + catch (const gdb_exception_error &)
> + {
> + return false;
> + }
> + }
> +
> + return false;
> +}
> +
> /* Given a line offset in LS, construct the relevant SALs. */
>
> static std::vector<symtab_and_line>
> @@ -2084,13 +2136,33 @@ 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 != sal_i.symtab)
> + continue;
> +
> + /* Check for unconditional flow control in the range
> + (extended heuristic; can be disabled). Memory read
> + failures are handled gracefully inside the helper. */
> + 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;
> }
> }
> }
> @@ -4343,3 +4415,73 @@ get_gdb_linespec_parser_quote_characters (void)
> {
> return linespec_quote_characters;
> }
> +
> +/* Return true if architecture implements the insn_is_jump/insn_branch_target
> + methods for the extended block-filter heuristic. */
> +
> +static bool
> +extended_block_filter_supported (struct gdbarch *gdbarch)
> +{
> + return (gdbarch_insn_is_jump_p (gdbarch)
> + && gdbarch_insn_is_ret_p(gdbarch)
> + && gdbarch_insn_branch_target_p (gdbarch));
> +}
> +
> +/* Callback for "show linespec-extended-block-filter". Distinguishes
> + the user's requested setting from whether it actually has any
> + effect on the current architecture. */
> +
> +static void
> +show_debug_linespec_extended_block_filter (struct ui_file *file,
> + int from_tty,
> + struct cmd_list_element *c,
> + const char *value)
> +{
> + struct gdbarch *gdbarch = current_inferior ()->arch ();
> +
> + gdb_printf (file,
> + _("The extended block-filter heuristic is set to %s "
> + "(architecture support for %s: %s).\n"),
> + value,
> + gdbarch_bfd_arch_info (gdbarch)->printable_name,
> + extended_block_filter_supported (gdbarch) ? "yes" : "no");
> +}
> +
> +/* Callback for "set linespec-extended-block-filter". Warn when
> + turning the setting on has no effect because the current
> + architecture doesn't implement the heuristic. */
> +
> +static void
> +set_debug_linespec_extended_block_filter (const char *args, int from_tty,
> + struct cmd_list_element *c)
> +{
> + struct gdbarch *gdbarch = current_inferior ()->arch ();
> +
> + if (debug_linespec_extended_block_filter
> + && !extended_block_filter_supported (gdbarch))
> + warning (_("the extended block-filter heuristic is not implemented "
> + "for %s; breakpoint location resolution will keep using "
> + "the original heuristic"),
> + gdbarch_bfd_arch_info (gdbarch)->printable_name);
> +}
> +
> +/* 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. Only\n\
> +architectures that implement gdbarch_insn_is_jump or\n\
> +gdbarch_insn_branch_target actually apply the extended heuristic;\n\
> +on others this setting has no effect.\n\
> +Default is on."),
> + set_debug_linespec_extended_block_filter,
> + show_debug_linespec_extended_block_filter,
> + &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..39f36ad4a27
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/block-filter-cases.exp
> @@ -0,0 +1,291 @@
> +# 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 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}]
> +
> +# Return true if the extended block-filter heuristic is actually
> +# implemented for the current architecture.
> +proc block_filter_arch_supported { } {
> + global gdb_prompt
> + set supported -1
> + gdb_test_multiple "show linespec-extended-block-filter" \
> + "query extended block-filter architecture support" {
> + -re -wrap "architecture support for \[^\r\n\]+: yes\\)\\." {
> + set supported 1
> + pass $gdb_test_name
> + }
> + -re -wrap "architecture support for \[^\r\n\]+: no\\)\\." {
> + set supported 0
> + pass $gdb_test_name
> + }
> + }
> + return $supported
> +}
> +
> +# Turn the extended block-filter heuristic on.
> +proc enable_extended_block_filter { desc } {
> + gdb_test "set linespec-extended-block-filter on" \
> + "(warning: the extended block-filter heuristic is not implemented\
> + for \[^\r\n\]+; breakpoint location resolution will keep using\
> + the original heuristic)?" \
> + $desc
> +}
> +
> +# Set breakpoint and return how many locations it resolves to.
> +proc bp_nlocs { srcfile line desc } {
> + set nlocs -1
> + gdb_test_multiple "break ${srcfile}:${line}" $desc {
> + -re -wrap "Breakpoint \[0-9\]+ at .*\\((\[0-9\]+) locations\\).*" {
> + set nlocs $expect_out(1,string)
> + pass $desc
> + }
> + -re -wrap "Breakpoint \[0-9\]+ at .*" {
> + 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" \
> + "The extended block-filter heuristic is set to on\
> + \\(architecture support for \[^\r\n\]+: (yes|no)\\)\\." \
> + "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" \
> + "The extended block-filter heuristic is set to off\
> + \\(architecture support for \[^\r\n\]+: (yes|no)\\)\\." \
> + "show linespec-extended-block-filter (off)"
> +
> +# Re-enable: on a supported arch this must be silent; on an unsupported
> +# arch prints an informational warning.
> +if { [block_filter_arch_supported] } {
> + gdb_test_no_output "set linespec-extended-block-filter on" \
> + "set on produces no warning on supported arch"
> +} else {
> + enable_extended_block_filter "set linespec-extended-block-filter on"
> +}
> +
> +gdb_test "show linespec-extended-block-filter" \
> + "The extended block-filter heuristic is set to on\
> + \\(architecture support for \[^\r\n\]+: (yes|no)\\)\\." \
> + "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 } {
> + if { [block_filter_arch_supported] } {
> + fail "expected 2 locations, got $nlocs"
> + } else {
> + unsupported "current arch lacks insn_is_jump support\
> + for the extended block filter"
> + }
> + } else {
> + pass "$nlocs locations (if-else branches on same line, different blocks)"
> + }
> +
> + 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"
> + }
> + }
> +}
> +
> +with_test_prefix "setting toggle affects resolution" {
> + clean_restart "${testfile}-O0"
> +
> + # Test with extended filter ON (default).
> + enable_extended_block_filter "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 } {
> + if { [block_filter_arch_supported] } {
> + fail "expected 2 locations with extended filter ON, got $nlocs_on"
> + } else {
> + unsupported "current arch lacks support\
> + for the extended block filter; skipping toggle checks"
> + }
> + } else {
> + pass "if-else with extended filter ON: $nlocs_on locations"
> +
> + # 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.
> + enable_extended_block_filter "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 == $nlocs_on } {
> + pass "if-else with extended filter re-enabled: $nlocs_on_again locations (verified)"
> + } else {
> + fail "expected $nlocs_on locations after re-enabling, got $nlocs_on_again"
> + }
> + }
> +}
>
>
>
> Intel Deutschland GmbH
>
> Registered Address: Dornacher Straße 1, 85622 Feldkirchen, Germany
> Tel: +49 89 991 430, www.intel.de <//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 München HRB 186928
>
Reviewed-By: Luis Machado <luis.machado.foss@gmai.com>
prev parent reply other threads:[~2026-07-25 7:55 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 9:36 [PATCH v3 0/1] Fix block filter heuristic in linespec " Klaus Gerlicher
2026-07-22 9:36 ` [PATCH v3 1/1] gdb/linespec: relax block filter " Klaus Gerlicher
2026-07-25 7:54 ` Luis [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=db7238d2-1628-44ff-949e-0c176ff6257b@gmail.com \
--to=luis.machado.foss@gmail.com \
--cc=christina.joos@intel.com \
--cc=gdb-patches@sourceware.org \
--cc=klaus.gerlicher@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox