* [PATCH 0/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
[not found] ` <1d9b21914354bef6a290ac30673741e722e11757.camel@de.ibm.com>
@ 2023-01-11 18:27 ` Carl Love
2023-01-11 18:27 ` [PATCH 1/2] " Carl Love
2023-01-11 18:27 ` [PATCH 2/2] " Carl Love
2 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-11 18:27 UTC (permalink / raw)
To: Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
GDB maintainers:
This patch set fixes a couple of issues with the gdb.reverse tests
finish-precsave.exp and finish-reverse.exp.
The first issue is when doing a reverse-finish command from a function,
gdb should stop at the first instruction of the source code line where
the call was made. The behavior should look the same as doing a
reverse-next from the first line of the function. Currently gdb stops
at the last instruction in the caller source code line. Issuing
reverse-step or reverse-next stops at the first instruction in the same
source code line. It then requires a second reverse step or next
command to reach the previous source code line in the caller. It
should only require one reverse step or next command to reach the
previous line.
The first patch in this series fixes the above issue on X86. A number
of additional testcases require updating since the output is slightly
different or the test case no longer needs to issue the two reverse
step/next instructions. The step_until proceedure in test
gdb.reverse/step-indirect-call-thunk.exp was moved to lib/gdb.exp and
renamed cmd_until. The proceedure is used to test the reverse-finish
command when returning from the entry point of the function.
The second issue with the reverse-finish command is that on PowerPC the
reverse-finish doesn't stop at the function call. The issue is PowerPC
uses two entry points. PowerPC calls the two entry points the local
entry point (LEP) and the global entry point (GEP). The LEP is
normally used when calling a function. The GEP is used when the table
of contents (TOC) needs to be setup before continuing execution at the
LEP. GDB is not handling the two entry points correctly. The second
patch fixes the reverse-finish behavior on PowerPC. On systems that
don't use two entry points the LEP and the GEP are the same.
A new testcase is added to verify the reverse-finish command works
correctly for X86 when returning from the body of a function and from
the entry point. Note, the finish_backward function must handle the
two scenarios slightly differently.
The new testcase is expanded in the PPC patch to add tests for the two
scenarios for a function called via the GEP. The initial set of tests
added in the X86 patch take care of the function being called via the
LEP on PowerPC.
The patches have been tested on PowerPC and X86 with no new
regressions.
Please let me know if the patches are acceptable for mainline. Thanks.
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
[not found] ` <1d9b21914354bef6a290ac30673741e722e11757.camel@de.ibm.com>
2023-01-11 18:27 ` [PATCH 0/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp Carl Love
@ 2023-01-11 18:27 ` Carl Love
2023-01-12 16:56 ` Tom de Vries
` (2 more replies)
2023-01-11 18:27 ` [PATCH 2/2] " Carl Love
2 siblings, 3 replies; 105+ messages in thread
From: Carl Love @ 2023-01-11 18:27 UTC (permalink / raw)
To: Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
GDB maintainers:
This patch fixes the issues with the reverse-finish command on X86.
The reverse-finish command now correctly stops at the first instruction
in the source code line of the caller. It now only requires a single
reverse-step or reverse-next instruction to get back to the previous
source code line.
It also adds a new testcase, gdb.reverse/finish-reverse-next.exp, and
updates several existing testcases.
Please let me know if you have any comments on the patch. Thanks.
Carl
--------------------------------------------------------------
X86: reverse-finish fix
Currently on X86, when executing the finish command in reverse, gdb does a
single step from the first instruction in the callee to get back to the
caller. GDB stops on the last instruction in the source code line where
the call was made. When stopped at the last instruction of the source code
line, a reverse next or step command will stop at the first instruction
of the same source code line thus requiring two step/next commands to
reach the previous source code line. It should only require one step/next
command to reach the previous source code line.
By contrast, a reverse next or step command from the first line in a
function stops at the first instruction in the source code line where the
call was made.
This patch fixes the reverse finish command so it will stop at the first
instruction of the source line where the function call was made. The
behavior on X86 for the reverse-finish command now matches doing a
reverse-next from the beginning of the function.
The proceed_to_finish flag in struct thread_control_state is no longer
used. This patch removes the declaration, initialization and setting of
the flag.
This patch requires a number of regression tests to be updated. Test
gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
previous line. The gdb output for tests gdb.reverse/until-precsave.exp
and gdb.reverse/until-reverse.exp changed slightly. The expected result in
tests gdb.reverse/amd64-ailcall-reverse.exp and
gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
result.
This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
reverse-finish command when returning from the entry point and from the
body of the function.
The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
was moved to lib/gdb.exp and renamed cmd_until.
The patch has been tested on X86 and PowerPC to verify no additional
regression failures occured.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29927
---
gdb/gdbthread.h | 4 -
gdb/infcall.c | 3 -
gdb/infcmd.c | 32 +++---
gdb/infrun.c | 41 +++----
gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
.../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
.../gdb.reverse/finish-reverse-next.c | 48 ++++++++
.../gdb.reverse/finish-reverse-next.exp | 108 ++++++++++++++++++
gdb/testsuite/gdb.reverse/finish-reverse.exp | 5 +
.../gdb.reverse/singlejmp-reverse.exp | 5 +-
.../gdb.reverse/step-indirect-call-thunk.exp | 49 ++------
gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 33 ++++++
14 files changed, 240 insertions(+), 106 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1721,19 +1721,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
@@ -1743,16 +1734,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
@@ -1778,9 +1775,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 181d961d80d..8ed538ea9ec 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,28 @@ 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
+ && ecs->event_thread->stop_pc () == ecs->stop_func_start)
{
struct thread_info *tp = ecs->event_thread;
+ stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
- /* 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;
+ /* 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);
+
+ /* 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.
+
+ 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 d631beb17c8..30635ab1754 100644
--- a/gdb/testsuite/gdb.mi/mi-reverse.exp
+++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
@@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
--- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
@@ -44,6 +44,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 00000000000..42e41b5a2e0
--- /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-2022 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 00000000000..7880de10ffc
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -0,0 +1,108 @@
+# Copyright 2008-2022 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 FUNCTION_test [gdb_get_line_number "CALL FUNCTION" $srcfile]
+gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
+ "set breakpoint on function1 call to stepi into function"
+
+# Continue to break point at function1 call in main.
+gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
+ "stopped at function1 entry point instruction to stepi into function"
+
+# stepi until we see "{" indicating we entered function1
+cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
+
+delete_breakpoints
+
+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_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
+ "set breakpoint on function1 call to step into body of function"
+
+# Continue to break point at function1 call in main.
+gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
+ "stopped at function1 entry point instruction to step to body of function"
+
+delete_breakpoints
+
+# 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/finish-reverse.exp b/gdb/testsuite/gdb.reverse/finish-reverse.exp
index 01ba309420c..a05cb81892a 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/finish-reverse.exp
@@ -16,6 +16,11 @@
# This file is part of the GDB testsuite. It tests 'finish' with
# reverse debugging.
+# This test verifies the fix for gdb bugzilla:
+
+# https://sourceware.org/bugzilla/show_bug.cgi?id=29927
+
+
if ![supports_reverse] {
return
}
diff --git a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
index 1ca7c2ce559..eb03051625a 100644
--- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
@@ -56,7 +56,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 ad637899e5b..1928cdda217 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -39,39 +39,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"
@@ -91,20 +58,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" \
+cmd_until "stepi" "apply\.2" "indirect_thunk" "stepi into call thunk"
+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" \
+cmd_until "stepi" "(inc|$pic_thunk_re)" "return_thunk" "stepi into return thunk"
+cmd_until "stepi" "return_thunk" "apply" \
"stepi out of return thunk back into apply"
-step_until "reverse-stepi" "apply" "return_thunk" \
+cmd_until "reverse-stepi" "apply" "return_thunk" \
"reverse-stepi into return thunk"
-step_until "reverse-stepi" "return_thunk" "inc" \
+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" \
+cmd_until "reverse-stepi" "(inc|$pic_thunk_re)" "indirect_thunk" \
"reverse-stepi into call thunk"
-step_until "reverse-stepi" "indirect_thunk" "apply" \
+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 0c2d7537cd6..777aec94ac1 100644
--- a/gdb/testsuite/gdb.reverse/until-precsave.exp
+++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
@@ -142,7 +142,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 23fc881dbf2..3a05953329f 100644
--- a/gdb/testsuite/gdb.reverse/until-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
@@ -113,7 +113,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 c41d4698d66..25f42eb5510 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9301,6 +9301,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 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.
#
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 2/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
[not found] ` <1d9b21914354bef6a290ac30673741e722e11757.camel@de.ibm.com>
2023-01-11 18:27 ` [PATCH 0/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp Carl Love
2023-01-11 18:27 ` [PATCH 1/2] " Carl Love
@ 2023-01-11 18:27 ` Carl Love
2023-01-13 15:55 ` Bruno Larsen
2 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-11 18:27 UTC (permalink / raw)
To: Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
GDB maintainers:
This patch fixes the issues with the reverse-finish command on
PowerPC. The reverse-finish command now correctly stops at the first
instruction in the source code line of the caller.
The patch adds tests for calling a function via the GEP to the new test
gdb.reverse/finish-reverse-next.exp.
Please let me know if you have any comments on the patch. Thanks.
Carl
--------------------------------------------------------------
PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
PowerPC uses two entry points called the local entry point (LEP) and the
global entry point (GEP). Normally the LEP is used when calling a
function. However, if the table of contents (TOC) value in
register 3 is not valid the GEP is called to setup the TOC before execution
continues at the LEP. When executing in reverse, the function
finish_backward sets the break point at the alternate entry point (GEP).
However if the forward execution enters via the normal entry point (LEP),
the reverse execution never sees the break point at the GEP of the
function. Reverse execution continues until the next break point is
encountered or the end of the recorded log is reached causing gdb to stop
at the wrong place.
This patch adds a new address to struct execution_control_state to hold the
address of the alternate function start address, known as the GEP on
PowerPC. The finish_backwards function is updated. If the stopping point
is between the two entry points (the LEP and GEP on PowerPC) , the stepping
range is set to execute back to the alternate entry point (GEP on PowerPC).
Otherwise, a breakpoint is inserted at the normal entry point (LEP on
PowerPC).
Function process_event_stop_test checks uses a stepping range to stop
execution in the caller at the first instruction of the source code line.
Note, on systems that only support one entry point, the address of the two
entry points are the same.
Test finish-reverse-next.exp is updated to include tests for the
reverse-finish command when the function is entered via the normal entry
point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
The patch has been tested on X86 and PowerPC with no regressions.
---
gdb/infcmd.c | 41 ++++---
gdb/infrun.c | 21 +++-
.../gdb.reverse/finish-reverse-next.c | 41 ++++++-
.../gdb.reverse/finish-reverse-next.exp | 107 +++++++++++++++---
4 files changed, 175 insertions(+), 35 deletions(-)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 9c42efeae8d..8c30af448ce 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1722,22 +1722,28 @@ finish_backward (struct finish_command_fsm *sm)
sal = find_pc_line (func_addr, 0);
frame_info_ptr frame = get_selected_frame (nullptr);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR alt_entry_point = sal.pc;
+ CORE_ADDR entry_point = alt_entry_point;
- if (sal.pc != pc)
+ if (gdbarch_skip_entrypoint_p (gdbarch))
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
+ /* Some architectures, like PowerPC use local and global entry
+ points. There is only one Entry Point (GEP = LEP) for other
+ architectures. The GEP is an alternate entry point that is used
+ setup the table of contents (TOC) in register r2 before execution
+ continues at the LEP. The LEP is the normal entry point.
+ The value of entry_point was initialized to the alternate entry
+ point (GEP). It will be adjusted if the normal entry point
+ (LEP) was used. */
+ entry_point = gdbarch_skip_entrypoint (gdbarch, entry_point);
- /* Set a step-resume at the function's entry point. Once that's
- hit, we'll do one more step backwards. */
- symtab_and_line sr_sal;
- sr_sal.pc = sal.pc;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
}
- else
+
+ if (alt_entry_point <= pc && pc <= entry_point)
{
- /* We are exactly at the function entry point. Note that this
+ /* We are exactly at the function entry point, or between the entry
+ point on platforms that have two (like PowerPC). Note that this
can only happen at frame #0.
When setting a step range, need to call set_step_info
@@ -1746,8 +1752,17 @@ finish_backward (struct finish_command_fsm *sm)
/* 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;
+ tp->control.step_range_start = alt_entry_point;
+ tp->control.step_range_end = alt_entry_point;
+ }
+ else
+ {
+ symtab_and_line sr_sal;
+ /* Set a step-resume at the function's entry point. */
+ sr_sal.pc = entry_point;
+ 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);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 8ed538ea9ec..89423556ec0 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1868,6 +1868,7 @@ struct execution_control_state
struct target_waitstatus ws;
int stop_func_filled_in = 0;
+ CORE_ADDR stop_func_alt_start = 0;
CORE_ADDR stop_func_start = 0;
CORE_ADDR stop_func_end = 0;
const char *stop_func_name = nullptr;
@@ -4663,6 +4664,14 @@ fill_in_stop_func (struct gdbarch *gdbarch,
&block);
ecs->stop_func_name = gsi == nullptr ? nullptr : gsi->print_name ();
+ /* PowerPC functions have a Local Entry Point and a Global Entry
+ Point. There is only one Entry Point (GEP = LEP) for other
+ architectures. The GEP is an alternate entry point that is used
+ setup the table of contents (TOC) in register r2 before execution
+ continues at the LEP. Save the alternate entry point address for
+ use later. */
+ ecs->stop_func_alt_start = ecs->stop_func_start;
+
/* The call to find_pc_partial_function, above, will set
stop_func_start and stop_func_end to the start and end
of the range containing the stop pc. If this range
@@ -4679,6 +4688,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
+= gdbarch_deprecated_function_start_offset (gdbarch);
if (gdbarch_skip_entrypoint_p (gdbarch))
+ /* The PowerPC architecture uses two entry points. Stop at the
+ regular entry point (LEP on PowerPC) initially. Will setup a
+ breakpoint for the alternate entry point (GEP) later. */
ecs->stop_func_start
= gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
}
@@ -6738,8 +6750,7 @@ process_event_stop_test (struct execution_control_state *ecs)
delete_step_resume_breakpoint (ecs->event_thread);
fill_in_stop_func (gdbarch, ecs);
- if (execution_direction == EXEC_REVERSE
- && ecs->event_thread->stop_pc () == ecs->stop_func_start)
+ if (execution_direction == EXEC_REVERSE)
{
struct thread_info *tp = ecs->event_thread;
stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
@@ -6755,7 +6766,7 @@ process_event_stop_test (struct execution_control_state *ecs)
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_start = ecs->stop_func_alt_start;
tp->control.step_range_end = ecs->stop_func_start;
keep_going (ecs);
return;
@@ -6892,8 +6903,10 @@ process_event_stop_test (struct execution_control_state *ecs)
(unless it's the function entry point, in which case
keep going back to the call point). */
CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
+
if (stop_pc == ecs->event_thread->control.step_range_start
- && stop_pc != ecs->stop_func_start
+ && (stop_pc < ecs->stop_func_alt_start
+ || stop_pc > ecs->stop_func_start)
&& execution_direction == EXEC_REVERSE)
end_stepping_range (ecs);
else
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
index 42e41b5a2e0..55f81d2bc01 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
@@ -1,4 +1,4 @@
-/* This testcase is part of GDB, the GNU debugger.
+j/* This testcase is part of GDB, the GNU debugger.
Copyright 2012-2022 Free Software Foundation, Inc.
@@ -24,11 +24,37 @@
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 alternat entry point is called
+ the global entry point (GEP). The GEP is only used if the table of
+ contents (TOC) value stored in register r2 needs to be setup prior to
+ execution starting at the LEP. 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. */
int
function1 (int a, int b) // FUNCTION1
{
+ /* The assembly code for this function when compiled for PowerPC is as
+ follows:
+
+ 0000000010000758 <function1>:
+ 10000758: 02 10 40 3c lis r2,4098 <- GEP
+ 1000075c: 00 7f 42 38 addi r2,r2,32512
+ 10000760: a6 02 08 7c mflr r0 <- LEP
+ 10000764: 10 00 01 f8 std r0,16(r1)
+ ....
+
+ When the function is called on PowerPC with function1 (a, b) the call
+ enters at the Local Entry Point (LEP). When the function is called via
+ a function pointer, the Global Entry Point (GEP) for function1 is used.
+ The GEP sets up register 2 before reaching the LEP.
+ */
int ret = 0;
ret = a + b;
@@ -39,10 +65,19 @@ int
main(int argc, char* argv[])
{
int a, b;
+ int (*funp) (int, int) = &function1;
+
+ /* Call function via Local Entry Point (LEP). */
a = 1;
b = 5;
- function1 (a, b); // CALL FUNCTION
+ function1 (a, b); // CALL VIA LEP
+
+ /* Call function via Global Entry Point (GEP). */
+ a = 10;
+ b = 50;
+
+ funp (a, b); // CALL VIA GEP
return 0;
}
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
index 7880de10ffc..fbc024b48b9 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -31,6 +31,18 @@
# 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 alternat entry point is called
+# the global entry point (GEP). The GEP is only used if the table of
+# contents (TOC) value stored in register r2 needs to be setup prior to
+# execution starting at the LEP. 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
}
@@ -50,32 +62,32 @@ if [supports_process_record] {
}
-### TEST 1: reverse finish from the entry point instruction in
-### function1.
+### 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 FUNCTION_test [gdb_get_line_number "CALL FUNCTION" $srcfile]
-gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
- "set breakpoint on function1 call to stepi into function"
+set LEP_test [gdb_get_line_number "CALL VIA LEP" $srcfile]
+gdb_test "break $srcfile:$LEP_test" "Breakpoint $decimal at .*" \
+ "set breakpoint on function1 LEP call to stepi into function"
# Continue to break point at function1 call in main.
gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
"stopped at function1 entry point instruction to stepi into function"
# stepi until we see "{" indicating we entered function1
-cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
+cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1 call"
delete_breakpoints
-gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
- "reverse-finish function1 "
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse-finish function1 LEP call from LEP "
# 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"
+gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call from LEP"
# Clear the recorded log.
gdb_test "record stop" "Process record is stopped.*" \
@@ -83,26 +95,91 @@ gdb_test "record stop" "Process record is stopped.*" \
gdb_test_no_output "record" "turn on process record for test2"
-### TEST 2: reverse finish from the body of function1.
+### TEST 2: reverse finish from the body of function1 when called using the
+### normal entry point (LEP).
# Set breakpoint at call to function1 in main.
-gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
- "set breakpoint on function1 call to step into body of function"
+gdb_test "break $srcfile:$LEP_test" "Breakpoint $decimal at .*" \
+ "set breakpoint on function1 LEP call to step into body of function"
# Continue to break point at function1 call in main.
gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
- "stopped at function1 entry point instruction to step to body of function"
+ "stopped at function1 entry point instruction to step body of function"
delete_breakpoints
# 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"
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse-finish function1 LEP 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"
+
+# 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 GEP_test [gdb_get_line_number "CALL VIA GEP" $srcfile]
+gdb_test "break $srcfile:$GEP_test" "Breakpoint $decimal at .*" \
+ "set breakpoint on function1 GEP call to stepi into function"
+
+# Continue to break point at funp call in main.
+gdb_test "continue" "Breakpoint $decimal.*funp \\(a, b\\).*" \
+ "stopped at funp entry point instruction"
+
+# stepi until we see "{" indicating we entered function.
+cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call"
+
+delete_breakpoints
+
+gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
+ "function1 GEP call call from GEP"
+
+# 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 = 50;.*" "reverse next at b = 50, call from GEP"
+
+# 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 the body of function 1 when calling using the
+### alternate entrypoint (GEP).
+gdb_test "break $srcfile:$GEP_test" "Breakpoint $decimal at .*" \
+ "set breakpoint on funp GEP call to step into body of function"
+
+# Continue to break point at funp call.
+gdb_test "continue" "Breakpoint $decimal,.*funp \\(a, b\\).*" \
+ "stopped at funp call"
+
+# Step into body of funp, called via GEP.
+gdb_test "step" ".*int ret = 0;.*" "step test 2"
+
+delete_breakpoints
+
+gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
+ "reverse-finish function1 GEP 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. 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 = 50;.*" \
+ "reverse next at b = 50 from function body"
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-11 18:27 ` [PATCH 1/2] " Carl Love
@ 2023-01-12 16:56 ` Tom de Vries
2023-01-12 18:54 ` Carl Love
2023-01-13 13:33 ` Bruno Larsen
2023-01-13 15:42 ` [PATCH 1/2] " Bruno Larsen
2 siblings, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-01-12 16:56 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 1/11/23 19:27, Carl Love via Gdb-patches wrote:
> This patch requires a number of regression tests to be updated. Test
> gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
> previous line.
Hi Carl,
FYI, I stumbled upon a FAIL (not related to reverse-finish) in
gdb.reverse/step-reverse.exp, see PR29962 (
https://sourceware.org/bugzilla/show_bug.cgi?id=29962 ) and wrote a
tentative patch for it (
https://sourceware.org/bugzilla/attachment.cgi?id=14588 ), and ended up
making the same fix in the gdb.mi/mi-reverse.exp test-case.
I'll test the patch a bit further before posting it.
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-12 16:56 ` Tom de Vries
@ 2023-01-12 18:54 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-12 18:54 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Tom:
On Thu, 2023-01-12 at 17:56 +0100, Tom de Vries wrote:
> On 1/11/23 19:27, Carl Love via Gdb-patches wrote:
> > This patch requires a number of regression tests to be
> > updated. Test
> > gdb.mi/mi-reverse.exp no longer needs to execute two steps to get
> > to the
> > previous line.
>
> Hi Carl,
>
> FYI, I stumbled upon a FAIL (not related to reverse-finish) in
> gdb.reverse/step-reverse.exp, see PR29962 (
> https://sourceware.org/bugzilla/show_bug.cgi?id=29962 ) and wrote
> a
> tentative patch for it (
> https://sourceware.org/bugzilla/attachment.cgi?id=14588 ), and ended
> up
> making the same fix in the gdb.mi/mi-reverse.exp test-case.
>
> I'll test the patch a bit further before posting it.
On PPC64 there are also issues with reverse stepping over a line that
has multiple executable statements in it. Not sure if this is related
to what you are seeing.
There is a patch that I have worked on with Luis Machado to fix. We
have posted versions of it to the mailing list. The subject line is:
Fix reverse stepping multiple contiguous PC ranges over the line table
which might be relevant. Unfortunately, work on this patch has been
stalled for awhile. The patch fixes 5 failures in gdb.reverse/solib-
precsave.exp and 5 failures in gdb.reverse/solib-reverse.exp.
You might want to take a look at it to see if it helps.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-11 18:27 ` [PATCH 1/2] " Carl Love
2023-01-12 16:56 ` Tom de Vries
@ 2023-01-13 13:33 ` Bruno Larsen
2023-01-13 16:43 ` Carl Love
2023-01-14 18:08 ` Carl Love
2023-01-13 15:42 ` [PATCH 1/2] " Bruno Larsen
2 siblings, 2 replies; 105+ messages in thread
From: Bruno Larsen @ 2023-01-13 13:33 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 11/01/2023 19:27, Carl Love via Gdb-patches wrote:
> GDB maintainers:
>
> This patch fixes the issues with the reverse-finish command on X86.
> The reverse-finish command now correctly stops at the first instruction
> in the source code line of the caller. It now only requires a single
> reverse-step or reverse-next instruction to get back to the previous
> source code line.
>
> It also adds a new testcase, gdb.reverse/finish-reverse-next.exp, and
> updates several existing testcases.
>
> Please let me know if you have any comments on the patch. Thanks.
Thanks for looking at this, this is a nice change. I just have a couple
of comments, mostly related to the testsuite side.
> Carl
>
> --------------------------------------------------------------
> X86: reverse-finish fix
>
> Currently on X86, when executing the finish command in reverse, gdb does a
> single step from the first instruction in the callee to get back to the
> caller. GDB stops on the last instruction in the source code line where
> the call was made. When stopped at the last instruction of the source code
> line, a reverse next or step command will stop at the first instruction
> of the same source code line thus requiring two step/next commands to
> reach the previous source code line. It should only require one step/next
> command to reach the previous source code line.
>
> By contrast, a reverse next or step command from the first line in a
> function stops at the first instruction in the source code line where the
> call was made.
>
> This patch fixes the reverse finish command so it will stop at the first
> instruction of the source line where the function call was made. The
> behavior on X86 for the reverse-finish command now matches doing a
> reverse-next from the beginning of the function.
>
> The proceed_to_finish flag in struct thread_control_state is no longer
> used. This patch removes the declaration, initialization and setting of
> the flag.
>
> This patch requires a number of regression tests to be updated. Test
> gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
> previous line. The gdb output for tests gdb.reverse/until-precsave.exp
> and gdb.reverse/until-reverse.exp changed slightly. The expected result in
> tests gdb.reverse/amd64-ailcall-reverse.exp and
s/ailcall/tailcall
> gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
> result.
>
> This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
> reverse-finish command when returning from the entry point and from the
> body of the function.
>
> The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
> was moved to lib/gdb.exp and renamed cmd_until.
I'm not a big fan of the name cmd_until, because it sounded to me like
you were testing the GDB command until. I think repeat_cmd_until or
repeat_until would avoid this possible confusion.
>
> The patch has been tested on X86 and PowerPC to verify no additional
> regression failures occured.
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29927
If you add record/29927 somewhere along the text of your commit message,
there is some automation that will comment on the bugzilla bug
specifying this commit. Might be worth doing for future reference.
> ---
> gdb/gdbthread.h | 4 -
> gdb/infcall.c | 3 -
> gdb/infcmd.c | 32 +++---
> gdb/infrun.c | 41 +++----
> gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
> .../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
> .../gdb.reverse/finish-reverse-next.c | 48 ++++++++
> .../gdb.reverse/finish-reverse-next.exp | 108 ++++++++++++++++++
> gdb/testsuite/gdb.reverse/finish-reverse.exp | 5 +
> .../gdb.reverse/singlejmp-reverse.exp | 5 +-
> .../gdb.reverse/step-indirect-call-thunk.exp | 49 ++------
> gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
> gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
> gdb/testsuite/lib/gdb.exp | 33 ++++++
> 14 files changed, 240 insertions(+), 106 deletions(-)
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
>
> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
> index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1721,19 +1721,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
> @@ -1743,16 +1734,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
> @@ -1778,9 +1775,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 181d961d80d..8ed538ea9ec 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,28 @@ 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
> + && ecs->event_thread->stop_pc () == ecs->stop_func_start)
Is there any reason to invert the order of checks here? The second if
clause is the same and keeping that would make the changes easier to parse.
> {
> struct thread_info *tp = ecs->event_thread;
> + stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
>
> - /* 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;
> + /* 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);
> +
> + /* 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.
> +
> + 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 d631beb17c8..30635ab1754 100644
> --- a/gdb/testsuite/gdb.mi/mi-reverse.exp
> +++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
> @@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
> --- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
> @@ -44,6 +44,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 00000000000..42e41b5a2e0
> --- /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-2022 Free Software Foundation, Inc.
copyright year should be 2023.
> +
> + 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 00000000000..7880de10ffc
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> @@ -0,0 +1,108 @@
> +# Copyright 2008-2022 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.
While testing locally, I ran into a bug with reverse finish at the
epilogue of the function, that your patch also fixed. It would be nice
if the test extended that. And since the bug was that GDB stopped
responding and even ctrl+c did nothing, I would suggest adding it as the
last test.
> +
> +# 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 FUNCTION_test [gdb_get_line_number "CALL FUNCTION" $srcfile]
> +gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
> + "set breakpoint on function1 call to stepi into function"
There is a proc in lib/gdb.exp called gdb_breakpoint which couldsimplify
this gdb_test to
gdb_breakpoint $srcfile:$FUNCTION_test temporary
And would remove the need for the delete_breakpoints call later.
> +
> +# Continue to break point at function1 call in main.
> +gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
> + "stopped at function1 entry point instruction to stepi into function"
You can use gdb_continue_to_breakpoint here instead.
> +
> +# stepi until we see "{" indicating we entered function1
> +cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
> +
> +delete_breakpoints
> +
> +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_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
> + "set breakpoint on function1 call to step into body of function"
> +
> +# Continue to break point at function1 call in main.
> +gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
> + "stopped at function1 entry point instruction to step to body of function"
> +
> +delete_breakpoints
> +
> +# 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/finish-reverse.exp b/gdb/testsuite/gdb.reverse/finish-reverse.exp
> index 01ba309420c..a05cb81892a 100644
> --- a/gdb/testsuite/gdb.reverse/finish-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse.exp
> @@ -16,6 +16,11 @@
> # This file is part of the GDB testsuite. It tests 'finish' with
> # reverse debugging.
>
> +# This test verifies the fix for gdb bugzilla:
> +
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=29927
> +
> +
Is this comment a left over from an earlier version?
I actually wonder if the whole new test is needed, or if you can just
add a couple of new tests to finish-reverse.exp; is there any reason you
went with the new test instead?
> if ![supports_reverse] {
> return
> }
> diff --git a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> index 1ca7c2ce559..eb03051625a 100644
> --- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> @@ -56,7 +56,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 ad637899e5b..1928cdda217 100644
> --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> @@ -39,39 +39,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"
>
> @@ -91,20 +58,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" \
> +cmd_until "stepi" "apply\.2" "indirect_thunk" "stepi into call thunk"
> +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" \
> +cmd_until "stepi" "(inc|$pic_thunk_re)" "return_thunk" "stepi into return thunk"
> +cmd_until "stepi" "return_thunk" "apply" \
> "stepi out of return thunk back into apply"
>
> -step_until "reverse-stepi" "apply" "return_thunk" \
> +cmd_until "reverse-stepi" "apply" "return_thunk" \
> "reverse-stepi into return thunk"
> -step_until "reverse-stepi" "return_thunk" "inc" \
> +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" \
> +cmd_until "reverse-stepi" "(inc|$pic_thunk_re)" "indirect_thunk" \
> "reverse-stepi into call thunk"
> -step_until "reverse-stepi" "indirect_thunk" "apply" \
> +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 0c2d7537cd6..777aec94ac1 100644
> --- a/gdb/testsuite/gdb.reverse/until-precsave.exp
> +++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
> @@ -142,7 +142,7 @@ gdb_test "advance marker2" \
> # Finish out to main scope (backward)
>
> gdb_test "finish" \
> - " in main .*$srcfile:$bp_location20.*" \
> + "main .*$srcfile:$bp_location20.*" \
This change doesn't seem connected to anything in this patch, is this
just a cosmetic change or was there some problem?
> "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 23fc881dbf2..3a05953329f 100644
> --- a/gdb/testsuite/gdb.reverse/until-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
> @@ -113,7 +113,7 @@ gdb_test "advance marker2" \
> # Finish out to main scope (backward)
>
> gdb_test "finish" \
> - " in main .*$srcfile:$bp_location20.*" \
> + "main .*$srcfile:$bp_location20.*" \
same here.
> "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 c41d4698d66..25f42eb5510 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -9301,6 +9301,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 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.
> #
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-11 18:27 ` [PATCH 1/2] " Carl Love
2023-01-12 16:56 ` Tom de Vries
2023-01-13 13:33 ` Bruno Larsen
@ 2023-01-13 15:42 ` Bruno Larsen
2 siblings, 0 replies; 105+ messages in thread
From: Bruno Larsen @ 2023-01-13 15:42 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 11/01/2023 19:27, Carl Love via Gdb-patches wrote:
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 181d961d80d..8ed538ea9ec 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,28 @@ process_event_stop_test (struct execution_control_state *ecs)
>
> case BPSTAT_WHAT_STEP_RESUME:
Something else that I failed to notice. Since you removed both comments
that mention that this case is here for reverse finishing, there is no
good way to figure out what GDB wants to do when this part of the code
is reached. Adding a comment here mentioning it would fix that.
> 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
> + && ecs->event_thread->stop_pc () == ecs->stop_func_start)
> {
> struct thread_info *tp = ecs->event_thread;
> + stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
>
> - /* 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;
> + /* 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);
> +
> + /* 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.
> +
> + 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;
> }
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-11 18:27 ` [PATCH 2/2] " Carl Love
@ 2023-01-13 15:55 ` Bruno Larsen
2023-01-14 18:08 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-13 15:55 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 11/01/2023 19:27, Carl Love via Gdb-patches wrote:
> GDB maintainers:
>
> This patch fixes the issues with the reverse-finish command on
> PowerPC. The reverse-finish command now correctly stops at the first
> instruction in the source code line of the caller.
>
> The patch adds tests for calling a function via the GEP to the new test
> gdb.reverse/finish-reverse-next.exp.
>
> Please let me know if you have any comments on the patch. Thanks.
I'm not all that familiar with PowerPC ABI and I dont have a computer
handy to test that the patch fixes the problem, but the logic seems
sound. Just a few nits inlined.
>
> Carl
>
> --------------------------------------------------------------
> PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
>
> PowerPC uses two entry points called the local entry point (LEP) and the
> global entry point (GEP). Normally the LEP is used when calling a
> function. However, if the table of contents (TOC) value in
> register 3 is not valid the GEP is called to setup the TOC before execution
> continues at the LEP. When executing in reverse, the function
> finish_backward sets the break point at the alternate entry point (GEP).
> However if the forward execution enters via the normal entry point (LEP),
> the reverse execution never sees the break point at the GEP of the
> function. Reverse execution continues until the next break point is
> encountered or the end of the recorded log is reached causing gdb to stop
> at the wrong place.
>
> This patch adds a new address to struct execution_control_state to hold the
> address of the alternate function start address, known as the GEP on
> PowerPC. The finish_backwards function is updated. If the stopping point
> is between the two entry points (the LEP and GEP on PowerPC) , the stepping
> range is set to execute back to the alternate entry point (GEP on PowerPC).
> Otherwise, a breakpoint is inserted at the normal entry point (LEP on
> PowerPC).
>
> Function process_event_stop_test checks uses a stepping range to stop
> execution in the caller at the first instruction of the source code line.
> Note, on systems that only support one entry point, the address of the two
> entry points are the same.
>
> Test finish-reverse-next.exp is updated to include tests for the
> reverse-finish command when the function is entered via the normal entry
> point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
>
> The patch has been tested on X86 and PowerPC with no regressions.
> ---
> gdb/infcmd.c | 41 ++++---
> gdb/infrun.c | 21 +++-
> .../gdb.reverse/finish-reverse-next.c | 41 ++++++-
> .../gdb.reverse/finish-reverse-next.exp | 107 +++++++++++++++---
> 4 files changed, 175 insertions(+), 35 deletions(-)
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 9c42efeae8d..8c30af448ce 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1722,22 +1722,28 @@ finish_backward (struct finish_command_fsm *sm)
> sal = find_pc_line (func_addr, 0);
>
> frame_info_ptr frame = get_selected_frame (nullptr);
> + struct gdbarch *gdbarch = get_frame_arch (frame);
> + CORE_ADDR alt_entry_point = sal.pc;
> + CORE_ADDR entry_point = alt_entry_point;
>
> - if (sal.pc != pc)
> + if (gdbarch_skip_entrypoint_p (gdbarch))
> {
> - struct gdbarch *gdbarch = get_frame_arch (frame);
> + /* Some architectures, like PowerPC use local and global entry
> + points. There is only one Entry Point (GEP = LEP) for other
> + architectures. The GEP is an alternate entry point that is used
> + setup the table of contents (TOC) in register r2 before execution
> + continues at the LEP. The LEP is the normal entry point.
I don't think an explanation on why there are 2 entry points is
necessary. just mentioning that both exist is enough IMHO.
> + The value of entry_point was initialized to the alternate entry
> + point (GEP). It will be adjusted if the normal entry point
> + (LEP) was used. */
> + entry_point = gdbarch_skip_entrypoint (gdbarch, entry_point);
>
> - /* Set a step-resume at the function's entry point. Once that's
> - hit, we'll do one more step backwards. */
> - symtab_and_line sr_sal;
> - sr_sal.pc = sal.pc;
> - sr_sal.pspace = get_frame_program_space (frame);
> - insert_step_resume_breakpoint_at_sal (gdbarch,
> - sr_sal, null_frame_id);
> }
> - else
> +
> + if (alt_entry_point <= pc && pc <= entry_point)
> {
> - /* We are exactly at the function entry point. Note that this
> + /* We are exactly at the function entry point, or between the entry
> + point on platforms that have two (like PowerPC). Note that this
> can only happen at frame #0.
>
> When setting a step range, need to call set_step_info
> @@ -1746,8 +1752,17 @@ finish_backward (struct finish_command_fsm *sm)
>
> /* 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;
> + tp->control.step_range_start = alt_entry_point;
> + tp->control.step_range_end = alt_entry_point;
I'm hesitant in this part. What if there is one instruction between the
GEP and the LEP and the inferior happens to be stopped there? Could this
happen? Like I said, I'm not familiar with the PPC abi, so excuse me if
the answer is obvious, but it seems to me that the step_range_end could
be set to the entry_point and we'd avoid this possibility.
> + }
> + else
> + {
> + symtab_and_line sr_sal;
> + /* Set a step-resume at the function's entry point. */
> + sr_sal.pc = entry_point;
> + 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);
> }
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 8ed538ea9ec..89423556ec0 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -1868,6 +1868,7 @@ struct execution_control_state
>
> struct target_waitstatus ws;
> int stop_func_filled_in = 0;
> + CORE_ADDR stop_func_alt_start = 0;
> CORE_ADDR stop_func_start = 0;
> CORE_ADDR stop_func_end = 0;
> const char *stop_func_name = nullptr;
> @@ -4663,6 +4664,14 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> &block);
> ecs->stop_func_name = gsi == nullptr ? nullptr : gsi->print_name ();
>
> + /* PowerPC functions have a Local Entry Point and a Global Entry
> + Point. There is only one Entry Point (GEP = LEP) for other
> + architectures. The GEP is an alternate entry point that is used
> + setup the table of contents (TOC) in register r2 before execution
> + continues at the LEP. Save the alternate entry point address for
Ditto here about explaining LEP and GEP. Just saying that GEP is the
alternate is probably enough.
> + use later. */
> + ecs->stop_func_alt_start = ecs->stop_func_start;
> +
> /* The call to find_pc_partial_function, above, will set
> stop_func_start and stop_func_end to the start and end
> of the range containing the stop pc. If this range
> @@ -4679,6 +4688,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> += gdbarch_deprecated_function_start_offset (gdbarch);
>
> if (gdbarch_skip_entrypoint_p (gdbarch))
> + /* The PowerPC architecture uses two entry points. Stop at the
> + regular entry point (LEP on PowerPC) initially. Will setup a
> + breakpoint for the alternate entry point (GEP) later. */
> ecs->stop_func_start
> = gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
> }
> @@ -6738,8 +6750,7 @@ process_event_stop_test (struct execution_control_state *ecs)
> delete_step_resume_breakpoint (ecs->event_thread);
> fill_in_stop_func (gdbarch, ecs);
>
> - if (execution_direction == EXEC_REVERSE
> - && ecs->event_thread->stop_pc () == ecs->stop_func_start)
> + if (execution_direction == EXEC_REVERSE)
Why is this change not in the previous patch?
> {
> struct thread_info *tp = ecs->event_thread;
> stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
> @@ -6755,7 +6766,7 @@ process_event_stop_test (struct execution_control_state *ecs)
>
> 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_start = ecs->stop_func_alt_start;
> tp->control.step_range_end = ecs->stop_func_start;
> keep_going (ecs);
> return;
> @@ -6892,8 +6903,10 @@ process_event_stop_test (struct execution_control_state *ecs)
> (unless it's the function entry point, in which case
> keep going back to the call point). */
> CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> +
> if (stop_pc == ecs->event_thread->control.step_range_start
> - && stop_pc != ecs->stop_func_start
> + && (stop_pc < ecs->stop_func_alt_start
> + || stop_pc > ecs->stop_func_start)
> && execution_direction == EXEC_REVERSE)
> end_stepping_range (ecs);
> else
> diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> index 42e41b5a2e0..55f81d2bc01 100644
> --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> @@ -1,4 +1,4 @@
> -/* This testcase is part of GDB, the GNU debugger.
> +j/* This testcase is part of GDB, the GNU debugger.
>
> Copyright 2012-2022 Free Software Foundation, Inc.
>
> @@ -24,11 +24,37 @@
> 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 alternat entry point is called
> + the global entry point (GEP). The GEP is only used if the table of
> + contents (TOC) value stored in register r2 needs to be setup prior to
> + execution starting at the LEP. 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. */
>
> int
> function1 (int a, int b) // FUNCTION1
> {
> + /* The assembly code for this function when compiled for PowerPC is as
> + follows:
> +
> + 0000000010000758 <function1>:
> + 10000758: 02 10 40 3c lis r2,4098 <- GEP
> + 1000075c: 00 7f 42 38 addi r2,r2,32512
> + 10000760: a6 02 08 7c mflr r0 <- LEP
> + 10000764: 10 00 01 f8 std r0,16(r1)
> + ....
> +
> + When the function is called on PowerPC with function1 (a, b) the call
> + enters at the Local Entry Point (LEP). When the function is called via
> + a function pointer, the Global Entry Point (GEP) for function1 is used.
> + The GEP sets up register 2 before reaching the LEP.
> + */
> int ret = 0;
>
> ret = a + b;
> @@ -39,10 +65,19 @@ int
> main(int argc, char* argv[])
> {
> int a, b;
> + int (*funp) (int, int) = &function1;
> +
> + /* Call function via Local Entry Point (LEP). */
>
> a = 1;
> b = 5;
>
> - function1 (a, b); // CALL FUNCTION
> + function1 (a, b); // CALL VIA LEP
> +
> + /* Call function via Global Entry Point (GEP). */
> + a = 10;
> + b = 50;
> +
> + funp (a, b); // CALL VIA GEP
> return 0;
> }
> diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> index 7880de10ffc..fbc024b48b9 100644
> --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> @@ -31,6 +31,18 @@
> # 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 alternat entry point is called
> +# the global entry point (GEP). The GEP is only used if the table of
> +# contents (TOC) value stored in register r2 needs to be setup prior to
> +# execution starting at the LEP. 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
> }
> @@ -50,32 +62,32 @@ if [supports_process_record] {
> }
>
>
> -### TEST 1: reverse finish from the entry point instruction in
> -### function1.
> +### 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 FUNCTION_test [gdb_get_line_number "CALL FUNCTION" $srcfile]
> -gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
> - "set breakpoint on function1 call to stepi into function"
> +set LEP_test [gdb_get_line_number "CALL VIA LEP" $srcfile]
> +gdb_test "break $srcfile:$LEP_test" "Breakpoint $decimal at .*" \
> + "set breakpoint on function1 LEP call to stepi into function"
>
> # Continue to break point at function1 call in main.
> gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
> "stopped at function1 entry point instruction to stepi into function"
>
> # stepi until we see "{" indicating we entered function1
> -cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
> +cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1 call"
>
> delete_breakpoints
>
> -gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
> - "reverse-finish function1 "
> +gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
> + "reverse-finish function1 LEP call from LEP "
>
> # 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"
> +gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call from LEP"
>
> # Clear the recorded log.
> gdb_test "record stop" "Process record is stopped.*" \
> @@ -83,26 +95,91 @@ gdb_test "record stop" "Process record is stopped.*" \
> gdb_test_no_output "record" "turn on process record for test2"
>
>
> -### TEST 2: reverse finish from the body of function1.
> +### TEST 2: reverse finish from the body of function1 when called using the
> +### normal entry point (LEP).
>
> # Set breakpoint at call to function1 in main.
> -gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at .*" \
> - "set breakpoint on function1 call to step into body of function"
> +gdb_test "break $srcfile:$LEP_test" "Breakpoint $decimal at .*" \
> + "set breakpoint on function1 LEP call to step into body of function"
>
> # Continue to break point at function1 call in main.
> gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*" \
> - "stopped at function1 entry point instruction to step to body of function"
> + "stopped at function1 entry point instruction to step body of function"
>
> delete_breakpoints
>
> # 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"
> +gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
> + "reverse-finish function1 LEP 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"
> +
> +# 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 GEP_test [gdb_get_line_number "CALL VIA GEP" $srcfile]
> +gdb_test "break $srcfile:$GEP_test" "Breakpoint $decimal at .*" \
> + "set breakpoint on function1 GEP call to stepi into function"
> +
> +# Continue to break point at funp call in main.
> +gdb_test "continue" "Breakpoint $decimal.*funp \\(a, b\\).*" \
> + "stopped at funp entry point instruction"
> +
> +# stepi until we see "{" indicating we entered function.
> +cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call"
> +
> +delete_breakpoints
> +
> +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> + "function1 GEP call call from GEP"
> +
> +# 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 = 50;.*" "reverse next at b = 50, call from GEP"
> +
> +# 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 the body of function 1 when calling using the
> +### alternate entrypoint (GEP).
> +gdb_test "break $srcfile:$GEP_test" "Breakpoint $decimal at .*" \
> + "set breakpoint on funp GEP call to step into body of function"
> +
> +# Continue to break point at funp call.
> +gdb_test "continue" "Breakpoint $decimal,.*funp \\(a, b\\).*" \
> + "stopped at funp call"
> +
> +# Step into body of funp, called via GEP.
> +gdb_test "step" ".*int ret = 0;.*" "step test 2"
> +
> +delete_breakpoints
> +
> +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> + "reverse-finish function1 GEP 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. 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 = 50;.*" \
> + "reverse next at b = 50 from function body"
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-13 13:33 ` Bruno Larsen
@ 2023-01-13 16:43 ` Carl Love
2023-01-13 17:04 ` Bruno Larsen
2023-01-14 18:08 ` Carl Love
1 sibling, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-13 16:43 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Bruno:
On Fri, 2023-01-13 at 14:33 +0100, Bruno Larsen wrote:
> > +# 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.
>
> While testing locally, I ran into a bug with reverse finish at the
> epilogue of the function, that your patch also fixed. It would be
> nice
> if the test extended that. And since the bug was that GDB stopped
> responding and even ctrl+c did nothing, I would suggest adding it as
> the
> last test.
I haven't run into the issue that mentioned about GDB not responding in
the epilogue. I will have to go play with that to see if I can
reproduce it. If you have any specific instructions on how you ran
into it that would be interesting and helpful.
I have read thru the other comments and will work on them and update
you on those fixes later. Thanks for the feedback.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-13 16:43 ` Carl Love
@ 2023-01-13 17:04 ` Bruno Larsen
2023-01-13 19:10 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-13 17:04 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 13/01/2023 17:43, Carl Love wrote:
> Bruno:
>
> On Fri, 2023-01-13 at 14:33 +0100, Bruno Larsen wrote:
>>> +# 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.
>> While testing locally, I ran into a bug with reverse finish at the
>> epilogue of the function, that your patch also fixed. It would be
>> nice
>> if the test extended that. And since the bug was that GDB stopped
>> responding and even ctrl+c did nothing, I would suggest adding it as
>> the
>> last test.
> I haven't run into the issue that mentioned about GDB not responding in
> the epilogue. I will have to go play with that to see if I can
> reproduce it. If you have any specific instructions on how you ran
> into it that would be interesting and helpful.
I manually ran gdb.reverse/finish-precsave (setting recording, of
course), set a temporary breakpoint on void_func, nexted once to be in
the epilogue and tried to reverse finish. I'm not sure if it was some
stale file before I recompiled the test, though.
Anyway, sorry if I was unclear, but that is not a regression of your
patch. Rather, you patch fixed that issue, I just want that test to
confirm that we don't accidentally regress it.
--
Cheers,
Bruno
>
> I have read thru the other comments and will work on them and update
> you on those fixes later. Thanks for the feedback.
>
> Carl
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-13 17:04 ` Bruno Larsen
@ 2023-01-13 19:10 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-13 19:10 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Bruno:
On Fri, 2023-01-13 at 18:04 +0100, Bruno Larsen wrote:
> > I haven't run into the issue that mentioned about GDB not
> > responding in
> > the epilogue. I will have to go play with that to see if I can
> > reproduce it. If you have any specific instructions on how you ran
> > into it that would be interesting and helpful.
>
> I manually ran gdb.reverse/finish-precsave (setting recording, of
> course), set a temporary breakpoint on void_func, nexted once to be
> in
> the epilogue and tried to reverse finish. I'm not sure if it was
> some
> stale file before I recompiled the test, though.
>
> Anyway, sorry if I was unclear, but that is not a regression of your
> patch. Rather, you patch fixed that issue, I just want that test to
> confirm that we don't accidentally regress it.
You were clear that you saw this as an existing issue before applying
my patches, i.e. not a regression due to my patch. But rather my patch
fixed an existing issue.
I have been playing around on my X86 box trying to reproduce the issue.
I have an X86 box running Ubuntu 22.04.1 LTS, gcc version Ubuntu
11.3.0-1ubuntu1~22.04.
Here is the log of what I did trying to reproduce the issue as you
described:
Note, I started by running
make check RUNTESTFLAGS='GDB=/home/carll/bin/gdb gdb.reverse/finish-precsave.exp'
to generate the binary for the test. I then cd'd to
~/GDB/build-finish-precsave/gdb/testsuite/outputs/gdb.reverse/finish-precsave
where the binary was saved.
Then I ran the test. The following is the results with the path names
to the files shortened to improve readability.
gdb ./finish-precsave
GNU gdb (GDB) 14.0.50.20230111-git
<snip>
Reading symbols from ./finish-precsave...
(gdb) break main
Breakpoint 1 at 0x11d3: file .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/finish-reverse.c, line 95.
(gdb) r
Starting program: .../gdb/testsuite/outputs/gdb.reverse/finish-precsave/finish-precsave
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (argc=1, argv=0x7fffffffe798)
at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/finish-reverse.c:95
95 for (i = 0; i < sizeof (testval.ffff); i++)
(gdb) record
(gdb) tb void_func
Temporary breakpoint 2 at 0x555555555131: file .../binutils-gdb-finishrecsave/gdb/testsuite/gdb.reverse/finish-reverse.c, line 44.
(gdb) c
Continuing.
Temporary breakpoint 2, void_func ()
at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/finish-reverse.c:44
44 void_test = 1; /* VOID FUNC */
(gdb) next
45 }
(gdb) reverse-finish
Run back to call of #0 void_func ()
at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/finish-reverse.c:45
0x00005555555551fd in main (argc=1, argv=0x7fffffffe798)
at ../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/finish-reverse.c:98
98 void_func (); /* call to void_func */
(gdb) reverse-step
98 void_func (); /* call to void_func */
(gdb) q
I have tried stopping in the other functions as well. The reverse-
finish still seems to work fine. I also tried setting layout-asm once
I reached the function and then did si to reach various instructions in
the epilog. Didn't seem to matter which instruction in the function I
was at when I issued the reverse-finish instruction, I was not able to
get gdb to hang. Unfortunately, I was not able to reproduce the issue
on X86. I have also tried reproducing the error on PowerPC without
success.
I created a new test case to do the above tests. My thought is if we
can get this new test case to reliably fail on your system without my
proposed patches, then we can add it to the new test case in the patch.
The test case passes on my X86 machine. Of course it fails on my PPC
machine due to the existing reverse finish issues. What do you think?
Carl
-------------------------------------------
reverse-finish hang test
---
.../gdb.reverse/gdb-reverse-finish-hang.exp | 54 +++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 gdb/testsuite/gdb.reverse/gdb-reverse-finish-hang.exp
diff --git a/gdb/testsuite/gdb.reverse/gdb-reverse-finish-hang.exp b/gdb/testsuite/gdb.reverse/gdb-reverse-finish-hang.exp
new file mode 100644
index 00000000000..14a3991c9b9
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/gdb-reverse-finish-hang.exp
@@ -0,0 +1,54 @@
+# 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 'finish' with
+# reverse debugging.
+
+if ![supports_reverse] {
+ return
+}
+
+standard_testfile finish-reverse.c
+set precsave [standard_output_file finish.precsave]
+
+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"
+}
+
+# Test reverse finish from void func to see if gdb hangs.
+set breakloc [gdb_get_line_number "VOID FUNC" "$srcfile"]
+gdb_test "tbreak void_func" \
+ "Temporary breakpoint $decimal at .*$srcfile, line $breakloc\." \
+ "set breakpoint on void_func"
+gdb_continue_to_breakpoint "void_func" ".*$srcfile:$breakloc.*"
+
+# Step into epilogue of void_func.
+gdb_test "step" ".*}.*" "step to epilog"
+
+# Test to see if gdb hangs when doing a reverse-finish from the epilogue.
+gdb_test "reverse-finish" "$decimal.*void_func.*" \
+ "return to caller of void_func ()"
+
+# Do reverse-next, should stay on void_func function due to existing bug
+# in reverse-finish.
+gdb_test "reverse-next" "$decimal.*void_func.*" \
+ "reverse next in main"
--
2.34.1
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-13 13:33 ` Bruno Larsen
2023-01-13 16:43 ` Carl Love
@ 2023-01-14 18:08 ` Carl Love
2023-01-16 12:31 ` Bruno Larsen
1 sibling, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-14 18:08 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
On Fri, 2023-01-13 at 14:33 +0100, Bruno Larsen wrote:
> On 11/01/2023 19:27, Carl Love via Gdb-patches wrote:
> > GDB maintainers:
> >
> > This patch fixes the issues with the reverse-finish command on X86.
> > The reverse-finish command now correctly stops at the first
> > instruction
> > in the source code line of the caller. It now only requires a
> > single
> > reverse-step or reverse-next instruction to get back to the
> > previous
> > source code line.
> >
> > It also adds a new testcase, gdb.reverse/finish-reverse-next.exp,
> > and
> > updates several existing testcases.
> >
> > Please let me know if you have any comments on the patch. Thanks.
> Thanks for looking at this, this is a nice change. I just have a
> couple
> of comments, mostly related to the testsuite side.
> > Carl
> >
> > --------------------------------------------------------------
> > X86: reverse-finish fix
> >
> > Currently on X86, when executing the finish command in reverse, gdb
> > does a
> > single step from the first instruction in the callee to get back to
> > the
> > caller. GDB stops on the last instruction in the source code line
> > where
> > the call was made. When stopped at the last instruction of the
> > source code
> > line, a reverse next or step command will stop at the first
> > instruction
> > of the same source code line thus requiring two step/next commands
> > to
> > reach the previous source code line. It should only require one
> > step/next
> > command to reach the previous source code line.
> >
> > By contrast, a reverse next or step command from the first line in
> > a
> > function stops at the first instruction in the source code line
> > where the
> > call was made.
> >
> > This patch fixes the reverse finish command so it will stop at the
> > first
> > instruction of the source line where the function call was
> > made. The
> > behavior on X86 for the reverse-finish command now matches doing a
> > reverse-next from the beginning of the function.
> >
> > The proceed_to_finish flag in struct thread_control_state is no
> > longer
> > used. This patch removes the declaration, initialization and
> > setting of
> > the flag.
> >
> > This patch requires a number of regression tests to be
> > updated. Test
> > gdb.mi/mi-reverse.exp no longer needs to execute two steps to get
> > to the
> > previous line. The gdb output for tests gdb.reverse/until-
> > precsave.exp
> > and gdb.reverse/until-reverse.exp changed slightly. The expected
> > result in
> > tests gdb.reverse/amd64-ailcall-reverse.exp and
> s/ailcall/tailcall
Fixed
> > gdb.reverse/singlejmp-reverse.exp are updated to the correct
> > expected
> > result.
> >
> > This patch adds a new test gdb.reverse/finish-reverse-next.exp to
> > test the
> > reverse-finish command when returning from the entry point and from
> > the
> > body of the function.
> >
> > The step_until proceedure in test gdb.reverse/step-indirect-call-
> > thunk.exp
> > was moved to lib/gdb.exp and renamed cmd_until.
> I'm not a big fan of the name cmd_until, because it sounded to me
> like
> you were testing the GDB command until. I think repeat_cmd_until or
> repeat_until would avoid this possible confusion.
Changed cmd_until to repeat_cmd_until.
> > The patch has been tested on X86 and PowerPC to verify no
> > additional
> > regression failures occured.
> >
> > Bug:
> > https://sourceware.org/bugzilla/show_bug.cgi?id=29927
> >
> If you add record/29927 somewhere along the text of your commit
> message,
> there is some automation that will comment on the bugzilla bug
> specifying this commit. Might be worth doing for future reference.
Added. I realized I had forgotten to do that after I sent the email.
I added it to both patches.
> > ---
> > gdb/gdbthread.h | 4 -
> > gdb/infcall.c | 3 -
> > gdb/infcmd.c | 32 +++---
> > gdb/infrun.c | 41 +++----
> > gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
> > .../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
> > .../gdb.reverse/finish-reverse-next.c | 48 ++++++++
> > .../gdb.reverse/finish-reverse-next.exp | 108
> > ++++++++++++++++++
> > gdb/testsuite/gdb.reverse/finish-reverse.exp | 5 +
> > .../gdb.reverse/singlejmp-reverse.exp | 5 +-
> > .../gdb.reverse/step-indirect-call-thunk.exp | 49 ++------
> > gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
> > gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
> > gdb/testsuite/lib/gdb.exp | 33 ++++++
> > 14 files changed, 240 insertions(+), 106 deletions(-)
> > create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-
> > next.c
> > create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-
> > next.exp
> >
> > diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
> > index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
> > --- a/gdb/infcmd.c
> > +++ b/gdb/infcmd.c
> > @@ -1721,19 +1721,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
> > @@ -1743,16 +1734,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
> > @@ -1778,9 +1775,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 181d961d80d..8ed538ea9ec 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,28 @@ 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
> > + && ecs->event_thread->stop_pc () == ecs->stop_func_start)
> Is there any reason to invert the order of checks here? The second
> if
> clause is the same and keeping that would make the changes easier to
> parse.
No, must have inadvertently swizzled it as part of the patch
development. Per comments for the second patch, PowerPC, the "cs-
>event_thread->stop_pc () == ecs->stop_func_start" check should be
removed in this patch not the PowerPC patch. Probably got missed when
I switched the order of the patches.
Fixed, removed the "ecs->event_thread->stop_pc () == ecs-
>stop_func_start" test here.
> > {
> > struct thread_info *tp = ecs->event_thread;
> > + stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (),
> > 0);
> >
> > - /* 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;
The following comment was from the second email.
> case BPSTAT_WHAT_STEP_RESUME:> Something else that I failed to
notice. Since you removed both
> comments
> that mention that this case is here for reverse finishing, there is
> no
> good way to figure out what GDB wants to do when this part of the
> code
> is reached. Adding a comment here mentioning it would fix that.
> > infrun_debug_printf ("BPSTAT_WHAT_STEP_RESUME");
There were two separate if statements, each with a comment about what
they were for. Those comments were removed and a new, similar, comment
was added in the single new if statement. Admittedly, the new comment
is a bit farther into the function and thus easy to miss. So, I moved
the initial comment about what is going on "We are finishing a function
in reverse or..." up to the beginning of the if statement. Hopefully
that helps make it quicker/easier for the reader to see what the
purpose of the case statement/if statement. Please let me know if that
helps address your concerns.
> > + /* 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);
> > +
> > + /* 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.
> > +
> > + 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 d631beb17c8..30635ab1754 100644
> > --- a/gdb/testsuite/gdb.mi/mi-reverse.exp
> > +++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
> > @@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
> > --- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
> > +++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
> > @@ -44,6 +44,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 00000000000..42e41b5a2e0
> > --- /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-2022 Free Software Foundation, Inc.
> copyright year should be 2023.
> > +
> > + 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 00000000000..7880de10ffc
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > @@ -0,0 +1,108 @@
> > +# Copyright 2008-2022 Free Software Foundation, Inc.
Fixed copyright so it reads 2008-2023. Fixed in finish-reverse-
next.exp and finish-reverse-next.c.
> > +
> > +# 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.
>
> While testing locally, I ran into a bug with reverse finish at the
> epilogue of the function, that your patch also fixed. It would be
> nice
> if the test extended that. And since the bug was that GDB stopped
> responding and even ctrl+c did nothing, I would suggest adding it as
> the
> last test.
Discussed this additional bug in earlier emails. Waiting to hear if
the new test I sent reliably exposes the gdb hang that Bruno reported.
If it does, I will add the new test to the new test case before posting
the updated patch set. Per the discussions, I have not been able to
reproduce the issue on my X86 or PowerPC machines.
>
> > +
> > +# 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 FUNCTION_test [gdb_get_line_number "CALL FUNCTION" $srcfile]
> > +gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at
> > .*" \his
> > + "set breakpoint on function1 call to stepi into function"
>
> There is a proc in lib/gdb.exp called gdb_breakpoint which
> couldsimplify
> this gdb_test to
>
> gdb_breakpoint $srcfile:$FUNCTION_test temporary
>
> And would remove the need for the delete_breakpoints call later.
>
OK, made the change in both tests. Made the same change in the PowerPC
patch that adds additional tests.
> > +
> > +# Continue to break point at function1 call in main.
> > +gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*"
> > \
> > + "stopped at function1 entry point instruction to stepi into
> > function"
> You can use gdb_continue_to_breakpoint here instead.
OK, made the change in both tests. Made the same change in the PowerPC
patch that adds additional tests.
> > +
> > +# stepi until we see "{" indicating we entered function1
> > +cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
> > +
> > +delete_breakpoints
> > +
> > +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_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at
> > .*" \
> > + "set breakpoint on function1 call to step into body of
> > function"
> > +
> > +# Continue to break point at function1 call in main.
> > +gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*"
> > \
> > + "stopped at function1 entry point instruction to step to body
> > of function"
> > +
> > +delete_breakpoints
> > +
> > +# 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/finish-reverse.exp
> > b/gdb/testsuite/gdb.reverse/finish-reverse.exp
> > index 01ba309420c..a05cb81892a 100644
> > --- a/gdb/testsuite/gdb.reverse/finish-reverse.exp
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse.exp
> > @@ -16,6 +16,11 @@
> > # This file is part of the GDB testsuite. It tests 'finish' with
> > # reverse debugging.
> >
> > +# This test verifies the fix for gdb bugzilla:
> > +
> > +#
> > https://sourceware.org/bugzilla/show_bug.cgi?id=29927
> >
> > +
> > +
>
> Is this comment a left over from an earlier version?
>
> I actually wonder if the whole new test is needed, or if you can
> just
> add a couple of new tests to finish-reverse.exp; is there any reason
> you
> went with the new test instead
Yes, it is left over. Initially I just added an additional test to
finish-reverse.exp for the PowerPC fix. But as work progressed, I kept
adding more tests for PowerPC then for X86. I felt that it was better
to have a new test file that was tied to the Bugzilla. The existing
test file has a different focus from the new tests. The bugzilla
change didn't get removed from finish-reverse.exp when the tests were
moved to the new file. We can combine the tests again if that is
preferable? My preference would be to have separate test files.
Please let me know if you would prefer a single file and I will merge
them before re-posting the patches.
>
> > if ![supports_reverse] {
> > return
> > }
> > diff --git a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> > b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> > index 1ca7c2ce559..eb03051625a 100644
> > --- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> > +++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> > @@ -56,7 +56,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 ad637899e5b..1928cdda217 100644
> > --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> > +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> > @@ -39,39 +39,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"
> >
> > @@ -91,20 +58,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" \
> > +cmd_until "stepi" "apply\.2" "indirect_thunk" "stepi into call
> > thunk"
> > +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" \
> > +cmd_until "stepi" "(inc|$pic_thunk_re)" "return_thunk" "stepi into
> > return thunk"
> > +cmd_until "stepi" "return_thunk" "apply" \
> > "stepi out of return thunk back into apply"
> >
> > -step_until "reverse-stepi" "apply" "return_thunk" \
> > +cmd_until "reverse-stepi" "apply" "return_thunk" \
> > "reverse-stepi into return thunk"
> > -step_until "reverse-stepi" "return_thunk" "inc" \
> > +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"
> > \
> > +cmd_until "reverse-stepi" "(inc|$pic_thunk_re)" "indirect_thunk" \
> > "reverse-stepi into call thunk"
> > -step_until "reverse-stepi" "indirect_thunk" "apply" \
> > +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 0c2d7537cd6..777aec94ac1 100644
> > --- a/gdb/testsuite/gdb.reverse/until-precsave.exp
> > +++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
> > @@ -142,7 +142,7 @@ gdb_test "advance marker2" \
> > # Finish out to main scope (backward)
> >
> > gdb_test "finish" \
> > - " in main .*$srcfile:$bp_location20.*" \
> > + "main .*$srcfile:$bp_location20.*" \
> This change doesn't seem connected to anything in this patch, is
> this
> just a cosmetic change or was there some problem?
> > "reverse-finish from marker2"
> >
The output changes due to the functional changes in infrun.c. Instead
of stepping back one instruction i.e. ecs->event_thread-
>stepping_over_breakpoint = 1 we step back using a range. Apparently
this causes the gdb output message to change.
Without the patch the output looks like:
Run back to call of #0 marker2 (a=43) at.../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/ur1.c:30
0x0000000010000838 in main (argc=1, argv=0x7fffffffcc58, envp=0x7fffffffcc68) at /.../gdb/testsuite/gdb.reverse/until-reverse.c:48^
With the patch the output looks like:
Run back to call of #0 marker2 (a=43) at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/ur1.c:30
main (argc=1, argv=0x7fffffffcc58, envp=0x7fffffffcc68) at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/until-reverse.c:48
Basically, you lose the hex value and "in" with the patch applied.
This is true in the until-reverse.exp tes, below, as well. The output
change was mentioned in the commit message as well.
> > # 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 23fc881dbf2..3a05953329f 100644
> > --- a/gdb/testsuite/gdb.reverse/until-reverse.exp
> > +++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
> > @@ -113,7 +113,7 @@ gdb_test "advance marker2" \
> > # Finish out to main scope (backward)
> >
> > gdb_test "finish" \
> > - " in main .*$srcfile:$bp_location20.*" \
> > + "main .*$srcfile:$bp_location20.*" \
> same here.
Yup, see above.
> > "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 c41d4698d66..25f42eb5510 100644
> > --- a/gdb/testsuite/lib/gdb.exp
> > +++ b/gdb/testsuite/lib/gdb.exp
> > @@ -9301,6 +9301,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 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.
> > #
>
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-13 15:55 ` Bruno Larsen
@ 2023-01-14 18:08 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-14 18:08 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
On Fri, 2023-01-13 at 16:55 +0100, Bruno Larsen wrote:
> On 11/01/2023 19:27, Carl Love via Gdb-patches wrote:
> > GDB maintainers:
> >
> > This patch fixes the issues with the reverse-finish command on
> > PowerPC. The reverse-finish command now correctly stops at the
> > first
> > instruction in the source code line of the caller.
> >
> > The patch adds tests for calling a function via the GEP to the new
> > test
> > gdb.reverse/finish-reverse-next.exp.
> >
> > Please let me know if you have any comments on the patch. Thanks.
> I'm not all that familiar with PowerPC ABI and I dont have a
> computer
> handy to test that the patch fixes the problem, but the logic seems
> sound. Just a few nits inlined.
> > Carl
> >
> > --------------------------------------------------------------
> > PowerPC: fix for gdb.reverse/finish-precsave.exp and
> > gdb.reverse/finish-reverse.exp
> >
> > PowerPC uses two entry points called the local entry point (LEP)
> > and the
> > global entry point (GEP). Normally the LEP is used when calling a
> > function. However, if the table of contents (TOC) value in
> > register 3 is not valid the GEP is called to setup the TOC before
> > execution
> > continues at the LEP. When executing in reverse, the function
> > finish_backward sets the break point at the alternate entry point
> > (GEP).
> > However if the forward execution enters via the normal entry point
> > (LEP),
> > the reverse execution never sees the break point at the GEP of the
> > function. Reverse execution continues until the next break point
> > is
> > encountered or the end of the recorded log is reached causing gdb
> > to stop
> > at the wrong place.
> >
> > This patch adds a new address to struct execution_control_state to
> > hold the
> > address of the alternate function start address, known as the GEP
> > on
> > PowerPC. The finish_backwards function is updated. If the
> > stopping point
> > is between the two entry points (the LEP and GEP on PowerPC) , the
> > stepping
> > range is set to execute back to the alternate entry point (GEP on
> > PowerPC).
> > Otherwise, a breakpoint is inserted at the normal entry point (LEP
> > on
> > PowerPC).
> >
> > Function process_event_stop_test checks uses a stepping range to
> > stop
> > execution in the caller at the first instruction of the source code
> > line.
> > Note, on systems that only support one entry point, the address of
> > the two
> > entry points are the same.
> >
> > Test finish-reverse-next.exp is updated to include tests for the
> > reverse-finish command when the function is entered via the normal
> > entry
> > point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
> >
> > The patch has been tested on X86 and PowerPC with no regressions.
> > ---
> > gdb/infcmd.c | 41 ++++---
> > gdb/infrun.c | 21 +++-
> > .../gdb.reverse/finish-reverse-next.c | 41 ++++++-
> > .../gdb.reverse/finish-reverse-next.exp | 107
> > +++++++++++++++---
> > 4 files changed, 175 insertions(+), 35 deletions(-)
> >
> > diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> > index 9c42efeae8d..8c30af448ce 100644
> > --- a/gdb/infcmd.c
> > +++ b/gdb/infcmd.c
> > @@ -1722,22 +1722,28 @@ finish_backward (struct finish_command_fsm
> > *sm)
> > sal = find_pc_line (func_addr, 0);
> >
> > frame_info_ptr frame = get_selected_frame (nullptr);
> > + struct gdbarch *gdbarch = get_frame_arch (frame);
> > + CORE_ADDR alt_entry_point = sal.pc;
> > + CORE_ADDR entry_point = alt_entry_point;
> >
> > - if (sal.pc != pc)
> > + if (gdbarch_skip_entrypoint_p (gdbarch))
> > {
> > - struct gdbarch *gdbarch = get_frame_arch (frame);
> > + /* Some architectures, like PowerPC use local and global
> > entry
> > + points. There is only one Entry Point (GEP = LEP) for other
> > + architectures. The GEP is an alternate entry point that is
> > used
> > + setup the table of contents (TOC) in register r2 before
> > execution
> > + continues at the LEP. The LEP is the normal entry point.
> I don't think an explanation on why there are 2 entry points is
> necessary. just mentioning that both exist is enough IMHO.
OK, took out the additional detail in the comment.
> > + The value of entry_point was initialized to the alternate
> > entry
> > + point (GEP). It will be adjusted if the normal entry point
> > + (LEP) was used. */
> > + entry_point = gdbarch_skip_entrypoint (gdbarch,
> > entry_point);
> >
> > - /* Set a step-resume at the function's entry point. Once
> > that's
> > - hit, we'll do one more step backwards. */
> > - symtab_and_line sr_sal;
> > - sr_sal.pc = sal.pc;
> > - sr_sal.pspace = get_frame_program_space (frame);
> > - insert_step_resume_breakpoint_at_sal (gdbarch,
> > - sr_sal, null_frame_id);
> > }
> > - else
> > +
> > + if (alt_entry_point <= pc && pc <= entry_point)
> > {
> > - /* We are exactly at the function entry point. Note that
> > this
> > + /* We are exactly at the function entry point, or between
> > the entry
> > + point on platforms that have two (like PowerPC). Note that
> > this
> > can only happen at frame #0.
> >
> > When setting a step range, need to call set_step_info
> > @@ -1746,8 +1752,17 @@ finish_backward (struct finish_command_fsm
> > *sm)
> >
> > /* 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;
> > + tp->control.step_range_start = alt_entry_point;
> > + tp->control.step_range_end = alt_entry_point;
> I'm hesitant in this part. What if there is one instruction between
> the
> GEP and the LEP and the inferior happens to be stopped there? Could
> this
> happen?
Yes, if the user did a step instruction from the caller and stopped on
the second instruction in the function. Note, there is actually one
instruction between the GEP instruction and the LEP instruction.
> Like I said, I'm not familiar with the PPC abi, so excuse me if
> the answer is obvious, but it seems to me that the step_range_end
> could
> be set to the entry_point and we'd avoid this possibility.
Yes, that might be a little safer. Changed to set step_range_end to
entry_point. the LEP which occurs two instructions after the GEP.
> > + }
> > + else
> > + {
> > + symtab_and_line sr_sal;
> > + /* Set a step-resume at the function's entry point. */
> > + sr_sal.pc = entry_point;
> > + 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);
> > }
> > diff --git a/gdb/infrun.c b/gdb/infrun.c
> > index 8ed538ea9ec..89423556ec0 100644
> > --- a/gdb/infrun.c
> > +++ b/gdb/infrun.c
> > @@ -1868,6 +1868,7 @@ struct execution_control_state
> >
> > struct target_waitstatus ws;
> > int stop_func_filled_in = 0;
> > + CORE_ADDR stop_func_alt_start = 0;
> > CORE_ADDR stop_func_start = 0;
> > CORE_ADDR stop_func_end = 0;
> > const char *stop_func_name = nullptr;
> > @@ -4663,6 +4664,14 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> > &block);
> > ecs->stop_func_name = gsi == nullptr ? nullptr : gsi-
> > >print_name ();
> >
> > + /* PowerPC functions have a Local Entry Point and a Global
> > Entry
> > + Point. There is only one Entry Point (GEP = LEP) for other
> > + architectures. The GEP is an alternate entry point that is
> > used
> > + setup the table of contents (TOC) in register r2 before
> > execution
> > + continues at the LEP. Save the alternate entry point address
> > for
> Ditto here about explaining LEP and GEP. Just saying that GEP is the
> alternate is probably enough.
OK, removed the additional explanation from both places in the GDB
code. I did leave the extra descripion in the test case where I gave
the sample assembly code. My feeling is having that extra information
is useful in the test case to explain what the specific test scenarios
are doing and why is helpful. Having the extra detail repeated three
times in the gdb source code and test case is probably a bit much.
> > + use later. */
> > + ecs->stop_func_alt_start = ecs->stop_func_start;
> > +
> > /* The call to find_pc_partial_function, above, will set
> > stop_func_start and stop_func_end to the start and end
> > of the range containing the stop pc. If this range
> > @@ -4679,6 +4688,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> > += gdbarch_deprecated_function_start_offset (gdbarch);
> >
> > if (gdbarch_skip_entrypoint_p (gdbarch))
> > + /* The PowerPC architecture uses two entry points. Stop at
> > the
> > + regular entry point (LEP on PowerPC) initially. Will
> > setup a
> > + breakpoint for the alternate entry point (GEP)
> > later. */
> > ecs->stop_func_start
> > = gdbarch_skip_entrypoint (gdbarch, ecs-
> > >stop_func_start);
> > }
> > @@ -6738,8 +6750,7 @@ process_event_stop_test (struct
> > execution_control_state *ecs)
> > delete_step_resume_breakpoint (ecs->event_thread);
> > fill_in_stop_func (gdbarch, ecs);
> >
> > - if (execution_direction == EXEC_REVERSE
> > - && ecs->event_thread->stop_pc () == ecs->stop_func_start)
> > + if (execution_direction == EXEC_REVERSE)
> Why is this change not in the previous patch?
Looks like it didn't get moved when I was reversing the order of the
patches.
Moved the change to the previous patch.
> > {
> > struct thread_info *tp = ecs->event_thread;
> > stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (),
> > 0);
> > @@ -6755,7 +6766,7 @@ process_event_stop_test (struct
> > execution_control_state *ecs)
> >
> > 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_start = ecs->stop_func_alt_start;
> > tp->control.step_range_end = ecs->stop_func_start;
> > keep_going (ecs);
> > return;
> > @@ -6892,8 +6903,10 @@ process_event_stop_test (struct
> > execution_control_state *ecs)
> > (unless it's the function entry point, in which case
> > keep going back to the call point). */
> > CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> > +
> > if (stop_pc == ecs->event_thread->control.step_range_start
> > - && stop_pc != ecs->stop_func_start
> > + && (stop_pc < ecs->stop_func_alt_start
> > + || stop_pc > ecs->stop_func_start)
> > && execution_direction == EXEC_REVERSE)
> > end_stepping_range (ecs);
> > else
> > diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > index 42e41b5a2e0..55f81d2bc01 100644
> > --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > @@ -1,4 +1,4 @@
> >
<snip>
> > diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > index 7880de10ffc..fbc024b48b9 100644
> > --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
<snip>
The comments for patch 1/2 about using gdb_breakpoint and
gdb_continue_to_breakpoint were also applied to the two new tests.
> > +
> > +### 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 GEP_test [gdb_get_line_number "CALL VIA GEP" $srcfile]
> > +gdb_test "break $srcfile:$GEP_test" "Breakpoint $decimal at .*" \
> > + "set breakpoint on function1 GEP call to stepi into function"
> > +
> > +# Continue to break point at funp call in main.
> > +gdb_test "continue" "Breakpoint $decimal.*funp \\(a, b\\).*" \
> > + "stopped at funp entry point instruction"
> > +
> > +# stepi until we see "{" indicating we entered function.
> > +cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call"
> > +
> > +delete_breakpoints
> > +
> > +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> > + "function1 GEP call call from GEP"
> > +
> > +# 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 = 50;.*" "reverse next at b = 50,
> > call from GEP"
> > +
> > +# 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 the body of function 1 when
> > calling using the
> > +### alternate entrypoint (GEP).
> > +gdb_test "break $srcfile:$GEP_test" "Breakpoint $decimal at .*" \
> > + "set breakpoint on funp GEP call to step into body of
> > function"
> > +
> > +# Continue to break point at funp call.
> > +gdb_test "continue" "Breakpoint $decimal,.*funp \\(a, b\\).*" \
> > + "stopped at funp call"
> > +
> > +# Step into body of funp, called via GEP.
> > +gdb_test "step" ".*int ret = 0;.*" "step test 2"
> > +
> > +delete_breakpoints
> > +
> > +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> > + "reverse-finish function1 GEP 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. 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 = 50;.*" \
> > + "reverse next at b = 50 from function body"
>
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-14 18:08 ` Carl Love
@ 2023-01-16 12:31 ` Bruno Larsen
2023-01-16 16:37 ` [PATCH 0/2 version 2] " Carl Love
` (2 more replies)
0 siblings, 3 replies; 105+ messages in thread
From: Bruno Larsen @ 2023-01-16 12:31 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 14/01/2023 19:08, Carl Love wrote:
> On Fri, 2023-01-13 at 14:33 +0100, Bruno Larsen wrote:
>> On 11/01/2023 19:27, Carl Love via Gdb-patches wrote:
>>> GDB maintainers:
>>>
>>> This patch fixes the issues with the reverse-finish command on X86.
>>> The reverse-finish command now correctly stops at the first
>>> instruction
>>> in the source code line of the caller. It now only requires a
>>> single
>>> reverse-step or reverse-next instruction to get back to the
>>> previous
>>> source code line.
>>>
>>> It also adds a new testcase, gdb.reverse/finish-reverse-next.exp,
>>> and
>>> updates several existing testcases.
>>>
>>> Please let me know if you have any comments on the patch. Thanks.
>> Thanks for looking at this, this is a nice change. I just have a
>> couple
>> of comments, mostly related to the testsuite side.
>>> Carl
>>>
>>> --------------------------------------------------------------
>>> X86: reverse-finish fix
>>>
>>> Currently on X86, when executing the finish command in reverse, gdb
>>> does a
>>> single step from the first instruction in the callee to get back to
>>> the
>>> caller. GDB stops on the last instruction in the source code line
>>> where
>>> the call was made. When stopped at the last instruction of the
>>> source code
>>> line, a reverse next or step command will stop at the first
>>> instruction
>>> of the same source code line thus requiring two step/next commands
>>> to
>>> reach the previous source code line. It should only require one
>>> step/next
>>> command to reach the previous source code line.
>>>
>>> By contrast, a reverse next or step command from the first line in
>>> a
>>> function stops at the first instruction in the source code line
>>> where the
>>> call was made.
>>>
>>> This patch fixes the reverse finish command so it will stop at the
>>> first
>>> instruction of the source line where the function call was
>>> made. The
>>> behavior on X86 for the reverse-finish command now matches doing a
>>> reverse-next from the beginning of the function.
>>>
>>> The proceed_to_finish flag in struct thread_control_state is no
>>> longer
>>> used. This patch removes the declaration, initialization and
>>> setting of
>>> the flag.
>>>
>>> This patch requires a number of regression tests to be
>>> updated. Test
>>> gdb.mi/mi-reverse.exp no longer needs to execute two steps to get
>>> to the
>>> previous line. The gdb output for tests gdb.reverse/until-
>>> precsave.exp
>>> and gdb.reverse/until-reverse.exp changed slightly. The expected
>>> result in
>>> tests gdb.reverse/amd64-ailcall-reverse.exp and
>> s/ailcall/tailcall
> Fixed
>
>>> gdb.reverse/singlejmp-reverse.exp are updated to the correct
>>> expected
>>> result.
>>>
>>> This patch adds a new test gdb.reverse/finish-reverse-next.exp to
>>> test the
>>> reverse-finish command when returning from the entry point and from
>>> the
>>> body of the function.
>>>
>>> The step_until proceedure in test gdb.reverse/step-indirect-call-
>>> thunk.exp
>>> was moved to lib/gdb.exp and renamed cmd_until.
>> I'm not a big fan of the name cmd_until, because it sounded to me
>> like
>> you were testing the GDB command until. I think repeat_cmd_until or
>> repeat_until would avoid this possible confusion.
> Changed cmd_until to repeat_cmd_until.
>
>>> The patch has been tested on X86 and PowerPC to verify no
>>> additional
>>> regression failures occured.
>>>
>>> Bug:
>>> https://sourceware.org/bugzilla/show_bug.cgi?id=29927
>>>
>> If you add record/29927 somewhere along the text of your commit
>> message,
>> there is some automation that will comment on the bugzilla bug
>> specifying this commit. Might be worth doing for future reference.
> Added. I realized I had forgotten to do that after I sent the email.
> I added it to both patches.
>
>>> ---
>>> gdb/gdbthread.h | 4 -
>>> gdb/infcall.c | 3 -
>>> gdb/infcmd.c | 32 +++---
>>> gdb/infrun.c | 41 +++----
>>> gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
>>> .../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
>>> .../gdb.reverse/finish-reverse-next.c | 48 ++++++++
>>> .../gdb.reverse/finish-reverse-next.exp | 108
>>> ++++++++++++++++++
>>> gdb/testsuite/gdb.reverse/finish-reverse.exp | 5 +
>>> .../gdb.reverse/singlejmp-reverse.exp | 5 +-
>>> .../gdb.reverse/step-indirect-call-thunk.exp | 49 ++------
>>> gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
>>> gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
>>> gdb/testsuite/lib/gdb.exp | 33 ++++++
>>> 14 files changed, 240 insertions(+), 106 deletions(-)
>>> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-
>>> next.c
>>> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-
>>> next.exp
>>>
>>> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
>>> index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
>>> --- a/gdb/infcmd.c
>>> +++ b/gdb/infcmd.c
>>> @@ -1721,19 +1721,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
>>> @@ -1743,16 +1734,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
>>> @@ -1778,9 +1775,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 181d961d80d..8ed538ea9ec 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,28 @@ 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
>>> + && ecs->event_thread->stop_pc () == ecs->stop_func_start)
>> Is there any reason to invert the order of checks here? The second
>> if
>> clause is the same and keeping that would make the changes easier to
>> parse.
> No, must have inadvertently swizzled it as part of the patch
> development. Per comments for the second patch, PowerPC, the "cs-
>> event_thread->stop_pc () == ecs->stop_func_start" check should be
> removed in this patch not the PowerPC patch. Probably got missed when
> I switched the order of the patches.
>
> Fixed, removed the "ecs->event_thread->stop_pc () == ecs-
>> stop_func_start" test here.
>>> {
>>> struct thread_info *tp = ecs->event_thread;
>>> + stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (),
>>> 0);
>>>
>>> - /* 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;
> The following comment was from the second email.
>
> > case BPSTAT_WHAT_STEP_RESUME:> Something else that I failed to
> notice. Since you removed both
>> comments
>> that mention that this case is here for reverse finishing, there is
>> no
>> good way to figure out what GDB wants to do when this part of the
>> code
>> is reached. Adding a comment here mentioning it would fix that.
>>> infrun_debug_printf ("BPSTAT_WHAT_STEP_RESUME");
> There were two separate if statements, each with a comment about what
> they were for. Those comments were removed and a new, similar, comment
> was added in the single new if statement. Admittedly, the new comment
> is a bit farther into the function and thus easy to miss. So, I moved
> the initial comment about what is going on "We are finishing a function
> in reverse or..." up to the beginning of the if statement. Hopefully
> that helps make it quicker/easier for the reader to see what the
> purpose of the case statement/if statement. Please let me know if that
> helps address your concerns.
Yeah, this works. It is mostly so that we don't end up with a comment
kinda far away or in a situation where it's hard to understand the point
of this case statement.
>
>>> + /* 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);
>>> +
>>> + /* 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.
>>> +
>>> + 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 d631beb17c8..30635ab1754 100644
>>> --- a/gdb/testsuite/gdb.mi/mi-reverse.exp
>>> +++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
>>> @@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
>>> --- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
>>> +++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
>>> @@ -44,6 +44,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 00000000000..42e41b5a2e0
>>> --- /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-2022 Free Software Foundation, Inc.
>> copyright year should be 2023.
>>> +
>>> + 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 00000000000..7880de10ffc
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
>>> @@ -0,0 +1,108 @@
>>> +# Copyright 2008-2022 Free Software Foundation, Inc.
> Fixed copyright so it reads 2008-2023. Fixed in finish-reverse-
> next.exp and finish-reverse-next.c.
>
>>> +
>>> +# 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.
>> While testing locally, I ran into a bug with reverse finish at the
>> epilogue of the function, that your patch also fixed. It would be
>> nice
>> if the test extended that. And since the bug was that GDB stopped
>> responding and even ctrl+c did nothing, I would suggest adding it as
>> the
>> last test.
> Discussed this additional bug in earlier emails. Waiting to hear if
> the new test I sent reliably exposes the gdb hang that Bruno reported.
> If it does, I will add the new test to the new test case before posting
> the updated patch set. Per the discussions, I have not been able to
> reproduce the issue on my X86 or PowerPC machines.
I just tried reproducing it again on my end and failed, even my original
test. It must have been a fluke, maybe I forgot to compile something
after pulling from upstream. Thanks for all the thought you put into
it, though!
>
>>> +
>>> +# 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 FUNCTION_test [gdb_get_line_number "CALL FUNCTION" $srcfile]
>>> +gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at
>>> .*" \his
>>> + "set breakpoint on function1 call to stepi into function"
>> There is a proc in lib/gdb.exp called gdb_breakpoint which
>> couldsimplify
>> this gdb_test to
>>
>> gdb_breakpoint $srcfile:$FUNCTION_test temporary
>>
>> And would remove the need for the delete_breakpoints call later.
>>
> OK, made the change in both tests. Made the same change in the PowerPC
> patch that adds additional tests.
>
>
>>> +
>>> +# Continue to break point at function1 call in main.
>>> +gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*"
>>> \
>>> + "stopped at function1 entry point instruction to stepi into
>>> function"
>> You can use gdb_continue_to_breakpoint here instead.
> OK, made the change in both tests. Made the same change in the PowerPC
> patch that adds additional tests.
>
>>> +
>>> +# stepi until we see "{" indicating we entered function1
>>> +cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
>>> +
>>> +delete_breakpoints
>>> +
>>> +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 functiojust dont get it confused with maftn1 in main.
>>> +gdb_test "break $srcfile:$FUNCTION_test" "Breakpoint $decimal at
>>> .*" \
>>> + "set breakpoint on function1 call to step into body of
>>> function"
>>> +
>>> +# Continue to break point at function1 call in main.
>>> +gdb_test "continue" "Breakpoint $decimal,.*function1 \\(a, b\\).*"
>>> \
>>> + "stopped at function1 entry point instruction to step to body
>>> of function"
>>> +
>>> +delete_breakpoints
>>> +
>>> +# 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/finish-reverse.exp
>>> b/gdb/testsuite/gdb.reverse/finish-reverse.exp
>>> index 01ba309420c..a05cb81892a 100644
>>> --- a/gdb/testsuite/gdb.reverse/finish-reverse.exp
>>> +++ b/gdb/testsuite/gdb.reverse/finish-reverse.exp
>>> @@ -16,6 +16,11 @@
>>> # This file is part of the GDB testsuite. It tests 'finish' with
>>> # reverse debugging.
>>>
>>> +# This test verifies the fix for gdb bugzilla:
>>> +
>>> +#
>>> https://sourceware.org/bugzilla/show_bug.cgi?id=29927
>>>
>>> +
>>> +
>> Is this comment a left over from an earlier version?
>>
>> I actually wonder if the whole new test is needed, or if you can
>> just
>> add a couple of new tests to finish-reverse.exp; is there any reason
>> you
>> went with the new test instead
> Yes, it is left over. Initially I just added an additional test to
> finish-reverse.exp for the PowerPC fix. But as work progressed, I kept
> adding more tests for PowerPC then for X86. I felt that it was better
> to have a new test file that was tied to the Bugzilla. The existing
> test file has a different focus from the new tests. The bugzilla
> change didn't get removed from finish-reverse.exp when the tests were
> moved to the new file. We can combine the tests again if that is
> preferable? My preference would be to have separate test files.
> Please let me know if you would prefer a single file and I will merge
> them before re-posting the patches.
Oh, ok, the separation makes sense now. I looked only at this patch
first and asked before looking at patch 2. I'd say its fine, no need to
merge them.
>
>>> if ![supports_reverse] {
>>> return
>>> }
>>> diff --git a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
>>> b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
>>> index 1ca7c2ce559..eb03051625a 100644
>>> --- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
>>> +++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
>>> @@ -56,7 +56,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 ad637899e5b..1928cdda217 100644
>>> --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
>>> +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
>>> @@ -39,39 +39,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"
>>>
>>> @@ -91,20 +58,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" \
>>> +cmd_until "stepi" "apply\.2" "indirect_thunk" "stepi into call
>>> thunk"
>>> +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" \
>>> +cmd_until "stepi" "(inc|$pic_thunk_re)" "return_thunk" "stepi into
>>> return thunk"
>>> +cmd_until "stepi" "return_thunk" "apply" \
>>> "stepi out of return thunk back into apply"
>>>
>>> -step_until "reverse-stepi" "apply" "return_thunk" \
>>> +cmd_until "reverse-stepi" "apply" "return_thunk" \
>>> "reverse-stepi into return thunk"
>>> -step_until "reverse-stepi" "return_thunk" "inc" \
>>> +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"
>>> \
>>> +cmd_until "reverse-stepi" "(inc|$pic_thunk_re)" "indirect_thunk" \
>>> "reverse-stepi into call thunk"
>>> -step_until "reverse-stepi" "indirect_thunk" "apply" \
>>> +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 0c2d7537cd6..777aec94ac1 100644
>>> --- a/gdb/testsuite/gdb.reverse/until-precsave.exp
>>> +++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
>>> @@ -142,7 +142,7 @@ gdb_test "advance marker2" \
>>> # Finish out to main scope (backward)
>>>
>>> gdb_test "finish" \
>>> - " in main .*$srcfile:$bp_location20.*" \
>>> + "main .*$srcfile:$bp_location20.*" \
>> This change doesn't seem connected to anything in this patch, is
>> this
>> just a cosmetic change or was there some problem?
>>> "reverse-finish from marker2"
>>>
> The output changes due to the functional changes in infrun.c. Instead
> of stepping back one instruction i.e. ecs->event_thread-
>> stepping_over_breakpoint = 1 we step back using a range. Apparently
> this causes the gdb output message to change.
>
> Without the patch the output looks like:
> Run back to call of #0 marker2 (a=43) at.../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/ur1.c:30
>
> 0x0000000010000838 in main (argc=1, argv=0x7fffffffcc58, envp=0x7fffffffcc68) at /.../gdb/testsuite/gdb.reverse/until-reverse.c:48^
>
> With the patch the output looks like:
>
> Run back to call of #0 marker2 (a=43) at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/ur1.c:30
>
> main (argc=1, argv=0x7fffffffcc58, envp=0x7fffffffcc68) at .../binutils-gdb-finish-precsave/gdb/testsuite/gdb.reverse/until-reverse.c:48
>
> Basically, you lose the hex value and "in" with the patch applied.
> This is true in the until-reverse.exp tes, below, as well. The output
> change was mentioned in the commit message as well.
Oh right, I should have checked the output before asking. Thank you for
explaining!
--
Cheers,
Bruno
>
>>> # 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 23fc881dbf2..3a05953329f 100644
>>> --- a/gdb/testsuite/gdb.reverse/until-reverse.exp
>>> +++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
>>> @@ -113,7 +113,7 @@ gdb_test "advance marker2" \
>>> # Finish out to main scope (backward)
>>>
>>> gdb_test "finish" \
>>> - " in main .*$srcfile:$bp_location20.*" \
>>> + "main .*$srcfile:$bp_location20.*" \
>> same here.
> Yup, see above.
>
>>> "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 c41d4698d66..25f42eb5510 100644
>>> --- a/gdb/testsuite/lib/gdb.exp
>>> +++ b/gdb/testsuite/lib/gdb.exp
>>> @@ -9301,6 +9301,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 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.
>>> #
>>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 0/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-16 12:31 ` Bruno Larsen
@ 2023-01-16 16:37 ` Carl Love
2023-01-16 16:37 ` [PATCH 1/2 " Carl Love
2023-01-16 16:37 ` [PATCH 2/2 version 2] " Carl Love
2 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-16 16:37 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
GDB maintainers:
Version 2: Addressed various comments from Bruno Larsen.
This patch set fixes a couple of issues with the gdb.reverse tests
finish-precsave.exp and finish-reverse.exp.
The first issue is when doing a reverse-finish command from a function,
gdb should stop at the first instruction of the source code line where
the call was made. The behavior should look the same as doing a
reverse-next from the first line of the function. Currently gdb stops
at the last instruction in the caller source code line. Issuing
reverse-step or reverse-next stops at the first instruction in the same
source code line. It then requires a second reverse step or next
command to reach the previous source code line in the caller. It
should only require one reverse step or next command to reach the
previous line.
The first patch in this series fixes the above issue on X86. A number
of additional testcases require updating since the output is slightly
different or the test case no longer needs to issue the two reverse
step/next instructions. The step_until proceedure in test
gdb.reverse/step-indirect-call-thunk.exp was moved to lib/gdb.exp and
renamed cmd_until. The proceedure is used to test the reverse-finish
command when returning from the entry point of the function.
The second issue with the reverse-finish command is that on PowerPC the
reverse-finish doesn't stop at the function call. The issue is PowerPC
uses two entry points. PowerPC calls the two entry points the local
entry point (LEP) and the global entry point (GEP). The LEP is
normally used when calling a function. The GEP is used when the table
of contents (TOC) needs to be setup before continuing execution at the
LEP. GDB is not handling the two entry points correctly. The second
patch fixes the reverse-finish behavior on PowerPC. On systems that
don't use two entry points the LEP and the GEP are the same.
A new testcase is added to verify the reverse-finish command works
correctly for X86 when returning from the body of a function and from
the entry point. Note, the finish_backward function must handle the
two scenarios slightly differently.
The new testcase is expanded in the PPC patch to add tests for the two
scenarios for a function called via the GEP. The initial set of tests
added in the X86 patch take care of the function being called via the
LEP on PowerPC.
The patches have been tested on PowerPC and X86 with no new
regressions.
Please let me know if the patches are acceptable for mainline. Thanks.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-16 12:31 ` Bruno Larsen
2023-01-16 16:37 ` [PATCH 0/2 version 2] " Carl Love
@ 2023-01-16 16:37 ` Carl Love
2023-01-17 12:35 ` Bruno Larsen
2023-01-16 16:37 ` [PATCH 2/2 version 2] " Carl Love
2 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-16 16:37 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
GDB maintainers:
Version 2: Addressed various comments from Bruno Larsen.
This patch fixes the issues with the reverse-finish command on X86.
The reverse-finish command now correctly stops at the first instruction
in the source code line of the caller. It now only requires a single
reverse-step or reverse-next instruction to get back to the previous
source code line.
It also adds a new testcase, gdb.reverse/finish-reverse-next.exp, and
updates several existing testcases.
Version 2 patch changes have been re-verified on PowerPC and X86 with
no regressions.
Please let me know if you have any comments on the patch. Thanks.
Carl
--------------------------------------------------------
X86: reverse-finish fix
PR record/29927 - reverse-finish requires two reverse next instructions to
reach previous source line
Currently on X86, when executing the finish command in reverse, gdb does a
single step from the first instruction in the callee to get back to the
caller. GDB stops on the last instruction in the source code line where
the call was made. When stopped at the last instruction of the source code
line, a reverse next or step command will stop at the first instruction
of the same source code line thus requiring two step/next commands to
reach the previous source code line. It should only require one step/next
command to reach the previous source code line.
By contrast, a reverse next or step command from the first line in a
function stops at the first instruction in the source code line where the
call was made.
This patch fixes the reverse finish command so it will stop at the first
instruction of the source line where the function call was made. The
behavior on X86 for the reverse-finish command now matches doing a
reverse-next from the beginning of the function.
The proceed_to_finish flag in struct thread_control_state is no longer
used. This patch removes the declaration, initialization and setting of
the flag.
This patch requires a number of regression tests to be updated. Test
gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
previous line. The gdb output for tests gdb.reverse/until-precsave.exp
and gdb.reverse/until-reverse.exp changed slightly. The expected result in
tests gdb.reverse/amd64-failcall-reverse.exp and
gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
result.
This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
reverse-finish command when returning from the entry point and from the
body of the function.
The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
was moved to lib/gdb.exp and renamed cmd_until.
The patch has been tested on X86 and PowerPC to verify no additional
regression failures occured.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29927
---
gdb/gdbthread.h | 4 -
gdb/infcall.c | 3 -
gdb/infcmd.c | 32 +++---
gdb/infrun.c | 40 +++----
gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
.../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
.../gdb.reverse/finish-reverse-next.c | 48 ++++++++
.../gdb.reverse/finish-reverse-next.exp | 104 ++++++++++++++++++
.../gdb.reverse/singlejmp-reverse.exp | 5 +-
.../gdb.reverse/step-indirect-call-thunk.exp | 49 ++-------
gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 33 ++++++
13 files changed, 230 insertions(+), 106 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1721,19 +1721,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
@@ -1743,16 +1734,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
@@ -1778,9 +1775,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 181d961d80d..86e5ef1ed12 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 d631beb17c8..30635ab1754 100644
--- a/gdb/testsuite/gdb.mi/mi-reverse.exp
+++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
@@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
--- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
@@ -44,6 +44,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 00000000000..f90ecbb93cb
--- /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 00000000000..63305c109e1
--- /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 1ca7c2ce559..eb03051625a 100644
--- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
@@ -56,7 +56,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 ad637899e5b..b82e5663bd5 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -39,39 +39,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"
@@ -91,20 +58,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 0c2d7537cd6..777aec94ac1 100644
--- a/gdb/testsuite/gdb.reverse/until-precsave.exp
+++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
@@ -142,7 +142,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 23fc881dbf2..3a05953329f 100644
--- a/gdb/testsuite/gdb.reverse/until-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
@@ -113,7 +113,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 c41d4698d66..234c21a04ea 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9301,6 +9301,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.
#
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-16 12:31 ` Bruno Larsen
2023-01-16 16:37 ` [PATCH 0/2 version 2] " Carl Love
2023-01-16 16:37 ` [PATCH 1/2 " Carl Love
@ 2023-01-16 16:37 ` Carl Love
2023-01-17 14:29 ` Bruno Larsen
2 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-16 16:37 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
GDB maintainers:
Version 2: Addressed various comments from Bruno Larsen.
This patch fixes the issues with the reverse-finish command on
PowerPC. The reverse-finish command now correctly stops at the first
instruction in the source code line of the caller.
The patch adds tests for calling a function via the GEP to the new test
gdb.reverse/finish-reverse-next.exp.
Version 2 patch changes have been re-verified on PowerPC and X86 with
no regressions.
Please let me know if you have any comments on the patch. Thanks.
Carl
---------------------------------------------------------------
PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
PR record/29927 - reverse-finish requires two reverse next instructions to
reach previous source line
PowerPC uses two entry points called the local entry point (LEP) and the
global entry point (GEP). Normally the LEP is used when calling a
function. However, if the table of contents (TOC) value in register 2 is
not valid the GEP is called to setup the TOC before execution continues at
the LEP. When executing in reverse, the function finish_backward sets the
break point at the alternate entry point (GEP). However if the forward
execution enters via the normal entry point (LEP), the reverse execution
never sees the break point at the GEP of the function. Reverse execution
continues until the next break point is encountered or the end of the
recorded log is reached causing gdb to stop at the wrong place.
This patch adds a new address to struct execution_control_state to hold the
address of the alternate function start address, known as the GEP on
PowerPC. The finish_backwards function is updated. If the stopping point
is between the two entry points (the LEP and GEP on PowerPC), the stepping
range is set to execute back to the alternate entry point (GEP on PowerPC).
Otherwise, a breakpoint is inserted at the normal entry point (LEP on
PowerPC).
Function process_event_stop_test checks uses a stepping range to stop
execution in the caller at the first instruction of the source code line.
Note, on systems that only support one entry point, the address of the two
entry points are the same.
Test finish-reverse-next.exp is updated to include tests for the
reverse-finish command when the function is entered via the normal entry
point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
The patch has been tested on X86 and PowerPC with no regressions.
---
gdb/infcmd.c | 40 +++++---
gdb/infrun.c | 16 +++-
.../gdb.reverse/finish-reverse-next.c | 41 +++++++-
.../gdb.reverse/finish-reverse-next.exp | 96 ++++++++++++++++---
4 files changed, 161 insertions(+), 32 deletions(-)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 9c42efeae8d..6aaed34b1b6 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1722,22 +1722,25 @@ finish_backward (struct finish_command_fsm *sm)
sal = find_pc_line (func_addr, 0);
frame_info_ptr frame = get_selected_frame (nullptr);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR alt_entry_point = sal.pc;
+ CORE_ADDR entry_point = alt_entry_point;
- if (sal.pc != pc)
+ if (gdbarch_skip_entrypoint_p (gdbarch))
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
-
- /* Set a step-resume at the function's entry point. Once that's
- hit, we'll do one more step backwards. */
- symtab_and_line sr_sal;
- sr_sal.pc = sal.pc;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ /* Some architectures, like PowerPC use local and global entry points.
+ There is only one Entry Point (GEP = LEP) for other architectures.
+ The GEP is an alternate entry point. The LEP is the normal entry
+ point. The value of entry_point was initialized to the alternate
+ entry point (GEP). It will be adjusted if the normal entry point
+ (LEP) was used. */
+ entry_point = gdbarch_skip_entrypoint (gdbarch, entry_point);
}
- else
+
+ if (alt_entry_point <= pc && pc <= entry_point)
{
- /* We are exactly at the function entry point. Note that this
+ /* We are exactly at the function entry point, or between the entry
+ point on platforms that have two (like PowerPC). Note that this
can only happen at frame #0.
When setting a step range, need to call set_step_info
@@ -1746,8 +1749,17 @@ finish_backward (struct finish_command_fsm *sm)
/* 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;
+ tp->control.step_range_start = alt_entry_point;
+ tp->control.step_range_end = entry_point;
+ }
+ else
+ {
+ symtab_and_line sr_sal;
+ /* Set a step-resume at the function's entry point. */
+ sr_sal.pc = entry_point;
+ 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);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 86e5ef1ed12..b69f84824a3 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1868,6 +1868,7 @@ struct execution_control_state
struct target_waitstatus ws;
int stop_func_filled_in = 0;
+ CORE_ADDR stop_func_alt_start = 0;
CORE_ADDR stop_func_start = 0;
CORE_ADDR stop_func_end = 0;
const char *stop_func_name = nullptr;
@@ -4663,6 +4664,12 @@ fill_in_stop_func (struct gdbarch *gdbarch,
&block);
ecs->stop_func_name = gsi == nullptr ? nullptr : gsi->print_name ();
+ /* PowerPC functions have a Local Entry Point and a Global Entry
+ Point. There is only one Entry Point (GEP = LEP) for other
+ architectures. Save the alternate entry point address (GEP) for
+ use later. */
+ ecs->stop_func_alt_start = ecs->stop_func_start;
+
/* The call to find_pc_partial_function, above, will set
stop_func_start and stop_func_end to the start and end
of the range containing the stop pc. If this range
@@ -4679,6 +4686,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
+= gdbarch_deprecated_function_start_offset (gdbarch);
if (gdbarch_skip_entrypoint_p (gdbarch))
+ /* The PowerPC architecture uses two entry points. Stop at the
+ regular entry point (LEP on PowerPC) initially. Will setup a
+ breakpoint for the alternate entry point (GEP) later. */
ecs->stop_func_start
= gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
}
@@ -6754,7 +6764,7 @@ process_event_stop_test (struct execution_control_state *ecs)
/* 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_start = ecs->stop_func_alt_start;
tp->control.step_range_end = ecs->stop_func_start;
keep_going (ecs);
return;
@@ -6891,8 +6901,10 @@ process_event_stop_test (struct execution_control_state *ecs)
(unless it's the function entry point, in which case
keep going back to the call point). */
CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
+
if (stop_pc == ecs->event_thread->control.step_range_start
- && stop_pc != ecs->stop_func_start
+ && (stop_pc < ecs->stop_func_alt_start
+ || stop_pc > ecs->stop_func_start)
&& execution_direction == EXEC_REVERSE)
end_stepping_range (ecs);
else
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
index f90ecbb93cb..6bac7c6117a 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
@@ -1,4 +1,4 @@
-/* This testcase is part of GDB, the GNU debugger.
+j/* This testcase is part of GDB, the GNU debugger.
Copyright 2012-2023 Free Software Foundation, Inc.
@@ -24,11 +24,37 @@
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 alternat entry point is called
+ the global entry point (GEP). The GEP is only used if the table of
+ contents (TOC) value stored in register r2 needs to be setup prior to
+ execution starting at the LEP. 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. */
int
function1 (int a, int b) // FUNCTION1
{
+ /* The assembly code for this function when compiled for PowerPC is as
+ follows:
+
+ 0000000010000758 <function1>:
+ 10000758: 02 10 40 3c lis r2,4098 <- GEP
+ 1000075c: 00 7f 42 38 addi r2,r2,32512
+ 10000760: a6 02 08 7c mflr r0 <- LEP
+ 10000764: 10 00 01 f8 std r0,16(r1)
+ ....
+
+ When the function is called on PowerPC with function1 (a, b) the call
+ enters at the Local Entry Point (LEP). When the function is called via
+ a function pointer, the Global Entry Point (GEP) for function1 is used.
+ The GEP sets up register 2 before reaching the LEP.
+ */
int ret = 0;
ret = a + b;
@@ -39,10 +65,19 @@ int
main(int argc, char* argv[])
{
int a, b;
+ int (*funp) (int, int) = &function1;
+
+ /* Call function via Local Entry Point (LEP). */
a = 1;
b = 5;
- function1 (a, b); // CALL FUNCTION
+ function1 (a, b); // CALL VIA LEP
+
+ /* Call function via Global Entry Point (GEP). */
+ a = 10;
+ b = 50;
+
+ funp (a, b); // CALL VIA GEP
return 0;
}
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
index 63305c109e1..240b7214ed2 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -31,6 +31,16 @@
# 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 alternat 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
}
@@ -50,30 +60,30 @@ if [supports_process_record] {
}
-### TEST 1: reverse finish from the entry point instruction in
-### function1.
+### 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_FUNCTION [gdb_get_line_number "CALL FUNCTION" $srcfile]
-gdb_breakpoint $srcfile:$bp_FUNCTION temporary
+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_FUNCTION\r\n.*"
+ ".*$srcfile:$bp_LEP_test\r\n.*"
# stepi until we see "{" indicating we entered function1
-repeat_cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
+repeat_cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1 call"
-gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
- "reverse-finish function1 "
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse-finish function1 LEP call from LEP "
# 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"
+gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call from LEP"
# Clear the recorded log.
gdb_test "record stop" "Process record is stopped.*" \
@@ -84,21 +94,81 @@ 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
+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_FUNCTION\r\n.*"
+ ".*$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"
-gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
- "reverse-finish function1 call from function body"
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse-finish function1 LEP 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"
+
+# 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 function" \
+ ".*$srcfile:$bp_GEP_test\r\n.*"
+
+# stepi until we see "{" indicating we entered function.
+cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call"
+
+gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
+ "function1 GEP call call from GEP"
+
+# 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 = 50;.*" "reverse next at b = 50, call from GEP"
+
+# 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 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 function" \
+ ".*$srcfile:$bp_GEP_test\r\n.*"
+
+# Step into body of funp, called via GEP.
+gdb_test "step" ".*int ret = 0;.*" "step test 2"
+
+gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
+ "reverse-finish function1 GEP 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. 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 = 50;.*" \
+ "reverse next at b = 50 from function body"
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-16 16:37 ` [PATCH 1/2 " Carl Love
@ 2023-01-17 12:35 ` Bruno Larsen
2023-01-20 0:03 ` [PATCH 1/2 version 3] " Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-17 12:35 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 16/01/2023 17:37, Carl Love wrote:
> GDB maintainers:
>
> Version 2: Addressed various comments from Bruno Larsen.
>
> This patch fixes the issues with the reverse-finish command on X86.
> The reverse-finish command now correctly stops at the first instruction
> in the source code line of the caller. It now only requires a single
> reverse-step or reverse-next instruction to get back to the previous
> source code line.
>
> It also adds a new testcase, gdb.reverse/finish-reverse-next.exp, and
> updates several existing testcases.
>
> Version 2 patch changes have been re-verified on PowerPC and X86 with
> no regressions.
>
> Please let me know if you have any comments on the patch. Thanks.
>
> Carl
>
> --------------------------------------------------------
> X86: reverse-finish fix
>
> PR record/29927 - reverse-finish requires two reverse next instructions to
> reach previous source line
>
> Currently on X86, when executing the finish command in reverse, gdb does a
> single step from the first instruction in the callee to get back to the
> caller. GDB stops on the last instruction in the source code line where
> the call was made. When stopped at the last instruction of the source code
> line, a reverse next or step command will stop at the first instruction
> of the same source code line thus requiring two step/next commands to
> reach the previous source code line. It should only require one step/next
> command to reach the previous source code line.
>
> By contrast, a reverse next or step command from the first line in a
> function stops at the first instruction in the source code line where the
> call was made.
>
> This patch fixes the reverse finish command so it will stop at the first
> instruction of the source line where the function call was made. The
> behavior on X86 for the reverse-finish command now matches doing a
> reverse-next from the beginning of the function.
>
> The proceed_to_finish flag in struct thread_control_state is no longer
> used. This patch removes the declaration, initialization and setting of
> the flag.
>
> This patch requires a number of regression tests to be updated. Test
> gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
> previous line. The gdb output for tests gdb.reverse/until-precsave.exp
> and gdb.reverse/until-reverse.exp changed slightly. The expected result in
> tests gdb.reverse/amd64-failcall-reverse.exp and
> gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
> result.
>
> This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
> reverse-finish command when returning from the entry point and from the
> body of the function.
>
> The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
> was moved to lib/gdb.exp and renamed cmd_until.
>
> The patch has been tested on X86 and PowerPC to verify no additional
> regression failures occured.
>
> Bug:https://sourceware.org/bugzilla/show_bug.cgi?id=29927
> ---
Changes look good now and I also dont see any regressions.
Reviewed-By: Bruno Larsen <blarsen@redhat.com>
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-16 16:37 ` [PATCH 2/2 version 2] " Carl Love
@ 2023-01-17 14:29 ` Bruno Larsen
2023-01-17 16:36 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-17 14:29 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 16/01/2023 17:37, Carl Love wrote:
> GDB maintainers:
>
> Version 2: Addressed various comments from Bruno Larsen.
>
> This patch fixes the issues with the reverse-finish command on
> PowerPC. The reverse-finish command now correctly stops at the first
> instruction in the source code line of the caller.
>
> The patch adds tests for calling a function via the GEP to the new test
> gdb.reverse/finish-reverse-next.exp.
>
> Version 2 patch changes have been re-verified on PowerPC and X86 with
> no regressions.
>
> Please let me know if you have any comments on the patch. Thanks.
>
> Carl
>
> ---------------------------------------------------------------
> PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
>
> PR record/29927 - reverse-finish requires two reverse next instructions to
> reach previous source line
>
> PowerPC uses two entry points called the local entry point (LEP) and the
> global entry point (GEP). Normally the LEP is used when calling a
> function. However, if the table of contents (TOC) value in register 2 is
> not valid the GEP is called to setup the TOC before execution continues at
> the LEP. When executing in reverse, the function finish_backward sets the
> break point at the alternate entry point (GEP). However if the forward
> execution enters via the normal entry point (LEP), the reverse execution
> never sees the break point at the GEP of the function. Reverse execution
> continues until the next break point is encountered or the end of the
> recorded log is reached causing gdb to stop at the wrong place.
>
> This patch adds a new address to struct execution_control_state to hold the
> address of the alternate function start address, known as the GEP on
> PowerPC. The finish_backwards function is updated. If the stopping point
> is between the two entry points (the LEP and GEP on PowerPC), the stepping
> range is set to execute back to the alternate entry point (GEP on PowerPC).
> Otherwise, a breakpoint is inserted at the normal entry point (LEP on
> PowerPC).
>
> Function process_event_stop_test checks uses a stepping range to stop
> execution in the caller at the first instruction of the source code line.
> Note, on systems that only support one entry point, the address of the two
> entry points are the same.
>
> Test finish-reverse-next.exp is updated to include tests for the
> reverse-finish command when the function is entered via the normal entry
> point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
>
> The patch has been tested on X86 and PowerPC with no regressions.
I will reiterate that I don't know much about PPC, so the best I can do
is check for style and tests, but apart from a few minor nits inlined,
it looks ok
Tested-By: Bruno Larsen <blarsen@redhat.com>
> ---
> gdb/infcmd.c | 40 +++++---
> gdb/infrun.c | 16 +++-
> .../gdb.reverse/finish-reverse-next.c | 41 +++++++-
> .../gdb.reverse/finish-reverse-next.exp | 96 ++++++++++++++++---
> 4 files changed, 161 insertions(+), 32 deletions(-)
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 9c42efeae8d..6aaed34b1b6 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1722,22 +1722,25 @@ finish_backward (struct finish_command_fsm *sm)
> sal = find_pc_line (func_addr, 0);
>
> frame_info_ptr frame = get_selected_frame (nullptr);
> + struct gdbarch *gdbarch = get_frame_arch (frame);
> + CORE_ADDR alt_entry_point = sal.pc;
> + CORE_ADDR entry_point = alt_entry_point;
>
> - if (sal.pc != pc)
> + if (gdbarch_skip_entrypoint_p (gdbarch))
> {
> - struct gdbarch *gdbarch = get_frame_arch (frame);
> -
> - /* Set a step-resume at the function's entry point. Once that's
> - hit, we'll do one more step backwards. */
> - symtab_and_line sr_sal;
> - sr_sal.pc = sal.pc;
> - sr_sal.pspace = get_frame_program_space (frame);
> - insert_step_resume_breakpoint_at_sal (gdbarch,
> - sr_sal, null_frame_id);
> + /* Some architectures, like PowerPC use local and global entry points.
> + There is only one Entry Point (GEP = LEP) for other architectures.
> + The GEP is an alternate entry point. The LEP is the normal entry
> + point. The value of entry_point was initialized to the alternate
> + entry point (GEP). It will be adjusted if the normal entry point
> + (LEP) was used. */
> + entry_point = gdbarch_skip_entrypoint (gdbarch, entry_point);
> }
> - else
> +
> + if (alt_entry_point <= pc && pc <= entry_point)
> {
> - /* We are exactly at the function entry point. Note that this
> + /* We are exactly at the function entry point, or between the entry
> + point on platforms that have two (like PowerPC). Note that this
> can only happen at frame #0.
>
> When setting a step range, need to call set_step_info
> @@ -1746,8 +1749,17 @@ finish_backward (struct finish_command_fsm *sm)
>
> /* 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;
> + tp->control.step_range_start = alt_entry_point;
> + tp->control.step_range_end = entry_point;
> + }
> + else
> + {
> + symtab_and_line sr_sal;
> + /* Set a step-resume at the function's entry point. */
> + sr_sal.pc = entry_point;
> + 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);
> }
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 86e5ef1ed12..b69f84824a3 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -1868,6 +1868,7 @@ struct execution_control_state
>
> struct target_waitstatus ws;
> int stop_func_filled_in = 0;
> + CORE_ADDR stop_func_alt_start = 0;
> CORE_ADDR stop_func_start = 0;
> CORE_ADDR stop_func_end = 0;
> const char *stop_func_name = nullptr;
> @@ -4663,6 +4664,12 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> &block);
> ecs->stop_func_name = gsi == nullptr ? nullptr : gsi->print_name ();
>
> + /* PowerPC functions have a Local Entry Point and a Global Entry
> + Point. There is only one Entry Point (GEP = LEP) for other
> + architectures. Save the alternate entry point address (GEP) for
> + use later. */
> + ecs->stop_func_alt_start = ecs->stop_func_start;
> +
> /* The call to find_pc_partial_function, above, will set
> stop_func_start and stop_func_end to the start and end
> of the range containing the stop pc. If this range
> @@ -4679,6 +4686,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> += gdbarch_deprecated_function_start_offset (gdbarch);
>
> if (gdbarch_skip_entrypoint_p (gdbarch))
> + /* The PowerPC architecture uses two entry points. Stop at the
> + regular entry point (LEP on PowerPC) initially. Will setup a
> + breakpoint for the alternate entry point (GEP) later. */
> ecs->stop_func_start
> = gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
> }
> @@ -6754,7 +6764,7 @@ process_event_stop_test (struct execution_control_state *ecs)
>
> /* 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_start = ecs->stop_func_alt_start;
> tp->control.step_range_end = ecs->stop_func_start;
> keep_going (ecs);
> return;
> @@ -6891,8 +6901,10 @@ process_event_stop_test (struct execution_control_state *ecs)
> (unless it's the function entry point, in which case
> keep going back to the call point). */
> CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> +
> if (stop_pc == ecs->event_thread->control.step_range_start
> - && stop_pc != ecs->stop_func_start
> + && (stop_pc < ecs->stop_func_alt_start
> + || stop_pc > ecs->stop_func_start)
> && execution_direction == EXEC_REVERSE)
> end_stepping_range (ecs);
> else
> diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> index f90ecbb93cb..6bac7c6117a 100644
> --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> @@ -1,4 +1,4 @@
> -/* This testcase is part of GDB, the GNU debugger.
> +j/* This testcase is part of GDB, the GNU debugger.
Accidental change that breaks the test here.
>
> Copyright 2012-2023 Free Software Foundation, Inc.
>
> @@ -24,11 +24,37 @@
> 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 alternat entry point is called
> + the global entry point (GEP). The GEP is only used if the table of
> + contents (TOC) value stored in register r2 needs to be setup prior to
> + execution starting at the LEP. 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. */
>
> int
> function1 (int a, int b) // FUNCTION1
> {
> + /* The assembly code for this function when compiled for PowerPC is as
> + follows:
> +
> + 0000000010000758 <function1>:
> + 10000758: 02 10 40 3c lis r2,4098 <- GEP
> + 1000075c: 00 7f 42 38 addi r2,r2,32512
> + 10000760: a6 02 08 7c mflr r0 <- LEP
> + 10000764: 10 00 01 f8 std r0,16(r1)
> + ....
> +
> + When the function is called on PowerPC with function1 (a, b) the call
> + enters at the Local Entry Point (LEP). When the function is called via
> + a function pointer, the Global Entry Point (GEP) for function1 is used.
> + The GEP sets up register 2 before reaching the LEP.
> + */
> int ret = 0;
>
> ret = a + b;
> @@ -39,10 +65,19 @@ int
> main(int argc, char* argv[])
> {
> int a, b;
> + int (*funp) (int, int) = &function1;
> +
> + /* Call function via Local Entry Point (LEP). */
>
> a = 1;
> b = 5;
>
> - function1 (a, b); // CALL FUNCTION
> + function1 (a, b); // CALL VIA LEP
> +
> + /* Call function via Global Entry Point (GEP). */
> + a = 10;
> + b = 50;
> +
> + funp (a, b); // CALL VIA GEP
> return 0;
> }
> diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> index 63305c109e1..240b7214ed2 100644
> --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> @@ -31,6 +31,16 @@
> # 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 alternat 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
> }
> @@ -50,30 +60,30 @@ if [supports_process_record] {
> }
>
>
> -### TEST 1: reverse finish from the entry point instruction in
> -### function1.
> +### 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_FUNCTION [gdb_get_line_number "CALL FUNCTION" $srcfile]
> -gdb_breakpoint $srcfile:$bp_FUNCTION temporary
> +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_FUNCTION\r\n.*"
> + ".*$srcfile:$bp_LEP_test\r\n.*"
>
> # stepi until we see "{" indicating we entered function1
> -repeat_cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
> +repeat_cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1 call"
>
> -gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
> - "reverse-finish function1 "
> +gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
> + "reverse-finish function1 LEP call from LEP "
>
> # 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"
> +gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call from LEP"
>
> # Clear the recorded log.
> gdb_test "record stop" "Process record is stopped.*" \
> @@ -84,21 +94,81 @@ 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
> +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_FUNCTION\r\n.*"
> + ".*$srcfile:$bp_LEP_test\r\n.*"
duplicate test name here.
>
> # 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"
> +gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
> + "reverse-finish function1 LEP 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"
> +
> +# 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 function" \
> + ".*$srcfile:$bp_GEP_test\r\n.*"
Duplicated test name here too.
> +
> +# stepi until we see "{" indicating we entered function.
> +cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call"
s/cmd_until/repeat_cmd_until
you probably missed because of the test compilation failed.
> +
> +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> + "function1 GEP call call from GEP"
> +
> +# 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 = 50;.*" "reverse next at b = 50, call from GEP"
> +
> +# 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 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 function" \
> + ".*$srcfile:$bp_GEP_test\r\n.*"
> +
> +# Step into body of funp, called via GEP.
> +gdb_test "step" ".*int ret = 0;.*" "step test 2"
> +
> +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> + "reverse-finish function1 GEP 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. 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 = 50;.*" \
> + "reverse next at b = 50 from function body"
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 14:29 ` Bruno Larsen
@ 2023-01-17 16:36 ` Carl Love
2023-01-17 16:55 ` Tom de Vries
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-17 16:36 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Bruno:
On Tue, 2023-01-17 at 15:29 +0100, Bruno Larsen wrote:
> On 16/01/2023 17:37, Carl Love wrote:
> > GDB maintainers:
> >
> > Version 2: Addressed various comments from Bruno Larsen.
> >
> > This patch fixes the issues with the reverse-finish command on
> > PowerPC. The reverse-finish command now correctly stops at the
> > first
> > instruction in the source code line of the caller.
> >
> > The patch adds tests for calling a function via the GEP to the new
> > test
> > gdb.reverse/finish-reverse-next.exp.
> >
> > Version 2 patch changes have been re-verified on PowerPC and X86
> > with
> > no regressions.
> >
> > Please let me know if you have any comments on the patch. Thanks.
> >
> > Carl
> >
> > ---------------------------------------------------------------
> > PowerPC: fix for gdb.reverse/finish-precsave.exp and
> > gdb.reverse/finish-reverse.exp
> >
> > PR record/29927 - reverse-finish requires two reverse next
> > instructions to
> > reach previous source line
> >
> > PowerPC uses two entry points called the local entry point (LEP)
> > and the
> > global entry point (GEP). Normally the LEP is used when calling a
> > function. However, if the table of contents (TOC) value in
> > register 2 is
> > not valid the GEP is called to setup the TOC before execution
> > continues at
> > the LEP. When executing in reverse, the function finish_backward
> > sets the
> > break point at the alternate entry point (GEP). However if the
> > forward
> > execution enters via the normal entry point (LEP), the reverse
> > execution
> > never sees the break point at the GEP of the function. Reverse
> > execution
> > continues until the next break point is encountered or the end of
> > the
> > recorded log is reached causing gdb to stop at the wrong place.
> >
> > This patch adds a new address to struct execution_control_state to
> > hold the
> > address of the alternate function start address, known as the GEP
> > on
> > PowerPC. The finish_backwards function is updated. If the
> > stopping point
> > is between the two entry points (the LEP and GEP on PowerPC), the
> > stepping
> > range is set to execute back to the alternate entry point (GEP on
> > PowerPC).
> > Otherwise, a breakpoint is inserted at the normal entry point (LEP
> > on
> > PowerPC).
> >
> > Function process_event_stop_test checks uses a stepping range to
> > stop
> > execution in the caller at the first instruction of the source code
> > line.
> > Note, on systems that only support one entry point, the address of
> > the two
> > entry points are the same.
> >
> > Test finish-reverse-next.exp is updated to include tests for the
> > reverse-finish command when the function is entered via the normal
> > entry
> > point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
> >
> > The patch has been tested on X86 and PowerPC with no regressions.
>
> I will reiterate that I don't know much about PPC, so the best I can
> do
> is check for style and tests, but apart from a few minor nits
> inlined,
> it looks ok
I fixed the issues, as noted below. I did a careful review of the log
files to make sure there are no remaining duplicates and that each of
the tests in both patches ran as expected.
Thanks for your help on these patches.
Carl
>
> Tested-By: Bruno Larsen <blarsen@redhat.com>
>
> > ---
> > gdb/infcmd.c | 40 +++++---
> > gdb/infrun.c | 16 +++-
> > .../gdb.reverse/finish-reverse-next.c | 41 +++++++-
> > .../gdb.reverse/finish-reverse-next.exp | 96
> > ++++++++++++++++---
> > 4 files changed, 161 insertions(+), 32 deletions(-)
> >
> > diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> > index 9c42efeae8d..6aaed34b1b6 100644
> > --- a/gdb/infcmd.c
> > +++ b/gdb/infcmd.c
> > @@ -1722,22 +1722,25 @@ finish_backward (struct finish_command_fsm
> > *sm)
> > sal = find_pc_line (func_addr, 0);
> >
> > frame_info_ptr frame = get_selected_frame (nullptr);
> > + struct gdbarch *gdbarch = get_frame_arch (frame);
> > + CORE_ADDR alt_entry_point = sal.pc;
> > + CORE_ADDR entry_point = alt_entry_point;
> >
> > - if (sal.pc != pc)
> > + if (gdbarch_skip_entrypoint_p (gdbarch))
> > {
> > - struct gdbarch *gdbarch = get_frame_arch (frame);
> > -
> > - /* Set a step-resume at the function's entry point. Once
> > that's
> > - hit, we'll do one more step backwards. */
> > - symtab_and_line sr_sal;
> > - sr_sal.pc = sal.pc;
> > - sr_sal.pspace = get_frame_program_space (frame);
> > - insert_step_resume_breakpoint_at_sal (gdbarch,
> > - sr_sal, null_frame_id);
> > + /* Some architectures, like PowerPC use local and global
> > entry points.
> > + There is only one Entry Point (GEP = LEP) for other
> > architectures.
> > + The GEP is an alternate entry point. The LEP is the normal
> > entry
> > + point. The value of entry_point was initialized to the
> > alternate
> > + entry point (GEP). It will be adjusted if the normal entry
> > point
> > + (LEP) was used. */
> > + entry_point = gdbarch_skip_entrypoint (gdbarch,
> > entry_point);
> > }
> > - else
> > +
> > + if (alt_entry_point <= pc && pc <= entry_point)
> > {
> > - /* We are exactly at the function entry point. Note that
> > this
> > + /* We are exactly at the function entry point, or between
> > the entry
> > + point on platforms that have two (like PowerPC). Note that
> > this
> > can only happen at frame #0.
> >
> > When setting a step range, need to call set_step_info
> > @@ -1746,8 +1749,17 @@ finish_backward (struct finish_command_fsm
> > *sm)
> >
> > /* 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;
> > + tp->control.step_range_start = alt_entry_point;
> > + tp->control.step_range_end = entry_point;
> > + }
> > + else
> > + {
> > + symtab_and_line sr_sal;
> > + /* Set a step-resume at the function's entry point. */
> > + sr_sal.pc = entry_point;
> > + 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);
> > }
> > diff --git a/gdb/infrun.c b/gdb/infrun.c
> > index 86e5ef1ed12..b69f84824a3 100644
> > --- a/gdb/infrun.c
> > +++ b/gdb/infrun.c
> > @@ -1868,6 +1868,7 @@ struct execution_control_state
> >
> > struct target_waitstatus ws;
> > int stop_func_filled_in = 0;
> > + CORE_ADDR stop_func_alt_start = 0;
> > CORE_ADDR stop_func_start = 0;
> > CORE_ADDR stop_func_end = 0;
> > const char *stop_func_name = nullptr;
> > @@ -4663,6 +4664,12 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> > &block);
> > ecs->stop_func_name = gsi == nullptr ? nullptr : gsi-
> > >print_name ();
> >
> > + /* PowerPC functions have a Local Entry Point and a Global
> > Entry
> > + Point. There is only one Entry Point (GEP = LEP) for other
> > + architectures. Save the alternate entry point address (GEP)
> > for
> > + use later. */
> > + ecs->stop_func_alt_start = ecs->stop_func_start;
> > +
> > /* The call to find_pc_partial_function, above, will set
> > stop_func_start and stop_func_end to the start and end
> > of the range containing the stop pc. If this range
> > @@ -4679,6 +4686,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> > += gdbarch_deprecated_function_start_offset (gdbarch);
> >
> > if (gdbarch_skip_entrypoint_p (gdbarch))
> > + /* The PowerPC architecture uses two entry points. Stop at
> > the
> > + regular entry point (LEP on PowerPC) initially. Will
> > setup a
> > + breakpoint for the alternate entry point (GEP)
> > later. */
> > ecs->stop_func_start
> > = gdbarch_skip_entrypoint (gdbarch, ecs-
> > >stop_func_start);
> > }
> > @@ -6754,7 +6764,7 @@ process_event_stop_test (struct
> > execution_control_state *ecs)
> >
> > /* 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_start = ecs->stop_func_alt_start;
> > tp->control.step_range_end = ecs->stop_func_start;
> > keep_going (ecs);
> > return;
> > @@ -6891,8 +6901,10 @@ process_event_stop_test (struct
> > execution_control_state *ecs)
> > (unless it's the function entry point, in which case
> > keep going back to the call point). */
> > CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
> > +
> > if (stop_pc == ecs->event_thread->control.step_range_start
> > - && stop_pc != ecs->stop_func_start
> > + && (stop_pc < ecs->stop_func_alt_start
> > + || stop_pc > ecs->stop_func_start)
> > && execution_direction == EXEC_REVERSE)
> > end_stepping_range (ecs);
> > else
> > diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > index f90ecbb93cb..6bac7c6117a 100644
> > --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > @@ -1,4 +1,4 @@
> > -/* This testcase is part of GDB, the GNU debugger.
> > +j/* This testcase is part of GDB, the GNU debugger.
> Accidental change that breaks the test here.
Fixed.
> >
> > Copyright 2012-2023 Free Software Foundation, Inc.
> >
> > @@ -24,11 +24,37 @@
> > 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 alternat entry
> > point is called
> > + the global entry point (GEP). The GEP is only used if the
> > table of
> > + contents (TOC) value stored in register r2 needs to be setup
> > prior to
> > + execution starting at the LEP. 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. */
> >
> > int
> > function1 (int a, int b) // FUNCTION1
> > {
> > + /* The assembly code for this function when compiled for PowerPC
> > is as
> > + follows:
> > +
> > + 0000000010000758 <function1>:
> > + 10000758: 02 10 40 3c lis r2,4098 <-
> > GEP
> > + 1000075c: 00 7f 42 38 addi r2,r2,32512
> > + 10000760: a6 02 08 7c mflr r0 <-
> > LEP
> > + 10000764: 10 00 01 f8 std r0,16(r1)
> > + ....
> > +
> > + When the function is called on PowerPC with function1 (a, b)
> > the call
> > + enters at the Local Entry Point (LEP). When the function is
> > called via
> > + a function pointer, the Global Entry Point (GEP) for
> > function1 is used.
> > + The GEP sets up register 2 before reaching the LEP.
> > + */
> > int ret = 0;
> >
> > ret = a + b;
> > @@ -39,10 +65,19 @@ int
> > main(int argc, char* argv[])
> > {
> > int a, b;
> > + int (*funp) (int, int) = &function1;
> > +
> > + /* Call function via Local Entry Point (LEP). */
> >
> > a = 1;
> > b = 5;
> >
> > - function1 (a, b); // CALL FUNCTION
> > + function1 (a, b); // CALL VIA LEP
> > +
> > + /* Call function via Global Entry Point (GEP). */
> > + a = 10;
> > + b = 50;
> > +
> > + funp (a, b); // CALL VIA GEP
> > return 0;
> > }
> > diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > index 63305c109e1..240b7214ed2 100644
> > --- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > @@ -31,6 +31,16 @@
> > # 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 alternat 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
> > }
> > @@ -50,30 +60,30 @@ if [supports_process_record] {
> > }
> >
> >
> > -### TEST 1: reverse finish from the entry point instruction in
> > -### function1.
> > +### 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_FUNCTION [gdb_get_line_number "CALL FUNCTION" $srcfile]
> > -gdb_breakpoint $srcfile:$bp_FUNCTION temporary
> > +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_FUNCTION\r\n.*"
> > + ".*$srcfile:$bp_LEP_test\r\n.*"
> >
> > # stepi until we see "{" indicating we entered function1
> > -repeat_cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1
> > call"
> > +repeat_cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1
> > call"
> >
> > -gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL
> > FUNCTION.*" \
> > - "reverse-finish function1 "
> > +gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA
> > LEP.*" \
> > + "reverse-finish function1 LEP call from LEP "
> >
> > # 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"
> > +gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call
> > from LEP"
> >
> > # Clear the recorded log.
> > gdb_test "record stop" "Process record is stopped.*" \
> > @@ -84,21 +94,81 @@ 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
> > +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_FUNCTION\r\n.*"
> > + ".*$srcfile:$bp_LEP_test\r\n.*"
> duplicate test name here.
fixed
> >
> > # 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"
> > +gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA
> > LEP.*" \
> > + "reverse-finish function1 LEP 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"
> > +
> > +# 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
> > function" \
> > + ".*$srcfile:$bp_GEP_test\r\n.*"
> Duplicated test name here too.
Fixed
> > +
> > +# stepi until we see "{" indicating we entered function.
> > +cmd_until "stepi" "CALL VIA GEP" "{" "stepi into funp call"
>
> s/cmd_until/repeat_cmd_until
>
> you probably missed because of the test compilation failed.
Fixed. Yup, I always try to go read the log file for that reason. I
have been burned in the past thinking it worked when it didn't actually
run.
>
> > +
> > +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> > + "function1 GEP call call from GEP"
> > +
> > +# 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 = 50;.*" "reverse next at b = 50,
> > call from GEP"
> > +
> > +# 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 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
> > function" \
> > + ".*$srcfile:$bp_GEP_test\r\n.*"
> > +
> > +# Step into body of funp, called via GEP.
> > +gdb_test "step" ".*int ret = 0;.*" "step test 2"
> > +
> > +gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
> > + "reverse-finish function1 GEP 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. 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 = 50;.*" \
> > + "reverse next at b = 50 from function body"
>
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 16:36 ` Carl Love
@ 2023-01-17 16:55 ` Tom de Vries
2023-01-17 17:03 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-01-17 16:55 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
AFAICT, this has been committed just now.
I'm having difficulty finding an approval, did it happen maybe offlist?
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 16:55 ` Tom de Vries
@ 2023-01-17 17:03 ` Carl Love
2023-01-17 17:14 ` Tom de Vries
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-17 17:03 UTC (permalink / raw)
To: Tom de Vries, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Tom:
On Tue, 2023-01-17 at 17:55 +0100, Tom de Vries wrote:
> AFAICT, this has been committed just now.
>
> I'm having difficulty finding an approval, did it happen maybe
> offlist?
>
> Thanks,
> - Tom
I just committed it based on Bruno's reply.
> The patch has been tested on X86 and PowerPC with no regressions.
I will reiterate that I don't know much about PPC, so the best I can do
is check for style and tests, but apart from a few minor nits inlined,
it looks ok
Tested-By: Bruno Larsen <blarsen@redhat.com>
I thought that was an approval to commit. Is it not?
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 17:03 ` Carl Love
@ 2023-01-17 17:14 ` Tom de Vries
2023-01-17 19:31 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-01-17 17:14 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
On 1/17/23 18:03, Carl Love wrote:
> Tom:
>
> On Tue, 2023-01-17 at 17:55 +0100, Tom de Vries wrote:
>> AFAICT, this has been committed just now.
>>
>> I'm having difficulty finding an approval, did it happen maybe
>> offlist?
>>
>> Thanks,
>> - Tom
>
> I just committed it based on Bruno's reply.
>
> > The patch has been tested on X86 and PowerPC with no regressions.
>
> I will reiterate that I don't know much about PPC, so the best I can do
> is check for style and tests, but apart from a few minor nits inlined,
> it looks ok
>
> Tested-By: Bruno Larsen <blarsen@redhat.com>
>
> I thought that was an approval to commit. Is it not?
Hi Carl,
sorry, AFAIU it's not. Bruno has been helpfully reviewing your patch,
but AFAIK he cannot approve it.
This is an easy mistake to make though, given the used formulation, it's
not the first time it happened, and it's one of the reasons we're trying
to move towards replying with the Approved-By tag to make approval more
formal, explicit and unambiguous.
FYI, I'm working my way toward reviewing these patches, and have
regained access to my usual powerpc machine, so I'll try to reproduce
the issue you're seeing.
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 17:14 ` Tom de Vries
@ 2023-01-17 19:31 ` Carl Love
2023-01-18 10:55 ` Tom de Vries
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-17 19:31 UTC (permalink / raw)
To: Tom de Vries, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Tom:
On Tue, 2023-01-17 at 18:14 +0100, Tom de Vries wrote:
> On 1/17/23 18:03, Carl Love wrote:
> > Tom:
> >
> > On Tue, 2023-01-17 at 17:55 +0100, Tom de Vries wrote:
> > > AFAICT, this has been committed just now.
> > >
> > > I'm having difficulty finding an approval, did it happen maybe
> > > offlist?
> > >
> > > Thanks,
> > > - Tom
> >
> > I just committed it based on Bruno's reply.
> >
> > > The patch has been tested on X86 and PowerPC with no
> > regressions.
> >
> > I will reiterate that I don't know much about PPC, so the best
> > I can do
> > is check for style and tests, but apart from a few minor nits
> > inlined,
> > it looks ok
> >
> > Tested-By: Bruno Larsen <blarsen@redhat.com>
> >
> > I thought that was an approval to commit. Is it not?
>
> Hi Carl,
>
> sorry, AFAIU it's not. Bruno has been helpfully reviewing your
> patch,
> but AFAIK he cannot approve it.
>
> This is an easy mistake to make though, given the used formulation,
> it's
> not the first time it happened, and it's one of the reasons we're
> trying
> to move towards replying with the Approved-By tag to make approval
> more
> formal, explicit and unambiguous.
>
> FYI, I'm working my way toward reviewing these patches, and have
> regained access to my usual powerpc machine, so I'll try to
> reproduce
> the issue you're seeing.
OK, thanks for the clarification on the process. In the past, I have
had people explicitly state in their reply that they could not approve
a patch but were just reviewing and commenting on it.
I will be sure to look for the "Approved-By tag" in the future. Sorry
for the mistake.
Please let me know if you need me to revert the patch, make some fixes,
or?
Thanks.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 19:31 ` Carl Love
@ 2023-01-18 10:55 ` Tom de Vries
2023-01-18 16:16 ` Carl Love
2023-01-18 22:26 ` Carl Love
0 siblings, 2 replies; 105+ messages in thread
From: Tom de Vries @ 2023-01-18 10:55 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
On 1/17/23 20:31, Carl Love wrote:
> Tom:
>
> On Tue, 2023-01-17 at 18:14 +0100, Tom de Vries wrote:
>> On 1/17/23 18:03, Carl Love wrote:
>>> Tom:
>>>
>>> On Tue, 2023-01-17 at 17:55 +0100, Tom de Vries wrote:
>>>> AFAICT, this has been committed just now.
>>>>
>>>> I'm having difficulty finding an approval, did it happen maybe
>>>> offlist?
>>>>
>>>> Thanks,
>>>> - Tom
>>>
>>> I just committed it based on Bruno's reply.
>>>
>>> > The patch has been tested on X86 and PowerPC with no
>>> regressions.
>>>
>>> I will reiterate that I don't know much about PPC, so the best
>>> I can do
>>> is check for style and tests, but apart from a few minor nits
>>> inlined,
>>> it looks ok
>>>
>>> Tested-By: Bruno Larsen <blarsen@redhat.com>
>>>
>>> I thought that was an approval to commit. Is it not?
>>
>> Hi Carl,
>>
>> sorry, AFAIU it's not. Bruno has been helpfully reviewing your
>> patch,
>> but AFAIK he cannot approve it.
>>
>> This is an easy mistake to make though, given the used formulation,
>> it's
>> not the first time it happened, and it's one of the reasons we're
>> trying
>> to move towards replying with the Approved-By tag to make approval
>> more
>> formal, explicit and unambiguous.
>>
>> FYI, I'm working my way toward reviewing these patches, and have
>> regained access to my usual powerpc machine, so I'll try to
>> reproduce
>> the issue you're seeing.
>
> OK, thanks for the clarification on the process. In the past, I have
> had people explicitly state in their reply that they could not approve
> a patch but were just reviewing and commenting on it.
>
> I will be sure to look for the "Approved-By tag" in the future. Sorry
> for the mistake.
>
> Please let me know if you need me to revert the patch, make some fixes,
> or?
I've run into regressions due to the first patch:
...
FAIL: gdb.btrace/rn-dl-bind.exp: test: reverse-next
FAIL: gdb.btrace/tailcall.exp: reverse-next.1
FAIL: gdb.btrace/tailcall.exp: step.1
...
So, please revert both.
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-18 10:55 ` Tom de Vries
@ 2023-01-18 16:16 ` Carl Love
2023-01-18 22:26 ` Carl Love
1 sibling, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-18 16:16 UTC (permalink / raw)
To: Tom de Vries, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
On Wed, 2023-01-18 at 11:55 +0100, Tom de Vries wrote:
> On 1/17/23 20:31, Carl Love wrote:
> > Tom:
> >
> > On Tue, 2023-01-17 at 18:14 +0100, Tom de Vries wrote:
> > > On 1/17/23 18:03, Carl Love wrote:
> > > > Tom:
> > > >
> > > > On Tue, 2023-01-17 at 17:55 +0100, Tom de Vries wrote:
> > > > > AFAICT, this has been committed just now.
> > > > >
> > > > > I'm having difficulty finding an approval, did it happen
> > > > > maybe
> > > > > offlist?
> > > > >
> > > > > Thanks,
> > > > > - Tom
> > > >
> > > > I just committed it based on Bruno's reply.
> > > >
> > > > > The patch has been tested on X86 and PowerPC with no
> > > > regressions.
> > > >
> > > > I will reiterate that I don't know much about PPC, so the
> > > > best
> > > > I can do
> > > > is check for style and tests, but apart from a few minor
> > > > nits
> > > > inlined,
> > > > it looks ok
> > > >
> > > > Tested-By: Bruno Larsen <blarsen@redhat.com>
> > > >
> > > > I thought that was an approval to commit. Is it not?
> > >
> > > Hi Carl,
> > >
> > > sorry, AFAIU it's not. Bruno has been helpfully reviewing your
> > > patch,
> > > but AFAIK he cannot approve it.
> > >
> > > This is an easy mistake to make though, given the used
> > > formulation,
> > > it's
> > > not the first time it happened, and it's one of the reasons we're
> > > trying
> > > to move towards replying with the Approved-By tag to make
> > > approval
> > > more
> > > formal, explicit and unambiguous.
> > >
> > > FYI, I'm working my way toward reviewing these patches, and have
> > > regained access to my usual powerpc machine, so I'll try to
> > > reproduce
> > > the issue you're seeing.
> >
> > OK, thanks for the clarification on the process. In the past, I
> > have
> > had people explicitly state in their reply that they could not
> > approve
> > a patch but were just reviewing and commenting on it.
> >
> > I will be sure to look for the "Approved-By tag" in the
> > future. Sorry
> > for the mistake.
> >
> > Please let me know if you need me to revert the patch, make some
> > fixes,
> > or?
>
> I've run into regressions due to the first patch:
> ...
> FAIL: gdb.btrace/rn-dl-bind.exp: test: reverse-next
> FAIL: gdb.btrace/tailcall.exp: reverse-next.1
> FAIL: gdb.btrace/tailcall.exp: step.1
> ...
>
> So, please revert both.
I reverted both commits. I will take see if I can reproduce the
failures you are seeing.
ommit b986eec55f460a9c77a0c06ec30d7280293f7a8c (HEAD -> master,
origin/master, origin/HEAD)
Author: Carl Love <cel@us.ibm.com>
Date: Wed Jan 18 11:13:17 2023 -0500
Revert "X86: reverse-finish fix"
This reverts commit b22548ddb30bfb167708e82d3bb932461c1b703a.
This patch is being reverted since the patch series is causing
regressions.
commit 15d2b36c5b60795067cec773a66d2627d2bf9266
Author: Carl Love <cel@us.ibm.com>
Date: Wed Jan 18 11:12:13 2023 -0500
Revert "PowerPC: fix for gdb.reverse/finish-precsave.exp and
gdb.reverse/finish-reverse.exp"
This reverts commit 92e07580db6a5572573d5177ca23933064158f89.
Reverting patch as the patch series is causing regressions.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-18 10:55 ` Tom de Vries
2023-01-18 16:16 ` Carl Love
@ 2023-01-18 22:26 ` Carl Love
2023-01-19 8:04 ` Bruno Larsen
1 sibling, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-18 22:26 UTC (permalink / raw)
To: Tom de Vries, Bruno Larsen, Ulrich Weigand, gdb-patches; +Cc: cel
Tom and Bruno:
On Wed, 2023-01-18 at 11:55 +0100, Tom de Vries wrote:
>
> I've run into regressions due to the first patch:
> ...
> FAIL: gdb.btrace/rn-dl-bind.exp: test: reverse-next
> FAIL: gdb.btrace/tailcall.exp: reverse-next.1
> FAIL: gdb.btrace/tailcall.exp: step.1
> ...
I am looking into these failures. I tried running the rn-dl-bind.exp
test on my PowerPC and X86 box. On both systems, I get the error:
UNSUPPORTED: gdb.btrace/rn-dl-bind.exp: target does not support record-btrace
testcase /../binutils-gdb-finish-precsave/gdb/testsuite/gdb.btrace/rn-dl-bind.exp completed in 0 seconds
I tried compiling the source code and running gdb by hand on my PowerPC
machine. When I try the command record btrace, I get the message: You
can't do that when your target is `multi-thread'. Digging into the GDB
manual I see it says the following about btrace:
Hardware-supported instruction recording, supported on Intel
processors. This method does not record data. Further, the data is
collected in a ring buffer so old data will be overwritten when the
buffer is full. It allows limited reverse execution. Variables and
registers are not available during reverse execution. In remote
debugging, recording continues on disconnect. Recorded data can be
inspected after reconnecting. The recording may be stopped using
record stop.
From this I am assuming you saw the error on and Intel box not a
PowerPC box.
I tried to run the rn-dl-bind.exp test on my X66 box by hand and got
the messages:
Breakpoint 1, main () at rn-dl-bind.c:35
35 ret = test (); /* main.1 */
(gdb) record btrace pt
Intel Processor Trace support was disabled at compile time.
(gdb) record btrace bts
Could not enable branch tracing for Thread 0x7ffff7d85740 (LWP
3087787): BTS support has been disabled for the target cpu.
I found on the web page:
https://gdb-patches.sourceware.narkive.com/Y1ypJmWj/patch-btrace-diagnose-record-bt
race-pt-without-libipt
says record btrace pt neds:
This requires a system with Linux kernel 4.1 or later running on a
5th Generation Intel Core processor or later.
Since I couldn't get the test to run on an IBM machine, I built GDB on
my personal Linux laptop. Initially, I was not able to get the test to
run. The log file had the error message:
(gdb) record btrace
Could not enable branch tracing for process 3941218: You do not have
permission to record the process. Try setting
/proc/sys/kernel/perf_event_paranoid to 2 or less.
I changed /proc/sys/kernel/perf_event_paranoid from 4 to 2. Now the
test runs.
(gdb) PASS: gdb.btrace/rn-dl-bind.exp: test: reverse-next
testcase /home/carll/GDB/binutils-
build/gdb/testsuite/../../../binutils-
gdb/gdb/testsuite/gdb.btrace/rn-dl-bind.exp completed in 0 seconds
=== gdb Summary ===
# of expected passes 9
The test works fine without my patches, with just the X86 patch and
with both the X86 patch and the PPC patch. Unfortunately, I wasn't
able to run the tests on the IBM machine but I can on my personal
laptop. However, I am still not seeing any errors as a result of my
patches.
Not sure what more I can do at this point. If you have some time, can
you take a look at the failures on your machine and let me know what
you are seeing. Maybe we can figure out what is going on.
Perhaps Bruno can also check to see if the two tests were ran on his
machine. If not, hopefully the info above will help Bruno to get the
tests to run on his machine and we can see if they fail there as well.
Thanks for the help with this patch.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-18 22:26 ` Carl Love
@ 2023-01-19 8:04 ` Bruno Larsen
2023-01-19 16:56 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-19 8:04 UTC (permalink / raw)
To: Carl Love, Tom de Vries, Ulrich Weigand, gdb-patches
On 18/01/2023 23:26, Carl Love wrote:
> Not sure what more I can do at this point. If you have some time, can
> you take a look at the failures on your machine and let me know what
> you are seeing. Maybe we can figure out what is going on.
>
> Perhaps Bruno can also check to see if the two tests were ran on his
> machine. If not, hopefully the info above will help Bruno to get the
> tests to run on his machine and we can see if they fail there as well.
I just tried running the gdb.btrace/rn-dl-bind.exp and also got 9
passes, so I cant help there, but I did miss the 2 failures in
tailcall.exp; here's the relevant log:
Breakpoint 1, main () at tailcall.c:37
38 answer += 1;
(gdb) PASS: gdb.btrace/tailcall.exp: next.1
reverse-next
foo () at tailcall.c:29
29 return bar ();
(gdb) FAIL: gdb.btrace/tailcall.exp: reverse-next.1
step
bar () at tailcall.c:24
24 }
(gdb) FAIL: gdb.btrace/tailcall.exp: step.1
finish
Some extra context, line 37 (the line that is being "undone" by
reverse-next) has a call to foo, which calls bar. Whats going on here is
that we're hitting the step-resume breakpoint when exiting the bar call,
instead of when exiting the foo call.Has a very similar smell to the
type of bug I fixed in commit 1f3e37e057e876b37db49dbd8ed5ca22c33f6772,
but that fix itself might not work because of tailcall optimizations.
If you have the test compiled, you can trigger the bug using regular
record, no need to use btrace specifically.
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-19 8:04 ` Bruno Larsen
@ 2023-01-19 16:56 ` Carl Love
2023-01-19 23:57 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-19 16:56 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
Bruno:
On Thu, 2023-01-19 at 09:04 +0100, Bruno Larsen wrote:
> On 18/01/2023 23:26, Carl Love wrote:
> > Not sure what more I can do at this point. If you have some time,
> > can
> > you take a look at the failures on your machine and let me know
> > what
> > you are seeing. Maybe we can figure out what is going on.
> >
> > Perhaps Bruno can also check to see if the two tests were ran on
> > his
> > machine. If not, hopefully the info above will help Bruno to get
> > the
> > tests to run on his machine and we can see if they fail there as
> > well.
>
> I just tried running the gdb.btrace/rn-dl-bind.exp and also got 9
> passes, so I cant help there, but I did miss the 2 failures in
> tailcall.exp; here's the relevant log:
>
> Breakpoint 1, main () at tailcall.c:37
> 38 answer += 1;
> (gdb) PASS: gdb.btrace/tailcall.exp: next.1
> reverse-next
> foo () at tailcall.c:29
> 29 return bar ();
> (gdb) FAIL: gdb.btrace/tailcall.exp: reverse-next.1
> step
> bar () at tailcall.c:24
> 24 }
> (gdb) FAIL: gdb.btrace/tailcall.exp: step.1
> finish
>
> Some extra context, line 37 (the line that is being "undone" by
> reverse-next) has a call to foo, which calls bar. Whats going on here
> is
> that we're hitting the step-resume breakpoint when exiting the bar
> call,
> instead of when exiting the foo call.Has a very similar smell to the
> type of bug I fixed in commit
> 1f3e37e057e876b37db49dbd8ed5ca22c33f6772,
> but that fix itself might not work because of tailcall optimizations.
>
> If you have the test compiled, you can trigger the bug using regular
> record, no need to use btrace specifically.
Thanks, I went back and tried the tailcall again. I was able to get it
to generate 2 fails on my laptop with just the X86 patch. Not sure why
I didn't see that before, maybe I had a typo??? I did note that git
on my laptop seems to act a bit weird so maybe that was an issue?? I
am having to double check the code changes after running git to make
sure it applied the changes correctly. Not sure why I didn't see the
passes in the full regression suite either. Anyway, I am looking to
see if I can figure out what the regression issue is for this test.
The gdb.btrace/rn-dl-bind.exp test still runs fine with 9 passes.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-19 16:56 ` Carl Love
@ 2023-01-19 23:57 ` Carl Love
2023-01-20 20:04 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-19 23:57 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
Bruno, Tom:
On Thu, 2023-01-19 at 08:56 -0800, Carl Love wrote:
<snip>
> >
> > If you have the test compiled, you can trigger the bug using
> > regular
> > record, no need to use btrace specifically.
>
> Thanks, I went back and tried the tailcall again. I was able to get
> it
> to generate 2 fails on my laptop with just the X86 patch. Not sure
> why
> I didn't see that before, maybe I had a typo???
I reviewed the full regression log on my X86 laptop and yup there are
the two errors for tailcall in the log. I just missed them when I was
looking. Argh.
> I did note that git
> on my laptop seems to act a bit weird so maybe that was an issue?? I
> am having to double check the code changes after running git to make
> sure it applied the changes correctly. Not sure why I didn't see the
> passes in the full regression suite either. Anyway, I am looking to
> see if I can figure out what the regression issue is for this test.
>
> The gdb.btrace/rn-dl-bind.exp test still runs fine with 9 passes.
I claim, the test case for gdb.btrace/tailcall.exp also needs fixing.
Without the patch, when you were in the main program at "answer += 1"
and did a reverse-next, gdb would go back thru the call to function bar
and thru the call to function foo stopping in main. That doesn't seem
right to me as you have stepped back thru function foo and bar.
With the patch the reverse-next only step back thru function bar and
stops in function foo at the call to bar, i.e. doesn't continue to step
back thru function bar.
The following is the tailcall source code with comments showing where
the reverse-step and reverse-next stop with and without the X86 patch
applied. Hopefully the code below is a little easier to follow.
Initially, the reverse-step and reverse-next tests are executed from
the line "answer += 1;" in function main.
static __attribute__ ((noinline)) int
bar (void)
{
return 42;
} <- reverse-step stops here (with no patch
and with X86 patch)
static __attribute__ ((noinline)) int
foo (void)
{
return bar (); <- reverse-next stops here (patch X86 applied)
}
int
main (void)
{
int answer;
answer = foo (); <- reverse-next tops here (no patch applied, stepped
back thru both the bar and foo functions)
answer += 1; <- GDB is here, now issue the reverse-step
and reverse-next commands
return answer;
}
As a result of the change in the reverse-next instruction, the expected
test results for the tailcall test need to be updated to reflect the
fact that gdb now stops in function foo not main.
--- a/gdb/testsuite/gdb.btrace/tailcall.exp
+++ b/gdb/testsuite/gdb.btrace/tailcall.exp
@@ -102,9 +102,9 @@ gdb_test "reverse-step" "\[^\r\n\]*main \\(\\) at tailcall.c
:37\r\n.*" \
"reverse-step.2"
gdb_test "next" "\[^\r\n\]*38.*" \
"next.1"
-gdb_test "reverse-next" "\[^\r\n\]*main \\(\\) at tailcall.c:37\r\n.*" \
+gdb_test "reverse-next" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
"reverse-next.1"
-gdb_test "step" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
+gdb_test "step" "\[^\r\n\]*bar \\(\\) at tailcall.c:24\r\n.*" \
"step.1"
gdb_test "finish" "\[^\r\n\]*main \\(\\) at tailcall.c:38\r\n.*" \
"finish.2"
With this change, the tailcall.exp test now passes on my X86 laptop.
The PowerPC do not change since the test is not supported on PowerPC.
I will post an updated version of the X86 patch with the fixes to the
tailcall test. It will be version 3. There are no changes to the
PowerPC patch.
The gdb.btrace/rn-dl-bind.exp test passes with and without my patches.
I still can not get this test to fail on my system.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-17 12:35 ` Bruno Larsen
@ 2023-01-20 0:03 ` Carl Love
2023-01-23 19:17 ` Pedro Alves
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-20 0:03 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches; +Cc: cel
Bruno, Tom:
Per the conversation about the regressions for the regressions in tests
FAIL: gdb.btrace/rn-dl-bind.exp: test: reverse-next
FAIL: gdb.btrace/tailcall.exp: reverse-next.1
FAIL: gdb.btrace/tailcall.exp: step.1
The following patch fixes the expected results for the tailcall test on
X86. Per the previous messages, the output needs to be updated since
the behavior of the reverse-next command was fixed.
As noted, I have not been able to reproduce the gdb.btrace/rn-dl-
bind.exp test failure.
The patch has been tested on my personal X86 laptop which has the
needed processor version and on the PowerPC machine with no regressions
found.
Carl
------------------------------------------
X86: reverse-finish fix
PR record/29927 - reverse-finish requires two reverse next instructions to
reach previous source line
Currently on X86, when executing the finish command in reverse, gdb does a
single step from the first instruction in the callee to get back to the
caller. GDB stops on the last instruction in the source code line where
the call was made. When stopped at the last instruction of the source code
line, a reverse next or step command will stop at the first instruction
of the same source code line thus requiring two step/next commands to
reach the previous source code line. It should only require one step/next
command to reach the previous source code line.
By contrast, a reverse next or step command from the first line in a
function stops at the first instruction in the source code line where the
call was made.
This patch fixes the reverse finish command so it will stop at the first
instruction of the source line where the function call was made. The
behavior on X86 for the reverse-finish command now matches doing a
reverse-next from the beginning of the function.
The proceed_to_finish flag in struct thread_control_state is no longer
used. This patch removes the declaration, initialization and setting of
the flag.
This patch requires a number of regression tests to be updated. Test
gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
previous line. The gdb output for tests gdb.reverse/until-precsave.exp
and gdb.reverse/until-reverse.exp changed slightly. The expected result in
tests gdb.reverse/amd64-failcall-reverse.exp and
gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
result. The expected result in btrace/tailcall.exp also changes since
the reverse-next now only steps back thru one function call not two
function calls.
This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
reverse-finish command when returning from the entry point and from the
body of the function.
The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
was moved to lib/gdb.exp and renamed cmd_until.
The patch has been tested on X86 and PowerPC to verify no additional
regression failures occured.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29927
---
gdb/gdbthread.h | 4 -
gdb/infcall.c | 3 -
gdb/infcmd.c | 32 +++---
gdb/infrun.c | 40 +++----
gdb/testsuite/gdb.btrace/tailcall.exp | 4 +-
gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
.../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
.../gdb.reverse/finish-reverse-next.c | 48 ++++++++
.../gdb.reverse/finish-reverse-next.exp | 104 ++++++++++++++++++
.../gdb.reverse/singlejmp-reverse.exp | 5 +-
.../gdb.reverse/step-indirect-call-thunk.exp | 49 ++-------
gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 33 ++++++
14 files changed, 232 insertions(+), 108 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1721,19 +1721,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
@@ -1743,16 +1734,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
@@ -1778,9 +1775,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 181d961d80d..86e5ef1ed12 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.btrace/tailcall.exp b/gdb/testsuite/gdb.btrace/tailcall.exp
index 028e03fc6f6..fa254664a09 100644
--- a/gdb/testsuite/gdb.btrace/tailcall.exp
+++ b/gdb/testsuite/gdb.btrace/tailcall.exp
@@ -102,9 +102,9 @@ gdb_test "reverse-step" "\[^\r\n\]*main \\(\\) at tailcall.c:37\r\n.*" \
"reverse-step.2"
gdb_test "next" "\[^\r\n\]*38.*" \
"next.1"
-gdb_test "reverse-next" "\[^\r\n\]*main \\(\\) at tailcall.c:37\r\n.*" \
+gdb_test "reverse-next" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
"reverse-next.1"
-gdb_test "step" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
+gdb_test "step" "\[^\r\n\]*bar \\(\\) at tailcall.c:24\r\n.*" \
"step.1"
gdb_test "finish" "\[^\r\n\]*main \\(\\) at tailcall.c:38\r\n.*" \
"finish.2"
diff --git a/gdb/testsuite/gdb.mi/mi-reverse.exp b/gdb/testsuite/gdb.mi/mi-reverse.exp
index d631beb17c8..30635ab1754 100644
--- a/gdb/testsuite/gdb.mi/mi-reverse.exp
+++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
@@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
--- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
@@ -44,6 +44,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 00000000000..f90ecbb93cb
--- /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 00000000000..63305c109e1
--- /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 1ca7c2ce559..eb03051625a 100644
--- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
@@ -56,7 +56,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 ad637899e5b..b82e5663bd5 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -39,39 +39,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"
@@ -91,20 +58,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 0c2d7537cd6..777aec94ac1 100644
--- a/gdb/testsuite/gdb.reverse/until-precsave.exp
+++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
@@ -142,7 +142,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 23fc881dbf2..3a05953329f 100644
--- a/gdb/testsuite/gdb.reverse/until-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
@@ -113,7 +113,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 c41d4698d66..234c21a04ea 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9301,6 +9301,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.
#
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 2/2 version 2] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-19 23:57 ` Carl Love
@ 2023-01-20 20:04 ` Carl Love
2023-01-23 16:42 ` [PATCH 1/2 version 3] " Carl Love
` (2 more replies)
0 siblings, 3 replies; 105+ messages in thread
From: Carl Love @ 2023-01-20 20:04 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
On Thu, 2023-01-19 at 15:57 -0800, Carl Love wrote:
> Bruno, Tom:
>
>
> On Thu, 2023-01-19 at 08:56 -0800, Carl Love wrote:
>
<snip>
>
> Without the patch, when you were in the main program at "answer += 1"
> and did a reverse-next, gdb would go back thru the call to function
> bar
> and thru the call to function foo stopping in main. That doesn't
> seem
> right to me as you have stepped back thru function foo and bar.
>
> With the patch the reverse-next only step back thru function bar and
> stops in function foo at the call to bar, i.e. doesn't continue to
> step
> back thru function bar.
>
> The following is the tailcall source code with comments showing where
> the reverse-step and reverse-next stop with and without the X86 patch
> applied. Hopefully the code below is a little easier to follow.
> Initially, the reverse-step and reverse-next tests are executed from
> the line "answer += 1;" in function main.
>
>
> static __attribute__ ((noinline)) int
> bar (void)
> {
> return 42;
> } <- reverse-step stops here (with no patch
> and with X86 patch)
>
> static __attribute__ ((noinline)) int
> foo (void)
> {
> return bar (); <- reverse-next stops here (patch X86 applied)
> }
>
> int
> main (void)
> {
> int answer;
>
> answer = foo (); <- reverse-next tops here (no patch applied,
> stepped
> back thru both the bar and foo functions)
> answer += 1; <- GDB is here, now issue the reverse-step
> and reverse-next commands
>
> return answer;
> }
>
> As a result of the change in the reverse-next instruction, the
> expected
> test results for the tailcall test need to be updated to reflect the
> fact that gdb now stops in function foo not main.
>
> --- a/gdb/testsuite/gdb.btrace/tailcall.exp
> +++ b/gdb/testsuite/gdb.btrace/tailcall.exp
> @@ -102,9 +102,9 @@ gdb_test "reverse-step" "\[^\r\n\]*main \\(\\) at
> tailcall.c
> :37\r\n.*" \
> "reverse-step.2"
> gdb_test "next" "\[^\r\n\]*38.*" \
> "next.1"
> -gdb_test "reverse-next" "\[^\r\n\]*main \\(\\) at
> tailcall.c:37\r\n.*" \
> +gdb_test "reverse-next" "\[^\r\n\]*foo \\(\\) at
> tailcall.c:29\r\n.*" \
> "reverse-next.1"
> -gdb_test "step" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
> +gdb_test "step" "\[^\r\n\]*bar \\(\\) at tailcall.c:24\r\n.*" \
> "step.1"
> gdb_test "finish" "\[^\r\n\]*main \\(\\) at tailcall.c:38\r\n.*" \
> "finish.2"
>
> With this change, the tailcall.exp test now passes on my X86 laptop.
> The PowerPC do not change since the test is not supported on PowerPC.
>
> I will post an updated version of the X86 patch with the fixes to the
> tailcall test. It will be version 3. There are no changes to the
> PowerPC patch.
>
> The gdb.btrace/rn-dl-bind.exp test passes with and without my
> patches.
> I still can not get this test to fail on my system.
I have been thinking about this and have decided the above change is
not what we should do. Basically if we forward step at answer = foo();
we stop at answer += 1;. Which is the expected behavior for next. So,
is we are at answer += 1; and do a reverse step it should take us to
answer = foo(). It would be the opposite of the forward next.
I think I have identified the single line in the function call
set_step_info() which caused the regression in gdb.btrace/tailcall.exp.
I have so far run a few experiments and it looks like not doing the
statement:
tp->control.step_stack_frame_id = get_stack_frame_id (frame);
eliminates the regression in tailcall.exp.
So far. I need to do some more testing but it looks like there is a
couple of regressions on my X86 laptop. It looks like the expected
behavior in both of these tests is for the reverse step over a function
stops at a function call within the function not stepping all the way
back to the call of the function. Basically, the expected behavior of
these reverse tests is not consistent across tests.
I am not seeing any PowerPC regression failures with the above change.
My IBM x86 machine tests are still running.
Anyway, just wanted to give people a heads up that I am pursuing
another fix and that I now think the above fix is not the best
direction to go.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-20 20:04 ` Carl Love
@ 2023-01-23 16:42 ` Carl Love
2023-01-23 16:42 ` [PATCH 2/2 " Carl Love
2023-02-10 20:55 ` [PATCH ] PowerPC: " Carl Love
2 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-23 16:42 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
Bruno, Tom, Ulrich, GDB developers:
Fixed the regression failure in gdb.btrace/tailcall.exp. The function
call set_step_info() sets the following values:
tp->control.step_frame_id = get_frame_id (frame);
tp->control.step_stack_frame_id = get_stack_frame_id (frame);
tp->current_symtab = sal.symtab;
tp->current_line = sal.line;
The regression failure was due to the function updating the value of
tp->control.step_stack_frame_id. So, the function call was replaced
with the three lines of code to update step_frame_id, current_symtab,
current_line. This was done in both places where set_step_info() was
being called.
The gdb.btrace tests require a 5th generation Intel processor to run.
I have run the regression tests on my X86 laptop with a 5th generation
processor as well as the IBM X86 system, with a pre 5th generation
processor and on PowerPC with no regressions.
I do not see the issue with test gdb.btrace/rn-dl-bind.exp Tom
reported.
Please let me know if this version of the patch is acceptable. Thanks.
Carl
----------------
X86: reverse-finish fix
PR record/29927 - reverse-finish requires two reverse next instructions to
reach previous source line
Currently on X86, when executing the finish command in reverse, gdb does a
single step from the first instruction in the callee to get back to the
caller. GDB stops on the last instruction in the source code line where
the call was made. When stopped at the last instruction of the source code
line, a reverse next or step command will stop at the first instruction
of the same source code line thus requiring two step/next commands to
reach the previous source code line. It should only require one step/next
command to reach the previous source code line.
By contrast, a reverse next or step command from the first line in a
function stops at the first instruction in the source code line where the
call was made.
This patch fixes the reverse finish command so it will stop at the first
instruction of the source line where the function call was made. The
behavior on X86 for the reverse-finish command now matches doing a
reverse-next from the beginning of the function.
The proceed_to_finish flag in struct thread_control_state is no longer
used. This patch removes the declaration, initialization and setting of
the flag.
This patch requires a number of regression tests to be updated. Test
gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
previous line. The gdb output for tests gdb.reverse/until-precsave.exp
and gdb.reverse/until-reverse.exp changed slightly. The expected result in
tests gdb.reverse/amd64-failcall-reverse.exp and
gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
result. Test gdb.reverse/singlejmp-reverse.exp no longer fails on "no
more reverse-execution history".
The reverse-next command should step all the way back thru a function call.
For example:
a = foo ();
b = 1; <- issuing reverse-next here should stop at the
previous line.
Test gdb.reverse/amd64-tailcall-reverse.exp expected the reverse-next
command to stop at a function call in foo (). That is not the correct
behavior. GDB now step to the previous line as expected. The expected
output for the test is updated to the correct behavior.
This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
reverse-finish command when returning from the entry point and from the
body of the function.
The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
was moved to lib/gdb.exp and renamed cmd_until.
The patch has been tested on X86 and PowerPC to verify no additional
regression failures occured.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29927
---
gdb/gdbthread.h | 4 -
gdb/infcall.c | 3 -
gdb/infcmd.c | 37 +++----
gdb/infrun.c | 45 ++++----
gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
.../gdb.reverse/amd64-tailcall-reverse.exp | 3 +-
.../gdb.reverse/finish-reverse-next.c | 48 ++++++++
.../gdb.reverse/finish-reverse-next.exp | 104 ++++++++++++++++++
.../gdb.reverse/singlejmp-reverse.exp | 3 -
.../gdb.reverse/step-indirect-call-thunk.exp | 49 ++-------
gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
gdb/testsuite/lib/gdb.exp | 33 ++++++
13 files changed, 237 insertions(+), 105 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..5d3221e8b90 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1721,19 +1721,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
@@ -1743,16 +1734,27 @@ 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 setup the current_symtab and
+ current_line. Do not change the step_stack_frame_id as this
+ will cause the reverse-next command to stop in the wrong spot. */
+ struct symtab_and_line stop_pc_sal;
+ stop_pc_sal = find_pc_line (pc, 0);
+ tp->control.step_frame_id = get_frame_id (frame);
+ tp->current_symtab = stop_pc_sal.symtab;
+ tp->current_line = stop_pc_sal.line;
+
+ /* 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
@@ -1778,9 +1780,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 181d961d80d..183110a049a 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,30 @@ 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)
- {
- struct thread_info *tp = ecs->event_thread;
-
- /* 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)
+
+ if (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;
+ 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. */
+
+ stop_pc_sal = find_pc_line (ecs->event_thread->stop_pc (), 0);
+
+ /* When setting a step range, need to setup the current_symtab and
+ current_line. Do not change the step_stack_frame_id as this
+ will cause the reverse-next command to stop in the wrong spot. */
+ tp->control.step_frame_id = get_frame_id (frame);
+ tp->current_symtab = stop_pc_sal.symtab;
+ tp->current_line = stop_pc_sal.line;
+
+ /* 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 d631beb17c8..30635ab1754 100644
--- a/gdb/testsuite/gdb.mi/mi-reverse.exp
+++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
@@ -97,15 +97,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 52a87faabf7..7d441dbb7a9 100644
--- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
@@ -44,6 +44,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 ();
+# Reverse step back to f ().
gdb_test "reverse-next" {f \(\);}
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 00000000000..f90ecbb93cb
--- /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 00000000000..63305c109e1
--- /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 1ca7c2ce559..e94bcdbe52e 100644
--- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
@@ -56,7 +56,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 \(\);}
diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
index ad637899e5b..b82e5663bd5 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -39,39 +39,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"
@@ -91,20 +58,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 0c2d7537cd6..777aec94ac1 100644
--- a/gdb/testsuite/gdb.reverse/until-precsave.exp
+++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
@@ -142,7 +142,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 23fc881dbf2..3a05953329f 100644
--- a/gdb/testsuite/gdb.reverse/until-reverse.exp
+++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
@@ -113,7 +113,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 c41d4698d66..234c21a04ea 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9301,6 +9301,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.
#
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-20 20:04 ` Carl Love
2023-01-23 16:42 ` [PATCH 1/2 version 3] " Carl Love
@ 2023-01-23 16:42 ` Carl Love
2023-02-10 20:55 ` [PATCH ] PowerPC: " Carl Love
2 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-23 16:42 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
Bruno, Tom, Ulrich, GDB maintainers:
This patch is functionally the same as version 2. It was refreshed to
properly apply on the X86 patch. The X86 patch changed the diff
locations slightly.
I have run the regression tests on my X86 laptop with a 5th generation
processor as well as the IBM X86 system, with a pre 5th generation
processor and on PowerPC with no regressions.
Please let me know if this version of the patch is acceptable. Thanks.
Carl
---------------------------------------------
PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
PR record/29927 - reverse-finish requires two reverse next instructions to
reach previous source line
PowerPC uses two entry points called the local entry point (LEP) and the
global entry point (GEP). Normally the LEP is used when calling a
function. However, if the table of contents (TOC) value in register 2 is
not valid the GEP is called to setup the TOC before execution continues at
the LEP. When executing in reverse, the function finish_backward sets the
break point at the alternate entry point (GEP). However if the forward
execution enters via the normal entry point (LEP), the reverse execution
never sees the break point at the GEP of the function. Reverse execution
continues until the next break point is encountered or the end of the
recorded log is reached causing gdb to stop at the wrong place.
This patch adds a new address to struct execution_control_state to hold the
address of the alternate function start address, known as the GEP on
PowerPC. The finish_backwards function is updated. If the stopping point
is between the two entry points (the LEP and GEP on PowerPC), the stepping
range is set to execute back to the alternate entry point (GEP on PowerPC).
Otherwise, a breakpoint is inserted at the normal entry point (LEP on
PowerPC).
Function process_event_stop_test checks uses a stepping range to stop
execution in the caller at the first instruction of the source code line.
Note, on systems that only support one entry point, the address of the two
entry points are the same.
Test finish-reverse-next.exp is updated to include tests for the
reverse-finish command when the function is entered via the normal entry
point (i.e. the LEP) and the alternate entry point (i.e. the GEP).
The patch has been tested on X86 and PowerPC with no regressions.
---
gdb/infcmd.c | 40 +++++---
gdb/infrun.c | 16 +++-
.../gdb.reverse/finish-reverse-next.c | 39 +++++++-
.../gdb.reverse/finish-reverse-next.exp | 96 ++++++++++++++++---
4 files changed, 160 insertions(+), 31 deletions(-)
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 5d3221e8b90..63e245f7de9 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1722,22 +1722,25 @@ finish_backward (struct finish_command_fsm *sm)
sal = find_pc_line (func_addr, 0);
frame_info_ptr frame = get_selected_frame (nullptr);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR alt_entry_point = sal.pc;
+ CORE_ADDR entry_point = alt_entry_point;
- if (sal.pc != pc)
+ if (gdbarch_skip_entrypoint_p (gdbarch))
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
-
- /* Set a step-resume at the function's entry point. Once that's
- hit, we'll do one more step backwards. */
- symtab_and_line sr_sal;
- sr_sal.pc = sal.pc;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ /* Some architectures, like PowerPC use local and global entry points.
+ There is only one Entry Point (GEP = LEP) for other architectures.
+ The GEP is an alternate entry point. The LEP is the normal entry
+ point. The value of entry_point was initialized to the alternate
+ entry point (GEP). It will be adjusted if the normal entry point
+ (LEP) was used. */
+ entry_point = gdbarch_skip_entrypoint (gdbarch, entry_point);
}
- else
+
+ if (alt_entry_point <= pc && pc <= entry_point)
{
- /* We are exactly at the function entry point. Note that this
+ /* We are exactly at the function entry point, or between the entry
+ point on platforms that have two (like PowerPC). Note that this
can only happen at frame #0.
When setting a step range, need to setup the current_symtab and
@@ -1751,8 +1754,17 @@ finish_backward (struct finish_command_fsm *sm)
/* 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;
+ tp->control.step_range_start = alt_entry_point;
+ tp->control.step_range_end = entry_point;
+ }
+ else
+ {
+ symtab_and_line sr_sal;
+ /* Set a step-resume at the function's entry point. */
+ sr_sal.pc = entry_point;
+ 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);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 183110a049a..a911aec8568 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1868,6 +1868,7 @@ struct execution_control_state
struct target_waitstatus ws;
int stop_func_filled_in = 0;
+ CORE_ADDR stop_func_alt_start = 0;
CORE_ADDR stop_func_start = 0;
CORE_ADDR stop_func_end = 0;
const char *stop_func_name = nullptr;
@@ -4663,6 +4664,12 @@ fill_in_stop_func (struct gdbarch *gdbarch,
&block);
ecs->stop_func_name = gsi == nullptr ? nullptr : gsi->print_name ();
+ /* PowerPC functions have a Local Entry Point and a Global Entry
+ Point. There is only one Entry Point (GEP = LEP) for other
+ architectures. Save the alternate entry point address (GEP) for
+ use later. */
+ ecs->stop_func_alt_start = ecs->stop_func_start;
+
/* The call to find_pc_partial_function, above, will set
stop_func_start and stop_func_end to the start and end
of the range containing the stop pc. If this range
@@ -4679,6 +4686,9 @@ fill_in_stop_func (struct gdbarch *gdbarch,
+= gdbarch_deprecated_function_start_offset (gdbarch);
if (gdbarch_skip_entrypoint_p (gdbarch))
+ /* The PowerPC architecture uses two entry points. Stop at the
+ regular entry point (LEP on PowerPC) initially. Will setup a
+ breakpoint for the alternate entry point (GEP) later. */
ecs->stop_func_start
= gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
}
@@ -6757,7 +6767,7 @@ process_event_stop_test (struct execution_control_state *ecs)
/* 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_start = ecs->stop_func_alt_start;
tp->control.step_range_end = ecs->stop_func_start;
keep_going (ecs);
return;
@@ -6894,8 +6904,10 @@ process_event_stop_test (struct execution_control_state *ecs)
(unless it's the function entry point, in which case
keep going back to the call point). */
CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
+
if (stop_pc == ecs->event_thread->control.step_range_start
- && stop_pc != ecs->stop_func_start
+ && (stop_pc < ecs->stop_func_alt_start
+ || stop_pc > ecs->stop_func_start)
&& execution_direction == EXEC_REVERSE)
end_stepping_range (ecs);
else
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.c b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
index f90ecbb93cb..0347906961d 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse-next.c
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
@@ -24,11 +24,37 @@
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 alternat entry point is called
+ the global entry point (GEP). The GEP is only used if the table of
+ contents (TOC) value stored in register r2 needs to be setup prior to
+ execution starting at the LEP. 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. */
int
function1 (int a, int b) // FUNCTION1
{
+ /* The assembly code for this function when compiled for PowerPC is as
+ follows:
+
+ 0000000010000758 <function1>:
+ 10000758: 02 10 40 3c lis r2,4098 <- GEP
+ 1000075c: 00 7f 42 38 addi r2,r2,32512
+ 10000760: a6 02 08 7c mflr r0 <- LEP
+ 10000764: 10 00 01 f8 std r0,16(r1)
+ ....
+
+ When the function is called on PowerPC with function1 (a, b) the call
+ enters at the Local Entry Point (LEP). When the function is called via
+ a function pointer, the Global Entry Point (GEP) for function1 is used.
+ The GEP sets up register 2 before reaching the LEP.
+ */
int ret = 0;
ret = a + b;
@@ -39,10 +65,19 @@ int
main(int argc, char* argv[])
{
int a, b;
+ int (*funp) (int, int) = &function1;
+
+ /* Call function via Local Entry Point (LEP). */
a = 1;
b = 5;
- function1 (a, b); // CALL FUNCTION
+ function1 (a, b); // CALL VIA LEP
+
+ /* Call function via Global Entry Point (GEP). */
+ a = 10;
+ b = 50;
+
+ funp (a, b); // CALL VIA GEP
return 0;
}
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
index 63305c109e1..a9c895dfcd4 100644
--- a/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -31,6 +31,16 @@
# 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 alternat 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
}
@@ -50,30 +60,30 @@ if [supports_process_record] {
}
-### TEST 1: reverse finish from the entry point instruction in
-### function1.
+### 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_FUNCTION [gdb_get_line_number "CALL FUNCTION" $srcfile]
-gdb_breakpoint $srcfile:$bp_FUNCTION temporary
+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_FUNCTION\r\n.*"
+ ".*$srcfile:$bp_LEP_test\r\n.*"
# stepi until we see "{" indicating we entered function1
-repeat_cmd_until "stepi" "CALL FUNCTION" "{" "stepi into function1 call"
+repeat_cmd_until "stepi" "CALL VIA LEP" "{" "stepi into function1 call"
-gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
- "reverse-finish function1 "
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse-finish function1 LEP call from LEP "
# 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"
+gdb_test "reverse-next" ".*b = 5;.*" "reverse next at b = 5, call from LEP"
# Clear the recorded log.
gdb_test "record stop" "Process record is stopped.*" \
@@ -84,21 +94,81 @@ 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
+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_FUNCTION\r\n.*"
+ ".*$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"
-gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL FUNCTION.*" \
- "reverse-finish function1 call from function body"
+gdb_test "reverse-finish" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse-finish function1 LEP 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"
+
+# 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"
+
+gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
+ "function1 GEP call call from GEP"
+
+# 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 = 50;.*" "reverse next at b = 50, call from GEP"
+
+# 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 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"
+
+gdb_test "reverse-finish" ".*funp \\(a, b\\);.*" \
+ "reverse-finish function1 GEP 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. 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 = 50;.*" \
+ "reverse next at b = 50 from function body"
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-20 0:03 ` [PATCH 1/2 version 3] " Carl Love
@ 2023-01-23 19:17 ` Pedro Alves
2023-01-23 21:13 ` Carl Love
2023-01-24 15:53 ` [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp Tom de Vries
0 siblings, 2 replies; 105+ messages in thread
From: Pedro Alves @ 2023-01-23 19:17 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
On 2023-01-20 12:03 a.m., Carl Love via Gdb-patches wrote:
> X86: reverse-finish fix
>
> PR record/29927 - reverse-finish requires two reverse next instructions to
> reach previous source line
>
> Currently on X86, when executing the finish command in reverse, gdb does a
> single step from the first instruction in the callee to get back to the
> caller. GDB stops on the last instruction in the source code line where
> the call was made. When stopped at the last instruction of the source code
> line, a reverse next or step command will stop at the first instruction
> of the same source code line thus requiring two step/next commands to
> reach the previous source code line. It should only require one step/next
> command to reach the previous source code line.
>
> By contrast, a reverse next or step command from the first line in a
> function stops at the first instruction in the source code line where the
> call was made.
I'd think this was on purpose. Note that next/step/reverse-{next/step} are line-oriented
stepping commands, they step/next until the previous/next line. While "finish" is described
as undoing the _function call_.
The manual says:
reverse-finish
Just as the finish command takes you to the point where the current function returns,
reverse-finish takes you to the point where it was called. Instead of ending up at the end of
the current function invocation, you end up at the beginning.
Say you have a line with multiple statements involving multiple function calls.
The simplest would be:
func1 (); func2 ();
Say you'd stopped inside 'func2'. If you do finish there, in current master gdb
stops at the call to 'func2', and you can then decide to reverse step into 'func1'.
While with your change, reverse-finish in func2 will make gdb stop at the beginning
of the line, before the call to func1.
Thus I'm really not convinced (yet) this change is a good one. It removes
a user choice. You can always do reverse-next/step do get what you want
reverse-finish do to, already.
Pedro Alves
>
> This patch fixes the reverse finish command so it will stop at the first
> instruction of the source line where the function call was made. The
> behavior on X86 for the reverse-finish command now matches doing a
> reverse-next from the beginning of the function.
>
> The proceed_to_finish flag in struct thread_control_state is no longer
> used. This patch removes the declaration, initialization and setting of
> the flag.
>
> This patch requires a number of regression tests to be updated. Test
> gdb.mi/mi-reverse.exp no longer needs to execute two steps to get to the
> previous line. The gdb output for tests gdb.reverse/until-precsave.exp
> and gdb.reverse/until-reverse.exp changed slightly. The expected result in
> tests gdb.reverse/amd64-failcall-reverse.exp and
> gdb.reverse/singlejmp-reverse.exp are updated to the correct expected
> result. The expected result in btrace/tailcall.exp also changes since
> the reverse-next now only steps back thru one function call not two
> function calls.
>
> This patch adds a new test gdb.reverse/finish-reverse-next.exp to test the
> reverse-finish command when returning from the entry point and from the
> body of the function.
>
> The step_until proceedure in test gdb.reverse/step-indirect-call-thunk.exp
Typo: proceedure -> procedure
> was moved to lib/gdb.exp and renamed cmd_until.
"cmd_until" here is stale.
>
> The patch has been tested on X86 and PowerPC to verify no additional
> regression failures occured.
occured -> occurred
>
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29927
> ---
> gdb/gdbthread.h | 4 -
> gdb/infcall.c | 3 -
> gdb/infcmd.c | 32 +++---
> gdb/infrun.c | 40 +++----
> gdb/testsuite/gdb.btrace/tailcall.exp | 4 +-
> gdb/testsuite/gdb.mi/mi-reverse.exp | 9 +-
> .../gdb.reverse/amd64-tailcall-reverse.exp | 5 +-
> .../gdb.reverse/finish-reverse-next.c | 48 ++++++++
> .../gdb.reverse/finish-reverse-next.exp | 104 ++++++++++++++++++
> .../gdb.reverse/singlejmp-reverse.exp | 5 +-
> .../gdb.reverse/step-indirect-call-thunk.exp | 49 ++-------
> gdb/testsuite/gdb.reverse/until-precsave.exp | 2 +-
> gdb/testsuite/gdb.reverse/until-reverse.exp | 2 +-
> gdb/testsuite/lib/gdb.exp | 33 ++++++
> 14 files changed, 232 insertions(+), 108 deletions(-)
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
>
> diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
> index 11d69fceab0..e4edff2d621 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 e09904f9a35..116605c43ef 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 0497ad05091..9c42efeae8d 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1721,19 +1721,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
> @@ -1743,16 +1734,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
> @@ -1778,9 +1775,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 181d961d80d..86e5ef1ed12 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.btrace/tailcall.exp b/gdb/testsuite/gdb.btrace/tailcall.exp
> index 028e03fc6f6..fa254664a09 100644
> --- a/gdb/testsuite/gdb.btrace/tailcall.exp
> +++ b/gdb/testsuite/gdb.btrace/tailcall.exp
> @@ -102,9 +102,9 @@ gdb_test "reverse-step" "\[^\r\n\]*main \\(\\) at tailcall.c:37\r\n.*" \
> "reverse-step.2"
> gdb_test "next" "\[^\r\n\]*38.*" \
> "next.1"
> -gdb_test "reverse-next" "\[^\r\n\]*main \\(\\) at tailcall.c:37\r\n.*" \
> +gdb_test "reverse-next" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
> "reverse-next.1"
> -gdb_test "step" "\[^\r\n\]*foo \\(\\) at tailcall.c:29\r\n.*" \
> +gdb_test "step" "\[^\r\n\]*bar \\(\\) at tailcall.c:24\r\n.*" \
> "step.1"
> gdb_test "finish" "\[^\r\n\]*main \\(\\) at tailcall.c:38\r\n.*" \
> "finish.2"
> diff --git a/gdb/testsuite/gdb.mi/mi-reverse.exp b/gdb/testsuite/gdb.mi/mi-reverse.exp
> index d631beb17c8..30635ab1754 100644
> --- a/gdb/testsuite/gdb.mi/mi-reverse.exp
> +++ b/gdb/testsuite/gdb.mi/mi-reverse.exp
> @@ -97,15 +97,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 52a87faabf7..9964b4f8e4b 100644
> --- a/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/amd64-tailcall-reverse.exp
> @@ -44,6 +44,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 00000000000..f90ecbb93cb
> --- /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 00000000000..63305c109e1
> --- /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 1ca7c2ce559..eb03051625a 100644
> --- a/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/singlejmp-reverse.exp
> @@ -56,7 +56,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 ad637899e5b..b82e5663bd5 100644
> --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> @@ -39,39 +39,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"
>
> @@ -91,20 +58,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 0c2d7537cd6..777aec94ac1 100644
> --- a/gdb/testsuite/gdb.reverse/until-precsave.exp
> +++ b/gdb/testsuite/gdb.reverse/until-precsave.exp
> @@ -142,7 +142,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 23fc881dbf2..3a05953329f 100644
> --- a/gdb/testsuite/gdb.reverse/until-reverse.exp
> +++ b/gdb/testsuite/gdb.reverse/until-reverse.exp
> @@ -113,7 +113,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 c41d4698d66..234c21a04ea 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -9301,6 +9301,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.
> #
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-23 19:17 ` Pedro Alves
@ 2023-01-23 21:13 ` Carl Love
2023-01-24 14:08 ` Pedro Alves
2023-01-24 15:53 ` [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp Tom de Vries
1 sibling, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-23 21:13 UTC (permalink / raw)
To: Pedro Alves, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
Pedro:
On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
> > Currently on X86, when executing the finish command in reverse, gdb
> > does a
> > single step from the first instruction in the callee to get back to
> > the
> > caller. GDB stops on the last instruction in the source code line
> > where
> > the call was made. When stopped at the last instruction of the
> > source code
> > line, a reverse next or step command will stop at the first
> > instruction
> > of the same source code line thus requiring two step/next commands
> > to
> > reach the previous source code line. It should only require one
> > step/next
> > command to reach the previous source code line.
> >
> > By contrast, a reverse next or step command from the first line in
> > a
> > function stops at the first instruction in the source code line
> > where the
> > call was made.
>
> I'd think this was on purpose. Note that next/step/reverse-
> {next/step} are line-oriented
> stepping commands, they step/next until the previous/next line.
> While "finish" is described
> as undoing the _function call_.
>
> The manual says:
>
> reverse-finish
> Just as the finish command takes you to the point where the current
> function returns,
> reverse-finish takes you to the point where it was called. Instead
> of ending up at the end of
> the current function invocation, you end up at the beginning.
>
> Say you have a line with multiple statements involving multiple
> function calls.
> The simplest would be:
>
> func1 (); func2 ();
>
> Say you'd stopped inside 'func2'. If you do finish there, in current
> master gdb
> stops at the call to 'func2', and you can then decide to reverse step
> into 'func1'.
I don't think you followed the issue.
So, if you are in func2 and do a reverse-finish, without the patch gdb
stops on the last instruction for the line that calls func2. Now if
you issue a reverse-step, you stop at the first instruction for the
call to func2, i.e. you are still on the same source code line. You
have not stepped back into func1 like you wanted to. Now you have to
issue a second reverse-step to get into func1. With the patch, you
issue the reverse-finish from func2 and stop at the first instruction
in the line that calls func2. Now when you issue the reverse-step you
step back into func1 as expected.
> While with your change, reverse-finish in func2 will make gdb stop at
> the beginning
> of the line, before the call to func1.
>
> Thus I'm really not convinced (yet) this change is a good one. It
> removes
> a user choice. You can always do reverse-next/step do get what you
> want
> reverse-finish do to, already.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-23 21:13 ` Carl Love
@ 2023-01-24 14:08 ` Pedro Alves
2023-01-24 14:23 ` Bruno Larsen
` (3 more replies)
0 siblings, 4 replies; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 14:08 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
On 2023-01-23 9:13 p.m., Carl Love wrote:
> Pedro:
>
> On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
>>> Currently on X86, when executing the finish command in reverse, gdb
>>> does a
>>> single step from the first instruction in the callee to get back to
>>> the
>>> caller. GDB stops on the last instruction in the source code line
>>> where
>>> the call was made. When stopped at the last instruction of the
>>> source code
>>> line, a reverse next or step command will stop at the first
>>> instruction
>>> of the same source code line thus requiring two step/next commands
>>> to
>>> reach the previous source code line. It should only require one
>>> step/next
>>> command to reach the previous source code line.
>>>
>>> By contrast, a reverse next or step command from the first line in
>>> a
>>> function stops at the first instruction in the source code line
>>> where the
>>> call was made.
>>
>> I'd think this was on purpose. Note that next/step/reverse-
>> {next/step} are line-oriented
>> stepping commands, they step/next until the previous/next line.
>> While "finish" is described
>> as undoing the _function call_.
>>
>> The manual says:
>>
>> reverse-finish
>> Just as the finish command takes you to the point where the current
>> function returns,
>> reverse-finish takes you to the point where it was called. Instead
>> of ending up at the end of
>> the current function invocation, you end up at the beginning.
>>
>> Say you have a line with multiple statements involving multiple
>> function calls.
>> The simplest would be:
>>
>> func1 (); func2 ();
>>
>> Say you'd stopped inside 'func2'. If you do finish there, in current
>> master gdb
>> stops at the call to 'func2', and you can then decide to reverse step
>> into 'func1'.
>
> I don't think you followed the issue.
Totally possible!
>
> So, if you are in func2 and do a reverse-finish, without the patch gdb
> stops on the last instruction for the line that calls func2.
Right.
> Now if
> you issue a reverse-step, you stop at the first instruction for the
> call to func2, i.e. you are still on the same source code line.
Wait. That right there sounds bogus. The source line looks like:
func1 (); func2 ();
so stepping backwards over that line should always stop at the first
instruction of the line, not in the middle. Let's simplify this.
Here's the full source code of my example:
(gdb) list 1
1 void func1 ()
2 {
3 }
4
5 void func2 ()
6 {
7 }
8
9 int main ()
10 {
11 func1 (); func2 ();
12 }
Compiled with:
$ gcc reverse.c -o reverse -g3 -O0
$ gcc -v
...
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
Now let's debug it with target record, using current gdb git master (f3d8ae90b236),
without your patch:
$ gdb ~/reverse
GNU gdb (GDB) 14.0.50.20230124-git
...
Reading symbols from /home/pedro/reverse...
(gdb) start
Temporary breakpoint 1 at 0x1147: file reverse.c, line 11.
Starting program: /home/pedro/reverse
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 1, main () at reverse.c:11
11 func1 (); func2 ();
(gdb) record
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x000055555555513f <+0>: endbr64
0x0000555555555143 <+4>: push %rbp
0x0000555555555144 <+5>: mov %rsp,%rbp
11 func1 (); func2 ();
=> 0x0000555555555147 <+8>: mov $0x0,%eax
0x000055555555514c <+13>: call 0x555555555129 <func1>
0x0000555555555151 <+18>: mov $0x0,%eax
0x0000555555555156 <+23>: call 0x555555555134 <func2>
0x000055555555515b <+28>: mov $0x0,%eax
12 }
0x0000555555555160 <+33>: pop %rbp
0x0000555555555161 <+34>: ret
End of assembler dump.
(gdb) n
12 }
So far so good, a "next" stepped over the whole of line 11 and stopped at line 12.
Let's confirm where we are now:
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x000055555555513f <+0>: endbr64
0x0000555555555143 <+4>: push %rbp
0x0000555555555144 <+5>: mov %rsp,%rbp
11 func1 (); func2 ();
0x0000555555555147 <+8>: mov $0x0,%eax
0x000055555555514c <+13>: call 0x555555555129 <func1>
0x0000555555555151 <+18>: mov $0x0,%eax
0x0000555555555156 <+23>: call 0x555555555134 <func2>
0x000055555555515b <+28>: mov $0x0,%eax
12 }
=> 0x0000555555555160 <+33>: pop %rbp
0x0000555555555161 <+34>: ret
End of assembler dump.
Good, we're at the first instruction of line 12.
Now let's undo the "next", with "reverse-next":
(gdb) reverse-next
11 func1 (); func2 ();
Seemingly stopped at line 11. Let's see exactly where:
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x000055555555513f <+0>: endbr64
0x0000555555555143 <+4>: push %rbp
0x0000555555555144 <+5>: mov %rsp,%rbp
11 func1 (); func2 ();
0x0000555555555147 <+8>: mov $0x0,%eax
0x000055555555514c <+13>: call 0x555555555129 <func1>
=> 0x0000555555555151 <+18>: mov $0x0,%eax
0x0000555555555156 <+23>: call 0x555555555134 <func2>
0x000055555555515b <+28>: mov $0x0,%eax
12 }
0x0000555555555160 <+33>: pop %rbp
0x0000555555555161 <+34>: ret
End of assembler dump.
(gdb)
And lo, we stopped in the middle of line 11! That is a bug, we should have stepped
back all the way to the beginning of the line. The "reverse-next" should have fully
undone the prior "next" command. Here's the same thing without the distracting
disassemble commands:
(gdb) b 11
Breakpoint 1 at 0x1147: file reverse.c, line 11.
(gdb) r
Starting program: /home/pedro/reverse
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at reverse.c:11
11 func1 (); func2 ();
(gdb) p $pc
$1 = (void (*)()) 0x555555555147 <main+8>
(gdb) record
(gdb) next
12 }
(gdb) reverse-next
11 func1 (); func2 ();
(gdb) p $pc
$2 = (void (*)()) 0x555555555151 <main+18>
(gdb)
This:
next -> reverse-next -> next -> reverse-next
... should leave you at the same instruction. But it doesn't in this example!
How does this happen? Let's look at the line table as seen by GDB:
(gdb) maint info line-table reverse.c
objfile: /home/pedro/reverse ((struct objfile *) 0x55dd5df77c50)
compunit_symtab: reverse.c ((struct compunit_symtab *) 0x55dd5de6b2e0)
symtab: /home/pedro/reverse.c ((struct symtab *) 0x55dd5de6b360)
linetable: ((struct linetable *) 0x55dd5dfd3290):
INDEX LINE ADDRESS IS-STMT PROLOGUE-END
0 2 0x0000555555555129 Y
1 3 0x0000555555555131 Y
2 6 0x0000555555555134 Y
3 7 0x000055555555513c Y
4 10 0x000055555555513f Y
5 11 0x0000555555555147 Y <<< here
6 11 0x0000555555555151 Y <<< here
7 12 0x0000555555555160 Y
8 END 0x0000555555555162 Y
Ah, there are two entries for line 11, both marked with IS-STMT. So when
stepping backward GDB only considered the region with index 6, that's why it
stopped at 0x0000555555555151.
Let's look at what we get with clang instead (Ubuntu clang version 14.0.0-1ubuntu1) :
(gdb) maintenance info line-table reverse.c
objfile: /home/pedro/reverse.clang ((struct objfile *) 0x5576be591ca0)
compunit_symtab: reverse.c ((struct compunit_symtab *) 0x5576be485300)
symtab: /home/pedro/reverse.c ((struct symtab *) 0x5576be485380)
linetable: ((struct linetable *) 0x5576be5ec8e0):
INDEX LINE ADDRESS IS-STMT PROLOGUE-END
0 2 0x0000555555555130 Y
1 3 0x0000555555555134 Y Y
2 6 0x0000555555555140 Y
3 7 0x0000555555555144 Y Y
4 10 0x0000555555555150 Y
5 11 0x0000555555555154 Y Y
6 11 0x0000555555555159
7 12 0x000055555555515e Y
8 END 0x0000555555555162 Y
Note no IS-STMT for the second range. And let's look at how GDB behaves with it:
(gdb) b 11
Breakpoint 1 at 0x1154: file reverse.c, line 11.
(gdb) r
Starting program: /home/pedro/reverse.clang
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main () at reverse.c:11
11 func1 (); func2 ();
(gdb) record
(gdb) p $pc
$1 = (void (*)()) 0x555555555154 <main+4>
(gdb) n
12 }
(gdb) reverse-next
No more reverse-execution history.
main () at reverse.c:11
11 func1 (); func2 ();
(gdb) p $pc
$2 = (void (*)()) 0x555555555154 <main+4>
(gdb)
Bingo. reverse-next fully stepped the whole line backwards.
> You
> have not stepped back into func1 like you wanted to. Now you have to
> issue a second reverse-step to get into func1. With the patch, you
> issue the reverse-finish from func2 and stop at the first instruction
> in the line that calls func2. Now when you issue the reverse-step you
> step back into func1 as expected.
>
So this fix is assuming that the reverse step stops in the middle of a
line, which I think is the real bug to fix. Once that is fixed, then
you will no longer need two reverse-steps after reverse-finish.
Here's what you get with current master without your patch, but using
the test program compiled with clang. Actually, let's use a slightly
modified program to force clang to emit some instructions between
the two calls. Like this:
$ cat reverse.c
void func1 (int i)
{
}
void func2 (int i)
{
}
int main (int argc, char **argv)
{
func1 (argc); func2 (argc);
}
Alright, here's the gdb session, with clang, no gdb patch:
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
11 func1 (argc); func2 (argc);
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x0000555555555150 <+0>: push %rbp
0x0000555555555151 <+1>: mov %rsp,%rbp
0x0000555555555154 <+4>: sub $0x10,%rsp
0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
11 func1 (argc); func2 (argc);
=> 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
0x0000555555555162 <+18>: call 0x555555555130 <func1>
0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
0x000055555555516a <+26>: call 0x555555555140 <func2>
12 }
0x000055555555516f <+31>: xor %eax,%eax
0x0000555555555171 <+33>: add $0x10,%rsp
0x0000555555555175 <+37>: pop %rbp
0x0000555555555176 <+38>: ret
End of assembler dump.
(gdb) record
(gdb) b func2
Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
(gdb) c
Continuing.
Breakpoint 2, func2 (i=1) at reverse.c:7
7 }
(gdb) reverse-finish
Run back to call of #0 func2 (i=1) at reverse.c:7
0x000055555555516a in main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
11 func1 (argc); func2 (argc);
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x0000555555555150 <+0>: push %rbp
0x0000555555555151 <+1>: mov %rsp,%rbp
0x0000555555555154 <+4>: sub $0x10,%rsp
0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
11 func1 (argc); func2 (argc);
0x000055555555515f <+15>: mov -0x4(%rbp),%edi
0x0000555555555162 <+18>: call 0x555555555130 <func1>
0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
=> 0x000055555555516a <+26>: call 0x555555555140 <func2>
12 }
0x000055555555516f <+31>: xor %eax,%eax
0x0000555555555171 <+33>: add $0x10,%rsp
0x0000555555555175 <+37>: pop %rbp
0x0000555555555176 <+38>: ret
End of assembler dump.
(gdb) reverse-step
func1 (i=1) at reverse.c:3
3 }
(gdb)
Note how a single reverse-step after the reverse-finish immediately
stepped backwards into func1. Exactly how I describing it originally.
With your patch, you'd break reverse-finish with clang:
(gdb) record
(gdb) b func2
Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
(gdb) c
Continuing.
Breakpoint 2, func2 (i=1) at reverse.c:7
7 }
(gdb) reverse-finish
Run back to call of #0 func2 (i=1) at reverse.c:7
func1 (i=1) at reverse.c:3
3 }
(gdb)
GDB stopped at line 3, info func1 which means it stepped too far without
stopping at func2's call site.
GDB is misbehaving with GCC's debug info. I suspect the reason we get
the two line entries for line 11 and both with IS-STMT is because GCC emits
column debug info nowadays by default. Here's what e.g.,
"llvm-dwarfdump --debug-line reverse" shows:
~~~
Address Line Column File ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000001129 2 1 1 0 0 is_stmt
0x0000000000001131 3 1 1 0 0 is_stmt
0x0000000000001134 6 1 1 0 0 is_stmt
0x000000000000113c 7 1 1 0 0 is_stmt
0x000000000000113f 10 1 1 0 0 is_stmt
0x0000000000001147 11 3 1 0 0 is_stmt
0x0000000000001151 11 13 1 0 0 is_stmt
0x0000000000001160 12 1 1 0 0 is_stmt
0x0000000000001162 12 1 1 0 0 is_stmt end_sequence
~~~
We can try disabling that with -gno-column-info, let's see what we get:
(gdb) maint info line-table reverse.c
objfile: /home/pedro/reverse.nocol ((struct objfile *) 0x5611464f6c10)
compunit_symtab: reverse.c ((struct compunit_symtab *) 0x5611463ea2e0)
symtab: /home/pedro/reverse.c ((struct symtab *) 0x5611463ea360)
linetable: ((struct linetable *) 0x561146474c80):
INDEX LINE ADDRESS IS-STMT PROLOGUE-END
0 2 0x0000555555555129 Y
1 3 0x0000555555555134 Y
2 6 0x0000555555555137 Y
3 7 0x0000555555555142 Y
4 10 0x0000555555555145 Y
5 11 0x0000555555555158 Y
6 12 0x0000555555555171 Y
7 END 0x0000555555555173 Y
(gdb)
... and in llvm-dwarfdump:
Address Line Column File ISA Discriminator Flags
------------------ ------ ------ ------ --- ------------- -------------
0x0000000000001129 2 0 1 0 0 is_stmt
0x0000000000001134 3 0 1 0 0 is_stmt
0x0000000000001137 6 0 1 0 0 is_stmt
0x0000000000001142 7 0 1 0 0 is_stmt
0x0000000000001145 10 0 1 0 0 is_stmt
0x0000000000001158 11 0 1 0 0 is_stmt
0x0000000000001171 12 0 1 0 0 is_stmt
0x0000000000001173 12 0 1 0 0 is_stmt end_sequence
Bingo. With no column info, only one entry for line 11.
Pedro Alves
>> While with your change, reverse-finish in func2 will make gdb stop at
>> the beginning
>> of the line, before the call to func1.
>>
>> Thus I'm really not convinced (yet) this change is a good one. It
>> removes
>> a user choice. You can always do reverse-next/step do get what you
>> want
>> reverse-finish do to, already.
>
> Carl
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 14:08 ` Pedro Alves
@ 2023-01-24 14:23 ` Bruno Larsen
2023-01-24 15:06 ` Pedro Alves
2023-01-24 15:51 ` Carl Love
` (2 subsequent siblings)
3 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-24 14:23 UTC (permalink / raw)
To: Pedro Alves, Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 24/01/2023 15:08, Pedro Alves wrote:
> On 2023-01-23 9:13 p.m., Carl Love wrote:
>> Pedro:
>>
>> On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
>>>> Currently on X86, when executing the finish command in reverse, gdb
>>>> does a
>>>> single step from the first instruction in the callee to get back to
>>>> the
>>>> caller. GDB stops on the last instruction in the source code line
>>>> where
>>>> the call was made. When stopped at the last instruction of the
>>>> source code
>>>> line, a reverse next or step command will stop at the first
>>>> instruction
>>>> of the same source code line thus requiring two step/next commands
>>>> to
>>>> reach the previous source code line. It should only require one
>>>> step/next
>>>> command to reach the previous source code line.
>>>>
>>>> By contrast, a reverse next or step command from the first line in
>>>> a
>>>> function stops at the first instruction in the source code line
>>>> where the
>>>> call was made.
>>> I'd think this was on purpose. Note that next/step/reverse-
>>> {next/step} are line-oriented
>>> stepping commands, they step/next until the previous/next line.
>>> While "finish" is described
>>> as undoing the _function call_.
>>>
>>> The manual says:
>>>
>>> reverse-finish
>>> Just as the finish command takes you to the point where the current
>>> function returns,
>>> reverse-finish takes you to the point where it was called. Instead
>>> of ending up at the end of
>>> the current function invocation, you end up at the beginning.
>>>
>>> Say you have a line with multiple statements involving multiple
>>> function calls.
>>> The simplest would be:
>>>
>>> func1 (); func2 ();
>>>
>>> Say you'd stopped inside 'func2'. If you do finish there, in current
>>> master gdb
>>> stops at the call to 'func2', and you can then decide to reverse step
>>> into 'func1'.
>> I don't think you followed the issue.
> Totally possible!
>
>> So, if you are in func2 and do a reverse-finish, without the patch gdb
>> stops on the last instruction for the line that calls func2.
> Right.
>
>> Now if
>> you issue a reverse-step, you stop at the first instruction for the
>> call to func2, i.e. you are still on the same source code line.
> Wait. That right there sounds bogus. The source line looks like:
>
> func1 (); func2 ();
>
> so stepping backwards over that line should always stop at the first
> instruction of the line, not in the middle. Let's simplify this.
>
> Here's the full source code of my example:
>
> (gdb) list 1
> 1 void func1 ()
> 2 {
> 3 }
> 4
> 5 void func2 ()
> 6 {
> 7 }
> 8
> 9 int main ()
> 10 {
> 11 func1 (); func2 ();
> 12 }
>
I think you are describing a different issue to what Carl is trying to
solve. Using your example code, I have the following debugging session:
$ ./gdb -q reverse
Reading symbols from reverse...
(gdb) start
Temporary breakpoint 1 at 0x401118: file t.c, line 8.
Starting program: /home/blarsen/Documents/build/gdb/reverse
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Temporary breakpoint 1, main () at t.c:8
8 func1(); func2();
(gdb) record
(gdb) n
9 }
(gdb) rs
func2 () at t.c:5
5 }
(gdb) reverse-finish
Run back to call of #0 func2 () at t.c:5
0x0000000000401127 in main () at t.c:8
8 func1(); func2();
(gdb) rs
8 func1(); func2();
(gdb)
func1 () at t.c:2
2 }
(gdb)
Notice how there were two "reverse-step" commands needed after the
"reverse-finish" used to exit func2. What Carl is proposing we do is
make it so GDB only needs one command. If I compare the $pc of where GDB
is stopped and the linetable, we get:
(gdb) print $pc
$2 = (void (*)()) 0x401127 <main+19>
(gdb) maint info line-table
objfile: /home/blarsen/Documents/downstream_build/gdb/reverse ((struct
objfile *) 0x10f7750)
compunit_symtab: t.c ((struct compunit_symtab *) 0x116c330)
symtab: /home/blarsen/Documents/downstream_build/gdb/t.c ((struct symtab
*) 0x116c3b0)
linetable: ((struct linetable *) 0x11aec80):
INDEX LINE ADDRESS IS-STMT PROLOGUE-END
0 1 0x0000000000401106 Y
1 2 0x000000000040110a Y
2 4 0x000000000040110d Y
3 5 0x0000000000401111 Y
4 7 0x0000000000401114 Y
5 8 0x0000000000401118 Y
6 8 0x0000000000401122 Y
7 9 0x0000000000401131 Y
8 END 0x0000000000401133 Y
We can see that GDB shouldn't even be able to stop at that $pc, it isn't
an is_stmt. We should have stopped at 0x401122, which is where the first
reverse-step stops:
(gdb) rs
8 f1(); f2();
(gdb) p $pc
$4 = (void (*)()) 0x401122 <main+14>
So not only are we needing an extra command to re-sync with user
expectations, we are in an instruction where the inferior state might be
all over the place.
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 14:23 ` Bruno Larsen
@ 2023-01-24 15:06 ` Pedro Alves
2023-01-24 16:04 ` Bruno Larsen
0 siblings, 1 reply; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 15:06 UTC (permalink / raw)
To: Bruno Larsen, Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 2023-01-24 2:23 p.m., Bruno Larsen wrote:
> On 24/01/2023 15:08, Pedro Alves wrote:
>> On 2023-01-23 9:13 p.m., Carl Love wrote:
>>> Pedro:
>>>
>>> On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
>>>>> Currently on X86, when executing the finish command in reverse, gdb
>>>>> does a
>>>>> single step from the first instruction in the callee to get back to
>>>>> the
>>>>> caller. GDB stops on the last instruction in the source code line
>>>>> where
>>>>> the call was made. When stopped at the last instruction of the
>>>>> source code
>>>>> line, a reverse next or step command will stop at the first
>>>>> instruction
>>>>> of the same source code line thus requiring two step/next commands
>>>>> to
>>>>> reach the previous source code line. It should only require one
>>>>> step/next
>>>>> command to reach the previous source code line.
>>>>>
>>>>> By contrast, a reverse next or step command from the first line in
>>>>> a
>>>>> function stops at the first instruction in the source code line
>>>>> where the
>>>>> call was made.
>>>> I'd think this was on purpose. Note that next/step/reverse-
>>>> {next/step} are line-oriented
>>>> stepping commands, they step/next until the previous/next line.
>>>> While "finish" is described
>>>> as undoing the _function call_.
>>>>
>>>> The manual says:
>>>>
>>>> reverse-finish
>>>> Just as the finish command takes you to the point where the current
>>>> function returns,
>>>> reverse-finish takes you to the point where it was called. Instead
>>>> of ending up at the end of
>>>> the current function invocation, you end up at the beginning.
>>>>
>>>> Say you have a line with multiple statements involving multiple
>>>> function calls.
>>>> The simplest would be:
>>>>
>>>> func1 (); func2 ();
>>>>
>>>> Say you'd stopped inside 'func2'. If you do finish there, in current
>>>> master gdb
>>>> stops at the call to 'func2', and you can then decide to reverse step
>>>> into 'func1'.
>>> I don't think you followed the issue.
>> Totally possible!
>>
>>> So, if you are in func2 and do a reverse-finish, without the patch gdb
>>> stops on the last instruction for the line that calls func2.
>> Right.
>>
>>> Now if
>>> you issue a reverse-step, you stop at the first instruction for the
>>> call to func2, i.e. you are still on the same source code line.
>> Wait. That right there sounds bogus. The source line looks like:
>>
>> func1 (); func2 ();
>>
>> so stepping backwards over that line should always stop at the first
>> instruction of the line, not in the middle. Let's simplify this.
>>
>> Here's the full source code of my example:
>>
>> (gdb) list 1
>> 1 void func1 ()
>> 2 {
>> 3 }
>> 4
>> 5 void func2 ()
>> 6 {
>> 7 }
>> 8
>> 9 int main ()
>> 10 {
>> 11 func1 (); func2 ();
>> 12 }
>>
> I think you are describing a different issue to what Carl is trying to solve. Using your example code, I have the following debugging session:
No, it's the exact same. Please re-read.
>
> $ ./gdb -q reverse
> Reading symbols from reverse...
> (gdb) start
> Temporary breakpoint 1 at 0x401118: file t.c, line 8.
> Starting program: /home/blarsen/Documents/build/gdb/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib64/libthread_db.so.1".
>
> Temporary breakpoint 1, main () at t.c:8
> 8 func1(); func2();
> (gdb) record
> (gdb) n
> 9 }
> (gdb) rs
> func2 () at t.c:5
> 5 }
> (gdb) reverse-finish
> Run back to call of #0 func2 () at t.c:5
> 0x0000000000401127 in main () at t.c:8
> 8 func1(); func2();
> (gdb) rs
> 8 func1(); func2();
> (gdb)
> func1 () at t.c:2
> 2 }
> (gdb)
>
> Notice how there were two "reverse-step" commands needed after the "reverse-finish" used to exit func2.
Yes. And the reason you need two "reverse-step" is because there are two line ranges for line 8, and reverse-step stops
at the beginning of the second range instead of at the beginning of the first. It's the exact same as with my simpler
example of just doing "next" -> "reverse-next", which I used as a simpler example to explain the problem.
> What Carl is proposing we do is make it so GDB only needs one command.
I understand. However, I am saying that that is papering over the actual problem, _and_ it only works in the situation
where you ended up with two line entries with is-stmt for the same line. Note how the patch breaks clang, and gcc with
-gno-column-info...
> If I compare the $pc of where GDB is stopped and the linetable, we get:
>
> (gdb) print $pc
> $2 = (void (*)()) 0x401127 <main+19>
> (gdb) maint info line-table
> objfile: /home/blarsen/Documents/downstream_build/gdb/reverse ((struct objfile *) 0x10f7750)
> compunit_symtab: t.c ((struct compunit_symtab *) 0x116c330)
> symtab: /home/blarsen/Documents/downstream_build/gdb/t.c ((struct symtab *) 0x116c3b0)
> linetable: ((struct linetable *) 0x11aec80):
> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
> 0 1 0x0000000000401106 Y
> 1 2 0x000000000040110a Y
> 2 4 0x000000000040110d Y
> 3 5 0x0000000000401111 Y
> 4 7 0x0000000000401114 Y
> 5 8 0x0000000000401118 Y
> 6 8 0x0000000000401122 Y
> 7 9 0x0000000000401131 Y
> 8 END 0x0000000000401133 Y
>
> We can see that GDB shouldn't even be able to stop at that $pc, it isn't an is_stmt.
reverse-finish is not supposed to step backwards until it reaches is_stmt. Doing so makes it
step backwards too much, as I've shown in my previous example.
> We should have stopped at 0x401122, which is where the first reverse-step stops:
No...
>
> (gdb) rs
> 8 f1(); f2();
> (gdb) p $pc
> $4 = (void (*)()) 0x401122 <main+14>
... no because in the case where you don't have column debug info (or with clang), there won't be
an is-stmt entry for the f2 call/column, there will only be one single line entry for the whole of
line 8, so gdb would step back too much.
>
> So not only are we needing an extra command to re-sync with user expectations, we are in an instruction where the inferior state might be all over the place.
>
What does that mean, the state might be all over the place? The DWARF should describe the locations of all variables accurately at all instructions.
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 14:08 ` Pedro Alves
2023-01-24 14:23 ` Bruno Larsen
@ 2023-01-24 15:51 ` Carl Love
2023-01-24 18:37 ` Pedro Alves
2023-01-24 18:25 ` Carl Love
2023-01-31 0:17 ` Reverse-next bug test case Carl Love
3 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-24 15:51 UTC (permalink / raw)
To: Pedro Alves, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
Cc: Luis Machado, cel
Pedro:
On Tue, 2023-01-24 at 14:08 +0000, Pedro Alves wrote:
> On 2023-01-23 9:13 p.m., Carl Love wrote:
> > Pedro:
> >
> > On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
> > > > Currently on X86, when executing the finish command in reverse,
> > > > gdb
> > > > does a
> > > > single step from the first instruction in the callee to get
> > > > back to
> > > > the
> > > > caller. GDB stops on the last instruction in the source code
> > > > line
> > > > where
> > > > the call was made. When stopped at the last instruction of the
> > > > source code
> > > > line, a reverse next or step command will stop at the first
> > > > instruction
> > > > of the same source code line thus requiring two step/next
> > > > commands
> > > > to
> > > > reach the previous source code line. It should only require
> > > > one
> > > > step/next
> > > > command to reach the previous source code line.
> > > >
> > > > By contrast, a reverse next or step command from the first line
> > > > in
> > > > a
> > > > function stops at the first instruction in the source code line
> > > > where the
> > > > call was made.
> > >
> > > I'd think this was on purpose. Note that next/step/reverse-
> > > {next/step} are line-oriented
> > > stepping commands, they step/next until the previous/next line.
> > > While "finish" is described
> > > as undoing the _function call_.
> > >
> > > The manual says:
> > >
> > > reverse-finish
> > > Just as the finish command takes you to the point where the
> > > current
> > > function returns,
> > > reverse-finish takes you to the point where it was called.
> > > Instead
> > > of ending up at the end of
> > > the current function invocation, you end up at the beginning.
> > >
> > > Say you have a line with multiple statements involving multiple
> > > function calls.
> > > The simplest would be:
> > >
> > > func1 (); func2 ();
> > >
> > > Say you'd stopped inside 'func2'. If you do finish there, in
> > > current
> > > master gdb
> > > stops at the call to 'func2', and you can then decide to reverse
> > > step
> > > into 'func1'.
> >
> > I don't think you followed the issue.
>
> Totally possible!
>
> > So, if you are in func2 and do a reverse-finish, without the patch
> > gdb
> > stops on the last instruction for the line that calls func2.
>
> Right.
>
> > Now if
> > you issue a reverse-step, you stop at the first instruction for the
> > call to func2, i.e. you are still on the same source code line.
>
> Wait. That right there sounds bogus. The source line looks like:
>
> func1 (); func2 ();
My bad, I didn't catch that you were implying func1 and func2 as being
on the same source line. There is an existing bugzilla for the case of
multiple executable statements on the same line.
https://sourceware.org/bugzilla/show_bug.cgi?id=28426
I have worked with Luis Machado <luis.machado@arm.com> on a patch to
address that issue. We have posted a few versions of the patch but it
still needs some work for finish. I wanted to get back to that patch
once the reverse-finish issue is done.
I need to spend some more time looking at the rest of your response to
understand everything you are talking about. That said, my first read
looked like the issue in the bugzilla I mentioned. The patch Luis and
I have for addressing multiple statements on the same line applies on
top of the X86 and PowerPC reverse-finish patches.
Let me spend some more time looking at your response. Thanks.
Carl
>
> so stepping backwards over that line should always stop at the first
> instruction of the line, not in the middle. Let's simplify this.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-23 19:17 ` Pedro Alves
2023-01-23 21:13 ` Carl Love
@ 2023-01-24 15:53 ` Tom de Vries
2023-01-24 18:48 ` Pedro Alves
1 sibling, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-01-24 15:53 UTC (permalink / raw)
To: Pedro Alves, Carl Love, Bruno Larsen, Ulrich Weigand,
will_schmidt, gdb-patches
On 1/23/23 20:17, Pedro Alves wrote:
> I'd think this was on purpose. Note that next/step/reverse-{next/step} are line-oriented
> stepping commands, they step/next until the previous/next line. While "finish" is described
> as undoing the_function call_.
>
> The manual says:
>
> reverse-finish
> Just as the finish command takes you to the point where the current function returns,
> reverse-finish takes you to the point where it was called. Instead of ending up at the end of
> the current function invocation, you end up at the beginning.
As well as:
...
finish
Continue running until just after function in the selected stack frame
returns. Print the returned value (if any). This command can be
abbreviated as fin.
...
It's only now that you mention the non-line nature of
finish/reverse-finish that I realize that that is the case. So I
suppose the docs could be a bit more explicit about this aspect.
I suppose an intuitive way to make available the two approaches (so
without the user losing options) would be to introduce finishi next to
finish and reverse-finishi next to finish, with the new commands
retaining the current functionality and the old ones being adjusted to
respect line boundaries. But having the commands change behaviour is
likely to cause confusion (well, assuming users notice the difference in
the first place), so I'm not sure if that's a good idea.
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 15:06 ` Pedro Alves
@ 2023-01-24 16:04 ` Bruno Larsen
2023-01-24 19:12 ` Pedro Alves
0 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-01-24 16:04 UTC (permalink / raw)
To: Pedro Alves, Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 24/01/2023 16:06, Pedro Alves wrote:
> On 2023-01-24 2:23 p.m., Bruno Larsen wrote:
>> On 24/01/2023 15:08, Pedro Alves wrote:
>>> On 2023-01-23 9:13 p.m., Carl Love wrote:
>>>> Pedro:
>>>>
>>>> On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
>>>>>> Currently on X86, when executing the finish command in reverse, gdb
>>>>>> does a
>>>>>> single step from the first instruction in the callee to get back to
>>>>>> the
>>>>>> caller. GDB stops on the last instruction in the source code line
>>>>>> where
>>>>>> the call was made. When stopped at the last instruction of the
>>>>>> source code
>>>>>> line, a reverse next or step command will stop at the first
>>>>>> instruction
>>>>>> of the same source code line thus requiring two step/next commands
>>>>>> to
>>>>>> reach the previous source code line. It should only require one
>>>>>> step/next
>>>>>> command to reach the previous source code line.
>>>>>>
>>>>>> By contrast, a reverse next or step command from the first line in
>>>>>> a
>>>>>> function stops at the first instruction in the source code line
>>>>>> where the
>>>>>> call was made.
>>>>> I'd think this was on purpose. Note that next/step/reverse-
>>>>> {next/step} are line-oriented
>>>>> stepping commands, they step/next until the previous/next line.
>>>>> While "finish" is described
>>>>> as undoing the _function call_.
>>>>>
>>>>> The manual says:
>>>>>
>>>>> reverse-finish
>>>>> Just as the finish command takes you to the point where the current
>>>>> function returns,
>>>>> reverse-finish takes you to the point where it was called. Instead
>>>>> of ending up at the end of
>>>>> the current function invocation, you end up at the beginning.
>>>>>
>>>>> Say you have a line with multiple statements involving multiple
>>>>> function calls.
>>>>> The simplest would be:
>>>>>
>>>>> func1 (); func2 ();
>>>>>
>>>>> Say you'd stopped inside 'func2'. If you do finish there, in current
>>>>> master gdb
>>>>> stops at the call to 'func2', and you can then decide to reverse step
>>>>> into 'func1'.
>>>> I don't think you followed the issue.
>>> Totally possible!
>>>
>>>> So, if you are in func2 and do a reverse-finish, without the patch gdb
>>>> stops on the last instruction for the line that calls func2.
>>> Right.
>>>
>>>> Now if
>>>> you issue a reverse-step, you stop at the first instruction for the
>>>> call to func2, i.e. you are still on the same source code line.
>>> Wait. That right there sounds bogus. The source line looks like:
>>>
>>> func1 (); func2 ();
>>>
>>> so stepping backwards over that line should always stop at the first
>>> instruction of the line, not in the middle. Let's simplify this.
>>>
>>> Here's the full source code of my example:
>>>
>>> (gdb) list 1
>>> 1 void func1 ()
>>> 2 {
>>> 3 }
>>> 4
>>> 5 void func2 ()
>>> 6 {
>>> 7 }
>>> 8
>>> 9 int main ()
>>> 10 {
>>> 11 func1 (); func2 ();
>>> 12 }
>>>
>> I think you are describing a different issue to what Carl is trying to solve. Using your example code, I have the following debugging session:
> No, it's the exact same. Please re-read.
>
>> $ ./gdb -q reverse
>> Reading symbols from reverse...
>> (gdb) start
>> Temporary breakpoint 1 at 0x401118: file t.c, line 8.
>> Starting program: /home/blarsen/Documents/build/gdb/reverse
>> [Thread debugging using libthread_db enabled]
>> Using host libthread_db library "/lib64/libthread_db.so.1".
>>
>> Temporary breakpoint 1, main () at t.c:8
>> 8 func1(); func2();
>> (gdb) record
>> (gdb) n
>> 9 }
>> (gdb) rs
>> func2 () at t.c:5
>> 5 }
>> (gdb) reverse-finish
>> Run back to call of #0 func2 () at t.c:5
>> 0x0000000000401127 in main () at t.c:8
>> 8 func1(); func2();
>> (gdb) rs
>> 8 func1(); func2();
>> (gdb)
>> func1 () at t.c:2
>> 2 }
>> (gdb)
>>
>> Notice how there were two "reverse-step" commands needed after the "reverse-finish" used to exit func2.
> Yes. And the reason you need two "reverse-step" is because there are two line ranges for line 8, and reverse-step stops
> at the beginning of the second range instead of at the beginning of the first. It's the exact same as with my simpler
> example of just doing "next" -> "reverse-next", which I used as a simpler example to explain the problem.
The simplified example is not the exact same use case. Looking at how
the program executes forward, if we next over this line we skip
everything, but if we step into func1 and use finish we will still stop
in line 11 and the user can decide to step into func2 or not. That is
why I assumed you were thinking of a different issue when I saw you
using next and reverse-next as examples.
Looking at where GDB lands when finishing from func1 we get (code
compiled with gcc -gno-column-info):
(gdb) start
Temporary breakpoint 1 at 0x401118: file t.c, line 8.
Starting program: /home/blarsen/Documents/downstream_build/gdb/reverse
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Temporary breakpoint 1, main () at t.c:8
8 f1(); f2();
(gdb) s
f1 () at t.c:2
2 }
(gdb) finish
Run till exit from #0 f1 () at t.c:2
0x0000000000401122 in main () at t.c:8
8 f1(); f2();
(gdb) disas /s
Dump of assembler code for function main:
t.c:
7 int main(){
0x0000000000401114 <+0>: push %rbp
0x0000000000401115 <+1>: mov %rsp,%rbp
8 f1(); f2();
0x0000000000401118 <+4>: mov $0x0,%eax
0x000000000040111d <+9>: call 0x401106 <f1>
=> 0x0000000000401122 <+14>: mov $0x0,%eax
0x0000000000401127 <+19>: call 0x40110d <f2>
0x000000000040112c <+24>: mov $0x0,%eax
9 }
0x0000000000401131 <+29>: pop %rbp
0x0000000000401132 <+30>: ret
End of assembler dump.
The behavior that we should emulate when going backwards is that
finishing from func2 stops us on the 'mov' instruction between the
calls. Looking at the clang session that I cut off from the previous email:
Alright, here's the gdb session, with clang, no gdb patch:
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
11 func1 (argc); func2 (argc);
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x0000555555555150 <+0>: push %rbp
0x0000555555555151 <+1>: mov %rsp,%rbp
0x0000555555555154 <+4>: sub $0x10,%rsp
0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
11 func1 (argc); func2 (argc);
=> 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
0x0000555555555162 <+18>: call 0x555555555130 <func1>
0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
0x000055555555516a <+26>: call 0x555555555140 <func2>
12 }
0x000055555555516f <+31>: xor %eax,%eax
0x0000555555555171 <+33>: add $0x10,%rsp
0x0000555555555175 <+37>: pop %rbp
0x0000555555555176 <+38>: ret
End of assembler dump.
(gdb) record
(gdb) b func2
Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
(gdb) c
Continuing.
Breakpoint 2, func2 (i=1) at reverse.c:7
7 }
(gdb) reverse-finish
Run back to call of #0 func2 (i=1) at reverse.c:7
0x000055555555516a in main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
11 func1 (argc); func2 (argc);
(gdb) disassemble /s
Dump of assembler code for function main:
reverse.c:
10 {
0x0000555555555150 <+0>: push %rbp
0x0000555555555151 <+1>: mov %rsp,%rbp
0x0000555555555154 <+4>: sub $0x10,%rsp
0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
11 func1 (argc); func2 (argc);
0x000055555555515f <+15>: mov -0x4(%rbp),%edi
0x0000555555555162 <+18>: call 0x555555555130 <func1>
0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
=> 0x000055555555516a <+26>: call 0x555555555140 <func2>
12 }
0x000055555555516f <+31>: xor %eax,%eax
0x0000555555555171 <+33>: add $0x10,%rsp
0x0000555555555175 <+37>: pop %rbp
0x0000555555555176 <+38>: ret
End of assembler dump.
(gdb) reverse-step
func1 (i=1) at reverse.c:3
3 }
(gdb)
We can see that GDB stopped on the call instruction instead. So a user
that finished from func1 or reverse-finished from func2 may see
different inferior states.
>
>> What Carl is proposing we do is make it so GDB only needs one command.
> I understand. However, I am saying that that is papering over the actual problem, _and_ it only works in the situation
> where you ended up with two line entries with is-stmt for the same line. Note how the patch breaks clang, and gcc with
> -gno-column-info...
>
>> If I compare the $pc of where GDB is stopped and the linetable, we get:
>>
>> (gdb) print $pc
>> $2 = (void (*)()) 0x401127 <main+19>
>> (gdb) maint info line-table
>> objfile: /home/blarsen/Documents/downstream_build/gdb/reverse ((struct objfile *) 0x10f7750)
>> compunit_symtab: t.c ((struct compunit_symtab *) 0x116c330)
>> symtab: /home/blarsen/Documents/downstream_build/gdb/t.c ((struct symtab *) 0x116c3b0)
>> linetable: ((struct linetable *) 0x11aec80):
>> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
>> 0 1 0x0000000000401106 Y
>> 1 2 0x000000000040110a Y
>> 2 4 0x000000000040110d Y
>> 3 5 0x0000000000401111 Y
>> 4 7 0x0000000000401114 Y
>> 5 8 0x0000000000401118 Y
>> 6 8 0x0000000000401122 Y
>> 7 9 0x0000000000401131 Y
>> 8 END 0x0000000000401133 Y
>>
>> We can see that GDB shouldn't even be able to stop at that $pc, it isn't an is_stmt.
> reverse-finish is not supposed to step backwards until it reaches is_stmt. Doing so makes it
> step backwards too much, as I've shown in my previous example.
>
>> We should have stopped at 0x401122, which is where the first reverse-step stops:
> No...
>
>> (gdb) rs
>> 8 f1(); f2();
>> (gdb) p $pc
>> $4 = (void (*)()) 0x401122 <main+14>
> ... no because in the case where you don't have column debug info (or with clang), there won't be
> an is-stmt entry for the f2 call/column, there will only be one single line entry for the whole of
> line 8, so gdb would step back too much.
>
>> So not only are we needing an extra command to re-sync with user expectations, we are in an instruction where the inferior state might be all over the place.
>>
> What does that mean, the state might be all over the place? The DWARF should describe the locations of all variables accurately at all instructions.
>
Unrelated to this specific issue, but I was looking at record/30025
(https://sourceware.org/bugzilla/show_bug.cgi?id=30025) and it confused
me because because GDB sometimes reported the incorrect parameter, but
if we continue single-stepping through instructions, GDB eventually
finds the correct value when we stop at an is_stmt instruction.
If I misunderstood something about 30025 and is_stmt, please let me
know! but as far as I can see, this is what happened.
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 14:08 ` Pedro Alves
2023-01-24 14:23 ` Bruno Larsen
2023-01-24 15:51 ` Carl Love
@ 2023-01-24 18:25 ` Carl Love
2023-01-24 19:21 ` Pedro Alves
2023-01-31 0:17 ` Reverse-next bug test case Carl Love
3 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-24 18:25 UTC (permalink / raw)
To: Pedro Alves, Bruno Larsen, Ulrich Weigand, gdb-patches; +Cc: Luis Machado, cel
Pedro:
On Tue, 2023-01-24 at 14:08 +0000, Pedro Alves wrote:
> On 2023-01-23 9:13 p.m., Carl Love wrote:
> > Pedro:
> >
> > On Mon, 2023-01-23 at 19:17 +0000, Pedro Alves wrote:
> > > > Currently on X86, when executing the finish command in reverse,
> > > > gdb
> > > > does a
> > > > single step from the first instruction in the callee to get
> > > > back to
> > > > the
> > > > caller. GDB stops on the last instruction in the source code
> > > > line
> > > > where
> > > > the call was made. When stopped at the last instruction of the
> > > > source code
> > > > line, a reverse next or step command will stop at the first
> > > > instruction
> > > > of the same source code line thus requiring two step/next
> > > > commands
> > > > to
> > > > reach the previous source code line. It should only require
> > > > one
> > > > step/next
> > > > command to reach the previous source code line.
> > > >
> > > > By contrast, a reverse next or step command from the first line
> > > > in
> > > > a
> > > > function stops at the first instruction in the source code line
> > > > where the
> > > > call was made.
> > >
> > > I'd think this was on purpose. Note that next/step/reverse-
> > > {next/step} are line-oriented
> > > stepping commands, they step/next until the previous/next line.
> > > While "finish" is described
> > > as undoing the _function call_.
> > >
> > > The manual says:
> > >
> > > reverse-finish
> > > Just as the finish command takes you to the point where the
> > > current
> > > function returns,
> > > reverse-finish takes you to the point where it was called.
> > > Instead
> > > of ending up at the end of
> > > the current function invocation, you end up at the beginning.
> > >
> > > Say you have a line with multiple statements involving multiple
> > > function calls.
> > > The simplest would be:
> > >
> > > func1 (); func2 ();
> > >
> > > Say you'd stopped inside 'func2'. If you do finish there, in
> > > current
> > > master gdb
> > > stops at the call to 'func2', and you can then decide to reverse
> > > step
> > > into 'func1'.
> >
> > I don't think you followed the issue.
>
> Totally possible!
>
> > So, if you are in func2 and do a reverse-finish, without the patch
> > gdb
> > stops on the last instruction for the line that calls func2.
>
> Right.
>
> > Now if
> > you issue a reverse-step, you stop at the first instruction for the
> > call to func2, i.e. you are still on the same source code line.
>
> Wait. That right there sounds bogus. The source line looks like:
>
> func1 (); func2 ();
>
> so stepping backwards over that line should always stop at the first
> instruction of the line, not in the middle. Let's simplify this.
>
> Here's the full source code of my example:
>
> (gdb) list 1
> 1 void func1 ()
> 2 {
> 3 }
> 4
> 5 void func2 ()
> 6 {
> 7 }
> 8
> 9 int main ()
> 10 {
> 11 func1 (); func2 ();
> 12 }
>
> Compiled with:
>
> $ gcc reverse.c -o reverse -g3 -O0
> $ gcc -v
> ...
> gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
>
> Now let's debug it with target record, using current gdb git master
> (f3d8ae90b236),
> without your patch:
>
> $ gdb ~/reverse
> GNU gdb (GDB) 14.0.50.20230124-git
> ...
> Reading symbols from /home/pedro/reverse...
> (gdb) start
> Temporary breakpoint 1 at 0x1147: file reverse.c, line 11.
> Starting program: /home/pedro/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-
> gnu/libthread_db.so.1".
>
> Temporary breakpoint 1, main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) record
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> => 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
>
> (gdb) n
> 12 }
>
> So far so good, a "next" stepped over the whole of line 11 and
> stopped at line 12.
>
> Let's confirm where we are now:
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> => 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
>
> Good, we're at the first instruction of line 12.
>
> Now let's undo the "next", with "reverse-next":
>
> (gdb) reverse-next
> 11 func1 (); func2 ();
>
> Seemingly stopped at line 11. Let's see exactly where:
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> => 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
> (gdb)
>
> And lo, we stopped in the middle of line 11! That is a bug, we
> should have stepped
> back all the way to the beginning of the line. The "reverse-next"
> should have fully
> undone the prior "next" command. Here's the same thing without the
> distracting
> disassemble commands:
>
> (gdb) b 11
> Breakpoint 1 at 0x1147: file reverse.c, line 11.
> (gdb) r
> Starting program: /home/pedro/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-
> gnu/libthread_db.so.1".
>
> Breakpoint 1, main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) p $pc
> $1 = (void (*)()) 0x555555555147 <main+8>
> (gdb) record
> (gdb) next
> 12 }
> (gdb) reverse-next
> 11 func1 (); func2 ();
> (gdb) p $pc
> $2 = (void (*)()) 0x555555555151 <main+18>
> (gdb)
>
>
> This:
>
> next -> reverse-next -> next -> reverse-next
>
> ... should leave you at the same instruction. But it doesn't in this
> example!
>
> How does this happen? Let's look at the line table as seen by GDB:
>
> (gdb) maint info line-table reverse.c
> objfile: /home/pedro/reverse ((struct objfile *) 0x55dd5df77c50)
> compunit_symtab: reverse.c ((struct compunit_symtab *)
> 0x55dd5de6b2e0)
> symtab: /home/pedro/reverse.c ((struct symtab *) 0x55dd5de6b360)
> linetable: ((struct linetable *) 0x55dd5dfd3290):
> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
> 0 2 0x0000555555555129 Y
> 1 3 0x0000555555555131 Y
> 2 6 0x0000555555555134 Y
> 3 7 0x000055555555513c Y
> 4 10 0x000055555555513f Y
> 5 11 0x0000555555555147 Y <<< here
> 6 11 0x0000555555555151 Y <<< here
> 7 12 0x0000555555555160 Y
> 8 END 0x0000555555555162 Y
>
> Ah, there are two entries for line 11, both marked with IS-STMT. So
> when
> stepping backward GDB only considered the region with index 6, that's
> why it
> stopped at 0x0000555555555151.
So, I walked thru your example on PowerPC and agree that the case where
we have func1 (); func2 (); on the same source line fails with the
reverse-next command. However, I think this is actually a "new"
regression failure for my patch. My patch was trying to fix the
behavior of the reverse-finish command and appears to have broken the
reverse-next command for this scenario.
Note, the initial version of this patch also broke the reverse-next
command (gdb.btrace/rn-dl-bind.exp and gdb.btrace/tailcall.exp) but the
current version of the patch fixed the tailcall.exp failure. Bruno and
I were not able to reproduce the failure for the rn-dl-bind.exp test.
Not sure if the test still fails for Tom with the latest patch or not.
Anyway, see the status summary below.
>
>
>
> Let's look at what we get with clang instead (Ubuntu clang version
> 14.0.0-1ubuntu1) :
>
> (gdb) maintenance info line-table reverse.c
> objfile: /home/pedro/reverse.clang ((struct objfile *)
> 0x5576be591ca0)
> compunit_symtab: reverse.c ((struct compunit_symtab *)
> 0x5576be485300)
> symtab: /home/pedro/reverse.c ((struct symtab *) 0x5576be485380)
> linetable: ((struct linetable *) 0x5576be5ec8e0):
> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
> 0 2 0x0000555555555130 Y
> 1 3 0x0000555555555134 Y Y
> 2 6 0x0000555555555140 Y
> 3 7 0x0000555555555144 Y Y
> 4 10 0x0000555555555150 Y
> 5 11 0x0000555555555154 Y Y
> 6 11 0x0000555555555159
> 7 12 0x000055555555515e Y
> 8 END 0x0000555555555162 Y
>
> Note no IS-STMT for the second range. And let's look at how GDB
> behaves with it:
>
> (gdb) b 11
> Breakpoint 1 at 0x1154: file reverse.c, line 11.
> (gdb) r
> Starting program: /home/pedro/reverse.clang
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-
> gnu/libthread_db.so.1".
>
> Breakpoint 1, main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) record
> (gdb) p $pc
> $1 = (void (*)()) 0x555555555154 <main+4>
> (gdb) n
> 12 }
> (gdb) reverse-next
>
> No more reverse-execution history.
> main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) p $pc
> $2 = (void (*)()) 0x555555555154 <main+4>
> (gdb)
>
> Bingo. reverse-next fully stepped the whole line backwards.
>
> > You
> > have not stepped back into func1 like you wanted to. Now you have
> > to
> > issue a second reverse-step to get into func1. With the patch,
> > you
> > issue the reverse-finish from func2 and stop at the first
> > instruction
> > in the line that calls func2. Now when you issue the reverse-step
> > you
> > step back into func1 as expected.
> >
>
> So this fix is assuming that the reverse step stops in the middle of
> a
> line, which I think is the real bug to fix. Once that is fixed, then
> you will no longer need two reverse-steps after reverse-finish.
>
> Here's what you get with current master without your patch, but using
> the test program compiled with clang. Actually, let's use a slightly
> modified program to force clang to emit some instructions between
> the two calls. Like this:
>
> $ cat reverse.c
> void func1 (int i)
> {
> }
>
> void func2 (int i)
> {
> }
>
> int main (int argc, char **argv)
> {
> func1 (argc); func2 (argc);
> }
>
> Alright, here's the gdb session, with clang, no gdb patch:
>
> Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc48) at
> reverse.c:11
> 11 func1 (argc); func2 (argc);
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x0000555555555150 <+0>: push %rbp
> 0x0000555555555151 <+1>: mov %rsp,%rbp
> 0x0000555555555154 <+4>: sub $0x10,%rsp
> 0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
> 0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
>
> 11 func1 (argc); func2 (argc);
> => 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
> 0x000055555555516a <+26>: call 0x555555555140 <func2>
>
> 12 }
> 0x000055555555516f <+31>: xor %eax,%eax
> 0x0000555555555171 <+33>: add $0x10,%rsp
> 0x0000555555555175 <+37>: pop %rbp
> 0x0000555555555176 <+38>: ret
> End of assembler dump.
> (gdb) record
> (gdb) b func2
> Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
> (gdb) c
> Continuing.
>
> Breakpoint 2, func2 (i=1) at reverse.c:7
> 7 }
> (gdb) reverse-finish
> Run back to call of #0 func2 (i=1) at reverse.c:7
> 0x000055555555516a in main (argc=1, argv=0x7fffffffdc48) at
> reverse.c:11
> 11 func1 (argc); func2 (argc);
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x0000555555555150 <+0>: push %rbp
> 0x0000555555555151 <+1>: mov %rsp,%rbp
> 0x0000555555555154 <+4>: sub $0x10,%rsp
> 0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
> 0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
>
> 11 func1 (argc); func2 (argc);
> 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
> => 0x000055555555516a <+26>: call 0x555555555140 <func2>
>
> 12 }
> 0x000055555555516f <+31>: xor %eax,%eax
> 0x0000555555555171 <+33>: add $0x10,%rsp
> 0x0000555555555175 <+37>: pop %rbp
> 0x0000555555555176 <+38>: ret
> End of assembler dump.
> (gdb) reverse-step
> func1 (i=1) at reverse.c:3
> 3 }
> (gdb)
>
>
> Note how a single reverse-step after the reverse-finish immediately
> stepped backwards into func1. Exactly how I describing it
> originally.
>
> With your patch, you'd break reverse-finish with clang:
>
> (gdb) record
> (gdb) b func2
> Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
> (gdb) c
> Continuing.
>
> Breakpoint 2, func2 (i=1) at reverse.c:7
> 7 }
> (gdb) reverse-finish
> Run back to call of #0 func2 (i=1) at reverse.c:7
> func1 (i=1) at reverse.c:3
> 3 }
> (gdb)
>
> GDB stopped at line 3, info func1 which means it stepped too far
> without
> stopping at func2's call site.
>
> GDB is misbehaving with GCC's debug info. I suspect the reason we
> get
> the two line entries for line 11 and both with IS-STMT is because GCC
> emits
> column debug info nowadays by default. Here's what e.g.,
> "llvm-dwarfdump --debug-line reverse" shows:
>
> ~~~
> Address Line Column File ISA Discriminator Flags
> ------------------ ------ ------ ------ --- ------------- ----------
> ---
> 0x0000000000001129 2 1 1 0 0 is_stmt
> 0x0000000000001131 3 1 1 0 0 is_stmt
> 0x0000000000001134 6 1 1 0 0 is_stmt
> 0x000000000000113c 7 1 1 0 0 is_stmt
> 0x000000000000113f 10 1 1 0 0 is_stmt
> 0x0000000000001147 11 3 1 0 0 is_stmt
> 0x0000000000001151 11 13 1 0 0 is_stmt
> 0x0000000000001160 12 1 1 0 0 is_stmt
> 0x0000000000001162 12 1 1 0 0 is_stmt
> end_sequence
> ~~~
>
> We can try disabling that with -gno-column-info, let's see what we
> get:
>
> (gdb) maint info line-table reverse.c
> objfile: /home/pedro/reverse.nocol ((struct objfile *)
> 0x5611464f6c10)
> compunit_symtab: reverse.c ((struct compunit_symtab *)
> 0x5611463ea2e0)
> symtab: /home/pedro/reverse.c ((struct symtab *) 0x5611463ea360)
> linetable: ((struct linetable *) 0x561146474c80):
> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
> 0 2 0x0000555555555129 Y
> 1 3 0x0000555555555134 Y
> 2 6 0x0000555555555137 Y
> 3 7 0x0000555555555142 Y
> 4 10 0x0000555555555145 Y
> 5 11 0x0000555555555158 Y
> 6 12 0x0000555555555171 Y
> 7 END 0x0000555555555173 Y
>
> (gdb)
>
> ... and in llvm-dwarfdump:
>
> Address Line Column File ISA Discriminator Flags
> ------------------ ------ ------ ------ --- ------------- ----------
> ---
> 0x0000000000001129 2 0 1 0 0 is_stmt
> 0x0000000000001134 3 0 1 0 0 is_stmt
> 0x0000000000001137 6 0 1 0 0 is_stmt
> 0x0000000000001142 7 0 1 0 0 is_stmt
> 0x0000000000001145 10 0 1 0 0 is_stmt
> 0x0000000000001158 11 0 1 0 0 is_stmt
> 0x0000000000001171 12 0 1 0 0 is_stmt
> 0x0000000000001173 12 0 1 0 0 is_stmt
> end_sequence
>
> Bingo. With no column info, only one entry for line 11.
>
I have not tested with clang. Actually I have never used clang so this
is another thing to look at and test.
Let me see if I can summarize the current situation.
1) The goal of the current X86 reverse patch is to fix the case where
we have called function foo () and are trying to do a reverse-finish
from inside the function. The mainline gdb code stops at the entry to
foo () then does a single instruction in the reverse direction to get
to the caller. Specifically, the code that this patch removes:
- if (ecs->event_thread->control.proceed_to_finish
- && execution_direction == EXEC_REVERSE)
- {
- struct thread_info *tp = ecs->event_thread;
-
- /* 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;
The single-step in gdb results in stopping at the last instruction in
the line where function foo is called. The result here is that you now
need to do two reverse-next instructions to get to the previous line.
The command sequence is: reverse-finish; reverse-next; reverst-next to
go from inside the function to the previous line in the caller.
Note, in this case you are in the function and trying to return to the
caller with the reverse-finish command. That is a different scenario
from what Pedro is talking about in 2) below.
2) The scenario that Pedro brings up is a reverse-next over a line with
two function calls on the same source line, i.e.
> 9 int main ()
> 10 {
> 11 func1 (); func2 ();
> 12 }
In this case you are in the caller and are trying to do a reverse-next
over the two function callers. This is a different scenario from 1).
This looks to me like an additional regression failure of the patch.
Unfortunately, this scenario does not seem to exit in any of the
current tests. Mainline gdb handles this case correctly. With my
patch, the reverse-next over the line now fails.
With out the patch, you just need reverse-next to step back over func1
(); func2 ();
With the patch you need reverse-next, reverse-next to step back over
the line with the two function calls.
3) The bug that I mentioned earlier for the case of
multiple executable statements on the same line.
https://sourceware.org/bugzilla/show_bug.cgi?id=28426
is for a case like:
int main ()
{
int a, b, c, d;
a = 1;
b = 2;
c = 3; d = 4;
a = a + b + c + d;
}
In this case the reverse-next from the last line a = a + b + c + d; is
not stepping all the way back over the line c = 3; d = 4;. This is a
simpler version of 2). Specifically the command sequence to step over
line c = 3; d = 4; is reverse-next, reverse-next. Only one reverse-
next should be required.
The patch that Luis and I have worked on fixes this issue, however it
does not fix the case of the multiple statements being function calls,
i.e. 2) above that Pedro is bringing up.
From a subsequent message from Pedro in this thread:
On Tue, 2023-01-24 at 15:06 +0000, Pedro Alves wrote:
> Yes. And the reason you need two "reverse-step" is because there are
> two line ranges for line 8, and reverse-step stops
> at the beginning of the second range instead of at the beginning of
> the first. It's the exact same as with my simpler
> example of just doing "next" -> "reverse-next", which I used as a
> simpler example to explain the problem.
>
> > What Carl is proposing we do is make it so GDB only needs one
> > command.
>
> I understand. However, I am saying that that is papering over the
> actual problem, _and_ it only works in the situation
> where you ended up with two line entries with is-stmt for the same
> line. Note how the patch breaks clang, and gcc with
> -gno-column-info...
I don't agree that I am "papering over the actual problem" rather I
think at this point that Pedro's test case is an additional case of the
reverse-next command being broken by my patch to fix the reverse-finish
command. The problem doesn't exist without my patch.
So at this point, I need to go see if I can figure out how the patch to
fix the reverse-finish command causes the regression in 2) for the
reverse-next command.
Looks like we also need an to add an additional test case for 2).
Also, will need to look at how any new fix for 2) behaves with clang.
Thanks for all the input on this issue. It seems that there is still
work to do.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 15:51 ` Carl Love
@ 2023-01-24 18:37 ` Pedro Alves
0 siblings, 0 replies; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 18:37 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, will_schmidt, gdb-patches
Cc: Luis Machado
On 2023-01-24 3:51 p.m., Carl Love wrote:
> On Tue, 2023-01-24 at 14:08 +0000, Pedro Alves wrote:
>> Wait. That right there sounds bogus. The source line looks like:
>>
>> func1 (); func2 ();
>
> My bad, I didn't catch that you were implying func1 and func2 as being
> on the same source line. There is an existing bugzilla for the case of
> multiple executable statements on the same line.
>
> https://sourceware.org/bugzilla/show_bug.cgi?id=28426
>
> I have worked with Luis Machado <luis.machado@arm.com> on a patch to
> address that issue. We have posted a few versions of the patch but it
> still needs some work for finish. I wanted to get back to that patch
> once the reverse-finish issue is done.
>
> I need to spend some more time looking at the rest of your response to
> understand everything you are talking about. That said, my first read
> looked like the issue in the bugzilla I mentioned. The patch Luis and
> I have for addressing multiple statements on the same line applies on
> top of the X86 and PowerPC reverse-finish patches.
You should fix the reverse-stepping multiple statements issue first, and
then the reverse-finish problems go away, you won't need that patch any more.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 15:53 ` [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp Tom de Vries
@ 2023-01-24 18:48 ` Pedro Alves
0 siblings, 0 replies; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 18:48 UTC (permalink / raw)
To: Tom de Vries, Carl Love, Bruno Larsen, Ulrich Weigand,
will_schmidt, gdb-patches
On 2023-01-24 3:53 p.m., Tom de Vries wrote:
> On 1/23/23 20:17, Pedro Alves wrote:
>> I'd think this was on purpose. Note that next/step/reverse-{next/step} are line-oriented
>> stepping commands, they step/next until the previous/next line. While "finish" is described
>> as undoing the_function call_.
>>
>> The manual says:
>>
>> reverse-finish
>> Just as the finish command takes you to the point where the current function returns,
>> reverse-finish takes you to the point where it was called. Instead of ending up at the end of
>> the current function invocation, you end up at the beginning.
>
> As well as:
> ...
> finish
> Continue running until just after function in the selected stack frame returns. Print the returned value (if any). This command can be abbreviated as fin.
> ...
>
> It's only now that you mention the non-line nature of finish/reverse-finish that I realize that that is the case. So I suppose the docs could be a bit more explicit about this aspect.
I guess.
>
> I suppose an intuitive way to make available the two approaches (so without the user losing options) would be to introduce finishi next to finish and reverse-finishi next to finish, with the new commands retaining the current functionality and the old ones being adjusted to respect line boundaries. But having the commands change behaviour is likely to cause confusion (well, assuming users notice the difference in the first place), so I'm not sure if that's a good idea.
They sure would notice a difference. Say for example, a source line like:
func1 (func2 (func3 ())));
and if you break in func3, and then do "finish", you expect that "step" steps into func2, while "next" would move to the next line.
If you changed finish to be line-oriented, then a "finish" while inside "func3" would either step over the whole "func1" call line instead,
or step into func2, depending on how you implement it. Regardless, it'd be a noticeable change, and I think a bad one.
Also, it complicates where we print the return value, as we would no longer present the stop at the instruction where we are able
to retrieve it.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 16:04 ` Bruno Larsen
@ 2023-01-24 19:12 ` Pedro Alves
2023-01-25 9:49 ` Bruno Larsen
2023-01-25 14:11 ` Ulrich Weigand
0 siblings, 2 replies; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 19:12 UTC (permalink / raw)
To: Bruno Larsen, Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 2023-01-24 4:04 p.m., Bruno Larsen wrote:
> On 24/01/2023 16:06, Pedro Alves wrote:
>>> Notice how there were two "reverse-step" commands needed after the "reverse-finish" used to exit func2.
>> Yes. And the reason you need two "reverse-step" is because there are two line ranges for line 8, and reverse-step stops
>> at the beginning of the second range instead of at the beginning of the first. It's the exact same as with my simpler
>> example of just doing "next" -> "reverse-next", which I used as a simpler example to explain the problem.
>
> The simplified example is not the exact same use case.
Correct, but it's the same root cause. Forget at reverse-finish, that is doing what it says it should do, that is,
to stop at the call to the function. You can just put a breakpoint at that same instruction, and once there, do a
reverse-step. GDB should then reverse step until it reaches a different line. But it does not. _That_ is the bug.
Vis (with gcc and column info):
...
(gdb) reverse-finish
Run back to call of #0 func2 (i=1) at reverse.c:7
0x0000555555555167 in main (argc=1, argv=0x7fffffffdc58) at reverse.c:11
^^^^^^^^^^^^^^^^^^
11 func1 (argc); func2 (argc);
(gdb) start
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Temporary breakpoint 2 at 0x555555555158: file reverse.c, line 11.
Starting program: /home/pedro/reverse
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 2, main (argc=1, argv=0x7fffffffdc58) at reverse.c:11
11 func1 (argc); func2 (argc);
(gdb) record
(gdb) b *0x0000555555555167 << manually set the breakpoint where the reverse-finish would stop
Breakpoint 4 at 0x555555555167: file reverse.c, line 11.
(gdb) c
Continuing.
Breakpoint 4, 0x0000555555555167 in main (argc=1, argv=0x7fffffffdc58) at reverse.c:11
11 func1 (argc); func2 (argc); << started at line 11
(gdb) reverse-step
11 func1 (argc); func2 (argc); << stopped at the same line, bug!
See, reverse-step stopped in the same line you started with. That is a bug, it should never
happen. Just like forward "step" never steps in the same line. Because that's how the
commands are supposed to work -- step until the line number changes!
> Looking at how the program executes forward, if we next over this line we skip everything, but if we step into func1 and use finish we will still stop in line 11 and the user can decide to step into func2 or not. That is why I assumed you were thinking of a different issue when I saw you using next and reverse-next as examples.
>
> Looking at where GDB lands when finishing from func1 we get (code compiled with gcc -gno-column-info):
>
> (gdb) start
> Temporary breakpoint 1 at 0x401118: file t.c, line 8.
> Starting program: /home/blarsen/Documents/downstream_build/gdb/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib64/libthread_db.so.1".
>
> Temporary breakpoint 1, main () at t.c:8
> 8 f1(); f2();
> (gdb) s
> f1 () at t.c:2
> 2 }
> (gdb) finish
> Run till exit from #0 f1 () at t.c:2
> 0x0000000000401122 in main () at t.c:8
> 8 f1(); f2();
> (gdb) disas /s
> Dump of assembler code for function main:
> t.c:
> 7 int main(){
> 0x0000000000401114 <+0>: push %rbp
> 0x0000000000401115 <+1>: mov %rsp,%rbp
>
> 8 f1(); f2();
> 0x0000000000401118 <+4>: mov $0x0,%eax
> 0x000000000040111d <+9>: call 0x401106 <f1>
> => 0x0000000000401122 <+14>: mov $0x0,%eax
> 0x0000000000401127 <+19>: call 0x40110d <f2>
> 0x000000000040112c <+24>: mov $0x0,%eax
>
> 9 }
> 0x0000000000401131 <+29>: pop %rbp
> 0x0000000000401132 <+30>: ret
> End of assembler dump.
>
> The behavior that we should emulate when going backwards is that finishing from func2 stops us on the 'mov' instruction between the calls. Looking at the clang session that I cut off from the previous email:
>
What is there are more instructions in between the calls? How do you know where to stop?
> Alright, here's the gdb session, with clang, no gdb patch:
>
> Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
> 11 func1 (argc); func2 (argc);
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x0000555555555150 <+0>: push %rbp
> 0x0000555555555151 <+1>: mov %rsp,%rbp
> 0x0000555555555154 <+4>: sub $0x10,%rsp
> 0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
> 0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
>
> 11 func1 (argc); func2 (argc);
> => 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
> 0x000055555555516a <+26>: call 0x555555555140 <func2>
>
> 12 }
> 0x000055555555516f <+31>: xor %eax,%eax
> 0x0000555555555171 <+33>: add $0x10,%rsp
> 0x0000555555555175 <+37>: pop %rbp
> 0x0000555555555176 <+38>: ret
> End of assembler dump.
> (gdb) record
> (gdb) b func2
> Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
> (gdb) c
> Continuing.
>
> Breakpoint 2, func2 (i=1) at reverse.c:7
> 7 }
> (gdb) reverse-finish
> Run back to call of #0 func2 (i=1) at reverse.c:7
> 0x000055555555516a in main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
> 11 func1 (argc); func2 (argc);
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x0000555555555150 <+0>: push %rbp
> 0x0000555555555151 <+1>: mov %rsp,%rbp
> 0x0000555555555154 <+4>: sub $0x10,%rsp
> 0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
> 0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
>
> 11 func1 (argc); func2 (argc);
> 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
> => 0x000055555555516a <+26>: call 0x555555555140 <func2>
>
> 12 }
> 0x000055555555516f <+31>: xor %eax,%eax
> 0x0000555555555171 <+33>: add $0x10,%rsp
> 0x0000555555555175 <+37>: pop %rbp
> 0x0000555555555176 <+38>: ret
> End of assembler dump.
> (gdb) reverse-step
> func1 (i=1) at reverse.c:3
> 3 }
> (gdb)
>
> We can see that GDB stopped on the call instruction instead. So a user that finished from func1 or reverse-finished from func2 may see different inferior states.
>
Seeing different inferior states is expected, as finish and reverse-finish are not the exact mirror of one another, like step
and reverse-step are. The exact reversal of finish would be the equivalent of being stopped at a function call return insn after
a "finish" (and the command could only be used while stopped there), and stepping back into the function up until the point
where you had typed "finish" and stopping there. Obviously impossible to implement. So we made "reverse-finish" do something
sensible, such as stepping backwards up until the call site.
>
>>
>>> What Carl is proposing we do is make it so GDB only needs one command.
>> I understand. However, I am saying that that is papering over the actual problem, _and_ it only works in the situation
>> where you ended up with two line entries with is-stmt for the same line. Note how the patch breaks clang, and gcc with
>> -gno-column-info...
>>
>>> If I compare the $pc of where GDB is stopped and the linetable, we get:
>>>
>>> (gdb) print $pc
>>> $2 = (void (*)()) 0x401127 <main+19>
>>> (gdb) maint info line-table
>>> objfile: /home/blarsen/Documents/downstream_build/gdb/reverse ((struct objfile *) 0x10f7750)
>>> compunit_symtab: t.c ((struct compunit_symtab *) 0x116c330)
>>> symtab: /home/blarsen/Documents/downstream_build/gdb/t.c ((struct symtab *) 0x116c3b0)
>>> linetable: ((struct linetable *) 0x11aec80):
>>> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
>>> 0 1 0x0000000000401106 Y
>>> 1 2 0x000000000040110a Y
>>> 2 4 0x000000000040110d Y
>>> 3 5 0x0000000000401111 Y
>>> 4 7 0x0000000000401114 Y
>>> 5 8 0x0000000000401118 Y
>>> 6 8 0x0000000000401122 Y
>>> 7 9 0x0000000000401131 Y
>>> 8 END 0x0000000000401133 Y
>>>
>>> We can see that GDB shouldn't even be able to stop at that $pc, it isn't an is_stmt.
>> reverse-finish is not supposed to step backwards until it reaches is_stmt. Doing so makes it
>> step backwards too much, as I've shown in my previous example.
>>
>>> We should have stopped at 0x401122, which is where the first reverse-step stops:
>> No...
>>
>>> (gdb) rs
>>> 8 f1(); f2();
>>> (gdb) p $pc
>>> $4 = (void (*)()) 0x401122 <main+14>
>> ... no because in the case where you don't have column debug info (or with clang), there won't be
>> an is-stmt entry for the f2 call/column, there will only be one single line entry for the whole of
>> line 8, so gdb would step back too much.
>>
>>> So not only are we needing an extra command to re-sync with user expectations, we are in an instruction where the inferior state might be all over the place.
>>>
>> What does that mean, the state might be all over the place? The DWARF should describe the locations of all variables accurately at all instructions.
>>
> Unrelated to this specific issue, but I was looking at record/30025 (https://sourceware.org/bugzilla/show_bug.cgi?id=30025) and it confused me because because GDB sometimes reported the incorrect parameter, but if we continue single-stepping through instructions, GDB eventually finds the correct value when we stop at an is_stmt instruction.
>
> If I misunderstood something about 30025 and is_stmt, please let me know! but as far as I can see, this is what happened.
>
I can't tell what is going on in that bug without debugging it myself, but seeing SIGTRAP makes me suspect that
one thing that could be going on is that GDB didn't apply the decr-pc-after-break adjustment properly, so
then the PC is pointing into the middle of an instruction and then all hell breaks loose.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 18:25 ` Carl Love
@ 2023-01-24 19:21 ` Pedro Alves
2023-01-24 19:26 ` Pedro Alves
0 siblings, 1 reply; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 19:21 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, gdb-patches; +Cc: Luis Machado
On 2023-01-24 6:25 p.m., Carl Love wrote:
> I have not tested with clang. Actually I have never used clang so this
> is another thing to look at and test.
>
>
> Let me see if I can summarize the current situation.
>
> 1) The goal of the current X86 reverse patch is to fix the case where
> we have called function foo () and are trying to do a reverse-finish
> from inside the function.
Wrong goal. There's nothing to fix there. The command is working as designed.
> The mainline gdb code stops at the entry to
> foo () then does a single instruction in the reverse direction to get
> to the caller. Specifically, the code that this patch removes:
>
> - if (ecs->event_thread->control.proceed_to_finish
> - && execution_direction == EXEC_REVERSE)
> - {
> - struct thread_info *tp = ecs->event_thread;
> -
> - /* 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;
>
> The single-step in gdb results in stopping at the last instruction in
> the line where function foo is called. The result here is that you now
> need to do two reverse-next instructions to get to the previous line.
And that is the bug. reverse-next/reverse-step should _never_ stop at the same line.
Same as forward step/next. For instance, this "next" command will just continue
stepping forever:
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc98) at reverse.c:11
11 while (1);
(gdb) next
Same for "step" instead of "next".
It turns out that reverse-next/step do stop immediately!
(gdb) reverse-next
11 while (1);
(gdb) reverse-next
11 while (1);
(gdb)
That's probably caused by the same bug.
> The command sequence is: reverse-finish; reverse-next; reverst-next to
> go from inside the function to the previous line in the caller.
>
> Note, in this case you are in the function and trying to return to the
> caller with the reverse-finish command. That is a different scenario
> from what Pedro is talking about in 2) below.
>
> 2) The scenario that Pedro brings up is a reverse-next over a line with
> two function calls on the same source line, i.e.
>
>> 9 int main ()
>> 10 {
>> 11 func1 (); func2 ();
>> 12 }
>
> In this case you are in the caller and are trying to do a reverse-next
> over the two function callers. This is a different scenario from 1).
>
I know it's a different scenario, but my scenario is just a way to show
up that the root of the problem can be seen with a simpler scenario. The
problem is in the reverse-step command, and you are focusing on the reverse-finish
command, incorrectly. Please read my responses to Bruno as well.
> 3) The bug that I mentioned earlier for the case of
> multiple executable statements on the same line.
>
> https://sourceware.org/bugzilla/show_bug.cgi?id=28426
>
> is for a case like:
>
> int main ()
> {
> int a, b, c, d;
> a = 1;
> b = 2;
> c = 3; d = 4;
> a = a + b + c + d;
> }
>
> In this case the reverse-next from the last line a = a + b + c + d; is
> not stepping all the way back over the line c = 3; d = 4;. This is a
> simpler version of 2). Specifically the command sequence to step over
> line c = 3; d = 4; is reverse-next, reverse-next. Only one reverse-
> next should be required.
>
Exactly. It's all the same bug.
> The patch that Luis and I have worked on fixes this issue, however it
> does not fix the case of the multiple statements being function calls,
> i.e. 2) above that Pedro is bringing up.
I have said it numerous times now, but it's worth repeating. It's all
the same bug. :-) Fix reverse-step, and then the reverse-finish
scenario fixes itself, because you will no longer need to issue
two reverse-step commands after reverse-finish.
>
>
> From a subsequent message from Pedro in this thread:
>
> On Tue, 2023-01-24 at 15:06 +0000, Pedro Alves wrote:
> > Yes. And the reason you need two "reverse-step" is because there are
> > two line ranges for line 8, and reverse-step stops
> > at the beginning of the second range instead of at the beginning of
> > the first. It's the exact same as with my simpler
> > example of just doing "next" -> "reverse-next", which I used as a
> > simpler example to explain the problem.
> >
> > > What Carl is proposing we do is make it so GDB only needs one
> > > command.
> >
> > I understand. However, I am saying that that is papering over the
> > actual problem, _and_ it only works in the situation
> > where you ended up with two line entries with is-stmt for the same
> > line. Note how the patch breaks clang, and gcc with
> > -gno-column-info...
>
> I don't agree that I am "papering over the actual problem" rather I
> think at this point that Pedro's test case is an additional case of the
> reverse-next command being broken by my patch to fix the reverse-finish
> command. The problem doesn't exist without my patch.
>
>
> So at this point, I need to go see if I can figure out how the patch to
> fix the reverse-finish command causes the regression in 2) for the
> reverse-next command.
At this point. NAK on the reverse-finish fix.
>
> Looks like we also need an to add an additional test case for 2).
> Also, will need to look at how any new fix for 2) behaves with clang.
>
> Thanks for all the input on this issue. It seems that there is still
> work to do.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 19:21 ` Pedro Alves
@ 2023-01-24 19:26 ` Pedro Alves
0 siblings, 0 replies; 105+ messages in thread
From: Pedro Alves @ 2023-01-24 19:26 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Ulrich Weigand, gdb-patches; +Cc: Luis Machado
On 2023-01-24 7:21 p.m., Pedro Alves wrote:
> And that is the bug. reverse-next/reverse-step should _never_ stop at the same line.
> Same as forward step/next. For instance, this "next" command will just continue
> stepping forever:
>
> Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc98) at reverse.c:11
> 11 while (1);
> (gdb) next
>
> Same for "step" instead of "next".
>
> It turns out that reverse-next/step do stop immediately!
>
> (gdb) reverse-next
> 11 while (1);
> (gdb) reverse-next
> 11 while (1);
> (gdb)
>
> That's probably caused by the same bug.
From the documentation:
reverse-step [count]
Run the program backward until control reaches the start of a different source line;
^^^^^^^^^
Emphasis mine.
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 19:12 ` Pedro Alves
@ 2023-01-25 9:49 ` Bruno Larsen
2023-01-25 14:11 ` Ulrich Weigand
1 sibling, 0 replies; 105+ messages in thread
From: Bruno Larsen @ 2023-01-25 9:49 UTC (permalink / raw)
To: Pedro Alves, Carl Love, Ulrich Weigand, will_schmidt, gdb-patches
On 24/01/2023 20:12, Pedro Alves wrote:
> On 2023-01-24 4:04 p.m., Bruno Larsen wrote:
>> On 24/01/2023 16:06, Pedro Alves wrote:
>>>> Notice how there were two "reverse-step" commands needed after the "reverse-finish" used to exit func2.
>>> Yes. And the reason you need two "reverse-step" is because there are two line ranges for line 8, and reverse-step stops
>>> at the beginning of the second range instead of at the beginning of the first. It's the exact same as with my simpler
>>> example of just doing "next" -> "reverse-next", which I used as a simpler example to explain the problem.
>> The simplified example is not the exact same use case.
> Correct, but it's the same root cause. Forget at reverse-finish, that is doing what it says it should do, that is,
> to stop at the call to the function. You can just put a breakpoint at that same instruction, and once there, do a
> reverse-step. GDB should then reverse step until it reaches a different line. But it does not. _That_ is the bug.
Ok, you convinced me. I played around some more with the no-column-info
example and what you said and I agree that fixing the column info bug
would fix Carl's bug for this patch. I'll update the relevant bug
(https://sourceware.org/bugzilla/show_bug.cgi?id=28426) and now we have
a way to reproduce that!
>
> Vis (with gcc and column info):
>
> ...
> (gdb) reverse-finish
> Run back to call of #0 func2 (i=1) at reverse.c:7
> 0x0000555555555167 in main (argc=1, argv=0x7fffffffdc58) at reverse.c:11
> ^^^^^^^^^^^^^^^^^^
> 11 func1 (argc); func2 (argc);
> (gdb) start
> The program being debugged has been started already.
> Start it from the beginning? (y or n) y
> Temporary breakpoint 2 at 0x555555555158: file reverse.c, line 11.
> Starting program: /home/pedro/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
>
> Temporary breakpoint 2, main (argc=1, argv=0x7fffffffdc58) at reverse.c:11
> 11 func1 (argc); func2 (argc);
> (gdb) record
> (gdb) b *0x0000555555555167 << manually set the breakpoint where the reverse-finish would stop
> Breakpoint 4 at 0x555555555167: file reverse.c, line 11.
> (gdb) c
> Continuing.
>
> Breakpoint 4, 0x0000555555555167 in main (argc=1, argv=0x7fffffffdc58) at reverse.c:11
> 11 func1 (argc); func2 (argc); << started at line 11
> (gdb) reverse-step
> 11 func1 (argc); func2 (argc); << stopped at the same line, bug!
>
> See, reverse-step stopped in the same line you started with. That is a bug, it should never
> happen. Just like forward "step" never steps in the same line. Because that's how the
> commands are supposed to work -- step until the line number changes!
>
>> Looking at how the program executes forward, if we next over this line we skip everything, but if we step into func1 and use finish we will still stop in line 11 and the user can decide to step into func2 or not. That is why I assumed you were thinking of a different issue when I saw you using next and reverse-next as examples.
>>
>> Looking at where GDB lands when finishing from func1 we get (code compiled with gcc -gno-column-info):
>>
>> (gdb) start
>> Temporary breakpoint 1 at 0x401118: file t.c, line 8.
>> Starting program: /home/blarsen/Documents/downstream_build/gdb/reverse
>> [Thread debugging using libthread_db enabled]
>> Using host libthread_db library "/lib64/libthread_db.so.1".
>>
>> Temporary breakpoint 1, main () at t.c:8
>> 8 f1(); f2();
>> (gdb) s
>> f1 () at t.c:2
>> 2 }
>> (gdb) finish
>> Run till exit from #0 f1 () at t.c:2
>> 0x0000000000401122 in main () at t.c:8
>> 8 f1(); f2();
>> (gdb) disas /s
>> Dump of assembler code for function main:
>> t.c:
>> 7 int main(){
>> 0x0000000000401114 <+0>: push %rbp
>> 0x0000000000401115 <+1>: mov %rsp,%rbp
>>
>> 8 f1(); f2();
>> 0x0000000000401118 <+4>: mov $0x0,%eax
>> 0x000000000040111d <+9>: call 0x401106 <f1>
>> => 0x0000000000401122 <+14>: mov $0x0,%eax
>> 0x0000000000401127 <+19>: call 0x40110d <f2>
>> 0x000000000040112c <+24>: mov $0x0,%eax
>>
>> 9 }
>> 0x0000000000401131 <+29>: pop %rbp
>> 0x0000000000401132 <+30>: ret
>> End of assembler dump.
>>
>> The behavior that we should emulate when going backwards is that finishing from func2 stops us on the 'mov' instruction between the calls. Looking at the clang session that I cut off from the previous email:
>>
> What is there are more instructions in between the calls? How do you know where to stop?
>
>> Alright, here's the gdb session, with clang, no gdb patch:
>>
>> Temporary breakpoint 1, main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
>> 11 func1 (argc); func2 (argc);
>> (gdb) disassemble /s
>> Dump of assembler code for function main:
>> reverse.c:
>> 10 {
>> 0x0000555555555150 <+0>: push %rbp
>> 0x0000555555555151 <+1>: mov %rsp,%rbp
>> 0x0000555555555154 <+4>: sub $0x10,%rsp
>> 0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
>> 0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
>>
>> 11 func1 (argc); func2 (argc);
>> => 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
>> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
>> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
>> 0x000055555555516a <+26>: call 0x555555555140 <func2>
>>
>> 12 }
>> 0x000055555555516f <+31>: xor %eax,%eax
>> 0x0000555555555171 <+33>: add $0x10,%rsp
>> 0x0000555555555175 <+37>: pop %rbp
>> 0x0000555555555176 <+38>: ret
>> End of assembler dump.
>> (gdb) record
>> (gdb) b func2
>> Breakpoint 2 at 0x555555555147: file reverse.c, line 7.
>> (gdb) c
>> Continuing.
>>
>> Breakpoint 2, func2 (i=1) at reverse.c:7
>> 7 }
>> (gdb) reverse-finish
>> Run back to call of #0 func2 (i=1) at reverse.c:7
>> 0x000055555555516a in main (argc=1, argv=0x7fffffffdc48) at reverse.c:11
>> 11 func1 (argc); func2 (argc);
>> (gdb) disassemble /s
>> Dump of assembler code for function main:
>> reverse.c:
>> 10 {
>> 0x0000555555555150 <+0>: push %rbp
>> 0x0000555555555151 <+1>: mov %rsp,%rbp
>> 0x0000555555555154 <+4>: sub $0x10,%rsp
>> 0x0000555555555158 <+8>: mov %edi,-0x4(%rbp)
>> 0x000055555555515b <+11>: mov %rsi,-0x10(%rbp)
>>
>> 11 func1 (argc); func2 (argc);
>> 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
>> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
>> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
>> => 0x000055555555516a <+26>: call 0x555555555140 <func2>
>>
>> 12 }
>> 0x000055555555516f <+31>: xor %eax,%eax
>> 0x0000555555555171 <+33>: add $0x10,%rsp
>> 0x0000555555555175 <+37>: pop %rbp
>> 0x0000555555555176 <+38>: ret
>> End of assembler dump.
>> (gdb) reverse-step
>> func1 (i=1) at reverse.c:3
>> 3 }
>> (gdb)
>>
>> We can see that GDB stopped on the call instruction instead. So a user that finished from func1 or reverse-finished from func2 may see different inferior states.
>>
> Seeing different inferior states is expected, as finish and reverse-finish are not the exact mirror of one another, like step
> and reverse-step are. The exact reversal of finish would be the equivalent of being stopped at a function call return insn after
> a "finish" (and the command could only be used while stopped there), and stepping back into the function up until the point
> where you had typed "finish" and stopping there. Obviously impossible to implement. So we made "reverse-finish" do something
> sensible, such as stepping backwards up until the call site.
>
>>>> What Carl is proposing we do is make it so GDB only needs one command.
>>> I understand. However, I am saying that that is papering over the actual problem, _and_ it only works in the situation
>>> where you ended up with two line entries with is-stmt for the same line. Note how the patch breaks clang, and gcc with
>>> -gno-column-info...
>>>
>>>> If I compare the $pc of where GDB is stopped and the linetable, we get:
>>>>
>>>> (gdb) print $pc
>>>> $2 = (void (*)()) 0x401127 <main+19>
>>>> (gdb) maint info line-table
>>>> objfile: /home/blarsen/Documents/downstream_build/gdb/reverse ((struct objfile *) 0x10f7750)
>>>> compunit_symtab: t.c ((struct compunit_symtab *) 0x116c330)
>>>> symtab: /home/blarsen/Documents/downstream_build/gdb/t.c ((struct symtab *) 0x116c3b0)
>>>> linetable: ((struct linetable *) 0x11aec80):
>>>> INDEX LINE ADDRESS IS-STMT PROLOGUE-END
>>>> 0 1 0x0000000000401106 Y
>>>> 1 2 0x000000000040110a Y
>>>> 2 4 0x000000000040110d Y
>>>> 3 5 0x0000000000401111 Y
>>>> 4 7 0x0000000000401114 Y
>>>> 5 8 0x0000000000401118 Y
>>>> 6 8 0x0000000000401122 Y
>>>> 7 9 0x0000000000401131 Y
>>>> 8 END 0x0000000000401133 Y
>>>>
>>>> We can see that GDB shouldn't even be able to stop at that $pc, it isn't an is_stmt.
>>> reverse-finish is not supposed to step backwards until it reaches is_stmt. Doing so makes it
>>> step backwards too much, as I've shown in my previous example.
>>>
>>>> We should have stopped at 0x401122, which is where the first reverse-step stops:
>>> No...
>>>
>>>> (gdb) rs
>>>> 8 f1(); f2();
>>>> (gdb) p $pc
>>>> $4 = (void (*)()) 0x401122 <main+14>
>>> ... no because in the case where you don't have column debug info (or with clang), there won't be
>>> an is-stmt entry for the f2 call/column, there will only be one single line entry for the whole of
>>> line 8, so gdb would step back too much.
>>>
>>>> So not only are we needing an extra command to re-sync with user expectations, we are in an instruction where the inferior state might be all over the place.
>>>>
>>> What does that mean, the state might be all over the place? The DWARF should describe the locations of all variables accurately at all instructions.
>>>
>> Unrelated to this specific issue, but I was looking at record/30025 (https://sourceware.org/bugzilla/show_bug.cgi?id=30025) and it confused me because because GDB sometimes reported the incorrect parameter, but if we continue single-stepping through instructions, GDB eventually finds the correct value when we stop at an is_stmt instruction.
>>
>> If I misunderstood something about 30025 and is_stmt, please let me know! but as far as I can see, this is what happened.
>>
> I can't tell what is going on in that bug without debugging it myself, but seeing SIGTRAP makes me suspect that
> one thing that could be going on is that GDB didn't apply the decr-pc-after-break adjustment properly, so
> then the PC is pointing into the middle of an instruction and then all hell breaks loose.
>
oh! This is very helpful, thank you!
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-24 19:12 ` Pedro Alves
2023-01-25 9:49 ` Bruno Larsen
@ 2023-01-25 14:11 ` Ulrich Weigand
2023-01-25 16:42 ` Pedro Alves
1 sibling, 1 reply; 105+ messages in thread
From: Ulrich Weigand @ 2023-01-25 14:11 UTC (permalink / raw)
To: gdb-patches, will_schmidt, Bruno Larsen, cel, pedro
Pedro Alves <pedro@palves.net> wrote:
> > 11 func1 (argc); func2 (argc);
> > 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
> > 0x0000555555555162 <+18>: call 0x555555555130 <func1>
> > 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
> > => 0x000055555555516a <+26>: call 0x555555555140 <func2>
> >
> > 12 }
> > 0x000055555555516f <+31>: xor %eax,%eax
> > 0x0000555555555171 <+33>: add $0x10,%rsp
> > 0x0000555555555175 <+37>: pop %rbp
> > 0x0000555555555176 <+38>: ret
> > End of assembler dump.
> > (gdb) reverse-step
> > func1 (i=1) at reverse.c:3
> > 3 }
> > (gdb)
> >
> >We can see that GDB stopped on the call instruction instead. So a user that finished from func1 or reverse-finished from func2 may see different inferior states.
>Seeing different inferior states is expected, as finish and reverse-finish are not the exact mirror of one another, like step
>and reverse-step are. The exact reversal of finish would be the equivalent of being stopped at a function call return insn after
>a "finish" (and the command could only be used while stopped there), and stepping back into the function up until the point
>where you had typed "finish" and stopping there. Obviously impossible to implement. So we made "reverse-finish" do something
>sensible, such as stepping backwards up until the call site.
Hi Pedro,
I certainly agree with you that reverse-step needs to be fixed,
and this explains at least part of the problems we were seeing.
However, I do think there is still another issue specific to
reverse-finish, along the lines Bruno pointed out. And in fact,
I do think that there is (or at least should be!) a well-defined
symmetry between finish and reverse-finish:
The effect of "finish" is: skip until the end of the current
function and then do a "step". (Semantically equivalently,
do a series of "next" until you leave the current function.)
Similarly, the effect of "reverse-finish" *should* be: reverse-skip
until the beginning of the current function and then do a reverse-step.
(Or semantically equivalent, do a series of "reverse-next" until you
leave the current function.)
However, the actual implementation of reverse-finish is subtly but
significantly different: it reverse-skips until the beginning of the
current function and then does a reverse-stepi (not reverse-step).
This has the at least surprising, but IMO even incorrect, effect
that when on the first line of a function, "reverse-finish" ends
up in a different place than "reverse-step". I believe they
ought to end up in the same place.
This was one of the primary intentions behind Carl's patch: change
reverse-finish so it does a reverse-step instead of a reverse-stepi.
(Of course, for this to be useful, reverse-step itself needs to work
correctly - which it doesn't right now as you point out.)
Bye,
Ulrich
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-25 14:11 ` Ulrich Weigand
@ 2023-01-25 16:42 ` Pedro Alves
2023-01-25 17:13 ` Ulrich Weigand
0 siblings, 1 reply; 105+ messages in thread
From: Pedro Alves @ 2023-01-25 16:42 UTC (permalink / raw)
To: Ulrich Weigand, gdb-patches, will_schmidt, Bruno Larsen, cel
On 2023-01-25 2:11 p.m., Ulrich Weigand wrote:
> Pedro Alves <pedro@palves.net> wrote:
>
>>> 11 func1 (argc); func2 (argc);
>>> 0x000055555555515f <+15>: mov -0x4(%rbp),%edi
>>> 0x0000555555555162 <+18>: call 0x555555555130 <func1>
>>> 0x0000555555555167 <+23>: mov -0x4(%rbp),%edi
>>> => 0x000055555555516a <+26>: call 0x555555555140 <func2>
>>>
>>> 12 }
>>> 0x000055555555516f <+31>: xor %eax,%eax
>>> 0x0000555555555171 <+33>: add $0x10,%rsp
>>> 0x0000555555555175 <+37>: pop %rbp
>>> 0x0000555555555176 <+38>: ret
>>> End of assembler dump.
>>> (gdb) reverse-step
>>> func1 (i=1) at reverse.c:3
>>> 3 }
>>> (gdb)
>>>
>>> We can see that GDB stopped on the call instruction instead. So a user that finished from func1 or reverse-finished from func2 may see different inferior states.
>
>> Seeing different inferior states is expected, as finish and reverse-finish are not the exact mirror of one another, like step
>> and reverse-step are. The exact reversal of finish would be the equivalent of being stopped at a function call return insn after
>> a "finish" (and the command could only be used while stopped there), and stepping back into the function up until the point
>> where you had typed "finish" and stopping there. Obviously impossible to implement. So we made "reverse-finish" do something
>> sensible, such as stepping backwards up until the call site.
>
> Hi Pedro,
>
> I certainly agree with you that reverse-step needs to be fixed,
> and this explains at least part of the problems we were seeing.
>
> However, I do think there is still another issue specific to
> reverse-finish, along the lines Bruno pointed out. And in fact,
> I do think that there is (or at least should be!) a well-defined
> symmetry between finish and reverse-finish:
>
> The effect of "finish" is: skip until the end of the current
> function and then do a "step". (Semantically equivalently,
> do a series of "next" until you leave the current function.)
But that this is not actually true -- this is not how finish is implemented.
Instead, we unwind to the caller frame, and put a breakpoint at that
frame'c PC, and run freely to that. A frame's PC is defined as the address
of the instruction that is executed once the callee returns.
OTOH, a (forward) step at the return line of a function steps until a different
line is reached, and in the case we step out of a function, once it reaches the
caller it notices we ended up in the middle of a line so it continues stepping until
the next line.
Note that finish vs step difference visible here:
(gdb) list 1
1 int func1 (int i)
2 {
3 return i + 1;
4 }
5
6 int func2 (int i)
7 {
8 return i + 1;
9 }
10
11 int main (int argc, char **argv)
12 {
13 func1 (func2 (argc));
14 return 0;
15 }
(gdb)
(gdb) b func2
Breakpoint 1 at 0x1147: file finish.c, line 8.
(gdb) r
Starting program: /home/pedro/finish
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, func2 (i=1) at finish.c:8
8 return i + 1;
(gdb) finish
Run till exit from #0 func2 (i=1) at finish.c:8
0x000055555555516c in main (argc=1, argv=0x7fffffffdcb8) at finish.c:13 <<< stopped in the middle of the line, as indicated by address on the left
13 func1 (func2 (argc));
Value returned is $1 = 2 <<< at this location we can use ABI knowledge to retrieve the return value
(gdb) p $pc
$2 = (void (*)()) 0x55555555516c <main+29> <<< matches the "0x000055555555516c in main" above, of course
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/pedro/finish
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, func2 (i=1) at finish.c:8
8 return i + 1;
(gdb) step
9 } <<< stopped a line bounary, and stepped over the func1 call as well!
(gdb) p $pc
$3 = (void (*)()) 0x55555555514d <func2+17>
>
> Similarly, the effect of "reverse-finish" *should* be: reverse-skip
> until the beginning of the current function and then do a reverse-step.
> (Or semantically equivalent, do a series of "reverse-next" until you
> leave the current function.)
I disagree, because that reverse-step would step backwards too much. Instead of stepping back to the
call of the function, it would step back further, as reverse-step will try to stop at the
beginning of a line. By doing that, you'll potentially step backwards more statements that
exist in the same line. Like:
a = 1; b = 2; func();
stepping back from inside func should stop at the first instruction of that whole line.
But finishing backwards should stop at the call to func(), without considering line
boundaries, just like forward finish does not.
From the manual:
"Like the step command, reverse-step will only stop at the beginning of a source line. It “un-executes” the previously executed source line."
>
> However, the actual implementation of reverse-finish is subtly but
> significantly different: it reverse-skips until the beginning of the
> current function and then does a reverse-stepi (not reverse-step).
>
> This has the at least surprising, but IMO even incorrect, effect
> that when on the first line of a function, "reverse-finish" ends
> up in a different place than "reverse-step". I believe they
> ought to end up in the same place.
I disagree.
Pedro Alves
>
>
> This was one of the primary intentions behind Carl's patch: change
> reverse-finish so it does a reverse-step instead of a reverse-stepi.
> (Of course, for this to be useful, reverse-step itself needs to work
> correctly - which it doesn't right now as you point out.)
>
> Bye,
> Ulrich
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-25 16:42 ` Pedro Alves
@ 2023-01-25 17:13 ` Ulrich Weigand
2023-01-25 17:24 ` Pedro Alves
0 siblings, 1 reply; 105+ messages in thread
From: Ulrich Weigand @ 2023-01-25 17:13 UTC (permalink / raw)
To: gdb-patches, will_schmidt, Bruno Larsen, cel, pedro
Pedro Alves <pedro@palves.net> wrote:
On 2023-01-25 2:11 p.m., Ulrich Weigand wrote:
> >The effect of "finish" is: skip until the end of the current
> >function and then do a "step". (Semantically equivalently,
> >do a series of "next" until you leave the current function.)
>
>But that this is not actually true -- this is not how finish is implemented.
Ah, you're right. I misremembered - I thought we were still stepping
after the step-resume breakpoint, but looks like we are not.
>Breakpoint 1, func2 (i=1) at finish.c:8
>8 return i + 1;
>(gdb) step
>9 } <<< stopped a line bounary, and stepped over the func1 call as well!
>(gdb) p $pc
>$3 = (void (*)()) 0x55555555514d <func2+17>
So this is still at the return in func2, but you're right,
the next step brings us directly to func1 without stopping
in main at all. This is indeed unlike finish.
>I disagree.
OK, you've convinced me as well. Sorry for the confusion ...
Bye,
Ulrich
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-25 17:13 ` Ulrich Weigand
@ 2023-01-25 17:24 ` Pedro Alves
2023-01-25 19:38 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Pedro Alves @ 2023-01-25 17:24 UTC (permalink / raw)
To: Ulrich Weigand, gdb-patches, will_schmidt, Bruno Larsen, cel
On 2023-01-25 5:13 p.m., Ulrich Weigand wrote:
>> Breakpoint 1, func2 (i=1) at finish.c:8
>> 8 return i + 1;
>> (gdb) step
>> 9 } <<< stopped a line bounary, and stepped over the func1 call as well!
>> (gdb) p $pc
>> $3 = (void (*)()) 0x55555555514d <func2+17>
> So this is still at the return in func2,
Whoops, the example that I quickly typed up didn't actually have an explicit return
line when I first tried it (it returned void), and then I thought of adding one and I added it
I missed that I now needed one extra step to get out of func, thinking I was at the last
line of main already.
> but you're right,
> the next step brings us directly to func1 without stopping
> in main at all. This is indeed unlike finish.
>
Exactly.
>> I disagree.
> OK, you've convinced me as well. Sorry for the confusion ...
No worries!
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2 version 3] fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-25 17:24 ` Pedro Alves
@ 2023-01-25 19:38 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-01-25 19:38 UTC (permalink / raw)
To: Pedro Alves, Ulrich Weigand, gdb-patches, Bruno Larsen; +Cc: cel, luis.machado
Pedro, Ulrich, Tom, Bruno:
On Wed, 2023-01-25 at 17:24 +0000, Pedro Alves wrote:
> On 2023-01-25 5:13 p.m., Ulrich Weigand wrote:
> > > Breakpoint 1, func2 (i=1) at finish.c:8
> > > 8 return i + 1;
> > > (gdb) step
> > > 9 }
> > > <<< stopped a line bounary, and stepped over the func1
> > > call as well!
> > > (gdb) p $pc
> > > $3 = (void (*)()) 0x55555555514d <func2+17>
> > So this is still at the return in func2,
>
> Whoops, the example that I quickly typed up didn't actually have an
> explicit return
> line when I first tried it (it returned void), and then I thought of
> adding one and I added it
> I missed that I now needed one extra step to get out of func,
> thinking I was at the last
> line of main already.
>
> > but you're right,
> > the next step brings us directly to func1 without stopping
> > in main at all. This is indeed unlike finish.
> >
>
> Exactly.
>
> > > I disagree.
> > OK, you've convinced me as well. Sorry for the confusion ...
>
> No worries!
OK, so there seems to be agreement that we do not want to move forward
with this patch to change the behavior of the reverse-finish command.
The consensus is the reverse-finish command is working as expected. So,
I formally withdraw patch 1 of 2 from consideration.
I worked on a patch with Luis, who is now busy with other things, to
fix the issue of two "simple" executable statements on a line not
working. The patch fixed that issue, but does not fix the example from
Pedro of two function calls in the same source line. So, I will pickup
this patch again and see if I can get the patch to correctly handle
column debug info and the is-stmt entry stuff and not break clang.
The second patch in this series address the reverse-finish command on
PowerPC which does not work due to the multiple entry points used in
PowerPC. I will rework the PowerPC patch to apply on mainline to
address the PowerPC issues so the reverse-finish command will behave
the same as on X86. This is probably the simpler/easier of the two
patches to do.
Thanks for all the discussion and help with this issue.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Reverse-next bug test case
2023-01-24 14:08 ` Pedro Alves
` (2 preceding siblings ...)
2023-01-24 18:25 ` Carl Love
@ 2023-01-31 0:17 ` Carl Love
2023-02-01 14:37 ` Pedro Alves
3 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-01-31 0:17 UTC (permalink / raw)
To: Pedro Alves, Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
Pedro, Ulrich, Tom, Bruno:
I put together a test case that demonstrates the error in the reverse-
next command based on Pedro's example from our earlier discussion. I
thought it would be best to make sure we all agree what the expected
behavior of the test should be before attempting to fix the issue. :-)
The first test scenario in the test is the example that Pedo gave. The
test expects that the reverse-next will stop at the beginning of the
line containing the two function calls. Then a reverse-step command
should then stop at the previous source code line. The test currently
fails the same on X86 and PowerPC, as expected, because the reverse-
next in correctly stops between func1 and func2. The following
reverse-step stops at the end of func1 not at the previous source code
line as it should.
I added a second test to do a reverse-step all the way back thru the
source line with the two function calls on it to make sure we agree on
the expected results for that scenario as well. The second test passes
on X86 and PowerPC.
The test case, explanation from Pedro's test, i.e. my first test case.
The patch for the new test case is attached at the end.
Thanks for the help reviewing this test.
Carl
On Tue, 2023-01-24 at 14:08 +0000, Pedro Alves wrote:
<snip>
>
> Wait. That right there sounds bogus. The source line looks like:
>
> func1 (); func2 ();
>
> so stepping backwards over that line should always stop at the first
> instruction of the line, not in the middle. Let's simplify this.
>
> Here's the full source code of my example:
>
> (gdb) list 1
> 1 void func1 ()
> 2 {
> 3 }
> 4
> 5 void func2 ()
> 6 {
> 7 }
> 8
> 9 int main ()
> 10 {
> 11 func1 (); func2 ();
> 12 }
>
> Compiled with:
>
> $ gcc reverse.c -o reverse -g3 -O0
> $ gcc -v
> ...
> gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
>
> Now let's debug it with target record, using current gdb git master
> (f3d8ae90b236),
> without your patch:
>
> $ gdb ~/reverse
> GNU gdb (GDB) 14.0.50.20230124-git
> ...
> Reading symbols from /home/pedro/reverse...
> (gdb) start
> Temporary breakpoint 1 at 0x1147: file reverse.c, line 11.
> Starting program: /home/pedro/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-
> gnu/libthread_db.so.1".
>
> Temporary breakpoint 1, main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) record
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> => 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
>
> (gdb) n
> 12 }
>
> So far so good, a "next" stepped over the whole of line 11 and
> stopped at line 12.
>
> Let's confirm where we are now:
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> => 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
>
> Good, we're at the first instruction of line 12.
>
> Now let's undo the "next", with "reverse-next":
>
> (gdb) reverse-next
> 11 func1 (); func2 ();
>
> Seemingly stopped at line 11. Let's see exactly where:
>
> (gdb) disassemble /s
> Dump of assembler code for function main:
> reverse.c:
> 10 {
> 0x000055555555513f <+0>: endbr64
> 0x0000555555555143 <+4>: push %rbp
> 0x0000555555555144 <+5>: mov %rsp,%rbp
>
> 11 func1 (); func2 ();
> 0x0000555555555147 <+8>: mov $0x0,%eax
> 0x000055555555514c <+13>: call 0x555555555129 <func1>
> => 0x0000555555555151 <+18>: mov $0x0,%eax
> 0x0000555555555156 <+23>: call 0x555555555134 <func2>
> 0x000055555555515b <+28>: mov $0x0,%eax
>
> 12 }
> 0x0000555555555160 <+33>: pop %rbp
> 0x0000555555555161 <+34>: ret
> End of assembler dump.
> (gdb)
>
> And lo, we stopped in the middle of line 11! That is a bug, we
> should have stepped
> back all the way to the beginning of the line. The "reverse-next"
> should have fully
> undone the prior "next" command. Here's the same thing without the
> distracting
> disassemble commands:
>
> (gdb) b 11
> Breakpoint 1 at 0x1147: file reverse.c, line 11.
> (gdb) r
> Starting program: /home/pedro/reverse
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-
> gnu/libthread_db.so.1".
>
> Breakpoint 1, main () at reverse.c:11
> 11 func1 (); func2 ();
> (gdb) p $pc
> $1 = (void (*)()) 0x555555555147 <main+8>
> (gdb) record
> (gdb) next
> 12 }
> (gdb) reverse-next
> 11 func1 (); func2 ();
> (gdb) p $pc
> $2 = (void (*)()) 0x555555555151 <main+18>
> (gdb)
>
>
> This:
>
> next -> reverse-next -> next -> reverse-next
>
> ... should leave you at the same instruction. But it doesn't in this
> example!
>
-------------------------------------------------------
Patch for the test case based on Pedro's test
New pedro test
---
gdb/testsuite/gdb.reverse/pedro_test.c | 18 ++++
gdb/testsuite/gdb.reverse/pedro_test.exp | 118 +++++++++++++++++++++++
2 files changed, 136 insertions(+)
create mode 100644 gdb/testsuite/gdb.reverse/pedro_test.c
create mode 100644 gdb/testsuite/gdb.reverse/pedro_test.exp
diff --git a/gdb/testsuite/gdb.reverse/pedro_test.c b/gdb/testsuite/gdb.reverse/pedro_test.c
new file mode 100644
index 00000000000..e3183356ff6
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/pedro_test.c
@@ -0,0 +1,18 @@
+void
+func1 ()
+{
+}
+
+void
+func2 ()
+{
+}
+
+int main ()
+{
+ int a, b;
+ a = 1;
+ b = 2;
+ func1 (); func2 ();
+ a = a + b; // START REVERSE TEST
+}
diff --git a/gdb/testsuite/gdb.reverse/pedro_test.exp b/gdb/testsuite/gdb.reverse/pedro_test.exp
new file mode 100644
index 00000000000..d315e993d5f
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/pedro_test.exp
@@ -0,0 +1,118 @@
+# 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".
+
+# This test checks to make sure there is no regression failures for
+# the reverse-next command when stepping back over two functions in
+# the same line.
+
+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-next command
+# Set breakpoint at the line after the function calls.
+set bp_start_reverse_test [gdb_get_line_number "START REVERSE TEST" $srcfile]
+gdb_breakpoint $srcfile:$bp_start_reverse_test temporary
+
+# Continue to break point for reverse-next test.
+# Command definition: reverse-next [count]
+# Run backward to the beginning of the previous line executed in the current
+# (innermost) stack frame. If the line contains function calls, they will be
+# “un-executed” without stopping. Starting from the first line of a function,
+# reverse-next will take you back to the caller of that function, before the
+# function was called, just as the normal next command would take you from
+# the last line of a function back to its return to its caller 2 .
+
+gdb_continue_to_breakpoint \
+ "stopped at command reverse-next test start location" \
+ ".*$srcfile:$bp_start_reverse_test\r\n.*"
+
+# The reverse-next should step all the way back to the begining of the line,
+# i.e. at the begining of the func1 call.
+gdb_test "reverse-next" ".*func1 \\(\\); func2 \\(\\);.*" \
+ "reverse-next to line with two functions"
+
+# A reverse-step should step back and stop at the begining
+# of the previous line b = 2, i.e. not in func1 ().
+gdb_test "reverse-step" ".*b = 2;.*" \
+ "reverse-step to previous line b = 2"
+
+
+# Setup for test 2
+# Go back to the start of the function
+gdb_test "reverse-continue" "a = 1;" "At start of main, 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-step command
+# Set breakpoint at the line after the function calls.
+gdb_breakpoint $srcfile:$bp_start_reverse_test temporary
+
+# Continue to the start of the reverse-step test.
+# Command definition: reverse-step [count]
+# Run the program backward until control reaches the start of a
+# different source line; then stop it, and return control to gdb.
+# Like the step command, reverse-step will only stop at the beginning of a
+# source line. It “un-executes” the previously executed source line. If the
+# previous source line included calls to debuggable functions, reverse-step
+# will step (backward) into the called function, stopping at the beginning
+# of the last statement in the called function (typically a return
+# statement). Also, as with the step command, if non-debuggable functions
+# are called, reverse-step will run thru them backward without stopping.
+
+gdb_continue_to_breakpoint \
+ "stopped at command reverse-step test start location" \
+ ".*$srcfile:$bp_start_reverse_test\r\n.*"
+
+# The first reverse step should take us call of func2 ().
+gdb_test "reverse-step" ".*}.*" \
+ "reverse-step into func2 "
+
+# The second reverse step should take us call of func2 ().
+gdb_test "reverse-step" ".*func1 \\(\\); func2 \\(\\);.*" \
+ "reverse-step to line func1(); func2(), at call for func2 "
+
+# The third reverse step should take us into func1 ().
+gdb_test "reverse-step" ".*}.*" \
+ "reverse-step into func1 "
+
+# The fourth reverse step should take us call of func1 ().
+gdb_test "reverse-step" ".*func1 \\(\\); func2 \\(\\);.*" \
+ "reverse-step to line func1(); func2(), at call for func1 "
+
+# The fifth reverse step should take us to b = 2 ().
+gdb_test "reverse-step" ".*b = 2;.*" \
+ "reverse-step to line b = 2 "
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: Reverse-next bug test case
2023-01-31 0:17 ` Reverse-next bug test case Carl Love
@ 2023-02-01 14:37 ` Pedro Alves
2023-02-01 18:40 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Pedro Alves @ 2023-02-01 14:37 UTC (permalink / raw)
To: Carl Love, Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches
On 2023-01-31 12:17 a.m., Carl Love wrote:
> +# The second reverse step should take us call of func2 ().
> +gdb_test "reverse-step" ".*func1 \\(\\); func2 \\(\\);.*" \
> + "reverse-step to line func1(); func2(), at call for func2 "
> +
From <https://sourceware.org/gdb/current/onlinedocs/gdb.html/Reverse-Execution.html> :
"Like the step command, reverse-step will only stop at the beginning of a source line. "
So when reverse-stepping is ongoing and execution internally stops at the call to func2, gdb
should realize it is not really at the beginning of a source line, and continue stepping.
That should take it inside func1, and stop there (at the beginning of a line), as it will have
reached a different line.
I would start by looking at making either of these pass:
$ make check TESTS="*/pedro_test.exp" RUNTESTFLAGS="CC_FOR_TARGET='gcc -gno-column-info'"
$ make check TESTS="*/pedro_test.exp" RUNTESTFLAGS="CC_FOR_TARGET=clang"
... as the misbehavior happens due to GDB misinterpreting multiple lines entries for the
same line when column info is emitted by current gcc. If you disable the column info, then gdb
should not stop in the middle of a line, and that's how gdb should always behave. (Making use
of column info is certainly interesting to support statement stepping, but that's orthogonal.)
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: Reverse-next bug test case
2023-02-01 14:37 ` Pedro Alves
@ 2023-02-01 18:40 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-02-01 18:40 UTC (permalink / raw)
To: Pedro Alves, Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
Pedro:
On Wed, 2023-02-01 at 14:37 +0000, Pedro Alves wrote:
> On 2023-01-31 12:17 a.m., Carl Love wrote:
> > +# The second reverse step should take us call of func2 ().
> > +gdb_test "reverse-step" ".*func1 \\(\\); func2 \\(\\);.*" \
> > + "reverse-step to line func1(); func2(), at call for func2 "
> > +
>
> From <
> https://sourceware.org/gdb/current/onlinedocs/gdb.html/Reverse-Execution.html
> > :
>
> "Like the step command, reverse-step will only stop at the beginning
> of a source line. "
>
> So when reverse-stepping is ongoing and execution internally stops at
> the call to func2, gdb
> should realize it is not really at the beginning of a source line,
> and continue stepping.
> That should take it inside func1, and stop there (at the beginning of
> a line), as it will have
> reached a different line.
>
> I would start by looking at making either of these pass:
>
> $ make check TESTS="*/pedro_test.exp"
> RUNTESTFLAGS="CC_FOR_TARGET='gcc -gno-column-info'"
OK, when I try the test with no column info, the test on PowerPC fails.
The initial Test 2 expected the second reverse-step to stop at func1();
func2() after stepping into func2 (). When the Test 2 is updated to
remove the second reverse-step:
...
gdb_continue_to_breakpoint \
"stopped at command reverse-step test start location" \
".*$srcfile:$bp_start_reverse_test\r\n.*"
# The first reverse step should take us call of func2 ().
gdb_test "reverse-step" ".*}.*" \
"reverse-step into func2 "
# The second reverse step should take us call of func2 ().
## ERROR, should not stop here as that is in the middle of the source line
#gdb_test "reverse-step" ".*func1 \\(\\); func2 \\(\\);.*" \
# "reverse-step to line func1(); func2(), at call for func2 "
# The third reverse step should take us into func1 ().
gdb_test "reverse-step" ".*}.*" \
"reverse-step into func1 "
# The fourth reverse step should take us call of func1 ().
gdb_test "reverse-step" ".*func1 \\(\\); func2 \\(\\);.*" \
"reverse-step to line func1(); func2(), at call for func1 "
# The fifth reverse step should take us to b = 2 ().
gdb_test "reverse-step" ".*b = 2;.*" \
"reverse-step to line b = 2 "
Then the test passes when running with no column info.
OK, that helps. Thanks.
Carl
>
> $ make check TESTS="*/pedro_test.exp"
> RUNTESTFLAGS="CC_FOR_TARGET=clang"
>
> ... as the misbehavior happens due to GDB misinterpreting multiple
> lines entries for the
> same line when column info is emitted by current gcc. If you disable
> the column info, then gdb
> should not stop in the middle of a line, and that's how gdb should
> always behave. (Making use
> of column info is certainly interesting to support statement
> stepping, but that's orthogonal.)
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-01-20 20:04 ` Carl Love
2023-01-23 16:42 ` [PATCH 1/2 version 3] " Carl Love
2023-01-23 16:42 ` [PATCH 2/2 " Carl Love
@ 2023-02-10 20:55 ` Carl Love
2023-02-17 12:24 ` Ulrich Weigand
2 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-02-10 20:55 UTC (permalink / raw)
To: Bruno Larsen, PedroAlves, Tom de Vries, Ulrich Weigand, gdb-patches; +Cc: cel
GDB maintainers:
I have reworked the PowerPC patch from the previous series to fix the
behavior of the reverse-finish command on PowerPC. The patch does not
change the behavior of the reverse-finish command on other
architectures. The patch simply make the command on PowerPC behave the
same as other architectures, specifically X86.
The issue with the reverse-finish command on PowerPC is the reverse-
finish command doesn't stop at the function call. The issue is PowerPC
uses two entry points. PowerPC calls the two entry points the local
entry point (LEP) and the global entry point (GEP). The LEP is
normally used when calling a function. The GEP is used when the table
of contents (TOC) needs to be setup before continuing execution at the
LEP. GDB is not handling the two entry points correctly. On systems
that don't use two entry points the LEP and the GEP are the same.
A new test case is added to verify the reverse-finish command works
properly. It checks five cases for the reverse-finish command,
executing the command when stopped on the alternate entry point, the
normal entry point, between the entry points, the body of the function
when it is called via the normal entry point and finally the body of
the function when called via the alternate entry point.
The patch and new test have been run on Power 10, Intel X86 pre
generation 5 and an Intel X86 system with a generation 5 processor.
The 5th generation X86 system is needed to run the btrace/tailcall.exp
and btrace/tailcall-only.exp tests that were an issue with the previous
patch series which was withdrawn from consideration.
Please let me know if the patch is acceptable. Thanks.
Carl
----------------------------------------------------------
PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
PPC64 multiple entry points. When executing in reverse the function
finish_backward sets the break point at the alternate entry point, known
as the global entry point (GEP) in PowerPC. However if the forward
execution enters via the normal entry point, known as the local entry
point (LEP) on PowerPC, reverse execution never sees the break point at the
alternate entry point of the function. Reverse execution continues until
the next break point is encountered thus stopping at the wrong place.
This patch adds a new address to struct execution_control_state to hold the
address of the alternate entry point (GEP). The finish_backwards function
is updated, if the stopping point is between the normal entry point (LEP)
and the end of the function, a breakpoint is set at the normal entry point.
If the stopping point is between the entry points, a breakpoint is set to
the alternate entry point.
The patch fixes the behavior of the reverse-finish command on PowerPC to
match the behavior of the command on other platforms, specifically X86.
The patch does not change the behavior of the command on X86.
A new test is added to verify the reverse-finish command on PowerPC
correctly stops at the instruction where the function call is made. A new
test, finish-reverse-next.exp, is added to verify the correct functionality
of the reverse-finish command. The reverse-finish comand is expected to
stop on the instruction that jumps to the function. Procedure
proc_step_until from test gdb.reverse/step-indirect-call-thunk.exp is moved
to lib/gdb.exp and renamed repeat_cmd_until.
The patch fixes 11 regression errors in test gdb.reverse/finish-precsave.exp
and 11 regression errors in test gdb.reverse/finish-reverse.exp.
The patch has been tested on Power 10 and X86 processor with no new
regression failures.
---
gdb/infcmd.c | 47 ++--
gdb/infrun.c | 26 ++
.../gdb.reverse/finish-reverse-next.c | 91 +++++++
.../gdb.reverse/finish-reverse-next.exp | 224 ++++++++++++++++++
.../gdb.reverse/step-indirect-call-thunk.exp | 33 ---
gdb/testsuite/lib/gdb.exp | 33 +++
6 files changed, 404 insertions(+), 50 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 77206fcbfe8..a65cc700fc9 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm *sm)
no way that a function up the stack can have a return address
that's equal to its entry point. */
- if (sal.pc != pc)
- {
- frame_info_ptr frame = get_selected_frame (nullptr);
- struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR alt_entry_point = sal.pc;
+ CORE_ADDR entry_point = alt_entry_point;
+ 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
- hit, we'll do one more step backwards. */
- symtab_and_line sr_sal;
- sr_sal.pc = sal.pc;
- sr_sal.pspace = get_frame_program_space (frame);
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ if (gdbarch_skip_entrypoint_p (gdbarch))
+ /* Some architectures, like PowerPC use local and global entry points.
+ There is only one Entry Point (GEP = LEP) for other architectures.
+ The GEP is an alternate entry point. The LEP is the normal entry point.
+ The value of entry_point was initialized to the alternate entry point
+ (GEP). It will be adjusted to the normal entry point if the function
+ has two entry points. */
+ entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
+
+ if ((pc >= alt_entry_point) && (pc <= entry_point))
+ /* We are either at one of the entry points or between the entry points.
+ If we are not at the alt_entry point, go back to the alt_entry_point
+ If we at the normal entry point step back one instruction, when we
+ stop we will determine if we entered via the entry point or the
+ alternate entry point. If we are at the alternate entry point,
+ single step back to the function call. */
+ tp->control.step_range_start = tp->control.step_range_end = 1;
- 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 in the body of the function. Set a breakpoint to backup to
+ the normal entry point. */
+ symtab_and_line sr_sal;
+ sr_sal.pc = entry_point;
+ 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);
}
/* finish_forward -- helper function for finish_command. FRAME is the
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 87ab73c47a4..f0bd13fc219 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1868,6 +1868,7 @@ struct execution_control_state
struct target_waitstatus ws;
int stop_func_filled_in = 0;
+ CORE_ADDR stop_func_alt_start = 0;
CORE_ADDR stop_func_start = 0;
CORE_ADDR stop_func_end = 0;
const char *stop_func_name = nullptr;
@@ -4680,6 +4681,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (gdbarch);
+ /* PowerPC functions have a Local Entry Point (LEP) and a Global
+ Entry Point (GEP). There is only one Entry Point (GEP = LEP) for
+ other architectures. */
+ ecs->stop_func_alt_start = ecs->stop_func_start;
+
if (gdbarch_skip_entrypoint_p (gdbarch))
ecs->stop_func_start
= gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
@@ -7269,6 +7275,26 @@ process_event_stop_test (struct execution_control_state *ecs)
}
}
+ if (execution_direction == EXEC_REVERSE
+ && ecs->event_thread->control.proceed_to_finish)
+ {
+ /* We are executing the reverse-finish command. */
+ if (ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
+ && ecs->event_thread->stop_pc () < ecs->stop_func_start
+ && ecs->stop_func_alt_start != ecs->stop_func_start)
+ /* If the system supports multiple entry points and we are finishing a
+ function in reverse. If we are between the entry points singe-step
+ back to the alternate entry point. If we are at the alternate entry
+ point -- just need to back up by one more single-step, which
+ should take us back to the function call. */
+ {
+ ecs->event_thread->control.step_range_start
+ = ecs->event_thread->control.step_range_end = 1;
+ keep_going (ecs);
+ return;
+ }
+ }
+
if (ecs->event_thread->control.step_range_end == 1)
{
/* It is stepi or nexti. We always want to stop stepping after
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 00000000000..e95ee8e33a6
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
@@ -0,0 +1,91 @@
+/* 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
+
+ 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). The GEP is only used if the table of
+ contents (TOC) value stored in register r2 needs to be setup prior to
+ execution starting at the LEP. 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. */
+
+int
+function2 (int a, int b)
+{
+ int ret = 0;
+ ret = ret + a + b;
+ return ret;
+}
+
+int
+function1 (int a, int b) // FUNCTION1
+{
+ int ret = 0;
+ int (*funp) (int, int) = &function2;
+ /* The assembly code for this function when compiled for PowerPC is as
+ follows:
+
+ 0000000010000758 <function1>:
+ 10000758: 02 10 40 3c lis r2,4098 <- GEP
+ 1000075c: 00 7f 42 38 addi r2,r2,32512
+ 10000760: a6 02 08 7c mflr r0 <- LEP
+ 10000764: 10 00 01 f8 std r0,16(r1)
+ ....
+
+ When the function is called on PowerPC with function1 (a, b) the call
+ enters at the Local Entry Point (LEP). When the function is called via
+ a function pointer, the Global Entry Point (GEP) for function1 is used.
+ The GEP sets up register 2 before reaching the LEP.
+ */
+ ret = funp (a + 1, b + 2);
+ return ret;
+}
+
+int
+main(int argc, char* argv[])
+{
+ int a, b;
+ int (*funp) (int, int) = &function1;
+
+ /* Call function via Local Entry Point (LEP). */
+
+ a = 1;
+ b = 5;
+
+ function1 (a, b); // CALL VIA LEP
+
+ /* Call function via Global Entry Point (GEP). */
+ a = 10;
+ b = 50;
+
+ funp (a, b); // CALL VIA GEP
+ 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 00000000000..6e08530c970
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -0,0 +1,224 @@
+# 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
+
+# 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
+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 (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"
+
+# The reverse-finish command should stop on the function call instruction
+# which is the last instruction in the source code line. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP" \
+ "reverse next 1 LEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse next 1 LEP 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP call from function body"
+gdb_test "reverse-next" ".*b = 50;.*" \
+ "reverse next 2 at b = 50 from function body"
diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
index 94292d5eb9b..dc5cf097511 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"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index faa0ac05a9a..c156982a674 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9295,6 +9295,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.
#
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-10 20:55 ` [PATCH ] PowerPC: " Carl Love
@ 2023-02-17 12:24 ` Ulrich Weigand
2023-02-20 16:34 ` Carl Love
2023-02-20 20:24 ` Carl Love
0 siblings, 2 replies; 105+ messages in thread
From: Ulrich Weigand @ 2023-02-17 12:24 UTC (permalink / raw)
To: gdb-patches, Bruno Larsen, tdevries, cel, pedro
Carl Love <cel@us.ibm.com> wrote:
This looks generally OK to me, except for two minor issues
in the code base, and one problem in the test suite:
>diff --git a/gdb/infcmd.c b/gdb/infcmd.c
>index 77206fcbfe8..a65cc700fc9 100644
>--- a/gdb/infcmd.c
>+++ b/gdb/infcmd.c
>@@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm *sm)
> no way that a function up the stack can have a return address
> that's equal to its entry point. */
>
>- if (sal.pc != pc)
>- {
>- frame_info_ptr frame = get_selected_frame (nullptr);
>- struct gdbarch *gdbarch = get_frame_arch (frame);
>+ CORE_ADDR alt_entry_point = sal.pc;
>+ CORE_ADDR entry_point = alt_entry_point;
>+ 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
>- hit, we'll do one more step backwards. */
>- symtab_and_line sr_sal;
>- sr_sal.pc = sal.pc;
>- sr_sal.pspace = get_frame_program_space (frame);
>- insert_step_resume_breakpoint_at_sal (gdbarch,
>- sr_sal, null_frame_id);
>+ if (gdbarch_skip_entrypoint_p (gdbarch))
>+ /* Some architectures, like PowerPC use local and global entry points.
>+ There is only one Entry Point (GEP = LEP) for other architectures.
>+ The GEP is an alternate entry point. The LEP is the normal entry point.
>+ The value of entry_point was initialized to the alternate entry point
>+ (GEP). It will be adjusted to the normal entry point if the function
>+ has two entry points. */
>+ entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
>+
>+ if ((pc >= alt_entry_point) && (pc <= entry_point))
>+ /* We are either at one of the entry points or between the entry points.
>+ If we are not at the alt_entry point, go back to the alt_entry_point
>+ If we at the normal entry point step back one instruction, when we
>+ stop we will determine if we entered via the entry point or the
>+ alternate entry point. If we are at the alternate entry point,
>+ single step back to the function call. */
>+ tp->control.step_range_start = tp->control.step_range_end = 1;
>
>- 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 in the body of the function. Set a breakpoint to backup to
>+ the normal entry point. */
>+ symtab_and_line sr_sal;
>+ sr_sal.pc = entry_point;
>+ 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);
> }
This change looks much larger than it actually is, because you've
swapped the order of the if vs. else blocks (the orignal code sets
the breakpoint in the if path and the single-step range in the
else path, while you've swapped this). Can you swap this back to
shorten the diff?
>+ if (execution_direction == EXEC_REVERSE
>+ && ecs->event_thread->control.proceed_to_finish)
>+ {
>+ /* We are executing the reverse-finish command. */
>+ if (ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
>+ && ecs->event_thread->stop_pc () < ecs->stop_func_start
>+ && ecs->stop_func_alt_start != ecs->stop_func_start)
This third condition seems redundant: if stop_pc is >= func_alt_start
*and* < func_start, then func_alt_start cannot be equal func_start.
>diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
>index 94292d5eb9b..dc5cf097511 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"
How is it OK to just remove this procedure? This is still used
in the rest of the step-indirect-call-thunk.exp test case ...
I get why you may want to reduce duplication, but then you'd
have to update current users of "step_until" as well.
Also, talking about duplication, should the (already separate)
gdb_step_until command in lib/gdb.exp now just be a variant
of the new repeat_cmd_until ?
Bye,
Ulrich
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-17 12:24 ` Ulrich Weigand
@ 2023-02-20 16:34 ` Carl Love
2023-02-20 16:48 ` Bruno Larsen
2023-02-20 20:24 ` Carl Love
1 sibling, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-02-20 16:34 UTC (permalink / raw)
To: Ulrich Weigand, gdb-patches, Bruno Larsen, tdevries, pedro; +Cc: cel
On Fri, 2023-02-17 at 12:24 +0000, Ulrich Weigand wrote:
> Carl Love <cel@us.ibm.com> wrote:
>
> This looks generally OK to me, except for two minor issues
> in the code base, and one problem in the test suite:
>
>
> > diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> > index 77206fcbfe8..a65cc700fc9 100644
> > --- a/gdb/infcmd.c
> > +++ b/gdb/infcmd.c
> > @@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm
> > *sm)
> > no way that a function up the stack can have a return address
> > that's equal to its entry point. */
> >
> > - if (sal.pc != pc)
> > - {
> > - frame_info_ptr frame = get_selected_frame (nullptr);
> > - struct gdbarch *gdbarch = get_frame_arch (frame);
> > + CORE_ADDR alt_entry_point = sal.pc;
> > + CORE_ADDR entry_point = alt_entry_point;
> > + 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
> > - hit, we'll do one more step backwards. */
> > - symtab_and_line sr_sal;
> > - sr_sal.pc = sal.pc;
> > - sr_sal.pspace = get_frame_program_space (frame);
> > - insert_step_resume_breakpoint_at_sal (gdbarch,
> > - sr_sal, null_frame_id);
> > + if (gdbarch_skip_entrypoint_p (gdbarch))
> > + /* Some architectures, like PowerPC use local and global entry
> > points.
> > + There is only one Entry Point (GEP = LEP) for other
> > architectures.
> > + The GEP is an alternate entry point. The LEP is the normal
> > entry point.
> > + The value of entry_point was initialized to the alternate
> > entry point
> > + (GEP). It will be adjusted to the normal entry point if
> > the function
> > + has two entry points. */
> > + entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
> > +
> > + if ((pc >= alt_entry_point) && (pc <= entry_point))
> > + /* We are either at one of the entry points or between the
> > entry points.
> > + If we are not at the alt_entry point, go back to the
> > alt_entry_point
> > + If we at the normal entry point step back one instruction,
> > when we
> > + stop we will determine if we entered via the entry point or
> > the
> > + alternate entry point. If we are at the alternate entry
> > point,
> > + single step back to the function call. */
> > + tp->control.step_range_start = tp->control.step_range_end = 1;
> >
> > - 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 in the body of the function. Set a breakpoint to
> > backup to
> > + the normal entry point. */
> > + symtab_and_line sr_sal;
> > + sr_sal.pc = entry_point;
> > + 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);
> > }
>
> This change looks much larger than it actually is, because you've
> swapped the order of the if vs. else blocks (the orignal code sets
> the breakpoint in the if path and the single-step range in the
> else path, while you've swapped this). Can you swap this back to
> shorten the diff?
OK, swapped them.
>
> > + if (execution_direction == EXEC_REVERSE
> > + && ecs->event_thread->control.proceed_to_finish)
> > + {
> > + /* We are executing the reverse-finish command. */
> > + if (ecs->event_thread->stop_pc () >= ecs-
> > >stop_func_alt_start
> > + && ecs->event_thread->stop_pc () < ecs->stop_func_start
> > + && ecs->stop_func_alt_start != ecs->stop_func_start)
>
> This third condition seems redundant: if stop_pc is >= func_alt_start
> *and* < func_start, then func_alt_start cannot be equal func_start.
Yes, on Powerpc the third condition is redundant. However, on other
platforms, specifically X86, the third condition is always false which
ensures the if statement is false. This is important on the tests
gdb.btrace/tailcall-only.exp and gdb.btrace/tailcall.exp which only run
on X86. The tests call the up command which will satisfy conditions 1
and 2 and thus do an "extra" step command resulting in a test failure.
The third condition ensures that we never execute an additional
reverse-step unless the platform supports multiple entry points and we
are at the alternate entry point. I can see where this is not obvious
at first glance. I added a comment to the if statement explaining the
need for the apparent redundancy.
Also, the if statement is nested inside of the if reverse if statement.
I combined the two if statements into a single if statement.
> > diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> > b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> > index 94292d5eb9b..dc5cf097511 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"
>
> How is it OK to just remove this procedure? This is still used
> in the rest of the step-indirect-call-thunk.exp test case ...
Yes, looks like my fix up of the call to step_until in step-indirect-
call-thunk.exp got lost somewhere along the line. I remember making
the change.
I went back to see why the regression testing didn't catch the error.
On PowerPC, the test doesn't run as the compile options "-mindirect-
branch=thunk" and "-mfunction-return=thunk" are not supported on
PowerPC, so the test fails anyways. It looks like the test didn't run
on my X86 either due to the regression test failing before getting to
the gdb tests. Looks like I need to run the regression test in
subdirectory gdb to make sure all of the gdb tests get run.
I have run the updated patch, on X86, manually and in the regression
test to make sure there are no regressions with this test. I checked
out the base and regression runs on X86 to make sure the regression
tests are all be run.
>
> I get why you may want to reduce duplication, but then you'd
> have to update current users of "step_until" as well.
Yes, those updates got lost rebasing the patch at some point. Fixed.
>
> Also, talking about duplication, should the (already separate)
> gdb_step_until command in lib/gdb.exp now just be a variant
> of the new repeat_cmd_until ?
OK, I extended the new repeat_cmd_until proceedure to take the
additional input max_steps. I created a new version of gdb_step_until
that calls repeat_cmd_until. I added an optional argument, current, to
gdb_step_until proceedure for the current line. By default, current is
set to "\}" which is needed by the call to repeat_cmd_until proceedure.
The new gdb_step_until proceedure works in the existing regression
tests without changing the gdb_step_until call in the existing tests.
Thanks for reviewing the patch. I will post an updated patch shortly.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-20 16:34 ` Carl Love
@ 2023-02-20 16:48 ` Bruno Larsen
0 siblings, 0 replies; 105+ messages in thread
From: Bruno Larsen @ 2023-02-20 16:48 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, gdb-patches, tdevries, pedro
On 20/02/2023 17:34, Carl Love wrote:
>>> + if (execution_direction == EXEC_REVERSE
>>> + && ecs->event_thread->control.proceed_to_finish)
>>> + {
>>> + /* We are executing the reverse-finish command. */
>>> + if (ecs->event_thread->stop_pc () >= ecs-
>>>> stop_func_alt_start
>>> + && ecs->event_thread->stop_pc () < ecs->stop_func_start
>>> + && ecs->stop_func_alt_start != ecs->stop_func_start)
>> This third condition seems redundant: if stop_pc is >= func_alt_start
>> *and* < func_start, then func_alt_start cannot be equal func_start.
> Yes, on Powerpc the third condition is redundant. However, on other
> platforms, specifically X86, the third condition is always false which
> ensures the if statement is false. This is important on the tests
> gdb.btrace/tailcall-only.exp and gdb.btrace/tailcall.exp which only run
> on X86. The tests call the up command which will satisfy conditions 1
> and 2 and thus do an "extra" step command resulting in a test failure.
> The third condition ensures that we never execute an additional
> reverse-step unless the platform supports multiple entry points and we
> are at the alternate entry point. I can see where this is not obvious
> at first glance. I added a comment to the if statement explaining the
> need for the apparent redundancy.
But it is always redundant, even on x86. If the stop_func_start is A,
there is no way the stop_pc can be simultaneously larger or equal to A,
and strictly smaller than A. The only way the third condition would make
a difference is if the second condition was `ecs->event_thread->stop_pc
() <= ecs->stop_func_start`
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-17 12:24 ` Ulrich Weigand
2023-02-20 16:34 ` Carl Love
@ 2023-02-20 20:24 ` Carl Love
2023-02-27 16:09 ` [PING] " Carl Love
` (4 more replies)
1 sibling, 5 replies; 105+ messages in thread
From: Carl Love @ 2023-02-20 20:24 UTC (permalink / raw)
To: Ulrich Weigand, gdb-patches, Bruno Larsen, tdevries, pedro; +Cc: cel
Ulrich, Bruno, GDB maintainers:
Per the comments from Ulrich, I have updated the patch to address the
comments about the source code and the testcase. I updated the new
library procedure so it can be called from gdb_step_until. So
gdb_step_until is now just a variant of the new repeat_cmd_until
proceedure.
The redundant if test has been removed. It was added to fix a
regression testing failure I saw on the gdb.btrace/tailcall.exp on X86.
I went back and redid the testing, rebuilding everything from scratch.
I am not able to reproduce the test failure without the redundant
check. Not sure why I initially saw the regression failure at this
point? Perhaps I hadn't re-enabled the
/proc/sys/kernel/perf_event_paranoid value? It must be 2 or lower for
the test to run. Otherwise the test fails. Anyway, the regression
tests on X86 run without the redundant check are passing on my laptop.
I resolved the issues with the testing on X86 to make sure it isn't
missing failures when testing gdb.reverse/step-indirect-call-thunk.exp.
As mentioned in the previous email, the test does not run on PowerPC
since the gcc command line options "-mindirect-branch=thunk" and "-
mfunction-return=thunk" are not supported on PowerPC. I disabled the
test on PowerPC in the updated patch.
Retested on X86 generation 5 and PowerPC with no regressions found.
Hopefully this version of the patch is acceptable.
Carl
-----------------------------------------------------
PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
PPC64 multiple entry points. When executing in reverse the function
finish_backward sets the break point at the alternate entry point, known
as the global entry point (GEP) in PowerPC. However if the forward
execution enters via the normal entry point, known as the local entry
point (LEP) on PowerPC, reverse execution never sees the break point at the
alternate entry point of the function. Reverse execution continues until
the next break point is encountered thus stopping at the wrong place.
This patch adds a new address to struct execution_control_state to hold the
address of the alternate entry point (GEP). The finish_backwards function
is updated, if the stopping point is between the normal entry point (LEP)
and the end of the function, a breakpoint is set at the normal entry point.
If the stopping point is between the entry points, a breakpoint is set to
the alternate entry point.
The patch fixes the behavior of the reverse-finish command on PowerPC to
match the behavior of the command on other platforms, specifically X86.
The patch does not change the behavior of the command on X86.
A new test is added to verify the reverse-finish command on PowerPC
correctly stops at the instruction where the function call is made. A new
test, finish-reverse-next.exp, is added to verify the correct functionality
of the reverse-finish command. The reverse-finish comand is expected to
stop on the instruction that jumps to the function. Procedure
proc_step_until from test gdb.reverse/step-indirect-call-thunk.exp is moved
to lib/gdb.exp and renamed repeat_cmd_until.
The patch fixes 11 regression errors in test gdb.reverse/finish-precsave.exp
and 11 regression errors in test gdb.reverse/finish-reverse.exp.
The patch has been tested on Power 10 and X86 processor with no new
regression failures.
---
gdb/infcmd.c | 47 ++--
gdb/infrun.c | 24 ++
.../gdb.reverse/finish-reverse-next.c | 91 +++++++
.../gdb.reverse/finish-reverse-next.exp | 224 ++++++++++++++++++
.../gdb.reverse/step-indirect-call-thunk.exp | 55 ++---
gdb/testsuite/lib/gdb.exp | 49 +++-
6 files changed, 421 insertions(+), 69 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 77206fcbfe8..0fa5719d38b 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm *sm)
no way that a function up the stack can have a return address
that's equal to its entry point. */
- if (sal.pc != pc)
- {
- frame_info_ptr frame = get_selected_frame (nullptr);
- struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR alt_entry_point = sal.pc;
+ CORE_ADDR entry_point = alt_entry_point;
+ frame_info_ptr frame = get_selected_frame (nullptr);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ if (gdbarch_skip_entrypoint_p (gdbarch))
+ /* Some architectures, like PowerPC use local and global entry points.
+ There is only one Entry Point (GEP = LEP) for other architectures.
+ The GEP is an alternate entry point. The LEP is the normal entry point.
+ The value of entry_point was initialized to the alternate entry point
+ (GEP). It will be adjusted to the normal entry point if the function
+ has two entry points. */
+ entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
- /* Set a step-resume at the function's entry point. Once that's
- hit, we'll do one more step backwards. */
+ if ((pc < alt_entry_point) || (pc > entry_point))
+ {
+ /* We are in the body of the function. Set a breakpoint to backup to
+ the normal entry point. */
symtab_and_line sr_sal;
- sr_sal.pc = sal.pc;
+ sr_sal.pc = entry_point;
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);
+ insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
+ null_frame_id);
}
+
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 either at one of the entry points or between the entry points.
+ If we are not at the alt_entry point, go back to the alt_entry_point
+ If we at the normal entry point step back one instruction, when we
+ stop we will determine if we entered via the entry point or the
+ alternate entry point. If we are at the alternate entry point,
+ single step back to the function call. */
+ tp->control.step_range_start = tp->control.step_range_end = 1;
+
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
/* finish_forward -- helper function for finish_command. FRAME is the
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 87ab73c47a4..987dbd16ea4 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1868,6 +1868,7 @@ struct execution_control_state
struct target_waitstatus ws;
int stop_func_filled_in = 0;
+ CORE_ADDR stop_func_alt_start = 0;
CORE_ADDR stop_func_start = 0;
CORE_ADDR stop_func_end = 0;
const char *stop_func_name = nullptr;
@@ -4680,6 +4681,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (gdbarch);
+ /* PowerPC functions have a Local Entry Point (LEP) and a Global
+ Entry Point (GEP). There is only one Entry Point (GEP = LEP) for
+ other architectures. */
+ ecs->stop_func_alt_start = ecs->stop_func_start;
+
if (gdbarch_skip_entrypoint_p (gdbarch))
ecs->stop_func_start
= gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
@@ -7269,6 +7275,24 @@ process_event_stop_test (struct execution_control_state *ecs)
}
}
+ if (execution_direction == EXEC_REVERSE
+ && ecs->event_thread->control.proceed_to_finish
+ && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
+ && ecs->event_thread->stop_pc () < ecs->stop_func_start)
+ {
+ /* We are executing the reverse-finish command.
+ If the system supports multiple entry points and we are finishing a
+ function in reverse. If we are between the entry points singe-step
+ back to the alternate entry point. If we are at the alternate entry
+ point -- just need to back up by one more single-step, which
+ should take us back to the function call. */
+ ecs->event_thread->control.step_range_start
+ = ecs->event_thread->control.step_range_end = 1;
+ keep_going (ecs);
+ return;
+
+ }
+
if (ecs->event_thread->control.step_range_end == 1)
{
/* It is stepi or nexti. We always want to stop stepping after
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 00000000000..e95ee8e33a6
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
@@ -0,0 +1,91 @@
+/* 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
+
+ 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). The GEP is only used if the table of
+ contents (TOC) value stored in register r2 needs to be setup prior to
+ execution starting at the LEP. 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. */
+
+int
+function2 (int a, int b)
+{
+ int ret = 0;
+ ret = ret + a + b;
+ return ret;
+}
+
+int
+function1 (int a, int b) // FUNCTION1
+{
+ int ret = 0;
+ int (*funp) (int, int) = &function2;
+ /* The assembly code for this function when compiled for PowerPC is as
+ follows:
+
+ 0000000010000758 <function1>:
+ 10000758: 02 10 40 3c lis r2,4098 <- GEP
+ 1000075c: 00 7f 42 38 addi r2,r2,32512
+ 10000760: a6 02 08 7c mflr r0 <- LEP
+ 10000764: 10 00 01 f8 std r0,16(r1)
+ ....
+
+ When the function is called on PowerPC with function1 (a, b) the call
+ enters at the Local Entry Point (LEP). When the function is called via
+ a function pointer, the Global Entry Point (GEP) for function1 is used.
+ The GEP sets up register 2 before reaching the LEP.
+ */
+ ret = funp (a + 1, b + 2);
+ return ret;
+}
+
+int
+main(int argc, char* argv[])
+{
+ int a, b;
+ int (*funp) (int, int) = &function1;
+
+ /* Call function via Local Entry Point (LEP). */
+
+ a = 1;
+ b = 5;
+
+ function1 (a, b); // CALL VIA LEP
+
+ /* Call function via Global Entry Point (GEP). */
+ a = 10;
+ b = 50;
+
+ funp (a, b); // CALL VIA GEP
+ 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 00000000000..1f53b649a7d
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -0,0 +1,224 @@
+# 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
+
+# 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
+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 (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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP" \
+ "reverse next 1 LEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse next 1 LEP 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP call from function body"
+gdb_test "reverse-next" ".*b = 50;.*" \
+ "reverse next 2 at b = 50 from function body"
diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
index 94292d5eb9b..61fb4974b8e 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -17,6 +17,12 @@ require supports_reverse
standard_testfile
+if { [istarget "powerpc*-*-linux*"] } {
+ # GCC for PowerPC on linux does not support the -mindirect-branch and
+ # -mfunction-return command line options.
+ return 0
+}
+
set cflags {}
lappend cflags debug
lappend cflags additional_flags=-mindirect-branch=thunk
@@ -36,39 +42,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 +61,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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index faa0ac05a9a..b10555fe5fb 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9267,31 +9267,58 @@ gdb_caching_proc arm_cc_for_target {
# Step until the pattern REGEXP is found. Step at most
# MAX_STEPS times, but stop stepping once REGEXP is found.
-#
+# START matches current location
# If REGEXP is found then a single pass is emitted, otherwise, after
# MAX_STEPS steps, a single fail is emitted.
#
# TEST_NAME is the name used in the pass/fail calls.
-proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
+proc gdb_step_until { regexp {test_name ""} {current ""} \
+ { max_steps 10 } } {
+ if { $current == "" } {
+ set current "\}"
+ }
+ if { $test_name == "" } {
+ set test_name "stepping until regexp"
+ }
+
+ repeat_cmd_until "step" $current $regexp $test_name "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
+# MAX_STEPS is number of steps attempted before fail is emitted
+#
+# 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_name {max_steps 100} } {
+ global gdb_prompt
if { $test_name == "" } {
set test_name "stepping until regexp"
}
set count 0
- gdb_test_multiple "step" "$test_name" {
- -re "$regexp\r\n$::gdb_prompt $" {
- pass $test_name
- }
- -re ".*$::gdb_prompt $" {
- if {$count < $max_steps} {
- incr count
- send_gdb "step\n"
+ gdb_test_multiple "$command" "$test_name" {
+ -re "$current.*$gdb_prompt $" {
+ incr count
+ if { $count < $max_steps } {
+ send_gdb "$command\n"
exp_continue
} else {
- fail $test_name
+ fail "$test_name"
}
}
+ -re "$target.*$gdb_prompt $" {
+ pass "$test_name"
+ }
}
}
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PING] Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-20 20:24 ` Carl Love
@ 2023-02-27 16:09 ` Carl Love
2023-02-28 13:39 ` Bruno Larsen
` (3 subsequent siblings)
4 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-02-27 16:09 UTC (permalink / raw)
To: Ulrich Weigand, gdb-patches, Bruno Larsen, tdevries, pedro; +Cc: cel
Ulrich, Bruno, Tom, Pedro, GDB maintainers:
Wondering if anyone has had a chance to review and test this patch?
Would really like to make sure some can test it on an Intel Generation
5 or newer processor to make sure there are no issues with the tests
gdb.btrace/rn-dl-bind.exp and gdb.btrace/tailcall.exp: reverse-next.
Thanks for the time and effort looking at this patch.
Carl
-------------------------------------------------
On Mon, 2023-02-20 at 12:24 -0800, Carl Love wrote:
> Ulrich, Bruno, GDB maintainers:
>
> Per the comments from Ulrich, I have updated the patch to address the
> comments about the source code and the testcase. I updated the new
> library procedure so it can be called from gdb_step_until. So
> gdb_step_until is now just a variant of the new repeat_cmd_until
> proceedure.
>
> The redundant if test has been removed. It was added to fix a
> regression testing failure I saw on the gdb.btrace/tailcall.exp on
> X86.
> I went back and redid the testing, rebuilding everything from
> scratch.
> I am not able to reproduce the test failure without the redundant
> check. Not sure why I initially saw the regression failure at this
> point? Perhaps I hadn't re-enabled the
> /proc/sys/kernel/perf_event_paranoid value? It must be 2 or lower
> for
> the test to run. Otherwise the test fails. Anyway, the regression
> tests on X86 run without the redundant check are passing on my
> laptop.
>
> I resolved the issues with the testing on X86 to make sure it isn't
> missing failures when testing gdb.reverse/step-indirect-call-
> thunk.exp.
> As mentioned in the previous email, the test does not run on PowerPC
> since the gcc command line options "-mindirect-branch=thunk" and "-
> mfunction-return=thunk" are not supported on PowerPC. I disabled the
> test on PowerPC in the updated patch.
>
> Retested on X86 generation 5 and PowerPC with no regressions found.
>
> Hopefully this version of the patch is acceptable.
>
> Carl
>
> -----------------------------------------------------
>
> PowerPC: fix for gdb.reverse/finish-precsave.exp and
> gdb.reverse/finish-reverse.exp
>
> PPC64 multiple entry points. When executing in reverse the function
> finish_backward sets the break point at the alternate entry point,
> known
> as the global entry point (GEP) in PowerPC. However if the forward
> execution enters via the normal entry point, known as the local entry
> point (LEP) on PowerPC, reverse execution never sees the break point
> at the
> alternate entry point of the function. Reverse execution continues
> until
> the next break point is encountered thus stopping at the wrong place.
>
> This patch adds a new address to struct execution_control_state to
> hold the
> address of the alternate entry point (GEP). The finish_backwards
> function
> is updated, if the stopping point is between the normal entry point
> (LEP)
> and the end of the function, a breakpoint is set at the normal entry
> point.
> If the stopping point is between the entry points, a breakpoint is
> set to
> the alternate entry point.
>
> The patch fixes the behavior of the reverse-finish command on PowerPC
> to
> match the behavior of the command on other platforms, specifically
> X86.
> The patch does not change the behavior of the command on X86.
>
> A new test is added to verify the reverse-finish command on PowerPC
> correctly stops at the instruction where the function call is
> made. A new
> test, finish-reverse-next.exp, is added to verify the correct
> functionality
> of the reverse-finish command. The reverse-finish comand is expected
> to
> stop on the instruction that jumps to the function. Procedure
> proc_step_until from test gdb.reverse/step-indirect-call-thunk.exp is
> moved
> to lib/gdb.exp and renamed repeat_cmd_until.
>
> The patch fixes 11 regression errors in test gdb.reverse/finish-
> precsave.exp
> and 11 regression errors in test gdb.reverse/finish-reverse.exp.
>
> The patch has been tested on Power 10 and X86 processor with no new
> regression failures.
> ---
> gdb/infcmd.c | 47 ++--
> gdb/infrun.c | 24 ++
> .../gdb.reverse/finish-reverse-next.c | 91 +++++++
> .../gdb.reverse/finish-reverse-next.exp | 224
> ++++++++++++++++++
> .../gdb.reverse/step-indirect-call-thunk.exp | 55 ++---
> gdb/testsuite/lib/gdb.exp | 49 +++-
> 6 files changed, 421 insertions(+), 69 deletions(-)
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 77206fcbfe8..0fa5719d38b 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm
> *sm)
> no way that a function up the stack can have a return address
> that's equal to its entry point. */
>
> - if (sal.pc != pc)
> - {
> - frame_info_ptr frame = get_selected_frame (nullptr);
> - struct gdbarch *gdbarch = get_frame_arch (frame);
> + CORE_ADDR alt_entry_point = sal.pc;
> + CORE_ADDR entry_point = alt_entry_point;
> + frame_info_ptr frame = get_selected_frame (nullptr);
> + struct gdbarch *gdbarch = get_frame_arch (frame);
> +
> + if (gdbarch_skip_entrypoint_p (gdbarch))
> + /* Some architectures, like PowerPC use local and global entry
> points.
> + There is only one Entry Point (GEP = LEP) for other
> architectures.
> + The GEP is an alternate entry point. The LEP is the normal
> entry point.
> + The value of entry_point was initialized to the alternate
> entry point
> + (GEP). It will be adjusted to the normal entry point if the
> function
> + has two entry points. */
> + entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
>
> - /* Set a step-resume at the function's entry point. Once
> that's
> - hit, we'll do one more step backwards. */
> + if ((pc < alt_entry_point) || (pc > entry_point))
> + {
> + /* We are in the body of the function. Set a breakpoint to
> backup to
> + the normal entry point. */
> symtab_and_line sr_sal;
> - sr_sal.pc = sal.pc;
> + sr_sal.pc = entry_point;
> 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);
> + insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
> + null_frame_id);
> }
> +
> 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 either at one of the entry points or between the entry
> points.
> + If we are not at the alt_entry point, go back to the
> alt_entry_point
> + If we at the normal entry point step back one instruction,
> when we
> + stop we will determine if we entered via the entry point or
> the
> + alternate entry point. If we are at the alternate entry
> point,
> + single step back to the function call. */
> + tp->control.step_range_start = tp->control.step_range_end = 1;
> +
> + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
> }
>
> /* finish_forward -- helper function for finish_command. FRAME is
> the
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 87ab73c47a4..987dbd16ea4 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -1868,6 +1868,7 @@ struct execution_control_state
>
> struct target_waitstatus ws;
> int stop_func_filled_in = 0;
> + CORE_ADDR stop_func_alt_start = 0;
> CORE_ADDR stop_func_start = 0;
> CORE_ADDR stop_func_end = 0;
> const char *stop_func_name = nullptr;
> @@ -4680,6 +4681,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> ecs->stop_func_start
> += gdbarch_deprecated_function_start_offset (gdbarch);
>
> + /* PowerPC functions have a Local Entry Point (LEP) and a
> Global
> + Entry Point (GEP). There is only one Entry Point (GEP =
> LEP) for
> + other architectures. */
> + ecs->stop_func_alt_start = ecs->stop_func_start;
> +
> if (gdbarch_skip_entrypoint_p (gdbarch))
> ecs->stop_func_start
> = gdbarch_skip_entrypoint (gdbarch, ecs-
> >stop_func_start);
> @@ -7269,6 +7275,24 @@ process_event_stop_test (struct
> execution_control_state *ecs)
> }
> }
>
> + if (execution_direction == EXEC_REVERSE
> + && ecs->event_thread->control.proceed_to_finish
> + && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
> + && ecs->event_thread->stop_pc () < ecs->stop_func_start)
> + {
> + /* We are executing the reverse-finish command.
> + If the system supports multiple entry points and we are
> finishing a
> + function in reverse. If we are between the entry points
> singe-step
> + back to the alternate entry point. If we are at the alternate
> entry
> + point -- just need to back up by one more single-step, which
> + should take us back to the function call. */
> + ecs->event_thread->control.step_range_start
> + = ecs->event_thread->control.step_range_end = 1;
> + keep_going (ecs);
> + return;
> +
> + }
> +
> if (ecs->event_thread->control.step_range_end == 1)
> {
> /* It is stepi or nexti. We always want to stop stepping
> after
> 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 00000000000..e95ee8e33a6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> @@ -0,0 +1,91 @@
> +/* 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
> +
> + 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). The GEP is only used if the table
> of
> + contents (TOC) value stored in register r2 needs to be setup
> prior to
> + execution starting at the LEP. 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. */
> +
> +int
> +function2 (int a, int b)
> +{
> + int ret = 0;
> + ret = ret + a + b;
> + return ret;
> +}
> +
> +int
> +function1 (int a, int b) // FUNCTION1
> +{
> + int ret = 0;
> + int (*funp) (int, int) = &function2;
> + /* The assembly code for this function when compiled for PowerPC
> is as
> + follows:
> +
> + 0000000010000758 <function1>:
> + 10000758: 02 10 40 3c lis r2,4098 <- GEP
> + 1000075c: 00 7f 42 38 addi r2,r2,32512
> + 10000760: a6 02 08 7c mflr r0 <- LEP
> + 10000764: 10 00 01 f8 std r0,16(r1)
> + ....
> +
> + When the function is called on PowerPC with function1 (a, b)
> the call
> + enters at the Local Entry Point (LEP). When the function is
> called via
> + a function pointer, the Global Entry Point (GEP) for function1
> is used.
> + The GEP sets up register 2 before reaching the LEP.
> + */
> + ret = funp (a + 1, b + 2);
> + return ret;
> +}
> +
> +int
> +main(int argc, char* argv[])
> +{
> + int a, b;
> + int (*funp) (int, int) = &function1;
> +
> + /* Call function via Local Entry Point (LEP). */
> +
> + a = 1;
> + b = 5;
> +
> + function1 (a, b); // CALL VIA LEP
> +
> + /* Call function via Global Entry Point (GEP). */
> + a = 10;
> + b = 50;
> +
> + funp (a, b); // CALL VIA GEP
> + 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 00000000000..1f53b649a7d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> @@ -0,0 +1,224 @@
> +# 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
> +
> +# 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
> +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 (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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP"
> \
> + "reverse next 1 LEP entry point function 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA
> LEP.*" \
> + "reverse next 1 LEP 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP entry point function 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP entry point function 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP call from function body"
> +gdb_test "reverse-next" ".*b = 50;.*" \
> + "reverse next 2 at b = 50 from function body"
> diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> index 94292d5eb9b..61fb4974b8e 100644
> --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> @@ -17,6 +17,12 @@ require supports_reverse
>
> standard_testfile
>
> +if { [istarget "powerpc*-*-linux*"] } {
> + # GCC for PowerPC on linux does not support the -mindirect-
> branch and
> + # -mfunction-return command line options.
> + return 0
> +}
> +
> set cflags {}
> lappend cflags debug
> lappend cflags additional_flags=-mindirect-branch=thunk
> @@ -36,39 +42,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 +61,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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index faa0ac05a9a..b10555fe5fb 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -9267,31 +9267,58 @@ gdb_caching_proc arm_cc_for_target {
>
> # Step until the pattern REGEXP is found. Step at most
> # MAX_STEPS times, but stop stepping once REGEXP is found.
> -#
> +# START matches current location
> # If REGEXP is found then a single pass is emitted, otherwise, after
> # MAX_STEPS steps, a single fail is emitted.
> #
> # TEST_NAME is the name used in the pass/fail calls.
>
> -proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
> +proc gdb_step_until { regexp {test_name ""} {current ""} \
> + { max_steps 10 } } {
> + if { $current == "" } {
> + set current "\}"
> + }
> + if { $test_name == "" } {
> + set test_name "stepping until regexp"
> + }
> +
> + repeat_cmd_until "step" $current $regexp $test_name "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
> +# MAX_STEPS is number of steps attempted before fail is emitted
> +#
> +# 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_name {max_steps
> 100} } {
> + global gdb_prompt
> if { $test_name == "" } {
> set test_name "stepping until regexp"
> }
>
> set count 0
> - gdb_test_multiple "step" "$test_name" {
> - -re "$regexp\r\n$::gdb_prompt $" {
> - pass $test_name
> - }
> - -re ".*$::gdb_prompt $" {
> - if {$count < $max_steps} {
> - incr count
> - send_gdb "step\n"
> + gdb_test_multiple "$command" "$test_name" {
> + -re "$current.*$gdb_prompt $" {
> + incr count
> + if { $count < $max_steps } {
> + send_gdb "$command\n"
> exp_continue
> } else {
> - fail $test_name
> + fail "$test_name"
> }
> }
> + -re "$target.*$gdb_prompt $" {
> + pass "$test_name"
> + }
> }
> }
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-20 20:24 ` Carl Love
2023-02-27 16:09 ` [PING] " Carl Love
@ 2023-02-28 13:39 ` Bruno Larsen
2023-02-28 16:19 ` Carl Love
2023-03-01 13:43 ` Tom de Vries
` (2 subsequent siblings)
4 siblings, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-02-28 13:39 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, gdb-patches, tdevries, pedro
On 20/02/2023 21:24, Carl Love wrote:
> Ulrich, Bruno, GDB maintainers:
>
> Per the comments from Ulrich, I have updated the patch to address the
> comments about the source code and the testcase. I updated the new
> library procedure so it can be called from gdb_step_until. So
> gdb_step_until is now just a variant of the new repeat_cmd_until
> proceedure.
>
> The redundant if test has been removed. It was added to fix a
> regression testing failure I saw on the gdb.btrace/tailcall.exp on X86.
> I went back and redid the testing, rebuilding everything from scratch.
> I am not able to reproduce the test failure without the redundant
> check. Not sure why I initially saw the regression failure at this
> point? Perhaps I hadn't re-enabled the
> /proc/sys/kernel/perf_event_paranoid value? It must be 2 or lower for
> the test to run. Otherwise the test fails. Anyway, the regression
> tests on X86 run without the redundant check are passing on my laptop.
>
> I resolved the issues with the testing on X86 to make sure it isn't
> missing failures when testing gdb.reverse/step-indirect-call-thunk.exp.
> As mentioned in the previous email, the test does not run on PowerPC
> since the gcc command line options "-mindirect-branch=thunk" and "-
> mfunction-return=thunk" are not supported on PowerPC. I disabled the
> test on PowerPC in the updated patch.
>
> Retested on X86 generation 5 and PowerPC with no regressions found.
>
> Hopefully this version of the patch is acceptable.
>
> Carl
Hi Carl,
Sorry about the delay. I've tested the series and see no regressions. In
particular, the tests you called out all passed on my machine. I have a
minor wording nit in one comment, but regardless, you can add to the tag:
Reviewed-By: Bruno Larsen <blarsen@redhat.com>
> -----------------------------------------------------
>
> PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
>
> PPC64 multiple entry points. When executing in reverse the function
> finish_backward sets the break point at the alternate entry point, known
> as the global entry point (GEP) in PowerPC. However if the forward
> execution enters via the normal entry point, known as the local entry
> point (LEP) on PowerPC, reverse execution never sees the break point at the
> alternate entry point of the function. Reverse execution continues until
> the next break point is encountered thus stopping at the wrong place.
>
> This patch adds a new address to struct execution_control_state to hold the
> address of the alternate entry point (GEP). The finish_backwards function
> is updated, if the stopping point is between the normal entry point (LEP)
> and the end of the function, a breakpoint is set at the normal entry point.
> If the stopping point is between the entry points, a breakpoint is set to
> the alternate entry point.
>
> The patch fixes the behavior of the reverse-finish command on PowerPC to
> match the behavior of the command on other platforms, specifically X86.
> The patch does not change the behavior of the command on X86.
>
> A new test is added to verify the reverse-finish command on PowerPC
> correctly stops at the instruction where the function call is made. A new
> test, finish-reverse-next.exp, is added to verify the correct functionality
> of the reverse-finish command. The reverse-finish comand is expected to
> stop on the instruction that jumps to the function. Procedure
> proc_step_until from test gdb.reverse/step-indirect-call-thunk.exp is moved
> to lib/gdb.exp and renamed repeat_cmd_until.
>
> The patch fixes 11 regression errors in test gdb.reverse/finish-precsave.exp
> and 11 regression errors in test gdb.reverse/finish-reverse.exp.
>
> The patch has been tested on Power 10 and X86 processor with no new
> regression failures.
> ---
> gdb/infcmd.c | 47 ++--
> gdb/infrun.c | 24 ++
> .../gdb.reverse/finish-reverse-next.c | 91 +++++++
> .../gdb.reverse/finish-reverse-next.exp | 224 ++++++++++++++++++
> .../gdb.reverse/step-indirect-call-thunk.exp | 55 ++---
> gdb/testsuite/lib/gdb.exp | 49 +++-
> 6 files changed, 421 insertions(+), 69 deletions(-)
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 77206fcbfe8..0fa5719d38b 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm *sm)
> no way that a function up the stack can have a return address
> that's equal to its entry point. */
>
> - if (sal.pc != pc)
> - {
> - frame_info_ptr frame = get_selected_frame (nullptr);
> - struct gdbarch *gdbarch = get_frame_arch (frame);
> + CORE_ADDR alt_entry_point = sal.pc;
> + CORE_ADDR entry_point = alt_entry_point;
> + frame_info_ptr frame = get_selected_frame (nullptr);
> + struct gdbarch *gdbarch = get_frame_arch (frame);
> +
> + if (gdbarch_skip_entrypoint_p (gdbarch))
> + /* Some architectures, like PowerPC use local and global entry points.
> + There is only one Entry Point (GEP = LEP) for other architectures.
> + The GEP is an alternate entry point. The LEP is the normal entry point.
> + The value of entry_point was initialized to the alternate entry point
> + (GEP). It will be adjusted to the normal entry point if the function
> + has two entry points. */
> + entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
>
> - /* Set a step-resume at the function's entry point. Once that's
> - hit, we'll do one more step backwards. */
> + if ((pc < alt_entry_point) || (pc > entry_point))
> + {
> + /* We are in the body of the function. Set a breakpoint to backup to
I would change backup for "return", or separate it to "back up",
otherwise I personally think of data backups.
--
Cheers,
Bruno
> + the normal entry point. */
> symtab_and_line sr_sal;
> - sr_sal.pc = sal.pc;
> + sr_sal.pc = entry_point;
> 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);
> + insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
> + null_frame_id);
> }
> +
> 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 either at one of the entry points or between the entry points.
> + If we are not at the alt_entry point, go back to the alt_entry_point
> + If we at the normal entry point step back one instruction, when we
> + stop we will determine if we entered via the entry point or the
> + alternate entry point. If we are at the alternate entry point,
> + single step back to the function call. */
> + tp->control.step_range_start = tp->control.step_range_end = 1;
> +
> + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
> }
>
> /* finish_forward -- helper function for finish_command. FRAME is the
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 87ab73c47a4..987dbd16ea4 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -1868,6 +1868,7 @@ struct execution_control_state
>
> struct target_waitstatus ws;
> int stop_func_filled_in = 0;
> + CORE_ADDR stop_func_alt_start = 0;
> CORE_ADDR stop_func_start = 0;
> CORE_ADDR stop_func_end = 0;
> const char *stop_func_name = nullptr;
> @@ -4680,6 +4681,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> ecs->stop_func_start
> += gdbarch_deprecated_function_start_offset (gdbarch);
>
> + /* PowerPC functions have a Local Entry Point (LEP) and a Global
> + Entry Point (GEP). There is only one Entry Point (GEP = LEP) for
> + other architectures. */
> + ecs->stop_func_alt_start = ecs->stop_func_start;
> +
> if (gdbarch_skip_entrypoint_p (gdbarch))
> ecs->stop_func_start
> = gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
> @@ -7269,6 +7275,24 @@ process_event_stop_test (struct execution_control_state *ecs)
> }
> }
>
> + if (execution_direction == EXEC_REVERSE
> + && ecs->event_thread->control.proceed_to_finish
> + && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
> + && ecs->event_thread->stop_pc () < ecs->stop_func_start)
> + {
> + /* We are executing the reverse-finish command.
> + If the system supports multiple entry points and we are finishing a
> + function in reverse. If we are between the entry points singe-step
> + back to the alternate entry point. If we are at the alternate entry
> + point -- just need to back up by one more single-step, which
> + should take us back to the function call. */
> + ecs->event_thread->control.step_range_start
> + = ecs->event_thread->control.step_range_end = 1;
> + keep_going (ecs);
> + return;
> +
> + }
> +
> if (ecs->event_thread->control.step_range_end == 1)
> {
> /* It is stepi or nexti. We always want to stop stepping after
> 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 00000000000..e95ee8e33a6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> @@ -0,0 +1,91 @@
> +/* 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
> +
> + 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). The GEP is only used if the table of
> + contents (TOC) value stored in register r2 needs to be setup prior to
> + execution starting at the LEP. 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. */
> +
> +int
> +function2 (int a, int b)
> +{
> + int ret = 0;
> + ret = ret + a + b;
> + return ret;
> +}
> +
> +int
> +function1 (int a, int b) // FUNCTION1
> +{
> + int ret = 0;
> + int (*funp) (int, int) = &function2;
> + /* The assembly code for this function when compiled for PowerPC is as
> + follows:
> +
> + 0000000010000758 <function1>:
> + 10000758: 02 10 40 3c lis r2,4098 <- GEP
> + 1000075c: 00 7f 42 38 addi r2,r2,32512
> + 10000760: a6 02 08 7c mflr r0 <- LEP
> + 10000764: 10 00 01 f8 std r0,16(r1)
> + ....
> +
> + When the function is called on PowerPC with function1 (a, b) the call
> + enters at the Local Entry Point (LEP). When the function is called via
> + a function pointer, the Global Entry Point (GEP) for function1 is used.
> + The GEP sets up register 2 before reaching the LEP.
> + */
> + ret = funp (a + 1, b + 2);
> + return ret;
> +}
> +
> +int
> +main(int argc, char* argv[])
> +{
> + int a, b;
> + int (*funp) (int, int) = &function1;
> +
> + /* Call function via Local Entry Point (LEP). */
> +
> + a = 1;
> + b = 5;
> +
> + function1 (a, b); // CALL VIA LEP
> +
> + /* Call function via Global Entry Point (GEP). */
> + a = 10;
> + b = 50;
> +
> + funp (a, b); // CALL VIA GEP
> + 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 00000000000..1f53b649a7d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> @@ -0,0 +1,224 @@
> +# 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
> +
> +# 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
> +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 (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. A reverse-next
> +# instruction should then stop at the first instruction in the same source
> +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP" \
> + "reverse next 1 LEP entry point function 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. A reverse-next
> +# instruction should then stop at the first instruction in the same source
> +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
> + "reverse next 1 LEP 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. A reverse-next
> +# instruction should then stop at the first instruction in the same source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP entry point function 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. A reverse-next
> +# instruction should then stop at the first instruction in the same source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP entry point function 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. A reverse-next
> +# instruction should then stop at the first instruction in the same source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP call from function body"
> +gdb_test "reverse-next" ".*b = 50;.*" \
> + "reverse next 2 at b = 50 from function body"
> diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> index 94292d5eb9b..61fb4974b8e 100644
> --- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> +++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
> @@ -17,6 +17,12 @@ require supports_reverse
>
> standard_testfile
>
> +if { [istarget "powerpc*-*-linux*"] } {
> + # GCC for PowerPC on linux does not support the -mindirect-branch and
> + # -mfunction-return command line options.
> + return 0
> +}
> +
> set cflags {}
> lappend cflags debug
> lappend cflags additional_flags=-mindirect-branch=thunk
> @@ -36,39 +42,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 +61,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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index faa0ac05a9a..b10555fe5fb 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -9267,31 +9267,58 @@ gdb_caching_proc arm_cc_for_target {
>
> # Step until the pattern REGEXP is found. Step at most
> # MAX_STEPS times, but stop stepping once REGEXP is found.
> -#
> +# START matches current location
> # If REGEXP is found then a single pass is emitted, otherwise, after
> # MAX_STEPS steps, a single fail is emitted.
> #
> # TEST_NAME is the name used in the pass/fail calls.
>
> -proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
> +proc gdb_step_until { regexp {test_name ""} {current ""} \
> + { max_steps 10 } } {
> + if { $current == "" } {
> + set current "\}"
> + }
> + if { $test_name == "" } {
> + set test_name "stepping until regexp"
> + }
> +
> + repeat_cmd_until "step" $current $regexp $test_name "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
> +# MAX_STEPS is number of steps attempted before fail is emitted
> +#
> +# 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_name {max_steps 100} } {
> + global gdb_prompt
> if { $test_name == "" } {
> set test_name "stepping until regexp"
> }
>
> set count 0
> - gdb_test_multiple "step" "$test_name" {
> - -re "$regexp\r\n$::gdb_prompt $" {
> - pass $test_name
> - }
> - -re ".*$::gdb_prompt $" {
> - if {$count < $max_steps} {
> - incr count
> - send_gdb "step\n"
> + gdb_test_multiple "$command" "$test_name" {
> + -re "$current.*$gdb_prompt $" {
> + incr count
> + if { $count < $max_steps } {
> + send_gdb "$command\n"
> exp_continue
> } else {
> - fail $test_name
> + fail "$test_name"
> }
> }
> + -re "$target.*$gdb_prompt $" {
> + pass "$test_name"
> + }
> }
> }
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-28 13:39 ` Bruno Larsen
@ 2023-02-28 16:19 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-02-28 16:19 UTC (permalink / raw)
To: Bruno Larsen, Ulrich Weigand, gdb-patches, tdevries, pedro; +Cc: cel
Bruno:
Thanks for testing and reviewing the patch
On Tue, 2023-02-28 at 14:39 +0100, Bruno Larsen wrote:
> Hi Carl,
>
> Sorry about the delay. I've tested the series and see no regressions.
> In
> particular, the tests you called out all passed on my machine. I have
> a
> minor wording nit in one comment, but regardless, you can add to the
> tag:
>
> Reviewed-By: Bruno Larsen <blarsen@redhat.com>
>
> > -----------------------------------------------------
> >
> >
<snip>
> > - /* Set a step-resume at the function's entry point. Once
> > that's
> > - hit, we'll do one more step backwards. */
> > + if ((pc < alt_entry_point) || (pc > entry_point))
> > + {
> > + /* We are in the body of the function. Set a breakpoint to
> > backup to
>
> I would change backup for "return", or separate it to "back up",
> otherwise I personally think of data backups.
OK, I changed the line as follows in my copy of the patch
entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
if ((pc < alt_entry_point) || (pc > entry_point))
{
- /* We are in the body of the function. Set a breakpoint to backup to
+ /* We are in the body of the function. Set a breakpoint to go back to
the normal entry point. */
symtab_and_line sr_sal;
I think that addresses your concern. It is not worth resending the
patch at this point for this change but will include it in any future
posts or commits. Thanks for the feedback.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-20 20:24 ` Carl Love
2023-02-27 16:09 ` [PING] " Carl Love
2023-02-28 13:39 ` Bruno Larsen
@ 2023-03-01 13:43 ` Tom de Vries
2023-03-01 16:26 ` Carl Love
2023-03-01 14:03 ` Tom de Vries
2023-03-01 14:34 ` Tom de Vries
4 siblings, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-03-01 13:43 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro
On 2/20/23 21:24, Carl Love wrote:
> +if { [istarget "powerpc*-*-linux*"] } {
> + # GCC for PowerPC on linux does not support the -mindirect-branch and
> + # -mfunction-return command line options.
> + return 0
> +}
> +
This bit is no longer necessary.
I've committed 2ef339e38f5 ("[gdb/testsuite] Require istarget x86* in
gdb.reverse/step-indirect-call-thunk.exp") which copied your fix from
commit 43127ae5714 ("Fix gdb.base/step-indirect-call-thunk.exp").
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-20 20:24 ` Carl Love
` (2 preceding siblings ...)
2023-03-01 13:43 ` Tom de Vries
@ 2023-03-01 14:03 ` Tom de Vries
2023-03-01 16:43 ` Carl Love
2023-03-01 14:34 ` Tom de Vries
4 siblings, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-03-01 14:03 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro
On 2/20/23 21:24, Carl Love wrote:
> # Step until the pattern REGEXP is found. Step at most
> # MAX_STEPS times, but stop stepping once REGEXP is found.
> -#
> +# START matches current location
> # If REGEXP is found then a single pass is emitted, otherwise, after
> # MAX_STEPS steps, a single fail is emitted.
> #
> # TEST_NAME is the name used in the pass/fail calls.
>
> -proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
> +proc gdb_step_until { regexp {test_name ""} {current ""} \
> + { max_steps 10 } } {
I assume you meant CURRENT instead of START.
Thanks,
- Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-02-20 20:24 ` Carl Love
` (3 preceding siblings ...)
2023-03-01 14:03 ` Tom de Vries
@ 2023-03-01 14:34 ` Tom de Vries
2023-03-01 20:39 ` Carl Love
4 siblings, 1 reply; 105+ messages in thread
From: Tom de Vries @ 2023-03-01 14:34 UTC (permalink / raw)
To: Carl Love, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro
[-- Attachment #1: Type: text/plain, Size: 459 bytes --]
On 2/20/23 21:24, Carl Love wrote:
> .../gdb.reverse/step-indirect-call-thunk.exp | 55 ++---
> gdb/testsuite/lib/gdb.exp | 49 +++-
I think the changes in these two files are not really related to
$subject. The only connection is that the newly introduced test-case
gdb.reverse/finish-reverse-next.exp uses repeat_cmd_until.
I propose to commit attached patch separately.
Carl, can you review the commit message?
Thanks,
- Tom
[-- Attachment #2: 0001-gdb-testsuite-Introduce-repeat_cmd_until.patch --]
[-- Type: text/x-patch, Size: 4457 bytes --]
From d211b4d17c4c2253d85a73a78db5581b369746bd Mon Sep 17 00:00:00 2001
From: Carl Love <cel@us.ibm.com>
Date: Wed, 1 Mar 2023 14:50:15 +0100
Subject: [PATCH] [gdb/testsuite] Introduce repeat_cmd_until
Test-case gdb.reverse/step-indirect-call-thunk.exp contains a proc step_until.
OTOH, we've got a somewhat similar proc in lib/gdb.exp: gdb_step_until.
Fix this by:
- moving step_until into lib/gdb.exp and renaming to repeat_cmd_until,
- reimplementing gdb_step_until using repeat_cmd_until, and
- reimplementing step_until as an local alias of repeat_cmd_until
(in order to avoid polluting history with updating all the calls).
Tested on x86_64-linux.
---
.../gdb.reverse/step-indirect-call-thunk.exp | 32 +-----------
gdb/testsuite/lib/gdb.exp | 49 ++++++++++++++-----
2 files changed, 40 insertions(+), 41 deletions(-)
diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
index f433efb11c2..d431d174f88 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -38,37 +38,9 @@ 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.
-#
+# Local alias for repeat_cmd_until.
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"
- }
- }
+ repeat_cmd_until $command $current $target $test
}
gdb_test_no_output "record"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 19c782bea46..650a44aab1e 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9270,31 +9270,58 @@ gdb_caching_proc arm_cc_for_target {
# Step until the pattern REGEXP is found. Step at most
# MAX_STEPS times, but stop stepping once REGEXP is found.
-#
+# CURRENT matches current location.
# If REGEXP is found then a single pass is emitted, otherwise, after
# MAX_STEPS steps, a single fail is emitted.
#
# TEST_NAME is the name used in the pass/fail calls.
-proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
+proc gdb_step_until { regexp {test_name ""} {current ""} \
+ { max_steps 10 } } {
+ if { $current == "" } {
+ set current "\}"
+ }
+ if { $test_name == "" } {
+ set test_name "stepping until regexp"
+ }
+
+ repeat_cmd_until "step" $current $regexp $test_name "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
+# MAX_STEPS is number of steps attempted before fail is emitted
+#
+# 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_name {max_steps 100} } {
+ global gdb_prompt
if { $test_name == "" } {
set test_name "stepping until regexp"
}
set count 0
- gdb_test_multiple "step" "$test_name" {
- -re "$regexp\r\n$::gdb_prompt $" {
- pass $test_name
- }
- -re ".*$::gdb_prompt $" {
- if {$count < $max_steps} {
- incr count
- send_gdb "step\n"
+ gdb_test_multiple "$command" "$test_name" {
+ -re "$current.*$gdb_prompt $" {
+ incr count
+ if { $count < $max_steps } {
+ send_gdb "$command\n"
exp_continue
} else {
- fail $test_name
+ fail "$test_name"
}
}
+ -re "$target.*$gdb_prompt $" {
+ pass "$test_name"
+ }
}
}
base-commit: 2c29b1ed19711fa2a16558015e5a6b46a09aefeb
--
2.35.3
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 13:43 ` Tom de Vries
@ 2023-03-01 16:26 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-03-01 16:26 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro
Tom:
On Wed, 2023-03-01 at 14:43 +0100, Tom de Vries wrote:
> On 2/20/23 21:24, Carl Love wrote:
> > +if { [istarget "powerpc*-*-linux*"] } {
> > + # GCC for PowerPC on linux does not support the -mindirect-
> > branch and
> > + # -mfunction-return command line options.
> > + return 0
> > +}
> > +
>
> This bit is no longer necessary.
>
> I've committed 2ef339e38f5 ("[gdb/testsuite] Require istarget x86*
> in
> gdb.reverse/step-indirect-call-thunk.exp") which copied your fix
> from
> commit 43127ae5714 ("Fix gdb.base/step-indirect-call-thunk.exp").
I update my source tree, without my patch applied, I verified the test
is not running on PowerPC. I will drop the above change from my patch.
Thanks.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 14:03 ` Tom de Vries
@ 2023-03-01 16:43 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-03-01 16:43 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
Tom:
On Wed, 2023-03-01 at 15:03 +0100, Tom de Vries wrote:
> On 2/20/23 21:24, Carl Love wrote:
> > # Step until the pattern REGEXP is found. Step at most
> > # MAX_STEPS times, but stop stepping once REGEXP is found.
> > -#
> > +# START matches current location
> > # If REGEXP is found then a single pass is emitted, otherwise,
> > after
> > # MAX_STEPS steps, a single fail is emitted.
> > #
> > # TEST_NAME is the name used in the pass/fail calls.
> >
> > -proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
> > +proc gdb_step_until { regexp {test_name ""} {current ""} \
> > + { max_steps 10 } } {
>
> I assume you meant CURRENT instead of START.
Yes, thanks for catching that. Fixed.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 14:34 ` Tom de Vries
@ 2023-03-01 20:39 ` Carl Love
2023-03-01 20:59 ` [PATCH 0/2 " Carl Love
` (2 more replies)
0 siblings, 3 replies; 105+ messages in thread
From: Carl Love @ 2023-03-01 20:39 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
Tom:
On Wed, 2023-03-01 at 15:34 +0100, Tom de Vries wrote:
> On 2/20/23 21:24, Carl Love wrote:
> > .../gdb.reverse/step-indirect-call-thunk.exp | 55 ++---
> > gdb/testsuite/lib/gdb.exp | 49 +++-
>
> I think the changes in these two files are not really related to
> $subject. The only connection is that the newly introduced test-
> case
> gdb.reverse/finish-reverse-next.exp uses repeat_cmd_until.
>
> I propose to commit attached patch separately.
OK, I split the patch. The first patch does the changes to the above
two files. The second patch is the PowerPC fix that uses the new
library proceedure.
>
> Carl, can you review the commit message?\
I reworked the commit message to make it flow better and remove the
comments about the movement of the proceedure.
I will post the two patch series.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 0/2 ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:39 ` Carl Love
@ 2023-03-01 20:59 ` Carl Love
2023-03-01 20:59 ` [PATCH 1/2] " Carl Love
2023-03-01 20:59 ` [PATCH 2/2 ] " Carl Love
2 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-03-01 20:59 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
Tom, Ulrich, Bruno, Pedro, GDB maintainers:
Per the feedback on the single patch to fix the gdb reverse-finish
command, I have split the patch into two patches.
The first patch moves the step_until proceedure from gdb.reverse/step-
indirect-call-thunk.exp to gdb/testsuite/lib/gdb.exp and renames it
repeat_cmd_until. The new repeat_cmd_until will be used in a new test
case for the second patch.
The second patch contains the changes to GDB to fix the behavior of the
reverse-finish command on PowerPC.
The changes to gdb.reverse/step-indirect-call-thunk.exp so the test
will not run on PowerPC were dropped per the comment from Tom stating
that commit 2ef339e38f5 ("[gdb/testsuite] Require istarget x86*
in gdb.reverse/step-indirect-call-thunk.exp") takes care of restricting
the test case to only run on X86.
The wording in file gdb/infcmd.c for the PowerPC fix was updated per
Bruno's feedback.
Thanks for all the feedback. Please let me know if the patch series is
acceptable for mainline.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 1/2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:39 ` Carl Love
2023-03-01 20:59 ` [PATCH 0/2 " Carl Love
@ 2023-03-01 20:59 ` Carl Love
2023-03-03 11:56 ` Bruno Larsen
2023-03-09 19:03 ` Tom Tromey
2023-03-01 20:59 ` [PATCH 2/2 ] " Carl Love
2 siblings, 2 replies; 105+ messages in thread
From: Carl Love @ 2023-03-01 20:59 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
Tom, Ulrich, Bruno, Pedro, GDB maintainers:
This patch moves the step_until procedure from gdb.reverse/step-
indirect-call-thunk.exp to gdb/testsuite/lib/gdb.exp and renames it
repeat_cmd_until. There are no functional changes as a result of this
change.
Patch tested on PowerPC and 5th generation X86 with no regression
failures.
Carl
--------------------------------------------------------
Move step_until procedure
Procedure proc_step_until from test gdb.reverse/step-indirect-call-thunk.exp
is moved to lib/gdb.exp and renamed repeat_cmd_until. The existing proceedure
gdb_step_until in lib/gdb.exp is simpler variant of the new repeat_cmd_until
proceedure. The existing proceedure gdb_step_until is changed to just call
the new repeat_cmd_until proceedure with the command set to "step" and an
optional CURRENT string. The default CURRENT string is set to "\}" to work
with the existing uses of proceedure gdb_step_until.
---
.../gdb.reverse/step-indirect-call-thunk.exp | 49 +++----------------
gdb/testsuite/lib/gdb.exp | 49 ++++++++++++++-----
2 files changed, 46 insertions(+), 52 deletions(-)
diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
index f433efb11c2..e6c81b80a7b 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -38,39 +38,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"
@@ -90,20 +57,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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 19c782bea46..2b2a554f4c7 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9270,31 +9270,58 @@ gdb_caching_proc arm_cc_for_target {
# Step until the pattern REGEXP is found. Step at most
# MAX_STEPS times, but stop stepping once REGEXP is found.
-#
+# CURRENT matches current location
# If REGEXP is found then a single pass is emitted, otherwise, after
# MAX_STEPS steps, a single fail is emitted.
#
# TEST_NAME is the name used in the pass/fail calls.
-proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
+proc gdb_step_until { regexp {test_name ""} {current ""} \
+ { max_steps 10 } } {
+ if { $current == "" } {
+ set current "\}"
+ }
+ if { $test_name == "" } {
+ set test_name "stepping until regexp"
+ }
+
+ repeat_cmd_until "step" $current $regexp $test_name "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
+# MAX_STEPS is number of steps attempted before fail is emitted
+#
+# 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_name {max_steps 100} } {
+ global gdb_prompt
if { $test_name == "" } {
set test_name "stepping until regexp"
}
set count 0
- gdb_test_multiple "step" "$test_name" {
- -re "$regexp\r\n$::gdb_prompt $" {
- pass $test_name
- }
- -re ".*$::gdb_prompt $" {
- if {$count < $max_steps} {
- incr count
- send_gdb "step\n"
+ gdb_test_multiple "$command" "$test_name" {
+ -re "$current.*$gdb_prompt $" {
+ incr count
+ if { $count < $max_steps } {
+ send_gdb "$command\n"
exp_continue
} else {
- fail $test_name
+ fail "$test_name"
}
}
+ -re "$target.*$gdb_prompt $" {
+ pass "$test_name"
+ }
}
}
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 2/2 ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:39 ` Carl Love
2023-03-01 20:59 ` [PATCH 0/2 " Carl Love
2023-03-01 20:59 ` [PATCH 1/2] " Carl Love
@ 2023-03-01 20:59 ` Carl Love
2023-03-08 16:19 ` [PING] " Carl Love
` (2 more replies)
2 siblings, 3 replies; 105+ messages in thread
From: Carl Love @ 2023-03-01 20:59 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
Tom, Ulrich, Bruno, Pedro, GDB maintainers:
This patch fixes the reverse-finish command on PowerPC. The command
now works the same as on other architectures, specifically X86. There
are no functional changes for other architectures. The patch includes
a new testcase to verify the reverse-finish command works correctly
with the multiple entry points supported by PowerPC.
Patch tested on PowerPC and 5th generation X86 with no regression
failures.
Carl
--------------------------------------------------------
PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
PPC64 multiple entry points, a normal entry point and an alternate entry
point. The alternate entry point is to setup the Table of Contents (TOC)
register before continuing at the normal entry point. When the TOC is
already valid, the normal entry point is used, this is typically the case.
The alternate entry point is typically referred to as the global entry
point (GEP) in IBM. The normal entry point is typically referred to as
the local entry point (LEP).
When GDB is executing the finish command in reverse, the function
finish_backward currently sets the break point at the alternate entry point.
This issue is if the function, when executing in the forward direction, entered
the function via the normal entry point, execution in the reverse direction
will never sees the break point at the alternate entry point. In this case,
the reverse execution continues until the next break point is encountered thus
stopping at the wrong place.
This patch adds a new address to struct execution_control_state to hold the
address of the alternate entry point (GEP). The finish_backwards function
is updated, if the stopping point is between the normal entry point (LEP)
and the end of the function, a breakpoint is set at the normal entry point.
If the stopping point is between the entry points, a breakpoint is set at
the alternate entry point. This ensures that GDB will always stop at the
normal entry point. If the function did enter via the alternate entry point,
GDB will detect that and continue to execute backwards in the function until
the alternate entry point is reached.
The patch fixes the behavior of the reverse-finish command on PowerPC to
match the behavior of the command on other platforms, specifically X86.
The patch does not change the behavior of the command on X86.
A new test is added to verify the reverse-finish command on PowerPC
correctly stops at the instruction where the function call is made.
The patch fixes 11 regression errors in test gdb.reverse/finish-precsave.exp
and 11 regression errors in test gdb.reverse/finish-reverse.exp.
The patch has been tested on Power 10 and X86 processor with no new
regression failures.
---
gdb/infcmd.c | 47 ++--
gdb/infrun.c | 24 ++
.../gdb.reverse/finish-reverse-next.c | 91 +++++++
.../gdb.reverse/finish-reverse-next.exp | 224 ++++++++++++++++++
4 files changed, 369 insertions(+), 17 deletions(-)
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index c369b795757..81c617448af 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm *sm)
no way that a function up the stack can have a return address
that's equal to its entry point. */
- if (sal.pc != pc)
- {
- frame_info_ptr frame = get_selected_frame (nullptr);
- struct gdbarch *gdbarch = get_frame_arch (frame);
+ CORE_ADDR alt_entry_point = sal.pc;
+ CORE_ADDR entry_point = alt_entry_point;
+ frame_info_ptr frame = get_selected_frame (nullptr);
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ if (gdbarch_skip_entrypoint_p (gdbarch))
+ /* Some architectures, like PowerPC use local and global entry points.
+ There is only one Entry Point (GEP = LEP) for other architectures.
+ The GEP is an alternate entry point. The LEP is the normal entry point.
+ The value of entry_point was initialized to the alternate entry point
+ (GEP). It will be adjusted to the normal entry point if the function
+ has two entry points. */
+ entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
- /* Set a step-resume at the function's entry point. Once that's
- hit, we'll do one more step backwards. */
+ if ((pc < alt_entry_point) || (pc > entry_point))
+ {
+ /* We are in the body of the function. Set a breakpoint to go back to
+ the normal entry point. */
symtab_and_line sr_sal;
- sr_sal.pc = sal.pc;
+ sr_sal.pc = entry_point;
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);
+ insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
+ null_frame_id);
}
+
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 either at one of the entry points or between the entry points.
+ If we are not at the alt_entry point, go back to the alt_entry_point
+ If we at the normal entry point step back one instruction, when we
+ stop we will determine if we entered via the entry point or the
+ alternate entry point. If we are at the alternate entry point,
+ single step back to the function call. */
+ tp->control.step_range_start = tp->control.step_range_end = 1;
+
+ proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
}
/* finish_forward -- helper function for finish_command. FRAME is the
diff --git a/gdb/infrun.c b/gdb/infrun.c
index ab77300f1ff..ca2fc02898a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1938,6 +1938,7 @@ struct execution_control_state
struct target_waitstatus ws;
int stop_func_filled_in = 0;
+ CORE_ADDR stop_func_alt_start = 0;
CORE_ADDR stop_func_start = 0;
CORE_ADDR stop_func_end = 0;
const char *stop_func_name = nullptr;
@@ -4822,6 +4823,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
ecs->stop_func_start
+= gdbarch_deprecated_function_start_offset (gdbarch);
+ /* PowerPC functions have a Local Entry Point (LEP) and a Global
+ Entry Point (GEP). There is only one Entry Point (GEP = LEP) for
+ other architectures. */
+ ecs->stop_func_alt_start = ecs->stop_func_start;
+
if (gdbarch_skip_entrypoint_p (gdbarch))
ecs->stop_func_start
= gdbarch_skip_entrypoint (gdbarch, ecs->stop_func_start);
@@ -7411,6 +7417,24 @@ process_event_stop_test (struct execution_control_state *ecs)
}
}
+ if (execution_direction == EXEC_REVERSE
+ && ecs->event_thread->control.proceed_to_finish
+ && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
+ && ecs->event_thread->stop_pc () < ecs->stop_func_start)
+ {
+ /* We are executing the reverse-finish command.
+ If the system supports multiple entry points and we are finishing a
+ function in reverse. If we are between the entry points singe-step
+ back to the alternate entry point. If we are at the alternate entry
+ point -- just need to back up by one more single-step, which
+ should take us back to the function call. */
+ ecs->event_thread->control.step_range_start
+ = ecs->event_thread->control.step_range_end = 1;
+ keep_going (ecs);
+ return;
+
+ }
+
if (ecs->event_thread->control.step_range_end == 1)
{
/* It is stepi or nexti. We always want to stop stepping after
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 00000000000..e95ee8e33a6
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
@@ -0,0 +1,91 @@
+/* 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
+
+ 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). The GEP is only used if the table of
+ contents (TOC) value stored in register r2 needs to be setup prior to
+ execution starting at the LEP. 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. */
+
+int
+function2 (int a, int b)
+{
+ int ret = 0;
+ ret = ret + a + b;
+ return ret;
+}
+
+int
+function1 (int a, int b) // FUNCTION1
+{
+ int ret = 0;
+ int (*funp) (int, int) = &function2;
+ /* The assembly code for this function when compiled for PowerPC is as
+ follows:
+
+ 0000000010000758 <function1>:
+ 10000758: 02 10 40 3c lis r2,4098 <- GEP
+ 1000075c: 00 7f 42 38 addi r2,r2,32512
+ 10000760: a6 02 08 7c mflr r0 <- LEP
+ 10000764: 10 00 01 f8 std r0,16(r1)
+ ....
+
+ When the function is called on PowerPC with function1 (a, b) the call
+ enters at the Local Entry Point (LEP). When the function is called via
+ a function pointer, the Global Entry Point (GEP) for function1 is used.
+ The GEP sets up register 2 before reaching the LEP.
+ */
+ ret = funp (a + 1, b + 2);
+ return ret;
+}
+
+int
+main(int argc, char* argv[])
+{
+ int a, b;
+ int (*funp) (int, int) = &function1;
+
+ /* Call function via Local Entry Point (LEP). */
+
+ a = 1;
+ b = 5;
+
+ function1 (a, b); // CALL VIA LEP
+
+ /* Call function via Global Entry Point (GEP). */
+ a = 10;
+ b = 50;
+
+ funp (a, b); // CALL VIA GEP
+ 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 00000000000..1f53b649a7d
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
@@ -0,0 +1,224 @@
+# 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
+
+# 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
+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 (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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP" \
+ "reverse next 1 LEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP.*" \
+ "reverse next 1 LEP 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP entry point function 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. A reverse-next
+# instruction should then stop at the first instruction in the same source
+# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
+ "reverse next 1 GEP call from function body"
+gdb_test "reverse-next" ".*b = 50;.*" \
+ "reverse next 2 at b = 50 from function body"
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:59 ` [PATCH 1/2] " Carl Love
@ 2023-03-03 11:56 ` Bruno Larsen
2023-03-08 16:19 ` [PING] " Carl Love
2023-03-09 19:03 ` Tom Tromey
1 sibling, 1 reply; 105+ messages in thread
From: Bruno Larsen @ 2023-03-03 11:56 UTC (permalink / raw)
To: Carl Love, Tom de Vries, Ulrich Weigand, gdb-patches, pedro
On 01/03/2023 21:59, Carl Love wrote:
> Tom, Ulrich, Bruno, Pedro, GDB maintainers:
>
> This patch moves the step_until procedure from gdb.reverse/step-
> indirect-call-thunk.exp to gdb/testsuite/lib/gdb.exp and renames it
> repeat_cmd_until. There are no functional changes as a result of this
> change.
>
> Patch tested on PowerPC and 5th generation X86 with no regression
> failures.
>
> Carl
>
> --------------------------------------------------------
The changes seem simple enough and dont change any outputs neither for
gcc nor clang testing, so:
Reviewed-By: Bruno Larsen <blarsen@redhat.com>
--
Cheers,
Bruno
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PING] Re: [PATCH 2/2 ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:59 ` [PATCH 2/2 ] " Carl Love
@ 2023-03-08 16:19 ` Carl Love
2023-03-09 16:09 ` Carl Love
2023-03-13 14:16 ` Ulrich Weigand
2023-03-24 17:23 ` [PATCH 2/2 ] " Simon Marchi
2 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-03-08 16:19 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
GCC developers:
Ping. Just wondering if someone could review this patch for
me. Thanks.
Carl
On Wed, 2023-03-01 at 12:59 -0800, Carl Love wrote:
> Tom, Ulrich, Bruno, Pedro, GDB maintainers:
>
> This patch fixes the reverse-finish command on PowerPC. The command
> now works the same as on other architectures, specifically
> X86. There
> are no functional changes for other architectures. The patch
> includes
> a new testcase to verify the reverse-finish command works correctly
> with the multiple entry points supported by PowerPC.
>
>
> Patch tested on PowerPC and 5th generation X86 with no regression
> failures.
>
> Carl
>
> --------------------------------------------------------
> PowerPC: fix for gdb.reverse/finish-precsave.exp and
> gdb.reverse/finish-reverse.exp
>
> PPC64 multiple entry points, a normal entry point and an alternate
> entry
> point. The alternate entry point is to setup the Table of Contents
> (TOC)
> register before continuing at the normal entry point. When the TOC
> is
> already valid, the normal entry point is used, this is typically the
> case.
> The alternate entry point is typically referred to as the global
> entry
> point (GEP) in IBM. The normal entry point is typically referred to
> as
> the local entry point (LEP).
>
> When GDB is executing the finish command in reverse, the function
> finish_backward currently sets the break point at the alternate entry
> point.
> This issue is if the function, when executing in the forward
> direction, entered
> the function via the normal entry point, execution in the reverse
> direction
> will never sees the break point at the alternate entry point. In
> this case,
> the reverse execution continues until the next break point is
> encountered thus
> stopping at the wrong place.
>
> This patch adds a new address to struct execution_control_state to
> hold the
> address of the alternate entry point (GEP). The finish_backwards
> function
> is updated, if the stopping point is between the normal entry point
> (LEP)
> and the end of the function, a breakpoint is set at the normal entry
> point.
> If the stopping point is between the entry points, a breakpoint is
> set at
> the alternate entry point. This ensures that GDB will always stop at
> the
> normal entry point. If the function did enter via the alternate
> entry point,
> GDB will detect that and continue to execute backwards in the
> function until
> the alternate entry point is reached.
>
> The patch fixes the behavior of the reverse-finish command on PowerPC
> to
> match the behavior of the command on other platforms, specifically
> X86.
> The patch does not change the behavior of the command on X86.
>
> A new test is added to verify the reverse-finish command on PowerPC
> correctly stops at the instruction where the function call is made.
>
> The patch fixes 11 regression errors in test gdb.reverse/finish-
> precsave.exp
> and 11 regression errors in test gdb.reverse/finish-reverse.exp.
>
> The patch has been tested on Power 10 and X86 processor with no new
> regression failures.
> ---
> gdb/infcmd.c | 47 ++--
> gdb/infrun.c | 24 ++
> .../gdb.reverse/finish-reverse-next.c | 91 +++++++
> .../gdb.reverse/finish-reverse-next.exp | 224
> ++++++++++++++++++
> 4 files changed, 369 insertions(+), 17 deletions(-)
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
> create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.exp
>
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index c369b795757..81c617448af 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm
> *sm)
> no way that a function up the stack can have a return address
> that's equal to its entry point. */
>
> - if (sal.pc != pc)
> - {
> - frame_info_ptr frame = get_selected_frame (nullptr);
> - struct gdbarch *gdbarch = get_frame_arch (frame);
> + CORE_ADDR alt_entry_point = sal.pc;
> + CORE_ADDR entry_point = alt_entry_point;
> + frame_info_ptr frame = get_selected_frame (nullptr);
> + struct gdbarch *gdbarch = get_frame_arch (frame);
> +
> + if (gdbarch_skip_entrypoint_p (gdbarch))
> + /* Some architectures, like PowerPC use local and global entry
> points.
> + There is only one Entry Point (GEP = LEP) for other
> architectures.
> + The GEP is an alternate entry point. The LEP is the normal
> entry point.
> + The value of entry_point was initialized to the alternate
> entry point
> + (GEP). It will be adjusted to the normal entry point if the
> function
> + has two entry points. */
> + entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
>
> - /* Set a step-resume at the function's entry point. Once
> that's
> - hit, we'll do one more step backwards. */
> + if ((pc < alt_entry_point) || (pc > entry_point))
> + {
> + /* We are in the body of the function. Set a breakpoint to go
> back to
> + the normal entry point. */
> symtab_and_line sr_sal;
> - sr_sal.pc = sal.pc;
> + sr_sal.pc = entry_point;
> 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);
> + insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
> + null_frame_id);
> }
> +
> 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 either at one of the entry points or between the entry
> points.
> + If we are not at the alt_entry point, go back to the
> alt_entry_point
> + If we at the normal entry point step back one instruction,
> when we
> + stop we will determine if we entered via the entry point or
> the
> + alternate entry point. If we are at the alternate entry
> point,
> + single step back to the function call. */
> + tp->control.step_range_start = tp->control.step_range_end = 1;
> +
> + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
> }
>
> /* finish_forward -- helper function for finish_command. FRAME is
> the
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index ab77300f1ff..ca2fc02898a 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -1938,6 +1938,7 @@ struct execution_control_state
>
> struct target_waitstatus ws;
> int stop_func_filled_in = 0;
> + CORE_ADDR stop_func_alt_start = 0;
> CORE_ADDR stop_func_start = 0;
> CORE_ADDR stop_func_end = 0;
> const char *stop_func_name = nullptr;
> @@ -4822,6 +4823,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> ecs->stop_func_start
> += gdbarch_deprecated_function_start_offset (gdbarch);
>
> + /* PowerPC functions have a Local Entry Point (LEP) and a
> Global
> + Entry Point (GEP). There is only one Entry Point (GEP =
> LEP) for
> + other architectures. */
> + ecs->stop_func_alt_start = ecs->stop_func_start;
> +
> if (gdbarch_skip_entrypoint_p (gdbarch))
> ecs->stop_func_start
> = gdbarch_skip_entrypoint (gdbarch, ecs-
> >stop_func_start);
> @@ -7411,6 +7417,24 @@ process_event_stop_test (struct
> execution_control_state *ecs)
> }
> }
>
> + if (execution_direction == EXEC_REVERSE
> + && ecs->event_thread->control.proceed_to_finish
> + && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
> + && ecs->event_thread->stop_pc () < ecs->stop_func_start)
> + {
> + /* We are executing the reverse-finish command.
> + If the system supports multiple entry points and we are
> finishing a
> + function in reverse. If we are between the entry points
> singe-step
> + back to the alternate entry point. If we are at the alternate
> entry
> + point -- just need to back up by one more single-step, which
> + should take us back to the function call. */
> + ecs->event_thread->control.step_range_start
> + = ecs->event_thread->control.step_range_end = 1;
> + keep_going (ecs);
> + return;
> +
> + }
> +
> if (ecs->event_thread->control.step_range_end == 1)
> {
> /* It is stepi or nexti. We always want to stop stepping
> after
> 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 00000000000..e95ee8e33a6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> @@ -0,0 +1,91 @@
> +/* 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
> +
> + 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). The GEP is only used if the table
> of
> + contents (TOC) value stored in register r2 needs to be setup
> prior to
> + execution starting at the LEP. 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. */
> +
> +int
> +function2 (int a, int b)
> +{
> + int ret = 0;
> + ret = ret + a + b;
> + return ret;
> +}
> +
> +int
> +function1 (int a, int b) // FUNCTION1
> +{
> + int ret = 0;
> + int (*funp) (int, int) = &function2;
> + /* The assembly code for this function when compiled for PowerPC
> is as
> + follows:
> +
> + 0000000010000758 <function1>:
> + 10000758: 02 10 40 3c lis r2,4098 <- GEP
> + 1000075c: 00 7f 42 38 addi r2,r2,32512
> + 10000760: a6 02 08 7c mflr r0 <- LEP
> + 10000764: 10 00 01 f8 std r0,16(r1)
> + ....
> +
> + When the function is called on PowerPC with function1 (a, b)
> the call
> + enters at the Local Entry Point (LEP). When the function is
> called via
> + a function pointer, the Global Entry Point (GEP) for function1
> is used.
> + The GEP sets up register 2 before reaching the LEP.
> + */
> + ret = funp (a + 1, b + 2);
> + return ret;
> +}
> +
> +int
> +main(int argc, char* argv[])
> +{
> + int a, b;
> + int (*funp) (int, int) = &function1;
> +
> + /* Call function via Local Entry Point (LEP). */
> +
> + a = 1;
> + b = 5;
> +
> + function1 (a, b); // CALL VIA LEP
> +
> + /* Call function via Global Entry Point (GEP). */
> + a = 10;
> + b = 50;
> +
> + funp (a, b); // CALL VIA GEP
> + 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 00000000000..1f53b649a7d
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> @@ -0,0 +1,224 @@
> +# 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
> +
> +# 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
> +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 (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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA LEP"
> \
> + "reverse next 1 LEP entry point function 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA
> LEP.*" \
> + "reverse next 1 LEP 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP entry point function 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP entry point function 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. A reverse-
> next
> +# instruction should then stop at the first instruction in the same
> source
> +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> + "reverse next 1 GEP call from function body"
> +gdb_test "reverse-next" ".*b = 50;.*" \
> + "reverse next 2 at b = 50 from function body"
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PING] Re: [PATCH 1/2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-03 11:56 ` Bruno Larsen
@ 2023-03-08 16:19 ` Carl Love
2023-03-09 16:09 ` Carl Love
0 siblings, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-03-08 16:19 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches, pedro; +Cc: cel
GCC developers:
Ping. Just wondering if anyone else has had a chance to review this
patch. Thanks.
Carl
On Fri, 2023-03-03 at 12:56 +0100, Bruno Larsen wrote:
> On 01/03/2023 21:59, Carl Love wrote:
> > Tom, Ulrich, Bruno, Pedro, GDB maintainers:
> >
> > This patch moves the step_until procedure from gdb.reverse/step-
> > indirect-call-thunk.exp to gdb/testsuite/lib/gdb.exp and renames it
> > repeat_cmd_until. There are no functional changes as a result of
> > this
> > change.
> >
> > Patch tested on PowerPC and 5th generation X86 with no regression
> > failures.
> >
> > Carl
> >
> > --------------------------------------------------------
> The changes seem simple enough and dont change any outputs neither
> for
> gcc nor clang testing, so:
> Reviewed-By: Bruno Larsen <blarsen@redhat.com>
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PING] Re: [PATCH 1/2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-08 16:19 ` [PING] " Carl Love
@ 2023-03-09 16:09 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-03-09 16:09 UTC (permalink / raw)
To: Bruno Larsen, Tom de Vries, Ulrich Weigand, gdb-patches, pedro; +Cc: cel
Oops, typo that should read GDB developers. Sorry about that.
On Wed, 2023-03-08 at 08:19 -0800, Carl Love wrote:
> GCC developers:
>
> Ping. Just wondering if anyone else has had a chance to review this
> patch. Thanks.
>
> Carl
>
> On Fri, 2023-03-03 at 12:56 +0100, Bruno Larsen wrote:
> > On 01/03/2023 21:59, Carl Love wrote:
> > > Tom, Ulrich, Bruno, Pedro, GDB maintainers:
> > >
> > > This patch moves the step_until procedure from gdb.reverse/step-
> > > indirect-call-thunk.exp to gdb/testsuite/lib/gdb.exp and renames
> > > it
> > > repeat_cmd_until. There are no functional changes as a result of
> > > this
> > > change.
> > >
> > > Patch tested on PowerPC and 5th generation X86 with no regression
> > > failures.
> > >
> > > Carl
> > >
> > > --------------------------------------------------------
> > The changes seem simple enough and dont change any outputs neither
> > for
> > gcc nor clang testing, so:
> > Reviewed-By: Bruno Larsen <blarsen@redhat.com>
> >
>
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PING] Re: [PATCH 2/2 ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-08 16:19 ` [PING] " Carl Love
@ 2023-03-09 16:09 ` Carl Love
0 siblings, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-03-09 16:09 UTC (permalink / raw)
To: Tom de Vries, Ulrich Weigand, gdb-patches, Bruno Larsen, pedro; +Cc: cel
Oops, that should have read GDB developers. Sorry about that.
On Wed, 2023-03-08 at 08:19 -0800, Carl Love wrote:
> GCC developers:
>
> Ping. Just wondering if someone could review this patch for
> me. Thanks.
>
> Carl
>
> On Wed, 2023-03-01 at 12:59 -0800, Carl Love wrote:
> > Tom, Ulrich, Bruno, Pedro, GDB maintainers:
> >
> > This patch fixes the reverse-finish command on PowerPC. The
> > command
> > now works the same as on other architectures, specifically
> > X86. There
> > are no functional changes for other architectures. The patch
> > includes
> > a new testcase to verify the reverse-finish command works correctly
> > with the multiple entry points supported by PowerPC.
> >
> >
> > Patch tested on PowerPC and 5th generation X86 with no regression
> > failures.
> >
> > Carl
> >
> > --------------------------------------------------------
> > PowerPC: fix for gdb.reverse/finish-precsave.exp and
> > gdb.reverse/finish-reverse.exp
> >
> > PPC64 multiple entry points, a normal entry point and an alternate
> > entry
> > point. The alternate entry point is to setup the Table of Contents
> > (TOC)
> > register before continuing at the normal entry point. When the TOC
> > is
> > already valid, the normal entry point is used, this is typically
> > the
> > case.
> > The alternate entry point is typically referred to as the global
> > entry
> > point (GEP) in IBM. The normal entry point is typically referred
> > to
> > as
> > the local entry point (LEP).
> >
> > When GDB is executing the finish command in reverse, the function
> > finish_backward currently sets the break point at the alternate
> > entry
> > point.
> > This issue is if the function, when executing in the forward
> > direction, entered
> > the function via the normal entry point, execution in the reverse
> > direction
> > will never sees the break point at the alternate entry point. In
> > this case,
> > the reverse execution continues until the next break point is
> > encountered thus
> > stopping at the wrong place.
> >
> > This patch adds a new address to struct execution_control_state to
> > hold the
> > address of the alternate entry point (GEP). The finish_backwards
> > function
> > is updated, if the stopping point is between the normal entry point
> > (LEP)
> > and the end of the function, a breakpoint is set at the normal
> > entry
> > point.
> > If the stopping point is between the entry points, a breakpoint is
> > set at
> > the alternate entry point. This ensures that GDB will always stop
> > at
> > the
> > normal entry point. If the function did enter via the alternate
> > entry point,
> > GDB will detect that and continue to execute backwards in the
> > function until
> > the alternate entry point is reached.
> >
> > The patch fixes the behavior of the reverse-finish command on
> > PowerPC
> > to
> > match the behavior of the command on other platforms, specifically
> > X86.
> > The patch does not change the behavior of the command on X86.
> >
> > A new test is added to verify the reverse-finish command on PowerPC
> > correctly stops at the instruction where the function call is made.
> >
> > The patch fixes 11 regression errors in test gdb.reverse/finish-
> > precsave.exp
> > and 11 regression errors in test gdb.reverse/finish-reverse.exp.
> >
> > The patch has been tested on Power 10 and X86 processor with no new
> > regression failures.
> > ---
> > gdb/infcmd.c | 47 ++--
> > gdb/infrun.c | 24 ++
> > .../gdb.reverse/finish-reverse-next.c | 91 +++++++
> > .../gdb.reverse/finish-reverse-next.exp | 224
> > ++++++++++++++++++
> > 4 files changed, 369 insertions(+), 17 deletions(-)
> > create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-
> > next.exp
> >
> > diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> > index c369b795757..81c617448af 100644
> > --- a/gdb/infcmd.c
> > +++ b/gdb/infcmd.c
> > @@ -1728,28 +1728,41 @@ finish_backward (struct finish_command_fsm
> > *sm)
> > no way that a function up the stack can have a return address
> > that's equal to its entry point. */
> >
> > - if (sal.pc != pc)
> > - {
> > - frame_info_ptr frame = get_selected_frame (nullptr);
> > - struct gdbarch *gdbarch = get_frame_arch (frame);
> > + CORE_ADDR alt_entry_point = sal.pc;
> > + CORE_ADDR entry_point = alt_entry_point;
> > + frame_info_ptr frame = get_selected_frame (nullptr);
> > + struct gdbarch *gdbarch = get_frame_arch (frame);
> > +
> > + if (gdbarch_skip_entrypoint_p (gdbarch))
> > + /* Some architectures, like PowerPC use local and global entry
> > points.
> > + There is only one Entry Point (GEP = LEP) for other
> > architectures.
> > + The GEP is an alternate entry point. The LEP is the normal
> > entry point.
> > + The value of entry_point was initialized to the alternate
> > entry point
> > + (GEP). It will be adjusted to the normal entry point if
> > the
> > function
> > + has two entry points. */
> > + entry_point = gdbarch_skip_entrypoint (gdbarch, sal.pc);
> >
> > - /* Set a step-resume at the function's entry point. Once
> > that's
> > - hit, we'll do one more step backwards. */
> > + if ((pc < alt_entry_point) || (pc > entry_point))
> > + {
> > + /* We are in the body of the function. Set a breakpoint to
> > go
> > back to
> > + the normal entry point. */
> > symtab_and_line sr_sal;
> > - sr_sal.pc = sal.pc;
> > + sr_sal.pc = entry_point;
> > 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);
> > + insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
> > + null_frame_id);
> > }
> > +
> > 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 either at one of the entry points or between the
> > entry
> > points.
> > + If we are not at the alt_entry point, go back to the
> > alt_entry_point
> > + If we at the normal entry point step back one instruction,
> > when we
> > + stop we will determine if we entered via the entry point or
> > the
> > + alternate entry point. If we are at the alternate entry
> > point,
> > + single step back to the function call. */
> > + tp->control.step_range_start = tp->control.step_range_end = 1;
> > +
> > + proceed ((CORE_ADDR) -1, GDB_SIGNAL_DEFAULT);
> > }
> >
> > /* finish_forward -- helper function for finish_command. FRAME is
> > the
> > diff --git a/gdb/infrun.c b/gdb/infrun.c
> > index ab77300f1ff..ca2fc02898a 100644
> > --- a/gdb/infrun.c
> > +++ b/gdb/infrun.c
> > @@ -1938,6 +1938,7 @@ struct execution_control_state
> >
> > struct target_waitstatus ws;
> > int stop_func_filled_in = 0;
> > + CORE_ADDR stop_func_alt_start = 0;
> > CORE_ADDR stop_func_start = 0;
> > CORE_ADDR stop_func_end = 0;
> > const char *stop_func_name = nullptr;
> > @@ -4822,6 +4823,11 @@ fill_in_stop_func (struct gdbarch *gdbarch,
> > ecs->stop_func_start
> > += gdbarch_deprecated_function_start_offset (gdbarch);
> >
> > + /* PowerPC functions have a Local Entry Point (LEP) and a
> > Global
> > + Entry Point (GEP). There is only one Entry Point (GEP =
> > LEP) for
> > + other architectures. */
> > + ecs->stop_func_alt_start = ecs->stop_func_start;
> > +
> > if (gdbarch_skip_entrypoint_p (gdbarch))
> > ecs->stop_func_start
> > = gdbarch_skip_entrypoint (gdbarch, ecs-
> > > stop_func_start);
> > @@ -7411,6 +7417,24 @@ process_event_stop_test (struct
> > execution_control_state *ecs)
> > }
> > }
> >
> > + if (execution_direction == EXEC_REVERSE
> > + && ecs->event_thread->control.proceed_to_finish
> > + && ecs->event_thread->stop_pc () >= ecs->stop_func_alt_start
> > + && ecs->event_thread->stop_pc () < ecs->stop_func_start)
> > + {
> > + /* We are executing the reverse-finish command.
> > + If the system supports multiple entry points and we are
> > finishing a
> > + function in reverse. If we are between the entry points
> > singe-step
> > + back to the alternate entry point. If we are at the alternate
> > entry
> > + point -- just need to back up by one more single-step, which
> > + should take us back to the function call. */
> > + ecs->event_thread->control.step_range_start
> > + = ecs->event_thread->control.step_range_end = 1;
> > + keep_going (ecs);
> > + return;
> > +
> > + }
> > +
> > if (ecs->event_thread->control.step_range_end == 1)
> > {
> > /* It is stepi or nexti. We always want to stop stepping
> > after
> > 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 00000000000..e95ee8e33a6
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.c
> > @@ -0,0 +1,91 @@
> > +/* 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
> > +
> > + 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). The GEP is only used if the
> > table
> > of
> > + contents (TOC) value stored in register r2 needs to be setup
> > prior to
> > + execution starting at the LEP. 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. */
> > +
> > +int
> > +function2 (int a, int b)
> > +{
> > + int ret = 0;
> > + ret = ret + a + b;
> > + return ret;
> > +}
> > +
> > +int
> > +function1 (int a, int b) // FUNCTION1
> > +{
> > + int ret = 0;
> > + int (*funp) (int, int) = &function2;
> > + /* The assembly code for this function when compiled for PowerPC
> > is as
> > + follows:
> > +
> > + 0000000010000758 <function1>:
> > + 10000758: 02 10 40 3c lis r2,4098 <-
> > GEP
> > + 1000075c: 00 7f 42 38 addi r2,r2,32512
> > + 10000760: a6 02 08 7c mflr r0 <-
> > LEP
> > + 10000764: 10 00 01 f8 std r0,16(r1)
> > + ....
> > +
> > + When the function is called on PowerPC with function1 (a, b)
> > the call
> > + enters at the Local Entry Point (LEP). When the function is
> > called via
> > + a function pointer, the Global Entry Point (GEP) for
> > function1
> > is used.
> > + The GEP sets up register 2 before reaching the LEP.
> > + */
> > + ret = funp (a + 1, b + 2);
> > + return ret;
> > +}
> > +
> > +int
> > +main(int argc, char* argv[])
> > +{
> > + int a, b;
> > + int (*funp) (int, int) = &function1;
> > +
> > + /* Call function via Local Entry Point (LEP). */
> > +
> > + a = 1;
> > + b = 5;
> > +
> > + function1 (a, b); // CALL VIA LEP
> > +
> > + /* Call function via Global Entry Point (GEP). */
> > + a = 10;
> > + b = 50;
> > +
> > + funp (a, b); // CALL VIA GEP
> > + 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 00000000000..1f53b649a7d
> > --- /dev/null
> > +++ b/gdb/testsuite/gdb.reverse/finish-reverse-next.exp
> > @@ -0,0 +1,224 @@
> > +# 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
> > +
> > +# 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
> > +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 (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. A
> > reverse-
> > next
> > +# instruction should then stop at the first instruction in the
> > same
> > source
> > +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA
> > LEP"
> > \
> > + "reverse next 1 LEP entry point function 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. A
> > reverse-
> > next
> > +# instruction should then stop at the first instruction in the
> > same
> > source
> > +# code line. Another revers-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" ".*function1 \\(a, b\\); // CALL VIA
> > LEP.*" \
> > + "reverse next 1 LEP 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. A
> > reverse-
> > next
> > +# instruction should then stop at the first instruction in the
> > same
> > source
> > +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> > + "reverse next 1 GEP entry point function 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. A
> > reverse-
> > next
> > +# instruction should then stop at the first instruction in the
> > same
> > source
> > +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> > + "reverse next 1 GEP entry point function 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. A
> > reverse-
> > next
> > +# instruction should then stop at the first instruction in the
> > same
> > source
> > +# code line. Another revers-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" ".*funp \\(a, b\\);.*" \
> > + "reverse next 1 GEP call from function body"
> > +gdb_test "reverse-next" ".*b = 50;.*" \
> > + "reverse next 2 at b = 50 from function body"
>
>
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:59 ` [PATCH 1/2] " Carl Love
2023-03-03 11:56 ` Bruno Larsen
@ 2023-03-09 19:03 ` Tom Tromey
2023-03-09 21:42 ` Carl Love
2023-03-09 21:54 ` [PATCH 1/2 ver 2] " Carl Love
1 sibling, 2 replies; 105+ messages in thread
From: Tom Tromey @ 2023-03-09 19:03 UTC (permalink / raw)
To: Carl Love via Gdb-patches
Cc: Tom de Vries, Ulrich Weigand, Bruno Larsen, pedro, Carl Love
>>>>> "Carl" == Carl Love via Gdb-patches <gdb-patches@sourceware.org> writes:
Carl> Procedure proc_step_until from test gdb.reverse/step-indirect-call-thunk.exp
The "proc_" in there seems incorrect.
Carl> # Step until the pattern REGEXP is found. Step at most
Carl> # MAX_STEPS times, but stop stepping once REGEXP is found.
Carl> -#
Carl> +# CURRENT matches current location
Carl> # If REGEXP is found then a single pass is emitted, otherwise, after
Carl> # MAX_STEPS steps, a single fail is emitted.
Carl> #
Carl> # TEST_NAME is the name used in the pass/fail calls.
Carl> -proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
Carl> +proc gdb_step_until { regexp {test_name ""} {current ""} \
Carl> + { max_steps 10 } } {
Carl> + if { $current == "" } {
Carl> + set current "\}"
Carl> + }
Carl> + if { $test_name == "" } {
Carl> + set test_name "stepping until regexp"
Carl> + }
I think you can just supply these as defaults directly in the proc
definition.
Carl> +# Do repeated stepping COMMANDs in order to reach TARGET from CURRENT
Carl> +#
Carl> +# COMMAND is a stepping command
Carl> +# CURRENT is a string matching the current location
Carl> +# TARGET is a string matching the target location
Carl> +# TEST is the test name
Carl> +# MAX_STEPS is number of steps attempted before fail is emitted
Carl> +#
Carl> +# The function issues repeated COMMANDs as long as the location matches
Carl> +# CURRENT up to a maximum of 100 steps.
s/100/MAX_STEPS
Carl> +#
Carl> +# TEST passes if the resulting location matches TARGET and fails
Carl> +# otherwise.
Carl> +#
Carl> +proc repeat_cmd_until { command current target test_name {max_steps 100} } {
The docs refer to "TEST" but should use "TEST_NAME".
thanks,
Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* RE: [PATCH 1/2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-09 19:03 ` Tom Tromey
@ 2023-03-09 21:42 ` Carl Love
2023-03-09 21:54 ` [PATCH 1/2 ver 2] " Carl Love
1 sibling, 0 replies; 105+ messages in thread
From: Carl Love @ 2023-03-09 21:42 UTC (permalink / raw)
To: Tom Tromey, Carl Love via Gdb-patches
Cc: Tom de Vries, Ulrich Weigand, Bruno Larsen, pedro
On Thu, 2023-03-09 at 12:03 -0700, Tom Tromey wrote:
> > > > > > "Carl" == Carl Love via Gdb-patches <
> > > > > > gdb-patches@sourceware.org> writes:
>
> Carl> Procedure proc_step_until from test gdb.reverse/step-indirect-
> call-thunk.exp
>
> The "proc_" in there seems incorrect.
Ah, yea. Good catch. Fixed that.
>
> Carl> # Step until the pattern REGEXP is found. Step at most
> Carl> # MAX_STEPS times, but stop stepping once REGEXP is found.
> Carl> -#
> Carl> +# CURRENT matches current location
> Carl> # If REGEXP is found then a single pass is emitted, otherwise,
> after
> Carl> # MAX_STEPS steps, a single fail is emitted.
> Carl> #
> Carl> # TEST_NAME is the name used in the pass/fail calls.
>
> Carl> -proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
> Carl> +proc gdb_step_until { regexp {test_name ""} {current ""} \
> Carl> + { max_steps 10 } } {
> Carl> + if { $current == "" } {
> Carl> + set current "\}"
> Carl> + }
> Carl> + if { $test_name == "" } {
> Carl> + set test_name "stepping until regexp"
> Carl> + }
>
> I think you can just supply these as defaults directly in the proc
> definition.
True, I guess I was just keeping with the original "style". But yea,
better to do these as defaults. Changed to use defaults in this
function and similarly in the the new proceedure gdb_step_until.
>
> Carl> +# Do repeated stepping COMMANDs in order to reach TARGET from
> CURRENT
> Carl> +#
> Carl> +# COMMAND is a stepping command
> Carl> +# CURRENT is a string matching the current location
> Carl> +# TARGET is a string matching the target location
> Carl> +# TEST is the test name
> Carl> +# MAX_STEPS is number of steps attempted before fail is
> emitted
> Carl> +#
> Carl> +# The function issues repeated COMMANDs as long as the
> location matches
> Carl> +# CURRENT up to a maximum of 100 steps.
>
> s/100/MAX_STEPS
OK, changed.
>
> Carl> +#
> Carl> +# TEST passes if the resulting location matches TARGET and
> fails
> Carl> +# otherwise.
> Carl> +#
> Carl> +proc repeat_cmd_until { command current target test_name
> {max_steps 100} } {
>
> The docs refer to "TEST" but should use "TEST_NAME".
yup, thanks. Changed.
Will post version 2. Thanks for the review.
Carl
^ permalink raw reply [flat|nested] 105+ messages in thread
* [PATCH 1/2 ver 2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-09 19:03 ` Tom Tromey
2023-03-09 21:42 ` Carl Love
@ 2023-03-09 21:54 ` Carl Love
2023-03-10 3:53 ` Tom Tromey
1 sibling, 1 reply; 105+ messages in thread
From: Carl Love @ 2023-03-09 21:54 UTC (permalink / raw)
To: Tom Tromey, Carl Love via Gdb-patches, cel
Cc: Tom de Vries, Ulrich Weigand, Bruno Larsen, pedro
GDB maintainers, Tom, Ulrich, Bruno, Pedro:
I fixed the documentation errors and changed the arguments of the
proceedures to set the values by default rather than using an
additional if statement.
Fixed a couple of spelling mistakes in the commit log.
I retested the patch to make sure everything still works.
Thanks for the reviews.
Carl
--------------------------------------------------------
Move step_until procedure
Procedure step_until from test gdb.reverse/step-indirect-call-thunk.exp
is moved to lib/gdb.exp and renamed repeat_cmd_until. The existing procedure
gdb_step_until in lib/gdb.exp is simpler variant of the new repeat_cmd_until
procedure. The existing procedure gdb_step_until is changed to just call
the new repeat_cmd_until procedure with the command set to "step" and an
optional CURRENT string. The default CURRENT string is set to "\}" to work
with the existing uses of procedure gdb_step_until.
---
.../gdb.reverse/step-indirect-call-thunk.exp | 49 +++----------------
gdb/testsuite/lib/gdb.exp | 47 ++++++++++++------
2 files changed, 41 insertions(+), 55 deletions(-)
diff --git a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
index f433efb11c2..e6c81b80a7b 100644
--- a/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
+++ b/gdb/testsuite/gdb.reverse/step-indirect-call-thunk.exp
@@ -38,39 +38,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"
@@ -90,20 +57,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/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 19c782bea46..46bd40318f6 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -9270,31 +9270,50 @@ gdb_caching_proc arm_cc_for_target {
# Step until the pattern REGEXP is found. Step at most
# MAX_STEPS times, but stop stepping once REGEXP is found.
-#
+# CURRENT matches current location
# If REGEXP is found then a single pass is emitted, otherwise, after
# MAX_STEPS steps, a single fail is emitted.
#
# TEST_NAME is the name used in the pass/fail calls.
-proc gdb_step_until { regexp {test_name ""} {max_steps 10} } {
- if { $test_name == "" } {
- set test_name "stepping until regexp"
- }
+proc gdb_step_until { regexp {test_name "stepping until regexp"} \
+ {current "\}"} { max_steps 10 } } {
+ repeat_cmd_until "step" $current $regexp $test_name "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_NAME is the test name
+# MAX_STEPS is number of steps attempted before fail is emitted
+#
+# The function issues repeated COMMANDs as long as the location matches
+# CURRENT up to a maximum of MAX_STEPS.
+#
+# TEST_NAME passes if the resulting location matches TARGET and fails
+# otherwise.
+
+proc repeat_cmd_until { command current target \
+ {test_name "stepping until regexp"} \
+ {max_steps 100} } {
+ global gdb_prompt
set count 0
- gdb_test_multiple "step" "$test_name" {
- -re "$regexp\r\n$::gdb_prompt $" {
- pass $test_name
- }
- -re ".*$::gdb_prompt $" {
- if {$count < $max_steps} {
- incr count
- send_gdb "step\n"
+ gdb_test_multiple "$command" "$test_name" {
+ -re "$current.*$gdb_prompt $" {
+ incr count
+ if { $count < $max_steps } {
+ send_gdb "$command\n"
exp_continue
} else {
- fail $test_name
+ fail "$test_name"
}
}
+ -re "$target.*$gdb_prompt $" {
+ pass "$test_name"
+ }
}
}
--
2.37.2
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 1/2 ver 2] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-09 21:54 ` [PATCH 1/2 ver 2] " Carl Love
@ 2023-03-10 3:53 ` Tom Tromey
0 siblings, 0 replies; 105+ messages in thread
From: Tom Tromey @ 2023-03-10 3:53 UTC (permalink / raw)
To: Carl Love
Cc: Tom Tromey, Carl Love via Gdb-patches, Tom de Vries,
Ulrich Weigand, Bruno Larsen, pedro
>>>>> Carl Love <cel@us.ibm.com> writes:
> Move step_until procedure
> Procedure step_until from test gdb.reverse/step-indirect-call-thunk.exp
> is moved to lib/gdb.exp and renamed repeat_cmd_until. The existing procedure
> gdb_step_until in lib/gdb.exp is simpler variant of the new repeat_cmd_until
> procedure. The existing procedure gdb_step_until is changed to just call
> the new repeat_cmd_until procedure with the command set to "step" and an
> optional CURRENT string. The default CURRENT string is set to "\}" to work
> with the existing uses of procedure gdb_step_until.
Thanks, this looks good to me.
Tom
^ permalink raw reply [flat|nested] 105+ messages in thread
* Re: [PATCH 2/2 ] PowerPC: fix for gdb.reverse/finish-precsave.exp and gdb.reverse/finish-reverse.exp
2023-03-01 20:59 ` [PATCH 2/2 ] " Carl Love
2023-03-08 16:19 ` [PING] " Carl Love
@ 2023-03-13 14:16 ` Ulrich Weigand
2023-03-13 17:31 ` Carl Love
2023-03-13 17:38 ` [PATCH 2/2 ver2] " Carl Love
2023-03-24 17:23 ` [PATCH 2/2 ] " Simon Marchi