Module Name:    src
Committed By:   pgoyette
Date:           Wed Nov  2 00:12:00 UTC 2016

Modified Files:
        src/sys/arch/i386/conf: INSTALL_FLOPPY
        src/sys/arch/i386/i386: process_machdep.c
        src/sys/arch/sh3/include: userret.h
        src/sys/arch/sh3/sh3: exception_vector.S process_machdep.c
            sh3_machdep.c
        src/sys/compat/netbsd32: netbsd32_ptrace.c
        src/sys/conf: files std
        src/sys/kern: files.kern init_main.c kern_stub.c sys_process.c
            syscalls.master
        src/sys/miscfs/procfs: files.procfs
        src/sys/modules: Makefile
        src/sys/sys: ptrace.h
Added Files:
        src/sys/kern: sys_ptrace.c sys_ptrace_common.c
        src/sys/modules/ptrace: Makefile
        src/sys/modules/ptrace_common: Makefile

Log Message:
* Split sys/kern/sys_process.c into three parts:
        1 - ptrace(2) syscall for native emulation
        2 - common ptrace(2) syscall code (shared with compat_netbsd32)
        3 - support routines that are shared with PROCFS and/or KTRACE

* Add module glue for #1 and #2.  Both modules will be built-in to the
  kernel if "options PTRACE" is included in the config file (this is
  the default, defined in sys/conf/std).

* Mark the ptrace(2) syscall as modular in syscalls.master (generated
  files will be committed shortly).

* Conditionalize all remaining portions of PTRACE code on a new kernel
  option PTRACE_HOOKS.

XXX Instead of PROCFS depending on 'options PTRACE', we should probably
    just add a procfs attribute to the sys/kern/sys_process.c file's
    entry in files.kern, and add PROCFS to the "#if defineds" for
    process_domem().  It's really confusing to have two different ways
    of requiring this file.


To generate a diff of this commit:
cvs rdiff -u -r1.29 -r1.30 src/sys/arch/i386/conf/INSTALL_FLOPPY
cvs rdiff -u -r1.85 -r1.86 src/sys/arch/i386/i386/process_machdep.c
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/sh3/include/userret.h
cvs rdiff -u -r1.49 -r1.50 src/sys/arch/sh3/sh3/exception_vector.S
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/sh3/sh3/process_machdep.c
cvs rdiff -u -r1.103 -r1.104 src/sys/arch/sh3/sh3/sh3_machdep.c
cvs rdiff -u -r1.1 -r1.2 src/sys/compat/netbsd32/netbsd32_ptrace.c
cvs rdiff -u -r1.1165 -r1.1166 src/sys/conf/files
cvs rdiff -u -r1.21 -r1.22 src/sys/conf/std
cvs rdiff -u -r1.12 -r1.13 src/sys/kern/files.kern
cvs rdiff -u -r1.483 -r1.484 src/sys/kern/init_main.c
cvs rdiff -u -r1.42 -r1.43 src/sys/kern/kern_stub.c
cvs rdiff -u -r1.174 -r1.175 src/sys/kern/sys_process.c
cvs rdiff -u -r0 -r1.1 src/sys/kern/sys_ptrace.c \
    src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.285 -r1.286 src/sys/kern/syscalls.master
cvs rdiff -u -r1.9 -r1.10 src/sys/miscfs/procfs/files.procfs
cvs rdiff -u -r1.181 -r1.182 src/sys/modules/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/modules/ptrace/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/modules/ptrace_common/Makefile
cvs rdiff -u -r1.47 -r1.48 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/sys/arch/i386/conf/INSTALL_FLOPPY
diff -u src/sys/arch/i386/conf/INSTALL_FLOPPY:1.29 src/sys/arch/i386/conf/INSTALL_FLOPPY:1.30
--- src/sys/arch/i386/conf/INSTALL_FLOPPY:1.29	Sat Sep 26 11:16:12 2015
+++ src/sys/arch/i386/conf/INSTALL_FLOPPY	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-#	$NetBSD: INSTALL_FLOPPY,v 1.29 2015/09/26 11:16:12 maxv Exp $
+#	$NetBSD: INSTALL_FLOPPY,v 1.30 2016/11/02 00:11:59 pgoyette Exp $
 #
 #	INSTALL - Installation kernel.
 #
@@ -64,6 +64,7 @@ options 	PIPE_SOCKETPAIR		# smaller, but
 no options 	EXEC_AOUT
 
 no options 	RFC2292		# Previous version of Adv. Sockets API for IPv6
+no options	PTRACE_HOOKS
 no options 	PTRACE		# Include ptrace(2)
 
 # Diagnostic/debugging support options

Index: src/sys/arch/i386/i386/process_machdep.c
diff -u src/sys/arch/i386/i386/process_machdep.c:1.85 src/sys/arch/i386/i386/process_machdep.c:1.86
--- src/sys/arch/i386/i386/process_machdep.c:1.85	Wed Feb 19 21:23:01 2014
+++ src/sys/arch/i386/i386/process_machdep.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: process_machdep.c,v 1.85 2014/02/19 21:23:01 dsl Exp $	*/
+/*	$NetBSD: process_machdep.c,v 1.86 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -52,7 +52,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.85 2014/02/19 21:23:01 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.86 2016/11/02 00:11:59 pgoyette Exp $");
 
 #include "opt_vm86.h"
 #include "opt_ptrace.h"
@@ -129,7 +129,7 @@ process_read_fpregs(struct lwp *l, struc
 	return 0;
 }
 
-#ifdef PTRACE
+#ifdef PTRACE_HOOKS
 int
 process_write_regs(struct lwp *l, const struct reg *regs)
 {
@@ -336,4 +336,4 @@ process_machdep_validxmmregs(struct proc
 	return (i386_use_fxsave);
 }
 #endif /* __HAVE_PTRACE_MACHDEP */
-#endif /* PTRACE */
+#endif /* PTRACE_HOOKS */

Index: src/sys/arch/sh3/include/userret.h
diff -u src/sys/arch/sh3/include/userret.h:1.13 src/sys/arch/sh3/include/userret.h:1.14
--- src/sys/arch/sh3/include/userret.h:1.13	Sun Jul  8 20:14:11 2012
+++ src/sys/arch/sh3/include/userret.h	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: userret.h,v 1.13 2012/07/08 20:14:11 dsl Exp $	*/
+/*	$NetBSD: userret.h,v 1.14 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*
  * Copyright (c) 1988 University of Utah.
@@ -54,7 +54,7 @@ userret(struct lwp *l)
 	/* Invoke MI userret code */
 	mi_userret(l);
 
-#ifdef PTRACE
+#ifdef PTRACE_HOOKS
 	/* Check if lwp is being PT_STEP'ed */
 	if (l->l_md.md_flags & MDL_SSTEP) {
 		struct trapframe *tf = l->l_md.md_regs;
@@ -75,7 +75,7 @@ userret(struct lwp *l)
 		}
 #endif
 	}
-#endif /* PTRACE */
+#endif /* PTRACE_HOOKS */
 }
 
 #endif /* !_SH3_USERRET_H_ */

Index: src/sys/arch/sh3/sh3/exception_vector.S
diff -u src/sys/arch/sh3/sh3/exception_vector.S:1.49 src/sys/arch/sh3/sh3/exception_vector.S:1.50
--- src/sys/arch/sh3/sh3/exception_vector.S:1.49	Fri Feb  4 04:14:25 2011
+++ src/sys/arch/sh3/sh3/exception_vector.S	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: exception_vector.S,v 1.49 2011/02/04 04:14:25 uwe Exp $	*/
+/*	$NetBSD: exception_vector.S,v 1.50 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
 #define _ALIGN_TEXT	.align 5
 #include <sh3/asm.h>
 
-__KERNEL_RCSID(0, "$NetBSD: exception_vector.S,v 1.49 2011/02/04 04:14:25 uwe Exp $")
+__KERNEL_RCSID(0, "$NetBSD: exception_vector.S,v 1.50 2016/11/02 00:11:59 pgoyette Exp $")
 
 
 /*
@@ -98,7 +98,7 @@ NENTRY(sh_vector_generic)
 
 	/* general_exception(curlwp, tf, TEA); */
 1:	mov	r4, r8
-#if defined(PTRACE) || defined(DDB)
+#if defined(PTRACE_HOOKS) || defined(DDB)
 	mov	#0, r2
 	MOV	(BBRA, r1)
 	mov.l	r2, @(TF_UBC, r14)	/* clear tf->tf_ubc */
@@ -115,7 +115,7 @@ NENTRY(sh_vector_generic)
 	jsr	@r0
 	 mov	r14, r5
 
-#if defined(PTRACE) || defined(DDB)
+#if defined(PTRACE_HOOKS) || defined(DDB)
 	mov.l	@(TF_UBC, r14), r2
 	tst	r2, r2			! single-step == 0?
 	bt	.Lg_return_from_exception

Index: src/sys/arch/sh3/sh3/process_machdep.c
diff -u src/sys/arch/sh3/sh3/process_machdep.c:1.20 src/sys/arch/sh3/sh3/process_machdep.c:1.21
--- src/sys/arch/sh3/sh3/process_machdep.c:1.20	Sun Jul  8 20:14:12 2012
+++ src/sys/arch/sh3/sh3/process_machdep.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: process_machdep.c,v 1.20 2012/07/08 20:14:12 dsl Exp $	*/
+/*	$NetBSD: process_machdep.c,v 1.21 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*
  * Copyright (c) 1993 The Regents of the University of California.
@@ -77,7 +77,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.20 2012/07/08 20:14:12 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.21 2016/11/02 00:11:59 pgoyette Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -101,7 +101,7 @@ static int process_machdep_write_regs40(
 #endif /* COMPAT_40 */
 
 
-#if defined(PTRACE) || defined(COREDUMP)
+#if defined(PTRACE_HOOKS) || defined(COREDUMP)
 
 static inline struct trapframe *
 process_frame(struct lwp *l)
@@ -141,10 +141,10 @@ process_read_regs(struct lwp *l, struct 
 	return (0);
 }
 
-#endif /* PTRACE || COREDUMP */
+#endif /* PTRACE_HOOKS || COREDUMP */
 
 
-#ifdef PTRACE
+#ifdef PTRACE_HOOKS
 
 int
 process_write_regs(struct lwp *l, const struct reg *regs)
@@ -360,4 +360,4 @@ process_set_pc(struct lwp *l, void *addr
 	return (0);
 }
 
-#endif /* PTRACE */
+#endif /* PTRACE_HOOKS */

