/* $NetBSD: mach_task.c,v 1.40 2003/11/24 16:51:33 manu Exp $ */ /*- * Copyright (c) 2002-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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation 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 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 "opt_ktrace.h" #include "opt_compat_darwin.h" #include __KERNEL_RCSID(0, "$NetBSD: mach_task.c,v 1.40 2003/11/24 16:51:33 manu Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef COMPAT_DARWIN #include #endif #define ISSET(t, f) ((t) & (f)) int mach_task_get_special_port(args) struct mach_trap_args *args; { mach_task_get_special_port_request_t *req = args->smsg; mach_task_get_special_port_reply_t *rep = args->rmsg; size_t *msglen = args->rsize; struct lwp *l = args->l; struct mach_emuldata *med; struct mach_right *mr; struct proc *tp; mach_port_t mn; int error; /* Get the target process from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, NULL)) != 0) return mach_msg_error(args, error); med = (struct mach_emuldata *)tp->p_emuldata; switch (req->req_which_port) { case MACH_TASK_KERNEL_PORT: mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0); break; case MACH_TASK_HOST_PORT: mr = mach_right_get(med->med_host, l, MACH_PORT_TYPE_SEND, 0); break; case MACH_TASK_BOOTSTRAP_PORT: mr = mach_right_get(med->med_bootstrap, l, MACH_PORT_TYPE_SEND, 0); break; case MACH_TASK_WIRED_LEDGER_PORT: case MACH_TASK_PAGED_LEDGER_PORT: default: uprintf("mach_task_get_special_port(): unimpl. port %d\n", req->req_which_port); return mach_msg_error(args, EINVAL); break; } rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_msgh_body.msgh_descriptor_count = 1; rep->rep_special_port.name = (mach_port_t)mr->mr_name; rep->rep_special_port.disposition = 0x11; /* XXX why? */ rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_ports_lookup(args) struct mach_trap_args *args; { mach_ports_lookup_request_t *req = args->smsg; mach_ports_lookup_reply_t *rep = args->rmsg; size_t *msglen = args->rsize; struct lwp *l = args->l; struct mach_emuldata *med; struct mach_right *mr; struct proc *tp; mach_port_t mn; mach_port_name_t mnp[7]; vaddr_t va; int error; /* Get the target process from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, NULL)) != 0) return mach_msg_error(args, error); /* * This is some out of band data sent with the reply. In the * encountered situation the out of band data has always been null * filled. We have to see more of this in order to fully understand * how this trap works. */ va = vm_map_min(&l->l_proc->p_vmspace->vm_map); if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va, PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) return mach_msg_error(args, error); med = (struct mach_emuldata *)tp->p_emuldata; mnp[0] = (mach_port_name_t)MACH_PORT_DEAD; mnp[3] = (mach_port_name_t)MACH_PORT_DEAD; mnp[5] = (mach_port_name_t)MACH_PORT_DEAD; mnp[6] = (mach_port_name_t)MACH_PORT_DEAD; mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0); mnp[MACH_TASK_KERNEL_PORT] = mr->mr_name; mr = mach_right_get(med->med_host, l, MACH_PORT_TYPE_SEND, 0); mnp[MACH_TASK_HOST_PORT] = mr->mr_name; mr = mach_right_get(med->med_bootstrap, l, MACH_PORT_TYPE_SEND, 0); mnp[MACH_TASK_BOOTSTRAP_PORT] = mr->mr_name; /* * On Darwin, the data seems always null... */ if ((error = copyout(mnp, (void *)va, sizeof(mnp))) != 0) return mach_msg_error(args, error); #ifdef KTRACE if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0) ktrmool(l->l_proc, mnp, sizeof(mnp), (void *)va); #endif rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_msgh_body.msgh_descriptor_count = 1; /* XXX why ? */ rep->rep_init_port_set.address = (void *)va; rep->rep_init_port_set.count = 3; /* XXX why ? */ rep->rep_init_port_set.copy = 2; /* XXX why ? */ rep->rep_init_port_set.disposition = 0x11; /* XXX why? */ rep->rep_init_port_set.type = 2; /* XXX why? */ rep->rep_init_port_set_count = 3; /* XXX why? */ rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_task_set_special_port(args) struct mach_trap_args *args; { mach_task_set_special_port_request_t *req = args->smsg; mach_task_set_special_port_reply_t *rep = args->rmsg; size_t *msglen = args->rsize; struct lwp *l = args->l; mach_port_t mn; struct mach_right *mr; struct mach_port *mp; struct mach_emuldata *med; /* * XXX is it possible to set the special ports of another process? */ mn = req->req_special_port.name; /* Null port ? */ if (mn == 0) return mach_msg_error(args, 0); /* Does the inserted port exists? */ if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0) return mach_msg_error(args, EPERM); if (mr->mr_type == MACH_PORT_TYPE_DEAD_NAME) return mach_msg_error(args, EINVAL); med = (struct mach_emuldata *)l->l_proc->p_emuldata; switch (req->req_which_port) { case MACH_TASK_KERNEL_PORT: mp = med->med_kernel; med->med_kernel = mr->mr_port; mp->mp_refcount--; if (mp->mp_refcount == 0) mach_port_put(mp); break; case MACH_TASK_HOST_PORT: mp = med->med_host; med->med_host = mr->mr_port; mp->mp_refcount--; if (mp->mp_refcount == 0) mach_port_put(mp); break; case MACH_TASK_BOOTSTRAP_PORT: mp = med->med_bootstrap; med->med_bootstrap = mr->mr_port; mp->mp_refcount--; if (mp->mp_refcount == 0) mach_port_put(mp); #ifdef COMPAT_DARWIN /* * mach_init sets the bootstrap port for any new process */ { struct darwin_emuldata *ded; ded = l->l_proc->p_emuldata; if (ded->ded_fakepid == 1) { mach_bootstrap_port = med->med_bootstrap; #ifdef DEBUG_DARWIN printf("*** New bootstrap port %p, " "recv %p [%p]\n", mach_bootstrap_port, mach_bootstrap_port->mp_recv, mach_bootstrap_port->mp_recv->mr_sethead); #endif /* DEBUG_DARWIN */ } } #endif /* COMPAT_DARWIN */ break; default: uprintf("mach_task_set_special_port: unimplemented port %d\n", req->req_which_port); } rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE); rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_task_threads(args) struct mach_trap_args *args; { mach_task_threads_request_t *req = args->smsg; mach_task_threads_reply_t *rep = args->rmsg; size_t *msglen = args->rsize; struct lwp *l = args->l; struct mach_emuldata *med; int error; vaddr_t va; size_t size; int i; struct mach_right *mr; mach_port_name_t *mnp; mach_port_t mn; struct proc *tp; /* Get the target lwp from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, NULL)) != 0) return mach_msg_error(args, error); med = tp->p_emuldata; size = tp->p_nlwps * sizeof(*mnp); va = vm_map_min(&l->l_proc->p_vmspace->vm_map); if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va, round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) return mach_msg_error(args, error); mnp = malloc(size, M_TEMP, M_WAITOK); for (i = 0; i < l->l_proc->p_nlwps; i++) { /* XXX each thread should have a kernel port */ mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0); mnp[i] = mr->mr_name; } if ((error = copyout(mnp, (void *)va, size)) != 0) { free(mnp, M_TEMP); return mach_msg_error(args, error); } free(mnp, M_TEMP); #ifdef KTRACE if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0) ktrmool(l->l_proc, mnp, size, (void *)va); #endif rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_body.msgh_descriptor_count = 1; rep->rep_list.address = (void *)va; rep->rep_list.count = tp->p_nlwps; rep->rep_list.copy = 0x02; rep->rep_list.disposition = 0x11; rep->rep_list.type = 0x02; rep->rep_count = tp->p_nlwps; rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_task_get_exception_ports(args) struct mach_trap_args *args; { mach_task_get_exception_ports_request_t *req = args->smsg; mach_task_get_exception_ports_reply_t *rep = args->rmsg; struct lwp *l = args->l; size_t *msglen = args->rsize; struct mach_emuldata *med; struct mach_right *mr; int i, j, count; mach_port_t mn; struct proc *tp; int error; /* Get the target lwp from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, NULL)) != 0) return mach_msg_error(args, error); med = tp->p_emuldata; /* It always return an array of 32 ports even if only 9 can be used */ count = sizeof(rep->rep_old_handler) / sizeof(rep->rep_old_handler[0]); rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_body.msgh_descriptor_count = count; rep->rep_masks_count = count; j = 0; for (i = 0; i <= MACH_EXC_MAX; i++) { if (med->med_exc[i] == NULL) continue; mr = mach_right_get(med->med_exc[i], l, MACH_PORT_TYPE_SEND, 0); rep->rep_old_handler[j].name = mr->mr_name; rep->rep_old_handler[j].disposition = 0x11; rep->rep_old_handler[j].type = 0; rep->rep_masks[j] = 1 << i; rep->rep_old_behaviors[j] = (int)mr->mr_port->mp_data >> 16; rep->rep_old_flavors[j] = (int)mr->mr_port->mp_data & 0xffff; j++; } rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_task_set_exception_ports(args) struct mach_trap_args *args; { mach_task_set_exception_ports_request_t *req = args->smsg; mach_task_set_exception_ports_reply_t *rep = args->rmsg; struct lwp *l = args->l; size_t *msglen = args->rsize; struct mach_emuldata *med; mach_port_name_t mn; struct mach_right *mr; struct mach_port *mp; /* * XXX Is it possible to set the exception port of a remote process? */ mn = req->req_new_port.name; if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_SEND)) == 0) return mach_msg_error(args, EPERM); mp = mr->mr_port; #ifdef DIAGNOSTIC if ((mp->mp_datatype != MACH_MP_EXC_FLAGS) && (mp->mp_datatype != MACH_MP_NONE)) printf("mach_task_set_exception_ports: data exists\n"); #endif mp->mp_datatype = MACH_MP_EXC_FLAGS; mp->mp_data = (void *)((req->req_behavior << 16) | req->req_flavor); med = l->l_proc->p_emuldata; if (req->req_mask & MACH_EXC_MASK_BAD_ACCESS) med->med_exc[MACH_EXC_BAD_ACCESS] = mp; if (req->req_mask & MACH_EXC_MASK_BAD_INSTRUCTION) med->med_exc[MACH_EXC_BAD_INSTRUCTION] = mp; if (req->req_mask & MACH_EXC_MASK_ARITHMETIC) med->med_exc[MACH_EXC_ARITHMETIC] = mp; if (req->req_mask & MACH_EXC_MASK_EMULATION) med->med_exc[MACH_EXC_EMULATION] = mp; if (req->req_mask & MACH_EXC_MASK_SOFTWARE) med->med_exc[MACH_EXC_SOFTWARE] = mp; if (req->req_mask & MACH_EXC_MASK_BREAKPOINT) med->med_exc[MACH_EXC_BREAKPOINT] = mp; if (req->req_mask & MACH_EXC_MASK_SYSCALL) med->med_exc[MACH_EXC_SYSCALL] = mp; if (req->req_mask & MACH_EXC_MASK_MACH_SYSCALL) med->med_exc[MACH_EXC_MACH_SYSCALL] = mp; if (req->req_mask & MACH_EXC_MASK_RPC_ALERT) med->med_exc[MACH_EXC_RPC_ALERT] = mp; #ifdef DEBUG_MACH if (req->req_mask & (MACH_EXC_ARITHMETIC | MACH_EXC_EMULATION | MACH_EXC_MASK_SYSCALL | MACH_EXC_MASK_MACH_SYSCALL | MACH_EXC_RPC_ALERT)) printf("mach_set_exception_ports: some exceptions are " "not supported (mask %x)\n", req->req_mask); #endif rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE); rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_task_info(args) struct mach_trap_args *args; { mach_task_info_request_t *req = args->smsg; mach_task_info_reply_t *rep = args->rmsg; struct lwp *l = args->l; size_t *msglen = args->rsize; int count; mach_port_t mn; struct proc *tp; int error; /* Get the target lwp from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, NULL)) != 0) return mach_msg_error(args, error); switch(req->req_flavor) { case MACH_TASK_BASIC_INFO: { struct mach_task_basic_info *mtbi; struct rusage *ru; count = sizeof(*mtbi) / sizeof(rep->rep_info[0]); if (req->req_count < count) return mach_msg_error(args, ENOBUFS); ru = &tp->p_stats->p_ru; mtbi = (struct mach_task_basic_info *)&rep->rep_info[0]; mtbi->mtbi_suspend_count = ru->ru_nvcsw + ru->ru_nivcsw; mtbi->mtbi_virtual_size = ru->ru_ixrss; mtbi->mtbi_resident_size = ru->ru_maxrss; mtbi->mtbi_user_time.seconds = ru->ru_utime.tv_sec; mtbi->mtbi_user_time.microseconds = ru->ru_utime.tv_usec; mtbi->mtbi_system_time.seconds = ru->ru_stime.tv_sec; mtbi->mtbi_system_time.microseconds = ru->ru_stime.tv_usec; mtbi->mtbi_policy = 0; *msglen = sizeof(*rep) - sizeof(rep->rep_info) + sizeof(*mtbi); break; } /* XXX this is supposed to be about threads, not processes... */ case MACH_TASK_THREAD_TIMES_INFO: { struct mach_task_thread_times_info *mttti; struct rusage *ru; count = sizeof(*mttti) / sizeof(rep->rep_info[0]); if (req->req_count < count) return mach_msg_error(args, ENOBUFS); ru = &tp->p_stats->p_ru; mttti = (struct mach_task_thread_times_info *)&rep->rep_info[0]; mttti->mttti_user_time.seconds = ru->ru_utime.tv_sec; mttti->mttti_user_time.microseconds = ru->ru_utime.tv_usec; mttti->mttti_system_time.seconds = ru->ru_stime.tv_sec; mttti->mttti_system_time.microseconds = ru->ru_stime.tv_usec; *msglen = sizeof(*rep) - sizeof(rep->rep_info) + sizeof(*mttti); break; } /* XXX a few statistics missing here */ case MACH_TASK_EVENTS_INFO: { struct mach_task_events_info *mtei; struct rusage *ru; count = sizeof(*mtei) / sizeof(rep->rep_info[0]); if (req->req_count < count) return mach_msg_error(args, ENOBUFS); mtei = (struct mach_task_events_info *)&rep->rep_info[0]; ru = &tp->p_stats->p_ru; mtei->mtei_faults = ru->ru_majflt; mtei->mtei_pageins = ru->ru_minflt; mtei->mtei_cow_faults = 0; /* XXX */ mtei->mtei_message_sent = ru->ru_msgsnd; mtei->mtei_message_received = ru->ru_msgrcv; mtei->mtei_syscalls_mach = 0; /* XXX */ mtei->mtei_syscalls_unix = 0; /* XXX */ mtei->mtei_csw = 0; /* XXX */ *msglen = sizeof(*rep) - sizeof(rep->rep_info) + sizeof(*mtei); break; } default: uprintf("mach_task_info: unsupported flavor %d\n", req->req_flavor); return mach_msg_error(args, EINVAL); }; rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE); rep->rep_msgh.msgh_size = *msglen - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_count = count; rep->rep_info[count + 1] = 8; /* Trailer */ return 0; } int mach_task_suspend(args) struct mach_trap_args *args; { mach_task_suspend_request_t *req = args->smsg; mach_task_suspend_reply_t *rep = args->rmsg; size_t *msglen = args->rsize; struct lwp *l = args->l; struct lwp *lp; mach_port_t mn; struct mach_emuldata *med; struct proc *tp; struct lwp *tl; int error; /* Get the target lwp from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, &tl)) != 0) return mach_msg_error(args, error); med = tp->p_emuldata; med->med_suspend++; /* XXX Mach also has a per thread semaphore */ LIST_FOREACH(lp, &tp->p_lwps, l_sibling) { switch(lp->l_stat) { case LSONPROC: case LSRUN: case LSSLEEP: case LSSUSPENDED: case LSZOMB: case LSDEAD: break; default: return mach_msg_error(args, 0); break; } } proc_stop(tp); rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE); rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_task_resume(args) struct mach_trap_args *args; { mach_task_resume_request_t *req = args->smsg; mach_task_resume_reply_t *rep = args->rmsg; size_t *msglen = args->rsize; struct lwp *l = args->l; mach_port_t mn; struct mach_emuldata *med; struct proc *tp; struct lwp *tl; int error; /* Get the target lwp from the remote port. */ mn = req->req_msgh.msgh_remote_port; if ((error = mach_get_target_task(l, mn, &tp, &tl)) != 0) return mach_msg_error(args, error); med = tp->p_emuldata; med->med_suspend--; /* XXX Mach also has a per thread semaphore */ #if 0 if (med->med_suspend > 0) return mach_msg_error(args, 0); /* XXX error code */ #endif /* XXX We should also wake up the stopped thread... */ #ifdef DEBUG_MACH printf("resuming pid %d\n", tp->p_pid); #endif (void)proc_unstop(tp); rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE); rep->rep_msgh.msgh_size = sizeof(*rep) - sizeof(rep->rep_trailer); rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_retval = 0; rep->rep_trailer.msgh_trailer_size = 8; *msglen = sizeof(*rep); return 0; } int mach_sys_task_for_pid(l, v, retval) struct lwp *l; void *v; register_t *retval; { struct mach_sys_task_for_pid_args /* { syscallarg(mach_port_t) target_tport; syscallarg(int) pid; syscallarg(mach_port_t) *t; } */ *uap = v; struct mach_right *mr; struct mach_emuldata *med; struct proc *p = l->l_proc; struct proc *t; int error; /* * target_tport is used because the task may be on * a different host. (target_tport, pid) is unique. * We don't support multiple-host configuration * yet, so this parameter should be useless. * However, we still validate it. */ if ((mr = mach_right_check(SCARG(uap, target_tport), l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL) return EPERM; if ((t = pfind(SCARG(uap, pid))) == NULL) return ESRCH; /* Allowed only if the UID match, if setuid, or if superuser */ if ((t->p_cred->p_ruid != p->p_cred->p_ruid || ISSET(t->p_flag, P_SUGID)) && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return (error); /* This will only work on a Mach process */ if ((t->p_emul != &emul_mach) && #ifdef COMPAT_DARWIN (t->p_emul != &emul_darwin) && #endif 1) return EINVAL; med = t->p_emuldata; if ((mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0)) == NULL) return EINVAL; if ((error = copyout(&mr->mr_name, SCARG(uap, t), sizeof(mr->mr_name))) != 0) return error; return 0; } inline int mach_get_target_task(l, mn, tp, tl) struct lwp *l; mach_port_t mn; struct proc **tp; struct lwp **tl; { struct mach_right *mr; struct proc *p; if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == 0) return EPERM; if (mr->mr_port->mp_datatype != MACH_MP_PROC) { #ifdef DEBUG_MACH printf("non proc data on task kernel port\n"); #endif return EINVAL; } /* * XXX There should be per-thread kernel ports to * avoid this: We always see the same thread. */ p = (struct proc *)mr->mr_port->mp_data; if (tp != NULL) *tp = p; if (tl != NULL) *tl = proc_representative_lwp(p); return 0; }