1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * ptrace(2) interface built on top of proc(4).
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#pragma weak _ptrace = ptrace
34
35#include "lint.h"
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <memory.h>
40#include <string.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <sys/types.h>
44#include <sys/uio.h>
45#include <signal.h>
46#include <sys/siginfo.h>
47#include <sys/fault.h>
48#include <sys/syscall.h>
49#include <procfs.h>
50#include <sys/psw.h>
51#include <sys/user.h>
52/*
53 * mtlib.h must precede thread.h
54 */
55#include <mtlib.h>
56#include <thread.h>
57#include <synch.h>
58
59static mutex_t pt_lock = DEFAULTMUTEX;
60
61#define	TRUE	1
62#define	FALSE	0
63
64/*
65 * All my children...
66 */
67typedef struct cstatus {
68	struct cstatus	*next;		/* linked list			*/
69	pid_t		pid;		/* process-id			*/
70	int		asfd;		/* /proc/<pid>/as		*/
71	int		ctlfd;		/* /proc/<pid>/ctl		*/
72	int		statusfd;	/* /proc/<pid>/status		*/
73	int		flags;		/* see below			*/
74	pstatus_t	pstatus;	/* from /proc/<pid>/status	*/
75	user_t		user;		/* manufactured u-block		*/
76} cstatus_t;
77
78/* flags */
79#define	CS_SETREGS	0x01		/* set registers on run		*/
80#define	CS_PSARGS	0x02		/* u_psargs[] has been fetched	*/
81#define	CS_SIGNAL	0x04		/* u_signal[] has been fetched	*/
82
83#define	NULLCP	((cstatus_t *)0)
84
85static cstatus_t *childp = NULLCP;
86
87/* fake u-block offsets */
88#define	UP		((user_t *)NULL)
89#define	U_REG		((int)(&UP->u_reg[0]))
90#define	U_AR0		((int)(&UP->u_ar0))
91#define	U_PSARGS	((int)(&UP->u_psargs[0]))
92#define	U_SIGNAL	((int)(&UP->u_signal[0]))
93#define	U_CODE		((int)(&UP->u_code))
94#define	U_ADDR		((int)(&UP->u_addr))
95#define	U_END		((int)sizeof (user_t))
96#define	REGADDR		0xffff0000	/* arbitrary kernel address for u_ar0 */
97
98/* external routines defined in this module */
99extern	int	ptrace(int, pid_t, int, int);
100/* static routines defined in this module */
101static	cstatus_t *FindProc(pid_t);
102static	void	CheckAllProcs(void);
103static	int	Dupfd(int, int);
104static	void	MakeProcName(char *, pid_t);
105static	int	OpenProc(cstatus_t *);
106static	void	CloseProc(cstatus_t *);
107static	cstatus_t *GrabProc(pid_t);
108static	void	ReleaseProc(cstatus_t *);
109static	int	ProcUpdate(cstatus_t *);
110static	void	MakeUser(cstatus_t *);
111static	void	GetPsargs(cstatus_t *);
112static	void	GetSignal(cstatus_t *);
113
114#if PTRACE_DEBUG
115/* for debugging */
116static char *
117map(int request)
118{
119	static char name[20];
120
121	switch (request) {
122	case 0:	return ("PTRACE_TRACEME");
123	case 1:	return ("PTRACE_PEEKTEXT");
124	case 2:	return ("PTRACE_PEEKDATA");
125	case 3:	return ("PTRACE_PEEKUSER");
126	case 4:	return ("PTRACE_POKETEXT");
127	case 5:	return ("PTRACE_POKEDATA");
128	case 6:	return ("PTRACE_POKEUSER");
129	case 7:	return ("PTRACE_CONT");
130	case 8:	return ("PTRACE_KILL");
131	case 9:	return ("PTRACE_SINGLESTEP");
132	}
133	(void) sprintf(name, "%d", request);
134	return (name);
135}
136#endif
137
138int
139ptrace(int request, pid_t pid, int addr, int data)
140{
141	pstatus_t *ps;
142	cstatus_t *cp;
143	unsigned xaddr;
144	struct {
145		long cmd;
146		union {
147			long flags;
148			sigset_t signals;
149			fltset_t faults;
150			sysset_t syscalls;
151			siginfo_t siginfo;
152		} arg;
153	} ctl;
154
155#if PTRACE_DEBUG
156	fprintf(stderr, " ptrace(%s, 0x%X, 0x%X, 0x%X)\n",
157	    map(request), pid, addr, data);
158#endif
159
160	(void) mutex_lock(&pt_lock);
161
162	if (request == 0) {	/* PTRACE_TRACEME, executed by traced process */
163		/*
164		 * Set stop-on-all-signals and nothing else.
165		 * Turn off inherit-on-fork flag (grandchildren run away).
166		 * Set ptrace-compatible flag.
167		 */
168		char procname[64];	/* /proc/<pid>/ctl */
169		int fd;
170
171		MakeProcName(procname, getpid());
172		(void) strcat(procname, "/ctl");
173		if ((fd = open(procname, O_WRONLY, 0)) < 0)
174			exit(255);
175		ctl.cmd = PCSTRACE;
176		prfillset(&ctl.arg.signals);
177		if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sigset_t))
178		    != sizeof (long)+sizeof (sigset_t))
179			exit(255);
180		ctl.cmd = PCSFAULT;
181		premptyset(&ctl.arg.faults);
182		if (write(fd, (char *)&ctl, sizeof (long)+sizeof (fltset_t))
183		    != sizeof (long)+sizeof (fltset_t))
184			exit(255);
185		ctl.cmd = PCSENTRY;
186		premptyset(&ctl.arg.syscalls);
187		if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sysset_t))
188		    != sizeof (long)+sizeof (sysset_t))
189			exit(255);
190		ctl.cmd = PCSEXIT;
191		premptyset(&ctl.arg.syscalls);
192		if (write(fd, (char *)&ctl, sizeof (long)+sizeof (sysset_t))
193		    != sizeof (long)+sizeof (sysset_t))
194			exit(255);
195		ctl.cmd = PCUNSET;
196		ctl.arg.flags = PR_FORK;
197		if (write(fd, (char *)&ctl, sizeof (long)+sizeof (long))
198		    != sizeof (long)+sizeof (long))
199			exit(255);
200		ctl.cmd = PCSET;
201		ctl.arg.flags = PR_PTRACE;
202		if (write(fd, (char *)&ctl, sizeof (long)+sizeof (long))
203		    != sizeof (long)+sizeof (long))
204			exit(255);
205		if (close(fd) != 0)
206			exit(255);
207
208		(void) mutex_unlock(&pt_lock);
209		return (0);
210	}
211
212again:
213	errno = 0;
214
215	/* find the cstatus structure corresponding to pid */
216	if ((cp = GrabProc(pid)) == NULLCP)
217		goto esrch;
218
219	ps = &cp->pstatus;
220	if (!(ps->pr_flags & PR_ISTOP)) {
221		if (ProcUpdate(cp) != 0) {
222			ReleaseProc(cp);
223			goto esrch;
224		}
225		if (!(ps->pr_flags & PR_ISTOP))
226			goto esrch;
227	}
228
229	/*
230	 * Process the request.
231	 */
232	errno = 0;
233	switch (request) {
234	case 1:		/* PTRACE_PEEKTEXT */
235	case 2:		/* PTRACE_PEEKDATA */
236		if (addr & 03)
237			goto eio;
238		if (pread(cp->asfd, (char *)&data, sizeof (data), (off_t)addr)
239		    == sizeof (data)) {
240			(void) mutex_unlock(&pt_lock);
241			return (data);
242		}
243		goto eio;
244
245	case 3:		/* PTRACE_PEEKUSER */
246		if (addr & 03)
247			goto eio;
248		xaddr = addr;
249		if (xaddr >= REGADDR && xaddr < REGADDR+sizeof (gregset_t))
250			xaddr -= REGADDR-U_REG;
251		if (xaddr >= U_PSARGS && xaddr < U_PSARGS+sizeof (UP->u_psargs))
252			GetPsargs(cp);
253		if (xaddr >= U_SIGNAL && xaddr < U_SIGNAL+sizeof (UP->u_signal))
254			GetSignal(cp);
255		if ((int)xaddr >= 0 && xaddr < U_END) {
256			/* LINTED pointer alignment */
257			data = *((int *)((caddr_t)(&cp->user) + xaddr));
258			(void) mutex_unlock(&pt_lock);
259			return (data);
260		}
261		goto eio;
262
263	case 4:		/* PTRACE_POKETEXT */
264	case 5:		/* PTRACE_POKEDATA */
265		if (addr & 03)
266			goto eio;
267		if (pwrite(cp->asfd, (char *)&data, sizeof (data), (off_t)addr)
268		    == sizeof (data)) {
269			(void) mutex_unlock(&pt_lock);
270			return (data);
271		}
272		goto eio;
273
274	case 6:		/* PTRACE_POKEUSER */
275		if (addr & 03)
276			goto eio;
277		xaddr = addr;
278		if (xaddr >= REGADDR && xaddr < REGADDR+sizeof (gregset_t))
279			xaddr -= REGADDR-U_REG;
280		if ((int)xaddr >= U_REG && xaddr < U_REG+sizeof (gregset_t)) {
281			int rx = (xaddr-U_REG)/sizeof (greg_t);
282			if (rx == EFL)
283				data = (cp->user.u_reg[EFL] & ~PSL_USERMASK) |
284				    (data & PSL_USERMASK);
285			cp->user.u_reg[rx] = data;
286			cp->flags |= CS_SETREGS;
287			(void) mutex_unlock(&pt_lock);
288			return (data);
289		}
290		goto eio;
291
292	case 7:		/* PTRACE_CONT */
293	case 9:		/* PTRACE_SINGLESTEP */
294	{
295		long runctl[3];
296
297		if (cp->flags & CS_SETREGS) {
298			long cmd;
299			iovec_t iov[2];
300
301			ps->pr_lwp.pr_reg[GS] = cp->user.u_reg[GS];
302			ps->pr_lwp.pr_reg[FS] = cp->user.u_reg[FS];
303			ps->pr_lwp.pr_reg[ES] = cp->user.u_reg[ES];
304			ps->pr_lwp.pr_reg[DS] = cp->user.u_reg[DS];
305			ps->pr_lwp.pr_reg[EDI] = cp->user.u_reg[EDI];
306			ps->pr_lwp.pr_reg[ESI] = cp->user.u_reg[ESI];
307			ps->pr_lwp.pr_reg[EBP] = cp->user.u_reg[EBP];
308			ps->pr_lwp.pr_reg[ESP] = cp->user.u_reg[ESP];
309			ps->pr_lwp.pr_reg[EBX] = cp->user.u_reg[EBX];
310			ps->pr_lwp.pr_reg[EDX] = cp->user.u_reg[EDX];
311			ps->pr_lwp.pr_reg[ECX] = cp->user.u_reg[ECX];
312			ps->pr_lwp.pr_reg[EAX] = cp->user.u_reg[EAX];
313			ps->pr_lwp.pr_reg[TRAPNO] = cp->user.u_reg[TRAPNO];
314			ps->pr_lwp.pr_reg[ERR] = cp->user.u_reg[ERR];
315			ps->pr_lwp.pr_reg[EIP] = cp->user.u_reg[EIP];
316			ps->pr_lwp.pr_reg[CS] = cp->user.u_reg[CS];
317			ps->pr_lwp.pr_reg[EFL] = cp->user.u_reg[EFL];
318			ps->pr_lwp.pr_reg[UESP] = cp->user.u_reg[UESP];
319			ps->pr_lwp.pr_reg[SS] = cp->user.u_reg[SS];
320			cmd = PCSREG;
321			iov[0].iov_base = (caddr_t)&cmd;
322			iov[0].iov_len = sizeof (long);
323			iov[1].iov_base = (caddr_t)&ps->pr_lwp.pr_reg[0];
324			iov[1].iov_len = sizeof (ps->pr_lwp.pr_reg);
325			if (writev(cp->ctlfd, iov, 2) < 0)
326				goto tryagain;
327		}
328		if (addr != 1 &&	/* new virtual address */
329		    addr != cp->user.u_reg[EIP]) {
330			runctl[0] = PCSVADDR;
331			runctl[1] = addr;
332			if (write(cp->ctlfd, (char *)runctl, 2*sizeof (long))
333			    != 2*sizeof (long))
334				goto tryagain;
335		}
336		/* make data the current signal */
337		if (data != 0 && data != ps->pr_lwp.pr_cursig) {
338			(void) memset((char *)&ctl.arg.siginfo, 0,
339			    sizeof (siginfo_t));
340			ctl.arg.siginfo.si_signo = data;
341			ctl.cmd = PCSSIG;
342			if (write(cp->ctlfd, (char *)&ctl,
343			    sizeof (long)+sizeof (siginfo_t))
344			    != sizeof (long)+sizeof (siginfo_t))
345				goto tryagain;
346		}
347		if (data == 0)
348			runctl[0] = PCCSIG;
349		else
350			runctl[0] = PCNULL;
351		runctl[1] = PCRUN;
352		runctl[2] = (request == 9)? PRSTEP : 0;
353		if (write(cp->ctlfd, (char *)runctl, 3*sizeof (long))
354		    != 3*sizeof (long)) {
355			if (errno == ENOENT) {
356				/* current signal must have killed it */
357				ReleaseProc(cp);
358				(void) mutex_unlock(&pt_lock);
359				return (data);
360			}
361			goto tryagain;
362		}
363		(void) memset((char *)ps, 0, sizeof (pstatus_t));
364		cp->flags = 0;
365		(void) mutex_unlock(&pt_lock);
366		return (data);
367	}
368
369	case 8:		/* PTRACE_KILL */
370		/* overkill? */
371		(void) memset((char *)&ctl.arg.siginfo, 0, sizeof (siginfo_t));
372		ctl.arg.siginfo.si_signo = SIGKILL;
373		ctl.cmd = PCSSIG;
374		(void) write(cp->ctlfd, (char *)&ctl,
375		    sizeof (long)+sizeof (siginfo_t));
376		(void) kill(pid, SIGKILL);
377		ReleaseProc(cp);
378		(void) mutex_unlock(&pt_lock);
379		return (0);
380
381	default:
382		goto eio;
383	}
384
385tryagain:
386	if (errno == EAGAIN) {
387		if (OpenProc(cp) == 0)
388			goto again;
389		ReleaseProc(cp);
390	}
391eio:
392	errno = EIO;
393	(void) mutex_unlock(&pt_lock);
394	return (-1);
395esrch:
396	errno = ESRCH;
397	(void) mutex_unlock(&pt_lock);
398	return (-1);
399}
400
401/*
402 * Find the cstatus structure corresponding to pid.
403 */
404static cstatus_t *
405FindProc(pid_t pid)
406{
407	cstatus_t *cp;
408
409	for (cp = childp; cp != NULLCP; cp = cp->next)
410		if (cp->pid == pid)
411			break;
412
413	return (cp);
414}
415
416/*
417 * Check every proc for existence, release those that are gone.
418 * Be careful about the linked list; ReleaseProc() changes it.
419 */
420static void
421CheckAllProcs()
422{
423	cstatus_t *cp = childp;
424
425	while (cp != NULLCP) {
426		cstatus_t *next = cp->next;
427
428		if (ProcUpdate(cp) != 0)
429			ReleaseProc(cp);
430		cp = next;
431	}
432}
433
434/*
435 * Utility for OpenProc().
436 */
437static int
438Dupfd(int fd, int dfd)
439{
440	/*
441	 * Make sure fd not one of 0, 1, or 2 to avoid stdio interference.
442	 * Also, if dfd is greater than 2, dup fd to be exactly dfd.
443	 */
444	if (dfd > 2 || (0 <= fd && fd <= 2)) {
445		if (dfd > 2 && fd != dfd)
446			(void) close(dfd);
447		else
448			dfd = 3;
449		if (fd != dfd) {
450			dfd = fcntl(fd, F_DUPFD, (intptr_t)dfd);
451			(void) close(fd);
452			fd = dfd;
453		}
454	}
455	/*
456	 * Mark filedescriptor close-on-exec.
457	 * Should also be close-on-return-from-fork-in-child.
458	 */
459	(void) fcntl(fd, F_SETFD, (intptr_t)1);
460	return (fd);
461}
462
463/*
464 * Construct the /proc directory name:  "/proc/<pid>"
465 * The name buffer passed by the caller must be large enough.
466 */
467static void
468MakeProcName(char *procname, pid_t pid)
469{
470	(void) sprintf(procname, "/proc/%ld", pid);
471}
472
473/*
474 * Open/reopen the /proc/<pid> files.
475 */
476static int
477OpenProc(cstatus_t *cp)
478{
479	char procname[64];		/* /proc/nnnnn/fname */
480	char *fname;
481	int fd;
482	int omode;
483
484	MakeProcName(procname, cp->pid);
485	fname = procname + strlen(procname);
486
487	/*
488	 * Use exclusive-open only if this is the first open.
489	 */
490	omode = (cp->asfd > 0)? O_RDWR : (O_RDWR|O_EXCL);
491	(void) strcpy(fname, "/as");
492	if ((fd = open(procname, omode, 0)) < 0 ||
493	    (cp->asfd = Dupfd(fd, cp->asfd)) < 0)
494		goto err;
495
496	(void) strcpy(fname, "/ctl");
497	if ((fd = open(procname, O_WRONLY, 0)) < 0 ||
498	    (cp->ctlfd = Dupfd(fd, cp->ctlfd)) < 0)
499		goto err;
500
501	(void) strcpy(fname, "/status");
502	if ((fd = open(procname, O_RDONLY, 0)) < 0 ||
503	    (cp->statusfd = Dupfd(fd, cp->statusfd)) < 0)
504		goto err;
505
506	return (0);
507
508err:
509	CloseProc(cp);
510	return (-1);
511}
512
513/*
514 * Close the /proc/<pid> files.
515 */
516static void
517CloseProc(cstatus_t *cp)
518{
519	if (cp->asfd > 0)
520		(void) close(cp->asfd);
521	if (cp->ctlfd > 0)
522		(void) close(cp->ctlfd);
523	if (cp->statusfd > 0)
524		(void) close(cp->statusfd);
525	cp->asfd = 0;
526	cp->ctlfd = 0;
527	cp->statusfd = 0;
528}
529
530/*
531 * Take control of a child process.
532 */
533static cstatus_t *
534GrabProc(pid_t pid)
535{
536	cstatus_t *cp;
537	long ctl[2];
538	pid_t ppid;
539
540	if (pid <= 0)
541		return (NULLCP);
542
543	if ((cp = FindProc(pid)) != NULLCP)	/* already grabbed */
544		return (cp);
545
546	CheckAllProcs();	/* clean up before grabbing new process */
547
548	cp = (cstatus_t *)malloc(sizeof (cstatus_t));
549	if (cp == NULLCP)
550		return (NULLCP);
551	(void) memset((char *)cp, 0, sizeof (cstatus_t));
552	cp->pid = pid;
553
554	ppid = getpid();
555	while (OpenProc(cp) == 0) {
556		ctl[0] = PCSET;
557		ctl[1] = PR_RLC;
558		errno = 0;
559
560		if (pread(cp->statusfd, (char *)&cp->pstatus,
561		    sizeof (cp->pstatus), (off_t)0) == sizeof (cp->pstatus) &&
562		    cp->pstatus.pr_ppid == ppid &&
563		    (cp->pstatus.pr_flags & PR_PTRACE) &&
564		    write(cp->ctlfd, (char *)ctl, 2*sizeof (long))
565		    == 2*sizeof (long)) {
566			cp->next = childp;
567			childp = cp;
568			MakeUser(cp);
569			return (cp);
570		}
571
572		if (errno != EAGAIN)
573			break;
574	}
575
576	free((char *)cp);
577	return (NULLCP);
578}
579
580/*
581 * Close the /proc/<pid> file, if open.
582 * Deallocate the memory used by the cstatus_t structure.
583 */
584static void
585ReleaseProc(cstatus_t *cp)
586{
587	CloseProc(cp);
588
589	if (childp == cp)
590		childp = cp->next;
591	else {
592		cstatus_t *pcp;
593
594		for (pcp = childp; pcp != NULLCP; pcp = pcp->next) {
595			if (pcp->next == cp) {
596				pcp->next = cp->next;
597				break;
598			}
599		}
600	}
601
602	free((char *)cp);
603}
604
605/*
606 * Update process information from /proc.
607 * Return 0 on success, -1 on failure.
608 */
609static int
610ProcUpdate(cstatus_t *cp)
611{
612	pstatus_t *ps = &cp->pstatus;
613
614	if (cp->flags & CS_SETREGS) {
615		long cmd;
616		iovec_t iov[2];
617
618		ps->pr_lwp.pr_reg[GS]   = cp->user.u_reg[GS];
619		ps->pr_lwp.pr_reg[FS]   = cp->user.u_reg[FS];
620		ps->pr_lwp.pr_reg[ES]   = cp->user.u_reg[ES];
621		ps->pr_lwp.pr_reg[DS]   = cp->user.u_reg[DS];
622		ps->pr_lwp.pr_reg[EDI]  = cp->user.u_reg[EDI];
623		ps->pr_lwp.pr_reg[ESI]  = cp->user.u_reg[ESI];
624		ps->pr_lwp.pr_reg[EBP]  = cp->user.u_reg[EBP];
625		ps->pr_lwp.pr_reg[ESP]  = cp->user.u_reg[ESP];
626		ps->pr_lwp.pr_reg[EBX]  = cp->user.u_reg[EBX];
627		ps->pr_lwp.pr_reg[EDX]  = cp->user.u_reg[EDX];
628		ps->pr_lwp.pr_reg[ECX]  = cp->user.u_reg[ECX];
629		ps->pr_lwp.pr_reg[EAX]  = cp->user.u_reg[EAX];
630		ps->pr_lwp.pr_reg[TRAPNO] = cp->user.u_reg[TRAPNO];
631		ps->pr_lwp.pr_reg[ERR]  = cp->user.u_reg[ERR];
632		ps->pr_lwp.pr_reg[EIP]  = cp->user.u_reg[EIP];
633		ps->pr_lwp.pr_reg[CS]   = cp->user.u_reg[CS];
634		ps->pr_lwp.pr_reg[EFL]  = cp->user.u_reg[EFL];
635		ps->pr_lwp.pr_reg[UESP] = cp->user.u_reg[UESP];
636		ps->pr_lwp.pr_reg[SS]   = cp->user.u_reg[SS];
637		cmd = PCSREG;
638		iov[0].iov_base = (caddr_t)&cmd;
639		iov[0].iov_len = sizeof (long);
640		iov[1].iov_base = (caddr_t)&ps->pr_lwp.pr_reg[0];
641		iov[1].iov_len = sizeof (ps->pr_lwp.pr_reg);
642		(void) writev(cp->ctlfd, iov, 2);
643		cp->flags &= ~CS_SETREGS;
644	}
645
646	while (pread(cp->statusfd, (char *)ps, sizeof (*ps), (off_t)0) < 0) {
647		/* attempt to regain control */
648		if (errno != EINTR &&
649		    !(errno == EAGAIN && OpenProc(cp) == 0))
650			return (-1);
651	}
652
653	if (ps->pr_flags & PR_ISTOP)
654		MakeUser(cp);
655	else
656		(void) memset((char *)ps, 0, sizeof (pstatus_t));
657
658	return (0);
659}
660
661/*
662 * Manufacture the contents of the fake u-block.
663 */
664static void
665MakeUser(cstatus_t *cp)
666{
667	pstatus_t *ps = &cp->pstatus;
668
669	cp->user.u_reg[GS]   = ps->pr_lwp.pr_reg[GS];
670	cp->user.u_reg[FS]   = ps->pr_lwp.pr_reg[FS];
671	cp->user.u_reg[ES]   = ps->pr_lwp.pr_reg[ES];
672	cp->user.u_reg[DS]   = ps->pr_lwp.pr_reg[DS];
673	cp->user.u_reg[EDI]  = ps->pr_lwp.pr_reg[EDI];
674	cp->user.u_reg[ESI]  = ps->pr_lwp.pr_reg[ESI];
675	cp->user.u_reg[EBP]  = ps->pr_lwp.pr_reg[EBP];
676	cp->user.u_reg[ESP]  = ps->pr_lwp.pr_reg[ESP];
677	cp->user.u_reg[EBX]  = ps->pr_lwp.pr_reg[EBX];
678	cp->user.u_reg[EDX]  = ps->pr_lwp.pr_reg[EDX];
679	cp->user.u_reg[ECX]  = ps->pr_lwp.pr_reg[ECX];
680	cp->user.u_reg[EAX]  = ps->pr_lwp.pr_reg[EAX];
681	cp->user.u_reg[TRAPNO] = ps->pr_lwp.pr_reg[TRAPNO];
682	cp->user.u_reg[ERR]  = ps->pr_lwp.pr_reg[ERR];
683	cp->user.u_reg[EIP]  = ps->pr_lwp.pr_reg[EIP];
684	cp->user.u_reg[CS]   = ps->pr_lwp.pr_reg[CS];
685	cp->user.u_reg[EFL]  = ps->pr_lwp.pr_reg[EFL];
686	cp->user.u_reg[UESP] = ps->pr_lwp.pr_reg[UESP];
687	cp->user.u_reg[SS]   = ps->pr_lwp.pr_reg[SS];
688	cp->user.u_ar0 = (greg_t *)REGADDR;
689	cp->user.u_code = ps->pr_lwp.pr_info.si_code;
690	cp->user.u_addr = ps->pr_lwp.pr_info.si_addr;
691	cp->flags &= ~(CS_PSARGS|CS_SIGNAL);
692}
693
694/*
695 * Fetch the contents of u_psargs[].
696 */
697static void
698GetPsargs(cstatus_t *cp)
699{
700	char procname[64];	/* /proc/<pid>/psinfo */
701	int fd;
702
703	MakeProcName(procname, cp->pid);
704	(void) strcat(procname, "/psinfo");
705	if ((fd = open(procname, O_RDONLY, 0)) < 0) {
706		(void) memset(cp->user.u_psargs, 0, PSARGSZ);
707		return;
708	}
709	(void) pread(fd, cp->user.u_psargs, PSARGSZ,
710	    (off_t)((psinfo_t *)0)->pr_psargs);
711	(void) close(fd);
712
713	cp->flags |= CS_PSARGS;
714}
715
716/*
717 * Fetch the contents of u_signal[].
718 */
719static void
720GetSignal(cstatus_t *cp)
721{
722	char procname[64];	/* /proc/<pid>/sigact */
723	int fd;
724	struct sigaction action[MAXSIG];
725	int i;
726
727	MakeProcName(procname, cp->pid);
728	(void) strcat(procname, "/sigact");
729	(void) memset((char *)action, 0, sizeof (action));
730	if ((fd = open(procname, O_RDONLY, 0)) >= 0) {
731		(void) read(fd, (char *)action, sizeof (action));
732		(void) close(fd);
733	}
734	for (i = 0; i < MAXSIG; i++)
735		cp->user.u_signal[i] = action[i].sa_handler;
736	cp->flags |= CS_SIGNAL;
737}
738