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.
This commit is contained in:
Mark Kettenis 2001-03-21 21:22:49 +00:00
parent 13b5765709
commit 84346e11ea
4 changed files with 168 additions and 31 deletions

View 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

View 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

View 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.
@ -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). */

View 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>
@ -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.