Module Name: src
Committed By: kamil
Date: Thu Feb 23 03:34:23 UTC 2017
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/include: netbsd32_machdep.h pcb.h proc.h ptrace.h
reg.h userret.h
src/sys/arch/i386/i386: machdep.c process_machdep.c trap.c
src/sys/arch/i386/include: pcb.h proc.h ptrace.h reg.h userret.h
src/sys/arch/x86/include: dbregs.h
src/sys/arch/x86/x86: dbregs.c vm_machdep.c
src/sys/compat/netbsd32: netbsd32_ptrace.c
src/sys/kern: sys_ptrace.c sys_ptrace_common.c
src/sys/sys: proc.h ptrace.h
Log Message:
Introduce PT_GETDBREGS and PT_SETDBREGS in ptrace(2) on i386 and amd64
This interface is modeled after FreeBSD API with the usage.
This replaced previous watchpoint API. The previous one was introduced
recently in NetBSD-current and remove its spurs without any
backward-compatibility.
Design choices for Debug Register accessors:
- exec() (TRAP_EXEC event) must remove debug registers from LWP
- debug registers are only per-LWP, not per-process globally
- debug registers must not be inherited after (v)forking a process
- debug registers must not be inherited after forking a thread
- a debugger is responsible to set global watchpoints/breakpoints with the
debug registers, to achieve this PTRACE_LWP_CREATE/PTRACE_LWP_EXIT event
monitoring function is designed to be used
- debug register traps must generate SIGTRAP with si_code TRAP_DBREG
- debugger is responsible to retrieve debug register state to distinguish
the exact debug register trap (DR6 is Status Register on x86)
- kernel must not remove debug register traps after triggering a trap event
a debugger is responsible to detach this trap with appropriate PT_SETDBREGS
call (DR7 is Control Register on x86)
- debug registers must not be exposed in mcontext
- userland must not be allowed to set a trap on the kernel
Implementation notes on i386 and amd64:
- the initial state of debug register is retrieved on boot and this value is
stored in a local copy (initdbregs), this value is used to initialize dbreg
context after PT_GETDBREGS
- struct dbregs is stored in pcb as a pointer and by default not initialized
- reserved registers (DR4-DR5, DR9-DR15) are ignored
Further ideas:
- restrict this interface with securelevel
Tested on real hardware i386 (Intel Pentium IV) and amd64 (Intel i7).
This commit enables 390 debug register ATF tests in kernel/arch/x86.
All tests are passing.
This commit does not cover netbsd32 compat code. Currently other interface
PT_GET_SIGINFO/PT_SET_SIGINFO is required in netbsd32 compat code in order to
validate reliably PT_GETDBREGS/PT_SETDBREGS.
This implementation does not cover FreeBSD specific defines in their
<x86/reg.h>: DBREG_DR7_LOCAL_ENABLE, DBREG_DR7_GLOBAL_ENABLE, DBREG_DR7_LEN_1
etc. These values tend to be reinvented by each tracer on its own. GNU
Debugger (GDB) works with NetBSD debug registers after adding this patch:
--- gdb/amd64bsd-nat.c.orig 2016-02-10 03:19:39.000000000 +0000
+++ gdb/amd64bsd-nat.c
@@ -167,6 +167,10 @@ amd64bsd_target (void)
#ifdef HAVE_PT_GETDBREGS
+#ifndef DBREG_DRX
+#define DBREG_DRX(d,x) ((d)->dr[(x)])
+#endif
+
static unsigned long
amd64bsd_dr_get (ptid_t ptid, int regnum)
{
Another reason to stop introducing unpopular defines covering machine
specific register macros is that these value varies across generations of
the same CPU family.
GDB demo:
(gdb) c
Continuing.
Watchpoint 2: traceme
Old value = 0
New value = 16
main (argc=1, argv=0x7f7fff79fe30) at test.c:8
8 printf("traceme=%d\n", traceme);
(Currently the GDB interface is not reliable due to NetBSD support bugs)
Sponsored by <The NetBSD Foundation>
To generate a diff of this commit:
cvs rdiff -u -r1.242 -r1.243 src/distrib/sets/lists/comp/md.amd64
cvs rdiff -u -r1.162 -r1.163 src/distrib/sets/lists/comp/md.i386
cvs rdiff -u -r1.251 -r1.252 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.103 -r1.104 src/sys/arch/amd64/amd64/netbsd32_machdep.c
cvs rdiff -u -r1.31 -r1.32 src/sys/arch/amd64/amd64/process_machdep.c
cvs rdiff -u -r1.91 -r1.92 src/sys/arch/amd64/amd64/trap.c
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/amd64/include/netbsd32_machdep.h
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/amd64/include/pcb.h
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/amd64/include/proc.h
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/amd64/include/ptrace.h \
src/sys/arch/amd64/include/reg.h
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/amd64/include/userret.h
cvs rdiff -u -r1.779 -r1.780 src/sys/arch/i386/i386/machdep.c
cvs rdiff -u -r1.88 -r1.89 src/sys/arch/i386/i386/process_machdep.c
cvs rdiff -u -r1.283 -r1.284 src/sys/arch/i386/i386/trap.c
cvs rdiff -u -r1.54 -r1.55 src/sys/arch/i386/include/pcb.h
cvs rdiff -u -r1.43 -r1.44 src/sys/arch/i386/include/proc.h
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/i386/include/ptrace.h
cvs rdiff -u -r1.19 -r1.20 src/sys/arch/i386/include/reg.h
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/i386/include/userret.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/x86/include/dbregs.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/x86/x86/dbregs.c
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/x86/x86/vm_machdep.c
cvs rdiff -u -r1.3 -r1.4 src/sys/compat/netbsd32/netbsd32_ptrace.c
cvs rdiff -u -r1.3 -r1.4 src/sys/kern/sys_ptrace.c
cvs rdiff -u -r1.16 -r1.17 src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.337 -r1.338 src/sys/sys/proc.h
cvs rdiff -u -r1.57 -r1.58 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.242 src/distrib/sets/lists/comp/md.amd64:1.243
--- src/distrib/sets/lists/comp/md.amd64:1.242 Wed Jan 11 12:02:24 2017
+++ src/distrib/sets/lists/comp/md.amd64 Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-# $NetBSD: md.amd64,v 1.242 2017/01/11 12:02:24 joerg Exp $
+# $NetBSD: md.amd64,v 1.243 2017/02/23 03:34:22 kamil Exp $
./usr/include/amd64 comp-c-include
./usr/include/amd64/ansi.h comp-c-include
@@ -552,7 +552,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/dbregs.h comp-obsolete obsolete
./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.162 src/distrib/sets/lists/comp/md.i386:1.163
--- src/distrib/sets/lists/comp/md.i386:1.162 Wed Jan 11 12:02:24 2017
+++ src/distrib/sets/lists/comp/md.i386 Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-# $NetBSD: md.i386,v 1.162 2017/01/11 12:02:24 joerg Exp $
+# $NetBSD: md.i386,v 1.163 2017/02/23 03:34:22 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
@@ -426,7 +426,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/dbregs.h comp-obsolete obsolete
./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.251 src/sys/arch/amd64/amd64/machdep.c:1.252
--- src/sys/arch/amd64/amd64/machdep.c:1.251 Sun Feb 5 08:36:08 2017
+++ src/sys/arch/amd64/amd64/machdep.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.251 2017/02/05 08:36:08 maxv Exp $ */
+/* $NetBSD: machdep.c,v 1.252 2017/02/23 03:34:22 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.251 2017/02/05 08:36:08 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.252 2017/02/23 03:34:22 kamil Exp $");
/* #define XENDEBUG_LOW */
@@ -175,6 +175,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v
#include <machine/specialreg.h>
#include <machine/bootinfo.h>
#include <x86/fpu.h>
+#include <x86/dbregs.h>
#include <machine/mtrr.h>
#include <machine/mpbiosvar.h>
@@ -282,6 +283,7 @@ void (*delay_func)(unsigned int) = xen_d
void (*initclock_func)(void) = xen_initclocks;
#endif
+struct pool x86_dbregspl;
/*
* Size of memory segments, before any memory is stolen.
@@ -469,11 +471,11 @@ x86_64_proc0_tss_ldt_init(void)
pcb->pcb_gs = 0;
pcb->pcb_rsp0 = (uvm_lwp_getuarea(l) + USPACE - 16) & ~0xf;
pcb->pcb_iopl = SEL_KPL;
+ pcb->pcb_dbregs = NULL;
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,11 +1318,13 @@ setregs(struct lwp *l, struct exec_packa
fpu_save_area_clear(l, pack->ep_osversion >= 699002600
? __NetBSD_NPXCW__ : __NetBSD_COMPAT_NPXCW__);
pcb->pcb_flags = 0;
+ if (pcb->pcb_dbregs != NULL) {
+ pool_put(&x86_dbregspl, pcb->pcb_dbregs);
+ pcb->pcb_dbregs = NULL;
+ }
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);
@@ -1491,6 +1495,7 @@ init_x86_64(paddr_t first_avail)
struct region_descriptor region;
struct mem_segment_descriptor *ldt_segp;
int x;
+ struct pcb *pcb;
#ifndef XEN
extern paddr_t local_apic_pa;
int ist;
@@ -1510,8 +1515,8 @@ init_x86_64(paddr_t first_avail)
use_pae = 1; /* PAE always enabled in long mode */
+ pcb = lwp_getpcb(&lwp0);
#ifdef XEN
- struct pcb *pcb = lwp_getpcb(&lwp0);
mutex_init(&pte_lock, MUTEX_DEFAULT, IPL_VM);
pcb->pcb_cr3 = xen_start_info.pt_base - KERNBASE;
__PRINTK(("pcb_cr3 0x%lx\n", xen_start_info.pt_base - KERNBASE));
@@ -1774,6 +1779,13 @@ init_x86_64(paddr_t first_avail)
kgdb_connect(1);
}
#endif
+
+ pcb->pcb_dbregs = NULL;
+
+ x86_dbregs_setup_initdbstate();
+
+ pool_init(&x86_dbregspl, sizeof(struct dbreg), 16, 0, 0, "dbregs",
+ NULL, IPL_NONE);
}
void
Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c
diff -u src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.103 src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.104
--- src/sys/arch/amd64/amd64/netbsd32_machdep.c:1.103 Tue Feb 14 09:03:48 2017
+++ src/sys/arch/amd64/amd64/netbsd32_machdep.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_machdep.c,v 1.103 2017/02/14 09:03:48 maxv Exp $ */
+/* $NetBSD: netbsd32_machdep.c,v 1.104 2017/02/23 03:34:22 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.103 2017/02/14 09:03:48 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.104 2017/02/23 03:34:22 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@@ -80,6 +80,8 @@ __KERNEL_RCSID(0, "$NetBSD: netbsd32_mac
#include <compat/sys/signal.h>
#include <compat/sys/signalvar.h>
+extern struct pool x86_dbregspl;
+
/* Provide a the name of the architecture we're emulating */
const char machine32[] = "i386";
const char machine_arch32[] = "i386";
@@ -136,9 +138,12 @@ netbsd32_setregs(struct lwp *l, struct e
fpu_save_area_clear(l, pack->ep_osversion >= 699002600
? __NetBSD_NPXCW__ : __NetBSD_COMPAT_NPXCW__);
- p->p_flag |= PK_32;
+ if (pcb->pcb_dbregs != NULL) {
+ pool_put(&x86_dbregspl, pcb->pcb_dbregs);
+ pcb->pcb_dbregs = NULL;
+ }
- memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+ p->p_flag |= PK_32;
tf = l->l_md.md_regs;
tf->tf_ds = LSEL(LUDATA32_SEL, SEL_UPL);
@@ -529,6 +534,28 @@ netbsd32_process_read_fpregs(struct lwp
}
int
+netbsd32_process_read_dbregs(struct lwp *l, struct dbreg32 *regs, size_t *sz)
+{
+#if notyet
+ struct pcb *pcb;
+
+ pcb = lwp_getpcb(l);
+
+ regs->dr[0] = pcb->pcb_dbregs->dr[0] & 0xffffffff;
+ regs->dr[1] = pcb->pcb_dbregs->dr[1] & 0xffffffff;
+ regs->dr[2] = pcb->pcb_dbregs->dr[2] & 0xffffffff;
+ regs->dr[3] = pcb->pcb_dbregs->dr[3] & 0xffffffff;
+
+ regs->dr[6] = pcb->pcb_dbregs->dr[6] & 0xffffffff;
+ regs->dr[7] = pcb->pcb_dbregs->dr[7] & 0xffffffff;
+
+ return 0;
+#else
+ return ENOTSUP;
+#endif
+}
+
+int
netbsd32_process_write_regs(struct lwp *l, const struct reg32 *regs)
{
struct trapframe *tf;
@@ -589,6 +616,29 @@ netbsd32_process_write_fpregs(struct lwp
}
int
+netbsd32_process_write_dbregs(struct lwp *l, const struct dbreg32 *regs,
+ size_t sz)
+{
+#if notyet
+ struct pcb *pcb;
+
+ pcb = lwp_getpcb(l);
+
+ pcb->pcb_dbregs->dr[0] = regs->dr[0];
+ pcb->pcb_dbregs->dr[1] = regs->dr[1];
+ pcb->pcb_dbregs->dr[2] = regs->dr[2];
+ pcb->pcb_dbregs->dr[3] = regs->dr[3];
+
+ pcb->pcb_dbregs->dr[6] = regs->dr[6];
+ pcb->pcb_dbregs->dr[7] = regs->dr[7];
+
+ return 0;
+#else
+ return ENOTSUP;
+#endif
+}
+
+int
netbsd32_sysarch(struct lwp *l, const struct netbsd32_sysarch_args *uap, register_t *retval)
{
/* {
Index: src/sys/arch/amd64/amd64/process_machdep.c
diff -u src/sys/arch/amd64/amd64/process_machdep.c:1.31 src/sys/arch/amd64/amd64/process_machdep.c:1.32
--- src/sys/arch/amd64/amd64/process_machdep.c:1.31 Mon Jan 16 21:35:59 2017
+++ src/sys/arch/amd64/amd64/process_machdep.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.31 2017/01/16 21:35:59 kamil Exp $ */
+/* $NetBSD: process_machdep.c,v 1.32 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -44,26 +44,39 @@
* registers or privileged bits in the PSL.
* The process is stopped at the time write_regs is called.
*
+ * process_read_fpregs(proc, regs, sz)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_fpregs is called.
+ *
+ * process_write_fpregs(proc, regs, sz)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_fpregs is called.
+ *
+ * process_read_dbregs(proc, regs, sz)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_dbregs is called.
+ *
+ * process_write_dbregs(proc, regs, sz)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_dbregs is called.
+ *
* process_sstep(proc)
* Arrange for the process to trap after executing a single instruction.
*
* 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.31 2017/01/16 21:35:59 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.32 2017/02/23 03:34:22 kamil Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -114,6 +127,15 @@ process_read_fpregs(struct lwp *l, struc
}
int
+process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz)
+{
+
+ x86_dbregs_read(l, regs);
+
+ return 0;
+}
+
+int
process_write_regs(struct lwp *l, const struct reg *regp)
{
struct trapframe *tf = process_frame(l);
@@ -145,6 +167,23 @@ process_write_fpregs(struct lwp *l, cons
}
int
+process_write_dbregs(struct lwp *l, const struct dbreg *regs, size_t sz)
+{
+ int error;
+
+ /*
+ * Check for security violations.
+ */
+ error = x86_dbregs_validate(regs);
+ if (error != 0)
+ return error;
+
+ x86_dbregs_write(l, regs);
+
+ return 0;
+}
+
+int
process_sstep(struct lwp *l, int sstep)
{
struct trapframe *tf = process_frame(l);
@@ -168,85 +207,3 @@ 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_type = PTRACE_PW_TYPE_DBREGS;
- 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_type != PTRACE_PW_TYPE_DBREGS)
- 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.91 src/sys/arch/amd64/amd64/trap.c:1.92
--- src/sys/arch/amd64/amd64/trap.c:1.91 Fri Feb 17 01:14:31 2017
+++ src/sys/arch/amd64/amd64/trap.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.91 2017/02/17 01:14:31 kamil Exp $ */
+/* $NetBSD: trap.c,v 1.92 2017/02/23 03:34:22 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.91 2017/02/17 01:14:31 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.92 2017/02/23 03:34:22 kamil Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -230,7 +230,7 @@ trap(struct trapframe *frame)
#endif
ksiginfo_t ksi;
void *onfault;
- int type, error, wptnfo;
+ int type, error;
uint64_t cr2;
bool pfail;
@@ -687,7 +687,7 @@ faultcommon:
* in kernel space because that is useful when
* debugging the kernel.
*/
- if (user_trap_x86_hw_watchpoint())
+ if (x86_dbregs_user_trap())
break;
/* Check whether they single-stepped into a lcall. */
@@ -710,10 +710,9 @@ faultcommon:
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGTRAP;
ksi.ksi_trap = type & ~T_USER;
- if ((wptnfo = user_trap_x86_hw_watchpoint())) {
+ if (x86_dbregs_user_trap()) {
+ x86_dbregs_store_dr6(l);
ksi.ksi_code = TRAP_DBREG;
- ksi.ksi_trap2 = x86_hw_watchpoint_reg(wptnfo);
- ksi.ksi_trap3 = x86_hw_watchpoint_type(wptnfo);
} else if (type == (T_BPTFLT|T_USER))
ksi.ksi_code = TRAP_BRKPT;
else
Index: src/sys/arch/amd64/include/netbsd32_machdep.h
diff -u src/sys/arch/amd64/include/netbsd32_machdep.h:1.21 src/sys/arch/amd64/include/netbsd32_machdep.h:1.22
--- src/sys/arch/amd64/include/netbsd32_machdep.h:1.21 Mon Feb 6 16:02:17 2017
+++ src/sys/arch/amd64/include/netbsd32_machdep.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_machdep.h,v 1.21 2017/02/06 16:02:17 maxv Exp $ */
+/* $NetBSD: netbsd32_machdep.h,v 1.22 2017/02/23 03:34:22 kamil Exp $ */
#ifndef _MACHINE_NETBSD32_H_
#define _MACHINE_NETBSD32_H_
@@ -114,6 +114,10 @@ struct fpreg32 {
char __data[108];
};
+struct dbreg32 {
+ int dr[8];
+};
+
struct x86_get_ldt_args32 {
int32_t start;
uint32_t desc;
@@ -149,8 +153,10 @@ struct x86_64_set_mtrr_args32 {
int netbsd32_process_read_regs(struct lwp *, struct reg32 *);
int netbsd32_process_read_fpregs(struct lwp *, struct fpreg32 *, size_t *);
+int netbsd32_process_read_dbregs(struct lwp *, struct dbreg32 *, size_t *);
int netbsd32_process_write_regs(struct lwp *, const struct reg32 *);
int netbsd32_process_write_fpregs(struct lwp *, const struct fpreg32 *, size_t);
+int netbsd32_process_write_dbregs(struct lwp *, const struct dbreg32 *, size_t);
#endif /* _MACHINE_NETBSD32_H_ */
Index: src/sys/arch/amd64/include/pcb.h
diff -u src/sys/arch/amd64/include/pcb.h:1.25 src/sys/arch/amd64/include/pcb.h:1.26
--- src/sys/arch/amd64/include/pcb.h:1.25 Thu Feb 20 18:19:10 2014
+++ src/sys/arch/amd64/include/pcb.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: pcb.h,v 1.25 2014/02/20 18:19:10 dsl Exp $ */
+/* $NetBSD: pcb.h,v 1.26 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -73,6 +73,7 @@
#ifdef __x86_64__
#include <x86/cpu_extended_state.h>
+#include <amd64/reg.h>
#define NIOPORTS 1024 /* # of ports we allow to be mapped */
@@ -89,9 +90,10 @@ struct pcb {
void *pcb_onfault; /* copyin/out fault recovery */
uint64_t pcb_fs;
uint64_t pcb_gs;
+ struct dbreg *pcb_dbregs;
int pcb_iopl;
- uint32_t pcb_unused[11]; /* unused */
+ uint32_t pcb_unused[9]; /* unused */
struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */
union savefpu pcb_savefpu __aligned(64); /* floating point state */
Index: src/sys/arch/amd64/include/proc.h
diff -u src/sys/arch/amd64/include/proc.h:1.20 src/sys/arch/amd64/include/proc.h:1.21
--- src/sys/arch/amd64/include/proc.h:1.20 Thu Dec 15 12:04:17 2016
+++ src/sys/arch/amd64/include/proc.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.20 2016/12/15 12:04:17 kamil Exp $ */
+/* $NetBSD: proc.h,v 1.21 2017/02/23 03:34:22 kamil Exp $ */
/*
* Copyright (c) 1991 Regents of the University of California.
@@ -52,12 +52,10 @@ 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_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.9 src/sys/arch/amd64/include/ptrace.h:1.10
--- src/sys/arch/amd64/include/ptrace.h:1.9 Mon Jan 16 21:35:59 2017
+++ src/sys/arch/amd64/include/ptrace.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.9 2017/01/16 21:35:59 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.10 2017/02/23 03:34:22 kamil Exp $ */
/*
* Copyright (c) 1993 Christopher G. Demetriou
@@ -41,9 +41,8 @@
#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_GETDBREGS (PT_FIRSTMACH + 5)
+#define PT_SETDBREGS (PT_FIRSTMACH + 6)
#define PT_MACHDEP_STRINGS \
"PT_STEP", \
@@ -51,9 +50,8 @@
"PT_SETREGS", \
"PT_GETFPREGS", \
"PT_SETFPREGS", \
- "PT_READ_WATCHPOINT", \
- "PT_WRITE_WATCHPOINT", \
- "PT_COUNT_WATCHPOINTS"
+ "PT_GETDBREGS", \
+ "PT_SETDBREGS",
#include <machine/reg.h>
#define PTRACE_REG_PC(r) (r)->regs[_REG_RIP]
@@ -65,50 +63,6 @@
#define PTRACE_BREAKPOINT_SIZE 1
#define PTRACE_BREAKPOINT_ADJ 1
-#define __HAVE_PTRACE_WATCHPOINTS
-
-/*
- * The current list of supported hardware watchpoints
- */
-#define PTRACE_PW_TYPE_DBREGS 1
-
-struct mdpw {
- union {
- /* Debug Registers DR0-3, DR6, DR7 */
- struct {
- void *_md_address;
- int _md_condition;
- int _md_length;
- } _dbregs;
- } _type;
-};
-
-/*
- * 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>
- *
- */
-
-#define md_address _type._dbregs._md_address
-#define md_condition _type._dbregs._md_condition
-#define md_length _type._dbregs._md_length
-
-
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd32.h"
@@ -117,17 +71,15 @@ struct mdpw {
#define process_read_regs32 netbsd32_process_read_regs
#define process_read_fpregs32 netbsd32_process_read_fpregs
+#define process_read_dbregs32 netbsd32_process_read_dbregs
#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_write_dbregs32 netbsd32_process_write_dbregs
#define process_reg32 struct reg32
#define process_fpreg32 struct fpreg32
-#define process_watchpoint32 struct ptrace_watchpoint32
+#define process_dbreg32 struct dbreg32
#endif /* COMPAT_NETBSD32 */
#endif /* _KERNEL_OPT */
Index: src/sys/arch/amd64/include/reg.h
diff -u src/sys/arch/amd64/include/reg.h:1.9 src/sys/arch/amd64/include/reg.h:1.10
--- src/sys/arch/amd64/include/reg.h:1.9 Tue Feb 11 20:17:16 2014
+++ src/sys/arch/amd64/include/reg.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: reg.h,v 1.9 2014/02/11 20:17:16 dsl Exp $ */
+/* $NetBSD: reg.h,v 1.10 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -56,6 +56,19 @@ struct fpreg {
struct fxsave fxstate;
};
+/*
+ * Debug Registers
+ *
+ * DR0-DR3 Debug Address Registers
+ * DR4-DR5 Reserved
+ * DR6 Debug Status Register
+ * DR7 Debug Control Register
+ * DR8-DR15 Reserved
+ */
+struct dbreg {
+ long dr[16];
+};
+
#else /* __x86_64__ */
#include <i386/reg.h>
Index: src/sys/arch/amd64/include/userret.h
diff -u src/sys/arch/amd64/include/userret.h:1.11 src/sys/arch/amd64/include/userret.h:1.12
--- src/sys/arch/amd64/include/userret.h:1.11 Mon Jan 16 21:19:35 2017
+++ src/sys/arch/amd64/include/userret.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: userret.h,v 1.11 2017/01/16 21:19:35 kamil Exp $ */
+/* $NetBSD: userret.h,v 1.12 2017/02/23 03:34:22 kamil Exp $ */
/*
* XXXfvdl same as i386 counterpart, but should probably be independent.
@@ -78,15 +78,13 @@ static __inline void userret(struct lwp
static __inline void
userret(struct lwp *l)
{
+ struct pcb *pcb = lwp_getpcb(l);
/* Invoke MI userret code */
mi_userret(l);
- /*
- * Allow to mix debug registers with single step.
- */
- if (l->l_md.md_flags & MDL_X86_HW_WATCHPOINTS)
- set_x86_hw_watchpoints(l);
+ if (pcb->pcb_dbregs)
+ x86_dbregs_set(l);
else
- clear_x86_hw_watchpoints();
+ x86_dbregs_clear(l);
}
Index: src/sys/arch/i386/i386/machdep.c
diff -u src/sys/arch/i386/i386/machdep.c:1.779 src/sys/arch/i386/i386/machdep.c:1.780
--- src/sys/arch/i386/i386/machdep.c:1.779 Fri Feb 17 12:10:40 2017
+++ src/sys/arch/i386/i386/machdep.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.779 2017/02/17 12:10:40 maxv Exp $ */
+/* $NetBSD: machdep.c,v 1.780 2017/02/23 03:34:22 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.779 2017/02/17 12:10:40 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.780 2017/02/23 03:34:22 kamil Exp $");
#include "opt_beep.h"
#include "opt_compat_ibcs2.h"
@@ -144,6 +144,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v
#include <x86/x86/tsc.h>
#include <x86/fpu.h>
+#include <x86/dbregs.h>
#include <x86/machdep.h>
#include <machine/multiboot.h>
@@ -237,6 +238,8 @@ int i386_use_fxsave;
int i386_has_sse;
int i386_has_sse2;
+struct pool x86_dbregspl;
+
vaddr_t idt_vaddr;
paddr_t idt_paddr;
vaddr_t gdt_vaddr;
@@ -508,7 +511,7 @@ i386_proc0_tss_ldt_init(void)
l->l_md.md_regs = (struct trapframe *)pcb->pcb_esp0 - 1;
memcpy(&pcb->pcb_fsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_fsd));
memcpy(&pcb->pcb_gsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_gsd));
- memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+ pcb->pcb_dbregs = NULL;
#ifndef XEN
lldt(pmap_kernel()->pm_ldt_sel);
@@ -841,8 +844,10 @@ setregs(struct lwp *l, struct exec_packa
memcpy(&pcb->pcb_fsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_fsd));
memcpy(&pcb->pcb_gsd, &gdtstore[GUDATA_SEL], sizeof(pcb->pcb_gsd));
-
- memset(l->l_md.md_watchpoint, 0, sizeof(*l->l_md.md_watchpoint));
+ if (pcb->pcb_dbregs != NULL) {
+ pool_put(&x86_dbregspl, pcb->pcb_dbregs);
+ pcb->pcb_dbregs = NULL;
+ }
tf = l->l_md.md_regs;
tf->tf_gs = GSEL(GUGS_SEL, SEL_UPL);
@@ -1089,6 +1094,7 @@ init386(paddr_t first_avail)
extern int biostramp_image_size;
extern u_char biostramp_image[];
#endif
+ struct pcb *pcb;
KASSERT(first_avail % PAGE_SIZE == 0);
@@ -1110,8 +1116,8 @@ init386(paddr_t first_avail)
use_pae = 0;
#endif
+ pcb = lwp_getpcb(&lwp0);
#ifdef XEN
- struct pcb *pcb = lwp_getpcb(&lwp0);
pcb->pcb_cr3 = PDPpaddr;
__PRINTK(("pcb_cr3 0x%lx cr3 0x%lx\n",
PDPpaddr, xpmap_ptom(PDPpaddr)));
@@ -1405,6 +1411,13 @@ init386(paddr_t first_avail)
rw_init(&svr4_fasttrap_lock);
pmc_init();
+
+ pcb->pcb_dbregs = NULL;
+
+ x86_dbregs_setup_initdbstate();
+
+ pool_init(&x86_dbregspl, sizeof(struct dbreg), 16, 0, 0, "dbregs",
+ NULL, IPL_NONE);
}
#include <dev/ic/mc146818reg.h> /* for NVRAM POST */
Index: src/sys/arch/i386/i386/process_machdep.c
diff -u src/sys/arch/i386/i386/process_machdep.c:1.88 src/sys/arch/i386/i386/process_machdep.c:1.89
--- src/sys/arch/i386/i386/process_machdep.c:1.88 Mon Jan 16 21:35:59 2017
+++ src/sys/arch/i386/i386/process_machdep.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.88 2017/01/16 21:35:59 kamil Exp $ */
+/* $NetBSD: process_machdep.c,v 1.89 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -44,25 +44,38 @@
* registers or privileged bits in the PSL.
* The process is stopped at the time write_regs is called.
*
+ * process_read_fpregs(proc, regs, sz)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_fpregs is called.
+ *
+ * process_write_fpregs(proc, regs, sz)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_fpregs is called.
+ *
+ * process_read_dbregs(proc, regs)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_dbregs is called.
+ *
+ * process_write_dbregs(proc, regs)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_dbregs is called.
+ *
* process_sstep(proc)
* Arrange for the process to trap after executing a single instruction.
*
* 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.88 2017/01/16 21:35:59 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.89 2017/02/23 03:34:22 kamil Exp $");
#include "opt_vm86.h"
#include "opt_ptrace.h"
@@ -140,6 +153,15 @@ process_read_fpregs(struct lwp *l, struc
return 0;
}
+int
+process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz)
+{
+
+ x86_dbregs_read(l, regs);
+
+ return 0;
+}
+
#ifdef PTRACE_HOOKS
int
process_write_regs(struct lwp *l, const struct reg *regs)
@@ -205,6 +227,22 @@ process_write_fpregs(struct lwp *l, cons
return 0;
}
+int
+process_write_dbregs(struct lwp *l, const struct dbreg *regs, size_t sz)
+{
+ int error;
+
+ /*
+ * Check for security violations.
+ */
+ error = x86_dbregs_validate(regs);
+ if (error != 0)
+ return error;
+
+ x86_dbregs_write(l, regs);
+
+ return 0;
+}
int
process_sstep(struct lwp *l, int sstep)
@@ -348,85 +386,3 @@ 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_type = PTRACE_PW_TYPE_DBREGS;
- 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_type != PTRACE_PW_TYPE_DBREGS)
- 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/i386/trap.c
diff -u src/sys/arch/i386/i386/trap.c:1.283 src/sys/arch/i386/i386/trap.c:1.284
--- src/sys/arch/i386/i386/trap.c:1.283 Fri Feb 17 01:14:31 2017
+++ src/sys/arch/i386/i386/trap.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,5 @@
-/* $NetBSD: trap.c,v 1.283 2017/02/17 01:14:31 kamil Exp $ */
+
+/* $NetBSD: trap.c,v 1.284 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000, 2005, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -68,7 +69,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.283 2017/02/17 01:14:31 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.284 2017/02/23 03:34:22 kamil Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@@ -251,7 +252,7 @@ trap(struct trapframe *frame)
struct trapframe *vframe;
ksiginfo_t ksi;
void *onfault;
- int type, error, wptnfo;
+ int type, error;
uint32_t cr2;
bool pfail;
@@ -681,6 +682,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 (x86_dbregs_user_trap())
+ break;
+
/* Check whether they single-stepped into a lcall. */
if (frame->tf_eip == (int)IDTVEC(osyscall))
return;
@@ -700,10 +714,9 @@ faultcommon:
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGTRAP;
ksi.ksi_trap = type & ~T_USER;
- if ((wptnfo = user_trap_x86_hw_watchpoint())) {
+ if (x86_dbregs_user_trap()) {
+ x86_dbregs_store_dr6(l);
ksi.ksi_code = TRAP_DBREG;
- ksi.ksi_trap2 = x86_hw_watchpoint_reg(wptnfo);
- ksi.ksi_trap3 = x86_hw_watchpoint_type(wptnfo);
} else if (type == (T_BPTFLT|T_USER))
ksi.ksi_code = TRAP_BRKPT;
else
Index: src/sys/arch/i386/include/pcb.h
diff -u src/sys/arch/i386/include/pcb.h:1.54 src/sys/arch/i386/include/pcb.h:1.55
--- src/sys/arch/i386/include/pcb.h:1.54 Mon Apr 21 19:13:22 2014
+++ src/sys/arch/i386/include/pcb.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: pcb.h,v 1.54 2014/04/21 19:13:22 christos Exp $ */
+/* $NetBSD: pcb.h,v 1.55 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1998, 2009 The NetBSD Foundation, Inc.
@@ -93,8 +93,9 @@ struct pcb {
int vm86_flagmask; /* flag mask for vm86 mode */
void *vm86_userp; /* XXX performance hack */
char *pcb_iomap; /* I/O permission bitmap */
+ struct dbreg *pcb_dbregs; /* CPU Debug Registers */
- int not_used[15];
+ int not_used[14];
/* floating point state */
struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */
Index: src/sys/arch/i386/include/proc.h
diff -u src/sys/arch/i386/include/proc.h:1.43 src/sys/arch/i386/include/proc.h:1.44
--- src/sys/arch/i386/include/proc.h:1.43 Thu Dec 15 12:04:18 2016
+++ src/sys/arch/i386/include/proc.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.43 2016/12/15 12:04:18 kamil Exp $ */
+/* $NetBSD: proc.h,v 1.44 2017/02/23 03:34:22 kamil Exp $ */
/*
* Copyright (c) 1991 Regents of the University of California.
@@ -50,12 +50,10 @@ 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_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.17 src/sys/arch/i386/include/ptrace.h:1.18
--- src/sys/arch/i386/include/ptrace.h:1.17 Mon Jan 16 21:35:59 2017
+++ src/sys/arch/i386/include/ptrace.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.17 2017/01/16 21:35:59 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.18 2017/02/23 03:34:22 kamil Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -86,9 +86,8 @@
/* The machine-dependent ptrace(2) requests. */
#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_GETDBREGS (PT_FIRSTMACH + 7)
+#define PT_SETDBREGS (PT_FIRSTMACH + 8)
#define PT_MACHDEP_STRINGS \
"PT_STEP", \
@@ -98,9 +97,9 @@
"PT_SETFPREGS", \
"PT_GETXMMREGS", \
"PT_SETXMMREGS", \
- "PT_READ_WATCHPOINT", \
- "PT_WRITE_WATCHPOINT", \
- "PT_COUNT_WATCHPOINTS"
+ "PT_GETDBREGS", \
+ "PT_SETDBREGS",
+
#include <machine/reg.h>
#define PTRACE_REG_PC(r) (r)->r_eip
@@ -112,50 +111,6 @@
#define PTRACE_BREAKPOINT_SIZE 1
#define PTRACE_BREAKPOINT_ADJ sizeof(PTRACE_BREAKPOINT)
-#define __HAVE_PTRACE_WATCHPOINTS
-
-/*
- * The current list of supported hardware watchpoints
- */
-#define PTRACE_PW_TYPE_DBREGS 1
-
-struct mdpw {
- union {
- /* Debug Registers DR0-3, DR6, DR7 */
- struct {
- void *_md_address;
- int _md_condition;
- int _md_length;
- } _dbregs;
- } _type;
-};
-
-/*
- * 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>
- *
- */
-
-#define md_address _type._dbregs._md_address
-#define md_condition _type._dbregs._md_condition
-#define md_length _type._dbregs._md_length
-
-
#ifdef _KERNEL
/*
Index: src/sys/arch/i386/include/reg.h
diff -u src/sys/arch/i386/include/reg.h:1.19 src/sys/arch/i386/include/reg.h:1.20
--- src/sys/arch/i386/include/reg.h:1.19 Wed Jan 16 09:37:08 2008
+++ src/sys/arch/i386/include/reg.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: reg.h,v 1.19 2008/01/16 09:37:08 ad Exp $ */
+/* $NetBSD: reg.h,v 1.20 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -107,4 +107,16 @@ struct xmmregs {
char __data[512];
};
+/*
+ * Debug Registers
+ *
+ * DR0-DR3 Debug Address Registers
+ * DR4-DR5 Reserved
+ * DR6 Debug Status Register
+ * DR7 Debug Control Register
+ */
+struct dbreg {
+ int dr[8];
+};
+
#endif /* !_I386_REG_H_ */
Index: src/sys/arch/i386/include/userret.h
diff -u src/sys/arch/i386/include/userret.h:1.13 src/sys/arch/i386/include/userret.h:1.14
--- src/sys/arch/i386/include/userret.h:1.13 Mon Jan 16 21:19:14 2017
+++ src/sys/arch/i386/include/userret.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: userret.h,v 1.13 2017/01/16 21:19:14 kamil Exp $ */
+/* $NetBSD: userret.h,v 1.14 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -74,15 +74,13 @@ static __inline void userret(struct lwp
static __inline void
userret(struct lwp *l)
{
+ struct pcb *pcb = lwp_getpcb(l);
/* Invoke MI userret code */
mi_userret(l);
- /*
- * Allow to mix debug registers with single step.
- */
- if (l->l_md.md_flags & MDL_X86_HW_WATCHPOINTS)
- set_x86_hw_watchpoints(l);
+ if (pcb->pcb_dbregs)
+ x86_dbregs_set(l);
else
- clear_x86_hw_watchpoints();
+ x86_dbregs_clear(l);
}
Index: src/sys/arch/x86/include/dbregs.h
diff -u src/sys/arch/x86/include/dbregs.h:1.3 src/sys/arch/x86/include/dbregs.h:1.4
--- src/sys/arch/x86/include/dbregs.h:1.3 Wed Jan 18 05:12:00 2017
+++ src/sys/arch/x86/include/dbregs.h Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dbregs.h,v 1.3 2017/01/18 05:12:00 kamil Exp $ */
+/* $NetBSD: dbregs.h,v 1.4 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,23 +30,22 @@
#ifndef _X86_DBREGS_H_
#define _X86_DBREGS_H_
-#if defined(_KERNEL)
-
#include <sys/param.h>
#include <sys/types.h>
+#include <machine/reg.h>
/*
* 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)
+#define X86_DR6_DR0_BREAKPOINT_CONDITION_DETECTED __BIT(0)
+#define X86_DR6_DR1_BREAKPOINT_CONDITION_DETECTED __BIT(1)
+#define X86_DR6_DR2_BREAKPOINT_CONDITION_DETECTED __BIT(2)
+#define X86_DR6_DR3_BREAKPOINT_CONDITION_DETECTED __BIT(3)
+#define X86_DR6_DEBUG_REGISTER_ACCESS_DETECTED __BIT(13)
+#define X86_DR6_SINGLE_STEP __BIT(14)
+#define X86_DR6_TASK_SWITCH __BIT(15)
/*
* CPU Debug Control Register (DR7)
@@ -57,108 +56,97 @@
*
* 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(_KERNEL) */
+#define X86_DR7_LOCAL_DR0_BREAKPOINT __BIT(0)
+#define X86_DR7_GLOBAL_DR0_BREAKPOINT __BIT(1)
+#define X86_DR7_LOCAL_DR1_BREAKPOINT __BIT(2)
+#define X86_DR7_GLOBAL_DR1_BREAKPOINT __BIT(3)
+#define X86_DR7_LOCAL_DR2_BREAKPOINT __BIT(4)
+#define X86_DR7_GLOBAL_DR2_BREAKPOINT __BIT(5)
+#define X86_DR7_LOCAL_DR3_BREAKPOINT __BIT(6)
+#define X86_DR7_GLOBAL_DR3_BREAKPOINT __BIT(7)
+#define X86_DR7_LOCAL_EXACT_BREAKPOINT __BIT(8)
+#define X86_DR7_GLOBAL_EXACT_BREAKPOINT __BIT(9)
+#define X86_DR7_RESTRICTED_TRANSACTIONAL_MEMORY __BIT(11)
+#define X86_DR7_GENERAL_DETECT_ENABLE __BIT(13)
+
+#define X86_DR7_DR0_CONDITION_MASK __BITS(16, 17)
+#define X86_DR7_DR0_LENGTH_MASK __BITS(18, 19)
+#define X86_DR7_DR1_CONDITION_MASK __BITS(20, 21)
+#define X86_DR7_DR1_LENGTH_MASK __BITS(22, 23)
+#define X86_DR7_DR2_CONDITION_MASK __BITS(24, 25)
+#define X86_DR7_DR2_LENGTH_MASK __BITS(26, 27)
+#define X86_DR7_DR3_CONDITION_MASK __BITS(28, 29)
+#define X86_DR7_DR3_LENGTH_MASK __BITS(30, 31)
/*
- * X86_HW_WATCHPOINT_DR7_CONDITION_IO_READWRITE is currently unused
+ * X86_DR7_CONDITION_IO_READWRITE is currently 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
+enum x86_dr7_condition {
+ X86_DR7_CONDITION_EXECUTION = 0x0,
+ X86_DR7_CONDITION_DATA_WRITE = 0x1,
+ X86_DR7_CONDITION_IO_READWRITE = 0x2,
+ X86_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,
+enum x86_dr7_length {
+ X86_DR7_LENGTH_BYTE = 0x0,
+ X86_DR7_LENGTH_TWOBYTES = 0x1,
/* 0x2 undefined */
- X86_HW_WATCHPOINT_DR7_LENGTH_FOURBYTES = 0x3
+ X86_DR7_LENGTH_FOURBYTES = 0x3
};
/*
- * 0x2 is currently unimplemented - it reflects 8 bytes on modern CPUs
+ * The number of available watchpoint/breakpoint registers available since
+ * Intel 80386. New CPUs (x86_64) ship with up to 16 Debug Registers but they
+ * still offer the same number of watchpoints/breakpoints.
*/
-enum x86_hw_watchpoint_event {
- X86_HW_WATCHPOINT_EVENT_NONE = 0x0,
- X86_HW_WATCHPOINT_EVENT_FIRED = 0x1,
- X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP = 0x2,
-};
-
-#if defined(_KMEMUSER) || defined(_KERNEL)
+#define X86_DBREGS 4
/*
- * 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
+ * Store the initial Debug Register state of CPU
+ * This copy will be used to initialize new debug register state
*/
-#define X86_HW_WATCHPOINTS 4
+void x86_dbregs_setup_initdbstate(void);
/*
- * lwpid - 0 means all LWPs in the process
- * address - 0 means that watchpoint is disabled
+ * Reset CPU Debug Registers - to be used after returning to user context
*/
-struct x86_hw_watchpoint {
- vaddr_t address;
- enum x86_hw_watchpoint_condition condition;
- enum x86_hw_watchpoint_length length;
-};
+void x86_dbregs_clear(struct lwp *l);
-#endif /* !defined(_KMEMUSER) && !defined(_KERNEL) */
+/*
+ * Retrieve Debug Registers from LWP's PCB and save in regs
+ * In case of empty register set, initialize it
+ */
+void x86_dbregs_read(struct lwp *l, struct dbreg *regs);
-#if defined(_KERNEL)
/*
* Set CPU Debug Registers - to be used before entering user-land context
*/
-void set_x86_hw_watchpoints(struct lwp *l);
+void x86_dbregs_set(struct lwp *l);
/*
- * Reset CPU Debug Registers - to be used after entering kernel context
+ * Store DR6 in LWP - to be used in trap function
*/
-void clear_x86_hw_watchpoints(void);
+void x86_dbregs_store_dr6(struct lwp *l);
/*
* Check if trap is triggered from user-land if so return nonzero value
*/
-int user_trap_x86_hw_watchpoint(void);
+int x86_dbregs_user_trap(void);
/*
* Check if trap is triggered from user-land if so return nonzero value
*/
-int x86_hw_watchpoint_type(int);
+int x86_dbregs_validate(const struct dbreg *regs);
/*
- * Return register that fired
+ * Write new Debug Registers from regs into LWP's PCB
*/
-int x86_hw_watchpoint_reg(int);
-
-#endif /* !defined(_KERNEL) */
+void x86_dbregs_write(struct lwp *l, const struct dbreg *regs);
#endif /* !_X86_DBREGS_H_ */
Index: src/sys/arch/x86/x86/dbregs.c
diff -u src/sys/arch/x86/x86/dbregs.c:1.4 src/sys/arch/x86/x86/dbregs.c:1.5
--- src/sys/arch/x86/x86/dbregs.c:1.4 Wed Jan 18 12:15:21 2017
+++ src/sys/arch/x86/x86/dbregs.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dbregs.c,v 1.4 2017/01/18 12:15:21 kamil Exp $ */
+/* $NetBSD: dbregs.c,v 1.5 2017/02/23 03:34:22 kamil Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -30,6 +30,7 @@
#include <sys/param.h>
#include <sys/types.h>
#include <sys/lwp.h>
+#include <sys/pool.h>
#include <x86/cpufunc.h>
#include <x86/dbregs.h>
@@ -38,129 +39,105 @@
#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;
- }
+extern struct pool x86_dbregspl;
- ldr7(dr);
-}
+static struct dbreg initdbstate;
void
-set_x86_hw_watchpoints(struct lwp *l)
+x86_dbregs_setup_initdbstate(void)
{
- size_t i;
-
- /* 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);
- }
- }
-}
+ /* DR0-DR3 should always be 0 */
+ initdbstate.dr[0] = rdr0();
+ initdbstate.dr[1] = rdr1();
+ initdbstate.dr[2] = rdr2();
+ initdbstate.dr[3] = rdr3();
+ /* DR4-DR5 are reserved - skip */
+ /* DR6 and DR7 contain predefined nonzero bits */
+ initdbstate.dr[6] = rdr6();
+ initdbstate.dr[7] = rdr7();
+ /* DR8-DR15 are reserved - skip */
+}
+
+#define X86_BREAKPOINT_CONDITION_DETECTED ( \
+ X86_DR6_DR0_BREAKPOINT_CONDITION_DETECTED | \
+ X86_DR6_DR1_BREAKPOINT_CONDITION_DETECTED | \
+ X86_DR6_DR2_BREAKPOINT_CONDITION_DETECTED | \
+ X86_DR6_DR3_BREAKPOINT_CONDITION_DETECTED )
+
+#define X86_GLOBAL_BREAKPOINT ( \
+ X86_DR7_GLOBAL_DR0_BREAKPOINT | \
+ X86_DR7_GLOBAL_DR1_BREAKPOINT | \
+ X86_DR7_GLOBAL_DR2_BREAKPOINT | \
+ X86_DR7_GLOBAL_DR3_BREAKPOINT )
void
-clear_x86_hw_watchpoints(void)
+x86_dbregs_clear(struct lwp *l)
{
+ struct pcb *pcb = lwp_getpcb(l);
+
+ KASSERT(pcb->pcb_dbregs == NULL);
/*
* 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));
+ ldr6(rdr6() & ~X86_BREAKPOINT_CONDITION_DETECTED);
+}
+
+void
+x86_dbregs_read(struct lwp *l, struct dbreg *regs)
+{
+ struct pcb *pcb = lwp_getpcb(l);
+
+ if (pcb->pcb_dbregs == NULL) {
+ pcb->pcb_dbregs = pool_get(&x86_dbregspl, PR_WAITOK);
+ memcpy(pcb->pcb_dbregs, &initdbstate, sizeof(initdbstate));
+ }
+ memcpy(regs, pcb->pcb_dbregs, sizeof(*regs));
}
-/* Local temporary bitfield concept to compose event and register that fired */
-#define DR_EVENT_MASK __BITS(7,0)
-#define DR_REGISTER_MASK __BITS(15,8)
+void
+x86_dbregs_set(struct lwp *l)
+{
+ struct pcb *pcb = lwp_getpcb(l);
+
+ KASSERT(pcb->pcb_dbregs != NULL);
+
+ ldr0(pcb->pcb_dbregs->dr[0]);
+ ldr1(pcb->pcb_dbregs->dr[1]);
+ ldr2(pcb->pcb_dbregs->dr[2]);
+ ldr3(pcb->pcb_dbregs->dr[3]);
+
+ ldr6(pcb->pcb_dbregs->dr[6]);
+ ldr7(pcb->pcb_dbregs->dr[7]);
+}
+
+void
+x86_dbregs_store_dr6(struct lwp *l)
+{
+ struct pcb *pcb = lwp_getpcb(l);
+
+ KASSERT(pcb->pcb_dbregs != NULL);
+
+ pcb->pcb_dbregs->dr[6] = rdr6();
+}
int
-user_trap_x86_hw_watchpoint(void)
+x86_dbregs_user_trap(void)
{
register_t dr7, dr6; /* debug registers dr6 and dr7 */
register_t bp; /* breakpoint bits extracted from dr6 */
- register_t dr; /* temporary value of dr0-dr3 */
- int rv; /* register and event that fired (if any) */
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) {
+ if ((dr7 & X86_GLOBAL_BREAKPOINT) == 0) {
/*
* all Global Breakpoint bits in the DR7 register are zero,
* thus the trap couldn't have been caused by the
@@ -170,11 +147,7 @@ user_trap_x86_hw_watchpoint(void)
}
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);
+ bp = dr6 & X86_BREAKPOINT_CONDITION_DETECTED;
if (!bp) {
/*
@@ -185,88 +158,56 @@ user_trap_x86_hw_watchpoint(void)
}
/*
- * Clear Status Register (DR6) now as it's not done by CPU.
- *
- * Clear BREAKPOINT_CONDITION_DETECTED and SINGLE_STEP 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 |
- X86_HW_WATCHPOINT_DR6_SINGLE_STEP));
-
- /*
* 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) {
- dr = rdr0();
- if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
- rv = 0;
- if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
- else
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
- return rv;
- }
-
- }
-
- if (bp & X86_HW_WATCHPOINT_DR6_DR1_BREAKPOINT_CONDITION_DETECTED) {
- dr = rdr1();
- if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
- rv = __SHIFTIN(1, DR_REGISTER_MASK);
- if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
- else
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
- return rv;
- }
-
- }
-
- if (bp & X86_HW_WATCHPOINT_DR6_DR2_BREAKPOINT_CONDITION_DETECTED) {
- dr = rdr2();
- if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
- rv = __SHIFTIN(2, DR_REGISTER_MASK);
- if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
- else
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
- return rv;
- }
-
- }
-
- if (bp & X86_HW_WATCHPOINT_DR6_DR3_BREAKPOINT_CONDITION_DETECTED) {
- dr = rdr3();
- if (dr < (vaddr_t)VM_MAXUSER_ADDRESS) {
- rv = __SHIFTIN(3, DR_REGISTER_MASK);
- if (bp & X86_HW_WATCHPOINT_DR6_SINGLE_STEP)
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED_AND_SSTEP;
- else
- rv |= X86_HW_WATCHPOINT_EVENT_FIRED;
- return rv;
- }
-
- }
+ if (bp & X86_DR6_DR0_BREAKPOINT_CONDITION_DETECTED)
+ if (rdr0() < (vaddr_t)VM_MAXUSER_ADDRESS)
+ return 1;
+
+ if (bp & X86_DR6_DR1_BREAKPOINT_CONDITION_DETECTED)
+ if (rdr1() < (vaddr_t)VM_MAXUSER_ADDRESS)
+ return 1;
+
+ if (bp & X86_DR6_DR2_BREAKPOINT_CONDITION_DETECTED)
+ if (rdr2() < (vaddr_t)VM_MAXUSER_ADDRESS)
+ return 1;
+
+ if (bp & X86_DR6_DR3_BREAKPOINT_CONDITION_DETECTED)
+ if (rdr3() < (vaddr_t)VM_MAXUSER_ADDRESS)
+ return 1;
return 0;
}
int
-x86_hw_watchpoint_type(int wptnfo)
+x86_dbregs_validate(const struct dbreg *regs)
{
+ size_t i;
+
+ /* Check that DR0-DR3 contain user-space address */
+ for (i = 0; i < X86_DBREGS; i++)
+ if (regs->dr[i] > (vaddr_t)VM_MAXUSER_ADDRESS)
+ return EINVAL;
+
+ /*
+ * Skip checks for reserved registers (DR4-DR5, DR8-DR15).
+ *
+ * Don't validate DR6-DR7 as some bits are set by hardware and a user
+ * cannot overwrite them.
+ */
- return __SHIFTOUT(wptnfo, DR_EVENT_MASK);
+ return 0;
}
-int
-x86_hw_watchpoint_reg(int wptnfo)
+void
+x86_dbregs_write(struct lwp *l, const struct dbreg *regs)
{
+ struct pcb *pcb = lwp_getpcb(l);
+
+ if (pcb->pcb_dbregs == NULL)
+ pcb->pcb_dbregs = pool_get(&x86_dbregspl, PR_WAITOK);
- return __SHIFTOUT(wptnfo, DR_REGISTER_MASK);
+ memcpy(pcb->pcb_dbregs, regs, sizeof(*regs));
}
Index: src/sys/arch/x86/x86/vm_machdep.c
diff -u src/sys/arch/x86/x86/vm_machdep.c:1.27 src/sys/arch/x86/x86/vm_machdep.c:1.28
--- src/sys/arch/x86/x86/vm_machdep.c:1.27 Thu Dec 15 12:04:18 2016
+++ src/sys/arch/x86/x86/vm_machdep.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: vm_machdep.c,v 1.27 2016/12/15 12:04:18 kamil Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.28 2017/02/23 03:34:22 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.27 2016/12/15 12:04:18 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.28 2017/02/23 03:34:22 kamil Exp $");
#include "opt_mtrr.h"
@@ -105,6 +105,9 @@ __KERNEL_RCSID(0, "$NetBSD: vm_machdep.c
#endif
#include <x86/fpu.h>
+#include <x86/dbregs.h>
+
+extern struct pool x86_dbregspl;
void
cpu_proc_fork(struct proc *p1, struct proc *p2)
@@ -157,6 +160,9 @@ cpu_lwp_fork(struct lwp *l1, struct lwp
/* Copy any additional fpu state */
fpu_save_area_fork(pcb2, pcb1);
+ /* Never inherit CPU Debug Registers */
+ pcb2->pcb_dbregs = NULL;
+
#if defined(XEN)
pcb2->pcb_iopl = SEL_KPL;
#endif
@@ -231,12 +237,6 @@ 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));
}
/*
@@ -270,9 +270,17 @@ cpu_lwp_free(struct lwp *l, int proc)
void
cpu_lwp_free2(struct lwp *l)
{
+ struct pcb *pcb;
KASSERT(l->l_md.md_gc_ptp == NULL);
KASSERT(l->l_md.md_gc_pmap == NULL);
+
+ pcb = lwp_getpcb(l);
+
+ if (pcb->pcb_dbregs) {
+ pool_put(&x86_dbregspl, pcb->pcb_dbregs);
+ pcb->pcb_dbregs = NULL;
+ }
}
/*
Index: src/sys/compat/netbsd32/netbsd32_ptrace.c
diff -u src/sys/compat/netbsd32/netbsd32_ptrace.c:1.3 src/sys/compat/netbsd32/netbsd32_ptrace.c:1.4
--- src/sys/compat/netbsd32/netbsd32_ptrace.c:1.3 Thu Dec 15 12:04:18 2016
+++ src/sys/compat/netbsd32/netbsd32_ptrace.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_ptrace.c,v 1.3 2016/12/15 12:04:18 kamil Exp $ */
+/* $NetBSD: netbsd32_ptrace.c,v 1.4 2017/02/23 03:34:22 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.3 2016/12/15 12:04:18 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.4 2017/02/23 03:34:22 kamil Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ptrace.h"
@@ -58,8 +58,7 @@ 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 netbsd32_dodbregs(struct lwp *, struct lwp *, struct uio *);
static int
@@ -168,13 +167,41 @@ netbsd32_dofpregs(struct lwp *curl /*tra
}
static int
-netbsd32_dowatchpoint(struct lwp *curl /*tracer*/, struct lwp *l /*traced*/,
- int write, struct ptrace_watchpoint *pw, void *addr, register_t *retval)
+netbsd32_dodbregs(struct lwp *curl /*tracer*/,
+ struct lwp *l /*traced*/,
+ struct uio *uio)
{
+#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS)
+ process_dbreg32 r32;
+ int error;
+ char *kv;
+ size_t kl;
- /* unimplemented */
+ KASSERT(l->l_proc->p_flag & PK_32);
+ if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r32))
+ return EINVAL;
+ kl = sizeof(r32);
+ kv = (char *)&r32;
+
+ kv += uio->uio_offset;
+ kl -= uio->uio_offset;
+ if (kl > uio->uio_resid)
+ kl = uio->uio_resid;
+ error = process_read_dbregs32(l, &r32, &kl);
+ if (error == 0)
+ error = uiomove(kv, kl, uio);
+ if (error == 0 && uio->uio_rw == UIO_WRITE) {
+ if (l->l_stat != LSSTOP)
+ error = EBUSY;
+ else
+ error = process_write_dbregs32(l, &r32, kl);
+ }
+ uio->uio_offset = 0;
+ return error;
+#else
return EINVAL;
+#endif
}
static struct ptrace_methods netbsd32_ptm = {
@@ -182,7 +209,7 @@ static struct ptrace_methods netbsd32_pt
.ptm_copyoutpiod = netbsd32_copyoutpiod,
.ptm_doregs = netbsd32_doregs,
.ptm_dofpregs = netbsd32_dofpregs,
- .ptm_dowatchpoint = netbsd32_dowatchpoint
+ .ptm_dodbregs = netbsd32_dodbregs
};
Index: src/sys/kern/sys_ptrace.c
diff -u src/sys/kern/sys_ptrace.c:1.3 src/sys/kern/sys_ptrace.c:1.4
--- src/sys/kern/sys_ptrace.c:1.3 Thu Dec 15 12:04:18 2016
+++ src/sys/kern/sys_ptrace.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_ptrace.c,v 1.3 2016/12/15 12:04:18 kamil Exp $ */
+/* $NetBSD: sys_ptrace.c,v 1.4 2017/02/23 03:34:22 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.3 2016/12/15 12:04:18 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.4 2017/02/23 03:34:22 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -169,7 +169,7 @@ static struct ptrace_methods native_ptm
.ptm_copyoutpiod = ptrace_copyoutpiod,
.ptm_doregs = process_doregs,
.ptm_dofpregs = process_dofpregs,
- .ptm_dowatchpoint = process_dowatchpoint,
+ .ptm_dodbregs = process_dodbregs,
};
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.16 src/sys/kern/sys_ptrace_common.c:1.17
--- src/sys/kern/sys_ptrace_common.c:1.16 Thu Feb 23 00:50:09 2017
+++ src/sys/kern/sys_ptrace_common.c Thu Feb 23 03:34:22 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_ptrace_common.c,v 1.16 2017/02/23 00:50:09 kamil Exp $ */
+/* $NetBSD: sys_ptrace_common.c,v 1.17 2017/02/23 03:34:22 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.16 2017/02/23 00:50:09 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.17 2017/02/23 03:34:22 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -202,10 +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:
+#ifdef PT_GETDBREGS
+ case PT_GETDBREGS:
+#endif
+#ifdef PT_SETDBREGS
+ case PT_SETDBREGS:
#endif
case PT_SET_EVENT_MASK:
case PT_GET_EVENT_MASK:
@@ -307,9 +308,6 @@ do_ptrace(struct ptrace_methods *ptm, st
struct ptrace_state ps;
struct ptrace_lwpinfo pl;
struct ptrace_siginfo psi;
-#ifdef __HAVE_PTRACE_WATCHPOINTS
- struct ptrace_watchpoint pw;
-#endif
struct vmspace *vm;
int error, write, tmp, pheld;
int signo = 0;
@@ -424,10 +422,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:
+#ifdef PT_GETDBREGS
+ case PT_GETDBREGS:
+#endif
+#ifdef PT_SETDBREGS
+ case PT_SETDBREGS:
#endif
#ifdef __HAVE_PTRACE_MACHDEP
PTRACE_MACHDEP_REQUEST_CASES
@@ -1226,29 +1225,17 @@ 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:
+#ifdef PT_SETDBREGS
+ case PT_SETDBREGS:
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;
+ /*FALLTHROUGH*/
+#endif
+#ifdef PT_GETDBREGS
+ case PT_GETDBREGS:
+ /* write = 0 done above. */
+#endif
+#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
+ tmp = data;
if (tmp != 0 && t->p_nlwps > 1) {
lwp_delref(lt);
mutex_enter(t->p_lock);
@@ -1261,15 +1248,23 @@ do_ptrace(struct ptrace_methods *ptm, st
lwp_addref(lt);
mutex_exit(t->p_lock);
}
- ++write;
- case PT_COUNT_WATCHPOINTS:
- if (!process_validwatchpoint(lt))
+ if (!process_validdbregs(lt))
error = EINVAL;
else {
- lwp_lock(lt);
- error = ptm->ptm_dowatchpoint(l, lt, write, &pw, addr,
- retval);
- lwp_unlock(lt);
+ error = proc_vmspace_getref(p, &vm);
+ if (error)
+ break;
+ iov.iov_base = addr;
+ iov.iov_len = PROC_DBREGSZ(p);
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = iov.iov_len;
+ uio.uio_rw = write ? UIO_WRITE : UIO_READ;
+ uio.uio_vmspace = vm;
+
+ error = ptm->ptm_dodbregs(l, lt, &uio);
+ uvmspace_free(vm);
}
break;
#endif
@@ -1391,6 +1386,55 @@ process_validfpregs(struct lwp *l)
#endif
}
+int
+process_dodbregs(struct lwp *curl /*tracer*/,
+ struct lwp *l /*traced*/,
+ struct uio *uio)
+{
+#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS)
+ int error;
+ struct dbreg r;
+ char *kv;
+ size_t kl;
+
+ if (uio->uio_offset < 0 || uio->uio_offset > (off_t)sizeof(r))
+ return EINVAL;
+
+ kl = sizeof(r);
+ kv = (char *)&r;
+
+ kv += uio->uio_offset;
+ kl -= uio->uio_offset;
+ if (kl > uio->uio_resid)
+ kl = uio->uio_resid;
+
+ error = process_read_dbregs(l, &r, &kl);
+ if (error == 0)
+ error = uiomove(kv, kl, uio);
+ if (error == 0 && uio->uio_rw == UIO_WRITE) {
+ if (l->l_stat != LSSTOP)
+ error = EBUSY;
+ else
+ error = process_write_dbregs(l, &r, kl);
+ }
+ uio->uio_offset = 0;
+ return error;
+#else
+ return EINVAL;
+#endif
+}
+
+int
+process_validdbregs(struct lwp *l)
+{
+
+#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
+ return (l->l_flag & LW_SYSTEM) == 0;
+#else
+ return 0;
+#endif
+}
+
static int
process_auxv_offset(struct proc *p, struct uio *uio)
{
@@ -1416,45 +1460,6 @@ 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, "");
Index: src/sys/sys/proc.h
diff -u src/sys/sys/proc.h:1.337 src/sys/sys/proc.h:1.338
--- src/sys/sys/proc.h:1.337 Sat Jan 14 06:36:52 2017
+++ src/sys/sys/proc.h Thu Feb 23 03:34:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.337 2017/01/14 06:36:52 kamil Exp $ */
+/* $NetBSD: proc.h,v 1.338 2017/02/23 03:34:23 kamil Exp $ */
/*-
* Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -573,6 +573,8 @@ _proclist_skipmarker(struct proc *p0)
sizeof(process_reg32) : sizeof(struct reg))
#define PROC_FPREGSZ(p) (((p)->p_flag & PK_32) ? \
sizeof(process_fpreg32) : sizeof(struct fpreg))
+#define PROC_DBREGSZ(p) (((p)->p_flag & PK_32) ? \
+ sizeof(process_dbreg32) : sizeof(struct dbreg))
/*
* PROCLIST_FOREACH: iterate on the given proclist, skipping PK_MARKER ones.
Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.57 src/sys/sys/ptrace.h:1.58
--- src/sys/sys/ptrace.h:1.57 Wed Feb 22 23:43:43 2017
+++ src/sys/sys/ptrace.h Thu Feb 23 03:34:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.57 2017/02/22 23:43:43 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.58 2017/02/23 03:34:23 kamil Exp $ */
/*-
* Copyright (c) 1984, 1993
@@ -144,20 +144,6 @@ struct ptrace_lwpinfo {
#define PL_EVENT_SUSPENDED 2
/*
- * 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 */
- int pw_type; /* HW Watchpoint type w/ MD content */
-#ifdef __HAVE_PTRACE_WATCHPOINTS
- struct mdpw pw_md; /* MD fields */
-#endif
-} ptrace_watchpoint_t;
-
-/*
* Signal Information structure
*/
typedef struct ptrace_siginfo {
@@ -178,6 +164,7 @@ struct reg;
#define process_reg64 struct reg
#endif
#endif
+
#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
struct fpreg;
#ifndef process_fpreg32
@@ -187,12 +174,14 @@ struct fpreg;
#define process_fpreg64 struct fpreg
#endif
#endif
-#ifdef __HAVE_PTRACE_WATCHPOINTS
-#ifndef process_watchpoint32
-#define process_watchpoint32 struct ptrace_watchpoint
+
+#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS)
+struct fpreg;
+#ifndef process_dbreg32
+#define process_dbreg32 struct dbreg
#endif
-#ifndef process_watchpoint64
-#define process_watchpoint64 struct ptrace_watchpoint
+#ifndef process_dbreg64
+#define process_dbreg64 struct dbreg
#endif
#endif
@@ -201,8 +190,7 @@ struct ptrace_methods {
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 (*ptm_dodbregs)(struct lwp *, struct lwp *, struct uio *);
};
int ptrace_init(void);
@@ -215,9 +203,8 @@ 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_dodbregs(struct lwp *, struct lwp *, struct uio *);
+int process_validdbregs(struct lwp *);
int process_domem(struct lwp *, struct lwp *, struct uio *);
@@ -235,6 +222,15 @@ int do_ptrace(struct ptrace_methods *, s
* will #define process_read_regs32 to netbsd32_process_read_regs (etc).
* In all other cases these #defines drop the size suffix.
*/
+#ifdef PT_GETDBREGS
+int process_read_dbregs(struct lwp *, struct dbreg *, size_t *);
+#ifndef process_read_dbregs32
+#define process_read_dbregs32 process_read_dbregs
+#endif
+#ifndef process_read_dbregs64
+#define process_read_dbregs64 process_read_dbregs
+#endif
+#endif
#ifdef PT_GETFPREGS
int process_read_fpregs(struct lwp *, struct fpreg *, size_t *);
#ifndef process_read_fpregs32
@@ -255,6 +251,15 @@ int process_read_regs(struct lwp *, stru
#endif
int process_set_pc(struct lwp *, void *);
int process_sstep(struct lwp *, int);
+#ifdef PT_SETDBREGS
+int process_write_dbregs(struct lwp *, const struct dbreg *, size_t);
+#ifndef process_write_dbregs32
+#define process_write_dbregs32 process_write_dbregs
+#endif
+#ifndef process_write_dbregs64
+#define process_write_dbregs64 process_write_dbregs
+#endif
+#endif
#ifdef PT_SETFPREGS
int process_write_fpregs(struct lwp *, const struct fpreg *, size_t);
#ifndef process_write_fpregs32
@@ -274,32 +279,6 @@ 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
-
int ptrace_machdep_dorequest(struct lwp *, struct lwp *, int,
void *, int);