Index: src/sys/arch/sh3/sh3/sh3_machdep.c
diff -u src/sys/arch/sh3/sh3/sh3_machdep.c:1.103 src/sys/arch/sh3/sh3/sh3_machdep.c:1.104
--- src/sys/arch/sh3/sh3/sh3_machdep.c:1.103	Sun Nov 22 18:44:25 2015
+++ src/sys/arch/sh3/sh3/sh3_machdep.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: sh3_machdep.c,v 1.103 2015/11/22 18:44:25 tsutsui Exp $	*/
+/*	$NetBSD: sh3_machdep.c,v 1.104 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 2002 The NetBSD Foundation, Inc.
@@ -65,7 +65,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.103 2015/11/22 18:44:25 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sh3_machdep.c,v 1.104 2016/11/02 00:11:59 pgoyette Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -194,7 +194,7 @@ sh_cpu_init(int arch, int product)
 	uvm_setpagesize();
 
 	/* setup UBC channel A for single-stepping */
-#if defined(PTRACE) || defined(DDB)
+#if defined(PTRACE_HOOKS) || defined(DDB)
 	_reg_write_2(SH_(BBRA), 0); /* disable channel A */
 	_reg_write_2(SH_(BBRB), 0); /* disable channel B */
 

Index: src/sys/compat/netbsd32/netbsd32_ptrace.c
diff -u src/sys/compat/netbsd32/netbsd32_ptrace.c:1.1 src/sys/compat/netbsd32/netbsd32_ptrace.c:1.2
--- src/sys/compat/netbsd32/netbsd32_ptrace.c:1.1	Wed Oct 19 09:44:01 2016
+++ src/sys/compat/netbsd32/netbsd32_ptrace.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_ptrace.c,v 1.1 2016/10/19 09:44:01 skrll Exp $	*/
+/*	$NetBSD: netbsd32_ptrace.c,v 1.2 2016/11/02 00:11:59 pgoyette 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.1 2016/10/19 09:44:01 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ptrace.c,v 1.2 2016/11/02 00:11:59 pgoyette Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ptrace.h"
@@ -193,7 +193,9 @@ static const struct syscall_package comp
 	{ 0, 0, NULL },
 };
 
-MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, "compat_netbsd32");
+#define	DEPS	"compat_netbsd32,ptrace_common"
+
+MODULE(MODULE_CLASS_EXEC, compat_netbsd32_ptrace, DEPS);
 
 static int
 compat_netbsd32_ptrace_modcmd(modcmd_t cmd, void *arg)

Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1165 src/sys/conf/files:1.1166
--- src/sys/conf/files:1.1165	Tue Nov  1 22:54:33 2016
+++ src/sys/conf/files	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-#	$NetBSD: files,v 1.1165 2016/11/01 22:54:33 pgoyette Exp $
+#	$NetBSD: files,v 1.1166 2016/11/02 00:11:59 pgoyette Exp $
 #	@(#)files.newconf	7.5 (Berkeley) 5/10/93
 
 version 	20150846
@@ -21,7 +21,7 @@ defparam opt_param.h		MAXUSERS
 defflag				INSECURE
 defflag				KTRACE
 defflag				MBUFTRACE
-defflag				PTRACE
+defflag	opt_ptrace.h		PTRACE PTRACE_HOOKS
 defflag				COREDUMP
 defflag	opt_modular.h		MODULAR
 defflag	opt_modular.h		MODULAR_DEFAULT_AUTOLOAD

Index: src/sys/conf/std
diff -u src/sys/conf/std:1.21 src/sys/conf/std:1.22
--- src/sys/conf/std:1.21	Sat Nov 14 07:31:13 2015
+++ src/sys/conf/std	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-# $NetBSD: std,v 1.21 2015/11/14 07:31:13 pgoyette Exp $
+# $NetBSD: std,v 1.22 2016/11/02 00:11:59 pgoyette Exp $
 #
 # standard MI 'options'
 #
@@ -27,7 +27,8 @@ options	VMSWAP		# Swap device/file suppo
 options	BUFQ_FCFS	# First-come First-serve strategy
 options	BUFQ_DISKSORT	# Traditional min seek sort strategy
 options	RFC2292		# Previous version of Adv. Sockets API for IPv6 
-options	PTRACE		# Include ptrace(2)
+options	PTRACE		# Include ptrace(2) syscall
+options	PTRACE_HOOKS	# Include ptrace hooks
 options	COREDUMP	# allow processes to coredump.
 options	AIO		# POSIX asynchronous I/O
 options	MQUEUE		# POSIX message queues

Index: src/sys/kern/files.kern
diff -u src/sys/kern/files.kern:1.12 src/sys/kern/files.kern:1.13
--- src/sys/kern/files.kern:1.12	Fri Sep 16 03:10:45 2016
+++ src/sys/kern/files.kern	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-#	$NetBSD: files.kern,v 1.12 2016/09/16 03:10:45 pgoyette Exp $
+#	$NetBSD: files.kern,v 1.13 2016/11/02 00:11:59 pgoyette Exp $
 
 #
 # kernel sources
@@ -144,7 +144,9 @@ file	kern/sys_mqueue.c		mqueue
 file	kern/sys_lwp.c			kern
 file	kern/sys_pipe.c			!pipe_socketpair
 file	kern/sys_pmc.c			kern
-file	kern/sys_process.c		ptrace | ktrace
+file	kern/sys_process.c		ptrace_hooks | ktrace
+file	kern/sys_ptrace.c		ptrace
+file	kern/sys_ptrace_common.c	ptrace
 file	kern/sys_pset.c			kern
 file	kern/sys_select.c		kern
 file	kern/sys_sig.c			kern

Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.483 src/sys/kern/init_main.c:1.484
--- src/sys/kern/init_main.c:1.483	Sat Sep 17 12:09:22 2016
+++ src/sys/kern/init_main.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: init_main.c,v 1.483 2016/09/17 12:09:22 maxv Exp $	*/
+/*	$NetBSD: init_main.c,v 1.484 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.483 2016/09/17 12:09:22 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.484 2016/11/02 00:11:59 pgoyette Exp $");
 
 #include "opt_ddb.h"
 #include "opt_inet.h"
@@ -190,9 +190,6 @@ extern void *_binary_splash_image_end;
 #endif
 #include <sys/kauth.h>
 #include <net80211/ieee80211_netbsd.h>
-#ifdef PTRACE
-#include <sys/ptrace.h>
-#endif /* PTRACE */
 #include <sys/cprng.h>
 
 #include <sys/syscall.h>
@@ -563,11 +560,6 @@ main(void)
 	ktrinit();
 #endif
 
-#ifdef PTRACE
-	/* Initialize ptrace. */
-	ptrace_init();
-#endif /* PTRACE */
-
 	machdep_init();
 
 	procinit_sysctl();

Index: src/sys/kern/kern_stub.c
diff -u src/sys/kern/kern_stub.c:1.42 src/sys/kern/kern_stub.c:1.43
--- src/sys/kern/kern_stub.c:1.42	Fri Aug 28 07:18:39 2015
+++ src/sys/kern/kern_stub.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_stub.c,v 1.42 2015/08/28 07:18:39 knakahara Exp $	*/
+/*	$NetBSD: kern_stub.c,v 1.43 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
@@ -62,10 +62,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.42 2015/08/28 07:18:39 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_stub.c,v 1.43 2016/11/02 00:11:59 pgoyette Exp $");
 
 #ifdef _KERNEL_OPT
-#include "opt_ptrace.h"
 #include "opt_ktrace.h"
 #endif
 
@@ -87,14 +86,6 @@ bool default_bus_space_handle_is_equal(b
     bus_space_handle_t);
 
 /*
- * Nonexistent system call-- signal process (may want to handle it).  Flag
- * error in case process won't see signal immediately (blocked or ignored).
- */
-#ifndef PTRACE
-__strong_alias(sys_ptrace,sys_nosys);
-#endif	/* PTRACE */
-
-/*
  * ktrace stubs.  ktruser() goes to enosys as we want to fail the syscall,
  * but not kill the process: utrace() is a debugging feature.
  */

