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
This commit is contained in:
Pedro Alves
2021-11-23 14:19:07 +00:00
parent 4414150d33
commit d37e084783
5 changed files with 177 additions and 15 deletions

View File

@@ -4491,9 +4491,9 @@ handle_syscall_event (struct execution_control_state *ecs)
infrun_debug_printf ("syscall number=%d", syscall_number);
ecs->event_thread->control.stop_bpstat
= bpstat_stop_status (regcache->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
= bpstat_stop_status_nowatch (regcache->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return false;
@@ -5288,9 +5288,9 @@ handle_inferior_event (struct execution_control_state *ecs)
ecs->event_thread->set_stop_pc (regcache_read_pc (regcache));
ecs->event_thread->control.stop_bpstat
= bpstat_stop_status (regcache->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
= bpstat_stop_status_nowatch (regcache->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return;
@@ -5531,9 +5531,9 @@ handle_inferior_event (struct execution_control_state *ecs)
(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
ecs->event_thread->control.stop_bpstat
= bpstat_stop_status (get_current_regcache ()->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
= bpstat_stop_status_nowatch (get_current_regcache ()->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return;
@@ -5642,9 +5642,9 @@ handle_inferior_event (struct execution_control_state *ecs)
(regcache_read_pc (get_thread_regcache (ecs->event_thread)));
ecs->event_thread->control.stop_bpstat
= bpstat_stop_status (get_current_regcache ()->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
= bpstat_stop_status_nowatch (get_current_regcache ()->aspace (),
ecs->event_thread->stop_pc (),
ecs->event_thread, ecs->ws);
if (handle_stop_requested (ecs))
return;