Psyscall.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/sysmacros.h>
#include "libproc.h"
#include "Pcontrol.h"
#include "Putil.h"
#include "P32ton.h"
#include "Pisadep.h"
extern sigset_t blockable_sigs;
static void
Pabort_agent(struct ps_prochandle *P)
{
int stop;
(void) Pstop(P, 0);
continue;
dprintf("agent LWP system call aborted\n");
}
}
/*
* Create the /proc agent LWP for further operations.
*/
int
Pcreate_agent(struct ps_prochandle *P)
{
int fd;
char pathname[100];
char *fname;
struct {
long cmd;
} cmd;
/*
* If not first reference, we already have the /proc agent LWP active.
*/
if (P->agentcnt > 0) {
P->agentcnt++;
return (0);
}
/*
* The agent is not available for use as a mortician or as an
* obstetrician.
*/
return (-1);
}
/*
* Create the special /proc agent LWP if it doesn't already exist.
* Give it the registers of the representative LWP.
*/
(void) Pstop(P, 0);
Psync(P);
goto bad;
}
/* refresh the process status */
(void) Pstopstatus(P, PCNULL, 0);
/* open the agent LWP files */
(void) set_minfd();
/*
* It is difficult to know how to recover from the two errors
* that follow. The agent LWP exists and we need to kill it,
* but we can't because we need it active in order to kill it.
* We just hope that these failures never occur.
*/
goto bad;
P->agentstatfd = fd;
goto bad;
P->agentctlfd = fd;
/*
* If the agent is currently asleep in a system call, attempt
* to abort the system call so it's ready to serve.
*/
dprintf("Pcreate_agent: aborting agent syscall\n");
Pabort_agent(P);
}
/* get the agent LWP status */
P->agentcnt++;
if (Pstopstatus(P, PCNULL, 0) != 0) {
Pdestroy_agent(P);
return (-1);
}
return (0);
bad:
if (P->agentstatfd >= 0)
(void) close(P->agentstatfd);
if (P->agentctlfd >= 0)
(void) close(P->agentctlfd);
P->agentstatfd = -1;
P->agentctlfd = -1;
/* refresh the process status */
(void) Pstopstatus(P, PCNULL, 0);
return (-1);
}
/*
* Decrement the /proc agent agent reference count.
* On last reference, destroy the agent.
*/
void
Pdestroy_agent(struct ps_prochandle *P)
{
if (P->agentcnt > 1)
P->agentcnt--;
else {
int flags;
Psync(P); /* Flush out any pending changes */
(void) Pstopstatus(P, PCNULL, 0);
/*
* If the agent is currently asleep in a system call, attempt
* to abort the system call so we can terminate the agent.
*/
dprintf("Pdestroy_agent: aborting agent syscall\n");
Pabort_agent(P);
}
/*
* The agent itself is destroyed by forcing it to execute
* the _lwp_exit(2) system call. Close our agent descriptors
* regardless of whether this is successful.
*/
(void) pr_lwp_exit(P);
(void) close(P->agentctlfd);
(void) close(P->agentstatfd);
P->agentctlfd = -1;
P->agentstatfd = -1;
P->agentcnt = 0;
/*
* Now that (hopefully) the agent has exited, refresh the
* status: the representative LWP is no longer the agent.
*/
(void) Pstopstatus(P, PCNULL, 0);
}
}
/*
* Execute the syscall instruction.
*/
static int
{
int cursig;
struct {
long cmd;
} ctl;
int sentry; /* old value of stop-on-syscall-entry */
/*
* If not already blocked, block all signals now.
*/
sizeof (sigset_t)) != 0) {
}
/*
* If there is a current signal, remember it and cancel it.
*/
}
goto bad;
(void) Pwait(P, 0);
}
goto bad;
if (cursig) /* restore cursig */
if (washeld) { /* restore the signal mask if we set it */
}
return (0);
bad:
return (-1);
}
/*
* Perform system call in controlled process.
*/
int
Psyscall(struct ps_prochandle *P,
int sysindex, /* system call index */
{
int agent_created = FALSE;
int i; /* general index value */
int model; /* data model */
int error = 0; /* syscall errno */
int Perr = 0; /* local error number */
int sexit; /* old value of stop-on-syscall-exit */
goto bad1; /* programming error */
goto bad1; /* dead processes can't perform system calls */
#ifndef _LP64
/* We must be a 64-bit process to deal with a 64-bit process */
if (model == PR_MODEL_LP64)
goto bad9;
#endif
/*
* Create the /proc agent LWP in the process to do all the work.
* by virtue of the reference count.)
*/
if (Pcreate_agent(P) != 0)
goto bad8;
/*
* Save agent's status to restore on exit.
*/
save_pstatus = P->status;
goto bad2;
if (Pscantext(P)) /* bad text ? */
goto bad3;
/*
* Validate arguments and compute the stack frame parameters.
* Begin with the current stack pointer.
*/
#ifdef _LP64
if (model == PR_MODEL_LP64) {
} else {
#endif
#ifdef _LP64
}
#endif
/*
* For each AT_BYREF argument, compute the necessary
* stack space and the object's stack address.
*/
default: /* programming error */
goto bad4;
case AT_BYVAL: /* simple argument */
break;
case AT_BYREF: /* must allocate space */
case AI_INPUT:
case AI_OUTPUT:
case AI_INOUT:
goto bad5; /* programming error */
break;
default: /* programming error */
goto bad6;
}
/* allocate stack space for BYREF argument */
goto bad7; /* programming error */
#ifdef _LP64
if (model == PR_MODEL_LP64)
else
#endif
break;
}
}
/*
* Point of no return.
* Perform the system call entry, adjusting %sp.
* This moves the LWP to the stopped-on-syscall-entry state
* just before the arguments to the system call are fetched.
*/
/*
* Execute the syscall instruction and stop on syscall entry.
*/
goto bad10;
dprintf("Psyscall(): copying arguments\n");
/*
* The LWP is stopped at syscall entry.
* Copy objects to stack frame for each argument.
*/
/* copy input byref parameter to process */
goto bad17;
}
}
goto bad18;
/*
* Complete the system call.
* This moves the LWP to the stopped-on-syscall-exit state.
*/
dprintf("Psyscall(): set running at sysentry\n");
do {
if (Psetrun(P, 0, 0) == -1)
goto bad21;
(void) Pwait(P, 0);
/*
* If the system call was _lwp_exit(), we expect that our last call
* to Pwait() will yield ENOENT because the LWP no longer exists.
*/
dprintf("Psyscall(): _lwp_exit successful\n");
goto out;
}
goto bad22;
goto bad23;
dprintf("Pissyscall_prev() failed\n");
goto bad24;
}
dprintf("Psyscall(): caught at sysexit\n");
/*
* For each argument.
*/
/* copy output byref parameter from process */
goto bad25;
}
}
goto bad26;
/*
* Get the return values from the syscall.
*/
dprintf("Psyscall(%d) fails with errno %d\n",
} else { /* normal return */
}
goto out;
Perr++;
Perr++;
Perr++;
Perr++;
Perr++;
Perr++;
Perr++;
Perr++;
error = -1;
out:
/*
* Destroy the /proc agent LWP now (or just bump down the ref count).
*/
if (agent_created) {
P->status = save_pstatus;
Psync(P);
}
Pdestroy_agent(P);
}
return (error);
}