const linetable_entry *best_entry = NULL;
int i, j;
+ /* True if the provided line gave an exact match. False if we had to
+ search for the next following line with code. */
+ bool was_exact = true;
+
std::vector<symtab_and_line> intermediate_results
= decode_digits_ordinary (self, ls, val.line, &best_entry);
if (intermediate_results.empty () && best_entry != NULL)
- intermediate_results = decode_digits_ordinary (self, ls,
- best_entry->line,
- &best_entry);
+ {
+ was_exact = false;
+ intermediate_results = decode_digits_ordinary (self, ls,
+ best_entry->line,
+ &best_entry);
+ }
/* For optimized code, the compiler can scatter one source line
across disjoint ranges of PC values, even when no duplicate
struct symbol *sym = (blocks[i]
? blocks[i]->containing_function ()
: NULL);
+ symtab_and_line &sal = intermediate_results[i];
+
+ /* Don't consider a match if:
+
+ - the provided line did not give an exact match (so we
+ started looking for lines below until we found one with
+ code associated to it)
+ - the found location is exactly the start of a function
+ - the provided line is above the declaration line of the
+ function
+
+ Consider the following source:
+
+ 10 } // end of a previous function
+ 11
+ 12 int
+ 13 main (void)
+ 14 {
+ 15 int i = 1;
+ 16
+ 17 return 0;
+ 18 }
+
+ The intent of this heuristic is that a breakpoint requested on
+ line 11 and 12 will not result in a breakpoint on main, but a
+ breakpoint on line 13 will. A breakpoint requested on the empty
+ line 16 will also result in a breakpoint in main, at line 17. */
+ if (!was_exact
+ && sym != nullptr
+ && sym->aclass () == LOC_BLOCK
+ && sal.pc == sym->value_block ()->entry_pc ()
+ && val.line < sym->line ())
+ continue;
if (self->funfirstline)
- skip_prologue_sal (&intermediate_results[i]);
- intermediate_results[i].symbol = sym;
- add_sal_to_sals (self, &values, &intermediate_results[i],
+ skip_prologue_sal (&sal);
+
+ sal.symbol = sym;
+ add_sal_to_sals (self, &values, &sal,
sym ? sym->natural_name () : NULL, 0);
}
}
if (values.empty ())
{
if (ls->explicit_loc.source_filename)
- throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
+ throw_error (NOT_FOUND_ERROR,
+ _("No compiled code for line %d in file \"%s\"."),
val.line, ls->explicit_loc.source_filename.get ());
else
- throw_error (NOT_FOUND_ERROR, _("No line %d in the current file."),
+ throw_error (NOT_FOUND_ERROR,
+ _("No compiled code for line %d in the current file."),
val.line);
}
# Single hex digit
set xd {[0-9a-f]}
- # This accepts e.g. "Breakpoint 1 at 0x40968a" (fixed GDB)
- # but rejects e.g. "Breakpoint 1 at 0x4" (broken GDB).
- gdb_test "b [gdb_get_line_number "gdb break here"]" \
- "Breakpoint \[0-9\] at 0x${xd}${xd}+: .*"
+ set lineno [gdb_get_line_number "gdb break here"]
+ gdb_test "set breakpoint pending on"
+ gdb_test "b $lineno" \
+ [multi_line \
+ "^No compiled code for line $lineno in the current file\\." \
+ "Breakpoint $::decimal \\($lineno\\) pending\\."] \
+ "break on line in garbage collected function"
}
set_breakpoint_on_gcd_function
test_no_break_on_catchpoint
-# Verify that GDB responds gracefully when asked to set a breakpoint
-# on a nonexistent source line.
-
proc_with_prefix test_break_nonexistent_line {} {
clean_restart break
return
}
+ # Verify that GDB responds gracefully when asked to set a
+ # breakpoint on a nonexistent source line.
gdb_test_no_output "set breakpoint pending off"
gdb_test "break 999" \
- "No line 999 in the current file." \
+ "^No compiled code for line 999 in the current file\\." \
"break on non-existent source line"
}
}
remote_exec build "rm -f core"
-# CHFts23469: Test that you can "clear" a bp set at
-# a line _before_ the routine (which will default to the
-# first line in the routine, which turns out to correspond
-# to the prolog--that's another bug...)
-#
-
-gdb_test "b ending-run.c:1" ".*Breakpoint.*ending-run.c, line 1.*" \
- "bpt at line before routine"
-
set break1_line [gdb_get_line_number "-break1-"]
gdb_test "b ending-run.c:$break1_line" \
- ".*Note.*also.*Breakpoint 2.*ending-run.c, line $break1_line.*" \
+ "Breakpoint 1 at ${::hex}.*" \
"b ending-run.c:$break1_line, one"
# Set up to go to the next-to-last line of the program
#
set break2_line [gdb_get_line_number "-break2-"]
-gdb_test "b ending-run.c:$break2_line" ".*Breakpoint 3.*ending-run.c, line $break2_line.*"
+gdb_test "b ending-run.c:$break2_line" ".*Breakpoint 2.*ending-run.c, line $break2_line.*"
# Expect to hit the bp at line "1", but symbolize this
# as line "13". Then try to clear it--this should work.
gdb_run_cmd
gdb_test "" ".*Breakpoint.*1.*callee.*$break1_line.*" "run"
-gdb_test "cle" ".*Deleted breakpoints 1 2.*" "clear worked"
-gdb_test_multiple "i b" "cleared bp at line before routine" {
- -re ".* breakpoint .* breakpoint .*$gdb_prompt $" {
- fail "cleared bp at line before routine"
+gdb_test "cle" "Deleted breakpoint 1 " "clear worked"
+gdb_test_multiple "i b" "cleared bp at stopped line" {
+ -re ".* breakpoint .* breakpoint .*$gdb_prompt $" {
+ fail $gdb_test_name
}
- -re ".*3.*main.*$break2_line.*$gdb_prompt $" {
- pass "cleared bp at line before routine"
+ -re ".*2.*main.*$break2_line.*$gdb_prompt $" {
+ pass $gdb_test_name
}
}
# Test some other "clear" combinations
#
-gdb_test "b ending-run.c:1" ".*Breakpoint.*4.*"
-gdb_test "b ending-run.c:$break1_line" ".*Note.*also.*Breakpoint.*5.*" "b ending-run.c:$break1_line, two"
+gdb_test "b ending-run.c:$break1_line" "Breakpoint 3 at ${::hex}.*" "b ending-run.c:$break1_line, two"
gdb_test "cle ending-run.c:$break1_line" \
- ".*Deleted breakpoints 4 5.*" "Cleared 2 by line"
+ "Deleted breakpoint 3 " "Cleared 2 by line"
gdb_test_multiple "info line ending-run.c:$break1_line" "" {
-re ".*address (0x\[0-9a-fA-F]*).*$gdb_prompt $" {
set line_nine $expect_out(1,string)
- gdb_test "b ending-run.c:$break1_line" ".*Breakpoint 6.*ending-run.c, line $break1_line.*"
- gdb_test "b *$line_nine" ".*Note.*also.*Breakpoint 7.*" "breakpoint 7 at *ending-run.c:$break1_line"
- gdb_test "cle" ".*Deleted breakpoints 6 7.*" "clear 2 by default"
+ gdb_test "b ending-run.c:$break1_line" ".*Breakpoint 4.*ending-run.c, line $break1_line.*"
+ gdb_test "b *$line_nine" ".*Note.*also.*Breakpoint 5.*" "breakpoint 7 at *ending-run.c:$break1_line"
+ gdb_test "cle" "Deleted breakpoints 4 5 " "clear 2 by default"
}
-re ".*$gdb_prompt $" {
fail "need to fix test for new compile outcome"
-re ".* breakpoint .* breakpoint .*$gdb_prompt $" {
fail "all set to continue (didn't clear bps)"
}
- -re ".*3.*main.*$break2_line.*$gdb_prompt $" {
+ -re ".*2.*main.*$break2_line.*$gdb_prompt $" {
pass "all set to continue"
}
-re ".*$gdb_prompt $" {
# past it.
#
if {$cmd == "continue"} {
- gdb_breakpoint "$execd_line"
+ gdb_breakpoint "$execd_line" "allow-pending"
}
# Execute past the exec call.
#
gdb_test_no_output "set breakpoint pending off"
gdb_test "hbreak 999" \
- "No line 999 in the current file." \
+ "^No compiled code for line 999 in the current file\\." \
"hardware break on non-existent source line"
# Run to the desired default location. If not positioned here, the
#
gdb_test_no_output "set breakpoint pending off"
-gdb_test "break 999" "No line 999 in the current file." \
+gdb_test "break 999" "^No compiled code for line 999 in the current file\\." \
"break on non-existent source line"
# Run to the desired default location. If not positioned here, the
add linespecs "-function myclass::myfunction -line 3" $location(normal)
add linespecs "-function myclass::myfunction -label top -line 3" \
$location(top)
- add linespecs "-line 3" $location(normal)
+ add linespecs "-line 25" $location(normal)
add linespecs "-function myclass::operator," $location(operator)
add linespecs "-function 'myclass::operator,'" $location(operator)
add linespecs "-function \"myclass::operator,\"" $location(operator)
# These are also not yet supported; -line is silently ignored.
add linespecs "-function myfunction -line 3" $location(normal)
add linespecs "-function myfunction -label top -line 3" $location(top)
- add linespecs "-line 3" $location(normal)
+ add linespecs "-line 25" $location(normal)
# Fire up gdb.
if {![runto_main]} {
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2022-2024 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/>. */
+
+/* The section where THE_LIB_PATH is not defined is compiled as a shared
+ library. The rest is compiled as the main executable (which loads the
+ shared library. */
+
+#if !defined(THE_LIB_PATH)
+
+void
+the_lib_func (void)
+{
+ static int x;
+ /* break here */
+ x++;
+}
+
+#else
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ void *lib = dlopen (THE_LIB_PATH, RTLD_NOW);
+ assert (lib != NULL);
+
+ void (*the_lib_func) (void) = dlsym (lib, "the_lib_func");
+ assert (the_lib_func != NULL);
+
+ the_lib_func ();
+
+ return 0;
+}
+
+#endif
--- /dev/null
+# Copyright 2022-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test that placing a line breakpoint outside a function results in a pending
+# breakpoint. More importantly, that it does "drift" and place a
+# breakpoint on the next function.
+#
+# See the .c file for more details.
+
+standard_testfile
+
+set shlib_path [standard_output_file ${testfile}-lib.so]
+if {[build_executable "build shlib" $shlib_path $srcfile {debug shlib}]} {
+ return
+}
+
+set opts [list debug shlib_load additional_flags=-DTHE_LIB_PATH="${shlib_path}"]
+if {[build_executable "failed to prepare" ${testfile} ${srcfile} $opts]} {
+ return
+}
+
+proc do_test {} {
+ clean_restart $::binfile
+
+ # To make things easier, just so we don't have to deal with the question.
+ gdb_test_no_output "set breakpoint pending on"
+
+ set lineno [gdb_get_line_number "break here"]
+ gdb_test "break $lineno" \
+ [multi_line \
+ "No compiled code for line $lineno in the current file\\." \
+ "Breakpoint 1 \\($lineno\\) pending\\."] \
+ "breakpoint on a line outside any function"
+
+ gdb_run_cmd
+ gdb_test_multiple "" "stop on lib function breakpoint" {
+ -re -wrap "Breakpoint 1, the_lib_func .*29.*x\\+\\+.*" {
+ pass $gdb_test_name
+ }
+ }
+}
+
+do_test
int i;
i = aa + 42;
+
+ /* These lines are intentionally left blank such that the tests trying
+ to place breakpoints at line -10 relative to the "set.breakpoint.here"
+ line below land on a valid breakpoint location, inside the function. */
+
+
+
+
+
+
return i; /* set breakpoint here */
}
"Undefined convenience variable or function \"%s\" not defined in \"%s\"."
invalid_label "No label \"%s\" defined in function \"%s\"."
invalid_parm "invalid linespec argument, \"%s\""
- invalid_offset "No line %d in the current file."
- invalid_offset_f "No line %d in file \"%s\"."
+ invalid_offset "No compiled code for line %d in the current file."
+ invalid_offset_f "No compiled code for line %d in file \"%s\"."
malformed_line_offset "malformed line offset: \"%s\""
source_incomplete \
"Source filename requires function, label, or line offset."
foreach x {1 +1 +100 -10} {
test_break "3 $x" unexpected_opt "number" $x
- test_break "-line 3 $x" garbage $x
+ test_break "-line 34 $x" garbage $x
test_break "+10 $x" unexpected_opt "number" $x
test_break "-line +10 $x" garbage $x
test_break "-10 $x" unexpected_opt "number" $x
test_break "-line -10 $x" garbage $x
}
- foreach x {3 +10 -10} {
+ foreach x {34 +10 -10} {
test_break "$x foo" unexpected_opt "string" "foo"
test_break "-line $x foo" garbage "foo"
}
test_break "${srcfile}::" invalid_function "${srcfile}::"
test_break "$srcfile:3 1" unexpected_opt "number" "1"
- test_break "-source $srcfile -line 3 1" garbage "1"
+ test_break "-source $srcfile -line 34 1" garbage "1"
test_break "$srcfile:3 +100" unexpected_opt "number" "+100"
- test_break "-source $srcfile -line 3 +100" garbage "+100"
+ test_break "-source $srcfile -line 34 +100" garbage "+100"
test_break "$srcfile:3 -100" unexpected_opt "number" "-100"
test_break "$srcfile:3 foo" unexpected_opt "string" "foo"
- test_break "-source $srcfile -line 3 foo" garbage "foo"
+ test_break "-source $srcfile -line 34 foo" garbage "foo"
foreach x $invalid_offsets {
test_break "$srcfile:$x" invalid_offset_f $x $srcfile
"No source file named foo.*" \
"set invalid explicit breakpoint by missing source and line"
gdb_test "python bp1 = gdb.Breakpoint (source=\"$srcfile\", line=\"900\")" \
- "No line 900 in file \"$srcfile\".*" \
+ [multi_line \
+ "^No compiled code for line 900 in file \"$srcfile\"\\." \
+ "Breakpoint $::decimal \[^\r\n\]+ pending\\."] \
"set invalid explicit breakpoint by source and invalid line"
gdb_test "python bp1 = gdb.Breakpoint (function=\"blah\")" \
"Function \"blah\" not defined.*" \
"8.36: trace disassembly"
gdb_test "tfind line 0" \
- "out of range.*|failed to find.*|No line 0 in .*" \
+ "out of range.*|failed to find.*|No compiled code for line 0 in .*" \
"8.18: tfind line 0"
gdb_test "tfind line 32767" \
- "out of range.*|failed to find.*|No line 32767 in .*" \
+ "out of range.*|failed to find.*|No compiled code for line 32767 in .*" \
"8.27: tfind line 32767"
gdb_test "tfind line NoSuChFiLe.c:$baseline" \
"No source file named.*" \
# 1.2 trace invalid source line
gdb_delete_tracepoints
gdb_test_no_output "set breakpoint pending off"
-gdb_test "trace $srcfile:99999" "No line 99999 in file \".*$srcfile\"." \
+gdb_test "trace $srcfile:99999" \
+ "No compiled code for line 99999 in file \".*$srcfile\"\\." \
"1.2a: trace invalid line in sourcefile"
gdb_test "info trace" "No tracepoints.*" \
"1.2b: reject invalid line in srcfile"