diff options
author | Pedro Alves <palves@redhat.com> | 2011-12-14 17:20:32 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2011-12-14 17:20:32 +0000 |
commit | 7b50312ad68f7c3acac2b318f6ff96956ad381ea (patch) | |
tree | 8334359a21c6cfe3384baa3bb625a28db9ace8c7 /gdb/i386-linux-nat.c | |
parent | 0d13c96b214428affc33281d6d119a873c45acee (diff) | |
download | gdb-7b50312ad68f7c3acac2b318f6ff96956ad381ea.zip gdb-7b50312ad68f7c3acac2b318f6ff96956ad381ea.tar.gz gdb-7b50312ad68f7c3acac2b318f6ff96956ad381ea.tar.bz2 |
gdb/
2011-12-14 Pedro Alves <pedro@codesourcery.com>
PR threads/10729
* linux-nat.c (linux_nat_new_thread): Change parameter to an lwp
pointer.
(linux_nat_prepare_to_resume): New global.
(lwp_free): New.
(purge_lwp_list): Use it.
(add_lwp): Call linux_nat_new_thread even on the first LWP.
Adjust to interface change.
(delete_lwp): Call lwp_free instead of xfree.
(detach_callback, linux_nat_detach, resume_lwp, linux_nat_resume)
(linux_handle_syscall_trap, linux_handle_extended_wait)
(linux_nat_filter_event, resume_stopped_resumed_lwps): Call
linux_nat_prepare_to_resume before resuming.
(linux_stop_lwp): New.
(linux_nat_set_new_thread): Adjust.
(linux_nat_set_prepare_to_resume): New.
* linux-nat.h (struct arch_lwp_info): Forward declare.
(struct lwp_info) <arch_private>: New field.
(linux_stop_lwp): Declare.
(linux_nat_set_new_thread): Adjust.
(linux_nat_set_prepare_to_resume): New.
* i386-nat.c (DR_NADDR, DR_STATUS, DR_CONTROL)
(struct i386_debug_reg_state): Move to i386-nat.h.
(dr_mirror): Comment.
(i386_debug_reg_state): New.
(i386_update_inferior_debug_regs): Simplify.
(i386_stopped_data_address): Use the debug register state from the
inferior, not from the local cache.
* i386-nat.h (struct i386_dr_low_type): Delete reset_addr and
unset_status fields. New get_addr and get_control fields.
(DR_FIRSTADDR, DR_LASTADDR, DR_CONTROL): Moved from i386-nat.c.
(DR_NADDR, DR_STATUS): New.
(struct i386_debug_reg_state): Moved from i386-nat.c.
* amd64-linux-nat.c (struct arch_lwp_info): New.
(amd64_linux_dr): Delete global.
(amd64_linux_dr_get_addr): New.
(amd64_linux_dr_get_control): New.
(amd64_linux_dr_unset_status): Delete.
(amd64_linux_dr_set_addr): Reimplement.
(amd64_linux_dr_reset_addr): Delete.
(update_debug_registers_callback): New.
(amd64_linux_dr_set_control): Reimplement.
(amd64_linux_dr_set_addr): Reimplement.
(amd64_linux_prepare_to_resume): New.
(amd64_linux_new_thread): Change parameter to an lwp pointer.
Reimplement.
(_initialize_amd64_linux_nat): No longer install
i386_dr_low.reset_addr and i386_dr_low.unset_status. Install
amd64_linux_dr_get_control as i386_dr_low.get_control. Install
amd64_linux_dr_get_addr as i386_dr_low.get_addr. Install
amd64_linux_prepare_to_resume.
* i386-linux-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
(DR_CONTROL): Delete.
(struct arch_lwp_info): New.
(i386_linux_dr): Delete global.
(i386_linux_dr_set_control): Reimplement.
(i386_linux_dr_get_addr): New.
(i386_linux_dr_set_addr): Reimplement.
(i386_linux_dr_get_control): New.
(update_debug_registers_callback): New.
(i386_linux_dr_unset_status): Delete.
(i386_linux_dr_set_addr): Reimplement.
(i386_linux_prepare_to_resume): New.
(i386_linux_new_thread): Change parameter to an lwp pointer.
Reimplement.
(_initialize_i386_linux_nat): No longer install
i386_dr_low.reset_addr and i386_dr_low.unset_status. Install
i386_linux_dr_get_control as i386_dr_low.get_control. Install
i386_linux_dr_get_addr as i386_dr_low.get_addr. Install
i386_linux_prepare_to_resume.
* arm-linux-nat.c (arm_linux_new_thread): Change parameter to an
lwp pointer. Adjust.
* ia64-linux-nat.c (ia64_linux_new_thread): Likewise.
* mips-linux-nat.c (mips_linux_new_thread): Likewise.
* ppc-linux-nat.c (ppc_linux_new_thread): Likewise.
* s390-nat.c (s390_fix_watch_points): Likewise.
* i386-darwin-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
(DR_CONTROL): Delete.
(i386_darwin_dr_reset_addr): Delete.
(i386_darwin_dr_get_addr): New.
(i386_darwin_dr_get_control): New.
* go32-nat.c
(go32_get_dr7, go32_get_dr): New.
(init_go32_ops): No longer install i386_dr_low.reset_addr.
Install go32_get_dr7 as i386_dr_low.get_control. Install
go32_get_dr as i386_dr_low.get_addr.
* i386bsd-nat.c (i386bsd_dr_get): New.
(i386bsd_dr_reset_addr): Delete.
(i386bsd_dr_get_addr): New.
(i386bsd_dr_get_status): Use i386bsd_dr_get.
(i386bsd_dr_get_control): New.
* i386bsd-nat.h (i386bsd_dr_reset_addr): Delete.
(i386bsd_dr_get_addr): New.
(i386bsd_dr_get_control): New.
* i386fbsd-nat.c (_initialize_i386fbsd_nat): No longer install
i386_dr_low.reset_addr and i386_dr_low.unset_status. Install
i386bsd_dr_get_control as i386_dr_low.get_control. Install
i386bsd_dr_get_addr as i386_dr_low.get_addr.
* windows-nat.c (init_windows_ops): No longer install
i386_dr_low.reset_addr and i386_dr_low.unset_status. Install
cygwin_get_dr7 as i386_dr_low.get_control. Install cygwin_get_dr
as i386_dr_low.get_addr.
(cygwin_get_dr): New.
(cygwin_get_dr7): New.
gdb/testsuite/
2011-12-14 Pedro Alves <pedro@codesourcery.com>
PR threads/10729
* gdb.mi/watch-nonstop.c: New file.
* gdb.mi/mi-watch-nonstop.exp: New file.
Diffstat (limited to 'gdb/i386-linux-nat.c')
-rw-r--r-- | gdb/i386-linux-nat.c | 143 |
1 files changed, 88 insertions, 55 deletions
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 7eb49ae..190979b 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -47,22 +47,6 @@ #include <sys/debugreg.h> #endif -#ifndef DR_FIRSTADDR -#define DR_FIRSTADDR 0 -#endif - -#ifndef DR_LASTADDR -#define DR_LASTADDR 3 -#endif - -#ifndef DR_STATUS -#define DR_STATUS 6 -#endif - -#ifndef DR_CONTROL -#define DR_CONTROL 7 -#endif - /* Prototypes for supply_gregset etc. */ #include "gregset.h" @@ -83,6 +67,14 @@ #define PTRACE_SETREGSET 0x4205 #endif +/* Per-thread arch-specific data we want to keep. */ + +struct arch_lwp_info +{ + /* Non-zero if our copy differs from what's recorded in the thread. */ + int debug_registers_changed; +}; + /* Does the current host support PTRACE_GETREGSET? */ static int have_ptrace_getregset = -1; @@ -651,8 +643,6 @@ i386_linux_store_inferior_registers (struct target_ops *ops, /* Support for debug registers. */ -static unsigned long i386_linux_dr[DR_CONTROL + 1]; - /* Get debug register REGNUM value from only the one LWP of PTID. */ static unsigned long @@ -692,74 +682,116 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) perror_with_name (_("Couldn't write debug register")); } -/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST. */ +/* Return the inferior's debug register REGNUM. */ -static void -i386_linux_dr_set_control (unsigned long control) +static CORE_ADDR +i386_linux_dr_get_addr (int regnum) { - struct lwp_info *lp; + /* DR6 and DR7 are retrieved with some other way. */ + gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); - i386_linux_dr[DR_CONTROL] = control; - ALL_LWPS (lp) - i386_linux_dr_set (lp->ptid, DR_CONTROL, control); + return i386_linux_dr_get (inferior_ptid, regnum); } -/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST. */ +/* Return the inferior's DR7 debug control register. */ -static void -i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) +static unsigned long +i386_linux_dr_get_control (void) { - struct lwp_info *lp; + return i386_linux_dr_get (inferior_ptid, DR_CONTROL); +} - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); +/* Get DR_STATUS from only the one LWP of INFERIOR_PTID. */ - i386_linux_dr[DR_FIRSTADDR + regnum] = addr; - ALL_LWPS (lp) - i386_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr); +static unsigned long +i386_linux_dr_get_status (void) +{ + return i386_linux_dr_get (inferior_ptid, DR_STATUS); } -/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST. */ +/* Callback for iterate_over_lwps. Update the debug registers of + LWP. */ + +static int +update_debug_registers_callback (struct lwp_info *lwp, void *arg) +{ + /* 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; +} + +/* Set DR_CONTROL to ADDR in all LWPs of the current inferior. */ static void -i386_linux_dr_reset_addr (int regnum) +i386_linux_dr_set_control (unsigned long control) { - i386_linux_dr_set_addr (regnum, 0); + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); } -/* Get DR_STATUS from only the one LWP of INFERIOR_PTID. */ +/* Set address REGNUM (zero based) to ADDR in all LWPs of the current + inferior. */ -static unsigned long -i386_linux_dr_get_status (void) +static void +i386_linux_dr_set_addr (int regnum, CORE_ADDR addr) { - return i386_linux_dr_get (inferior_ptid, DR_STATUS); + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid)); + + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); } -/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST. */ +/* Called when resuming a thread. + If the debug regs have changed, update the thread's copies. */ static void -i386_linux_dr_unset_status (unsigned long mask) +i386_linux_prepare_to_resume (struct lwp_info *lwp) { - struct lwp_info *lp; + int clear_status = 0; - ALL_LWPS (lp) + if (lwp->arch_private->debug_registers_changed) { - unsigned long value; + struct i386_debug_reg_state *state = i386_debug_reg_state (); + int i; + + for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) + if (state->dr_ref_count[i] > 0) + { + i386_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]); + + /* If we're setting a watchpoint, any change the inferior + had done itself to the debug registers needs to be + discarded, otherwise, i386_stopped_data_address can get + confused. */ + clear_status = 1; + } - value = i386_linux_dr_get (lp->ptid, DR_STATUS); - value &= ~mask; - i386_linux_dr_set (lp->ptid, DR_STATUS, value); + i386_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror); + + lwp->arch_private->debug_registers_changed = 0; } + + if (clear_status || lwp->stopped_by_watchpoint) + i386_linux_dr_set (lwp->ptid, DR_STATUS, 0); } static void -i386_linux_new_thread (ptid_t ptid) +i386_linux_new_thread (struct lwp_info *lp) { - int i; + struct arch_lwp_info *info = XCNEW (struct arch_lwp_info); - for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++) - i386_linux_dr_set (ptid, i, i386_linux_dr[i]); + info->debug_registers_changed = 1; - i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]); + lp->arch_private = info; } @@ -978,9 +1010,9 @@ _initialize_i386_linux_nat (void) i386_dr_low.set_control = i386_linux_dr_set_control; i386_dr_low.set_addr = i386_linux_dr_set_addr; - i386_dr_low.reset_addr = i386_linux_dr_reset_addr; + i386_dr_low.get_addr = i386_linux_dr_get_addr; i386_dr_low.get_status = i386_linux_dr_get_status; - i386_dr_low.unset_status = i386_linux_dr_unset_status; + i386_dr_low.get_control = i386_linux_dr_get_control; i386_set_debug_register_length (4); /* Override the default ptrace resume method. */ @@ -999,4 +1031,5 @@ _initialize_i386_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); linux_nat_set_new_thread (t, i386_linux_new_thread); + linux_nat_set_prepare_to_resume (t, i386_linux_prepare_to_resume); } |