Index: src/sys/kern/sys_process.c
diff -u src/sys/kern/sys_process.c:1.174 src/sys/kern/sys_process.c:1.175
--- src/sys/kern/sys_process.c:1.174	Wed Oct 19 09:44:01 2016
+++ src/sys/kern/sys_process.c	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_process.c,v 1.174 2016/10/19 09:44:01 skrll Exp $	*/
+/*	$NetBSD: sys_process.c,v 1.175 2016/11/02 00:11:59 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.174 2016/10/19 09:44:01 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_process.c,v 1.175 2016/11/02 00:11:59 pgoyette Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -144,975 +144,7 @@ __KERNEL_RCSID(0, "$NetBSD: sys_process.
 
 #include <machine/reg.h>
 
-#ifdef PTRACE
-
-# ifdef DEBUG
-#  define DPRINTF(a) uprintf a
-# else
-#  define DPRINTF(a)
-# endif
-
-static kauth_listener_t ptrace_listener;
-#ifdef PTRACE
-static int process_auxv_offset(struct proc *, struct uio *);
-#endif
-
-static int
-ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
-    void *arg0, void *arg1, void *arg2, void *arg3)
-{
-	struct proc *p;
-	int result;
-
-	result = KAUTH_RESULT_DEFER;
-	p = arg0;
-
-	if (action != KAUTH_PROCESS_PTRACE)
-		return result;
-
-	switch ((u_long)arg1) {
-	case PT_TRACE_ME:
-	case PT_ATTACH:
-	case PT_WRITE_I:
-	case PT_WRITE_D:
-	case PT_READ_I:
-	case PT_READ_D:
-	case PT_IO:
-#ifdef PT_GETREGS
-	case PT_GETREGS:
-#endif
-#ifdef PT_SETREGS
-	case PT_SETREGS:
-#endif
-#ifdef PT_GETFPREGS
-	case PT_GETFPREGS:
-#endif
-#ifdef PT_SETFPREGS
-	case PT_SETFPREGS:
-#endif
-	case PT_SET_EVENT_MASK:
-	case PT_GET_EVENT_MASK:
-	case PT_GET_PROCESS_STATE:
-#ifdef __HAVE_PTRACE_MACHDEP
-	PTRACE_MACHDEP_REQUEST_CASES
-#endif
-		if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
-		    ISSET(p->p_flag, PK_SUGID)) {
-			break;
-		}
-
-		result = KAUTH_RESULT_ALLOW;
-
-	break;
-
-#ifdef PT_STEP
-	case PT_STEP:
-#endif
-	case PT_CONTINUE:
-	case PT_KILL:
-	case PT_DETACH:
-	case PT_LWPINFO:
-	case PT_SYSCALL:
-	case PT_SYSCALLEMU:
-	case PT_DUMPCORE:
-		result = KAUTH_RESULT_ALLOW;
-		break;
-
-	default:
-		break;
-	}
-
-	return result;
-}
-
-void
-ptrace_init(void)
-{
-
-	ptrace_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
-	    ptrace_listener_cb, NULL);
-}
-
-static int
-ptrace_copyinpiod(struct ptrace_io_desc *piod, const void *addr)
-{
-	return copyin(addr, piod, sizeof(*piod));
-}
-
-static void
-ptrace_copyoutpiod(const struct ptrace_io_desc *piod, void *addr)
-{
-	(void) copyout(piod, addr, sizeof(*piod));
-}
-
-
-static struct ptrace_methods native_ptm = {
-	.ptm_copyinpiod = ptrace_copyinpiod,
-	.ptm_copyoutpiod = ptrace_copyoutpiod,
-	.ptm_doregs = process_doregs,
-	.ptm_dofpregs = process_dofpregs,
-};
-
-/*
- * Process debugging system call.
- */
-int
-sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval)
-{
-	/* {
-		syscallarg(int) req;
-		syscallarg(pid_t) pid;
-		syscallarg(void *) addr;
-		syscallarg(int) data;
-	} */
-
-	return do_ptrace(&native_ptm, l, SCARG(uap, req), SCARG(uap, pid),
-	    SCARG(uap, addr), SCARG(uap, data), retval);
-}
-
-int
-do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
-    void *addr, int data, register_t *retval)
-{
-	struct proc *p = l->l_proc;
-	struct lwp *lt;
-#ifdef PT_STEP
-	struct lwp *lt2;
-#endif
-	struct proc *t;				/* target process */
-	struct uio uio;
-	struct iovec iov;
-	struct ptrace_io_desc piod;
-	struct ptrace_event pe;
-	struct ptrace_state ps;
-	struct ptrace_lwpinfo pl;
-	struct vmspace *vm;
-	int error, write, tmp, pheld;
-	int signo = 0;
-	int resume_all;
-	ksiginfo_t ksi;
-	char *path;
-	int len = 0;
-	error = 0;
-
-	/*
-	 * If attaching or detaching, we need to get a write hold on the
-	 * proclist lock so that we can re-parent the target process.
-	 */
-	mutex_enter(proc_lock);
-
-	/* "A foolish consistency..." XXX */
-	if (req == PT_TRACE_ME) {
-		t = p;
-		mutex_enter(t->p_lock);
-	} else {
-		/* Find the process we're supposed to be operating on. */
-		t = proc_find(pid);
-		if (t == NULL) {
-			mutex_exit(proc_lock);
-			return ESRCH;
-		}
-
-		/* XXX-elad */
-		mutex_enter(t->p_lock);
-		error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
-		    t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
-		if (error) {
-			mutex_exit(proc_lock);
-			mutex_exit(t->p_lock);
-			return ESRCH;
-		}
-	}
-
-	/*
-	 * Grab a reference on the process to prevent it from execing or
-	 * exiting.
-	 */
-	if (!rw_tryenter(&t->p_reflock, RW_READER)) {
-		mutex_exit(proc_lock);
-		mutex_exit(t->p_lock);
-		return EBUSY;
-	}
-
-	/* Make sure we can operate on it. */
-	switch (req) {
-	case  PT_TRACE_ME:
-		/* Saying that you're being traced is always legal. */
-		break;
-
-	case  PT_ATTACH:
-		/*
-		 * You can't attach to a process if:
-		 *	(1) it's the process that's doing the attaching,
-		 */
-		if (t->p_pid == p->p_pid) {
-			error = EINVAL;
-			break;
-		}
-
-		/*
-		 *  (2) it's a system process
-		 */
-		if (t->p_flag & PK_SYSTEM) {
-			error = EPERM;
-			break;
-		}
-
-		/*
-		 *	(3) it's already being traced, or
-		 */
-		if (ISSET(t->p_slflag, PSL_TRACED)) {
-			error = EBUSY;
-			break;
-		}
-
-		/*
-		 * 	(4) the tracer is chrooted, and its root directory is
-		 * 	    not at or above the root directory of the tracee
-		 */
-		mutex_exit(t->p_lock);	/* XXXSMP */
-		tmp = proc_isunder(t, l);
-		mutex_enter(t->p_lock);	/* XXXSMP */
-		if (!tmp) {
-			error = EPERM;
-			break;
-		}
-		break;
-
-	case  PT_READ_I:
-	case  PT_READ_D:
-	case  PT_WRITE_I:
-	case  PT_WRITE_D:
-	case  PT_IO:
-#ifdef PT_GETREGS
-	case  PT_GETREGS:
-#endif
-#ifdef PT_SETREGS
-	case  PT_SETREGS:
-#endif
-#ifdef PT_GETFPREGS
-	case  PT_GETFPREGS:
-#endif
-#ifdef PT_SETFPREGS
-	case  PT_SETFPREGS:
-#endif
-#ifdef __HAVE_PTRACE_MACHDEP
-	PTRACE_MACHDEP_REQUEST_CASES
-#endif
-		/*
-		 * You can't read/write the memory or registers of a process
-		 * if the tracer is chrooted, and its root directory is not at
-		 * or above the root directory of the tracee.
-		 */
-		mutex_exit(t->p_lock);	/* XXXSMP */
-		tmp = proc_isunder(t, l);
-		mutex_enter(t->p_lock);	/* XXXSMP */
-		if (!tmp) {
-			error = EPERM;
-			break;
-		}
-		/*FALLTHROUGH*/
-
-	case  PT_CONTINUE:
-	case  PT_KILL:
-	case  PT_DETACH:
-	case  PT_LWPINFO:
-	case  PT_SYSCALL:
-	case  PT_SYSCALLEMU:
-	case  PT_DUMPCORE:
-#ifdef PT_STEP
-	case  PT_STEP:
-#endif
-	case  PT_SET_EVENT_MASK:
-	case  PT_GET_EVENT_MASK:
-	case  PT_GET_PROCESS_STATE:
-		/*
-		 * You can't do what you want to the process if:
-		 *	(1) It's not being traced at all,
-		 */
-		if (!ISSET(t->p_slflag, PSL_TRACED)) {
-			error = EPERM;
-			break;
-		}
-
-		/*
-		 *	(2) it's being traced by procfs (which has
-		 *	    different signal delivery semantics),
-		 */
-		if (ISSET(t->p_slflag, PSL_FSTRACE)) {
-			DPRINTF(("file system traced\n"));
-			error = EBUSY;
-			break;
-		}
-
-		/*
-		 *	(3) it's not being traced by _you_, or
-		 */
-		if (t->p_pptr != p) {
-			DPRINTF(("parent %d != %d\n", t->p_pptr->p_pid,
-			    p->p_pid));
-			error = EBUSY;
-			break;
-		}
-
-		/*
-		 *	(4) it's not currently stopped.
-		 */
-		if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
-			DPRINTF(("stat %d flag %d\n", t->p_stat,
-			    !t->p_waited));
-			error = EBUSY;
-			break;
-		}
-		break;
-
-	default:			/* It was not a legal request. */
-		error = EINVAL;
-		break;
-	}
-
-	if (error == 0) {
-		error = kauth_authorize_process(l->l_cred,
-		    KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req),
-		    NULL, NULL);
-	}
-	if (error == 0) {
-		lt = lwp_find_first(t);
-		if (lt == NULL)
-			error = ESRCH;
-	}
-
-	if (error != 0) {
-		mutex_exit(proc_lock);
-		mutex_exit(t->p_lock);
-		rw_exit(&t->p_reflock);
-		return error;
-	}
-
-	/* Do single-step fixup if needed. */
-	FIX_SSTEP(t);
-	KASSERT(lt != NULL);
-	lwp_addref(lt);
-
-	/*
-	 * Which locks do we need held? XXX Ugly.
-	 */
-	switch (req) {
-#ifdef PT_STEP
-	case PT_STEP:
-#endif
-	case PT_CONTINUE:
-	case PT_DETACH:
-	case PT_KILL:
-	case PT_SYSCALL:
-	case PT_SYSCALLEMU:
-	case PT_ATTACH:
-	case PT_TRACE_ME:
-		pheld = 1;
-		break;
-	default:
-		mutex_exit(proc_lock);
-		mutex_exit(t->p_lock);
-		pheld = 0;
-		break;
-	}
-
-	/* Now do the operation. */
-	write = 0;
-	*retval = 0;
-	tmp = 0;
-	resume_all = 1;
-
-	switch (req) {
-	case  PT_TRACE_ME:
-		/* Just set the trace flag. */
-		SET(t->p_slflag, PSL_TRACED);
-		t->p_opptr = t->p_pptr;
-		break;
-
-	case  PT_WRITE_I:		/* XXX no separate I and D spaces */
-	case  PT_WRITE_D:
-#if defined(__HAVE_RAS)
-		/*
-		 * Can't write to a RAS
-		 */
-		if (ras_lookup(t, addr) != (void *)-1) {
-			error = EACCES;
-			break;
-		}
-#endif
-		write = 1;
-		tmp = data;
-		/* FALLTHROUGH */
-
-	case  PT_READ_I:		/* XXX no separate I and D spaces */
-	case  PT_READ_D:
-		/* write = 0 done above. */
-		iov.iov_base = (void *)&tmp;
-		iov.iov_len = sizeof(tmp);
-		uio.uio_iov = &iov;
-		uio.uio_iovcnt = 1;
-		uio.uio_offset = (off_t)(unsigned long)addr;
-		uio.uio_resid = sizeof(tmp);
-		uio.uio_rw = write ? UIO_WRITE : UIO_READ;
-		UIO_SETUP_SYSSPACE(&uio);
-
-		error = process_domem(l, lt, &uio);
-		if (!write)
-			*retval = tmp;
-		break;
-
-	case  PT_IO:
-		error = ptm->ptm_copyinpiod(&piod, addr);
-		if (error)
-			break;
-
-		iov.iov_base = piod.piod_addr;
-		iov.iov_len = piod.piod_len;
-		uio.uio_iov = &iov;
-		uio.uio_iovcnt = 1;
-		uio.uio_offset = (off_t)(unsigned long)piod.piod_offs;
-		uio.uio_resid = piod.piod_len;
-
-		switch (piod.piod_op) {
-		case PIOD_READ_D:
-		case PIOD_READ_I:
-			uio.uio_rw = UIO_READ;
-			break;
-		case PIOD_WRITE_D:
-		case PIOD_WRITE_I:
-			/*
-			 * Can't write to a RAS
-			 */
-			if (ras_lookup(t, addr) != (void *)-1) {
-				return EACCES;
-			}
-			uio.uio_rw = UIO_WRITE;
-			break;
-		case PIOD_READ_AUXV:
-			req = PT_READ_D;
-			uio.uio_rw = UIO_READ;
-			tmp = t->p_execsw->es_arglen * PROC_PTRSZ(t);
-			if (uio.uio_offset > tmp)
-				return EIO;
-			if (uio.uio_resid > tmp - uio.uio_offset)
-				uio.uio_resid = tmp - uio.uio_offset;
-			piod.piod_len = iov.iov_len = uio.uio_resid;
-			error = process_auxv_offset(t, &uio);
-			if (error)
-				return error;
-			break;
-		default:
-			error = EINVAL;
-			break;
-		}
-		if (error)
-			break;
-		error = proc_vmspace_getref(l->l_proc, &vm);
-		if (error)
-			break;
-		uio.uio_vmspace = vm;
-
-		error = process_domem(l, lt, &uio);
-		piod.piod_len -= uio.uio_resid;
-		(void) ptm->ptm_copyoutpiod(&piod, addr);
-
-		uvmspace_free(vm);
-		break;
-
-	case  PT_DUMPCORE:
-		if ((path = addr) != NULL) {
-			char *dst;
-			len = data;
-
-			if (len < 0 || len >= MAXPATHLEN) {
-				error = EINVAL;
-				break;
-			}
-			dst = kmem_alloc(len + 1, KM_SLEEP);
-			if ((error = copyin(path, dst, len)) != 0) {
-				kmem_free(dst, len + 1);
-				break;
-			}
-			path = dst;
-			path[len] = '\0';
-		}
-		error = (*coredump_vec)(lt, path);
-		if (path)
-			kmem_free(path, len + 1);
-		break;
-
-#ifdef PT_STEP
-	case  PT_STEP:
-		/*
-		 * From the 4.4BSD PRM:
-		 * "Execution continues as in request PT_CONTINUE; however
-		 * as soon as possible after execution of at least one
-		 * instruction, execution stops again. [ ... ]"
-		 */
-#endif
-	case  PT_CONTINUE:
-	case  PT_SYSCALL:
-	case  PT_DETACH:
-		if (req == PT_SYSCALL) {
-			if (!ISSET(t->p_slflag, PSL_SYSCALL)) {
-				SET(t->p_slflag, PSL_SYSCALL);
-#ifdef __HAVE_SYSCALL_INTERN
-				(*t->p_emul->e_syscall_intern)(t);
-#endif
-			}
-		} else {
-			if (ISSET(t->p_slflag, PSL_SYSCALL)) {
-				CLR(t->p_slflag, PSL_SYSCALL);
-#ifdef __HAVE_SYSCALL_INTERN
-				(*t->p_emul->e_syscall_intern)(t);
-#endif
-			}
-		}
-		t->p_trace_enabled = trace_is_enabled(t);
-
-		/*
-		 * Pick up the LWPID, if supplied.  There are two cases:
-		 * data < 0 : step or continue single thread, lwp = -data
-		 * data > 0 in PT_STEP : step this thread, continue others
-		 * For operations other than PT_STEP, data > 0 means
-		 * data is the signo to deliver to the process.
-		 */
-		tmp = data;
-		if (tmp >= 0) {
-#ifdef PT_STEP
-			if (req == PT_STEP)
-				signo = 0;
-			else
-#endif
-			{
-				signo = tmp;
-				tmp = 0;	/* don't search for LWP */
-			}
-		} else
-			tmp = -tmp;
-
-		if (tmp > 0) {
-			if (req == PT_DETACH) {
-				error = EINVAL;
-				break;
-			}
-			lwp_delref2 (lt);
-			lt = lwp_find(t, tmp);
-			if (lt == NULL) {
-				error = ESRCH;
-				break;
-			}
-			lwp_addref(lt);
-			resume_all = 0;
-			signo = 0;
-		}
-
-		/*
-		 * From the 4.4BSD PRM:
-		 * "The data argument is taken as a signal number and the
-		 * child's execution continues at location addr as if it
-		 * incurred that signal.  Normally the signal number will
-		 * be either 0 to indicate that the signal that caused the
-		 * stop should be ignored, or that value fetched out of
-		 * the process's image indicating which signal caused
-		 * the stop.  If addr is (int *)1 then execution continues
-		 * from where it stopped."
-		 */
-
-		/* Check that the data is a valid signal number or zero. */
-		if (signo < 0 || signo >= NSIG) {
-			error = EINVAL;
-			break;
-		}
-
-		/* If the address parameter is not (int *)1, set the pc. */
-		if ((int *)addr != (int *)1) {
-			error = process_set_pc(lt, addr);
-			if (error != 0)
-				break;
-		}
-#ifdef PT_STEP
-		/*
-		 * Arrange for a single-step, if that's requested and possible.
-		 * More precisely, set the single step status as requested for
-		 * the requested thread, and clear it for other threads.
-		 */
-		LIST_FOREACH(lt2, &t->p_lwps, l_sibling) {
-			if (lt != lt2) {
-				lwp_lock(lt2);
-				process_sstep(lt2, 0);
-				lwp_unlock(lt2);
-			}
-		}
-		error = process_sstep(lt, req == PT_STEP);
-		if (error)
-			break;
-#endif
-		if (req == PT_DETACH) {
-			CLR(t->p_slflag, PSL_TRACED|PSL_FSTRACE|PSL_SYSCALL);
-
-			/* give process back to original parent or init */
-			if (t->p_opptr != t->p_pptr) {
-				struct proc *pp = t->p_opptr;
-				proc_reparent(t, pp ? pp : initproc);
-			}
-
-			/* not being traced any more */
-			t->p_opptr = NULL;
-		}
-	sendsig:
-		t->p_fpid = 0;
-		/* Finally, deliver the requested signal (or none). */
-		if (t->p_stat == SSTOP) {
-			/*
-			 * Unstop the process.  If it needs to take a
-			 * signal, make all efforts to ensure that at
-			 * an LWP runs to see it.
-			 */
-			t->p_xsig = signo;
-			if (resume_all)
-				proc_unstop(t);
-			else
-				lwp_unstop(lt);
-		} else if (signo != 0) {
-			KSI_INIT_EMPTY(&ksi);
-			ksi.ksi_signo = signo;
-			kpsignal2(t, &ksi);
-		}
-		break;
-
-	case  PT_SYSCALLEMU:
-		if (!ISSET(t->p_slflag, PSL_SYSCALL) || t->p_stat != SSTOP) {
-			error = EINVAL;
-			break;
-		}
-		SET(t->p_slflag, PSL_SYSCALLEMU);
-		break;
-
-	case  PT_KILL:
-		/* just send the process a KILL signal. */
-		signo = SIGKILL;
-		goto sendsig;	/* in PT_CONTINUE, above. */
-
-	case  PT_ATTACH:
-		/*
-		 * Go ahead and set the trace flag.
-		 * Save the old parent (it's reset in
-		 *   _DETACH, and also in kern_exit.c:wait4()
-		 * Reparent the process so that the tracing
-		 *   proc gets to see all the action.
-		 * Stop the target.
-		 */
-		t->p_opptr = t->p_pptr;
-		if (t->p_pptr != p) {
-			struct proc *parent = t->p_pptr;
-
-			if (parent->p_lock < t->p_lock) {
-				if (!mutex_tryenter(parent->p_lock)) {
-					mutex_exit(t->p_lock);
-					mutex_enter(parent->p_lock);
-					mutex_enter(t->p_lock);
-				}
-			} else if (parent->p_lock > t->p_lock) {
-				mutex_enter(parent->p_lock);
-			}
-			parent->p_slflag |= PSL_CHTRACED;
-			proc_reparent(t, p);
-			if (parent->p_lock != t->p_lock)
-				mutex_exit(parent->p_lock);
-		}
-		SET(t->p_slflag, PSL_TRACED);
-		signo = SIGSTOP;
-		goto sendsig;
-
-	case  PT_GET_EVENT_MASK:
-		if (data != sizeof(pe)) {
-			DPRINTF(("ptrace(%d): %d != %zu\n", req,
-			    data, sizeof(pe)));
-			error = EINVAL;
-			break;
-		}
-		memset(&pe, 0, sizeof(pe));
-		pe.pe_set_event = ISSET(t->p_slflag, PSL_TRACEFORK) ?
-		    PTRACE_FORK : 0;
-		error = copyout(&pe, addr, sizeof(pe));
-		break;
-
-	case  PT_SET_EVENT_MASK:
-		if (data != sizeof(pe)) {
-			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
-			    sizeof(pe)));
-			error = EINVAL;
-			break;
-		}
-		if ((error = copyin(addr, &pe, sizeof(pe))) != 0)
-			return error;
-		if (pe.pe_set_event & PTRACE_FORK)
-			SET(t->p_slflag, PSL_TRACEFORK);
-		else
-			CLR(t->p_slflag, PSL_TRACEFORK);
-		break;
-
-	case  PT_GET_PROCESS_STATE:
-		if (data != sizeof(ps)) {
-			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
-			    sizeof(ps)));
-			error = EINVAL;
-			break;
-		}
-		memset(&ps, 0, sizeof(ps));
-		if (t->p_fpid) {
-			ps.pe_report_event = PTRACE_FORK;
-			ps.pe_other_pid = t->p_fpid;
-		}
-		error = copyout(&ps, addr, sizeof(ps));
-		break;
-
-	case PT_LWPINFO:
-		if (data != sizeof(pl)) {
-			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
-			    sizeof(pl)));
-			error = EINVAL;
-			break;
-		}
-		error = copyin(addr, &pl, sizeof(pl));
-		if (error)
-			break;
-		tmp = pl.pl_lwpid;
-		lwp_delref(lt);
-		mutex_enter(t->p_lock);
-		if (tmp == 0)
-			lt = lwp_find_first(t);
-		else {
-			lt = lwp_find(t, tmp);
-			if (lt == NULL) {
-				mutex_exit(t->p_lock);
-				error = ESRCH;
-				break;
-			}
-			lt = LIST_NEXT(lt, l_sibling);
-		}
-		while (lt != NULL && !lwp_alive(lt))
-			lt = LIST_NEXT(lt, l_sibling);
-		pl.pl_lwpid = 0;
-		pl.pl_event = 0;
-		if (lt) {
-			lwp_addref(lt);
-			pl.pl_lwpid = lt->l_lid;
-			if (lt->l_lid == t->p_sigctx.ps_lwp)
-				pl.pl_event = PL_EVENT_SIGNAL;
-		}
-		mutex_exit(t->p_lock);
-
-		error = copyout(&pl, addr, sizeof(pl));
-		break;
-
-#ifdef PT_SETREGS
-	case  PT_SETREGS:
-		write = 1;
-#endif
-#ifdef PT_GETREGS
-	case  PT_GETREGS:
-		/* write = 0 done above. */
-#endif
-#if defined(PT_SETREGS) || defined(PT_GETREGS)
-		tmp = data;
-		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);
-		}
-		if (!process_validregs(lt))
-			error = EINVAL;
-		else {
-			error = proc_vmspace_getref(p, &vm);
-			if (error)
-				break;
-			iov.iov_base = addr;
-			iov.iov_len = PROC_REGSZ(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_doregs(l, lt, &uio);
-			uvmspace_free(vm);
-		}
-		break;
-#endif
-
-#ifdef PT_SETFPREGS
-	case  PT_SETFPREGS:
-		write = 1;
-#endif
-#ifdef PT_GETFPREGS
-	case  PT_GETFPREGS:
-		/* write = 0 done above. */
-#endif
-#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
-		tmp = data;
-		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);
-		}
-		if (!process_validfpregs(lt))
-			error = EINVAL;
-		else {
-			error = proc_vmspace_getref(p, &vm);
-			if (error)
-				break;
-			iov.iov_base = addr;
-			iov.iov_len = PROC_FPREGSZ(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_dofpregs(l, lt, &uio);
-			uvmspace_free(vm);
-		}
-		break;
-#endif
-
-#ifdef __HAVE_PTRACE_MACHDEP
-	PTRACE_MACHDEP_REQUEST_CASES
-		error = ptrace_machdep_dorequest(l, lt, req, addr, data);
-		break;
-#endif
-	}
-
-	if (pheld) {
-		mutex_exit(t->p_lock);
-		mutex_exit(proc_lock);
-	}
-	if (lt != NULL)
-		lwp_delref(lt);
-	rw_exit(&t->p_reflock);
-
-	return error;
-}
-
-int
-process_doregs(struct lwp *curl /*tracer*/,
-    struct lwp *l /*traced*/,
-    struct uio *uio)
-{
-#if defined(PT_GETREGS) || defined(PT_SETREGS)
-	int error;
-	struct reg r;
-	char *kv;
-	int 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 ((size_t)kl > uio->uio_resid)
-		kl = uio->uio_resid;
-
-	error = process_read_regs(l, &r);
-	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_regs(l, &r);
-	}
-
-	uio->uio_offset = 0;
-	return error;
-#else
-	return EINVAL;
-#endif
-}
-
-int
-process_validregs(struct lwp *l)
-{
-
-#if defined(PT_SETREGS) || defined(PT_GETREGS)
-	return (l->l_flag & LW_SYSTEM) == 0;
-#else
-	return 0;
-#endif
-}
-
-int
-process_dofpregs(struct lwp *curl /*tracer*/,
-    struct lwp *l /*traced*/,
-    struct uio *uio)
-{
-#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
-	int error;
-	struct fpreg 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_fpregs(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_fpregs(l, &r, kl);
-	}
-	uio->uio_offset = 0;
-	return error;
-#else
-	return EINVAL;
-#endif
-}
-
-int
-process_validfpregs(struct lwp *l)
-{
-
-#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
-	return (l->l_flag & LW_SYSTEM) == 0;
-#else
-	return 0;
-#endif
-}
-#endif /* PTRACE */
-
-#if defined(KTRACE) || defined(PTRACE)
+#if defined(KTRACE) || defined(PTRACE_HOOKS)
 int
 process_domem(struct lwp *curl /*tracer*/,
     struct lwp *l /*traced*/,
@@ -1156,9 +188,7 @@ process_domem(struct lwp *curl /*tracer*
 #endif
 	return error;
 }
-#endif /* KTRACE || PTRACE */
 
-#if defined(KTRACE) || defined(PTRACE)
 void
 process_stoptrace(void)
 {
@@ -1186,32 +216,16 @@ process_stoptrace(void)
 	}
 	mutex_exit(p->p_lock);
 }
-#endif	/* KTRACE || PTRACE */
+#endif	/* KTRACE || PTRACE_HOOKS */
 
-#ifdef PTRACE
-static int
-process_auxv_offset(struct proc *p, struct uio *uio)
+/*
+ * Dummy routine so that ptrace_common module will fail to load if this
+ * routine is not defined.
+ */
+#if defined(PTRACE_HOOKS)
+void
+ptrace_hooks(void)
 {
-	struct ps_strings pss;
-	int error;
-	off_t off = (off_t)p->p_psstrp;
 
-	if ((error = copyin_psstrings(p, &pss)) != 0)
-		return error;
-
-	if (pss.ps_envstr == NULL)
-		return EIO;
-
-	uio->uio_offset += (off_t)(vaddr_t)(pss.ps_envstr + pss.ps_nenvstr + 1);
-#ifdef __MACHINE_STACK_GROWS_UP
-	if (uio->uio_offset < off)
-		return EIO;
-#else
-	if (uio->uio_offset > off)
-		return EIO;
-	if ((uio->uio_offset + uio->uio_resid) > off)
-		uio->uio_resid = off - uio->uio_offset;
-#endif
-	return 0;
 }
 #endif

Index: src/sys/kern/syscalls.master
diff -u src/sys/kern/syscalls.master:1.285 src/sys/kern/syscalls.master:1.286
--- src/sys/kern/syscalls.master:1.285	Sun Jul  3 14:24:59 2016
+++ src/sys/kern/syscalls.master	Wed Nov  2 00:11:59 2016
@@ -1,4 +1,4 @@
-	$NetBSD: syscalls.master,v 1.285 2016/07/03 14:24:59 christos Exp $
+	$NetBSD: syscalls.master,v 1.286 2016/11/02 00:11:59 pgoyette Exp $
 
 ;	@(#)syscalls.master	8.2 (Berkeley) 1/13/94
 
@@ -100,11 +100,12 @@
 21	COMPAT_40 MODULAR compat	\
 		{ int|sys||mount(const char *type, const char *path, \
 			    int flags, void *data); }
-22	STD 	 RUMP	{ int|sys||unmount(const char *path, int flags); }
+22	STD 	RUMP	{ int|sys||unmount(const char *path, int flags); }
 23	STD 	RUMP	{ int|sys||setuid(uid_t uid); }
 24	NOERR 	RUMP	{ uid_t|sys||getuid_with_euid(void); } getuid
 25	NOERR 	RUMP	{ uid_t|sys||geteuid(void); }
-26	STD 		{ int|sys||ptrace(int req, pid_t pid, void *addr, \
+26	STD 	MODULAR ptrace	\
+			{ int|sys||ptrace(int req, pid_t pid, void *addr, \
 			    int data); }
 27	STD 	RUMP	{ ssize_t|sys||recvmsg(int s, struct msghdr *msg, \
 			    int flags); }

Index: src/sys/miscfs/procfs/files.procfs
diff -u src/sys/miscfs/procfs/files.procfs:1.9 src/sys/miscfs/procfs/files.procfs:1.10
--- src/sys/miscfs/procfs/files.procfs:1.9	Sat Oct 11 06:42:20 2014
+++ src/sys/miscfs/procfs/files.procfs	Wed Nov  2 00:12:00 2016
@@ -1,6 +1,6 @@
-#	$NetBSD: files.procfs,v 1.9 2014/10/11 06:42:20 uebayasi Exp $
+#	$NetBSD: files.procfs,v 1.10 2016/11/02 00:12:00 pgoyette Exp $
 
-deffs	PROCFS:	PTRACE
+deffs	PROCFS:	PTRACE_HOOKS
 
 define	procfs: vfs
 file	miscfs/procfs/procfs_cmdline.c	procfs

Index: src/sys/modules/Makefile
diff -u src/sys/modules/Makefile:1.181 src/sys/modules/Makefile:1.182
--- src/sys/modules/Makefile:1.181	Wed Oct 19 09:44:01 2016
+++ src/sys/modules/Makefile	Wed Nov  2 00:12:00 2016
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.181 2016/10/19 09:44:01 skrll Exp $
+#	$NetBSD: Makefile,v 1.182 2016/11/02 00:12:00 pgoyette Exp $
 
 .include <bsd.own.mk>
 
@@ -96,6 +96,8 @@ SUBDIR+=	pf
 SUBDIR+=	ppp_bsdcomp
 SUBDIR+=	ppp_deflate
 SUBDIR+=	procfs
+SUBDIR+=	ptrace
+SUBDIR+=	ptrace_common
 SUBDIR+=	ptyfs
 SUBDIR+=	puffs
 SUBDIR+=	putter

Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.47 src/sys/sys/ptrace.h:1.48
--- src/sys/sys/ptrace.h:1.47	Wed Oct 19 09:44:01 2016
+++ src/sys/sys/ptrace.h	Wed Nov  2 00:12:00 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.47 2016/10/19 09:44:01 skrll Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.48 2016/11/02 00:12:00 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 1984, 1993
@@ -146,7 +146,9 @@ struct ptrace_methods {
 	int (*ptm_dofpregs)(struct lwp *, struct lwp *, struct uio *);
 };
 
-void	ptrace_init(void);
+int	ptrace_init(void);
+int	ptrace_fini(void);
+void	ptrace_hooks(void);
 
 int	process_doregs(struct lwp *, struct lwp *, struct uio *);
 int	process_validregs(struct lwp *);

Added files:

Index: src/sys/kern/sys_ptrace.c
diff -u /dev/null src/sys/kern/sys_ptrace.c:1.1
--- /dev/null	Wed Nov  2 00:12:00 2016
+++ src/sys/kern/sys_ptrace.c	Wed Nov  2 00:11:59 2016
@@ -0,0 +1,296 @@
+/*	$NetBSD: sys_ptrace.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $	*/
+
+/*-
+ * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)sys_process.c	8.1 (Berkeley) 6/10/93
+ */
+
+/*-
+ * Copyright (c) 1993 Jan-Simon Pendry.
+ * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)sys_process.c	8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * References:
+ *	(1) Bach's "The Design of the UNIX Operating System",
+ *	(2) sys/miscfs/procfs from UCB's 4.4BSD-Lite distribution,
+ *	(3) the "4.4BSD Programmer's Reference Manual" published
+ *		by USENIX and O'Reilly & Associates.
+ * The 4.4BSD PRM does a reasonably good job of documenting what the various
+ * ptrace() requests should actually do, and its text is quoted several times
+ * in this file.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_ptrace.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/exec.h>
+#include <sys/pax.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/ras.h>
+#include <sys/kmem.h>
+#include <sys/kauth.h>
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+#include <sys/syscallvar.h>
+#include <sys/syscall.h>
+#include <sys/module.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/reg.h>
+
+/*
+ * PTRACE methods
+ */
+
+static int ptrace_copyinpiod(struct ptrace_io_desc *, const void *);
+static void ptrace_copyoutpiod(const struct ptrace_io_desc *, void *);
+static int ptrace_doregs(struct lwp *, struct lwp *, struct uio *);
+static int ptrace_dofpregs(struct lwp *, struct lwp *, struct uio *);
+
+static int
+ptrace_copyinpiod(struct ptrace_io_desc *piod, const void *addr)
+{
+	return copyin(addr, piod, sizeof(*piod));
+}
+
+static void
+ptrace_copyoutpiod(const struct ptrace_io_desc *piod, void *addr)
+{
+	(void) copyout(piod, addr, sizeof(*piod));
+}
+
+int
+ptrace_doregs(struct lwp *curl /*tracer*/,
+    struct lwp *l /*traced*/,
+    struct uio *uio)
+{
+#if defined(PT_GETREGS) || defined(PT_SETREGS)
+	int error;
+	struct reg r;
+	char *kv;
+	int 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 ((size_t)kl > uio->uio_resid)
+		kl = uio->uio_resid;
+
+	error = process_read_regs(l, &r);
+	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_regs(l, &r);
+	}
+
+	uio->uio_offset = 0;
+	return error;
+#else
+	return EINVAL;
+#endif
+}
+
+int
+ptrace_dofpregs(struct lwp *curl /*tracer*/,
+    struct lwp *l /*traced*/,
+    struct uio *uio)
+{
+#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
+	int error;
+	struct fpreg 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_fpregs(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_fpregs(l, &r, kl);
+	}
+	uio->uio_offset = 0;
+	return error;
+#else
+	return EINVAL;
+#endif
+}
+
+static struct ptrace_methods native_ptm = {
+	.ptm_copyinpiod = ptrace_copyinpiod,
+	.ptm_copyoutpiod = ptrace_copyoutpiod,
+	.ptm_doregs = ptrace_doregs,
+	.ptm_dofpregs = ptrace_dofpregs,
+};
+
+static const struct syscall_package ptrace_syscalls[] = {
+	{ SYS_ptrace, 0, (sy_call_t *)sys_ptrace },
+	{ 0, 0, NULL },
+}; 
+
+/*    
+ * Process debugging system call.
+ */   
+int   
+sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval)
+{
+	/* { 
+		syscallarg(int) req;
+		syscallarg(pid_t) pid;
+		syscallarg(void *) addr;
+		syscallarg(int) data;
+	} */
+ 
+        return do_ptrace(&native_ptm, l, SCARG(uap, req), SCARG(uap, pid),
+            SCARG(uap, addr), SCARG(uap, data), retval);
+}
+
+#define	DEPS	"ptrace_common"  
+
+MODULE(MODULE_CLASS_EXEC, ptrace, DEPS);
+ 
+static int
+ptrace_modcmd(modcmd_t cmd, void *arg)
+{
+	int error;
+ 
+	switch (cmd) {
+	case MODULE_CMD_INIT: 
+		error = syscall_establish(&emul_netbsd, ptrace_syscalls);
+		break;
+	case MODULE_CMD_FINI:
+		error = syscall_disestablish(&emul_netbsd, ptrace_syscalls);
+		break;
+	default:
+		error = ENOTTY;
+		break;
+	}
+	return error;
+}
Index: src/sys/kern/sys_ptrace_common.c
diff -u /dev/null src/sys/kern/sys_ptrace_common.c:1.1
--- /dev/null	Wed Nov  2 00:12:00 2016
+++ src/sys/kern/sys_ptrace_common.c	Wed Nov  2 00:11:59 2016
@@ -0,0 +1,1171 @@
+/*	$NetBSD: sys_ptrace_common.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $	*/
+
+/*-
+ * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ */
+
+/*-
+ * Copyright (c) 1982, 1986, 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)sys_process.c	8.1 (Berkeley) 6/10/93
+ */
+
+/*-
+ * Copyright (c) 1993 Jan-Simon Pendry.
+ * Copyright (c) 1994 Christopher G. Demetriou.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	from: @(#)sys_process.c	8.1 (Berkeley) 6/10/93
+ */
+
+/*
+ * References:
+ *	(1) Bach's "The Design of the UNIX Operating System",
+ *	(2) sys/miscfs/procfs from UCB's 4.4BSD-Lite distribution,
+ *	(3) the "4.4BSD Programmer's Reference Manual" published
+ *		by USENIX and O'Reilly & Associates.
+ * The 4.4BSD PRM does a reasonably good job of documenting what the various
+ * ptrace() requests should actually do, and its text is quoted several times
+ * in this file.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.1 2016/11/02 00:11:59 pgoyette Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_ptrace.h"
+#include "opt_ktrace.h"
+#include "opt_pax.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/exec.h>
+#include <sys/pax.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/ras.h>
+#include <sys/kmem.h>
+#include <sys/kauth.h>
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+#include <sys/module.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/reg.h>
+
+#ifdef PTRACE
+
+# ifdef DEBUG
+#  define DPRINTF(a) uprintf a
+# else
+#  define DPRINTF(a)
+# endif
+
+static kauth_listener_t ptrace_listener;
+static int process_auxv_offset(struct proc *, struct uio *);
+
+#if 0
+static int ptrace_cbref;
+static kmutex_t ptrace_mtx;
+static kcondvar_t ptrace_cv;
+#endif
+
+static int
+ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
+    void *arg0, void *arg1, void *arg2, void *arg3)
+{
+	struct proc *p;
+	int result;
+
+	result = KAUTH_RESULT_DEFER;
+	p = arg0;
+
+#if 0
+	mutex_enter(&ptrace_mtx);
+	ptrace_cbref++;
+	mutex_exit(&ptrace_mtx);
+#endif
+	if (action != KAUTH_PROCESS_PTRACE)
+		goto out;
+
+	switch ((u_long)arg1) {
+	case PT_TRACE_ME:
+	case PT_ATTACH:
+	case PT_WRITE_I:
+	case PT_WRITE_D:
+	case PT_READ_I:
+	case PT_READ_D:
+	case PT_IO:
+#ifdef PT_GETREGS
+	case PT_GETREGS:
+#endif
+#ifdef PT_SETREGS
+	case PT_SETREGS:
+#endif
+#ifdef PT_GETFPREGS
+	case PT_GETFPREGS:
+#endif
+#ifdef PT_SETFPREGS
+	case PT_SETFPREGS:
+#endif
+	case PT_SET_EVENT_MASK:
+	case PT_GET_EVENT_MASK:
+	case PT_GET_PROCESS_STATE:
+#ifdef __HAVE_PTRACE_MACHDEP
+	PTRACE_MACHDEP_REQUEST_CASES
+#endif
+		if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
+		    ISSET(p->p_flag, PK_SUGID)) {
+			break;
+		}
+
+		result = KAUTH_RESULT_ALLOW;
+
+	break;
+
+#ifdef PT_STEP
+	case PT_STEP:
+#endif
+	case PT_CONTINUE:
+	case PT_KILL:
+	case PT_DETACH:
+	case PT_LWPINFO:
+	case PT_SYSCALL:
+	case PT_SYSCALLEMU:
+	case PT_DUMPCORE:
+		result = KAUTH_RESULT_ALLOW;
+		break;
+
+	default:
+		break;
+	}
+
+ out:
+#if 0
+	mutex_enter(&ptrace_mtx);
+	if (--ptrace_cbref == 0)
+		cv_broadcast(&ptrace_cv);
+	mutex_exit(&ptrace_mtx);
+#endif
+
+	return result;
+}
+
+int
+ptrace_init(void)
+{
+
+#if 0
+	mutex_init(&ptrace_mtx, MUTEX_DEFAULT, IPL_NONE);
+	cv_init(&ptrace_cv, "ptracecb");
+	ptrace_cbref = 0;
+#endif
+	ptrace_listener = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
+	    ptrace_listener_cb, NULL);
+	return 0;
+}
+
+int
+ptrace_fini(void)
+{
+
+	kauth_unlisten_scope(ptrace_listener);
+
+#if 0
+	/* Make sure no-one is executing our kauth listener */
+
+	mutex_enter(&ptrace_mtx);
+	while (ptrace_cbref != 0)
+		cv_wait(&ptrace_cv, &ptrace_mtx);
+	mutex_exit(&ptrace_mtx);
+	mutex_destroy(&ptrace_mtx);
+	cv_destroy(&ptrace_cv);
+#endif
+
+	return 0;
+}
+
+int
+do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
+    void *addr, int data, register_t *retval)
+{
+	struct proc *p = l->l_proc;
+	struct lwp *lt;
+#ifdef PT_STEP
+	struct lwp *lt2;
+#endif
+	struct proc *t;				/* target process */
+	struct uio uio;
+	struct iovec iov;
+	struct ptrace_io_desc piod;
+	struct ptrace_event pe;
+	struct ptrace_state ps;
+	struct ptrace_lwpinfo pl;
+	struct vmspace *vm;
+	int error, write, tmp, pheld;
+	int signo = 0;
+	int resume_all;
+	ksiginfo_t ksi;
+	char *path;
+	int len = 0;
+	error = 0;
+
+	/*
+	 * If attaching or detaching, we need to get a write hold on the
+	 * proclist lock so that we can re-parent the target process.
+	 */
+	mutex_enter(proc_lock);
+
+	/* "A foolish consistency..." XXX */
+	if (req == PT_TRACE_ME) {
+		t = p;
+		mutex_enter(t->p_lock);
+	} else {
+		/* Find the process we're supposed to be operating on. */
+		t = proc_find(pid);
+		if (t == NULL) {
+			mutex_exit(proc_lock);
+			return ESRCH;
+		}
+
+		/* XXX-elad */
+		mutex_enter(t->p_lock);
+		error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
+		    t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
+		if (error) {
+			mutex_exit(proc_lock);
+			mutex_exit(t->p_lock);
+			return ESRCH;
+		}
+	}
+
+	/*
+	 * Grab a reference on the process to prevent it from execing or
+	 * exiting.
+	 */
+	if (!rw_tryenter(&t->p_reflock, RW_READER)) {
+		mutex_exit(proc_lock);
+		mutex_exit(t->p_lock);
+		return EBUSY;
+	}
+
+	/* Make sure we can operate on it. */
+	switch (req) {
+	case  PT_TRACE_ME:
+		/* Saying that you're being traced is always legal. */
+		break;
+
+	case  PT_ATTACH:
+		/*
+		 * You can't attach to a process if:
+		 *	(1) it's the process that's doing the attaching,
+		 */
+		if (t->p_pid == p->p_pid) {
+			error = EINVAL;
+			break;
+		}
+
+		/*
+		 *  (2) it's a system process
+		 */
+		if (t->p_flag & PK_SYSTEM) {
+			error = EPERM;
+			break;
+		}
+
+		/*
+		 *	(3) it's already being traced, or
+		 */
+		if (ISSET(t->p_slflag, PSL_TRACED)) {
+			error = EBUSY;
+			break;
+		}
+
+		/*
+		 * 	(4) the tracer is chrooted, and its root directory is
+		 * 	    not at or above the root directory of the tracee
+		 */
+		mutex_exit(t->p_lock);	/* XXXSMP */
+		tmp = proc_isunder(t, l);
+		mutex_enter(t->p_lock);	/* XXXSMP */
+		if (!tmp) {
+			error = EPERM;
+			break;
+		}
+		break;
+
+	case  PT_READ_I:
+	case  PT_READ_D:
+	case  PT_WRITE_I:
+	case  PT_WRITE_D:
+	case  PT_IO:
+#ifdef PT_GETREGS
+	case  PT_GETREGS:
+#endif
+#ifdef PT_SETREGS
+	case  PT_SETREGS:
+#endif
+#ifdef PT_GETFPREGS
+	case  PT_GETFPREGS:
+#endif
+#ifdef PT_SETFPREGS
+	case  PT_SETFPREGS:
+#endif
+#ifdef __HAVE_PTRACE_MACHDEP
+	PTRACE_MACHDEP_REQUEST_CASES
+#endif
+		/*
+		 * You can't read/write the memory or registers of a process
+		 * if the tracer is chrooted, and its root directory is not at
+		 * or above the root directory of the tracee.
+		 */
+		mutex_exit(t->p_lock);	/* XXXSMP */
+		tmp = proc_isunder(t, l);
+		mutex_enter(t->p_lock);	/* XXXSMP */
+		if (!tmp) {
+			error = EPERM;
+			break;
+		}
+		/*FALLTHROUGH*/
+
+	case  PT_CONTINUE:
+	case  PT_KILL:
+	case  PT_DETACH:
+	case  PT_LWPINFO:
+	case  PT_SYSCALL:
+	case  PT_SYSCALLEMU:
+	case  PT_DUMPCORE:
+#ifdef PT_STEP
+	case  PT_STEP:
+#endif
+	case  PT_SET_EVENT_MASK:
+	case  PT_GET_EVENT_MASK:
+	case  PT_GET_PROCESS_STATE:
+		/*
+		 * You can't do what you want to the process if:
+		 *	(1) It's not being traced at all,
+		 */
+		if (!ISSET(t->p_slflag, PSL_TRACED)) {
+			error = EPERM;
+			break;
+		}
+
+		/*
+		 *	(2) it's being traced by procfs (which has
+		 *	    different signal delivery semantics),
+		 */
+		if (ISSET(t->p_slflag, PSL_FSTRACE)) {
+			DPRINTF(("file system traced\n"));
+			error = EBUSY;
+			break;
+		}
+
+		/*
+		 *	(3) it's not being traced by _you_, or
+		 */
+		if (t->p_pptr != p) {
+			DPRINTF(("parent %d != %d\n", t->p_pptr->p_pid,
+			    p->p_pid));
+			error = EBUSY;
+			break;
+		}
+
+		/*
+		 *	(4) it's not currently stopped.
+		 */
+		if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
+			DPRINTF(("stat %d flag %d\n", t->p_stat,
+			    !t->p_waited));
+			error = EBUSY;
+			break;
+		}
+		break;
+
+	default:			/* It was not a legal request. */
+		error = EINVAL;
+		break;
+	}
+
+	if (error == 0) {
+		error = kauth_authorize_process(l->l_cred,
+		    KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req),
+		    NULL, NULL);
+	}
+	if (error == 0) {
+		lt = lwp_find_first(t);
+		if (lt == NULL)
+			error = ESRCH;
+	}
+
+	if (error != 0) {
+		mutex_exit(proc_lock);
+		mutex_exit(t->p_lock);
+		rw_exit(&t->p_reflock);
+		return error;
+	}
+
+	/* Do single-step fixup if needed. */
+	FIX_SSTEP(t);
+	KASSERT(lt != NULL);
+	lwp_addref(lt);
+
+	/*
+	 * Which locks do we need held? XXX Ugly.
+	 */
+	switch (req) {
+#ifdef PT_STEP
+	case PT_STEP:
+#endif
+	case PT_CONTINUE:
+	case PT_DETACH:
+	case PT_KILL:
+	case PT_SYSCALL:
+	case PT_SYSCALLEMU:
+	case PT_ATTACH:
+	case PT_TRACE_ME:
+		pheld = 1;
+		break;
+	default:
+		mutex_exit(proc_lock);
+		mutex_exit(t->p_lock);
+		pheld = 0;
+		break;
+	}
+
+	/* Now do the operation. */
+	write = 0;
+	*retval = 0;
+	tmp = 0;
+	resume_all = 1;
+
+	switch (req) {
+	case  PT_TRACE_ME:
+		/* Just set the trace flag. */
+		SET(t->p_slflag, PSL_TRACED);
+		t->p_opptr = t->p_pptr;
+		break;
+
+	case  PT_WRITE_I:		/* XXX no separate I and D spaces */
+	case  PT_WRITE_D:
+#if defined(__HAVE_RAS)
+		/*
+		 * Can't write to a RAS
+		 */
+		if (ras_lookup(t, addr) != (void *)-1) {
+			error = EACCES;
+			break;
+		}
+#endif
+		write = 1;
+		tmp = data;
+		/* FALLTHROUGH */
+
+	case  PT_READ_I:		/* XXX no separate I and D spaces */
+	case  PT_READ_D:
+		/* write = 0 done above. */
+		iov.iov_base = (void *)&tmp;
+		iov.iov_len = sizeof(tmp);
+		uio.uio_iov = &iov;
+		uio.uio_iovcnt = 1;
+		uio.uio_offset = (off_t)(unsigned long)addr;
+		uio.uio_resid = sizeof(tmp);
+		uio.uio_rw = write ? UIO_WRITE : UIO_READ;
+		UIO_SETUP_SYSSPACE(&uio);
+
+		error = process_domem(l, lt, &uio);
+		if (!write)
+			*retval = tmp;
+		break;
+
+	case  PT_IO:
+		error = ptm->ptm_copyinpiod(&piod, addr);
+		if (error)
+			break;
+
+		iov.iov_base = piod.piod_addr;
+		iov.iov_len = piod.piod_len;
+		uio.uio_iov = &iov;
+		uio.uio_iovcnt = 1;
+		uio.uio_offset = (off_t)(unsigned long)piod.piod_offs;
+		uio.uio_resid = piod.piod_len;
+
+		switch (piod.piod_op) {
+		case PIOD_READ_D:
+		case PIOD_READ_I:
+			uio.uio_rw = UIO_READ;
+			break;
+		case PIOD_WRITE_D:
+		case PIOD_WRITE_I:
+			/*
+			 * Can't write to a RAS
+			 */
+			if (ras_lookup(t, addr) != (void *)-1) {
+				return EACCES;
+			}
+			uio.uio_rw = UIO_WRITE;
+			break;
+		case PIOD_READ_AUXV:
+			req = PT_READ_D;
+			uio.uio_rw = UIO_READ;
+			tmp = t->p_execsw->es_arglen * PROC_PTRSZ(t);
+			if (uio.uio_offset > tmp)
+				return EIO;
+			if (uio.uio_resid > tmp - uio.uio_offset)
+				uio.uio_resid = tmp - uio.uio_offset;
+			piod.piod_len = iov.iov_len = uio.uio_resid;
+			error = process_auxv_offset(t, &uio);
+			if (error)
+				return error;
+			break;
+		default:
+			error = EINVAL;
+			break;
+		}
+		if (error)
+			break;
+		error = proc_vmspace_getref(l->l_proc, &vm);
+		if (error)
+			break;
+		uio.uio_vmspace = vm;
+
+		error = process_domem(l, lt, &uio);
+		piod.piod_len -= uio.uio_resid;
+		(void) ptm->ptm_copyoutpiod(&piod, addr);
+
+		uvmspace_free(vm);
+		break;
+
+	case  PT_DUMPCORE:
+		if ((path = addr) != NULL) {
+			char *dst;
+			len = data;
+
+			if (len < 0 || len >= MAXPATHLEN) {
+				error = EINVAL;
+				break;
+			}
+			dst = kmem_alloc(len + 1, KM_SLEEP);
+			if ((error = copyin(path, dst, len)) != 0) {
+				kmem_free(dst, len + 1);
+				break;
+			}
+			path = dst;
+			path[len] = '\0';
+		}
+		error = (*coredump_vec)(lt, path);
+		if (path)
+			kmem_free(path, len + 1);
+		break;
+
+#ifdef PT_STEP
+	case  PT_STEP:
+		/*
+		 * From the 4.4BSD PRM:
+		 * "Execution continues as in request PT_CONTINUE; however
+		 * as soon as possible after execution of at least one
+		 * instruction, execution stops again. [ ... ]"
+		 */
+#endif
+	case  PT_CONTINUE:
+	case  PT_SYSCALL:
+	case  PT_DETACH:
+		if (req == PT_SYSCALL) {
+			if (!ISSET(t->p_slflag, PSL_SYSCALL)) {
+				SET(t->p_slflag, PSL_SYSCALL);
+#ifdef __HAVE_SYSCALL_INTERN
+				(*t->p_emul->e_syscall_intern)(t);
+#endif
+			}
+		} else {
+			if (ISSET(t->p_slflag, PSL_SYSCALL)) {
+				CLR(t->p_slflag, PSL_SYSCALL);
+#ifdef __HAVE_SYSCALL_INTERN
+				(*t->p_emul->e_syscall_intern)(t);
+#endif
+			}
+		}
+		t->p_trace_enabled = trace_is_enabled(t);
+
+		/*
+		 * Pick up the LWPID, if supplied.  There are two cases:
+		 * data < 0 : step or continue single thread, lwp = -data
+		 * data > 0 in PT_STEP : step this thread, continue others
+		 * For operations other than PT_STEP, data > 0 means
+		 * data is the signo to deliver to the process.
+		 */
+		tmp = data;
+		if (tmp >= 0) {
+#ifdef PT_STEP
+			if (req == PT_STEP)
+				signo = 0;
+			else
+#endif
+			{
+				signo = tmp;
+				tmp = 0;	/* don't search for LWP */
+			}
+		} else
+			tmp = -tmp;
+
+		if (tmp > 0) {
+			if (req == PT_DETACH) {
+				error = EINVAL;
+				break;
+			}
+			lwp_delref2 (lt);
+			lt = lwp_find(t, tmp);
+			if (lt == NULL) {
+				error = ESRCH;
+				break;
+			}
+			lwp_addref(lt);
+			resume_all = 0;
+			signo = 0;
+		}
+
+		/*
+		 * From the 4.4BSD PRM:
+		 * "The data argument is taken as a signal number and the
+		 * child's execution continues at location addr as if it
+		 * incurred that signal.  Normally the signal number will
+		 * be either 0 to indicate that the signal that caused the
+		 * stop should be ignored, or that value fetched out of
+		 * the process's image indicating which signal caused
+		 * the stop.  If addr is (int *)1 then execution continues
+		 * from where it stopped."
+		 */
+
+		/* Check that the data is a valid signal number or zero. */
+		if (signo < 0 || signo >= NSIG) {
+			error = EINVAL;
+			break;
+		}
+
+		/* If the address parameter is not (int *)1, set the pc. */
+		if ((int *)addr != (int *)1) {
+			error = process_set_pc(lt, addr);
+			if (error != 0)
+				break;
+		}
+#ifdef PT_STEP
+		/*
+		 * Arrange for a single-step, if that's requested and possible.
+		 * More precisely, set the single step status as requested for
+		 * the requested thread, and clear it for other threads.
+		 */
+		LIST_FOREACH(lt2, &t->p_lwps, l_sibling) {
+			if (lt != lt2) {
+				lwp_lock(lt2);
+				process_sstep(lt2, 0);
+				lwp_unlock(lt2);
+			}
+		}
+		error = process_sstep(lt, req == PT_STEP);
+		if (error)
+			break;
+#endif
+		if (req == PT_DETACH) {
+			CLR(t->p_slflag, PSL_TRACED|PSL_FSTRACE|PSL_SYSCALL);
+
+			/* give process back to original parent or init */
+			if (t->p_opptr != t->p_pptr) {
+				struct proc *pp = t->p_opptr;
+				proc_reparent(t, pp ? pp : initproc);
+			}
+
+			/* not being traced any more */
+			t->p_opptr = NULL;
+		}
+	sendsig:
+		t->p_fpid = 0;
+		/* Finally, deliver the requested signal (or none). */
+		if (t->p_stat == SSTOP) {
+			/*
+			 * Unstop the process.  If it needs to take a
+			 * signal, make all efforts to ensure that at
+			 * an LWP runs to see it.
+			 */
+			t->p_xsig = signo;
+			if (resume_all)
+				proc_unstop(t);
+			else
+				lwp_unstop(lt);
+		} else if (signo != 0) {
+			KSI_INIT_EMPTY(&ksi);
+			ksi.ksi_signo = signo;
+			kpsignal2(t, &ksi);
+		}
+		break;
+
+	case  PT_SYSCALLEMU:
+		if (!ISSET(t->p_slflag, PSL_SYSCALL) || t->p_stat != SSTOP) {
+			error = EINVAL;
+			break;
+		}
+		SET(t->p_slflag, PSL_SYSCALLEMU);
+		break;
+
+	case  PT_KILL:
+		/* just send the process a KILL signal. */
+		signo = SIGKILL;
+		goto sendsig;	/* in PT_CONTINUE, above. */
+
+	case  PT_ATTACH:
+		/*
+		 * Go ahead and set the trace flag.
+		 * Save the old parent (it's reset in
+		 *   _DETACH, and also in kern_exit.c:wait4()
+		 * Reparent the process so that the tracing
+		 *   proc gets to see all the action.
+		 * Stop the target.
+		 */
+		t->p_opptr = t->p_pptr;
+		if (t->p_pptr != p) {
+			struct proc *parent = t->p_pptr;
+
+			if (parent->p_lock < t->p_lock) {
+				if (!mutex_tryenter(parent->p_lock)) {
+					mutex_exit(t->p_lock);
+					mutex_enter(parent->p_lock);
+					mutex_enter(t->p_lock);
+				}
+			} else if (parent->p_lock > t->p_lock) {
+				mutex_enter(parent->p_lock);
+			}
+			parent->p_slflag |= PSL_CHTRACED;
+			proc_reparent(t, p);
+			if (parent->p_lock != t->p_lock)
+				mutex_exit(parent->p_lock);
+		}
+		SET(t->p_slflag, PSL_TRACED);
+		signo = SIGSTOP;
+		goto sendsig;
+
+	case  PT_GET_EVENT_MASK:
+		if (data != sizeof(pe)) {
+			DPRINTF(("ptrace(%d): %d != %zu\n", req,
+			    data, sizeof(pe)));
+			error = EINVAL;
+			break;
+		}
+		memset(&pe, 0, sizeof(pe));
+		pe.pe_set_event = ISSET(t->p_slflag, PSL_TRACEFORK) ?
+		    PTRACE_FORK : 0;
+		error = copyout(&pe, addr, sizeof(pe));
+		break;
+
+	case  PT_SET_EVENT_MASK:
+		if (data != sizeof(pe)) {
+			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
+			    sizeof(pe)));
+			error = EINVAL;
+			break;
+		}
+		if ((error = copyin(addr, &pe, sizeof(pe))) != 0)
+			return error;
+		if (pe.pe_set_event & PTRACE_FORK)
+			SET(t->p_slflag, PSL_TRACEFORK);
+		else
+			CLR(t->p_slflag, PSL_TRACEFORK);
+		break;
+
+	case  PT_GET_PROCESS_STATE:
+		if (data != sizeof(ps)) {
+			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
+			    sizeof(ps)));
+			error = EINVAL;
+			break;
+		}
+		memset(&ps, 0, sizeof(ps));
+		if (t->p_fpid) {
+			ps.pe_report_event = PTRACE_FORK;
+			ps.pe_other_pid = t->p_fpid;
+		}
+		error = copyout(&ps, addr, sizeof(ps));
+		break;
+
+	case PT_LWPINFO:
+		if (data != sizeof(pl)) {
+			DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
+			    sizeof(pl)));
+			error = EINVAL;
+			break;
+		}
+		error = copyin(addr, &pl, sizeof(pl));
+		if (error)
+			break;
+		tmp = pl.pl_lwpid;
+		lwp_delref(lt);
+		mutex_enter(t->p_lock);
+		if (tmp == 0)
+			lt = lwp_find_first(t);
+		else {
+			lt = lwp_find(t, tmp);
+			if (lt == NULL) {
+				mutex_exit(t->p_lock);
+				error = ESRCH;
+				break;
+			}
+			lt = LIST_NEXT(lt, l_sibling);
+		}
+		while (lt != NULL && !lwp_alive(lt))
+			lt = LIST_NEXT(lt, l_sibling);
+		pl.pl_lwpid = 0;
+		pl.pl_event = 0;
+		if (lt) {
+			lwp_addref(lt);
+			pl.pl_lwpid = lt->l_lid;
+			if (lt->l_lid == t->p_sigctx.ps_lwp)
+				pl.pl_event = PL_EVENT_SIGNAL;
+		}
+		mutex_exit(t->p_lock);
+
+		error = copyout(&pl, addr, sizeof(pl));
+		break;
+
+#ifdef PT_SETREGS
+	case  PT_SETREGS:
+		write = 1;
+#endif
+#ifdef PT_GETREGS
+	case  PT_GETREGS:
+		/* write = 0 done above. */
+#endif
+#if defined(PT_SETREGS) || defined(PT_GETREGS)
+		tmp = data;
+		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);
+		}
+		if (!process_validregs(lt))
+			error = EINVAL;
+		else {
+			error = proc_vmspace_getref(p, &vm);
+			if (error)
+				break;
+			iov.iov_base = addr;
+			iov.iov_len = PROC_REGSZ(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_doregs(l, lt, &uio);
+			uvmspace_free(vm);
+		}
+		break;
+#endif
+
+#ifdef PT_SETFPREGS
+	case  PT_SETFPREGS:
+		write = 1;
+#endif
+#ifdef PT_GETFPREGS
+	case  PT_GETFPREGS:
+		/* write = 0 done above. */
+#endif
+#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
+		tmp = data;
+		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);
+		}
+		if (!process_validfpregs(lt))
+			error = EINVAL;
+		else {
+			error = proc_vmspace_getref(p, &vm);
+			if (error)
+				break;
+			iov.iov_base = addr;
+			iov.iov_len = PROC_FPREGSZ(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_dofpregs(l, lt, &uio);
+			uvmspace_free(vm);
+		}
+		break;
+#endif
+
+#ifdef __HAVE_PTRACE_MACHDEP
+	PTRACE_MACHDEP_REQUEST_CASES
+		error = ptrace_machdep_dorequest(l, lt, req, addr, data);
+		break;
+#endif
+	}
+
+	if (pheld) {
+		mutex_exit(t->p_lock);
+		mutex_exit(proc_lock);
+	}
+	if (lt != NULL)
+		lwp_delref(lt);
+	rw_exit(&t->p_reflock);
+
+	return error;
+}
+
+int
+process_doregs(struct lwp *curl /*tracer*/,
+    struct lwp *l /*traced*/,
+    struct uio *uio)
+{
+#if defined(PT_GETREGS) || defined(PT_SETREGS)
+	int error;
+	struct reg r;
+	char *kv;
+	int 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 ((size_t)kl > uio->uio_resid)
+		kl = uio->uio_resid;
+
+	error = process_read_regs(l, &r);
+	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_regs(l, &r);
+	}
+
+	uio->uio_offset = 0;
+	return error;
+#else
+	return EINVAL;
+#endif
+}
+
+int
+process_validregs(struct lwp *l)
+{
+
+#if defined(PT_SETREGS) || defined(PT_GETREGS)
+	return (l->l_flag & LW_SYSTEM) == 0;
+#else
+	return 0;
+#endif
+}
+
+int
+process_dofpregs(struct lwp *curl /*tracer*/,
+    struct lwp *l /*traced*/,
+    struct uio *uio)
+{
+#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
+	int error;
+	struct fpreg 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_fpregs(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_fpregs(l, &r, kl);
+	}
+	uio->uio_offset = 0;
+	return error;
+#else
+	return EINVAL;
+#endif
+}
+
+int
+process_validfpregs(struct lwp *l)
+{
+
+#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
+	return (l->l_flag & LW_SYSTEM) == 0;
+#else
+	return 0;
+#endif
+}
+
+static int
+process_auxv_offset(struct proc *p, struct uio *uio)
+{
+	struct ps_strings pss;
+	int error;
+	off_t off = (off_t)p->p_psstrp;
+
+	if ((error = copyin_psstrings(p, &pss)) != 0)
+		return error;
+
+	if (pss.ps_envstr == NULL)
+		return EIO;
+
+	uio->uio_offset += (off_t)(vaddr_t)(pss.ps_envstr + pss.ps_nenvstr + 1);
+#ifdef __MACHINE_STACK_GROWS_UP
+	if (uio->uio_offset < off)
+		return EIO;
+#else
+	if (uio->uio_offset > off)
+		return EIO;
+	if ((uio->uio_offset + uio->uio_resid) > off)
+		uio->uio_resid = off - uio->uio_offset;
+#endif
+	return 0;
+}
+#endif /* PTRACE */
+
+MODULE(MODULE_CLASS_EXEC, ptrace_common, "");
+ 
+static int
+ptrace_common_modcmd(modcmd_t cmd, void *arg)
+{
+        int error;
+ 
+        switch (cmd) {
+        case MODULE_CMD_INIT:
+                error = ptrace_init();
+                break;
+        case MODULE_CMD_FINI:
+                error = ptrace_fini();
+                break;
+        default:
+		ptrace_hooks();
+                error = ENOTTY;
+                break;
+        }
+        return error;
+}
+

