Module Name: src
Committed By: kamil
Date: Thu Dec 15 12:04:18 UTC 2016
Modified Files:
src/distrib/sets/lists/comp: md.amd64 md.i386
src/sys/arch/amd64/amd64: machdep.c netbsd32_machdep.c
process_machdep.c trap.c
src/sys/arch/amd64/conf: files.amd64
src/sys/arch/amd64/include: proc.h ptrace.h userret.h
src/sys/arch/i386/conf: files.i386
src/sys/arch/i386/i386: machdep.c process_machdep.c
src/sys/arch/i386/include: proc.h ptrace.h userret.h
src/sys/arch/x86/include: Makefile dbregs.h
src/sys/arch/x86/x86: vm_machdep.c
src/sys/arch/xen/conf: files.xen
src/sys/compat/netbsd32: netbsd32_ptrace.c
src/sys/kern: sys_ptrace.c sys_ptrace_common.c
src/sys/sys: ptrace.h
Added Files:
src/sys/arch/x86/x86: dbregs.c
Log Message:
Add support for hardware assisted watchpoints/breakpoints API in ptrace(2)
Add new ptrace(2) calls:
- PT_COUNT_WATCHPOINTS - count the number of available hardware watchpoints
- PT_READ_WATCHPOINT - read struct ptrace_watchpoint from the kernel state
- PT_WRITE_WATCHPOINT - write new struct ptrace_watchpoint state, this
includes enabling and disabling watchpoints
The ptrace_watchpoint structure contains MI and MD parts:
typedef struct ptrace_watchpoint {
int pw_index; /* HW Watchpoint ID (count from 0) */
lwpid_t pw_lwpid; /* LWP described */
struct mdpw pw_md; /* MD fields */
} ptrace_watchpoint_t;
For example amd64 defines MD as follows:
struct mdpw {
void *md_address;
int md_condition;
int md_length;
};
These calls are protected with the __HAVE_PTRACE_WATCHPOINTS guard.
Tested on amd64, initial support added for i386 and XEN.
Sponsored by <The NetBSD Foundation>
To generate a diff of this commit:
cvs rdiff -u -r1.239 -r1.240 src/distrib/sets/lists/comp/md.amd64
cvs rdiff -u -r1.159 -r1.160 src/distrib/sets/lists/comp/md.i386
cvs rdiff -u -r1.237 -r1.238 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.97 -r1.98 src/sys/arch/amd64/amd64/netbsd32_machdep.c
cvs rdiff -u -r1.29 -r1.30 src/sys/arch/amd64/amd64/process_machdep.c
cvs rdiff -u -r1.87 -r1.88 src/sys/arch/amd64/amd64/trap.c
cvs rdiff -u -r1.87 -r1.88 src/sys/arch/amd64/conf/files.amd64
cvs rdiff -u -r1.19 -r1.20 src/sys/arch/amd64/include/proc.h
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/amd64/include/ptrace.h
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/amd64/include/userret.h
cvs rdiff -u -r1.375 -r1.376 src/sys/arch/i386/conf/files.i386
cvs rdiff -u -r1.766 -r1.767 src/sys/arch/i386/i386/machdep.c
cvs rdiff -u -r1.86 -r1.87 src/sys/arch/i386/i386/process_machdep.c
cvs rdiff -u -r1.42 -r1.43 src/sys/arch/i386/include/proc.h
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/i386/include/ptrace.h
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/i386/include/userret.h
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/x86/include/Makefile
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/include/dbregs.h
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/dbregs.c
cvs rdiff -u -r1.26 -r1.27 src/sys/arch/x86/x86/vm_machdep.c
cvs rdiff -u -r1.142 -r1.143 src/sys/arch/xen/conf/files.xen
cvs rdiff -u -r1.2 -r1.3 src/sys/compat/netbsd32/netbsd32_ptrace.c
cvs rdiff -u -r1.2 -r1.3 src/sys/kern/sys_ptrace.c
cvs rdiff -u -r1.6 -r1.7 src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.49 -r1.50 src/sys/sys/ptrace.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/distrib/sets/lists/comp/md.amd64
diff -u src/distrib/sets/lists/comp/md.amd64:1.239 src/distrib/sets/lists/comp/md.amd64:1.240
--- src/distrib/sets/lists/comp/md.amd64:1.239 Wed Dec 14 12:59:51 2016
+++ src/distrib/sets/lists/comp/md.amd64 Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-# $NetBSD: md.amd64,v 1.239 2016/12/14 12:59:51 kre Exp $
+# $NetBSD: md.amd64,v 1.240 2016/12/15 12:04:18 kamil Exp $
./usr/include/amd64 comp-c-include
./usr/include/amd64/ansi.h comp-c-include
@@ -496,6 +496,7 @@
./usr/include/x86/cpu_ucode.h comp-c-include
./usr/include/x86/cputypes.h comp-c-include
./usr/include/x86/cpuvar.h comp-c-include
+./usr/include/x86/dbregs.h comp-c-include
./usr/include/x86/float.h comp-c-include
./usr/include/x86/fpu.h comp-c-include
./usr/include/x86/ieee.h comp-c-include
Index: src/distrib/sets/lists/comp/md.i386
diff -u src/distrib/sets/lists/comp/md.i386:1.159 src/distrib/sets/lists/comp/md.i386:1.160
--- src/distrib/sets/lists/comp/md.i386:1.159 Sat Oct 15 11:34:30 2016
+++ src/distrib/sets/lists/comp/md.i386 Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-# $NetBSD: md.i386,v 1.159 2016/10/15 11:34:30 christos Exp $
+# $NetBSD: md.i386,v 1.160 2016/12/15 12:04:18 kamil Exp $
./usr/include/clang-3.4/__wmmintrin_aes.h comp-obsolete obsolete
./usr/include/clang-3.4/__wmmintrin_pclmul.h comp-obsolete obsolete
./usr/include/clang-3.4/ammintrin.h comp-obsolete obsolete
@@ -370,6 +370,7 @@
./usr/include/x86/cpu_ucode.h comp-c-include
./usr/include/x86/cputypes.h comp-c-include
./usr/include/x86/cpuvar.h comp-c-include
+./usr/include/x86/dbregs.h comp-c-include
./usr/include/x86/float.h comp-c-include
./usr/include/x86/fpu.h comp-c-include
./usr/include/x86/ieee.h comp-c-include
Index: src/sys/arch/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.237 src/sys/arch/amd64/amd64/machdep.c:1.238
--- src/sys/arch/amd64/amd64/machdep.c:1.237 Mon Dec 12 02:51:24 2016
+++ src/sys/arch/amd64/amd64/machdep.c Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.237 2016/12/12 02:51:24 pgoyette Exp $ */
+/* $NetBSD: machdep.c,v 1.238 2016/12/15 12:04:17 kamil Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -111,7 +111,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.237 2016/12/12 02:51:24 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.238 2016/12/15 12:04:17 kamil Exp $");
/* #define XENDEBUG_LOW */
@@ -482,6 +482,7 @@ x86_64_proc0_tss_ldt_init(void)
pmap_kernel()->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL);
pcb->pcb_cr0 = rcr0() & ~CR0_TS;
l->l_md.md_regs = (struct trapframe *)pcb->pcb_rsp0 - 1;
+ memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
#if !defined(XEN)
lldt(pmap_kernel()->pm_ldt_sel);
@@ -1316,6 +1317,8 @@ setregs(struct lwp *l, struct exec_packa
l->l_proc->p_flag &= ~PK_32;
+ memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+
tf = l->l_md.md_regs;
tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c
diff -u src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.97 src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.98
--- src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.97 Wed Oct 19 09:44:00 2016
+++ src/sys/arch/amd64/amd64/netbsd32_machdep.c Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_machdep.c,v 1.97 2016/10/19 09:44:00 skrll Exp $ */
+/* $NetBSD: netbsd32_machdep.c,v 1.98 2016/12/15 12:04:17 kamil Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.97 2016/10/19 09:44:00 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.98 2016/12/15 12:04:17 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@@ -129,6 +129,8 @@ netbsd32_setregs(struct lwp *l, struct e
p->p_flag |= PK_32;
+ memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+
tf = l->l_md.md_regs;
tf->tf_ds = LSEL(LUDATA32_SEL, SEL_UPL);
tf->tf_es = LSEL(LUDATA32_SEL, SEL_UPL);
Index: src/sys/arch/amd64/amd64/process_machdep.c
diff -u src/sys/arch/amd64/amd64/process_machdep.c:1.29 src/sys/arch/amd64/amd64/process_machdep.c:1.30
--- src/sys/arch/amd64/amd64/process_machdep.c:1.29 Sat Feb 15 22:20:41 2014
+++ src/sys/arch/amd64/amd64/process_machdep.c Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.29 2014/02/15 22:20:41 dsl Exp $ */
+/* $NetBSD: process_machdep.c,v 1.30 2016/12/15 12:04:17 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -49,11 +49,21 @@
*
* process_set_pc(proc)
* Set the process's program counter.
+ *
+ * process_count_watchpoints(proc, retval)
+ * Return the number of supported hardware watchpoints.
+ *
+ * process_read_watchpoint(proc, watchpoint)
+ * Read hardware watchpoint of the given index.
+ *
+ * process_write_watchpoint(proc, watchpoint)
+ * Write hardware watchpoint of the given index.
+ *
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.29 2014/02/15 22:20:41 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.30 2016/12/15 12:04:17 kamil Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -66,6 +76,7 @@ __KERNEL_RCSID(0, "$NetBSD: process_mach
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/segments.h>
+#include <x86/dbregs.h>
#include <x86/fpu.h>
static inline struct trapframe *process_frame(struct lwp *);
@@ -157,3 +168,81 @@ process_set_pc(struct lwp *l, void *addr
return (0);
}
+
+int
+process_count_watchpoints(struct lwp *l, register_t *retval)
+{
+
+ *retval = X86_HW_WATCHPOINTS;
+
+ return (0);
+}
+
+int
+process_read_watchpoint(struct lwp *l, struct ptrace_watchpoint *pw)
+{
+
+ pw->pw_md.md_address =
+ (void*)(intptr_t)l->l_md.md_watchpoint[pw->pw_index].address;
+ pw->pw_md.md_condition = l->l_md.md_watchpoint[pw->pw_index].condition;
+ pw->pw_md.md_length = l->l_md.md_watchpoint[pw->pw_index].length;
+
+ return (0);
+}
+
+static void
+update_mdl_x86_hw_watchpoints(struct lwp *l)
+{
+ size_t i;
+
+ for (i = 0; i < X86_HW_WATCHPOINTS; i++) {
+ if (l->l_md.md_watchpoint[0].address != 0) {
+ return;
+ }
+ }
+ l->l_md.md_flags &= ~MDL_X86_HW_WATCHPOINTS;
+}
+
+int
+process_write_watchpoint(struct lwp *l, struct ptrace_watchpoint *pw)
+{
+
+ if (pw->pw_index > X86_HW_WATCHPOINTS)
+ return (EINVAL);
+
+ if (pw->pw_md.md_address == 0) {
+ l->l_md.md_watchpoint[pw->pw_index].address = 0;
+ update_mdl_x86_hw_watchpoints(l);
+ return (0);
+ }
+
+ if ((vaddr_t)pw->pw_md.md_address > VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+
+ switch (pw->pw_md.md_condition) {
+ case X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION:
+ case X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE:
+ case X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ switch (pw->pw_md.md_length) {
+ case X86_HW_WATCHPOINT_DR7_LENGTH_BYTE:
+ case X86_HW_WATCHPOINT_DR7_LENGTH_TWOBYTES:
+ case X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ l->l_md.md_watchpoint[pw->pw_index].address =
+ (vaddr_t)pw->pw_md.md_address;
+ l->l_md.md_watchpoint[pw->pw_index].condition = pw->pw_md.md_condition;
+ l->l_md.md_watchpoint[pw->pw_index].length = pw->pw_md.md_length;
+
+ l->l_md.md_flags |= MDL_X86_HW_WATCHPOINTS;
+
+ return (0);
+}
Index: src/sys/arch/amd64/amd64/trap.c
diff -u src/sys/arch/amd64/amd64/trap.c:1.87 src/sys/arch/amd64/amd64/trap.c:1.88
--- src/sys/arch/amd64/amd64/trap.c:1.87 Wed Oct 26 22:02:14 2016
+++ src/sys/arch/amd64/amd64/trap.c Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.87 2016/10/26 22:02:14 christos Exp $ */
+/* $NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.87 2016/10/26 22:02:14 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.88 2016/12/15 12:04:17 kamil Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -673,6 +673,19 @@ faultcommon:
}
case T_TRCTRAP:
+ /*
+ * Ignore debug register trace traps due to
+ * accesses in the user's address space, which
+ * can happen under several conditions such as
+ * if a user sets a watchpoint on a buffer and
+ * then passes that buffer to a system call.
+ * We still want to get TRCTRAPS for addresses
+ * in kernel space because that is useful when
+ * debugging the kernel.
+ */
+ if (user_trap_x86_hw_watchpoint())
+ break;
+
/* Check whether they single-stepped into a lcall. */
if (frame->tf_rip == (uint64_t)IDTVEC(oosyscall) ||
frame->tf_rip == (uint64_t)IDTVEC(osyscall) ||
Index: src/sys/arch/amd64/conf/files.amd64
diff -u src/sys/arch/amd64/conf/files.amd64:1.87 src/sys/arch/amd64/conf/files.amd64:1.88
--- src/sys/arch/amd64/conf/files.amd64:1.87 Sun Sep 6 07:17:14 2015
+++ src/sys/arch/amd64/conf/files.amd64 Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-# $NetBSD: files.amd64,v 1.87 2015/09/06 07:17:14 uebayasi Exp $
+# $NetBSD: files.amd64,v 1.88 2016/12/15 12:04:17 kamil Exp $
#
# new style config file for amd64 architecture
#
@@ -49,6 +49,7 @@ file arch/amd64/amd64/machdep.c machdep
file arch/amd64/amd64/process_machdep.c machdep
file arch/amd64/amd64/trap.c machdep
file arch/x86/x86/fpu.c machdep
+file arch/x86/x86/dbregs.c machdep
file arch/x86/x86/convert_xmm_s87.c machdep
file arch/amd64/amd64/lock_stubs.S machdep
file dev/cons.c machdep
Index: src/sys/arch/amd64/include/proc.h
diff -u src/sys/arch/amd64/include/proc.h:1.19 src/sys/arch/amd64/include/proc.h:1.20
--- src/sys/arch/amd64/include/proc.h:1.19 Thu Feb 20 18:19:10 2014
+++ src/sys/arch/amd64/include/proc.h Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.19 2014/02/20 18:19:10 dsl Exp $ */
+/* $NetBSD: proc.h,v 1.20 2016/12/15 12:04:17 kamil Exp $ */
/*
* Copyright (c) 1991 Regents of the University of California.
@@ -38,6 +38,7 @@
#include <machine/frame.h>
#include <machine/pcb.h>
+#include <x86/dbregs.h>
/*
* Machine-dependent part of the lwp structure for amd64.
@@ -51,10 +52,12 @@ struct mdlwp {
struct vm_page *md_gc_ptp; /* pages from pmap g/c */
int md_flags; /* machine-dependent flags */
volatile int md_astpending;
+ struct x86_hw_watchpoint md_watchpoint[X86_HW_WATCHPOINTS];
};
-#define MDL_COMPAT32 0x0008 /* i386, always return via iret */
-#define MDL_IRET 0x0010 /* force return via iret, not sysret */
+#define MDL_COMPAT32 0x0008 /* i386, always return via iret */
+#define MDL_IRET 0x0010 /* force return via iret, not sysret */
+#define MDL_X86_HW_WATCHPOINTS 0x0020 /* has hardware watchpoints */
struct mdproc {
int md_flags;
Index: src/sys/arch/amd64/include/ptrace.h
diff -u src/sys/arch/amd64/include/ptrace.h:1.7 src/sys/arch/amd64/include/ptrace.h:1.8
--- src/sys/arch/amd64/include/ptrace.h:1.7 Wed Oct 19 09:44:00 2016
+++ src/sys/arch/amd64/include/ptrace.h Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.7 2016/10/19 09:44:00 skrll Exp $ */
+/* $NetBSD: ptrace.h,v 1.8 2016/12/15 12:04:17 kamil Exp $ */
/*
* Copyright (c) 1993 Christopher G. Demetriou
@@ -36,18 +36,24 @@
/*
* i386-dependent ptrace definitions
*/
-#define PT_STEP (PT_FIRSTMACH + 0)
-#define PT_GETREGS (PT_FIRSTMACH + 1)
-#define PT_SETREGS (PT_FIRSTMACH + 2)
-#define PT_GETFPREGS (PT_FIRSTMACH + 3)
-#define PT_SETFPREGS (PT_FIRSTMACH + 4)
+#define PT_STEP (PT_FIRSTMACH + 0)
+#define PT_GETREGS (PT_FIRSTMACH + 1)
+#define PT_SETREGS (PT_FIRSTMACH + 2)
+#define PT_GETFPREGS (PT_FIRSTMACH + 3)
+#define PT_SETFPREGS (PT_FIRSTMACH + 4)
+#define PT_READ_WATCHPOINT (PT_FIRSTMACH + 5)
+#define PT_WRITE_WATCHPOINT (PT_FIRSTMACH + 6)
+#define PT_COUNT_WATCHPOINTS (PT_FIRSTMACH + 7)
#define PT_MACHDEP_STRINGS \
"PT_STEP", \
"PT_GETREGS", \
"PT_SETREGS", \
"PT_GETFPREGS", \
- "PT_SETFPREGS",
+ "PT_SETFPREGS", \
+ "PT_READ_WATCHPOINT", \
+ "PT_WRITE_WATCHPOINT", \
+ "PT_COUNT_WATCHPOINTS"
#include <machine/reg.h>
#define PTRACE_REG_PC(r) (r)->regs[_REG_RIP]
@@ -59,6 +65,34 @@
#define PTRACE_BREAKPOINT_SIZE 1
#define PTRACE_BREAKPOINT_ADJ 1
+#define __HAVE_PTRACE_WATCHPOINTS
+
+/*
+ * This MD structure translates into x86_hw_watchpoint
+ *
+ * pw_address - 0 represents disabled hardware watchpoint
+ *
+ * conditions:
+ * 0b00 - execution
+ * 0b01 - data write
+ * 0b10 - io read/write (not implemented)
+ * 0b11 - data read/write
+ *
+ * length:
+ * 0b00 - 1 byte
+ * 0b01 - 2 bytes
+ * 0b10 - undefined (8 bytes in modern CPUs - not implemented)
+ * 0b11 - 4 bytes
+ *
+ * Helper symbols for conditions and length are available in <x86/dbregs.h>
+ *
+ */
+struct mdpw {
+ void *md_address;
+ int md_condition;
+ int md_length;
+};
+
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd32.h"
@@ -71,8 +105,13 @@
#define process_write_regs32 netbsd32_process_write_regs
#define process_write_fpregs32 netbsd32_process_write_fpregs
+#define process_write_watchpoint32 netbsd32_process_write_watchpoint
+#define process_read_watchpoint32 netbsd32_process_read_watchpoint
+#define process_count_watchpoint32 netbsd32_process_count_watchpoint
+
#define process_reg32 struct reg32
#define process_fpreg32 struct fpreg32
+#define process_watchpoint32 struct ptrace_watchpoint32
#endif /* COMPAT_NETBSD32 */
#endif /* _KERNEL_OPT */
Index: src/sys/arch/amd64/include/userret.h
diff -u src/sys/arch/amd64/include/userret.h:1.9 src/sys/arch/amd64/include/userret.h:1.10
--- src/sys/arch/amd64/include/userret.h:1.9 Mon Apr 28 20:23:12 2008
+++ src/sys/arch/amd64/include/userret.h Thu Dec 15 12:04:17 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: userret.h,v 1.9 2008/04/28 20:23:12 martin Exp $ */
+/* $NetBSD: userret.h,v 1.10 2016/12/15 12:04:17 kamil Exp $ */
/*
* XXXfvdl same as i386 counterpart, but should probably be independent.
@@ -67,6 +67,7 @@
*/
#include <sys/userret.h>
+#include <x86/dbregs.h>
static __inline void userret(struct lwp *);
@@ -80,4 +81,15 @@ userret(struct lwp *l)
/* Invoke MI userret code */
mi_userret(l);
+
+ /*
+ * Never mix debug registers with single step, while technically
+ * possible on x86 CPUs, it adds unnecessary complications we do
+ * not want to handle it.
+ */
+ if ((l->l_md.md_regs->tf_rflags & PSL_T) == 0 &&
+ l->l_md.md_flags & MDL_X86_HW_WATCHPOINTS)
+ set_x86_hw_watchpoints(l);
+ else
+ clear_x86_hw_watchpoints();
}
Index: src/sys/arch/i386/conf/files.i386
diff -u src/sys/arch/i386/conf/files.i386:1.375 src/sys/arch/i386/conf/files.i386:1.376
--- src/sys/arch/i386/conf/files.i386:1.375 Tue Dec 13 10:54:27 2016
+++ src/sys/arch/i386/conf/files.i386 Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-# $NetBSD: files.i386,v 1.375 2016/12/13 10:54:27 kamil Exp $
+# $NetBSD: files.i386,v 1.376 2016/12/15 12:04:18 kamil Exp $
#
# new style config file for i386 architecture
#
@@ -79,6 +79,7 @@ file arch/x86/x86/convert_xmm_s87.c
file arch/i386/i386/trap.c
file dev/cons.c
file arch/x86/x86/fpu.c
+file arch/x86/x86/dbregs.c
file arch/i386/i386/mptramp.S multiprocessor
Index: src/sys/arch/i386/i386/machdep.c
diff -u src/sys/arch/i386/i386/machdep.c:1.766 src/sys/arch/i386/i386/machdep.c:1.767
--- src/sys/arch/i386/i386/machdep.c:1.766 Sun Dec 11 22:38:50 2016
+++ src/sys/arch/i386/i386/machdep.c Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.766 2016/12/11 22:38:50 martin Exp $ */
+/* $NetBSD: machdep.c,v 1.767 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008, 2009
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.766 2016/12/11 22:38:50 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.767 2016/12/15 12:04:18 kamil Exp $");
#include "opt_beep.h"
#include "opt_compat_ibcs2.h"
@@ -513,6 +513,7 @@ i386_proc0_tss_ldt_init(void)
l->l_md.md_regs = (struct trapframe *)pcb->pcb_esp0 - 1;
memcpy(&pcb->pcb_fsd, &gdt[GUDATA_SEL], sizeof(pcb->pcb_fsd));
memcpy(&pcb->pcb_gsd, &gdt[GUDATA_SEL], sizeof(pcb->pcb_gsd));
+ memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
#ifndef XEN
lldt(pmap_kernel()->pm_ldt_sel);
@@ -846,6 +847,8 @@ setregs(struct lwp *l, struct exec_packa
memcpy(&pcb->pcb_fsd, &gdt[GUDATA_SEL], sizeof(pcb->pcb_fsd));
memcpy(&pcb->pcb_gsd, &gdt[GUDATA_SEL], sizeof(pcb->pcb_gsd));
+ memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+
tf = l->l_md.md_regs;
tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
tf->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
Index: src/sys/arch/i386/i386/process_machdep.c
diff -u src/sys/arch/i386/i386/process_machdep.c:1.86 src/sys/arch/i386/i386/process_machdep.c:1.87
--- src/sys/arch/i386/i386/process_machdep.c:1.86 Wed Nov 2 00:11:59 2016
+++ src/sys/arch/i386/i386/process_machdep.c Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.86 2016/11/02 00:11:59 pgoyette Exp $ */
+/* $NetBSD: process_machdep.c,v 1.87 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -49,10 +49,20 @@
*
* process_set_pc(proc)
* Set the process's program counter.
+ *
+ * process_count_watchpoints(proc, retval)
+ * Return the number of supported hardware watchpoints.
+ *
+ * process_read_watchpoint(proc, watchpoint)
+ * Read hardware watchpoint of the given index.
+ *
+ * process_write_watchpoint(proc, watchpoint)
+ * Write hardware watchpoint of the given index.
+ *
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.86 2016/11/02 00:11:59 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.87 2016/12/15 12:04:18 kamil Exp $");
#include "opt_vm86.h"
#include "opt_ptrace.h"
@@ -71,6 +81,7 @@ __KERNEL_RCSID(0, "$NetBSD: process_mach
#include <machine/reg.h>
#include <machine/segments.h>
+#include <x86/dbregs.h>
#include <x86/fpu.h>
#ifdef VM86
@@ -337,3 +348,81 @@ process_machdep_validxmmregs(struct proc
}
#endif /* __HAVE_PTRACE_MACHDEP */
#endif /* PTRACE_HOOKS */
+
+int
+process_count_watchpoints(struct lwp *l, register_t *retval)
+{
+
+ *retval = X86_HW_WATCHPOINTS;
+
+ return (0);
+}
+
+int
+process_read_watchpoint(struct lwp *l, struct ptrace_watchpoint *pw)
+{
+
+ pw->pw_md.md_address =
+ (void*)(intptr_t)l->l_md.md_watchpoint[pw->pw_index].address;
+ pw->pw_md.md_condition = l->l_md.md_watchpoint[pw->pw_index].condition;
+ pw->pw_md.md_length = l->l_md.md_watchpoint[pw->pw_index].length;
+
+ return (0);
+}
+
+static void
+update_mdl_x86_hw_watchpoints(struct lwp *l)
+{
+ size_t i;
+
+ for (i = 0; i < X86_HW_WATCHPOINTS; i++) {
+ if (l->l_md.md_watchpoint[0].address != 0) {
+ return;
+ }
+ }
+ l->l_md.md_flags &= ~MDL_X86_HW_WATCHPOINTS;
+}
+
+int
+process_write_watchpoint(struct lwp *l, struct ptrace_watchpoint *pw)
+{
+
+ if (pw->pw_index > X86_HW_WATCHPOINTS)
+ return (EINVAL);
+
+ if (pw->pw_md.md_address == 0) {
+ l->l_md.md_watchpoint[pw->pw_index].address = 0;
+ update_mdl_x86_hw_watchpoints(l);
+ return (0);
+ }
+
+ if ((vaddr_t)pw->pw_md.md_address > VM_MAXUSER_ADDRESS)
+ return (EINVAL);
+
+ switch (pw->pw_md.md_condition) {
+ case X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION:
+ case X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE:
+ case X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ switch (pw->pw_md.md_length) {
+ case X86_HW_WATCHPOINT_DR7_LENGTH_BYTE:
+ case X86_HW_WATCHPOINT_DR7_LENGTH_TWOBYTES:
+ case X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ l->l_md.md_watchpoint[pw->pw_index].address =
+ (vaddr_t)pw->pw_md.md_address;
+ l->l_md.md_watchpoint[pw->pw_index].condition = pw->pw_md.md_condition;
+ l->l_md.md_watchpoint[pw->pw_index].length = pw->pw_md.md_length;
+
+ l->l_md.md_flags |= MDL_X86_HW_WATCHPOINTS;
+
+ return (0);
+}
Index: src/sys/arch/i386/include/proc.h
diff -u src/sys/arch/i386/include/proc.h:1.42 src/sys/arch/i386/include/proc.h:1.43
--- src/sys/arch/i386/include/proc.h:1.42 Thu Feb 20 18:19:10 2014
+++ src/sys/arch/i386/include/proc.h Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.42 2014/02/20 18:19:10 dsl Exp $ */
+/* $NetBSD: proc.h,v 1.43 2016/12/15 12:04:18 kamil Exp $ */
/*
* Copyright (c) 1991 Regents of the University of California.
@@ -36,6 +36,7 @@
#include <machine/frame.h>
#include <machine/pcb.h>
+#include <x86/dbregs.h>
/*
* Machine-dependent part of the lwp structure for i386.
@@ -49,10 +50,12 @@ struct mdlwp {
volatile int md_astpending; /* AST pending for this process */
struct pmap *md_gc_pmap; /* pmap being garbage collected */
struct vm_page *md_gc_ptp; /* pages from pmap g/c */
+ struct x86_hw_watchpoint md_watchpoint[X86_HW_WATCHPOINTS];
};
/* md_flags */
-#define MDL_IOPL 0x0002 /* XEN: i/o privilege */
+#define MDL_IOPL 0x0002 /* XEN: i/o privilege */
+#define MDL_X86_HW_WATCHPOINTS 0x0004 /* has hardware watchpoints */
struct mdproc {
int md_flags;
Index: src/sys/arch/i386/include/ptrace.h
diff -u src/sys/arch/i386/include/ptrace.h:1.15 src/sys/arch/i386/include/ptrace.h:1.16
--- src/sys/arch/i386/include/ptrace.h:1.15 Fri Sep 25 16:05:17 2015
+++ src/sys/arch/i386/include/ptrace.h Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.15 2015/09/25 16:05:17 christos Exp $ */
+/* $NetBSD: ptrace.h,v 1.16 2016/12/15 12:04:18 kamil Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -84,8 +84,11 @@
#define __HAVE_PROCFS_MACHDEP
/* The machine-dependent ptrace(2) requests. */
-#define PT_GETXMMREGS (PT_FIRSTMACH + 5)
-#define PT_SETXMMREGS (PT_FIRSTMACH + 6)
+#define PT_GETXMMREGS (PT_FIRSTMACH + 5)
+#define PT_SETXMMREGS (PT_FIRSTMACH + 6)
+#define PT_READ_WATCHPOINT (PT_FIRSTMACH + 7)
+#define PT_WRITE_WATCHPOINT (PT_FIRSTMACH + 8)
+#define PT_COUNT_WATCHPOINTS (PT_FIRSTMACH + 9)
#define PT_MACHDEP_STRINGS \
"PT_STEP", \
@@ -94,7 +97,10 @@
"PT_GETFPREGS", \
"PT_SETFPREGS", \
"PT_GETXMMREGS", \
- "PT_SETXMMREGS",
+ "PT_SETXMMREGS", \
+ "PT_READ_WATCHPOINT", \
+ "PT_WRITE_WATCHPOINT", \
+ "PT_COUNT_WATCHPOINTS"
#include <machine/reg.h>
#define PTRACE_REG_PC(r) (r)->r_eip
@@ -106,6 +112,34 @@
#define PTRACE_BREAKPOINT_SIZE 1
#define PTRACE_BREAKPOINT_ADJ sizeof(PTRACE_BREAKPOINT)
+#define __HAVE_PTRACE_WATCHPOINTS
+
+/*
+ * This MD structure translates into x86_hw_watchpoint
+ *
+ * pw_address - 0 represents disabled hardware watchpoint
+ *
+ * conditions:
+ * 0b00 - execution
+ * 0b01 - data write
+ * 0b10 - io read/write (not implemented)
+ * 0b11 - data read/write
+ *
+ * length:
+ * 0b00 - 1 byte
+ * 0b01 - 2 bytes
+ * 0b10 - undefined
+ * 0b11 - 4 bytes
+ *
+ * Helper symbols for conditions and length are available in <x86/dbregs.h>
+ *
+ */
+struct mdpw {
+ void *md_address;
+ int md_condition;
+ int md_length;
+};
+
#ifdef _KERNEL
/*
Index: src/sys/arch/i386/include/userret.h
diff -u src/sys/arch/i386/include/userret.h:1.11 src/sys/arch/i386/include/userret.h:1.12
--- src/sys/arch/i386/include/userret.h:1.11 Mon Apr 28 20:23:24 2008
+++ src/sys/arch/i386/include/userret.h Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: userret.h,v 1.11 2008/04/28 20:23:24 martin Exp $ */
+/* $NetBSD: userret.h,v 1.12 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -63,6 +63,7 @@
*/
#include <sys/userret.h>
+#include <x86/dbregs.h>
static __inline void userret(struct lwp *);
@@ -76,4 +77,15 @@ userret(struct lwp *l)
/* Invoke MI userret code */
mi_userret(l);
+
+ /*
+ * Never mix debug registers with single step, while technically
+ * possible on x86 CPUs, it adds unnecessary complications we do
+ * not want to handle it.
+ */
+ if ((l->l_md.md_regs->tf_eflags & PSL_T) == 0 &&
+ l->l_md.md_flags & MDL_X86_HW_WATCHPOINTS)
+ set_x86_hw_watchpoints(l);
+ else
+ clear_x86_hw_watchpoints();
}
Index: src/sys/arch/x86/include/Makefile
diff -u src/sys/arch/x86/include/Makefile:1.20 src/sys/arch/x86/include/Makefile:1.21
--- src/sys/arch/x86/include/Makefile:1.20 Sat Feb 27 00:09:45 2016
+++ src/sys/arch/x86/include/Makefile Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.20 2016/02/27 00:09:45 tls Exp $
+# $NetBSD: Makefile,v 1.21 2016/12/15 12:04:18 kamil Exp $
INCSDIR=/usr/include/x86
@@ -11,6 +11,7 @@ INCS= aout_machdep.h \
cpu_ucode.h \
cputypes.h \
cpuvar.h \
+ dbregs.h \
float.h \
fpu.h \
ieee.h ieeefp.h \
Index: src/sys/arch/x86/include/dbregs.h
diff -u src/sys/arch/x86/include/dbregs.h:1.1 src/sys/arch/x86/include/dbregs.h:1.2
--- src/sys/arch/x86/include/dbregs.h:1.1 Sun Nov 27 14:49:21 2016
+++ src/sys/arch/x86/include/dbregs.h Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: dbregs.h,v 1.1 2016/11/27 14:49:21 kamil Exp $ */
+/* $NetBSD: dbregs.h,v 1.2 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,16 +30,115 @@
#ifndef _X86_DBREGS_H_
#define _X86_DBREGS_H_
-#ifdef _KERNEL
+#if defined(_KMEMUSER) || defined(_KERNEL)
-struct lwp;
-struct dbreg;
+#include <sys/param.h>
+#include <sys/types.h>
-void reset_dbregs(void);
+/*
+ * CPU Debug Status Register (DR6)
+ *
+ * Reserved bits: 4-12 and on x86_64 32-64
+ */
+#define X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED __BIT(0)
+#define X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED __BIT(1)
+#define X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED __BIT(2)
+#define X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED __BIT(3)
+#define X86_HW_WATCHPOINT_DR6_DEBUG_REGISTER_ACCESS_DETECTED __BIT(13)
+#define X86_HW_WATCHPOINT_DR6_SINGLE_STEP __BIT(14)
+#define X86_HW_WATCHPOINT_DR6_TASK_SWITCH __BIT(15)
+
+/*
+ * CPU Debug Control Register (DR7)
+ *
+ * LOCAL_EXACT_BREAKPOINT and GLOBAL_EXACT_BREAKPOINT are no longer used since
+ * the P6 processor family - portable code should set these bits
+ * unconditionally in oder to get exact breakpoints
+ *
+ * Reserved bits: 10, 12, 14-15 and on x86_64 32-64
+ */
+#define X86_HW_WATCHPOINT_DR7_LOCAL_DR0_BREAKPOINT __BIT(0)
+#define X86_HW_WATCHPOINT_DR7_GLOBAL_DR0_BREAKPOINT __BIT(1)
+#define X86_HW_WATCHPOINT_DR7_LOCAL_DR1_BREAKPOINT __BIT(2)
+#define X86_HW_WATCHPOINT_DR7_GLOBAL_DR1_BREAKPOINT __BIT(3)
+#define X86_HW_WATCHPOINT_DR7_LOCAL_DR2_BREAKPOINT __BIT(4)
+#define X86_HW_WATCHPOINT_DR7_GLOBAL_DR2_BREAKPOINT __BIT(5)
+#define X86_HW_WATCHPOINT_DR7_LOCAL_DR3_BREAKPOINT __BIT(6)
+#define X86_HW_WATCHPOINT_DR7_GLOBAL_DR3_BREAKPOINT __BIT(7)
+#define X86_HW_WATCHPOINT_DR7_LOCAL_EXACT_BREAKPOINT __BIT(8)
+#define X86_HW_WATCHPOINT_DR7_GLOBAL_EXACT_BREAKPOINT __BIT(9)
+#define X86_HW_WATCHPOINT_DR7_RESTRICTED_TRANSACTIONAL_MEMORY __BIT(11)
+#define X86_HW_WATCHPOINT_DR7_GENERAL_DETECT_ENABLE __BIT(13)
+
+#define X86_HW_WATCHPOINT_DR7_DR0_CONDITION_MASK __BITS(16, 17)
+#define X86_HW_WATCHPOINT_DR7_DR0_LENGTH_MASK __BITS(18, 19)
+#define X86_HW_WATCHPOINT_DR7_DR1_CONDITION_MASK __BITS(20, 21)
+#define X86_HW_WATCHPOINT_DR7_DR1_LENGTH_MASK __BITS(22, 23)
+#define X86_HW_WATCHPOINT_DR7_DR2_CONDITION_MASK __BITS(24, 25)
+#define X86_HW_WATCHPOINT_DR7_DR2_LENGTH_MASK __BITS(26, 27)
+#define X86_HW_WATCHPOINT_DR7_DR3_CONDITION_MASK __BITS(28, 29)
+#define X86_HW_WATCHPOINT_DR7_DR3_LENGTH_MASK __BITS(30, 31)
+
+#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+
+/*
+ * X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE is unused
+ * it requires DE (debug extension) flag in control register CR4 set
+ * not all CPUs support it
+ */
+enum x86_hw_watchpoint_condition {
+ X86_HW_WATCHPOINT_DR7_CONDITION_EXECUTION = 0x0,
+ X86_HW_WATCHPOINT_DR7_CONDITION_DATA_WRITE = 0x1,
+ X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE = 0x2,
+ X86_HW_WATCHPOINT_DR7_CONDITION_DATA_READWRITE = 0x3
+};
+
+/*
+ * 0x2 is currently unimplemented - it reflects 8 bytes on modern CPUs
+ */
+enum x86_hw_watchpoint_length {
+ X86_HW_WATCHPOINT_DR7_LENGTH_BYTE = 0x0,
+ X86_HW_WATCHPOINT_DR7_LENGTH_TWOBYTES = 0x1,
+ /* 0x2 undefined */
+ X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES = 0x3
+};
+
+#if defined(_KMEMUSER) || defined(_KERNEL)
+
+/*
+ * The number of available watchpoint registers available since Intel 80386
+ * New CPUs ship with up to 16 Debug Registers but they still offer four
+ * watchpoints, while there other registers are reserved
+ */
+#define X86_HW_WATCHPOINTS 4
+
+/*
+ * lwpid - 0 means all LWPs in the process
+ * address - 0 means that watchpoint is disabled
+ */
+struct x86_hw_watchpoint {
+ vaddr_t address;
+ enum x86_hw_watchpoint_condition condition;
+ enum x86_hw_watchpoint_length length;
+};
+
+/*
+ * Set CPU Debug Registers - to be used before entering user-land context
+ */
+void set_x86_hw_watchpoints(struct lwp *l);
-int process_write_dbregs(struct lwp *lwp, const struct dbreg *regs);
-int process_read_dbregs(struct lwp *lwp, struct dbreg *regs);
+/*
+ * Reset CPU Debug Registers - to be used after entering kernel context
+ */
+void clear_x86_hw_watchpoints(void);
+
+/*
+ * Check if trap is triggered from user-land if so return nonzero value
+ *
+ * This resets Debug Status Register (DR6) break point detection
+ */
+int user_trap_x86_hw_watchpoint(void);
-#endif
+#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
-#endif /* _X86_FPU_H_ */
+#endif /* !_X86_DBREGS_H_ */
Index: src/sys/arch/x86/x86/vm_machdep.c
diff -u src/sys/arch/x86/x86/vm_machdep.c:1.26 src/sys/arch/x86/x86/vm_machdep.c:1.27
--- src/sys/arch/x86/x86/vm_machdep.c:1.26 Tue Nov 8 03:05:36 2016
+++ src/sys/arch/x86/x86/vm_machdep.c Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: vm_machdep.c,v 1.26 2016/11/08 03:05:36 christos Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.27 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 1982, 1986 The Regents of the University of California.
@@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.26 2016/11/08 03:05:36 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.27 2016/12/15 12:04:18 kamil Exp $");
#include "opt_mtrr.h"
@@ -231,6 +231,12 @@ cpu_lwp_fork(struct lwp *l1, struct lwp
pcb2->pcb_esp = (int)sf;
pcb2->pcb_ebp = (int)l2;
#endif
+
+ /*
+ * Do not inherit hardware watchpoints. If they are desired, userland
+ * should do it on its own.
+ */
+ memset(l2->l_md.md_watchpoint, 0, sizeof(*l2->l_md.md_watchpoint));
}
/*
Index: src/sys/arch/xen/conf/files.xen
diff -u src/sys/arch/xen/conf/files.xen:1.142 src/sys/arch/xen/conf/files.xen:1.143
--- src/sys/arch/xen/conf/files.xen:1.142 Tue Dec 13 10:54:27 2016
+++ src/sys/arch/xen/conf/files.xen Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-# $NetBSD: files.xen,v 1.142 2016/12/13 10:54:27 kamil Exp $
+# $NetBSD: files.xen,v 1.143 2016/12/15 12:04:18 kamil Exp $
# NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp
# NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp
@@ -84,6 +84,7 @@ file arch/x86/x86/convert_xmm_s87.c
file arch/x86/x86/db_memrw.c ddb | kgdb
file arch/x86/x86/db_trace.c ddb
file arch/x86/x86/fpu.c
+file arch/x86/x86/dbregs.c
file arch/xen/x86/hypervisor_machdep.c
# file arch/x86/x86/mtrr_i686.c mtrr
file arch/x86/x86/syscall.c
Index: src/sys/compat/netbsd32/netbsd32_ptrace.c
diff -u src/sys/compat/netbsd32/netbsd32_ptrace.c:1.2 src/sys/compat/netbsd32/netbsd32_ptrace.c:1.3
--- src/sys/compat/netbsd32/netbsd32_ptrace.c:1.2 Wed Nov 2 00:11:59 2016
+++ src/sys/compat/netbsd32/netbsd32_ptrace.c Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_ptrace.c,v 1.2 2016/11/02 00:11:59 pgoyette Exp $ */
+/* $NetBSD: netbsd32_ptrace.c,v 1.3 2016/12/15 12:04:18 kamil Exp $ */
/*
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.2 2016/11/02 00:11:59 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.3 2016/12/15 12:04:18 kamil Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ptrace.h"
@@ -58,6 +58,8 @@ static int netbsd32_copyinpiod(struct pt
static void netbsd32_copyoutpiod(const struct ptrace_io_desc *, void *);
static int netbsd32_doregs(struct lwp *, struct lwp *, struct uio *);
static int netbsd32_dofpregs(struct lwp *, struct lwp *, struct uio *);
+static int netbsd32_dowatchpoint(struct lwp *, struct lwp *, int,
+ struct ptrace_watchpoint *, void *, register_t *);
static int
@@ -165,11 +167,22 @@ netbsd32_dofpregs(struct lwp *curl /*tra
#endif
}
+static int
+netbsd32_dowatchpoint(struct lwp *curl /*tracer*/, struct lwp *l /*traced*/,
+ int write, struct ptrace_watchpoint *pw, void *addr, register_t *retval)
+{
+
+ /* unimplemented */
+
+ return EINVAL;
+}
+
static struct ptrace_methods netbsd32_ptm = {
.ptm_copyinpiod = netbsd32_copyinpiod,
.ptm_copyoutpiod = netbsd32_copyoutpiod,
.ptm_doregs = netbsd32_doregs,
- .ptm_dofpregs = netbsd32_dofpregs
+ .ptm_dofpregs = netbsd32_dofpregs,
+ .ptm_dowatchpoint = netbsd32_dowatchpoint
};
Index: src/sys/kern/sys_ptrace.c
diff -u src/sys/kern/sys_ptrace.c:1.2 src/sys/kern/sys_ptrace.c:1.3
--- src/sys/kern/sys_ptrace.c:1.2 Thu Nov 3 03:57:05 2016
+++ src/sys/kern/sys_ptrace.c Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_ptrace.c,v 1.2 2016/11/03 03:57:05 pgoyette Exp $ */
+/* $NetBSD: sys_ptrace.c,v 1.3 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.2 2016/11/03 03:57:05 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.3 2016/12/15 12:04:18 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -169,6 +169,7 @@ static struct ptrace_methods native_ptm
.ptm_copyoutpiod = ptrace_copyoutpiod,
.ptm_doregs = process_doregs,
.ptm_dofpregs = process_dofpregs,
+ .ptm_dowatchpoint = process_dowatchpoint,
};
static const struct syscall_package ptrace_syscalls[] = {
Index: src/sys/kern/sys_ptrace_common.c
diff -u src/sys/kern/sys_ptrace_common.c:1.6 src/sys/kern/sys_ptrace_common.c:1.7
--- src/sys/kern/sys_ptrace_common.c:1.6 Mon Dec 5 22:07:16 2016
+++ src/sys/kern/sys_ptrace_common.c Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_ptrace_common.c,v 1.6 2016/12/05 22:07:16 christos Exp $ */
+/* $NetBSD: sys_ptrace_common.c,v 1.7 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.6 2016/12/05 22:07:16 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.7 2016/12/15 12:04:18 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -202,6 +202,11 @@ ptrace_listener_cb(kauth_cred_t cred, ka
#ifdef PT_SETFPREGS
case PT_SETFPREGS:
#endif
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+ case PT_READ_WATCHPOINT:
+ case PT_WRITE_WATCHPOINT:
+ case PT_COUNT_WATCHPOINTS:
+#endif
case PT_SET_EVENT_MASK:
case PT_GET_EVENT_MASK:
case PT_GET_PROCESS_STATE:
@@ -295,6 +300,9 @@ do_ptrace(struct ptrace_methods *ptm, st
struct ptrace_event pe;
struct ptrace_state ps;
struct ptrace_lwpinfo pl;
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+ struct ptrace_watchpoint pw;
+#endif
struct vmspace *vm;
int error, write, tmp, pheld;
int signo = 0;
@@ -405,6 +413,11 @@ do_ptrace(struct ptrace_methods *ptm, st
#ifdef PT_SETFPREGS
case PT_SETFPREGS:
#endif
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+ case PT_READ_WATCHPOINT:
+ case PT_WRITE_WATCHPOINT:
+ case PT_COUNT_WATCHPOINTS:
+#endif
#ifdef __HAVE_PTRACE_MACHDEP
PTRACE_MACHDEP_REQUEST_CASES
#endif
@@ -993,6 +1006,54 @@ do_ptrace(struct ptrace_methods *ptm, st
break;
#endif
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+ /*
+ * The "write" variable is used as type of operation.
+ * Possible values:
+ * 0 - return the number of supported hardware watchpoints
+ * 1 - set new watchpoint value
+ * 2 - get existing watchpoint image
+ */
+ case PT_WRITE_WATCHPOINT:
+ write = 1;
+ case PT_READ_WATCHPOINT:
+ /* write = 0 done above */
+
+ if (data != sizeof(pw)) {
+ DPRINTF(("ptrace(%d): %d != %zu\n", req,
+ data, sizeof(pe)));
+ error = EINVAL;
+ break;
+ }
+ error = copyin(addr, &pw, sizeof(pw));
+ if (error)
+ break;
+ tmp = pw.pw_lwpid;
+ if (tmp != 0 && t->p_nlwps > 1) {
+ lwp_delref(lt);
+ mutex_enter(t->p_lock);
+ lt = lwp_find(t, tmp);
+ if (lt == NULL) {
+ mutex_exit(t->p_lock);
+ error = ESRCH;
+ break;
+ }
+ lwp_addref(lt);
+ mutex_exit(t->p_lock);
+ }
+ ++write;
+ case PT_COUNT_WATCHPOINTS:
+ if (!process_validwatchpoint(lt))
+ error = EINVAL;
+ else {
+ lwp_lock(lt);
+ error = ptm->ptm_dowatchpoint(l, lt, write, &pw, addr,
+ retval);
+ lwp_unlock(lt);
+ }
+ break;
+#endif
+
#ifdef __HAVE_PTRACE_MACHDEP
PTRACE_MACHDEP_REQUEST_CASES
error = ptrace_machdep_dorequest(l, lt, req, addr, data);
@@ -1135,6 +1196,45 @@ process_auxv_offset(struct proc *p, stru
#endif
return 0;
}
+
+int
+process_dowatchpoint(struct lwp *curl /*tracer*/, struct lwp *l /*traced*/,
+ int operation, struct ptrace_watchpoint *pw, void *addr,
+ register_t *retval)
+{
+
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+ int error;
+
+ KASSERT(operation >= 0);
+ KASSERT(operation <= 2);
+
+ switch (operation) {
+ case 0:
+ return process_count_watchpoints(l, retval);
+ case 1:
+ error = process_read_watchpoint(l, pw);
+ if (error)
+ return error;
+ return copyout(pw, addr, sizeof(*pw));
+ default:
+ return process_write_watchpoint(l, pw);
+ }
+#else
+ return EINVAL;
+#endif
+}
+
+int
+process_validwatchpoint(struct lwp *l)
+{
+
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+ return (l->l_flag & LW_SYSTEM) == 0;
+#else
+ return 0;
+#endif
+}
#endif /* PTRACE */
MODULE(MODULE_CLASS_EXEC, ptrace_common, "");
@@ -1158,4 +1258,3 @@ ptrace_common_modcmd(modcmd_t cmd, void
}
return error;
}
-
Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.49 src/sys/sys/ptrace.h:1.50
--- src/sys/sys/ptrace.h:1.49 Fri Nov 4 18:14:04 2016
+++ src/sys/sys/ptrace.h Thu Dec 15 12:04:18 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.49 2016/11/04 18:14:04 christos Exp $ */
+/* $NetBSD: ptrace.h,v 1.50 2016/12/15 12:04:18 kamil Exp $ */
/*-
* Copyright (c) 1984, 1993
@@ -118,6 +118,19 @@ struct ptrace_lwpinfo {
#define PL_EVENT_NONE 0
#define PL_EVENT_SIGNAL 1
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+/*
+ * Hardware Watchpoints
+ *
+ * MD code handles switch informing whether a particular watchpoint is enabled
+ */
+typedef struct ptrace_watchpoint {
+ int pw_index; /* HW Watchpoint ID (count from 0) */
+ lwpid_t pw_lwpid; /* LWP described */
+ struct mdpw pw_md; /* MD fields */
+} ptrace_watchpoint_t;
+#endif
+
#ifdef _KERNEL
#if defined(PT_GETREGS) || defined(PT_SETREGS)
@@ -138,12 +151,22 @@ struct fpreg;
#define process_fpreg64 struct fpreg
#endif
#endif
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+#ifndef process_watchpoint32
+#define process_watchpoint32 struct ptrace_watchpoint
+#endif
+#ifndef process_watchpoint64
+#define process_watchpoint64 struct ptrace_watchpoint
+#endif
+#endif
struct ptrace_methods {
int (*ptm_copyinpiod)(struct ptrace_io_desc *, const void *);
void (*ptm_copyoutpiod)(const struct ptrace_io_desc *, void *);
int (*ptm_doregs)(struct lwp *, struct lwp *, struct uio *);
int (*ptm_dofpregs)(struct lwp *, struct lwp *, struct uio *);
+ int (*ptm_dowatchpoint)(struct lwp *, struct lwp *, int,
+ struct ptrace_watchpoint *, void *, register_t *);
};
int ptrace_init(void);
@@ -156,6 +179,10 @@ int process_validregs(struct lwp *);
int process_dofpregs(struct lwp *, struct lwp *, struct uio *);
int process_validfpregs(struct lwp *);
+int process_dowatchpoint(struct lwp *, struct lwp *, int,
+ struct ptrace_watchpoint *, void *, register_t *);
+int process_validwatchpoint(struct lwp *);
+
int process_domem(struct lwp *, struct lwp *, struct uio *);
void process_stoptrace(void);
@@ -211,6 +238,32 @@ int process_write_regs(struct lwp *, con
#endif
#endif
+#ifdef __HAVE_PTRACE_WATCHPOINTS
+int process_count_watchpoints(struct lwp *, register_t *retval);
+#ifndef process_count_watchpoints32
+#define process_count_watchpoints32 process_count_watchpoints
+#endif
+#ifndef process_count_watchpoints64
+#define process_count_watchpoints64 process_count_watchpoints
+#endif
+
+int process_read_watchpoint(struct lwp *, struct ptrace_watchpoint *);
+#ifndef process_read_watchpoint32
+#define process_read_watchpoint32 process_read_watchpoint
+#endif
+#ifndef process_read_watchpoint64
+#define process_read_watchpoint64 process_read_watchpoint
+#endif
+
+int process_write_watchpoint(struct lwp *, struct ptrace_watchpoint *);
+#ifndef process_write_watchpoint32
+#define process_write_watchpoint32 process_write_watchpoint
+#endif
+#ifndef process_write_watchpoint64
+#define process_write_watchpoint64 process_write_watchpoint
+#endif
+#endif
+
#ifdef __HAVE_PROCFS_MACHDEP
int ptrace_machdep_dorequest(struct lwp *, struct lwp *, int,
void *, int);
Added files:
Index: src/sys/arch/x86/x86/dbregs.c
diff -u /dev/null src/sys/arch/x86/x86/dbregs.c:1.1
--- /dev/null Thu Dec 15 12:04:19 2016
+++ src/sys/arch/x86/x86/dbregs.c Thu Dec 15 12:04:18 2016
@@ -0,0 +1,230 @@
+/* $NetBSD: dbregs.c,v 1.1 2016/12/15 12:04:18 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/lwp.h>
+#include <x86/cpufunc.h>
+#include <x86/dbregs.h>
+
+#include <uvm/uvm_prot.h>
+#include <uvm/uvm_pmap.h>
+
+#include <machine/pmap.h>
+
+static void
+set_x86_hw_watchpoint(size_t idx, vaddr_t address,
+ enum x86_hw_watchpoint_condition condition,
+ enum x86_hw_watchpoint_length length)
+{
+ register_t dr;
+
+ KASSERT(address < VM_MAXUSER_ADDRESS);
+
+ /* Read the original DR7 value in order to save existing watchpoints */
+ dr = rdr7();
+
+ switch (idx) {
+ case 0:
+ ldr0(address);
+ dr |= X86_HW_WATCHPOINT_DR7_GLOBAL_DR0_BREAKPOINT;
+ dr |= __SHIFTIN(condition,
+ X86_HW_WATCHPOINT_DR7_DR0_CONDITION_MASK);
+ dr |= __SHIFTIN(length,
+ X86_HW_WATCHPOINT_DR7_DR0_LENGTH_MASK);
+ break;
+ case 1:
+ ldr1(address);
+ dr |= X86_HW_WATCHPOINT_DR7_GLOBAL_DR1_BREAKPOINT;
+ dr |= __SHIFTIN(condition,
+ X86_HW_WATCHPOINT_DR7_DR1_CONDITION_MASK);
+ dr |= __SHIFTIN(length,
+ X86_HW_WATCHPOINT_DR7_DR1_LENGTH_MASK);
+ break;
+ case 2:
+ ldr2(address);
+ dr |= X86_HW_WATCHPOINT_DR7_GLOBAL_DR2_BREAKPOINT;
+ dr |= __SHIFTIN(condition,
+ X86_HW_WATCHPOINT_DR7_DR2_CONDITION_MASK);
+ dr |= __SHIFTIN(length,
+ X86_HW_WATCHPOINT_DR7_DR2_LENGTH_MASK);
+ break;
+ case 3:
+ ldr3(address);
+ dr |= X86_HW_WATCHPOINT_DR7_GLOBAL_DR3_BREAKPOINT;
+ dr |= __SHIFTIN(condition,
+ X86_HW_WATCHPOINT_DR7_DR3_CONDITION_MASK);
+ dr |= __SHIFTIN(length,
+ X86_HW_WATCHPOINT_DR7_DR3_LENGTH_MASK);
+ break;
+ }
+
+ ldr7(dr);
+}
+
+void
+set_x86_hw_watchpoints(struct lwp *l)
+{
+ size_t i;
+
+ /* Assert that Debug Registers are not mixed with Debug Trap Flag */
+#ifdef __x86_64__
+ KASSERT((l->l_md.md_regs->tf_rflags & PSL_T) == 0);
+#else
+ KASSERT((l->l_md.md_regs->tf_eflags & PSL_T) == 0);
+#endif
+
+ /* Assert that there are available watchpoints */
+ KASSERT(l->l_md.md_flags & MDL_X86_HW_WATCHPOINTS);
+
+ /* Clear Debug Control Register (DR7) first */
+ ldr7(0);
+
+ /*
+ * Clear Debug Status Register (DR6) as these bits are never cleared
+ * automatically by the processor
+ *
+ * Clear BREAKPOINT_CONDITION_DETECTED bits and ignore the rest
+ */
+ ldr6(rdr6() &
+ ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
+
+ for (i = 0; i < X86_HW_WATCHPOINTS; i++) {
+ if (l->l_md.md_watchpoint[i].address != 0) {
+ set_x86_hw_watchpoint(i,
+ l->l_md.md_watchpoint[i].address,
+ l->l_md.md_watchpoint[i].condition,
+ l->l_md.md_watchpoint[i].length);
+ }
+ }
+}
+
+void
+clear_x86_hw_watchpoints(void)
+{
+
+ /*
+ * It's sufficient to just disable Debug Control Register (DR7)
+ * it will deactivate hardware watchpoints
+ */
+ ldr7(0);
+ /*
+ * However at some point we need to clear Debug Status Registers (DR6)
+ * CPU will never do it automatically
+ *
+ * Clear BREAKPOINT_CONDITION_DETECTED bits and ignore the rest
+ */
+ ldr6(rdr6() &
+ ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
+}
+
+int
+user_trap_x86_hw_watchpoint(void)
+{
+ register_t dr7, dr6; /* debug registers dr6 and dr7 */
+ register_t bp; /* breakpoint bits extracted from dr6 */
+ int nbp; /* number of breakpoints that triggered */
+ vaddr_t addr[X86_HW_WATCHPOINTS]; /* breakpoint addresses */
+ int i;
+
+ dr7 = rdr7();
+ if ((dr7 &
+ (X86_HW_WATCHPOINT_DR7_GLOBAL_DR0_BREAKPOINT |
+ X86_HW_WATCHPOINT_DR7_GLOBAL_DR1_BREAKPOINT |
+ X86_HW_WATCHPOINT_DR7_GLOBAL_DR2_BREAKPOINT |
+ X86_HW_WATCHPOINT_DR7_GLOBAL_DR3_BREAKPOINT)) == 0) {
+ /*
+ * all Global Breakpoint bits in the DR7 register are zero,
+ * thus the trap couldn't have been caused by the
+ * hardware debug registers
+ */
+ return 0;
+ }
+
+ nbp = 0;
+ dr6 = rdr6();
+ bp = dr6 & \
+ (X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED);
+
+ if (!bp) {
+ /*
+ * None of the breakpoint bits are set meaning this
+ * trap was not caused by any of the debug registers
+ */
+ return 0;
+ }
+
+ /*
+ * at least one of the breakpoints were hit, check to see
+ * which ones and if any of them are user space addresses
+ */
+
+ if (bp & X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED)
+ addr[nbp++] = (vaddr_t)rdr0();
+ if (bp & X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED)
+ addr[nbp++] = (vaddr_t)rdr1();
+ if (bp & X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED)
+ addr[nbp++] = (vaddr_t)rdr2();
+ if (bp & X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED)
+ addr[nbp++] = (vaddr_t)rdr3();
+
+ for (i = 0; i < nbp; i++) {
+ /* Check if addr[i] is in user space */
+ if (addr[i] >= (vaddr_t)VM_MAXUSER_ADDRESS)
+ continue;
+
+ /*
+ * Clear Status Register (DR6) now as it's not done by CPU.
+ *
+ * Clear BREAKPOINT_CONDITION_DETECTED bits and ignore
+ * the rest.
+ */
+ ldr6(dr6 &
+ ~(X86_HW_WATCHPOINT_DR6_DR0_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED |
+ X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED));
+
+ return nbp;
+ }
+
+ /*
+ * None of the breakpoints are in user space.
+ */
+ return 0;
+}