Make Linux use the new unified support for hardware breakpoints
authorMark Kettenis <kettenis@gnu.org>
Wed, 21 Mar 2001 21:22:49 +0000 (21:22 +0000)
committerMark Kettenis <kettenis@gnu.org>
Wed, 21 Mar 2001 21:22:49 +0000 (21:22 +0000)
and watchpoints on x86 targets.
* i386-linux-nat.c: Doc fixes.  Include "gdb_assert.h".
[HAVE_SYS_DEBUGREG_H]: Include <sys/debugreg.h>.
(DR_FIRSTADDR, DR_LASTADDR, DR_STATUS, DR_CONTROL): Define to
appropriate value if not already defined.
(register_u_addr): New function.
(kernel_u_size): New function.
(i386_linux_dr_get, i386_linux_dr_set): New functions.
(i386_linux_dr_set_control, i386_linux_dr_set_addr,
i386_linux_reset_addr, i386_linux_dr_get_status): New functions.
* config/i386/nm-linux.h: Don't include "nm-i386v.h".
(I386_USE_GENERIC_WATCHPOINTS): Define and include "nm-i386.h".
(TARGET_HAS_HARDWARE_WATCHPOINTS,
TARGET_CAN_USE_HARDWARE_WATCHPOINTS, HAVE_CONTINUABLE_WATCHPOINT,
STOPPED_BY_WATCHPOINT, target_insert_watchpoint,
target_remove_watchpoint): Remove macros.
(i386_stopped_by_watchpoint, i386_insert_watchpoint,
i386_remove_watchpoint): Remove prototypes.
(register_u_addr): New prototype.
(REGISTER_U_ADDR): Define in terms of register_u_addr.
(i386_linux_dr_set_control, i386_linux_dr_set_addr,
i386_linux_reset_addr, i386_linux_dr_get_status): New prototypes.
(I386_DR_LOW_SET_CONTROL, I386_DR_LOW_SET_ADDR,
I386_DR_LOW_RESET_ADDR, I386_DR_LOW_GET_STATUS): New macros.
* config/i386/linux.mh (NATDEPFILES): Replace i386v-nat.o with
i386-nat.o.

gdb/ChangeLog
gdb/config/i386/linux.mh
gdb/config/i386/nm-linux.h
gdb/i386-linux-nat.c

index 2d6aa24ba57753523be7a42e428aba22a111ca75..d0e3133ca98107bc27f8a2fedcac0d09d36f92f1 100644 (file)
@@ -1,3 +1,33 @@
+2001-03-21  Mark Kettenis  <kettenis@gnu.org>
+
+       Make Linux use the new unified support for hardware breakpoints
+       and watchpoints on x86 targets.
+       * i386-linux-nat.c: Doc fixes.  Include "gdb_assert.h".
+       [HAVE_SYS_DEBUGREG_H]: Include <sys/debugreg.h>.
+       (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS, DR_CONTROL): Define to
+       appropriate value if not already defined.
+       (register_u_addr): New function.
+       (kernel_u_size): New function.
+       (i386_linux_dr_get, i386_linux_dr_set): New functions.
+       (i386_linux_dr_set_control, i386_linux_dr_set_addr,
+       i386_linux_reset_addr, i386_linux_dr_get_status): New functions.
+       * config/i386/nm-linux.h: Don't include "nm-i386v.h".
+       (I386_USE_GENERIC_WATCHPOINTS): Define and include "nm-i386.h".
+       (TARGET_HAS_HARDWARE_WATCHPOINTS,
+       TARGET_CAN_USE_HARDWARE_WATCHPOINTS, HAVE_CONTINUABLE_WATCHPOINT,
+       STOPPED_BY_WATCHPOINT, target_insert_watchpoint,
+       target_remove_watchpoint): Remove macros.
+       (i386_stopped_by_watchpoint, i386_insert_watchpoint,
+       i386_remove_watchpoint): Remove prototypes.
+       (register_u_addr): New prototype.
+       (REGISTER_U_ADDR): Define in terms of register_u_addr.
+       (i386_linux_dr_set_control, i386_linux_dr_set_addr,
+       i386_linux_reset_addr, i386_linux_dr_get_status): New prototypes.
+       (I386_DR_LOW_SET_CONTROL, I386_DR_LOW_SET_ADDR,
+       I386_DR_LOW_RESET_ADDR, I386_DR_LOW_GET_STATUS): New macros.
+       * config/i386/linux.mh (NATDEPFILES): Replace i386v-nat.o with
+       i386-nat.o.
+
 2001-03-21  Jim Blandy  <jimb@redhat.com>
 
        * linespec.c (find_methods): Whitespace differences aren't
