diff options
author | Mark Kettenis <kettenis@gnu.org> | 2001-03-21 21:22:49 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@gnu.org> | 2001-03-21 21:22:49 +0000 |
commit | 84346e11ea3d9a98216ce8eded615888d80b7cad (patch) | |
tree | c252c44be205f1f02a7f4cbeedf4ac7a2f23992b | |
parent | 13b57657099c839e1508400a4a73b222d4da2c25 (diff) | |
download | gdb-84346e11ea3d9a98216ce8eded615888d80b7cad.zip gdb-84346e11ea3d9a98216ce8eded615888d80b7cad.tar.gz gdb-84346e11ea3d9a98216ce8eded615888d80b7cad.tar.bz2 |
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.
-rw-r--r-- | gdb/ChangeLog | 30 | ||||
-rw-r--r-- | gdb/config/i386/linux.mh | 2 | ||||
-rw-r--r-- | gdb/config/i386/nm-linux.h | 60 | ||||
-rw-r--r-- | gdb/i386-linux-nat.c | 107 |
4 files changed, 168 insertions, 31 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2d6aa24..d0e3133 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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 diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh index 9b329be..ee8ecea 100644 --- a/gdb/config/i386/linux.mh +++ b/gdb/config/i386/linux.mh @@ -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 diff --git a/gdb/config/i386/nm-linux.h b/gdb/config/i386/nm-linux.h index 97800b6..15b373e 100644 --- a/gdb/config/i386/nm-linux.h +++ b/gdb/config/i386/nm-linux.h @@ -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. @@ -23,52 +23,56 @@ #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). */ diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 62fe3d4..aac9289 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -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> @@ -31,6 +32,26 @@ #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 = ; +/* 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)); +} + + /* 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) } +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); +} + + /* Interpreting register set info found in core files. */ /* Provide registers to GDB from a core file. |