| Index: gdb/gdbserver/i386-low.c
|
| diff --git a/gdb/gdbserver/i386-low.c b/gdb/gdbserver/i386-low.c
|
| index 362395c234d32fa247125609da7c7da7f53deff6..902a9e9156ad323f194b83f9dd39d09786c5f6f5 100644
|
| --- a/gdb/gdbserver/i386-low.c
|
| +++ b/gdb/gdbserver/i386-low.c
|
| @@ -559,24 +559,60 @@ i386_low_stopped_data_address (struct i386_debug_reg_state *state,
|
| CORE_ADDR addr = 0;
|
| int i;
|
| int rc = 0;
|
| + /* The current thread's DR_STATUS. We always need to read this to
|
| + check whether some watchpoint caused the trap. */
|
| unsigned status;
|
| - unsigned control;
|
| -
|
| - /* Get the current values the inferior has. If the thread was
|
| - running when we last changed watchpoints, the mirror no longer
|
| - represents what was set in this LWP's debug registers. */
|
| + /* We need DR_CONTROL as well, but only iff DR_STATUS indicates a
|
| + data breakpoint trap. Only fetch it when necessary, to avoid an
|
| + unnecessary extra syscall when no watchpoint triggered. */
|
| + int control_p = 0;
|
| + unsigned control = 0;
|
| +
|
| + /* In non-stop/async, threads can be running while we change the
|
| + global dr_mirror (and friends). Say, we set a watchpoint, and
|
| + let threads resume. Now, say you delete the watchpoint, or
|
| + add/remove watchpoints such that dr_mirror changes while threads
|
| + are running. On targets that support non-stop,
|
| + inserting/deleting watchpoints updates the global dr_mirror only.
|
| + It does not update the real thread's debug registers; that's only
|
| + done prior to resume. Instead, if threads are running when the
|
| + mirror changes, a temporary and transparent stop on all threads
|
| + is forced so they can get their copy of the debug registers
|
| + updated on re-resume. Now, say, a thread hit a watchpoint before
|
| + having been updated with the new dr_mirror contents, and we
|
| + haven't yet handled the corresponding SIGTRAP. If we trusted
|
| + dr_mirror below, we'd mistake the real trapped address (from the
|
| + last time we had updated debug registers in the thread) with
|
| + whatever was currently in dr_mirror. So to fix this, dr_mirror
|
| + always represents intention, what we _want_ threads to have in
|
| + debug registers. To get at the address and cause of the trap, we
|
| + need to read the state the thread still has in its debug
|
| + registers.
|
| +
|
| + In sum, always get the current debug register values the current
|
| + thread has, instead of trusting the global mirror. If the thread
|
| + was running when we last changed watchpoints, the mirror no
|
| + longer represents what was set in this thread's debug
|
| + registers. */
|
| status = i386_dr_low_get_status ();
|
| - control = i386_dr_low_get_control ();
|
|
|
| ALL_DEBUG_REGISTERS (i)
|
| {
|
| - if (I386_DR_WATCH_HIT (status, i)
|
| - /* This second condition makes sure DRi is set up for a data
|
| - watchpoint, not a hardware breakpoint. The reason is
|
| - that GDB doesn't call the target_stopped_data_address
|
| - method except for data watchpoints. In other words, I'm
|
| - being paranoiac. */
|
| - && I386_DR_GET_RW_LEN (control, i) != 0)
|
| + if (!I386_DR_WATCH_HIT (status, i))
|
| + continue;
|
| +
|
| + if (!control_p)
|
| + {
|
| + control = i386_dr_low_get_control ();
|
| + control_p = 1;
|
| + }
|
| +
|
| + /* This second condition makes sure DRi is set up for a data
|
| + watchpoint, not a hardware breakpoint. The reason is that
|
| + GDB doesn't call the target_stopped_data_address method
|
| + except for data watchpoints. In other words, I'm being
|
| + paranoiac. */
|
| + if (I386_DR_GET_RW_LEN (control, i) != 0)
|
| {
|
| addr = i386_dr_low_get_addr (i);
|
| rc = 1;
|
|
|