index 9b329be767a9582dca7e9cb37b4ca96de78a6e5b..ee8ecea1f0d10ea350edb6c5615b2be49ee776e7 100644 (file)
@@ -5,7 +5,7 @@ XDEPFILES=
 
 NAT_FILE= nm-linux.h
 NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o \
-       core-aout.o i386v-nat.o i386-linux-nat.o i387-nat.o \
+       core-aout.o i386-nat.o i386-linux-nat.o i387-nat.o \
        proc-service.o thread-db.o lin-lwp.o
 
 LOADLIBES = -ldl -rdynamic
index 97800b6ed48c55fb8c2b44b29232fc9ecb14dafb..15b373e228d687bda06aa09f4bcd966cef3ee7bd 100644 (file)
@@ -1,6 +1,6 @@
 /* Native support for Linux/x86.
    Copyright 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000
+   1999, 2000, 2001
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #ifndef NM_LINUX_H
 #define NM_LINUX_H
 
-#include "i386/nm-i386v.h"
+/* GNU/Linux supports the i386 hardware debugging registers.  */
+#define I386_USE_GENERIC_WATCHPOINTS
+
+#include "i386/nm-i386.h"
 #include "nm-linux.h"
 
-/* Return sizeof user struct to callers in less machine dependent routines */
+/* Return sizeof user struct to callers in less machine dependent
+   routines.  */
 
-#define KERNEL_U_SIZE kernel_u_size()
 extern int kernel_u_size (void);
+#define KERNEL_U_SIZE kernel_u_size()
 
 #define U_REGS_OFFSET 0
 
-/* GNU/Linux supports the 386 hardware debugging registers.  */
+extern CORE_ADDR register_u_addr (CORE_ADDR blockend, int regnum);
+#define REGISTER_U_ADDR(addr, blockend, regnum) \
+  (addr) = register_u_addr (blockend, regnum)
 
-#define TARGET_HAS_HARDWARE_WATCHPOINTS
+/* Provide access to the i386 hardware debugging registers.  */
 
-#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
+extern void i386_linux_dr_set_control (long control);
+#define I386_DR_LOW_SET_CONTROL(control) \
+  i386_linux_dr_set_control (control)
 
-/* After a watchpoint trap, the PC points to the instruction after
-   the one that caused the trap.  Therefore we don't need to step over it.
-   But we do need to reset the status register to avoid another trap.  */
-#define HAVE_CONTINUABLE_WATCHPOINT
+extern void i386_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+#define I386_DR_LOW_SET_ADDR(regnum, addr) \
+  i386_linux_dr_set_addr (regnum, addr)
 
-#define STOPPED_BY_WATCHPOINT(W)  \
-  i386_stopped_by_watchpoint (inferior_pid)
+extern void i386_linux_dr_reset_addr (int regnum);
+#define I386_DR_LOW_RESET_ADDR(regnum) \
+  i386_linux_dr_reset_addr (regnum)
 
-/* Use these macros for watchpoint insertion/removal.  */
+extern long i386_linux_dr_get_status (void);
+#define I386_DR_LOW_GET_STATUS() \
+  i386_linux_dr_get_status ()
 
-#define target_insert_watchpoint(addr, len, type)  \
-  i386_insert_watchpoint (inferior_pid, addr, len, type)
-
-#define target_remove_watchpoint(addr, len, type)  \
-  i386_remove_watchpoint (inferior_pid, addr, len)
-
-/* We define this if link.h is available, because with ELF we use SVR4 style
-   shared libraries. */
+/* We define this if link.h is available, because with ELF we use SVR4
+   style shared libraries.  */
 
 #ifdef HAVE_LINK_H
 #define SVR4_SHARED_LIBS
