Move low-level Linux x86 debug register code to a shared file
authorGary Benson <gbenson@redhat.com>
Tue, 24 Mar 2015 14:05:45 +0000 (14:05 +0000)
committerGary Benson <gbenson@redhat.com>
Tue, 24 Mar 2015 14:05:45 +0000 (14:05 +0000)
This commit moves the now-identical low-level Linux x86 debug register
code from gdb/x86-linux-nat.c and gdb/gdbserver/linux-x86-low.c into a
new shared file gdb/nat/x86-linux-dregs.c.

gdb/ChangeLog:

* nat/x86-linux-dregs.h: New file.
* nat/x86-linux-dregs.c: Likewise.
* Makefile.in (HFILES_NO_SRCDIR): Add nat/x86-linux-dregs.h.
(x86-linux-dregs.o): New rule.
* config/i386/linux.mh (NATDEPFILES): Add x86-linux-dregs.o.
* config/i386/linux64.mh (NATDEPFILES): Likewise.
* x86-linux-nat.c: Include nat/x86-linux-dregs.h.
(u_debugreg_offset): Moved to nat/x86-linux-dregs.c.
(x86_linux_dr_get): Likewise.
(x86_linux_dr_set): Likewise.
(x86_linux_dr_get_addr): Likewise.
(x86_linux_dr_get_control): Likewise.
(x86_linux_dr_get_status): Likewise.
(update_debug_registers_callback): Likewise.
(x86_linux_dr_set_control): Likewise.
(x86_linux_dr_set_addr): Likewise.
(x86_linux_update_debug_registers): Likewise.

gdb/gdbserver/ChangeLog:

* Makefile.in (x86-linux-dregs.o): New rule.
* configure.srv: Add x86-linux-dregs.o to relevant targets.
* linux-x86-low.c: Include nat/x86-linux-dregs.h.
(u_debugreg_offset): Moved to nat/x86-linux-dregs.c.
(x86_linux_dr_get): Likewise.
(x86_linux_dr_set): Likewise.
(update_debug_registers_callback): Likewise.
(x86_linux_dr_set_addr): Likewise.
(x86_linux_dr_get_addr): Likewise.
(x86_linux_dr_set_control): Likewise.
(x86_linux_dr_get_control): Likewise.
(x86_linux_dr_get_status): Likewise.
(x86_linux_update_debug_registers): Likewise.

gdb/ChangeLog
gdb/Makefile.in
gdb/config/i386/linux.mh
gdb/config/i386/linux64.mh
gdb/gdbserver/ChangeLog
gdb/gdbserver/Makefile.in
gdb/gdbserver/configure.srv
gdb/gdbserver/linux-x86-low.c
gdb/nat/x86-linux-dregs.c [new file with mode: 0644]
gdb/nat/x86-linux-dregs.h [new file with mode: 0644]
gdb/x86-linux-nat.c

index a8ad8911afd348216d0b979491c0de0c4a0b1bb1..7dcec1fdbe25ca54c116d57e1851cff7372da131 100644 (file)
@@ -1,3 +1,23 @@
+2015-03-24  Gary Benson  <gbenson@redhat.com>
+
+       * nat/x86-linux-dregs.h: New file.
+       * nat/x86-linux-dregs.c: Likewise.
+       * Makefile.in (HFILES_NO_SRCDIR): Add nat/x86-linux-dregs.h.
+       (x86-linux-dregs.o): New rule.
+       * config/i386/linux.mh (NATDEPFILES): Add x86-linux-dregs.o.
+       * config/i386/linux64.mh (NATDEPFILES): Likewise.
+       * x86-linux-nat.c: Include nat/x86-linux-dregs.h.
+       (u_debugreg_offset): Moved to nat/x86-linux-dregs.c.
+       (x86_linux_dr_get): Likewise.
+       (x86_linux_dr_set): Likewise.
+       (x86_linux_dr_get_addr): Likewise.
+       (x86_linux_dr_get_control): Likewise.
+       (x86_linux_dr_get_status): Likewise.
+       (update_debug_registers_callback): Likewise.
+       (x86_linux_dr_set_control): Likewise.
+       (x86_linux_dr_set_addr): Likewise.
+       (x86_linux_update_debug_registers): Likewise.
+
 2015-03-24  Gary Benson  <gbenson@redhat.com>
 
        * x86-linux-nat.c (x86_linux_update_debug_registers):
index 6cc41ffd34f735a02223e289dfbf1a0f4de26919..ae50041053cc3a86d2a9abe741c58216a2775465 100644 (file)
@@ -968,7 +968,7 @@ i386-linux-nat.h common/common-defs.h common/errors.h common/common-types.h \
 common/common-debug.h common/cleanups.h common/gdb_setjmp.h \
 common/common-exceptions.h target/target.h common/symbol.h \
 common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
