# 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 . # 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 } }