-#include "solib.h"             /* Support for shared libraries. */
+#include "solib.h"             /* Support for shared libraries.  */
 #endif
 
 /* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
 #define FETCH_INFERIOR_REGISTERS
 
-/* Nevertheless, define CANNOT_{FETCH,STORE}_REGISTER, because we might fall
-   back on the code `infptrace.c' (well a copy of that code in
-   `i386-linux-nat.c' for now) and we can access only the
+/* Nevertheless, define CANNOT_{FETCH,STORE}_REGISTER, because we
+   might fall back on the code `infptrace.c' (well a copy of that code
+   in `i386-linux-nat.c' for now) and we can access only the
    general-purpose registers in that way.  */
 extern int cannot_fetch_register (int regno);
 extern int cannot_store_register (int regno);
@@ -78,10 +82,6 @@ extern int cannot_store_register (int regno);
 /* Override child_resume in `infptrace.c'.  */
 #define CHILD_RESUME
 
-extern CORE_ADDR i386_stopped_by_watchpoint (int);
-extern int i386_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw);
-extern int i386_remove_watchpoint (int pid, CORE_ADDR addr, int len);
-
 /* FIXME: kettenis/2000-09-03: This should be moved to ../nm-linux.h
    once we have converted all Linux targets to use the new threads
    stuff (without the #undef of course).  */
index 62fe3d4191b1aa4b98c5e7ff9414b614d3c712df..aac928963431d28d312ffa6b82e624f877e35ee8 100644 (file)
@@ -23,6 +23,7 @@
 #include "gdbcore.h"
 #include "regcache.h"
 
+#include "gdb_assert.h"
 #include <sys/ptrace.h>
 #include <sys/user.h>
 #include <sys/procfs.h>
 #include <sys/reg.h>
 #endif
 
+#ifdef HAVE_SYS_DEBUGREG_H
+#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"
 
@@ -110,6 +131,26 @@ int have_ptrace_getfpxregs =
 ;
 \f
 
+/* Support for the user struct.  */
+
+/* Return the address of register REGNUM.  BLOCKEND is the value of
+   u.u_ar0, which should point to the registers.  */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
+{
+  return (blockend + 4 * regmap[regnum]);
+}
+
+/* Return the size of the user struct.  */
+
+int
+kernel_u_size (void)
+{
+  return (sizeof (struct user));
+}
+\f
+
 /* Fetching registers directly from the U area, one at a time.  */
 
 /* FIXME: kettenis/2000-03-05: This duplicates code from `inptrace.c'.
@@ -660,6 +701,72 @@ store_inferior_registers (int regno)
 }
 \f
 
+static long
+i386_linux_dr_get (int regnum)
+{
+  int tid;
+  long value;
+
+  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
+     multi-threaded processes here.  For now, pretend there is just
+     one thread.  */
+  tid = PIDGET (inferior_pid);
+
+  errno = 0;
+  value = ptrace (PT_READ_U, tid,
+                 offsetof (struct user, u_debugreg[regnum]), 0);
+  if (errno != 0)
+    perror_with_name ("Couldn't read debug register");
+
+  return value;
+}
+
+static void
+i386_linux_dr_set (int regnum, long value)
+{
+  int tid;
+
+  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
+     multi-threaded processes here.  For now, pretend there is just
+     one thread.  */
+  tid = PIDGET (inferior_pid);
+
+  errno = 0;
+  ptrace (PT_WRITE_U, tid,
+         offsetof (struct user, u_debugreg[regnum]), value);
+  if (errno != 0)
+    perror_with_name ("Couldn't write debug register");
+}
+
+void
+i386_linux_dr_set_control (long control)
+{
+  i386_linux_dr_set (DR_CONTROL, control);
+}
+
+void
+i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+{
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  i386_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+}
+
+void
+i386_linux_dr_reset_addr (int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
+}
+
+long
+i386_linux_dr_get_status (void)
+{
+  return i386_linux_dr_get (DR_STATUS);
+}
+\f
+
 /* Interpreting register set info found in core files.  */
 
 /* Provide registers to GDB from a core file.