NetBSD-5.0.2/sys/compat/darwin/darwin_ptrace.c

Compare this file to the similar file:
Show the results in this format:

/*	$NetBSD: darwin_ptrace.c,v 1.17 2008/04/28 20:23:41 martin Exp $ */

/*-
 * Copyright (c) 2003 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Emmanuel Dreyfus.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: darwin_ptrace.c,v 1.17 2008/04/28 20:23:41 martin Exp $");

#include "opt_ptrace.h"

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/proc.h>
#include <sys/ptrace.h>

#include <sys/syscall.h>
#include <sys/syscallargs.h>

#include <compat/sys/signal.h>

#include <compat/mach/mach_types.h>
#include <compat/mach/mach_vm.h>

#include <compat/darwin/darwin_exec.h>
#include <compat/darwin/darwin_audit.h>
#include <compat/darwin/darwin_ptrace.h>
#include <compat/darwin/darwin_syscallargs.h>

#define ISSET(t, f)     ((t) & (f))

int
darwin_sys_ptrace(struct lwp *l, const struct darwin_sys_ptrace_args *uap, register_t *retval)
{
#if defined(PTRACE) || defined(_LKM)
	/* {
		syscallarg(int) req;
		syscallarg(pid_t) pid;
		syscallarg(void *) addr;
		syscallarg(int) data;
	} */
	int req = SCARG(uap, req);
	struct proc *p = l->l_proc;
	struct darwin_emuldata *ded = NULL;
	struct proc *t;			/* target process */
	struct sys_ptrace_args bsd_ua;
	int error;

#ifdef _LKM
#define sys_ptrace (*sysent[SYS_ptrace].sy_call)
	if (sys_ptrace == sys_nosys)
		return ENOSYS;
#endif

	/* XXXAD locking */
	SCARG(&bsd_ua, req) = SCARG(uap, req);
	SCARG(&bsd_ua, pid) = SCARG(uap, pid);
	SCARG(&bsd_ua, addr) = SCARG(uap, addr);
	SCARG(&bsd_ua, data) = SCARG(uap, data);


	ded = (struct darwin_emuldata *)p->p_emuldata;

	switch (req) {
	case DARWIN_PT_ATTACHEXC:
		if ((t = pfind(SCARG(uap, pid))) == NULL)
			return ESRCH;

		if (t->p_emul != &emul_darwin)
			return ESRCH;
		ded = t->p_emuldata;

		if (ded->ded_flags & DARWIN_DED_SIGEXC)
			return EBUSY;

		ded->ded_flags |= DARWIN_DED_SIGEXC;

		SCARG(&bsd_ua, req) = PT_ATTACH;
		if ((error = sys_ptrace(l, &bsd_ua, retval)) != 0)
			 ded->ded_flags &= ~DARWIN_DED_SIGEXC;

		return error;
		break;

	case DARWIN_PT_SIGEXC:
		if ((p->p_slflag & PSL_TRACED) == 0)
			return EBUSY;

		ded->ded_flags |= DARWIN_DED_SIGEXC;
		break;

	case DARWIN_PT_DETACH: {
		int had_sigexc = 0;

		if ((t = pfind(SCARG(uap, pid))) == NULL)
			return (ESRCH);

		if ((t->p_emul == &emul_darwin) &&
		    (t->p_slflag & PSL_TRACED) &&
		    (t->p_pptr == p)) {
			ded = t->p_emuldata;
			if (ded->ded_flags & DARWIN_DED_SIGEXC) {
				had_sigexc = 1;
				ded->ded_flags &= ~DARWIN_DED_SIGEXC;
			}
		}

		/*
		 * If the process is not marked as stopped,
		 * sys_ptrace sanity checks will return EBUSY.
		 */
		mutex_enter(proc_lock);
		mutex_enter(t->p_lock);
		proc_stop(t, 0, SIGSTOP);
		mutex_exit(t->p_lock);
		mutex_exit(proc_lock);

		if ((error = sys_ptrace(l, &bsd_ua, retval)) != 0) {
			mutex_enter(proc_lock);
			mutex_enter(t->p_lock);
			proc_unstop(t);
			mutex_exit(t->p_lock);
			mutex_exit(proc_lock);
			if (had_sigexc)
				ded->ded_flags |= DARWIN_DED_SIGEXC;
		}

		break;
	}

	case DARWIN_PT_THUPDATE: {
		int signo = SCARG(uap, data);

		if ((t = pfind(SCARG(uap, pid))) == NULL)
			return ESRCH;

		/* Checks from native ptrace */
		if (!ISSET(t->p_slflag, PSL_TRACED))
			return EPERM;

		if (ISSET(t->p_slflag, PSL_FSTRACE))
			return EBUSY;

		if (t->p_pptr != p)
			return EBUSY;

#if 0
		if (t->p_stat != SSTOP || !ISSET(t->p_sflag, PS_WAITED))
			return EBUSY;
#endif
		if ((signo < 0) || (signo > NSIG))
			return EINVAL;

		t->p_xstat = signo;
		if (signo != 0)
			sigaddset(&p->p_sigpend.sp_set, signo);

		break;
	}

	case DARWIN_PT_READ_U:
	case DARWIN_PT_WRITE_U:
	case DARWIN_PT_STEP:
	case DARWIN_PT_FORCEQUOTA:
	case DARWIN_PT_DENY_ATTACH:
		printf("darwin_sys_ptrace: unimplemented command %d\n", req);
		break;

	/* The other ptrace commands are the same on NetBSD */
	default:
		return sys_ptrace(l, &bsd_ua, retval);
		break;
	}

	return 0;
#else
	return ENOSYS;
#endif /* PTRACE || _LKM */
}

int
darwin_sys_kdebug_trace(struct lwp *l, const struct darwin_sys_kdebug_trace_args *uap, register_t *retval)
{
	/* {
		syscallarg(int) debugid;
		syscallarg(int) arg1;
		syscallarg(int) arg2;
		syscallarg(int) arg3;
		syscallarg(int) arg4;
		syscallarg(int) arg5;
	} */
	int args[4];
	char *str;

	args[0] = SCARG(uap, arg1);
	args[1] = SCARG(uap, arg2);
	args[2] = SCARG(uap, arg3);
	args[3] = 0;
	str = (char*)args;

#ifdef DEBUG_DARWIN
	printf("darwin_sys_kdebug_trace(%x, (%x %x %x)/\"%s\", %x, %x)\n",
	    SCARG(uap, debugid), SCARG(uap, arg1), SCARG(uap, arg2),
	    SCARG(uap, arg3), str, SCARG(uap, arg4), SCARG(uap, arg5));
#endif
	return 0;
}