Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Introduce PT_GETDBREGS and PT_SETDBREGS in ptrace(2) on i386...
details: https://anonhg.NetBSD.org/src/rev/92604985a10d
branches: trunk
changeset: 351702:92604985a10d
user: kamil <kamil%NetBSD.org@localhost>
date: Thu Feb 23 03:34:22 2017 +0000
description:
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>
diffstat:
distrib/sets/lists/comp/md.amd64 | 4 +-
distrib/sets/lists/comp/md.i386 | 4 +-
sys/arch/amd64/amd64/machdep.c | 24 +-
sys/arch/amd64/amd64/netbsd32_machdep.c | 58 +++++-
sys/arch/amd64/amd64/process_machdep.c | 143 +++++----------
sys/arch/amd64/amd64/trap.c | 13 +-
sys/arch/amd64/include/netbsd32_machdep.h | 8 +-
sys/arch/amd64/include/pcb.h | 6 +-
sys/arch/amd64/include/proc.h | 4 +-
sys/arch/amd64/include/ptrace.h | 64 +------
sys/arch/amd64/include/reg.h | 15 +-
sys/arch/amd64/include/userret.h | 12 +-
sys/arch/i386/i386/machdep.c | 25 ++-
sys/arch/i386/i386/process_machdep.c | 142 +++++----------
sys/arch/i386/i386/trap.c | 25 ++-
sys/arch/i386/include/pcb.h | 5 +-
sys/arch/i386/include/proc.h | 4 +-
sys/arch/i386/include/ptrace.h | 57 +-----
sys/arch/i386/include/reg.h | 14 +-
sys/arch/i386/include/userret.h | 12 +-
sys/arch/x86/include/dbregs.h | 138 ++++++--------
sys/arch/x86/x86/dbregs.c | 273 +++++++++++------------------
sys/arch/x86/x86/vm_machdep.c | 24 +-
sys/compat/netbsd32/netbsd32_ptrace.c | 43 +++-
sys/kern/sys_ptrace.c | 6 +-
sys/kern/sys_ptrace_common.c | 167 +++++++++--------
sys/sys/proc.h | 4 +-
sys/sys/ptrace.h | 81 +++-----
28 files changed, 629 insertions(+), 746 deletions(-)
diffs (truncated from 2357 to 300 lines):
diff -r c30ebb0069d9 -r 92604985a10d distrib/sets/lists/comp/md.amd64
--- a/distrib/sets/lists/comp/md.amd64 Thu Feb 23 02:28:10 2017 +0000
+++ b/distrib/sets/lists/comp/md.amd64 Thu Feb 23 03:34:22 2017 +0000
@@ -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
diff -r c30ebb0069d9 -r 92604985a10d distrib/sets/lists/comp/md.i386
--- a/distrib/sets/lists/comp/md.i386 Thu Feb 23 02:28:10 2017 +0000
+++ b/distrib/sets/lists/comp/md.i386 Thu Feb 23 03:34:22 2017 +0000
@@ -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
diff -r c30ebb0069d9 -r 92604985a10d sys/arch/amd64/amd64/machdep.c
--- a/sys/arch/amd64/amd64/machdep.c Thu Feb 23 02:28:10 2017 +0000
+++ b/sys/arch/amd64/amd64/machdep.c Thu Feb 23 03:34:22 2017 +0000
@@ -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 @@
#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 (*initclock_func)(void) = xen_initclocks;
#endif
+struct pool x86_dbregspl;
/*
* Size of memory segments, before any memory is stolen.
@@ -469,11 +471,11 @@
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 @@
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 @@
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 @@
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 @@
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
diff -r c30ebb0069d9 -r 92604985a10d sys/arch/amd64/amd64/netbsd32_machdep.c
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c Thu Feb 23 02:28:10 2017 +0000
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c Thu Feb 23 03:34:22 2017 +0000
@@ -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 @@
#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 @@
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 @@
}
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 @@
}
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)
{
/* {
diff -r c30ebb0069d9 -r 92604985a10d sys/arch/amd64/amd64/process_machdep.c
--- a/sys/arch/amd64/amd64/process_machdep.c Thu Feb 23 02:28:10 2017 +0000
+++ b/sys/arch/amd64/amd64/process_machdep.c Thu Feb 23 03:34:22 2017 +0000
@@ -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 @@
}
int
+process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz)
+{
+
+ x86_dbregs_read(l, regs);
+
Home |
Main Index |
Thread Index |
Old Index