diff options
Diffstat (limited to 'gdb/x86-linux-nat.c')
-rw-r--r-- | gdb/x86-linux-nat.c | 168 |
1 files changed, 1 insertions, 167 deletions
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c index 9eb82c5..84021fb 100644 --- a/gdb/x86-linux-nat.c +++ b/gdb/x86-linux-nat.c @@ -40,6 +40,7 @@ #include "nat/linux-btrace.h" #include "nat/linux-nat.h" #include "nat/x86-linux.h" +#include "nat/x86-linux-dregs.h" /* Per-thread arch-specific data we want to keep. */ @@ -51,173 +52,6 @@ struct arch_lwp_info /* Does the current host support PTRACE_GETREGSET? */ int have_ptrace_getregset = -1; - - -/* Return the offset of REGNUM in the u_debugreg field of struct - user. */ - -static int -u_debugreg_offset (int regnum) -{ - return (offsetof (struct user, u_debugreg) - + sizeof (((struct user *) 0)->u_debugreg[0]) * regnum); -} - -/* Support for debug registers. */ - -/* Get debug register REGNUM value from the LWP specified by PTID. */ - -static unsigned long -x86_linux_dr_get (ptid_t ptid, int regnum) -{ - int tid; - unsigned long value; - - gdb_assert (ptid_lwp_p (ptid)); - tid = ptid_get_lwp (ptid); - - errno = 0; - value = ptrace (PTRACE_PEEKUSER, tid, u_debugreg_offset (regnum), 0); - - if (errno != 0) - perror_with_name (_("Couldn't read debug register")); - - return value; -} - -/* Set debug register REGNUM to VALUE in the LWP specified by PTID. */ - -static void -x86_linux_dr_set (ptid_t ptid, int regnum, unsigned long value) -{ - int tid; - - gdb_assert (ptid_lwp_p (ptid)); - tid = ptid_get_lwp (ptid); - - errno = 0; - ptrace (PTRACE_POKEUSER, tid, u_debugreg_offset (regnum), value); - if (errno != 0) - perror_with_name (_("Couldn't write debug register")); -} - -/* Return the address stored in the current inferior's debug register - REGNUM. */ - -static CORE_ADDR -x86_linux_dr_get_addr (int regnum) -{ - gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); - - return x86_linux_dr_get (current_lwp_ptid (), regnum); -} - -/* Return the value stored in the current inferior's debug control - register. */ - -static unsigned long -x86_linux_dr_get_control (void) -{ - return x86_linux_dr_get (current_lwp_ptid (), DR_CONTROL); -} - -/* Return the value stored in the current inferior's debug status - register. */ - -static unsigned long -x86_linux_dr_get_status (void) -{ - return x86_linux_dr_get (current_lwp_ptid (), DR_STATUS); -} - -/* Callback for iterate_over_lwps. Mark that our local mirror of - LWP's debug registers has been changed, and cause LWP to stop if - it isn't already. Values are written from our local mirror to - the actual debug registers immediately prior to LWP resuming. */ - -static int -update_debug_registers_callback (struct lwp_info *lwp, void *arg) -{ - lwp_set_debug_registers_changed (lwp, 1); - - if (!lwp_is_stopped (lwp)) - linux_stop_lwp (lwp); - - /* Continue the iteration. */ - return 0; -} - -/* Store CONTROL in the debug control registers of all LWPs of the - current inferior. */ - -static void -x86_linux_dr_set_control (unsigned long control) -{ - ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (current_lwp_ptid ())); - - iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); -} - -/* Store ADDR in debug register REGNUM of all LWPs of the current - inferior. */ - -static void -x86_linux_dr_set_addr (int regnum, CORE_ADDR addr) -{ - ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (current_lwp_ptid ())); - - gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); - - iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL); -} - -/* Update the thread's debug registers if the values in our local - mirror have been changed. */ - -static void -x86_linux_update_debug_registers (struct lwp_info *lwp) -{ - ptid_t ptid = ptid_of_lwp (lwp); - int clear_status = 0; - - gdb_assert (lwp_is_stopped (lwp)); - - if (lwp_debug_registers_changed (lwp)) - { - struct x86_debug_reg_state *state - = x86_debug_reg_state (ptid_get_pid (ptid)); - int i; - - /* Prior to Linux kernel 2.6.33 commit - 72f674d203cd230426437cdcf7dd6f681dad8b0d, setting DR0-3 to - a value that did not match what was enabled in DR_CONTROL - resulted in EINVAL. To avoid this we zero DR_CONTROL before - writing address registers, only writing DR_CONTROL's actual - value once all the addresses are in place. */ - x86_linux_dr_set (ptid, DR_CONTROL, 0); - - ALL_DEBUG_ADDRESS_REGISTERS (i) - if (state->dr_ref_count[i] > 0) - { - x86_linux_dr_set (ptid, i, state->dr_mirror[i]); - - /* If we're setting a watchpoint, any change the inferior - has made to its debug registers needs to be discarded - to avoid x86_stopped_data_address getting confused. */ - clear_status = 1; - } - - /* If DR_CONTROL is supposed to be zero then it's already set. */ - if (state->dr_control_mirror != 0) - x86_linux_dr_set (ptid, DR_CONTROL, state->dr_control_mirror); - - lwp_set_debug_registers_changed (lwp, 0); - } - - if (clear_status - || lwp_stop_reason (lwp) == TARGET_STOPPED_BY_WATCHPOINT) - x86_linux_dr_set (ptid, DR_STATUS, 0); -} /* Called prior to resuming a thread. */ |