# Copyright 2008-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 . */ # This file is part of the GDB testsuite. It tests reverse stepping. # Lots of code borrowed from "step-test.exp". # The reverse finish command should return from a function and stop on # the first instruction of the source line where the function call is made. # Specifically, the behavior should match doing a reverse next from the # first instruction in the function. GDB should only take one reverse step # or next statement to reach the previous source code line. # This testcase verifies the reverse-finish command stops at the first # instruction in the source code line where the function was called. There # are two scenarios that must be checked: # 1) gdb is at the entry point instruction for the function # 2) gdb is in the body of the function. # This test verifies the fix for gdb bugzilla: # https://sourceware.org/bugzilla/show_bug.cgi?id=29927 # PowerPC supports two entry points to a function. The normal entry point # is called the local entry point (LEP). The alternate entry point is called # the global entry point (GEP). A function call via a function pointer # will entry via the GEP. A normal function call will enter via the LEP. # # This test has been expanded to include tests to verify the reverse-finish # command works properly if the function is called via the GEP. The original # test only verified the reverse-finish command for a normal call that used # the LEP. if ![supports_reverse] { return } standard_testfile if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { return -1 } runto_main if [supports_process_record] { # Activate process record/replay. gdb_test_no_output "record" "turn on process record for test1" } ### TEST 1: reverse finish from the entry point instruction (LEP) in ### function1 when called using the normal entry point (LEP). # Set breakpoint at call to function1 in main. set bp_LEP_test [gdb_get_line_number "CALL VIA LEP" $srcfile] gdb_breakpoint $srcfile:$bp_LEP_test temporary # Continue to break point at function1 call in main. gdb_continue_to_breakpoint \ "stopped at function1 entry point instruction to stepi into function" \ ".*$srcfile:$bp_LEP_test\r\n.*" # stepi until we see "{" indicating we entered function1 repeat_cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1 call" "100" # The reverse-finish command should stop on the function call instruction # which is the last instruction in the source code line. Another reverse-next # instruction stops at the previous source code line. gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \ "reverse-finish function1 LEP call from LEP " gdb_test "reverse-next" ".*b = 5;.*" "reverse next 2, at b = 5, call from LEP" gdb_test "reverse-continue" ".*" "setup for test 2" # Turn off record to clear logs and turn on again gdb_test "record stop" "Process record is stopped.*" \ "turn off process record for test1" gdb_test_no_output "record" "turn on process record for test2" ### TEST 2: reverse finish from the body of function1. # Set breakpoint at call to function1 in main. gdb_breakpoint $srcfile:$bp_LEP_test temporary # Continue to break point at function1 call in main. gdb_continue_to_breakpoint \ "at function1 entry point instruction to step to body of function" \ ".*$srcfile:$bp_LEP_test\r\n.*" # do a step instruction to get to the body of the function gdb_test "step" ".*int ret = 0;.*" "step test 1" # The reverse-finish command should stop on the function call instruction # which is the last instruction in the source code line. Another reverse-next # instruction stops at the previous source code line. gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \ "reverse-finish function1 LEP call from function body" gdb_test "reverse-next" ".*b = 5;.*" \ "reverse next 2 at b = 5, from function body" gdb_test "reverse-continue" ".*" "setup for test 3" # Turn off record to clear logs and turn on again gdb_test "record stop" "Process record is stopped.*" \ "turn off process record for test2" gdb_test_no_output "record" "turn on process record for test3" ### TEST 3: reverse finish from the alternate entry point instruction (GEP) in ### function1 when called using the alternate entry point (GEP). # Set breakpoint at call to funp in main. set bp_GEP_test [gdb_get_line_number "CALL VIA GEP" $srcfile] gdb_breakpoint $srcfile:$bp_GEP_test temporary # Continue to break point at funp call in main. gdb_continue_to_breakpoint \ "stopped at function1 entry point instruction to stepi into funp" \ ".*$srcfile:$bp_GEP_test\r\n.*" # stepi until we see "{" indicating we entered function. repeat_cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call" # The reverse-finish command should stop on the function call instruction # which is the last instruction in the source code line. Another reverse-next # instruction stops at the previous source code line. gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \ "function1 GEP call call from GEP" gdb_test "reverse-next" ".*b = 50;.*" "reverse next 2 at b = 50, call from GEP" gdb_test "reverse-continue" ".*" "setup for test 4" # Turn off record to clear logs and turn on again gdb_test "record stop" "Process record is stopped.*" \ "turn off process record for test3" gdb_test_no_output "record" "turn on process record for test4" ### TEST 4: reverse finish from between the GEP and LEP in ### function1 when called using the alternate entry point (GEP). # Set breakpoint at call to funp in main. set bp_GEP_test [gdb_get_line_number "CALL VIA GEP" $srcfile] gdb_breakpoint $srcfile:$bp_GEP_test temporary # Continue to break point at funp call in main. gdb_continue_to_breakpoint \ "stopped at function1 entry point instruction to stepi into funp again" \ ".*$srcfile:$bp_GEP_test\r\n.*" # stepi until we see "{" indicating we entered function. repeat_cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call again" # do one more stepi so we are between the GEP and LEP. gdb_test "stepi" "{" "stepi to between GEP and LEP" # The reverse-finish command should stop on the function call instruction # which is the last instruction in the source code line. Another reverse-next # instruction stops at the previous source code line. gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \ "function1 GEP call call from GEP again" gdb_test "reverse-next" ".*b = 50;.*" \ "reverse next 2 at b = 50, call from GEP again" gdb_test "reverse-continue" ".*" "setup for test 5" # Turn off record to clear logs and turn on again gdb_test "record stop" "Process record is stopped.*" \ "turn off process record for test4" gdb_test_no_output "record" "turn on process record for test5" ### TEST 5: reverse finish from the body of function 1 when calling using the ### alternate entrypoint (GEP). gdb_breakpoint $srcfile:$bp_GEP_test temporary # Continue to break point at funp call. gdb_continue_to_breakpoint \ "at function1 entry point instruction to step to body of funp call" \ ".*$srcfile:$bp_GEP_test\r\n.*" # Step into body of funp, called via GEP. gdb_test "step" ".*int ret = 0;.*" "step test 2" # The reverse-finish command should stop on the function call instruction # which is the last instruction in the source code line. Another reverse-next # instruction stops at the previous source code line. gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \ "reverse-finish function1 GEP call, from function body " gdb_test "reverse-next" ".*b = 50;.*" \ "reverse next 2 at b = 50 from function body"