aboutsummaryrefslogtreecommitdiff
path: root/gdb/infrun.c
diff options
context:
space:
mode:
authorCarl Love <cel@linux.ibm.com>2024-01-02 17:46:02 -0500
committerCarl Love <cel@linux.ibm.com>2024-01-02 17:46:02 -0500
commitfe6356def678a93121a68147bdf93b6980bbf75d (patch)
treecb2ff763d9af621b425751841cd6255ee59baa94 /gdb/infrun.c
parent29deb4221d07d2c497183853e6023acb51d49be9 (diff)
downloadfsf-binutils-gdb-fe6356def678a93121a68147bdf93b6980bbf75d.zip
fsf-binutils-gdb-fe6356def678a93121a68147bdf93b6980bbf75d.tar.gz
fsf-binutils-gdb-fe6356def678a93121a68147bdf93b6980bbf75d.tar.bz2
PowerPC and aarch64: Fix reverse stepping failure
When running GDB's testsuite on aarch64-linux/Ubuntu 20.04 (also spotted on the ppc backend), there are failures in gdb.reverse/solib-precsave.exp and gdb.reverse/solib-reverse.exp. The failure happens around the following code: 38 b[1] = shr2(17); /* middle part two */ 40 b[0] = 6; b[1] = 9; /* generic statement, end part two */ 42 shr1 ("message 1\n"); /* shr1 one */ Normal execution: - step from line 38 will land on line 40. - step from line 40 will land on line 42. Reverse execution: - step from line 42 will land on line 40. - step from line 40 will land on line 40. - step from line 40 will land on line 38. The problem here is that line 40 contains two contiguous but distinct PC ranges in the line table, like so: Line 40 - [0x7ec ~ 0x7f4] Line 40 - [0x7f4 ~ 0x7fc] The two distinct ranges are generated because GCC started outputting source column information, which GDB doesn't take into account at the moment. When stepping forward from line 40, we skip both of these ranges and land on line 42. When stepping backward from line 42, we stop at the start PC of the second (or first, going backwards) range of line 40. Since we've reached ecs->event_thread->control.step_range_start, we stop stepping backwards. The above issues were fixed by introducing a new function that looks for adjacent PC ranges for the same line, until we notice a line change. Then we take that as the start PC of the range. The new start PC for the range is used for the control.step_range_start when setting up a step range. The test case gdb.reverse/map-to-same-line.exp is added to test the fix for the above reverse step issues. Patch has been tested on PowerPC, X86 and AArch64 with no regressions.
Diffstat (limited to 'gdb/infrun.c')
-rw-r--r--gdb/infrun.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1d86389..c769e97 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -116,6 +116,8 @@ static struct async_event_handler *infrun_async_inferior_event_token;
/* Stores whether infrun_async was previously enabled or disabled.
Starts off as -1, indicating "never enabled/disabled". */
static int infrun_is_async = -1;
+static CORE_ADDR update_line_range_start (CORE_ADDR pc,
+ struct execution_control_state *ecs);
/* See infrun.h. */
@@ -7295,6 +7297,27 @@ handle_signal_stop (struct execution_control_state *ecs)
process_event_stop_test (ecs);
}
+/* Return the address for the beginning of the line. */
+
+CORE_ADDR
+update_line_range_start (CORE_ADDR pc, struct execution_control_state *ecs)
+{
+ /* The line table may have multiple entries for the same source code line.
+ Given the PC, check the line table and return the PC that corresponds
+ to the line table entry for the source line that PC is in. */
+ CORE_ADDR start_line_pc = ecs->event_thread->control.step_range_start;
+ std::optional<CORE_ADDR> real_range_start;
+
+ /* Call find_line_range_start to get the smallest address in the
+ linetable for multiple Line X entries in the line table. */
+ real_range_start = find_line_range_start (pc);
+
+ if (real_range_start.has_value ())
+ start_line_pc = *real_range_start;
+
+ return start_line_pc;
+}
+
/* Come here when we've got some debug event / signal we can explain
(IOW, not a random signal), and test whether it should cause a
stop, or whether we should resume the inferior (transparently).
@@ -8109,6 +8132,29 @@ process_event_stop_test (struct execution_control_state *ecs)
if (stop_pc_sal.is_stmt)
{
+ if (execution_direction == EXEC_REVERSE)
+ {
+ /* We are stepping backwards make sure we have reached the
+ beginning of the line. */
+ CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
+ CORE_ADDR start_line_pc
+ = update_line_range_start (stop_pc, ecs);
+
+ if (stop_pc != start_line_pc)
+ {
+ /* Have not reached the beginning of the source code line.
+ Set a step range. Execution should stop in any function
+ calls we execute back into before reaching the beginning
+ of the line. */
+ ecs->event_thread->control.step_range_start
+ = start_line_pc;
+ ecs->event_thread->control.step_range_end = stop_pc;
+ set_step_info (ecs->event_thread, frame, stop_pc_sal);
+ keep_going (ecs);
+ return;
+ }
+ }
+
/* We are at the start of a statement.
So stop. Note that we don't stop if we step into the middle of a
@@ -8183,6 +8229,17 @@ process_event_stop_test (struct execution_control_state *ecs)
set_step_info (ecs->event_thread, frame, stop_pc_sal);
infrun_debug_printf ("keep going");
+
+ if (execution_direction == EXEC_REVERSE)
+ {
+ CORE_ADDR stop_pc = ecs->event_thread->stop_pc ();
+
+ /* Make sure the stop_pc is set to the beginning of the line. */
+ if (stop_pc != ecs->event_thread->control.step_range_start)
+ ecs->event_thread->control.step_range_start
+ = update_line_range_start (stop_pc, ecs);
+ }
+
keep_going (ecs);
}