-common/common-remote-fileio.h nat/x86-linux.h
+common/common-remote-fileio.h nat/x86-linux.h nat/x86-linux-dregs.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -2303,6 +2303,10 @@ x86-linux.o: ${srcdir}/nat/x86-linux.c
        $(COMPILE) $(srcdir)/nat/x86-linux.c
        $(POSTCOMPILE)
 
+x86-linux-dregs.o: ${srcdir}/nat/x86-linux-dregs.c
+       $(COMPILE) $(srcdir)/nat/x86-linux-dregs.c
+       $(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
index ae19f9626540a4a69f7f05da4cecf312a6838aa6..9be2c5fc8a4b236b7ef08f79d0c66116686e151f 100644 (file)
@@ -5,7 +5,8 @@ NATDEPFILES= inf-ptrace.o fork-child.o \
        x86-nat.o x86-dregs.o i386-linux-nat.o x86-linux-nat.o \
        proc-service.o linux-thread-db.o \
        linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \
-       linux-btrace.o linux-waitpid.o linux-personality.o x86-linux.o
+       linux-btrace.o linux-waitpid.o linux-personality.o x86-linux.o \
+       x86-linux-dregs.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
 # The dynamically loaded libthread_db needs access to symbols in the
index 4a05f9116b42d585065d3a0564f0f692d95bded7..224a2a97e692787dd5cd2ad5b8c5829e3212d2fa 100644 (file)
@@ -5,7 +5,8 @@ NATDEPFILES= inf-ptrace.o fork-child.o \
        linux-nat.o linux-osdata.o \
        proc-service.o linux-thread-db.o linux-fork.o \
        linux-procfs.o linux-ptrace.o linux-btrace.o \
-       linux-waitpid.o linux-personality.o x86-linux.o
+       linux-waitpid.o linux-personality.o x86-linux.o \
+       x86-linux-dregs.o
 NAT_FILE= config/nm-linux.h
 NAT_CDEPS = $(srcdir)/proc-service.list
 
index f58010377ec5e225b319e45196a340efe6ac7313..8d1d84464dd6114aff8597b2d4e5e65feedb79e8 100644 (file)
@@ -1,3 +1,19 @@
+2015-03-24  Gary Benson  <gbenson@redhat.com>
+
+       * Makefile.in (x86-linux-dregs.o): New rule.
+       * configure.srv: Add x86-linux-dregs.o to relevant targets.
+       * linux-x86-low.c: Include nat/x86-linux-dregs.h.
+       (u_debugreg_offset): Moved to nat/x86-linux-dregs.c.
+       (x86_linux_dr_get): Likewise.
+       (x86_linux_dr_set): Likewise.
+       (update_debug_registers_callback): Likewise.
+       (x86_linux_dr_set_addr): Likewise.
+       (x86_linux_dr_get_addr): Likewise.
+       (x86_linux_dr_set_control): Likewise.
+       (x86_linux_dr_get_control): Likewise.
+       (x86_linux_dr_get_status): Likewise.
+       (x86_linux_update_debug_registers): Likewise.
+
 2015-03-24  Gary Benson  <gbenson@redhat.com>
 
        * linux-x86-low.c (x86_linux_update_debug_registers):
index 7b1e52c02a8e4e46c6ba84e0da4db50ff49a6cf2..9d698c6a23d4f5643f71473a9f08983196b1003a 100644 (file)
@@ -612,6 +612,9 @@ btrace-common.o: ../common/btrace-common.c
 x86-linux.o: ../nat/x86-linux.c
        $(COMPILE) $<
        $(POSTCOMPILE)
+x86-linux-dregs.o: ../nat/x86-linux-dregs.c
+       $(COMPILE) $<
+       $(POSTCOMPILE)
 
 aarch64.c : $(srcdir)/../regformats/aarch64.dat $(regdat_sh)
        $(SHELL) $(regdat_sh) $(srcdir)/../regformats/aarch64.dat aarch64.c
index fcb29ff7fb91da77b733063f71f03cc73aaafd79..81dd235db7e52911f880eaa993d0dcad89777210 100644 (file)
@@ -110,6 +110,7 @@ case "${target}" in
                        fi
                        srv_tgtobj="$srv_linux_obj linux-x86-low.o x86-low.o x86-dregs.o i387-fp.o"
                        srv_tgtobj="${srv_tgtobj} linux-btrace.o x86-linux.o"
+                       srv_tgtobj="${srv_tgtobj} x86-linux-dregs.o"
                        srv_linux_usrregs=yes
                        srv_linux_regsets=yes
                        srv_linux_thread_db=yes
@@ -326,6 +327,7 @@ case "${target}" in
   x86_64-*-linux*)     srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj"
                        srv_tgtobj="$srv_linux_obj linux-x86-low.o x86-low.o x86-dregs.o i387-fp.o"
                        srv_tgtobj="${srv_tgtobj} linux-btrace.o x86-linux.o"
