Skip to content

Commit baf6989

Browse files
committed
Fix reverse-singlestepping through ARM instructions that trigger data watchpoints.
1 parent 3611867 commit baf6989

4 files changed

Lines changed: 45 additions & 4 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,6 +1801,7 @@ set(TESTS_WITHOUT_PROGRAM
18011801
vsyscall_singlestep
18021802
watch_code
18031803
watchpoint_cond
1804+
watchpoint_step
18041805
watchpoint_unaligned2
18051806
when
18061807
)

src/ReplayTimeline.cc

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,10 +1300,13 @@ ReplayResult ReplayTimeline::reverse_singlestep(
13001300
RUN_SINGLESTEP_FAST_FORWARD);
13011301
constraints.stop_before_states.push_back(&end.ptr->proto.regs);
13021302
result = current->replay_step(constraints);
1303+
ReplayResult result_with_breakpoints_and_watchpoints = result;
13031304
update_observable_break_status(now, result);
1305+
bool stopped_before_watchpoint =
1306+
!result.break_status.data_watchpoints_hit().empty() &&
1307+
arch_watch_fires_before_instr(current->arch());
13041308
if (result.break_status.hardware_or_software_breakpoint_hit() ||
1305-
(!result.break_status.data_watchpoints_hit().empty() &&
1306-
arch_watch_fires_before_instr(current->arch()))) {
1309+
stopped_before_watchpoint) {
13071310
// If we hit a breakpoint while singlestepping, we didn't
13081311
// make any progress.
13091312
unapply_breakpoints_and_watchpoints();
@@ -1325,10 +1328,18 @@ ReplayResult ReplayTimeline::reverse_singlestep(
13251328
<< " pretending we stopped earlier.";
13261329
break;
13271330
}
1328-
destination_candidate = step_start;
1331+
if (stopped_before_watchpoint) {
1332+
// On ARM, watchpoints fire before the instruction executes.
1333+
// This instruction triggered the watchpoint so we need to
1334+
// stop before the instruction is reverse-executed, i.e. after
1335+
// it actually executed.
1336+
destination_candidate = now;
1337+
} else {
1338+
destination_candidate = step_start;
1339+
}
13291340
LOG(debug) << "Setting candidate after step: "
13301341
<< destination_candidate;
1331-
destination_candidate_result = result;
1342+
destination_candidate_result = result_with_breakpoints_and_watchpoints;
13321343
destination_candidate_tuid = result.break_status.task()->tuid();
13331344
destination_candidate_saw_other_task_break = seen_other_task_break;
13341345
seen_other_task_break = false;

src/test/watchpoint_step.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from util import *
2+
3+
send_gdb('break main')
4+
expect_gdb('Breakpoint 1')
5+
send_gdb('c')
6+
expect_gdb('Breakpoint 1')
7+
8+
send_gdb('p &var')
9+
expect_gdb(r'\$1 = \(volatile int \*\) ')
10+
11+
send_gdb('watch *$1')
12+
expect_gdb('Hardware[()/a-z ]+watchpoint 2')
13+
14+
send_gdb('c')
15+
expect_gdb('Old value = 0')
16+
expect_gdb('New value = 42')
17+
18+
send_gdb('reverse-stepi')
19+
expect_gdb('Old value = 42')
20+
expect_gdb('New value = 0')
21+
22+
send_gdb('stepi')
23+
expect_gdb('Old value = 0')
24+
expect_gdb('New value = 42')
25+
26+
ok()

src/test/watchpoint_step.run

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source `dirname $0`/util.sh
2+
record watchpoint$bitness
3+
debug_gdb_only watchpoint_step

0 commit comments

Comments
 (0)