Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Unified Diff: gdb/gdbserver/i386-low.c

Issue 11969036: Merge GDB 7.5.1 (Closed) Base URL: http://git.chromium.org/native_client/nacl-gdb.git@master
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gdb/gdbserver/hostio.c ('k') | gdb/gdbserver/inferiors.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
« no previous file with comments | « gdb/gdbserver/hostio.c ('k') | gdb/gdbserver/inferiors.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698