7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CDDL HEADER START
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The contents of this file are subject to the terms of the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Common Development and Distribution License (the "License").
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * You may not use this file except in compliance with the License.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * See the License for the specific language governing permissions
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * and limitations under the License.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * When distributing Covered Code, include this CDDL HEADER in each
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If applicable, add the following below this CDDL HEADER, with the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * fields enclosed by brackets "[]" replaced with your own identifying
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * information: Portions Copyright [yyyy] [name of copyright owner]
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * CDDL HEADER END
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Use is subject to license terms.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Copyright (c) 2013, Joyent, Inc. All rights reserved.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dprintf("agent LWP is stopped or asleep in syscall %d\n", sysnum);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) Pstop(P, 0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Create the /proc agent LWP for further operations.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If not first reference, we already have the /proc agent LWP active.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (P->agentcnt > 0) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The agent is not available for use as a mortician or as an
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * obstetrician.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Create the special /proc agent LWP if it doesn't already exist.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Give it the registers of the representative LWP.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) Pstop(P, 0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (write(P->ctlfd, &cmd, sizeof (cmd)) != sizeof (cmd))
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* refresh the process status */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* open the agent LWP files */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) snprintf(pathname, sizeof (pathname), "%s/%d/lwp/agent/",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * It is difficult to know how to recover from the two errors
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * that follow. The agent LWP exists and we need to kill it,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * but we can't because we need it active in order to kill it.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * We just hope that these failures never occur.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If the agent is currently asleep in a system call or stopped on
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * system call entry, attempt to abort the system call so it's ready to
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dprintf("Pcreate_agent: aborting agent syscall; lwp is %s\n",
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* get the agent LWP status */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (P->agentstatfd >= 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (P->agentctlfd >= 0)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* refresh the process status */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Decrement the /proc agent agent reference count.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * On last reference, destroy the agent.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If the agent is currently asleep in a system call, attempt
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * to abort the system call so we can terminate the agent.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if ((flags & (PR_AGENT|PR_ASLEEP)) == (PR_AGENT|PR_ASLEEP)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The agent itself is destroyed by forcing it to execute
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * the _lwp_exit(2) system call. Close our agent descriptors
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * regardless of whether this is successful.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Now that (hopefully) the agent has exited, refresh the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * status: the representative LWP is no longer the agent.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Execute the syscall instruction.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi sentry = Psysentry(P, sysindex, TRUE); /* set stop-on-syscall-entry */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If not already blocked, block all signals now.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (memcmp(&P->status.pr_lwp.pr_lwphold, &blockable_sigs,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi sizeof (sigset_t)) != 0) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If there is a current signal, remember it and cancel it.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) Pwait(P, 0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (washeld) { /* restore the signal mask if we set it */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) Psysentry(P, sysindex, sentry); /* restore sysentry stop */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi return (-1);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Perform system call in controlled process.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi uint_t nargs, /* number of arguments to system call */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi int i; /* general index value */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (sysindex <= 0 || sysindex > PRMAXSYS || nargs > MAXARGS)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (P->state == PS_DEAD || P->state == PS_UNDEAD || P->state == PS_IDLE)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi goto bad1; /* dead processes can't perform system calls */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* We must be a 64-bit process to deal with a 64-bit process */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Create the /proc agent LWP in the process to do all the work.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * (It may already exist; nested create/destroy is permitted
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * by virtue of the reference count.)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Save agent's status to restore on exit.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Validate arguments and compute the stack frame parameters.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Begin with the current stack pointer.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi#if defined(__amd64)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * To offset the expense of computerised subtraction, the AMD64
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * ABI allows a process the use of a 128-byte area beyond the
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * location pointed to by %rsp. We must advance the agent's
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * stack pointer by at least the size of this region or else it
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * may corrupt this temporary storage.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * For each AT_BYREF argument, compute the necessary
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * stack space and the object's stack address.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi default: /* programming error */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi default: /* programming error */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* allocate stack space for BYREF argument */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Point of no return.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Perform the system call entry, adjusting %sp.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * This moves the LWP to the stopped-on-syscall-entry state
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * just before the arguments to the system call are fetched.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi P->flags |= SETREGS; /* set registers before continuing */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dprintf("Psyscall(): execute(sysindex = %d)\n", sysindex);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Execute the syscall instruction and stop on syscall entry.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi !Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)))
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * The LWP is stopped at syscall entry.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Copy objects to stack frame for each argument.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* copy input byref parameter to process */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Complete the system call.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * This moves the LWP to the stopped-on-syscall-exit state.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi sexit = Psysexit(P, sysindex, TRUE); /* catch this syscall exit */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) Pwait(P, 0);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } while (P->state == PS_STOP && P->status.pr_lwp.pr_why != PR_SYSEXIT);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi (void) Psysexit(P, sysindex, sexit); /* restore original setting */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * If the system call was _lwp_exit(), we expect that our last call
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * to Pwait() will yield ENOENT because the LWP no longer exists.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (P->state != PS_STOP || P->status.pr_lwp.pr_why != PR_SYSEXIT)
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi if (!Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)) {
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * For each argument.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi /* copy output byref parameter from process */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Get the return values from the syscall.
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi } else { /* normal return */
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dprintf("Psyscall(%d) returns 0x%lx 0x%lx\n", sysindex,
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi P->status.pr_lwp.pr_rval1, P->status.pr_lwp.pr_rval2);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi dprintf("Psyscall(%d) fails with local error %d\n", sysindex, Perr);
7aec1d6e253b21f9e9b7ef68b4d81ab9859b51fecindi * Destroy the /proc agent LWP now (or just bump down the ref count).