diff options
-rw-r--r-- | gdb/gdbthread.h | 4 | ||||
-rw-r--r-- | gdb/infcall.c | 3 | ||||
-rw-r--r-- | gdb/infcmd.c | 32 | ||||
-rw-r--r-- | gdb/infrun.c | 40 | ||||
-rw-r--r-- | gdb/testsuite/gdb.mi/mi-reverse.exp | 9 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/finish-reverse-next.c | 48 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/finish-reverse-next.exp | 104 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/singlejmp-reverse.exp | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp | 49 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/until-precsave.exp | 2 | ||||
-rw-r--r-- | gdb/testsuite/gdb.reverse/until-reverse.exp | 2 | ||||
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 33 |
13 files changed, 230 insertions, 106 deletions
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 11d69fc..e4edff2 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -150,10 +150,6 @@ struct thread_control_state 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; diff --git a/gdb/infcall.c b/gdb/infcall.c index e09904f..116605c 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -625,9 +625,6 @@ run_inferior_call (std::unique_ptr<call_thread_fsm> sm, 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. */ diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 7d5ec77..5fcd2ab 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1719,19 +1719,10 @@ finish_backward (struct finish_command_fsm *sm) 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 @@ -1741,16 +1732,22 @@ finish_backward (struct finish_command_fsm *sm) 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 @@ -1776,9 +1773,6 @@ finish_forward (struct finish_command_fsm *sm, frame_info_ptr frame) 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); } diff --git a/gdb/infrun.c b/gdb/infrun.c index edfb5ab..05b150b 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2748,8 +2748,6 @@ clear_proceed_status_thread (struct thread_info *tp) 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. */ @@ -6737,31 +6735,27 @@ process_event_stop_test (struct execution_control_state *ecs) 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; } diff --git a/gdb/testsuite/gdb.mi/mi-reverse.exp b/gdb/testsuite/gdb.mi/mi-reverse.exp index 020b6fe..619550a 100644 --- a/gdb/testsuite/gdb.mi/mi-reverse.exp +++ b/gdb/testsuite/gdb.mi/mi-reverse.exp @@ -95,15 +95,10 @@ proc test_controlled_execution_reverse {} { "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 diff --git a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp index dd6e4d2..0cbabd6 100644 --- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp +++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp @@ -42,6 +42,5 @@ if [supports_process_record] { 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 \(\);} diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c b/gdb/testsuite/gdb.reverse/finish-reverse-next.c new file mode 100644 index 0000000..f90ecbb --- /dev/null +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c @@ -0,0 +1,48 @@ +/* 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; +} diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp new file mode 100644 index 0000000..63305c1 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp @@ -0,0 +1,104 @@ +# 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" diff --git a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp index bc7e687..3678f2c 100644 --- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp +++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp @@ -54,7 +54,4 @@ gdb_test "next" {v = 3;} "next to v = 3" # { gdb_test "reverse-step" {nodebug \(\);} -# FAIL was: -# No more reverse-execution history. -# { -gdb_test "reverse-next" {f \(\);} +gdb_test "reverse-next" {g \(\);} diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp index 94292d5..4a0e0c2 100644 --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp @@ -36,39 +36,6 @@ if { ![runto_main] } { 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" @@ -88,20 +55,20 @@ gdb_test "reverse-next" "apply\.2.*" \ "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" diff --git a/gdb/testsuite/gdb.reverse/until-precsave.exp b/gdb/testsuite/gdb.reverse/until-precsave.exp index b5b2ba7..5090510 100644 --- a/gdb/testsuite/gdb.reverse/until-precsave.exp +++ b/gdb/testsuite/gdb.reverse/until-precsave.exp @@ -138,7 +138,7 @@ gdb_test "advance marker2" \ # 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) diff --git a/gdb/testsuite/gdb.reverse/until-reverse.exp b/gdb/testsuite/gdb.reverse/until-reverse.exp index c9d0c7e..3256946 100644 --- a/gdb/testsuite/gdb.reverse/until-reverse.exp +++ b/gdb/testsuite/gdb.reverse/until-reverse.exp @@ -111,7 +111,7 @@ gdb_test "advance marker2" \ # 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) diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 68337bd..a677f84 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -9261,6 +9261,39 @@ proc gdb_step_until { regexp {test_name ""} {max_steps 10} } { } } +# 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. # |