[PATCH 13/14] Move low-level Linux x86 debug register code to a shared file
Gary Benson
gbenson@redhat.com
Mon Sep 8 15:46:00 GMT 2014
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.
(x86_linux_dr_get): Moved to nat/x86-linux-dregs.c.
(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.
(x86_linux_dr_get): Removed.
(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 | 19 +++++
gdb/Makefile.in | 7 ++-
gdb/config/i386/linux.mh | 2 +-
gdb/config/i386/linux64.mh | 2 +-
gdb/gdbserver/ChangeLog | 15 ++++
gdb/gdbserver/Makefile.in | 3 +
gdb/gdbserver/configure.srv | 2 +
gdb/gdbserver/linux-x86-low.c | 155 +------------------------------------
gdb/nat/x86-linux-dregs.c | 174 +++++++++++++++++++++++++++++++++++++++++
gdb/nat/x86-linux-dregs.h | 53 +++++++++++++
gdb/x86-linux-nat.c | 158 +-------------------------------------
11 files changed, 276 insertions(+), 314 deletions(-)
create mode 100644 gdb/nat/x86-linux-dregs.c
create mode 100644 gdb/nat/x86-linux-dregs.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index f2bbf6b..ac041fa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -940,7 +940,8 @@ common/print-utils.h common/rsp-low.h nat/x86-dregs.h x86-linux-nat.h \
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 target/symbol.h \
-common/common-regcache.h common/common-inferior.h nat/x86-linux.h
+common/common-regcache.h common/common-inferior.h nat/x86-linux.h \
+nat/x86-linux-dregs.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -2225,6 +2226,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
#
diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh
index f409bfe..804bb0b 100644
--- a/gdb/config/i386/linux.mh
+++ b/gdb/config/i386/linux.mh
@@ -5,7 +5,7 @@ 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 x86-linux.o
+ linux-btrace.o linux-waitpid.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
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
index 1d40167..384e393 100644
--- a/gdb/config/i386/linux64.mh
+++ b/gdb/config/i386/linux64.mh
@@ -5,7 +5,7 @@ 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 x86-linux.o
+ linux-waitpid.o x86-linux.o x86-linux-dregs.o
NAT_FILE= config/nm-linux.h
NAT_CDEPS = $(srcdir)/proc-service.list
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 03f4ae4..7f0e2f2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -586,6 +586,9 @@ mips-linux-watch.o: ../nat/mips-linux-watch.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
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 2c261dc..ebbd63d 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -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
@@ -317,6 +318,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
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 9bd4ae2..4a0a3cb 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -38,6 +38,7 @@
#include "tracepoint.h"
#include "ax.h"
#include "nat/x86-linux.h"
+#include "nat/x86-linux-dregs.h"
#ifdef __x86_64__
/* Defined in auto-generated file amd64-linux.c. */
@@ -522,113 +523,6 @@ x86_breakpoint_at (CORE_ADDR pc)
/* 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,
- offsetof (struct user, u_debugreg[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,
- offsetof (struct user, u_debugreg[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 (current_inferior_pid ());
-
- 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_inferior_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 (current_inferior_pid ());
-
- 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_inferior_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_inferior_ptid (), DR_STATUS);
-}
-
/* Low-level function vector. */
struct x86_dr_low_type x86_dr_low =
{
@@ -762,53 +656,6 @@ x86_debug_reg_state (pid_t pid)
return &proc->private->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_is_stopped_by_watchpoint (lwp))
- 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
index 0000000..9f742b2
--- /dev/null
+++ b/gdb/nat/x86-linux-dregs.c
@@ -0,0 +1,174 @@
+/* Low-level debug register code for x86 (i386 and x86-64).
+
+ Copyright (C) 1999-2014 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 "common-inferior.h"
+#include "nat/x86-linux.h"
+#include "nat/x86-dregs.h"
+#include "nat/x86-linux-dregs.h"
+
+/* 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,
+ offsetof (struct user, u_debugreg[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,
+ offsetof (struct user, u_debugreg[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_inferior_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 (current_inferior_pid ());
+
+ 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_inferior_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 (current_inferior_pid ());
+
+ 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_inferior_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_is_stopped_by_watchpoint (lwp))
+ 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
index 0000000..7d526b7
--- /dev/null
+++ b/gdb/nat/x86-linux-dregs.h
@@ -0,0 +1,53 @@
+/* Low-level debug register code for x86 (i386 and x86-64).
+
+ Copyright (C) 1999-2014 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 */
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index 5efaf9f..c524c31 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -38,166 +38,10 @@
#include "x86-xstate.h"
#include "nat/linux-btrace.h"
#include "nat/x86-linux.h"
+#include "nat/x86-linux-dregs.h"
/* Does the current host support PTRACE_GETREGSET? */
int have_ptrace_getregset = -1;
-
-
-/* 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,
- offsetof (struct user, u_debugreg[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,
- offsetof (struct user, u_debugreg[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_inferior_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_inferior_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_inferior_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 (current_inferior_pid ());
-
- 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 (current_inferior_pid ());
-
- 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_is_stopped_by_watchpoint (lwp))
- x86_linux_dr_set (ptid, DR_STATUS, 0);
-}
/* Called prior to resuming a thread. */
--
1.7.1
More information about the Gdb-patches
mailing list