2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A/*
2N/A * ptrace(2) interface built on top of proc(4).
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#pragma weak _ptrace = ptrace
2N/A
2N/A#include "lint.h"
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <memory.h>
2N/A#include <string.h>
2N/A#include <fcntl.h>
2N/A#include <errno.h>
2N/A#include <sys/types.h>
2N/A#include <sys/uio.h>
2N/A#include <signal.h>
2N/A#include <sys/siginfo.h>
2N/A#include <sys/fault.h>
2N/A#include <sys/syscall.h>
2N/A#include <procfs.h>
2N/A#include <sys/psw.h>
2N/A#include <sys/user.h>
2N/A/*
2N/A * mtlib.h must precede thread.h
2N/A */
2N/A#include <mtlib.h>
2N/A#include <thread.h>
2N/A#include <synch.h>
2N/A
2N/Astatic mutex_t pt_lock = DEFAULTMUTEX;
2N/A
2N/A#define TRUE 1
2N/A#define FALSE 0
2N/A
2N/A/*
2N/A * All my children...
2N/A */
2N/Atypedef struct cstatus {
2N/A struct cstatus *next; /* linked list */
2N/A pid_t pid; /* process-id */
2N/A int asfd; /* /proc/<pid>/as */
2N/A int ctlfd; /* /proc/<pid>/ctl */
2N/A int statusfd; /* /proc/<pid>/status */
2N/A int flags; /* see below */
2N/A pstatus_t pstatus; /* from /proc/<pid>/status */
2N/A user_t user; /* manufactured u-block */
2N/A} cstatus_t;
2N/A
2N/A/* flags */
2N/A#define CS_SETREGS 0x01 /* set registers on run */
2N/A#define CS_PSARGS 0x02 /* u_psargs[] has been fetched */
2N/A#define CS_SIGNAL 0x04 /* u_signal[] has been fetched */
2N/A
2N/A#define NULLCP ((cstatus_t *)0)
2N/A
2N/Astatic cstatus_t *childp = NULLCP;
2N/A
2N/A/* fake u-block offsets */
2N/A#define UP ((user_t *)NULL)
2N/A#define U_REG ((int)(&UP->u_reg[0]))
2N/A#define U_AR0 ((int)(&UP->u_ar0))
2N/A#define U_PSARGS ((int)(&UP->u_psargs[0]))
2N/A#define U_SIGNAL ((int)(&UP->u_signal[0]))
2N/A#define U_CODE ((int)(&UP->u_code))
2N/A#define U_ADDR ((int)(&UP->u_addr))
2N/A#define U_END ((int)sizeof (user_t))
2N/A#define REGADDR 0xffff0000 /* arbitrary kernel address for u_ar0 */
2N/A
2N/A/* external routines defined in this module */
2N/Aextern int ptrace(int, pid_t, int, int);
2N/A/* static routines defined in this module */
2N/Astatic cstatus_t *FindProc(pid_t);
2N/Astatic void CheckAllProcs(void);
2N/Astatic int Dupfd(int, int);
2N/Astatic void MakeProcName(char *, pid_t);
2N/Astatic int OpenProc(cstatus_t *);
2N/Astatic void CloseProc(cstatus_t *);
2N/Astatic cstatus_t *GrabProc(pid_t);
2N/Astatic void ReleaseProc(cstatus_t *);
2N/Astatic int ProcUpdate(cstatus_t *);
2N/Astatic void MakeUser(cstatus_t *);
2N/Astatic void GetPsargs(cstatus_t *);
2N/Astatic void GetSignal(cstatus_t *);
2N/A
2N/A#if PTRACE_DEBUG
2N/A/* for debugging */
2N/Astatic char *
2N/Amap(int request)
2N/A{
2N/A static char name[20];
2N/A
2N/A switch (request) {
2N/A case 0: return ("PTRACE_TRACEME");
2N/A case 1: return ("PTRACE_PEEKTEXT");
2N/A case 2: return ("PTRACE_PEEKDATA");
2N/A case 3: return ("PTRACE_PEEKUSER");
2N/A case 4: return ("PTRACE_POKETEXT");
2N/A case 5: return ("PTRACE_POKEDATA");
2N/A case 6: return ("PTRACE_POKEUSER");
2N/A case 7: return ("PTRACE_CONT");
2N/A case 8: return ("PTRACE_KILL");
2N/A case 9: return ("PTRACE_SINGLESTEP");
2N/A }
2N/A (void) sprintf(name, "%d", request);
2N/A return (name);
2N/A}
2N/A#endif
2N/A
2N/Aint
2N/Aptrace(int request, pid_t pid, int addr, int data)
2N/A{
2N/A pstatus_t *ps;
2N/A cstatus_t *cp;
2N/A unsigned xaddr;
2N/A struct {
2N/A long cmd;
2N/A union {
2N/A long flags;
2N/A sigset_t signals;
2N/A fltset_t faults;
2N/A sysset_t syscalls;
2N/A siginfo_t siginfo;
2N/A } arg;
2N/A } ctl;
2N/A
2N/A#if PTRACE_DEBUG
2N/A fprintf(stderr, " ptrace(%s, 0x%X, 0x%X, 0x%X)\n",
2N/A map(request), pid, addr, data);
2N/A#endif
2N/A
2N/A (void) mutex_lock(&pt_lock);
2N/A
2N/A if (request == 0) { /* PTRACE_TRACEME, executed by traced process */
2N/A /*
2N/A * Set stop-on-all-signals and nothing else.
2N/A * Turn off inherit-on-fork flag (grandchildren run away).
2N/A * Set ptrace-compatible flag.
2N/A */
2N/A char procname[64]; /* /proc/<pid>/ctl */
2N/A int fd;
2N/A
2N/A MakeProcName(procname, getpid());
2N/A (void) strcat(procname, "/ctl");
2N/A if ((fd = open(procname, O_WRONLY, 0)) < 0)
2N/A exit(255);
2N/A ctl.cmd = PCSTRACE;
2N/A prfillset(&ctl.arg.signals);
2N/A if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sigset_t))
2N/A != sizeof (long)+sizeof (sigset_t))
2N/A exit(255);
2N/A ctl.cmd = PCSFAULT;
2N/A premptyset(&ctl.arg.faults);
2N/A if (write(fd, (char *)&ctl, sizeof (long)+sizeof (fltset_t))
2N/A != sizeof (long)+sizeof (fltset_t))
2N/A exit(255);
2N/A ctl.cmd = PCSENTRY;
2N/A premptyset(&ctl.arg.syscalls);
2N/A if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sysset_t))
2N/A != sizeof (long)+sizeof (sysset_t))
2N/A exit(255);
2N/A ctl.cmd = PCSEXIT;
2N/A premptyset(&ctl.arg.syscalls);
2N/A if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sysset_t))
2N/A != sizeof (long)+sizeof (sysset_t))
2N/A exit(255);
2N/A ctl.cmd = PCUNSET;
2N/A ctl.arg.flags = PR_FORK;
2N/A if (write(fd, (char *)&ctl, sizeof (long)+sizeof (long))
2N/A != sizeof (long)+sizeof (long))
2N/A exit(255);
2N/A ctl.cmd = PCSET;
2N/A ctl.arg.flags = PR_PTRACE;
2N/A if (write(fd, (char *)&ctl, sizeof (long)+sizeof (long))
2N/A != sizeof (long)+sizeof (long))
2N/A exit(255);
2N/A if (close(fd) != 0)
2N/A exit(255);
2N/A
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (0);
2N/A }
2N/A
2N/Aagain:
2N/A errno = 0;
2N/A
2N/A /* find the cstatus structure corresponding to pid */
2N/A if ((cp = GrabProc(pid)) == NULLCP)
2N/A goto esrch;
2N/A
2N/A ps = &cp->pstatus;
2N/A if (!(ps->pr_flags & PR_ISTOP)) {
2N/A if (ProcUpdate(cp) != 0) {
2N/A ReleaseProc(cp);
2N/A goto esrch;
2N/A }
2N/A if (!(ps->pr_flags & PR_ISTOP))
2N/A goto esrch;
2N/A }
2N/A
2N/A /*
2N/A * Process the request.
2N/A */
2N/A errno = 0;
2N/A switch (request) {
2N/A case 1: /* PTRACE_PEEKTEXT */
2N/A case 2: /* PTRACE_PEEKDATA */
2N/A if (addr & 03)
2N/A goto eio;
2N/A if (pread(cp->asfd, (char *)&data, sizeof (data), (off_t)addr)
2N/A == sizeof (data)) {
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (data);
2N/A }
2N/A goto eio;
2N/A
2N/A case 3: /* PTRACE_PEEKUSER */
2N/A if (addr & 03)
2N/A goto eio;
2N/A xaddr = addr;
2N/A if (xaddr >= REGADDR && xaddr < REGADDR+sizeof (gregset_t))
2N/A xaddr -= REGADDR-U_REG;
2N/A if (xaddr >= U_PSARGS && xaddr < U_PSARGS+sizeof (UP->u_psargs))
2N/A GetPsargs(cp);
2N/A if (xaddr >= U_SIGNAL && xaddr < U_SIGNAL+sizeof (UP->u_signal))
2N/A GetSignal(cp);
2N/A if ((int)xaddr >= 0 && xaddr < U_END) {
2N/A /* LINTED pointer alignment */
2N/A data = *((int *)((caddr_t)(&cp->user) + xaddr));
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (data);
2N/A }
2N/A goto eio;
2N/A
2N/A case 4: /* PTRACE_POKETEXT */
2N/A case 5: /* PTRACE_POKEDATA */
2N/A if (addr & 03)
2N/A goto eio;
2N/A if (pwrite(cp->asfd, (char *)&data, sizeof (data), (off_t)addr)
2N/A == sizeof (data)) {
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (data);
2N/A }
2N/A goto eio;
2N/A
2N/A case 6: /* PTRACE_POKEUSER */
2N/A if (addr & 03)
2N/A goto eio;
2N/A xaddr = addr;
2N/A if (xaddr >= REGADDR && xaddr < REGADDR+sizeof (gregset_t))
2N/A xaddr -= REGADDR-U_REG;
2N/A if ((int)xaddr >= U_REG && xaddr < U_REG+sizeof (gregset_t)) {
2N/A int rx = (xaddr-U_REG)/sizeof (greg_t);
2N/A if (rx == EFL)
2N/A data = (cp->user.u_reg[EFL] & ~PSL_USERMASK) |
2N/A (data & PSL_USERMASK);
2N/A cp->user.u_reg[rx] = data;
2N/A cp->flags |= CS_SETREGS;
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (data);
2N/A }
2N/A goto eio;
2N/A
2N/A case 7: /* PTRACE_CONT */
2N/A case 9: /* PTRACE_SINGLESTEP */
2N/A {
2N/A long runctl[3];
2N/A
2N/A if (cp->flags & CS_SETREGS) {
2N/A long cmd;
2N/A iovec_t iov[2];
2N/A
2N/A ps->pr_lwp.pr_reg[GS] = cp->user.u_reg[GS];
2N/A ps->pr_lwp.pr_reg[FS] = cp->user.u_reg[FS];
2N/A ps->pr_lwp.pr_reg[ES] = cp->user.u_reg[ES];
2N/A ps->pr_lwp.pr_reg[DS] = cp->user.u_reg[DS];
2N/A ps->pr_lwp.pr_reg[EDI] = cp->user.u_reg[EDI];
2N/A ps->pr_lwp.pr_reg[ESI] = cp->user.u_reg[ESI];
2N/A ps->pr_lwp.pr_reg[EBP] = cp->user.u_reg[EBP];
2N/A ps->pr_lwp.pr_reg[ESP] = cp->user.u_reg[ESP];
2N/A ps->pr_lwp.pr_reg[EBX] = cp->user.u_reg[EBX];
2N/A ps->pr_lwp.pr_reg[EDX] = cp->user.u_reg[EDX];
2N/A ps->pr_lwp.pr_reg[ECX] = cp->user.u_reg[ECX];
2N/A ps->pr_lwp.pr_reg[EAX] = cp->user.u_reg[EAX];
2N/A ps->pr_lwp.pr_reg[TRAPNO] = cp->user.u_reg[TRAPNO];
2N/A ps->pr_lwp.pr_reg[ERR] = cp->user.u_reg[ERR];
2N/A ps->pr_lwp.pr_reg[EIP] = cp->user.u_reg[EIP];
2N/A ps->pr_lwp.pr_reg[CS] = cp->user.u_reg[CS];
2N/A ps->pr_lwp.pr_reg[EFL] = cp->user.u_reg[EFL];
2N/A ps->pr_lwp.pr_reg[UESP] = cp->user.u_reg[UESP];
2N/A ps->pr_lwp.pr_reg[SS] = cp->user.u_reg[SS];
2N/A cmd = PCSREG;
2N/A iov[0].iov_base = (caddr_t)&cmd;
2N/A iov[0].iov_len = sizeof (long);
2N/A iov[1].iov_base = (caddr_t)&ps->pr_lwp.pr_reg[0];
2N/A iov[1].iov_len = sizeof (ps->pr_lwp.pr_reg);
2N/A if (writev(cp->ctlfd, iov, 2) < 0)
2N/A goto tryagain;
2N/A }
2N/A if (addr != 1 && /* new virtual address */
2N/A addr != cp->user.u_reg[EIP]) {
2N/A runctl[0] = PCSVADDR;
2N/A runctl[1] = addr;
2N/A if (write(cp->ctlfd, (char *)runctl, 2*sizeof (long))
2N/A != 2*sizeof (long))
2N/A goto tryagain;
2N/A }
2N/A /* make data the current signal */
2N/A if (data != 0 && data != ps->pr_lwp.pr_cursig) {
2N/A (void) memset((char *)&ctl.arg.siginfo, 0,
2N/A sizeof (siginfo_t));
2N/A ctl.arg.siginfo.si_signo = data;
2N/A ctl.cmd = PCSSIG;
2N/A if (write(cp->ctlfd, (char *)&ctl,
2N/A sizeof (long)+sizeof (siginfo_t))
2N/A != sizeof (long)+sizeof (siginfo_t))
2N/A goto tryagain;
2N/A }
2N/A if (data == 0)
2N/A runctl[0] = PCCSIG;
2N/A else
2N/A runctl[0] = PCNULL;
2N/A runctl[1] = PCRUN;
2N/A runctl[2] = (request == 9)? PRSTEP : 0;
2N/A if (write(cp->ctlfd, (char *)runctl, 3*sizeof (long))
2N/A != 3*sizeof (long)) {
2N/A if (errno == ENOENT) {
2N/A /* current signal must have killed it */
2N/A ReleaseProc(cp);
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (data);
2N/A }
2N/A goto tryagain;
2N/A }
2N/A (void) memset((char *)ps, 0, sizeof (pstatus_t));
2N/A cp->flags = 0;
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (data);
2N/A }
2N/A
2N/A case 8: /* PTRACE_KILL */
2N/A /* overkill? */
2N/A (void) memset((char *)&ctl.arg.siginfo, 0, sizeof (siginfo_t));
2N/A ctl.arg.siginfo.si_signo = SIGKILL;
2N/A ctl.cmd = PCSSIG;
2N/A (void) write(cp->ctlfd, (char *)&ctl,
2N/A sizeof (long)+sizeof (siginfo_t));
2N/A (void) kill(pid, SIGKILL);
2N/A ReleaseProc(cp);
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (0);
2N/A
2N/A default:
2N/A goto eio;
2N/A }
2N/A
2N/Atryagain:
2N/A if (errno == EAGAIN) {
2N/A if (OpenProc(cp) == 0)
2N/A goto again;
2N/A ReleaseProc(cp);
2N/A }
2N/Aeio:
2N/A errno = EIO;
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (-1);
2N/Aesrch:
2N/A errno = ESRCH;
2N/A (void) mutex_unlock(&pt_lock);
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Find the cstatus structure corresponding to pid.
2N/A */
2N/Astatic cstatus_t *
2N/AFindProc(pid_t pid)
2N/A{
2N/A cstatus_t *cp;
2N/A
2N/A for (cp = childp; cp != NULLCP; cp = cp->next)
2N/A if (cp->pid == pid)
2N/A break;
2N/A
2N/A return (cp);
2N/A}
2N/A
2N/A/*
2N/A * Check every proc for existence, release those that are gone.
2N/A * Be careful about the linked list; ReleaseProc() changes it.
2N/A */
2N/Astatic void
2N/ACheckAllProcs()
2N/A{
2N/A cstatus_t *cp = childp;
2N/A
2N/A while (cp != NULLCP) {
2N/A cstatus_t *next = cp->next;
2N/A
2N/A if (ProcUpdate(cp) != 0)
2N/A ReleaseProc(cp);
2N/A cp = next;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Utility for OpenProc().
2N/A */
2N/Astatic int
2N/ADupfd(int fd, int dfd)
2N/A{
2N/A /*
2N/A * Make sure fd not one of 0, 1, or 2 to avoid stdio interference.
2N/A * Also, if dfd is greater than 2, dup fd to be exactly dfd.
2N/A */
2N/A if (dfd > 2 || (0 <= fd && fd <= 2)) {
2N/A if (dfd > 2 && fd != dfd)
2N/A (void) close(dfd);
2N/A else
2N/A dfd = 3;
2N/A if (fd != dfd) {
2N/A dfd = fcntl(fd, F_DUPFD, (intptr_t)dfd);
2N/A (void) close(fd);
2N/A fd = dfd;
2N/A }
2N/A }
2N/A /*
2N/A * Mark filedescriptor close-on-exec.
2N/A * Should also be close-on-return-from-fork-in-child.
2N/A */
2N/A (void) fcntl(fd, F_SETFD, (intptr_t)1);
2N/A return (fd);
2N/A}
2N/A
2N/A/*
2N/A * Construct the /proc directory name: "/proc/<pid>"
2N/A * The name buffer passed by the caller must be large enough.
2N/A */
2N/Astatic void
2N/AMakeProcName(char *procname, pid_t pid)
2N/A{
2N/A (void) sprintf(procname, "/proc/%ld", pid);
2N/A}
2N/A
2N/A/*
2N/A * Open/reopen the /proc/<pid> files.
2N/A */
2N/Astatic int
2N/AOpenProc(cstatus_t *cp)
2N/A{
2N/A char procname[64]; /* /proc/nnnnn/fname */
2N/A char *fname;
2N/A int fd;
2N/A int omode;
2N/A
2N/A MakeProcName(procname, cp->pid);
2N/A fname = procname + strlen(procname);
2N/A
2N/A /*
2N/A * Use exclusive-open only if this is the first open.
2N/A */
2N/A omode = (cp->asfd > 0)? O_RDWR : (O_RDWR|O_EXCL);
2N/A (void) strcpy(fname, "/as");
2N/A if ((fd = open(procname, omode, 0)) < 0 ||
2N/A (cp->asfd = Dupfd(fd, cp->asfd)) < 0)
2N/A goto err;
2N/A
2N/A (void) strcpy(fname, "/ctl");
2N/A if ((fd = open(procname, O_WRONLY, 0)) < 0 ||
2N/A (cp->ctlfd = Dupfd(fd, cp->ctlfd)) < 0)
2N/A goto err;
2N/A
2N/A (void) strcpy(fname, "/status");
2N/A if ((fd = open(procname, O_RDONLY, 0)) < 0 ||
2N/A (cp->statusfd = Dupfd(fd, cp->statusfd)) < 0)
2N/A goto err;
2N/A
2N/A return (0);
2N/A
2N/Aerr:
2N/A CloseProc(cp);
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Close the /proc/<pid> files.
2N/A */
2N/Astatic void
2N/ACloseProc(cstatus_t *cp)
2N/A{
2N/A if (cp->asfd > 0)
2N/A (void) close(cp->asfd);
2N/A if (cp->ctlfd > 0)
2N/A (void) close(cp->ctlfd);
2N/A if (cp->statusfd > 0)
2N/A (void) close(cp->statusfd);
2N/A cp->asfd = 0;
2N/A cp->ctlfd = 0;
2N/A cp->statusfd = 0;
2N/A}
2N/A
2N/A/*
2N/A * Take control of a child process.
2N/A */
2N/Astatic cstatus_t *
2N/AGrabProc(pid_t pid)
2N/A{
2N/A cstatus_t *cp;
2N/A long ctl[2];
2N/A pid_t ppid;
2N/A
2N/A if (pid <= 0)
2N/A return (NULLCP);
2N/A
2N/A if ((cp = FindProc(pid)) != NULLCP) /* already grabbed */
2N/A return (cp);
2N/A
2N/A CheckAllProcs(); /* clean up before grabbing new process */
2N/A
2N/A cp = (cstatus_t *)malloc(sizeof (cstatus_t));
2N/A if (cp == NULLCP)
2N/A return (NULLCP);
2N/A (void) memset((char *)cp, 0, sizeof (cstatus_t));
2N/A cp->pid = pid;
2N/A
2N/A ppid = getpid();
2N/A while (OpenProc(cp) == 0) {
2N/A ctl[0] = PCSET;
2N/A ctl[1] = PR_RLC;
2N/A errno = 0;
2N/A
2N/A if (pread(cp->statusfd, (char *)&cp->pstatus,
2N/A sizeof (cp->pstatus), (off_t)0) == sizeof (cp->pstatus) &&
2N/A cp->pstatus.pr_ppid == ppid &&
2N/A (cp->pstatus.pr_flags & PR_PTRACE) &&
2N/A write(cp->ctlfd, (char *)ctl, 2*sizeof (long))
2N/A == 2*sizeof (long)) {
2N/A cp->next = childp;
2N/A childp = cp;
2N/A MakeUser(cp);
2N/A return (cp);
2N/A }
2N/A
2N/A if (errno != EAGAIN)
2N/A break;
2N/A }
2N/A
2N/A free((char *)cp);
2N/A return (NULLCP);
2N/A}
2N/A
2N/A/*
2N/A * Close the /proc/<pid> file, if open.
2N/A * Deallocate the memory used by the cstatus_t structure.
2N/A */
2N/Astatic void
2N/AReleaseProc(cstatus_t *cp)
2N/A{
2N/A CloseProc(cp);
2N/A
2N/A if (childp == cp)
2N/A childp = cp->next;
2N/A else {
2N/A cstatus_t *pcp;
2N/A
2N/A for (pcp = childp; pcp != NULLCP; pcp = pcp->next) {
2N/A if (pcp->next == cp) {
2N/A pcp->next = cp->next;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A free((char *)cp);
2N/A}
2N/A
2N/A/*
2N/A * Update process information from /proc.
2N/A * Return 0 on success, -1 on failure.
2N/A */
2N/Astatic int
2N/AProcUpdate(cstatus_t *cp)
2N/A{
2N/A pstatus_t *ps = &cp->pstatus;
2N/A
2N/A if (cp->flags & CS_SETREGS) {
2N/A long cmd;
2N/A iovec_t iov[2];
2N/A
2N/A ps->pr_lwp.pr_reg[GS] = cp->user.u_reg[GS];
2N/A ps->pr_lwp.pr_reg[FS] = cp->user.u_reg[FS];
2N/A ps->pr_lwp.pr_reg[ES] = cp->user.u_reg[ES];
2N/A ps->pr_lwp.pr_reg[DS] = cp->user.u_reg[DS];
2N/A ps->pr_lwp.pr_reg[EDI] = cp->user.u_reg[EDI];
2N/A ps->pr_lwp.pr_reg[ESI] = cp->user.u_reg[ESI];
2N/A ps->pr_lwp.pr_reg[EBP] = cp->user.u_reg[EBP];
2N/A ps->pr_lwp.pr_reg[ESP] = cp->user.u_reg[ESP];
2N/A ps->pr_lwp.pr_reg[EBX] = cp->user.u_reg[EBX];
2N/A ps->pr_lwp.pr_reg[EDX] = cp->user.u_reg[EDX];
2N/A ps->pr_lwp.pr_reg[ECX] = cp->user.u_reg[ECX];
2N/A ps->pr_lwp.pr_reg[EAX] = cp->user.u_reg[EAX];
2N/A ps->pr_lwp.pr_reg[TRAPNO] = cp->user.u_reg[TRAPNO];
2N/A ps->pr_lwp.pr_reg[ERR] = cp->user.u_reg[ERR];
2N/A ps->pr_lwp.pr_reg[EIP] = cp->user.u_reg[EIP];
2N/A ps->pr_lwp.pr_reg[CS] = cp->user.u_reg[CS];
2N/A ps->pr_lwp.pr_reg[EFL] = cp->user.u_reg[EFL];
2N/A ps->pr_lwp.pr_reg[UESP] = cp->user.u_reg[UESP];
2N/A ps->pr_lwp.pr_reg[SS] = cp->user.u_reg[SS];
2N/A cmd = PCSREG;
2N/A iov[0].iov_base = (caddr_t)&cmd;
2N/A iov[0].iov_len = sizeof (long);
2N/A iov[1].iov_base = (caddr_t)&ps->pr_lwp.pr_reg[0];
2N/A iov[1].iov_len = sizeof (ps->pr_lwp.pr_reg);
2N/A (void) writev(cp->ctlfd, iov, 2);
2N/A cp->flags &= ~CS_SETREGS;
2N/A }
2N/A
2N/A while (pread(cp->statusfd, (char *)ps, sizeof (*ps), (off_t)0) < 0) {
2N/A /* attempt to regain control */
2N/A if (errno != EINTR &&
2N/A !(errno == EAGAIN && OpenProc(cp) == 0))
2N/A return (-1);
2N/A }
2N/A
2N/A if (ps->pr_flags & PR_ISTOP)
2N/A MakeUser(cp);
2N/A else
2N/A (void) memset((char *)ps, 0, sizeof (pstatus_t));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Manufacture the contents of the fake u-block.
2N/A */
2N/Astatic void
2N/AMakeUser(cstatus_t *cp)
2N/A{
2N/A pstatus_t *ps = &cp->pstatus;
2N/A
2N/A cp->user.u_reg[GS] = ps->pr_lwp.pr_reg[GS];
2N/A cp->user.u_reg[FS] = ps->pr_lwp.pr_reg[FS];
2N/A cp->user.u_reg[ES] = ps->pr_lwp.pr_reg[ES];
2N/A cp->user.u_reg[DS] = ps->pr_lwp.pr_reg[DS];
2N/A cp->user.u_reg[EDI] = ps->pr_lwp.pr_reg[EDI];
2N/A cp->user.u_reg[ESI] = ps->pr_lwp.pr_reg[ESI];
2N/A cp->user.u_reg[EBP] = ps->pr_lwp.pr_reg[EBP];
2N/A cp->user.u_reg[ESP] = ps->pr_lwp.pr_reg[ESP];
2N/A cp->user.u_reg[EBX] = ps->pr_lwp.pr_reg[EBX];
2N/A cp->user.u_reg[EDX] = ps->pr_lwp.pr_reg[EDX];
2N/A cp->user.u_reg[ECX] = ps->pr_lwp.pr_reg[ECX];
2N/A cp->user.u_reg[EAX] = ps->pr_lwp.pr_reg[EAX];
2N/A cp->user.u_reg[TRAPNO] = ps->pr_lwp.pr_reg[TRAPNO];
2N/A cp->user.u_reg[ERR] = ps->pr_lwp.pr_reg[ERR];
2N/A cp->user.u_reg[EIP] = ps->pr_lwp.pr_reg[EIP];
2N/A cp->user.u_reg[CS] = ps->pr_lwp.pr_reg[CS];
2N/A cp->user.u_reg[EFL] = ps->pr_lwp.pr_reg[EFL];
2N/A cp->user.u_reg[UESP] = ps->pr_lwp.pr_reg[UESP];
2N/A cp->user.u_reg[SS] = ps->pr_lwp.pr_reg[SS];
2N/A cp->user.u_ar0 = (greg_t *)REGADDR;
2N/A cp->user.u_code = ps->pr_lwp.pr_info.si_code;
2N/A cp->user.u_addr = ps->pr_lwp.pr_info.si_addr;
2N/A cp->flags &= ~(CS_PSARGS|CS_SIGNAL);
2N/A}
2N/A
2N/A/*
2N/A * Fetch the contents of u_psargs[].
2N/A */
2N/Astatic void
2N/AGetPsargs(cstatus_t *cp)
2N/A{
2N/A char procname[64]; /* /proc/<pid>/psinfo */
2N/A int fd;
2N/A
2N/A MakeProcName(procname, cp->pid);
2N/A (void) strcat(procname, "/psinfo");
2N/A if ((fd = open(procname, O_RDONLY, 0)) < 0) {
2N/A (void) memset(cp->user.u_psargs, 0, PSARGSZ);
2N/A return;
2N/A }
2N/A (void) pread(fd, cp->user.u_psargs, PSARGSZ,
2N/A (off_t)((psinfo_t *)0)->pr_psargs);
2N/A (void) close(fd);
2N/A
2N/A cp->flags |= CS_PSARGS;
2N/A}
2N/A
2N/A/*
2N/A * Fetch the contents of u_signal[].
2N/A */
2N/Astatic void
2N/AGetSignal(cstatus_t *cp)
2N/A{
2N/A char procname[64]; /* /proc/<pid>/sigact */
2N/A int fd;
2N/A struct sigaction action[MAXSIG];
2N/A int i;
2N/A
2N/A MakeProcName(procname, cp->pid);
2N/A (void) strcat(procname, "/sigact");
2N/A (void) memset((char *)action, 0, sizeof (action));
2N/A if ((fd = open(procname, O_RDONLY, 0)) >= 0) {
2N/A (void) read(fd, (char *)action, sizeof (action));
2N/A (void) close(fd);
2N/A }
2N/A for (i = 0; i < MAXSIG; i++)
2N/A cp->user.u_signal[i] = action[i].sa_handler;
2N/A cp->flags |= CS_SIGNAL;
2N/A}