+                       srv_tgtobj="${srv_tgtobj} x86-linux-dregs.o"
                        srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
                        srv_linux_usrregs=yes # This is for i386 progs.
                        srv_linux_regsets=yes
index e371873296e8bf9bb5c754e390eddf069c464d93..8a3b5a81ebed1103f63dbab969cfba1cae8c46f7 100644 (file)
@@ -39,6 +39,7 @@
 #include "ax.h"
 #include "nat/linux-nat.h"
 #include "nat/x86-linux.h"
+#include "nat/x86-linux-dregs.h"
 
 #ifdef __x86_64__
 /* Defined in auto-generated file amd64-linux.c.  */
@@ -524,125 +525,6 @@ x86_breakpoint_at (CORE_ADDR pc)
   return 0;
 }
 \f
-
-/* 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"));
-}
-
-/* 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 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);
-}
-
-/* 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);
-}
-
-/* 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);
-}
-
-/* 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);
-}
-
 /* Low-level function vector.  */
 struct x86_dr_low_type x86_dr_low =
   {
@@ -776,54 +658,6 @@ x86_debug_reg_state (pid_t pid)
   return &proc->priv->arch_private->debug_reg_state;
 }
 
-/* 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.  */
 
 static void
diff --git a/gdb/nat/x86-linux-dregs.c b/gdb/nat/x86-linux-dregs.c
new file mode 100644 (file)
index 0000000..9389803
--- /dev/null
@@ -0,0 +1,183 @@
+/* Low-level debug register code for GNU/Linux x86 (i386 and x86-64).
+
+   Copyright (C) 1999-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include <sys/ptrace.h>
+#include <sys/user.h>
+#include "target/waitstatus.h"
+#include "nat/x86-linux.h"
+#include "nat/x86-dregs.h"
+#include "nat/x86-linux-dregs.h"
+
+/* 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);
+}
+
+/* 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"));
+}
+
+/* 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;
+}
+
+/* See nat/x86-linux-dregs.h.  */
+
+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);
+}
+
+/* See nat/x86-linux-dregs.h.  */
+
+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);
+}
+
+/* See nat/x86-linux-dregs.h.  */
+
+unsigned long
+x86_linux_dr_get_control (void)
+{
+  return x86_linux_dr_get (current_lwp_ptid (), DR_CONTROL);
+}
+
+/* See nat/x86-linux-dregs.h.  */
+
+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);
+}
+
+/* See nat/x86-linux-dregs.h.  */
+
+unsigned long
+x86_linux_dr_get_status (void)
+{
+  return x86_linux_dr_get (current_lwp_ptid (), DR_STATUS);
+}
+
+/* See nat/x86-linux-dregs.h.  */
+
+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);
+}
diff --git a/gdb/nat/x86-linux-dregs.h b/gdb/nat/x86-linux-dregs.h
new file mode 100644 (file)
index 0000000..063e508
--- /dev/null
@@ -0,0 +1,53 @@
+/* Low-level debug register code for GNU/Linux x86 (i386 and x86-64).
+
+   Copyright (C) 1999-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef X86_LINUX_DREGS_H
+#define X86_LINUX_DREGS_H
+
+/* Return the address stored in the current inferior's debug register
+   REGNUM.  */
+
+extern CORE_ADDR x86_linux_dr_get_addr (int regnum);
+
+/* Store ADDR in debug register REGNUM of all LWPs of the current
+   inferior.  */
+
+extern void x86_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+
+/* Return the value stored in the current inferior's debug control
+   register.  */
+
+extern unsigned long x86_linux_dr_get_control (void);
+
+/* Store CONTROL in the debug control registers of all LWPs of the
+   current inferior.  */
+
+extern void x86_linux_dr_set_control (unsigned long control);
+
+/* Return the value stored in the current inferior's debug status
+   register.  */
+
+extern unsigned long x86_linux_dr_get_status (void);
+
+/* Update the thread's debug registers if the values in our local
+   mirror have been changed.  */
+
+extern void x86_linux_update_debug_registers (struct lwp_info *lwp);
+
+#endif /* X86_LINUX_DREGS_H */
index 9eb82c5cdee9220aaa51863699349890d654f1ee..84021fb9cfd3b55c4438c8f56b881daf9a517507 100644 (file)
@@ -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;
-\f
-
-/* 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.  */