diff options
author | Pedro Alves <pedro@palves.net> | 2021-11-23 14:19:07 +0000 |
---|---|---|
committer | Pedro Alves <pedro@palves.net> | 2022-03-21 17:27:17 +0000 |
commit | d37e084783a04c63ae137f953ebdb58bb6f7f704 (patch) | |
tree | 90e82c9060245f0cec3f94d3cb6a2a73bc8df4c0 /gdb/breakpoint.h | |
parent | 4414150d33212f5f395c3bf8a940bccf80ffc508 (diff) | |
download | binutils-d37e084783a04c63ae137f953ebdb58bb6f7f704.zip binutils-d37e084783a04c63ae137f953ebdb58bb6f7f704.tar.gz binutils-d37e084783a04c63ae137f953ebdb58bb6f7f704.tar.bz2 |
Watchpoint followed by catchpoint misreports watchpoint (PR gdb/28621)
If GDB reports a watchpoint hit, and then the next event is not
TARGET_WAITKIND_STOPPED, but instead some event for which there's a
catchpoint, such that GDB calls bpstat_stop_status, GDB mistakenly
thinks the watchpoint triggered. Vis, using foll-fork.c:
(gdb) awatch v
Hardware access (read/write) watchpoint 2: v
(gdb) catch fork
Catchpoint 3 (fork)
(gdb) c
Continuing.
Hardware access (read/write) watchpoint 2: v
Old value = 0
New value = 5
main () at gdb.base/foll-fork.c:16
16 pid = fork ();
(gdb)
Continuing.
Hardware access (read/write) watchpoint 2: v <<<<
<<<< these lines are spurious
Value = 5 <<<<
Catchpoint 3 (forked process 1712369), arch_fork (ctid=0x7ffff7fa4810) at arch-fork.h:49
49 arch-fork.h: No such file or directory.
(gdb)
The problem is that when we handle the fork event, nothing called
watchpoints_triggered before calling bpstat_stop_status. Thus, each
watchpoint's watchpoint_triggered field was still set to
watch_triggered_yes from the previous (real) watchpoint stop.
watchpoint_triggered is only current called in the handle_signal_stop
path, when handling TARGET_WAITKIND_STOPPED.
This fixes it by adding watchpoint_triggered calls in the other events
paths that call bpstat_stop_status. But instead of adding them
explicitly, it adds a new function bpstat_stop_status_nowatch that
wraps bpstat_stop_status and calls watchpoint_triggered, and then
replaces most calls to bpstat_stop_status with calls to
bpstat_stop_status_nowatch.
This required constifying watchpoints_triggered.
New test included, which fails without the fix.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28621
Change-Id: I282b38c2eee428d25319af3bc842f9feafed461c
Diffstat (limited to 'gdb/breakpoint.h')
-rw-r--r-- | gdb/breakpoint.h | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index ba28219..e412c4d 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -968,13 +968,31 @@ extern bpstat *build_bpstat_chain (const address_space *aspace, several reasons concurrently.) Each element of the chain has valid next, breakpoint_at, - commands, FIXME??? fields. */ + commands, FIXME??? fields. + + watchpoints_triggered must be called beforehand to set up each + watchpoint's watchpoint_triggered value. + +*/ extern bpstat *bpstat_stop_status (const address_space *aspace, CORE_ADDR pc, thread_info *thread, const target_waitstatus &ws, bpstat *stop_chain = nullptr); + +/* Like bpstat_stop_status, but clears all watchpoints' + watchpoint_triggered flag. Unlike with bpstat_stop_status, there's + no need to call watchpoint_triggered beforehand. You'll typically + use this variant when handling a known-non-watchpoint event, like a + fork or exec event. */ + +extern bpstat *bpstat_stop_status_nowatch (const address_space *aspace, + CORE_ADDR bp_addr, + thread_info *thread, + const target_waitstatus &ws); + + /* This bpstat_what stuff tells wait_for_inferior what to do with a breakpoint (a challenging task). @@ -1607,8 +1625,9 @@ extern void insert_single_step_breakpoint (struct gdbarch *, otherwise, return false. */ extern int insert_single_step_breakpoints (struct gdbarch *); -/* Check if any hardware watchpoints have triggered, according to the - target. */ +/* Check whether any hardware watchpoints have triggered or not, + according to the target, and record it in each watchpoint's + 'watchpoint_triggered' field. */ int watchpoints_triggered (const target_waitstatus &); /* Helper for transparent breakpoint hiding for memory read and write |