blob: d1c3f3de8f0805af5bbbaa524df83085d8bcdb18 [file]
# 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/>.
# Check that attempting to create a FinishBreakpoint within an inline
# function will fail.
#
# For inline functions the 'finish' command steps forward until we are
# outside the inline function.
#
# For FinishBreakpoints though we need to pick an address an place a
# breakpoint there. Currently GDB doesn't know where to place such a
# breakpoint for an inline function, so our solution is to prevent
# creation of FinishBreakpoints for inline frames.
load_lib gdb-python.exp
require allow_python_tests
standard_testfile
if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} {
return
}
if {![runto_main]} {
return
}
# Source the Python script.
set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py]
gdb_test "source $pyfile" "Python script imported" "import python scripts"
# Breakpoint locations needed for this test.
gdb_breakpoint foo
gdb_breakpoint bar
gdb_breakpoint baz
set final_lineno [gdb_get_line_number "Final breakpoint."]
gdb_breakpoint $final_lineno
# Depending on how the code is compiled, and exactly where the finish
# breakpoint is placed, the breakpoint could potentially be reported
# on either of these lines.
set lineno_1 [gdb_get_line_number "Finish location."]
set lineno_2 [expr {$lineno_1 + 1}]
set lineno_re "(?:$lineno_1|$lineno_2)"
# Run to 'foo', which is an inline function called from a normal
# function, and try to create a MyFinishBreakpoint. This should fail.
gdb_continue_to_breakpoint "breakpoint in foo"
gdb_test "python MyFinishBreakpoint(gdb.selected_frame())" \
"Error occurred in Python: Unable to create FinishBreakpoint for inline frame\\." \
"try to create FinishBreakpoint for inline frame, caller is a normal frame"
# Continue to 'bar', which is an inline function called from another
# inline function, and try to create a MyFinishBreakpoint. This
# should fail.
gdb_continue_to_breakpoint "breakpoint in bar"
gdb_test "python MyFinishBreakpoint(gdb.selected_frame())" \
"Error occurred in Python: Unable to create FinishBreakpoint for inline frame\\." \
"try to create FinishBreakpoint for inline frame, caller is an inline frame"
# Continue to 'baz', which is a normal function called from an inline
# function, and create a MyFinishBreakpoint, which we expect to succeed.
gdb_continue_to_breakpoint "breakpoint in baz"
gdb_test "python MyFinishBreakpoint(gdb.selected_frame())" \
"Temporary breakpoint $decimal at $hex: file \[^\r\n\]+/$srcfile, line $lineno_re\\." \
"create FinishBreakpoint normal function, caller is an inline frame"
# Continue and make sure we hit the MyFinishBreakpoint.
set saw_finish_breakpoint false
set saw_return_value false
set saw_breakpoint_location false
set saw_source_line false
gdb_test_multiple "continue" "continue to finish breakpoint" {
-re "^Stopped at MyFinishBreakpoint\r\n" {
set saw_finish_breakpoint true
exp_continue
}
-re "^Return value is 51\r\n" {
set saw_return_value true
exp_continue
}
-re "^Breakpoint $decimal, ($hex in )?bar \\(arg=$decimal\\) at \[^\r\n\]+/$srcfile:$lineno_re\r\n" {
set saw_breakpoint_location true
exp_continue
}
-re "^$lineno_re\\s+\[^\r\n\]+\r\n" {
set saw_source_line true
exp_continue
}
-re "^$gdb_prompt $" {
gdb_assert {$saw_finish_breakpoint \
&& $saw_return_value \
&& $saw_breakpoint_location \
&& $saw_source_line } $gdb_test_name
}
-re "^\[^\r\n\]*\r\n" {
exp_continue
}
}
# Continue to the final breakpoint location. We don't expect to see
# any of the MyFinishBreakpoint output here. If we do then we've hit
# an unexpected FinishBreakpoint.
set saw_finish_breakpoint false
set saw_return_value false
set saw_breakpoint_location false
set saw_source_line false
gdb_test_multiple "continue" "continue to final breakpoint" {
-re "^Stopped at MyFinishBreakpoint\r\n" {
set saw_finish_breakpoint true
exp_continue
}
-re "^Return value is 51\r\n" {
set saw_return_value true
exp_continue
}
-re "^Breakpoint $decimal, main \\(\\) at \[^\r\n\]+/$srcfile:$final_lineno\r\n" {
set saw_breakpoint_location true
exp_continue
}
-re "^$final_lineno\\s+\[^\r\n\]+\r\n" {
set saw_source_line true
exp_continue
}
-re "^$gdb_prompt $" {
gdb_assert {!$saw_finish_breakpoint \
&& !$saw_return_value \
&& $saw_breakpoint_location \
&& $saw_source_line } $gdb_test_name
}
-re "^\[^\r\n\]*\r\n" {
exp_continue
}
}