the finished single step. */
int trap_expected = 0;
- /* Nonzero if the thread is being proceeded for a "finish" command
- or a similar situation when return value should be printed. */
- int proceed_to_finish = 0;
-
/* Nonzero if the thread is being proceeded for an inferior function
call. */
int in_infcall = 0;
disable_watchpoints_before_interactive_call_start ();
- /* We want to print return value, please... */
- call_thread->control.proceed_to_finish = 1;
-
try
{
/* Infcalls run synchronously, in the foreground. */
sal = find_pc_line (func_addr, 0);
- tp->control.proceed_to_finish = 1;
- /* Special case: if we're sitting at the function entry point,
- then all we need to do is take a reverse singlestep. We
- don't need to set a breakpoint, and indeed it would do us
- no good to do so.
-
- Note that this can only happen at frame #0, since there's
- no way that a function up the stack can have a return address
- that's equal to its entry point. */
+ frame_info_ptr frame = get_selected_frame (nullptr);
if (sal.pc != pc)
{
- frame_info_ptr frame = get_selected_frame (nullptr);
struct gdbarch *gdbarch = get_frame_arch (frame);
/* Set a step-resume at the function's entry point. Once that's
sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
-
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
else
{
- /* We're almost there -- we just need to back up by one more
- single-step. */
- tp->control.step_range_start = tp->control.step_range_end = 1;
- proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
+ /* We are exactly at the function entry point. Note that this
+ can only happen at frame #0.
+
+ When setting a step range, need to call set_step_info
+ to setup the current_line/symtab fields as well. */
+ set_step_info (tp, frame, find_pc_line (pc, 0));
+
+ /* Return using a step range so we will keep stepping back
+ to the first instruction in the source code line. */
+ tp->control.step_range_start = sal.pc;
+ tp->control.step_range_end = sal.pc;
}
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
/* finish_forward -- helper function for finish_command. FRAME is the
set_longjmp_breakpoint (tp, frame_id);
- /* We want to print return value, please... */
- tp->control.proceed_to_finish = 1;
-
proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
tp->control.stop_step = 0;
- tp->control.proceed_to_finish = 0;
-
tp->control.stepping_command = 0;
/* Discard any remaining commands or status from previous stop. */
case BPSTAT_WHAT_STEP_RESUME:
infrun_debug_printf ("BPSTAT_WHAT_STEP_RESUME");
-
delete_step_resume_breakpoint (ecs->event_thread);
- if (ecs->event_thread->control.proceed_to_finish
- && execution_direction == EXEC_REVERSE)
+ fill_in_stop_func (gdbarch, ecs);
+
+ if (execution_direction == EXEC_REVERSE)
{
struct thread_info *tp = ecs->event_thread;
+ /* We are finishing a function in reverse or stepping over a function
+ call in reverse, and just hit the step-resume breakpoint at the
+ start address of the function, and we're almost there -- just need
+ to back up to the function call. */
- /* We are finishing a function in reverse, and just hit the
- step-resume breakpoint at the start address of the
- function, and we're almost there -- just need to back up
- by one more single-step, which should take us back to the
- function call. */
- tp->control.step_range_start = tp->control.step_range_end = 1;
- keep_going (ecs);
- return;
- }
- fill_in_stop_func (gdbarch, ecs);
- if (ecs->event_thread->stop_pc () == ecs->stop_func_start
- && execution_direction == EXEC_REVERSE)
- {
- /* We are stepping over a function call in reverse, and just
- hit the step-resume breakpoint at the start address of
- the function. Go back to single-stepping, which should
- take us back to the function call. */
- ecs->event_thread->stepping_over_breakpoint = 1;
+ stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
+
+ /* When setting a step range, need to call set_step_info
+ to setup the current_line/symtab fields as well. */
+ set_step_info (tp, frame, stop_pc_sal);
+
+ /* Return using a step range so we will keep stepping back to the
+ first instruction in the source code line. */
+ tp->control.step_range_start = ecs->stop_func_start;
+ tp->control.step_range_end = ecs->stop_func_start;
keep_going (ecs);
return;
}
"basics.c" $line_main_callme_1 "" \
"reverse finish from callme"
- # Test exec-reverse-next
- # It takes two steps to get back to the previous line,
- # as the first step moves us to the start of the current line,
- # and the one after that moves back to the previous line.
-
- mi_execute_to "exec-next --reverse 2" \
+ mi_execute_to "exec-next --reverse" \
"end-stepping-range" "main" "" \
"basics.c" $line_main_hello "" \
- "reverse next to get over the call to do_nothing"
+ "reverse next to get over the call to do_nothing"
# Test exec-reverse-step
gdb_test "next" {f \(\);} "next to f"
gdb_test "next" {v = 3;} "next to v = 3"
-# FAIL was:
-# 29 g ();
-gdb_test "reverse-next" {f \(\);}
+# Reverse step back into f (). Puts us at call to g () in function f ().
+gdb_test "reverse-next" {g \(\);}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2012-2023 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 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 require one reverse
+ step or next statement to reach the previous source code line.
+
+ This test verifies the fix for gdb bugzilla:
+
+ https://sourceware.org/bugzilla/show_bug.cgi?id=29927
+*/
+
+int
+function1 (int a, int b) // FUNCTION1
+{
+ int ret = 0;
+
+ ret = a + b;
+ return ret;
+}
+
+int
+main(int argc, char* argv[])
+{
+ int a, b;
+
+ a = 1;
+ b = 5;
+
+ function1 (a, b); // CALL FUNCTION
+ return 0;
+}
--- /dev/null
+# Copyright 2008-2023 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/>. */
+
+# 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
+
+if ![supports_reverse] {
+ return
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
+ return -1
+}
+
+runto_main
+set target_remote [gdb_is_target_remote]
+
+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 in
+### function1.
+
+# Set breakpoint at call to function1 in main.
+set bp_FUNCTION [gdb_get_line_number "CALL FUNCTION" $srcfile]
+gdb_breakpoint $srcfile:$bp_FUNCTION 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_FUNCTION\r\n.*"
+
+# stepi until we see "{" indicating we entered function1
+repeat_cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
+
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
+ "reverse-finish function1 "
+
+# Check to make sure we stopped at the first instruction in the source code
+# line. It should only take one reverse next command to get to the previous
+# source line. If GDB stops at the last instruction in the source code line
+# it will take two reverse next instructions to get to the previous source
+# line.
+gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call from function"
+
+# Clear the recorded log.
+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_FUNCTION 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_FUNCTION\r\n.*"
+
+# do a step instruction to get to the body of the function
+gdb_test "step" ".*int ret = 0;.*" "step test 1"
+
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
+ "reverse-finish function1 call from function body"
+
+# Check to make sure we stopped at the first instruction in the source code
+# line. It should only take one reverse next command to get to the previous
+# source line.
+gdb_test "reverse-next" ".*b = 5;.*" \
+ "reverse next at b = 5, from function body"
# {
gdb_test "reverse-step" {nodebug \(\);}
-# FAIL was:
-# No more reverse-execution history.
-# {
-gdb_test "reverse-next" {f \(\);}
+gdb_test "reverse-next" {g \(\);}
return -1
}
-# Do repeated stepping COMMANDs in order to reach TARGET from CURRENT
-#
-# COMMAND is a stepping command
-# CURRENT is a string matching the current location
-# TARGET is a string matching the target location
-# TEST is the test name
-#
-# The function issues repeated COMMANDs as long as the location matches
-# CURRENT up to a maximum of 100 steps.
-#
-# TEST passes if the resulting location matches TARGET and fails
-# otherwise.
-#
-proc step_until { command current target test } {
- global gdb_prompt
-
- set count 0
- gdb_test_multiple "$command" "$test" {
- -re "$current.*$gdb_prompt $" {
- incr count
- if { $count < 100 } {
- send_gdb "$command\n"
- exp_continue
- } else {
- fail "$test"
- }
- }
- -re "$target.*$gdb_prompt $" {
- pass "$test"
- }
- }
-}
-
gdb_test_no_output "record"
gdb_test "next" ".*" "record trace"
"reverse-step through thunks and over inc"
# We can use instruction stepping to step into thunks.
-step_until "stepi" "apply\.2" "indirect_thunk" "stepi into call thunk"
-step_until "stepi" "indirect_thunk" "inc" \
+repeat_cmd_until "stepi" "apply\.2" "indirect_thunk" "stepi into call thunk"
+repeat_cmd_until "stepi" "indirect_thunk" "inc" \
"stepi out of call thunk into inc"
set alphanum_re "\[a-zA-Z0-9\]"
set pic_thunk_re "__$alphanum_re*\\.get_pc_thunk\\.$alphanum_re* \\(\\)"
-step_until "stepi" "(inc|$pic_thunk_re)" "return_thunk" "stepi into return thunk"
-step_until "stepi" "return_thunk" "apply" \
+repeat_cmd_until "stepi" "(inc|$pic_thunk_re)" "return_thunk" "stepi into return thunk"
+repeat_cmd_until "stepi" "return_thunk" "apply" \
"stepi out of return thunk back into apply"
-step_until "reverse-stepi" "apply" "return_thunk" \
+repeat_cmd_until "reverse-stepi" "apply" "return_thunk" \
"reverse-stepi into return thunk"
-step_until "reverse-stepi" "return_thunk" "inc" \
+repeat_cmd_until "reverse-stepi" "return_thunk" "inc" \
"reverse-stepi out of return thunk into inc"
-step_until "reverse-stepi" "(inc|$pic_thunk_re)" "indirect_thunk" \
+repeat_cmd_until "reverse-stepi" "(inc|$pic_thunk_re)" "indirect_thunk" \
"reverse-stepi into call thunk"
-step_until "reverse-stepi" "indirect_thunk" "apply" \
+repeat_cmd_until "reverse-stepi" "indirect_thunk" "apply" \
"reverse-stepi out of call thunk into apply"
# Finish out to main scope (backward)
gdb_test "finish" \
- " in main .*$srcfile:$bp_location20.*" \
+ "main .*$srcfile:$bp_location20.*" \
"reverse-finish from marker2"
# Advance backward to last line of factorial (outer invocation)
# Finish out to main scope (backward)
gdb_test "finish" \
- " in main .*$srcfile:$bp_location20.*" \
+ "main .*$srcfile:$bp_location20.*" \
"reverse-finish from marker2"
# Advance backward to last line of factorial (outer invocation)
}
}
+# Do repeated stepping COMMANDs in order to reach TARGET from CURRENT
+#
+# COMMAND is a stepping command
+# CURRENT is a string matching the current location
+# TARGET is a string matching the target location
+# TEST is the test name
+#
+# The function issues repeated COMMANDs as long as the location matches
+# CURRENT up to a maximum of 100 steps.
+#
+# TEST passes if the resulting location matches TARGET and fails
+# otherwise.
+
+proc repeat_cmd_until { command current target test } {
+ global gdb_prompt
+
+ set count 0
+ gdb_test_multiple "$command" "$test" {
+ -re "$current.*$gdb_prompt $" {
+ incr count
+ if { $count < 100 } {
+ send_gdb "$command\n"
+ exp_continue
+ } else {
+ fail "$test"
+ }
+ }
+ -re "$target.*$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+}
+
# Check if the compiler emits epilogue information associated
# with the closing brace or with the last statement line.
#