* linux-x86-low.c (update_debug_registers_callback): New.
(i386_dr_low_set_addr): Use it.
(i386_dr_low_get_addr): New.
(i386_dr_low_set_control): Use update_debug_registers_callback.
(i386_dr_low_get_control): New.
(i386_dr_low_get_status): Adjust.
* linux-low.c (linux_stop_lwp): New.
* linux-low.h (linux_stop_lwp): Declare.
* i386-low.c (I386_DR_GET_RW_LEN): Take the dr7 contents as
argument instead of a i386_debug_reg_state.
(I386_DR_WATCH_HIT): Take the dr6 contents as argument instead of
a i386_debug_reg_state.
(i386_insert_aligned_watchpoint): Adjust.
(i386_remove_aligned_watchpoint): Adjust.
(i386_low_stopped_data_address): Read the debug registers from the
inferior instead of from the mirrors.
* i386-low.h (struct i386_debug_reg_state): Extend comment.
(i386_dr_low_get_addr): Declare.
(i386_dr_low_get_control): Declare.
(i386_dr_low_get_status): Change prototype.
* win32-i386-low.c (dr_status_mirror, dr_control_mirror): New globals.
(i386_dr_low_get_addr): New.
(i386_dr_low_get_control): New.
(i386_dr_low_get_status): Adjust prototype. Return
dr_status_mirror.
(i386_initial_stuff): Clear dr_status_mirror and
dr_control_mirror.
(i386_get_thread_context): Adjust.
(i386_set_thread_context): Adjust.
(i386_thread_added): Adjust.
+2010-08-25 Pedro Alves <pedro@codesourcery.com>
+
+ PR threads/10729
+
+ * linux-x86-low.c (update_debug_registers_callback): New.
+ (i386_dr_low_set_addr): Use it.
+ (i386_dr_low_get_addr): New.
+ (i386_dr_low_set_control): Use update_debug_registers_callback.
+ (i386_dr_low_get_control): New.
+ (i386_dr_low_get_status): Adjust.
+ * linux-low.c (linux_stop_lwp): New.
+ * linux-low.h (linux_stop_lwp): Declare.
+
+ * i386-low.c (I386_DR_GET_RW_LEN): Take the dr7 contents as
+ argument instead of a i386_debug_reg_state.
+ (I386_DR_WATCH_HIT): Take the dr6 contents as argument instead of
+ a i386_debug_reg_state.
+ (i386_insert_aligned_watchpoint): Adjust.
+ (i386_remove_aligned_watchpoint): Adjust.
+ (i386_low_stopped_data_address): Read the debug registers from the
+ inferior instead of from the mirrors.
+ * i386-low.h (struct i386_debug_reg_state): Extend comment.
+ (i386_dr_low_get_addr): Declare.
+ (i386_dr_low_get_control): Declare.
+ (i386_dr_low_get_status): Change prototype.
+
+ * win32-i386-low.c (dr_status_mirror, dr_control_mirror): New globals.
+ (i386_dr_low_get_addr): New.
+ (i386_dr_low_get_control): New.
+ (i386_dr_low_get_status): Adjust prototype. Return
+ dr_status_mirror.
+ (i386_initial_stuff): Clear dr_status_mirror and
+ dr_control_mirror.
+ (i386_get_thread_context): Adjust.
+ (i386_set_thread_context): Adjust.
+ (i386_thread_added): Adjust.
+
2010-08-24 Pedro Alves <pedro@codesourcery.com>
* linux-low.h (linux_thread_area): Delete declaration.
} while (0)
/* Get from DR7 the RW and LEN fields for the I'th debug register. */
-#define I386_DR_GET_RW_LEN(state, i) \
- (((state)->dr_control_mirror \
+#define I386_DR_GET_RW_LEN(dr7, i) \
+ (((dr7) \
>> (DR_CONTROL_SHIFT + DR_CONTROL_SIZE * (i))) & 0x0f)
/* Did the watchpoint whose address is in the I'th register break? */
-#define I386_DR_WATCH_HIT(state,i) ((state)->dr_status_mirror & (1 << (i)))
+#define I386_DR_WATCH_HIT(dr6, i) ((dr6) & (1 << (i)))
/* A macro to loop over all debug registers. */
#define ALL_DEBUG_REGISTERS(i) for (i = 0; i < DR_NADDR; i++)
{
if (!I386_DR_VACANT (state, i)
&& state->dr_mirror[i] == addr
- && I386_DR_GET_RW_LEN (state, i) == len_rw_bits)
+ && I386_DR_GET_RW_LEN (state->dr_control_mirror, i) == len_rw_bits)
{
state->dr_ref_count[i]++;
return 0;
{
if (!I386_DR_VACANT (state, i)
&& state->dr_mirror[i] == addr
- && I386_DR_GET_RW_LEN (state, i) == len_rw_bits)
+ && I386_DR_GET_RW_LEN (state->dr_control_mirror, i) == len_rw_bits)
{
if (--state->dr_ref_count[i] == 0) /* No longer in use? */
{
CORE_ADDR addr = 0;
int i;
int rc = 0;
+ unsigned status;
+ unsigned control;
- /* Get dr_status_mirror for use by I386_DR_WATCH_HIT. */
- i386_dr_low_get_status (state);
+ /* 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. */
+ status = i386_dr_low_get_status ();
+ control = i386_dr_low_get_control ();
ALL_DEBUG_REGISTERS (i)
{
- if (I386_DR_WATCH_HIT (state, 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 (state, i) != 0)
+ && I386_DR_GET_RW_LEN (control, i) != 0)
{
- addr = state->dr_mirror[i];
+ addr = i386_dr_low_get_addr (i);
rc = 1;
if (debug_hw_points)
i386_show_dr (state, "watchpoint_hit", addr, -1, hw_write);
struct i386_debug_reg_state
{
/* Mirror the inferior's DRi registers. We keep the status and
- control registers separated because they don't hold addresses. */
+ control registers separated because they don't hold addresses.
+ Note that since we can change these mirrors while threads are
+ running, we never trust them to explain a cause of a trap.
+ For that, we need to peek directly in the inferior registers. */
CORE_ADDR dr_mirror[DR_NADDR];
unsigned dr_status_mirror, dr_control_mirror;
extern void i386_dr_low_set_addr (const struct i386_debug_reg_state *state,
int regnum);
+/* Return the inferior's debug register REGNUM. */
+extern CORE_ADDR i386_dr_low_get_addr (int regnum);
+
/* Update the inferior's DR7 debug control register from STATE. */
extern void i386_dr_low_set_control (const struct i386_debug_reg_state *state);
-/* Get the value of the inferior's DR6 debug status register
- and record it in STATE. */
-extern void i386_dr_low_get_status (struct i386_debug_reg_state *state);
+/* Return the value of the inferior's DR7 debug control register. */
+extern unsigned i386_dr_low_get_control (void);
+
+/* Return the value of the inferior's DR6 debug status register. */
+extern unsigned i386_dr_low_get_status (void);
return kill (lwpid, signo);
}
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+ send_sigstop (lwp);
+}
+
static void
send_sigstop (struct lwp_info *lwp)
{
void linux_attach_lwp (unsigned long pid);
struct lwp_info *find_lwp_pid (ptid_t ptid);
+void linux_stop_lwp (struct lwp_info *lwp);
/* From thread-db.c */
int thread_db_init (int use_events);
error ("Couldn't write debug register");
}
+static int
+update_debug_registers_callback (struct inferior_list_entry *entry,
+ void *pid_p)
+{
+ struct lwp_info *lwp = (struct lwp_info *) entry;
+ int pid = *(int *) pid_p;
+
+ /* Only update the threads of this process. */
+ if (pid_of (lwp) == pid)
+ {
+ /* The actual update is done later just before resuming the lwp,
+ we just mark that the registers need updating. */
+ lwp->arch_private->debug_registers_changed = 1;
+
+ /* If the lwp isn't stopped, force it to momentarily pause, so
+ we can update its debug registers. */
+ if (!lwp->stopped)
+ linux_stop_lwp (lwp);
+ }
+
+ return 0;
+}
+
/* Update the inferior's debug register REGNUM from STATE. */
void
i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum)
{
- struct inferior_list_entry *lp;
- CORE_ADDR addr;
- /* Only need to update the threads of this process. */
+ /* Only update the threads of this process. */
int pid = pid_of (get_thread_lwp (current_inferior));
if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
fatal ("Invalid debug register %d", regnum);
- addr = state->dr_mirror[regnum];
+ find_inferior (&all_lwps, update_debug_registers_callback, &pid);
+}
- for (lp = all_lwps.head; lp; lp = lp->next)
- {
- struct lwp_info *lwp = (struct lwp_info *) lp;
+/* Return the inferior's debug register REGNUM. */
- /* The actual update is done later, we just mark that the register
- needs updating. */
- if (pid_of (lwp) == pid)
- lwp->arch_private->debug_registers_changed = 1;
- }
+CORE_ADDR
+i386_dr_low_get_addr (int regnum)
+{
+ struct lwp_info *lwp = get_thread_lwp (current_inferior);
+ ptid_t ptid = ptid_of (lwp);
+
+ /* DR6 and DR7 are retrieved with some other way. */
+ gdb_assert (DR_FIRSTADDR <= regnum && regnum < DR_LASTADDR);
+
+ return x86_linux_dr_get (ptid, regnum);
}
/* Update the inferior's DR7 debug control register from STATE. */
void
i386_dr_low_set_control (const struct i386_debug_reg_state *state)
{
- struct inferior_list_entry *lp;
- /* Only need to update the threads of this process. */
+ /* Only update the threads of this process. */
int pid = pid_of (get_thread_lwp (current_inferior));
- for (lp = all_lwps.head; lp; lp = lp->next)
- {
- struct lwp_info *lwp = (struct lwp_info *) lp;
+ find_inferior (&all_lwps, update_debug_registers_callback, &pid);
+}
- /* The actual update is done later, we just mark that the register
- needs updating. */
- if (pid_of (lwp) == pid)
- lwp->arch_private->debug_registers_changed = 1;
- }
+/* Return the inferior's DR7 debug control register. */
+
+unsigned
+i386_dr_low_get_control (void)
+{
+ struct lwp_info *lwp = get_thread_lwp (current_inferior);
+ ptid_t ptid = ptid_of (lwp);
+
+ return x86_linux_dr_get (ptid, DR_CONTROL);
}
/* Get the value of the DR6 debug status register from the inferior
and record it in STATE. */
-void
-i386_dr_low_get_status (struct i386_debug_reg_state *state)
+unsigned
+i386_dr_low_get_status (void)
{
struct lwp_info *lwp = get_thread_lwp (current_inferior);
ptid_t ptid = ptid_of (lwp);
- state->dr_status_mirror = x86_linux_dr_get (ptid, DR_STATUS);
+ return x86_linux_dr_get (ptid, DR_STATUS);
}
\f
/* Watchpoint support. */
#endif
static struct i386_debug_reg_state debug_reg_state;
+static unsigned dr_status_mirror;
+static unsigned dr_control_mirror;
static int debug_registers_changed = 0;
static int debug_registers_used = 0;
debug_registers_used = 1;
}
+CORE_ADDR
+i386_dr_low_get_addr (int regnum)
+{
+ gdb_assert (DR_FIRSTADDR <= regnum && regnum < DR_LASTADDR);
+
+ return debug_reg_state.dr_mirror[regnum];
+}
+
/* Update the inferior's DR7 debug control register from STATE. */
void
debug_registers_used = 1;
}
+unsigned
+i386_dr_low_get_control (void)
+{
+ return dr_control_mirror;
+}
+
/* Get the value of the DR6 debug status register from the inferior
and record it in STATE. */
-void
-i386_dr_low_get_status (struct i386_debug_reg_state *state)
+unsigned
+i386_dr_low_get_status (void)
{
/* We don't need to do anything here, the last call to thread_rec for
current_event.dwThreadId id has already set it. */
+ return dr_status_mirror;
}
/* Watchpoint support. */
i386_low_init_dregs (&debug_reg_state);
debug_registers_changed = 0;
debug_registers_used = 0;
+ dr_status_mirror = 0;
+ dr_control_mirror = 0;
}
static void
dr->dr_mirror[1] = th->context.Dr1;
dr->dr_mirror[2] = th->context.Dr2;
dr->dr_mirror[3] = th->context.Dr3;
- dr->dr_status_mirror = th->context.Dr6;
- dr->dr_control_mirror = th->context.Dr7;
+ dr_status_mirror = th->context.Dr6;
+ dr_control_mirror = th->context.Dr7;
}
}
th->context.Dr1 = dr->dr_mirror[1];
th->context.Dr2 = dr->dr_mirror[2];
th->context.Dr3 = dr->dr_mirror[3];
- /* th->context.Dr6 = dr->dr_status_mirror;
+ /* th->context.Dr6 = dr_status_mirror;
FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr->dr_control_mirror;
+ th->context.Dr7 = dr_control_mirror;
}
SetThreadContext (th->h, &th->context);
th->context.Dr1 = dr->dr_mirror[1];
th->context.Dr2 = dr->dr_mirror[2];
th->context.Dr3 = dr->dr_mirror[3];
- /* th->context.Dr6 = dr->dr_status_mirror;
+ /* th->context.Dr6 = dr_status_mirror;
FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr->dr_control_mirror;
+ th->context.Dr7 = dr_control_mirror;
SetThreadContext (th->h, &th->context);
th->context.ContextFlags = 0;