Module Name: src
Committed By: christos
Date: Sun Dec 17 04:35:21 UTC 2017
Modified Files:
src/sys/kern: sys_ptrace_common.c
Log Message:
untangle the mess:
- factor out common code
- break each ptrace subcall to its own sub-function
... more to come ...
To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/kern/sys_ptrace_common.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/sys_ptrace_common.c
diff -u src/sys/kern/sys_ptrace_common.c:1.26 src/sys/kern/sys_ptrace_common.c:1.27
--- src/sys/kern/sys_ptrace_common.c:1.26 Sat Dec 9 00:18:45 2017
+++ src/sys/kern/sys_ptrace_common.c Sat Dec 16 23:35:21 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_ptrace_common.c,v 1.26 2017/12/09 05:18:45 christos Exp $ */
+/* $NetBSD: sys_ptrace_common.c,v 1.27 2017/12/17 04:35:21 christos Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -118,7 +118,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.26 2017/12/09 05:18:45 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.27 2017/12/17 04:35:21 christos Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -299,113 +299,80 @@ ptrace_fini(void)
return 0;
}
-int
-do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
- void *addr, int data, register_t *retval)
+static struct proc *
+ptrace_find(struct lwp *l, int req, pid_t pid)
{
- struct proc *p = l->l_proc;
- struct lwp *lt;
- struct lwp *lt2;
- 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 ptrace_siginfo psi;
- 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);
+ struct proc *t;
/* "A foolish consistency..." XXX */
if (req == PT_TRACE_ME) {
- t = p;
+ t = l->l_proc;
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;
- }
+ return t;
+ }
- /* 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;
- }
+ /* Find the process we're supposed to be operating on. */
+ t = proc_find(pid);
+ if (t == NULL)
+ return NULL;
+
+ /* XXX-elad */
+ mutex_enter(t->p_lock);
+ int error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
+ t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
+ if (error) {
+ mutex_exit(t->p_lock);
+ return NULL;
}
+ return t;
+}
+static int
+ptrace_allowed(struct lwp *l, int req, struct proc *t, struct proc *p)
+{
/*
* 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);
+ if (!rw_tryenter(&t->p_reflock, RW_READER))
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;
+ return 0;
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;
- }
+ if (t->p_pid == p->p_pid)
+ return EINVAL;
/*
* (2) it's a system process
*/
- if (t->p_flag & PK_SYSTEM) {
- error = EPERM;
- break;
- }
+ if (t->p_flag & PK_SYSTEM)
+ return EPERM;
/*
* (3) it's already being traced, or
*/
- if (ISSET(t->p_slflag, PSL_TRACED)) {
- error = EBUSY;
- break;
- }
+ if (ISSET(t->p_slflag, PSL_TRACED))
+ return EBUSY;
/*
* (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);
+ int tmp = proc_isunder(t, l);
mutex_enter(t->p_lock); /* XXXSMP */
- if (!tmp) {
- error = EPERM;
- break;
- }
- break;
+ if (!tmp)
+ return EPERM;
+ return 0;
case PT_READ_I:
case PT_READ_D:
@@ -445,10 +412,8 @@ do_ptrace(struct ptrace_methods *ptm, st
mutex_exit(t->p_lock); /* XXXSMP */
tmp = proc_isunder(t, l);
mutex_enter(t->p_lock); /* XXXSMP */
- if (!tmp) {
- error = EPERM;
- break;
- }
+ if (!tmp)
+ return EPERM;
/*FALLTHROUGH*/
case PT_CONTINUE:
@@ -472,10 +437,8 @@ do_ptrace(struct ptrace_methods *ptm, st
* 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;
- }
+ if (!ISSET(t->p_slflag, PSL_TRACED))
+ return EPERM;
/*
* (2) it's not being traced by _you_, or
@@ -483,8 +446,7 @@ do_ptrace(struct ptrace_methods *ptm, st
if (t->p_pptr != p) {
DPRINTF(("parent %d != %d\n", t->p_pptr->p_pid,
p->p_pid));
- error = EBUSY;
- break;
+ return EBUSY;
}
/*
@@ -493,42 +455,18 @@ do_ptrace(struct ptrace_methods *ptm, st
if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
DPRINTF(("stat %d flag %d\n", t->p_stat,
!t->p_waited));
- error = EBUSY;
- break;
+ return EBUSY;
}
- break;
+ return 0;
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;
+ return EINVAL;
}
+}
- /* Do single-step fixup if needed. */
- FIX_SSTEP(t);
- KASSERT(lt != NULL);
- lwp_addref(lt);
-
- /*
- * Which locks do we need held? XXX Ugly.
- */
+static int
+ptrace_needs_hold(int req)
+{
switch (req) {
#ifdef PT_STEP
case PT_STEP:
@@ -540,13 +478,431 @@ do_ptrace(struct ptrace_methods *ptm, st
case PT_SYSCALLEMU:
case PT_ATTACH:
case PT_TRACE_ME:
- pheld = 1;
+ case PT_GET_SIGINFO:
+ case PT_SET_SIGINFO:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid)
+{
+ if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
+ return 0;
+
+ lwp_delref(*lt);
+
+ mutex_enter(t->p_lock);
+ *lt = lwp_find(t, lid);
+ if (*lt == NULL) {
+ mutex_exit(t->p_lock);
+ return ESRCH;
+ }
+
+ if ((*lt)->l_flag & LW_SYSTEM) {
+ *lt = NULL;
+ return EINVAL;
+ }
+
+ lwp_addref(*lt);
+ mutex_exit(t->p_lock);
+
+ return 0;
+}
+
+static int
+ptrace_get_siginfo(struct proc *t, void *addr, size_t data)
+{
+ struct ptrace_siginfo psi;
+
+ if (data != sizeof(psi)) {
+ DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(psi)));
+ return EINVAL;
+ }
+ psi.psi_siginfo._info = t->p_sigctx.ps_info;
+ psi.psi_lwpid = t->p_sigctx.ps_lwp;
+
+ return copyout(&psi, addr, sizeof(psi));
+}
+
+static int
+ptrace_set_siginfo(struct proc *t, struct lwp **lt, void *addr, size_t data)
+{
+ struct ptrace_siginfo psi;
+
+ if (data != sizeof(psi)) {
+ DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(psi)));
+ return EINVAL;
+ }
+
+ int error = copyin(addr, &psi, sizeof(psi));
+ if (error)
+ return error;
+
+ /* Check that the data is a valid signal number or zero. */
+ if (psi.psi_siginfo.si_signo < 0 || psi.psi_siginfo.si_signo >= NSIG)
+ return EINVAL;
+
+ if ((error = ptrace_update_lwp(t, lt, psi.psi_lwpid)) != 0)
+ return error;
+
+ t->p_sigctx.ps_faked = true;
+ t->p_sigctx.ps_info = psi.psi_siginfo._info;
+ t->p_sigctx.ps_lwp = psi.psi_lwpid;
+ return 0;
+}
+
+static int
+ptrace_get_event_mask(struct proc *t, void *addr, size_t data)
+{
+ struct ptrace_event pe;
+
+ if (data != sizeof(pe)) {
+ DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(pe)));
+ return EINVAL;
+ }
+ memset(&pe, 0, sizeof(pe));
+ pe.pe_set_event = ISSET(t->p_slflag, PSL_TRACEFORK) ?
+ PTRACE_FORK : 0;
+ pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK) ?
+ PTRACE_VFORK : 0;
+ pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK_DONE) ?
+ PTRACE_VFORK_DONE : 0;
+ pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_CREATE) ?
+ PTRACE_LWP_CREATE : 0;
+ pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_EXIT) ?
+ PTRACE_LWP_EXIT : 0;
+ return copyout(&pe, addr, sizeof(pe));
+}
+
+static int
+ptrace_set_event_mask(struct proc *t, void *addr, size_t data)
+{
+ struct ptrace_event pe;
+ int error;
+
+ if (data != sizeof(pe)) {
+ DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(pe)));
+ return EINVAL;
+ }
+ 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);
+#if notyet
+ if (pe.pe_set_event & PTRACE_VFORK)
+ SET(t->p_slflag, PSL_TRACEVFORK);
+ else
+ CLR(t->p_slflag, PSL_TRACEVFORK);
+#else
+ if (pe.pe_set_event & PTRACE_VFORK)
+ return ENOTSUP;
+#endif
+ if (pe.pe_set_event & PTRACE_VFORK_DONE)
+ SET(t->p_slflag, PSL_TRACEVFORK_DONE);
+ else
+ CLR(t->p_slflag, PSL_TRACEVFORK_DONE);
+ if (pe.pe_set_event & PTRACE_LWP_CREATE)
+ SET(t->p_slflag, PSL_TRACELWP_CREATE);
+ else
+ CLR(t->p_slflag, PSL_TRACELWP_CREATE);
+ if (pe.pe_set_event & PTRACE_LWP_EXIT)
+ SET(t->p_slflag, PSL_TRACELWP_EXIT);
+ else
+ CLR(t->p_slflag, PSL_TRACELWP_EXIT);
+ return 0;
+}
+
+static int
+ptrace_get_process_state(struct proc *t, void *addr, size_t data)
+{
+ struct ptrace_state ps;
+
+ if (data != sizeof(ps)) {
+ DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(ps)));
+ return EINVAL;
+ }
+ memset(&ps, 0, sizeof(ps));
+
+ if (t->p_fpid) {
+ ps.pe_report_event = PTRACE_FORK;
+ ps.pe_other_pid = t->p_fpid;
+ } else if (t->p_vfpid) {
+ ps.pe_report_event = PTRACE_VFORK;
+ ps.pe_other_pid = t->p_vfpid;
+ } else if (t->p_vfpid_done) {
+ ps.pe_report_event = PTRACE_VFORK_DONE;
+ ps.pe_other_pid = t->p_vfpid_done;
+ } else if (t->p_lwp_created) {
+ ps.pe_report_event = PTRACE_LWP_CREATE;
+ ps.pe_lwp = t->p_lwp_created;
+ } else if (t->p_lwp_exited) {
+ ps.pe_report_event = PTRACE_LWP_EXIT;
+ ps.pe_lwp = t->p_lwp_exited;
+ }
+ return copyout(&ps, addr, sizeof(ps));
+}
+
+static int
+ptrace_lwpinfo(struct proc *t, struct lwp **lt, void *addr, size_t data)
+{
+ struct ptrace_lwpinfo pl;
+
+ if (data != sizeof(pl)) {
+ DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(pl)));
+ return EINVAL;
+ }
+ int error = copyin(addr, &pl, sizeof(pl));
+ if (error)
+ return error;
+
+ lwpid_t 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);
+ return ESRCH;
+ }
+ *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_flag & LW_WSUSPEND)
+ pl.pl_event = PL_EVENT_SUSPENDED;
+ /*
+ * If we match the lwp, or it was sent to every lwp,
+ * we set PL_EVENT_SIGNAL.
+ * XXX: ps_lwp == 0 means everyone and noone, so
+ * check ps_signo too.
+ */
+ else if ((*lt)->l_lid == t->p_sigctx.ps_lwp
+ || (t->p_sigctx.ps_lwp == 0 &&
+ t->p_sigctx.ps_info._signo))
+ pl.pl_event = PL_EVENT_SIGNAL;
+ }
+ mutex_exit(t->p_lock);
+
+ return copyout(&pl, addr, sizeof(pl));
+}
+
+static int
+ptrace_sigmask(struct proc *t, struct lwp **lt, int rq, void *addr, size_t data)
+{
+ int error;
+
+ if ((error = ptrace_update_lwp(t, lt, data)) != 0)
+ return error;
+
+ if (rq == PT_GET_SIGMASK)
+ return copyout(&(*lt)->l_sigmask, addr, sizeof(sigset_t));
+
+ error = copyin(addr, &(*lt)->l_sigmask, sizeof(sigset_t));
+ if (error)
+ return error;
+ sigminusset(&sigcantmask, &(*lt)->l_sigmask);
+ return 0;
+}
+
+static int
+ptrace_startstop(struct proc *t, struct lwp **lt, int rq, void *addr,
+ size_t data)
+{
+ int error;
+
+ if ((error = ptrace_update_lwp(t, lt, data)) != 0)
+ return error;
+
+ lwp_lock(*lt);
+ if (rq == PT_SUSPEND)
+ (*lt)->l_flag |= LW_WSUSPEND;
+ else
+ (*lt)->l_flag &= ~LW_WSUSPEND;
+ lwp_unlock(*lt);
+ return 0;
+}
+
+static int
+ptrace_uio_dir(int req)
+{
+ switch (req) {
+#if defined(PT_GETREGS)
+ case PT_GETREGS:
+#endif
+#if defined(PT_GETFPREGS)
+ case PT_GETFPREGS:
+#endif
+#if defined(PT_GETDBREGS)
+ case PT_GETDBREGS:
+#endif
+ return UIO_READ;
+#if defined(PT_SETREGS)
+ case PT_SETREGS:
+#endif
+#if defined(PT_SETFPREGS)
+ case PT_SETFPREGS:
+#endif
+#if defined(PT_SETDBREGS)
+ case PT_SETDBREGS:
+#endif
+ return UIO_WRITE;
+ default:
+ return -1;
+ }
+}
+
+static int
+ptrace_regs(struct lwp *l, struct lwp **lt, int rq, struct ptrace_methods *ptm,
+ void *addr, size_t data)
+{
+ int error;
+ struct proc *t = l->l_proc;
+ struct vmspace *vm;
+
+ if ((error = ptrace_update_lwp(t, lt, data)) != 0)
+ return error;
+
+ int dir = ptrace_uio_dir(rq);
+ size_t size;
+ int (*func)(struct lwp *, struct lwp *, struct uio *);
+
+ switch (rq) {
+#if defined(PT_SETREGS) || defined(PT_GETREGS)
+#if defined(PT_GETREGS)
+ case PT_GETREGS:
+#endif
+#if defined(PT_GETREGS)
+ case PT_SETREGS:
+#endif
+ if (!process_validregs(*lt))
+ return EINVAL;
+ size = PROC_REGSZ(t);
+ func = ptm->ptm_doregs;
break;
+#endif
+#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
+#if defined(PT_GETFPREGS)
+ case PT_GETFPREGS:
+#endif
+#if defined(PT_GETFPREGS)
+ case PT_SETFPREGS:
+#endif
+ if (!process_validfpregs(*lt))
+ return EINVAL;
+ size = PROC_FPREGSZ(t);
+ func = ptm->ptm_dofpregs;
+ break;
+#endif
+#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
+#if defined(PT_GETDBREGS)
+ case PT_GETDBREGS:
+#endif
+#if defined(PT_GETDBREGS)
+ case PT_SETDBREGS:
+#endif
+ if (!process_validdbregs(*lt))
+ return EINVAL;
+ size = PROC_DBREGSZ(t);
+ func = ptm->ptm_dodbregs;
+ break;
+#endif
default:
+ return EINVAL;
+ }
+
+ error = proc_vmspace_getref(t, &vm);
+ if (error)
+ return error;
+
+ struct uio uio;
+ struct iovec iov;
+
+ iov.iov_base = addr;
+ iov.iov_len = size;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = 0;
+ uio.uio_resid = iov.iov_len;
+ uio.uio_rw = dir;
+ uio.uio_vmspace = vm;
+
+ error = (*func)(l, *lt, &uio);
+ uvmspace_free(vm);
+ return error;
+}
+
+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 = NULL;
+ struct lwp *lt2;
+ struct proc *t; /* target process */
+ struct uio uio;
+ struct iovec iov;
+ struct ptrace_io_desc piod;
+ 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);
+
+ t = ptrace_find(l, req, pid);
+ if (t == NULL) {
mutex_exit(proc_lock);
+ return ESRCH;
+ }
+
+ pheld = 1;
+ if ((error = ptrace_allowed(l, req, t, p)) != 0)
+ goto out;
+
+ if ((error = kauth_authorize_process(l->l_cred,
+ KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req), NULL, NULL)) != 0)
+ goto out;
+
+ if ((lt = lwp_find_first(t)) == NULL) {
+ error = ESRCH;
+ goto out;
+ }
+
+ /* Do single-step fixup if needed. */
+ FIX_SSTEP(t);
+ KASSERT(lt != NULL);
+ lwp_addref(lt);
+
+ /*
+ * Which locks do we need held? XXX Ugly.
+ */
+ if ((pheld = ptrace_needs_hold(req)) == 0) {
mutex_exit(t->p_lock);
- pheld = 0;
- break;
+ mutex_exit(proc_lock);
}
/* Now do the operation. */
@@ -879,24 +1235,10 @@ do_ptrace(struct ptrace_methods *ptm, st
case PT_CLEARSTEP:
/* write = 0 done above. */
+ if ((error = ptrace_update_lwp(t, <, data)) != 0)
+ break;
- 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 (ISSET(lt->l_flag, LW_SYSTEM))
- error = EINVAL;
- else if (write)
+ if (write)
SET(lt->l_pflag, LP_SINGLESTEP);
else
CLR(lt->l_pflag, LP_SINGLESTEP);
@@ -922,389 +1264,61 @@ do_ptrace(struct ptrace_methods *ptm, st
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;
- pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK) ?
- PTRACE_VFORK : 0;
- pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEVFORK_DONE) ?
- PTRACE_VFORK_DONE : 0;
- pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_CREATE) ?
- PTRACE_LWP_CREATE : 0;
- pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_EXIT) ?
- PTRACE_LWP_EXIT : 0;
- error = copyout(&pe, addr, sizeof(pe));
+ error = ptrace_get_event_mask(t, addr, data);
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);
-#if notyet
- if (pe.pe_set_event & PTRACE_VFORK)
- SET(t->p_slflag, PSL_TRACEVFORK);
- else
- CLR(t->p_slflag, PSL_TRACEVFORK);
-#else
- if (pe.pe_set_event & PTRACE_VFORK) {
- error = ENOTSUP;
- break;
- }
-#endif
- if (pe.pe_set_event & PTRACE_VFORK_DONE)
- SET(t->p_slflag, PSL_TRACEVFORK_DONE);
- else
- CLR(t->p_slflag, PSL_TRACEVFORK_DONE);
- if (pe.pe_set_event & PTRACE_LWP_CREATE)
- SET(t->p_slflag, PSL_TRACELWP_CREATE);
- else
- CLR(t->p_slflag, PSL_TRACELWP_CREATE);
- if (pe.pe_set_event & PTRACE_LWP_EXIT)
- SET(t->p_slflag, PSL_TRACELWP_EXIT);
- else
- CLR(t->p_slflag, PSL_TRACELWP_EXIT);
+ error = ptrace_set_event_mask(t, addr, data);
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;
- } else if (t->p_vfpid) {
- ps.pe_report_event = PTRACE_VFORK;
- ps.pe_other_pid = t->p_vfpid;
- } else if (t->p_vfpid_done) {
- ps.pe_report_event = PTRACE_VFORK_DONE;
- ps.pe_other_pid = t->p_vfpid_done;
- } else if (t->p_lwp_created) {
- ps.pe_report_event = PTRACE_LWP_CREATE;
- ps.pe_lwp = t->p_lwp_created;
- } else if (t->p_lwp_exited) {
- ps.pe_report_event = PTRACE_LWP_EXIT;
- ps.pe_lwp = t->p_lwp_exited;
- }
- error = copyout(&ps, addr, sizeof(ps));
+ error = ptrace_get_process_state(t, addr, data);
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_flag & LW_WSUSPEND)
- pl.pl_event = PL_EVENT_SUSPENDED;
- /*
- * If we match the lwp, or it was sent to every lwp,
- * we set PL_EVENT_SIGNAL.
- * XXX: ps_lwp == 0 means everyone and noone, so
- * check ps_signo too.
- */
- else if (lt->l_lid == t->p_sigctx.ps_lwp
- || (t->p_sigctx.ps_lwp == 0 &&
- t->p_sigctx.ps_info._signo))
- pl.pl_event = PL_EVENT_SIGNAL;
- }
- mutex_exit(t->p_lock);
-
- error = copyout(&pl, addr, sizeof(pl));
+ error = ptrace_lwpinfo(t, <, addr, data);
break;
case PT_SET_SIGINFO:
- if (data != sizeof(psi)) {
- DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
- sizeof(psi)));
- error = EINVAL;
- break;
- }
-
- error = copyin(addr, &psi, sizeof(psi));
- if (error)
- break;
-
- /* Check that the data is a valid signal number or zero. */
- if (psi.psi_siginfo.si_signo < 0 ||
- psi.psi_siginfo.si_signo >= NSIG) {
- error = EINVAL;
- break;
- }
-
- tmp = psi.psi_lwpid;
- if (tmp != 0)
- lwp_delref(lt);
-
- mutex_enter(t->p_lock);
-
- if (tmp != 0) {
- lt = lwp_find(t, tmp);
- if (lt == NULL) {
- mutex_exit(t->p_lock);
- error = ESRCH;
- break;
- }
- lwp_addref(lt);
- }
-
- t->p_sigctx.ps_faked = true;
- t->p_sigctx.ps_info = psi.psi_siginfo._info;
- t->p_sigctx.ps_lwp = psi.psi_lwpid;
- mutex_exit(t->p_lock);
+ error = ptrace_set_siginfo(t, <, addr, data);
break;
case PT_GET_SIGINFO:
- if (data != sizeof(psi)) {
- DPRINTF(("ptrace(%d): %d != %zu\n", req, data,
- sizeof(psi)));
- error = EINVAL;
- break;
- }
- mutex_enter(t->p_lock);
- psi.psi_siginfo._info = t->p_sigctx.ps_info;
- psi.psi_lwpid = t->p_sigctx.ps_lwp;
- mutex_exit(t->p_lock);
-
- error = copyout(&psi, addr, sizeof(psi));
- if (error)
- break;
-
+ error = ptrace_get_siginfo(t, addr, data);
break;
case PT_SET_SIGMASK:
- write = 1;
-
case PT_GET_SIGMASK:
- /* write = 0 done above. */
-
- 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 (lt->l_flag & LW_SYSTEM)
- error = EINVAL;
- else if (write == 1) {
- error = copyin(addr, <->l_sigmask, sizeof(sigset_t));
- sigminusset(&sigcantmask, <->l_sigmask);
- } else
- error = copyout(<->l_sigmask, addr, sizeof(sigset_t));
-
+ error = ptrace_sigmask(t, <, req, addr, data);
break;
case PT_RESUME:
- write = 1;
-
case PT_SUSPEND:
- /* write = 0 done above. */
-
- 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 (lt->l_flag & LW_SYSTEM) {
- error = EINVAL;
- } else {
- lwp_lock(lt);
- if (write == 0)
- lt->l_flag |= LW_WSUSPEND;
- else
- lt->l_flag &= ~LW_WSUSPEND;
- lwp_unlock(lt);
- }
+ error = ptrace_startstop(t, <, req, addr, data);
break;
+#if defined(PT_SETREGS) || defined(PT_GETREGS) || \
+ defined(PT_SETFPREGS) || defined(PT_GETFOREGS) || \
+ defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
#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;
- /*FALLTHROUGH*/
#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 PT_SETDBREGS
case PT_SETDBREGS:
- write = 1;
- /*FALLTHROUGH*/
#endif
#ifdef PT_GETDBREGS
case PT_GETDBREGS:
- /* write = 0 done above. */
#endif
-#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
- tmp = data;
- if (tmp != 0 && t->p_nlwps > 1) {
- lwp_delref(lt);
- mutex_enter(t->p_lock);
- 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_validdbregs(lt))
- error = EINVAL;
- else {
- error = proc_vmspace_getref(p, &vm);
- if (error)
- break;
- iov.iov_base = addr;
- iov.iov_len = PROC_DBREGSZ(p);
- uio.uio_iov = &iov;
- uio.uio_iovcnt = 1;
- uio.uio_offset = 0;
- uio.uio_resid = iov.iov_len;
- uio.uio_rw = write ? UIO_WRITE : UIO_READ;
- uio.uio_vmspace = vm;
-
- error = ptm->ptm_dodbregs(l, lt, &uio);
- uvmspace_free(vm);
- }
+ error = ptrace_regs(l, <, req, ptm, addr, data);
break;
#endif
@@ -1315,6 +1329,7 @@ do_ptrace(struct ptrace_methods *ptm, st
#endif
}
+out:
if (pheld) {
mutex_exit(t->p_lock);
mutex_exit(proc_lock);