Index: src/sys/modules/ptrace/Makefile
diff -u /dev/null src/sys/modules/ptrace/Makefile:1.1
--- /dev/null	Wed Nov  2 00:12:00 2016
+++ src/sys/modules/ptrace/Makefile	Wed Nov  2 00:12:00 2016
@@ -0,0 +1,12 @@
+#	$NetBSD: Makefile,v 1.1 2016/11/02 00:12:00 pgoyette Exp $
+#
+.include "../Makefile.inc"
+
+.PATH:	${S}/kern
+
+CPPFLAGS+=	-DPTRACE
+
+KMOD=	ptrace
+SRCS=	sys_ptrace.c
+
+.include <bsd.kmodule.mk>

Index: src/sys/modules/ptrace_common/Makefile
diff -u /dev/null src/sys/modules/ptrace_common/Makefile:1.1
--- /dev/null	Wed Nov  2 00:12:00 2016
+++ src/sys/modules/ptrace_common/Makefile	Wed Nov  2 00:12:00 2016
@@ -0,0 +1,12 @@
+#	$NetBSD: Makefile,v 1.1 2016/11/02 00:12:00 pgoyette Exp $
+#
+.include "../Makefile.inc"
+
+.PATH:	${S}/kern
+
+CPPFLAGS+=	-DPTRACE
+
+KMOD=	ptrace_common
+SRCS=	sys_ptrace_common.c
+
+.include <bsd.kmodule.mk>

Reply via email to