aboutsummaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorJoerg Wunsch <joerg@FreeBSD.org>2000-08-17 16:27:26 +0000
committerJoerg Wunsch <joerg@FreeBSD.org>2000-08-17 16:27:26 +0000
commit22c68d23f579474a2ce8ed1909c672e2ca36f876 (patch)
tree6b3680edf13e2938d094757153fd34666ade3c50 /gnu
parent8ba8e2ef62e2b9a6edfc1583dc569fe388f3672d (diff)
Notes
Diffstat (limited to 'gnu')
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c223
-rw-r--r--gnu/usr.bin/binutils/gdb/i386/nm.h33
2 files changed, 256 insertions, 0 deletions
diff --git a/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c
index 8dd81d16d1b66..75824d3ee2286 100644
--- a/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c
+++ b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c
@@ -428,3 +428,226 @@ _initialize_core_aout ()
{
add_core_fns (&aout_core_fns);
}
+
+#ifdef PT_GETDBREGS
+
+/*
+ * 0: no trace output
+ * 1: trace watchpoint requests
+ * 2: trace `watchpoint hit?' tests, too
+ */
+#define WATCHPOINT_DEBUG 0
+
+#include "breakpoint.h"
+
+int
+can_watch(type, cnt, ot)
+ int type, cnt, ot;
+{
+ int rv;
+ static int cnt_watch, cnt_awatch;
+
+ switch (type)
+ {
+ case bp_hardware_watchpoint:
+ cnt_watch = cnt;
+ break;
+
+ case bp_access_watchpoint:
+ cnt_awatch = cnt;
+ break;
+
+ default:
+ rv = 0;
+ goto overandout;
+ }
+
+ rv = cnt_watch + cnt_awatch <= 4? 1: -1;
+
+ overandout:
+#if WATCHPOINT_DEBUG
+ printf_filtered("can_watch(%d, %d, %d) = %d (counts: w: %d, rw: %d)\n",
+ type, cnt, ot, rv, cnt_watch, cnt_awatch);
+#endif
+
+ return rv;
+}
+
+int
+stopped_by_watchpoint()
+{
+ struct dbreg dbr;
+ extern int inferior_pid;
+
+ if (inferior_pid != 0 && core_bfd == NULL)
+ {
+ int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
+
+ if (ptrace(PT_GETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
+ {
+ perror("ptrace(PT_GETDBREGS) failed");
+ return 0;
+ }
+#if WATCHPOINT_DEBUG > 1
+ printf_filtered("stopped_by_watchpoint(): DR6 = %#x\n", dbr.dr6);
+#endif
+ /*
+ * If a hardware watchpoint was hit, one of the lower 4 bits in
+ * DR6 is set (the actual bit indicates which of DR0...DR3 triggered
+ * the trap).
+ */
+ return dbr.dr6 & 0x0f;
+ }
+ else
+ {
+ warning("Can't set a watchpoint on a core file.");
+ return 0;
+ }
+}
+
+int
+insert_watchpoint(addr, len, type)
+ int addr, len, type;
+{
+ struct dbreg dbr;
+ extern int inferior_pid;
+
+ if (inferior_pid != 0 && core_bfd == NULL)
+ {
+ int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
+ int i, mask;
+ unsigned int sbits;
+
+ if (ptrace(PT_GETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
+ {
+ perror("ptrace(PT_GETDBREGS) failed");
+ return 0;
+ }
+
+ for (i = 0, mask = 0x03; i < 4; i++, mask <<= 2)
+ if ((dbr.dr7 & mask) == 0)
+ break;
+ if (i >= 4) {
+ warning("no more hardware watchpoints available");
+ return -1;
+ }
+
+ /* paranoia */
+ if (len > 4)
+ {
+ warning("watchpoint length %d unsupported, using lenght = 4",
+ len);
+ len = 4;
+ }
+ else if (len == 3)
+ {
+ warning("weird watchpoint length 3, using 2");
+ len = 2;
+ }
+ else if (len == 0)
+ {
+ warning("weird watchpoint length 0, using 1");
+ len = 1;
+ }
+
+ switch (len)
+ {
+ case 1: sbits = 0; break;
+ case 2: sbits = 4; break;
+ case 4: sbits = 0x0c; break;
+ }
+
+ /*
+ * The `type' value is 0 for `watch on write', 1 for `watch on
+ * read', 2 for `watch on both'. The i386 debug register
+ * breakpoint types are 0 for `execute' (not used in GDB), 1 for
+ * `write', and 4 for `read/write'. Plain `read' trapping is
+ * not supported on i386, value 3 is illegal.
+ */
+ switch (type)
+ {
+ default:
+ warning("weird watchpoint type %d, using a write watchpoint");
+ /* FALLTHROUGH */
+ case 0:
+ sbits |= 1;
+ break;
+
+ case 2:
+ sbits |= 3;
+ break;
+ }
+ sbits <<= 4 * i + 16;
+ sbits |= 1 << 2 * i;
+
+ dbr.dr7 |= sbits;
+ *(&dbr.dr0 + i) = (unsigned int)addr;
+
+#if WATCHPOINT_DEBUG
+ printf_filtered("insert_watchpoint(), inserting DR7 = %#x, DR%d = %#x\n",
+ dbr.dr7, i, addr);
+#endif
+ if (ptrace(PT_SETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
+ {
+ perror("ptrace(PT_SETDBREGS) failed");
+ return 0;
+ }
+ }
+ else
+ {
+ warning("Can't set a watchpoint on a core file.");
+ return 0;
+ }
+}
+
+int
+remove_watchpoint(addr, len, type)
+ int addr, len, type;
+{
+ struct dbreg dbr;
+ extern int inferior_pid;
+
+ if (inferior_pid != 0 && core_bfd == NULL)
+ {
+ int pid = inferior_pid & ((1 << 17) - 1); /* XXX extract pid from tid */
+ int i;
+ unsigned int sbits, *dbregp;
+
+ if (ptrace(PT_GETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
+ {
+ perror("ptrace(PT_GETDBREGS) failed");
+ return 0;
+ }
+
+ for (i = 0, dbregp = &dbr.dr0; i < 4; i++, dbregp++)
+ if (*dbregp == (unsigned int)addr)
+ break;
+ if (i >= 4)
+ {
+ warning("watchpoint for address %#x not found", addr);
+ return -1;
+ }
+
+ *dbregp = 0;
+ sbits = 0xf << (4 * i + 16);
+ sbits |= 3 << 2 * i;
+ dbr.dr7 &= ~sbits;
+
+#if WATCHPOINT_DEBUG
+ printf_filtered("remove_watchpoint(): removing watchpoint for %#x, DR7 = %#x\n",
+ addr, dbr.dr7);
+#endif
+ if (ptrace(PT_SETDBREGS, pid, (caddr_t)&dbr, 0) == -1)
+ {
+ perror("ptrace(PT_SETDBREGS) failed");
+ return 0;
+ }
+ }
+ else
+ {
+ warning("Can't set a watchpoint on a core file.");
+ return 0;
+ }
+}
+
+#endif /* PT_GETDBREGS */
diff --git a/gnu/usr.bin/binutils/gdb/i386/nm.h b/gnu/usr.bin/binutils/gdb/i386/nm.h
index 786abc94b6488..65f872b83ea17 100644
--- a/gnu/usr.bin/binutils/gdb/i386/nm.h
+++ b/gnu/usr.bin/binutils/gdb/i386/nm.h
@@ -1,3 +1,4 @@
+/* $FreeBSD$ */
/* Native-dependent definitions for Intel 386 running BSD Unix, for GDB.
Copyright 1986, 1987, 1989, 1992, 1996 Free Software Foundation, Inc.
@@ -132,4 +133,36 @@ extern int kernel_writablecore;
if (!strcmp(STR, "kgdb")) \
kernel_debugging = 1;
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#ifdef PT_GETDBREGS
+#define TARGET_HAS_HARDWARE_WATCHPOINTS
+
+extern int can_watch PARAMS((int type, int cnt, int othertype));
+extern int stopped_by_watchpoint PARAMS((void));
+extern int insert_watchpoint PARAMS((int addr, int len, int type));
+extern int remove_watchpoint PARAMS((int addr, int len, int type));
+
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) \
+ can_watch(type, cnt, ot)
+
+/* 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
+
+#define STOPPED_BY_WATCHPOINT(W) \
+ stopped_by_watchpoint()
+
+/* Use these macros for watchpoint insertion/removal. */
+
+#define target_insert_watchpoint(addr, len, type) \
+ insert_watchpoint(addr, len, type)
+
+#define target_remove_watchpoint(addr, len, type) \
+ remove_watchpoint(addr, len, type)
+
+#endif /* PT_GETDBREGS */
+
#endif /* NM_FREEBSD_H */