/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* ptrace(2) interface built on top of proc(4).
*/
#include "lint.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <procfs.h>
/*
*/
#include <mtlib.h>
#include <thread.h>
#include <synch.h>
#include <unistd.h>
#define FALSE 0
/*
* All my children...
*/
typedef struct cstatus {
} cstatus_t;
/* flags */
/* fake u-block offsets */
/* external routines defined in this module */
/* static routines defined in this module */
static void CheckAllProcs(void);
static int Dupfd(int, int);
static void MakeProcName(char *, pid_t);
static void ReleaseProc(cstatus_t *);
static int ProcUpdate(cstatus_t *);
#if PTRACE_DEBUG
/* for debugging */
static char *
{
switch (request) {
case 0: return ("PTRACE_TRACEME");
case 1: return ("PTRACE_PEEKTEXT");
case 2: return ("PTRACE_PEEKDATA");
case 3: return ("PTRACE_PEEKUSER");
case 4: return ("PTRACE_POKETEXT");
case 5: return ("PTRACE_POKEDATA");
case 6: return ("PTRACE_POKEUSER");
case 7: return ("PTRACE_CONT");
case 8: return ("PTRACE_KILL");
case 9: return ("PTRACE_SINGLESTEP");
}
return (name);
}
#endif
int
{
unsigned xaddr;
struct {
long cmd;
union {
long flags;
} arg;
} ctl;
#if PTRACE_DEBUG
#endif
(void) mutex_lock(&pt_lock);
if (request == 0) { /* PTRACE_TRACEME, executed by traced process */
/*
* Set stop-on-all-signals and nothing else.
* Turn off inherit-on-fork flag (grandchildren run away).
* Set ptrace-compatible flag.
*/
int fd;
exit(255);
!= sizeof (long)+sizeof (sigset_t))
exit(255);
!= sizeof (long)+sizeof (fltset_t))
exit(255);
!= sizeof (long)+sizeof (sysset_t))
exit(255);
!= sizeof (long)+sizeof (sysset_t))
exit(255);
!= sizeof (long)+sizeof (long))
exit(255);
!= sizeof (long)+sizeof (long))
exit(255);
exit(255);
(void) mutex_unlock(&pt_lock);
return (0);
}
errno = 0;
/* find the cstatus structure corresponding to pid */
goto esrch;
if (ProcUpdate(cp) != 0) {
goto esrch;
}
goto esrch;
}
/*
* Process the request.
*/
errno = 0;
switch (request) {
case 1: /* PTRACE_PEEKTEXT */
case 2: /* PTRACE_PEEKDATA */
if (addr & 03)
goto eio;
== sizeof (data)) {
(void) mutex_unlock(&pt_lock);
return (data);
}
goto eio;
case 3: /* PTRACE_PEEKUSER */
if (addr & 03)
goto eio;
/* LINTED pointer alignment */
(void) mutex_unlock(&pt_lock);
return (data);
}
goto eio;
case 4: /* PTRACE_POKETEXT */
case 5: /* PTRACE_POKEDATA */
if (addr & 03)
goto eio;
== sizeof (data)) {
(void) mutex_unlock(&pt_lock);
return (data);
}
goto eio;
case 6: /* PTRACE_POKEUSER */
if (addr & 03)
goto eio;
data &= ~03;
(void) mutex_unlock(&pt_lock);
return (data);
}
goto eio;
case 7: /* PTRACE_CONT */
case 9: /* PTRACE_SINGLESTEP */
{
long cmd;
goto tryagain;
}
!= 2*sizeof (long))
goto tryagain;
}
/* make data the current signal */
sizeof (siginfo_t));
sizeof (long)+sizeof (siginfo_t))
!= sizeof (long)+sizeof (siginfo_t))
goto tryagain;
}
if (data == 0)
else
!= 3*sizeof (long)) {
/* current signal must have killed it */
(void) mutex_unlock(&pt_lock);
return (data);
}
goto tryagain;
}
(void) mutex_unlock(&pt_lock);
return (data);
}
case 8: /* PTRACE_KILL */
/* overkill? */
sizeof (long)+sizeof (siginfo_t));
(void) mutex_unlock(&pt_lock);
return (0);
default:
goto eio;
}
goto again;
}
eio:
(void) mutex_unlock(&pt_lock);
return (-1);
(void) mutex_unlock(&pt_lock);
return (-1);
}
/*
* Find the cstatus structure corresponding to pid.
*/
static cstatus_t *
{
break;
return (cp);
}
/*
* Check every proc for existence, release those that are gone.
* Be careful about the linked list; ReleaseProc() changes it.
*/
static void
{
if (ProcUpdate(cp) != 0)
}
}
/*
* Utility for OpenProc().
*/
static int
{
/*
* Make sure fd not one of 0, 1, or 2 to avoid stdio interference.
* Also, if dfd is greater than 2, dup fd to be exactly dfd.
*/
else
dfd = 3;
}
}
/*
* Mark filedescriptor close-on-exec.
* Should also be close-on-return-from-fork-in-child.
*/
return (fd);
}
/*
* Construct the /proc directory name: "/proc/<pid>"
* The name buffer passed by the caller must be large enough.
*/
static void
{
}
/*
*/
static int
{
char *fname;
int fd;
int omode;
/*
* Use exclusive-open only if this is the first open.
*/
goto err;
goto err;
goto err;
return (0);
err:
return (-1);
}
/*
* Close the /proc/<pid> files.
*/
static void
{
}
/*
* Take control of a child process.
*/
static cstatus_t *
{
if (pid <= 0)
return (NULLCP);
return (cp);
CheckAllProcs(); /* clean up before grabbing new process */
return (NULLCP);
errno = 0;
== 2*sizeof (long)) {
return (cp);
}
break;
}
return (NULLCP);
}
/*
* Close the /proc/<pid> file, if open.
* Deallocate the memory used by the cstatus_t structure.
*/
static void
{
else {
break;
}
}
}
}
/*
* Update process information from /proc.
* Return 0 on success, -1 on failure.
*/
static int
{
long cmd;
}
/* attempt to regain control */
return (-1);
}
else
return (0);
}
/*
* Manufacture the contents of the fake u-block.
*/
static void
{
}
/*
* Fetch the contents of u_psargs[].
*/
static void
{
int fd;
return;
}
}
/*
* Fetch the contents of u_signal[].
*/
static void
{
int fd;
int i;
}
for (i = 0; i < MAXSIG; i++)
}