xref: /onnv-gate/usr/src/cmd/truss/main.c (revision 12273:63678502e95e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211132Sraf 
220Sstevel@tonic-gate /*
23*12273SCasper.Dik@Sun.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <stdio.h>
291914Scasper #include <stdio_ext.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <memory.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <wait.h>
380Sstevel@tonic-gate #include <limits.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate #include <sys/types.h>
410Sstevel@tonic-gate #include <sys/time.h>
420Sstevel@tonic-gate #include <sys/times.h>
430Sstevel@tonic-gate #include <sys/fstyp.h>
440Sstevel@tonic-gate #include <sys/fsid.h>
450Sstevel@tonic-gate #include <sys/stat.h>
460Sstevel@tonic-gate #include <sys/mman.h>
470Sstevel@tonic-gate #include <sys/resource.h>
480Sstevel@tonic-gate #include <libproc.h>
49*12273SCasper.Dik@Sun.COM #include <priv.h>
500Sstevel@tonic-gate #include "ramdata.h"
510Sstevel@tonic-gate #include "proto.h"
520Sstevel@tonic-gate #include "htbl.h"
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * The user can trace individual threads by using the 'pid/1,3-6,8-' syntax.
560Sstevel@tonic-gate  * This structure keeps track of pid/lwp specifications.  If there are no LWPs
570Sstevel@tonic-gate  * specified, then 'lwps' will be NULL.
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate typedef struct proc_set {
600Sstevel@tonic-gate 	pid_t		pid;
610Sstevel@tonic-gate 	const char 	*lwps;
620Sstevel@tonic-gate } proc_set_t;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  * Function prototypes for static routines in this file.
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate void	setup_basetime(hrtime_t, struct timeval *);
680Sstevel@tonic-gate int	xcreat(char *);
690Sstevel@tonic-gate void	setoutput(int);
700Sstevel@tonic-gate void	report(private_t *, time_t);
710Sstevel@tonic-gate void	prtim(timestruc_t *);
720Sstevel@tonic-gate void	pids(char *, proc_set_t *);
730Sstevel@tonic-gate void	psargs(private_t *);
740Sstevel@tonic-gate int	control(private_t *, pid_t);
750Sstevel@tonic-gate int	grabit(private_t *, proc_set_t *);
760Sstevel@tonic-gate void	release(private_t *, pid_t);
770Sstevel@tonic-gate void	intr(int);
780Sstevel@tonic-gate int	wait4all(void);
790Sstevel@tonic-gate void	letgo(private_t *);
800Sstevel@tonic-gate void	child_to_file();
810Sstevel@tonic-gate void	file_to_parent();
820Sstevel@tonic-gate void	per_proc_init();
830Sstevel@tonic-gate int	lib_sort(const void *, const void *);
840Sstevel@tonic-gate int	key_sort(const void *, const void *);
850Sstevel@tonic-gate 
860Sstevel@tonic-gate void	*worker_thread(void *);
870Sstevel@tonic-gate void	main_thread(int);
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * Test for empty set.
910Sstevel@tonic-gate  * is_empty() should not be called directly.
920Sstevel@tonic-gate  */
930Sstevel@tonic-gate int	is_empty(const uint32_t *, size_t);
940Sstevel@tonic-gate #define	isemptyset(sp) \
950Sstevel@tonic-gate 	is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t))
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate  * OR the second set into the first set.
990Sstevel@tonic-gate  * or_set() should not be called directly.
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate void	or_set(uint32_t *, const uint32_t *, size_t);
1020Sstevel@tonic-gate #define	prorset(sp1, sp2) \
1030Sstevel@tonic-gate 	or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \
1040Sstevel@tonic-gate 	sizeof (*(sp1)) / sizeof (uint32_t))
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate /* fetch or allocate thread-private data */
1070Sstevel@tonic-gate private_t *
get_private()1080Sstevel@tonic-gate get_private()
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	void *value;
1110Sstevel@tonic-gate 	private_t *pri = NULL;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (thr_getspecific(private_key, &value) == 0)
1140Sstevel@tonic-gate 		pri = value;
1150Sstevel@tonic-gate 	if (pri == NULL) {
1160Sstevel@tonic-gate 		pri = my_malloc(sizeof (*pri), NULL);
1170Sstevel@tonic-gate 		(void) memset(pri, 0, sizeof (*pri));
1180Sstevel@tonic-gate 		pri->sys_path = my_malloc(pri->sys_psize = 16, NULL);
1190Sstevel@tonic-gate 		pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL);
1200Sstevel@tonic-gate 		if (thr_setspecific(private_key, pri) == ENOMEM)
1210Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 	return (pri);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /* destructor function for thread-private data */
1270Sstevel@tonic-gate void
free_private(void * value)1280Sstevel@tonic-gate free_private(void *value)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	private_t *pri = value;
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 	if (pri->sys_path)
1330Sstevel@tonic-gate 		free(pri->sys_path);
1340Sstevel@tonic-gate 	if (pri->sys_string)
1350Sstevel@tonic-gate 		free(pri->sys_string);
1360Sstevel@tonic-gate 	if (pri->exec_string)
1370Sstevel@tonic-gate 		free(pri->exec_string);
1380Sstevel@tonic-gate 	if (pri->str_buffer)
1390Sstevel@tonic-gate 		free(pri->str_buffer);
1400Sstevel@tonic-gate 	free(pri);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate  * This is called by the main thread (via create_thread())
1450Sstevel@tonic-gate  * and is also called from other threads in worker_thread()
1460Sstevel@tonic-gate  * while holding truss_lock.  No further locking is required.
1470Sstevel@tonic-gate  */
1480Sstevel@tonic-gate void
insert_lwpid(lwpid_t lwpid)1490Sstevel@tonic-gate insert_lwpid(lwpid_t lwpid)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	int i;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	truss_nlwp++;
1540Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
1550Sstevel@tonic-gate 		if (truss_lwpid[i] == 0)
1560Sstevel@tonic-gate 			break;
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 	if (i == truss_maxlwp) {
1590Sstevel@tonic-gate 		/* double the size of the array */
1600Sstevel@tonic-gate 		truss_lwpid = my_realloc(truss_lwpid,
16111798SRoger.Faulkner@Sun.COM 		    truss_maxlwp * 2 * sizeof (lwpid_t), NULL);
1620Sstevel@tonic-gate 		(void) memset(&truss_lwpid[truss_maxlwp], 0,
16311798SRoger.Faulkner@Sun.COM 		    truss_maxlwp * sizeof (lwpid_t));
1640Sstevel@tonic-gate 		truss_maxlwp *= 2;
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 	truss_lwpid[i] = lwpid;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate /*
1701132Sraf  * This is called from the first worker thread to encounter one of
1711132Sraf  * (leave_hung || interrupt || sigusr1).  It must notify all other
1721132Sraf  * worker threads of the same condition.  truss_lock is held.
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate void
broadcast_signals(void)1751132Sraf broadcast_signals(void)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	static int int_notified = FALSE;
1780Sstevel@tonic-gate 	static int usr1_notified = FALSE;
1790Sstevel@tonic-gate 	static int usr2_notified = FALSE;
1801132Sraf 	lwpid_t my_id = thr_self();
1811132Sraf 	lwpid_t lwpid;
1820Sstevel@tonic-gate 	int i;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (interrupt && !int_notified) {
1850Sstevel@tonic-gate 		int_notified = TRUE;
1860Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
1871132Sraf 			if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
1881132Sraf 				(void) thr_kill(lwpid, interrupt);
1890Sstevel@tonic-gate 		}
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 	if (sigusr1 && !usr1_notified) {
1920Sstevel@tonic-gate 		usr1_notified = TRUE;
1930Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
1941132Sraf 			if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
1951132Sraf 				(void) thr_kill(lwpid, SIGUSR1);
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 	if (leave_hung && !usr2_notified) {
1990Sstevel@tonic-gate 		usr2_notified = TRUE;
2000Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
2011132Sraf 			if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
2021132Sraf 				(void) thr_kill(lwpid, SIGUSR2);
2030Sstevel@tonic-gate 		}
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate static struct ps_lwphandle *
grab_lwp(lwpid_t who)2080Sstevel@tonic-gate grab_lwp(lwpid_t who)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	struct ps_lwphandle *Lwp;
2110Sstevel@tonic-gate 	int gcode;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) {
2140Sstevel@tonic-gate 		if (gcode != G_NOPROC) {
2150Sstevel@tonic-gate 			(void) fprintf(stderr,
21611798SRoger.Faulkner@Sun.COM 			    "%s: cannot grab LWP %u in process %d,"
21711798SRoger.Faulkner@Sun.COM 			    " reason: %s\n",
21811798SRoger.Faulkner@Sun.COM 			    command, who, (int)Pstatus(Proc)->pr_pid,
21911798SRoger.Faulkner@Sun.COM 			    Lgrab_error(gcode));
2200Sstevel@tonic-gate 			interrupt = SIGTERM;	/* post an interrupt */
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 	return (Lwp);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate  * Iteration function called for each initial lwp in the controlled process.
2280Sstevel@tonic-gate  */
2290Sstevel@tonic-gate /* ARGSUSED */
2300Sstevel@tonic-gate int
create_thread(void * arg,const lwpstatus_t * Lsp)2310Sstevel@tonic-gate create_thread(void *arg, const lwpstatus_t *Lsp)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	struct ps_lwphandle *new_Lwp;
2340Sstevel@tonic-gate 	lwpid_t lwpid;
2350Sstevel@tonic-gate 	int *count = arg;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid))
2380Sstevel@tonic-gate 		*count += 1;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) {
2410Sstevel@tonic-gate 		if (thr_create(NULL, 0, worker_thread, new_Lwp,
2420Sstevel@tonic-gate 		    THR_BOUND | THR_SUSPENDED, &lwpid) != 0)
2430Sstevel@tonic-gate 			abend("cannot create lwp to follow child lwp", NULL);
2440Sstevel@tonic-gate 		insert_lwpid(lwpid);
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	return (0);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate int
main(int argc,char * argv[])2500Sstevel@tonic-gate main(int argc, char *argv[])
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	private_t *pri;
2530Sstevel@tonic-gate 	struct tms tms;
2540Sstevel@tonic-gate 	struct rlimit rlim;
2550Sstevel@tonic-gate 	int ofd = -1;
2560Sstevel@tonic-gate 	int opt;
2570Sstevel@tonic-gate 	int i;
2580Sstevel@tonic-gate 	int first;
2590Sstevel@tonic-gate 	int errflg = FALSE;
2600Sstevel@tonic-gate 	int badname = FALSE;
2610Sstevel@tonic-gate 	proc_set_t *grab = NULL;
2620Sstevel@tonic-gate 	const pstatus_t *Psp;
2630Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
2640Sstevel@tonic-gate 	int sharedmem;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	/* a few of these need to be initialized to NULL */
2670Sstevel@tonic-gate 	Cp = NULL;
2680Sstevel@tonic-gate 	fcall_tbl = NULL;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	/*
2710Sstevel@tonic-gate 	 * Make sure fd's 0, 1, and 2 are allocated,
2720Sstevel@tonic-gate 	 * just in case truss was invoked from init.
2730Sstevel@tonic-gate 	 */
2740Sstevel@tonic-gate 	while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2)
2750Sstevel@tonic-gate 		;
2760Sstevel@tonic-gate 	if (i > 2)
2770Sstevel@tonic-gate 		(void) close(i);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	starttime = times(&tms);	/* for elapsed timing */
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	/* this should be per-traced-process */
2820Sstevel@tonic-gate 	pagesize = sysconf(_SC_PAGESIZE);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	/* command name (e.g., "truss") */
2850Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
2860Sstevel@tonic-gate 		command++;
2870Sstevel@tonic-gate 	else
2880Sstevel@tonic-gate 		command = argv[0];
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	/* set up the initial private data */
2910Sstevel@tonic-gate 	(void) mutex_init(&truss_lock, USYNC_THREAD, NULL);
2920Sstevel@tonic-gate 	(void) mutex_init(&count_lock, USYNC_THREAD, NULL);
2930Sstevel@tonic-gate 	(void) cond_init(&truss_cv, USYNC_THREAD, NULL);
2940Sstevel@tonic-gate 	if (thr_keycreate(&private_key, free_private) == ENOMEM)
2950Sstevel@tonic-gate 		abend("memory allocation failure", NULL);
2960Sstevel@tonic-gate 	pri = get_private();
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	Euid = geteuid();
2990Sstevel@tonic-gate 	Egid = getegid();
3000Sstevel@tonic-gate 	Ruid = getuid();
3010Sstevel@tonic-gate 	Rgid = getgid();
3020Sstevel@tonic-gate 	ancestor = getpid();
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	prfillset(&trace);	/* default: trace all system calls */
3050Sstevel@tonic-gate 	premptyset(&verbose);	/* default: no syscall verbosity */
3060Sstevel@tonic-gate 	premptyset(&rawout);	/* default: no raw syscall interpretation */
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	prfillset(&signals);	/* default: trace all signals */
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	prfillset(&faults);	/* default: trace all faults */
3110Sstevel@tonic-gate 	prdelset(&faults, FLTPAGE);	/* except this one */
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	premptyset(&readfd);	/* default: dump no buffers */
3140Sstevel@tonic-gate 	premptyset(&writefd);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	premptyset(&syshang);	/* default: hang on no system calls */
3170Sstevel@tonic-gate 	premptyset(&sighang);	/* default: hang on no signals */
3180Sstevel@tonic-gate 	premptyset(&flthang);	/* default: hang on no faults */
3190Sstevel@tonic-gate 
3201132Sraf 	(void) sigemptyset(&emptyset);	/* for unblocking all signals */
3211132Sraf 	(void) sigfillset(&fillset);	/* for blocking all signals */
3221132Sraf 
3230Sstevel@tonic-gate #define	OPTIONS	"FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
3240Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
3250Sstevel@tonic-gate 		switch (opt) {
3260Sstevel@tonic-gate 		case 'F':		/* force grabbing (no O_EXCL) */
3270Sstevel@tonic-gate 			Fflag = PGRAB_FORCE;
3280Sstevel@tonic-gate 			break;
3290Sstevel@tonic-gate 		case 'p':		/* grab processes */
3300Sstevel@tonic-gate 			pflag = TRUE;
3310Sstevel@tonic-gate 			break;
3320Sstevel@tonic-gate 		case 'f':		/* follow children */
3330Sstevel@tonic-gate 			fflag = TRUE;
3340Sstevel@tonic-gate 			break;
3350Sstevel@tonic-gate 		case 'c':		/* don't trace, just count */
3360Sstevel@tonic-gate 			cflag = TRUE;
3370Sstevel@tonic-gate 			iflag = TRUE;	/* implies no interruptable syscalls */
3380Sstevel@tonic-gate 			break;
3390Sstevel@tonic-gate 		case 'a':		/* display argument lists */
3400Sstevel@tonic-gate 			aflag = TRUE;
3410Sstevel@tonic-gate 			break;
3420Sstevel@tonic-gate 		case 'e':		/* display environments */
3430Sstevel@tonic-gate 			eflag = TRUE;
3440Sstevel@tonic-gate 			break;
3450Sstevel@tonic-gate 		case 'i':		/* don't show interruptable syscalls */
3460Sstevel@tonic-gate 			iflag = TRUE;
3470Sstevel@tonic-gate 			break;
3480Sstevel@tonic-gate 		case 'l':		/* show lwp id for each syscall */
3490Sstevel@tonic-gate 			lflag = TRUE;
3500Sstevel@tonic-gate 			break;
3510Sstevel@tonic-gate 		case 'h':		/* debugging: report hash stats */
3520Sstevel@tonic-gate 			hflag = TRUE;
3530Sstevel@tonic-gate 			break;
3540Sstevel@tonic-gate 		case 'd':		/* show time stamps */
3550Sstevel@tonic-gate 			dflag = TRUE;
3560Sstevel@tonic-gate 			break;
3570Sstevel@tonic-gate 		case 'D':		/* show time deltas */
3580Sstevel@tonic-gate 			Dflag = TRUE;
3590Sstevel@tonic-gate 			break;
3600Sstevel@tonic-gate 		case 'E':
3610Sstevel@tonic-gate 			Eflag = TRUE;	/* show syscall times */
3620Sstevel@tonic-gate 			break;
3630Sstevel@tonic-gate 		case 't':		/* system calls to trace */
3640Sstevel@tonic-gate 			if (syslist(optarg, &trace, &tflag))
3650Sstevel@tonic-gate 				badname = TRUE;
3660Sstevel@tonic-gate 			break;
3670Sstevel@tonic-gate 		case 'T':		/* system calls to hang process */
3680Sstevel@tonic-gate 			if (syslist(optarg, &syshang, &Tflag))
3690Sstevel@tonic-gate 				badname = TRUE;
3700Sstevel@tonic-gate 			break;
3710Sstevel@tonic-gate 		case 'v':		/* verbose interpretation of syscalls */
3720Sstevel@tonic-gate 			if (syslist(optarg, &verbose, &vflag))
3730Sstevel@tonic-gate 				badname = TRUE;
3740Sstevel@tonic-gate 			break;
3750Sstevel@tonic-gate 		case 'x':		/* raw interpretation of syscalls */
3760Sstevel@tonic-gate 			if (syslist(optarg, &rawout, &xflag))
3770Sstevel@tonic-gate 				badname = TRUE;
3780Sstevel@tonic-gate 			break;
3790Sstevel@tonic-gate 		case 's':		/* signals to trace */
3800Sstevel@tonic-gate 			if (siglist(pri, optarg, &signals, &sflag))
3810Sstevel@tonic-gate 				badname = TRUE;
3820Sstevel@tonic-gate 			break;
3830Sstevel@tonic-gate 		case 'S':		/* signals to hang process */
3840Sstevel@tonic-gate 			if (siglist(pri, optarg, &sighang, &Sflag))
3850Sstevel@tonic-gate 				badname = TRUE;
3860Sstevel@tonic-gate 			break;
3870Sstevel@tonic-gate 		case 'm':		/* machine faults to trace */
3880Sstevel@tonic-gate 			if (fltlist(optarg, &faults, &mflag))
3890Sstevel@tonic-gate 				badname = TRUE;
3900Sstevel@tonic-gate 			break;
3910Sstevel@tonic-gate 		case 'M':		/* machine faults to hang process */
3920Sstevel@tonic-gate 			if (fltlist(optarg, &flthang, &Mflag))
3930Sstevel@tonic-gate 				badname = TRUE;
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 		case 'u':		/* user library functions to trace */
3960Sstevel@tonic-gate 			if (liblist(optarg, 0))
3970Sstevel@tonic-gate 				badname = TRUE;
3980Sstevel@tonic-gate 			break;
3990Sstevel@tonic-gate 		case 'U':		/* user library functions to hang */
4000Sstevel@tonic-gate 			if (liblist(optarg, 1))
4010Sstevel@tonic-gate 				badname = TRUE;
4020Sstevel@tonic-gate 			break;
4030Sstevel@tonic-gate 		case 'r':		/* show contents of read(fd) */
4040Sstevel@tonic-gate 			if (fdlist(optarg, &readfd))
4050Sstevel@tonic-gate 				badname = TRUE;
4060Sstevel@tonic-gate 			break;
4070Sstevel@tonic-gate 		case 'w':		/* show contents of write(fd) */
4080Sstevel@tonic-gate 			if (fdlist(optarg, &writefd))
4090Sstevel@tonic-gate 				badname = TRUE;
4100Sstevel@tonic-gate 			break;
4110Sstevel@tonic-gate 		case 'o':		/* output file for trace */
4120Sstevel@tonic-gate 			oflag = TRUE;
4130Sstevel@tonic-gate 			if (ofd >= 0)
4140Sstevel@tonic-gate 				(void) close(ofd);
4150Sstevel@tonic-gate 			if ((ofd = xcreat(optarg)) < 0) {
4160Sstevel@tonic-gate 				perror(optarg);
4170Sstevel@tonic-gate 				badname = TRUE;
4180Sstevel@tonic-gate 			}
4190Sstevel@tonic-gate 			break;
4200Sstevel@tonic-gate 		default:
4210Sstevel@tonic-gate 			errflg = TRUE;
4220Sstevel@tonic-gate 			break;
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	if (badname)
4270Sstevel@tonic-gate 		exit(2);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	/* if -a or -e was specified, force tracing of exec() */
43011798SRoger.Faulkner@Sun.COM 	if (aflag || eflag)
4310Sstevel@tonic-gate 		praddset(&trace, SYS_execve);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/*
4340Sstevel@tonic-gate 	 * Make sure that all system calls, signals, and machine faults
4350Sstevel@tonic-gate 	 * that hang the process are added to their trace sets.
4360Sstevel@tonic-gate 	 */
4370Sstevel@tonic-gate 	prorset(&trace, &syshang);
4380Sstevel@tonic-gate 	prorset(&signals, &sighang);
4390Sstevel@tonic-gate 	prorset(&faults, &flthang);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	argc -= optind;
4420Sstevel@tonic-gate 	argv += optind;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/* collect the specified process ids */
4450Sstevel@tonic-gate 	if (pflag && argc > 0) {
4460Sstevel@tonic-gate 		grab = my_malloc(argc * sizeof (proc_set_t),
44711798SRoger.Faulkner@Sun.COM 		    "memory for process-ids");
4480Sstevel@tonic-gate 		while (argc-- > 0)
4490Sstevel@tonic-gate 			pids(*argv++, grab);
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	if (errflg || (argc <= 0 && ngrab <= 0)) {
4530Sstevel@tonic-gate 		(void) fprintf(stderr,
4540Sstevel@tonic-gate 	"usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
45511798SRoger.Faulkner@Sun.COM 		    command);
4560Sstevel@tonic-gate 		(void) fprintf(stderr,
4570Sstevel@tonic-gate 	"\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
4580Sstevel@tonic-gate 		(void) fprintf(stderr,
45911798SRoger.Faulkner@Sun.COM 		    "\t[-o outfile]  command | -p pid[/lwps] ...\n");
4600Sstevel@tonic-gate 		exit(2);
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	if (argc > 0) {		/* create the controlled process */
4640Sstevel@tonic-gate 		int err;
4650Sstevel@tonic-gate 		char path[PATH_MAX];
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
4680Sstevel@tonic-gate 		if (Proc == NULL) {
4690Sstevel@tonic-gate 			switch (err) {
4700Sstevel@tonic-gate 			case C_PERM:
4710Sstevel@tonic-gate 				(void) fprintf(stderr,
47211798SRoger.Faulkner@Sun.COM 				    "%s: cannot trace set-id or "
47311798SRoger.Faulkner@Sun.COM 				    "unreadable object file: %s\n",
47411798SRoger.Faulkner@Sun.COM 				    command, path);
4750Sstevel@tonic-gate 				break;
4760Sstevel@tonic-gate 			case C_LP64:
4770Sstevel@tonic-gate 				(void) fprintf(stderr,
47811798SRoger.Faulkner@Sun.COM 				    "%s: cannot control _LP64 "
47911798SRoger.Faulkner@Sun.COM 				    "program: %s\n",
48011798SRoger.Faulkner@Sun.COM 				    command, path);
4810Sstevel@tonic-gate 				break;
4820Sstevel@tonic-gate 			case C_NOEXEC:
4830Sstevel@tonic-gate 				(void) fprintf(stderr,
48411798SRoger.Faulkner@Sun.COM 				    "%s: cannot execute program: %s\n",
48511798SRoger.Faulkner@Sun.COM 				    command, argv[0]);
4860Sstevel@tonic-gate 				break;
4870Sstevel@tonic-gate 			case C_NOENT:
4880Sstevel@tonic-gate 				(void) fprintf(stderr,
48911798SRoger.Faulkner@Sun.COM 				    "%s: cannot find program: %s\n",
49011798SRoger.Faulkner@Sun.COM 				    command, argv[0]);
4910Sstevel@tonic-gate 				break;
4920Sstevel@tonic-gate 			case C_STRANGE:
4930Sstevel@tonic-gate 				break;
4940Sstevel@tonic-gate 			default:
4950Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s\n",
49611798SRoger.Faulkner@Sun.COM 				    command, Pcreate_error(err));
4970Sstevel@tonic-gate 				break;
4980Sstevel@tonic-gate 			}
4990Sstevel@tonic-gate 			exit(2);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 		if (fflag || Dynpat != NULL)
5020Sstevel@tonic-gate 			(void) Psetflags(Proc, PR_FORK);
5030Sstevel@tonic-gate 		else
5040Sstevel@tonic-gate 			(void) Punsetflags(Proc, PR_FORK);
5050Sstevel@tonic-gate 		Psp = Pstatus(Proc);
5060Sstevel@tonic-gate 		Lsp = &Psp->pr_lwp;
5070Sstevel@tonic-gate 		pri->lwpstat = Lsp;
5080Sstevel@tonic-gate 		data_model = Psp->pr_dmodel;
5090Sstevel@tonic-gate 		created = Psp->pr_pid;
5100Sstevel@tonic-gate 		make_pname(pri, 0);
5110Sstevel@tonic-gate 		(void) sysentry(pri, 1);
5120Sstevel@tonic-gate 		pri->length = 0;
5130Sstevel@tonic-gate 		if (!cflag && prismember(&trace, SYS_execve)) {
5140Sstevel@tonic-gate 			pri->exec_string = my_realloc(pri->exec_string,
51511798SRoger.Faulkner@Sun.COM 			    strlen(pri->sys_string) + 1, NULL);
5160Sstevel@tonic-gate 			(void) strcpy(pri->exec_pname, pri->pname);
5170Sstevel@tonic-gate 			(void) strcpy(pri->exec_string, pri->sys_string);
5180Sstevel@tonic-gate 			pri->length += strlen(pri->sys_string);
5190Sstevel@tonic-gate 			pri->exec_lwpid = pri->lwpstat->pr_lwpid;
5200Sstevel@tonic-gate 			pri->sys_leng = 0;
5210Sstevel@tonic-gate 			*pri->sys_string = '\0';
5220Sstevel@tonic-gate 		}
5230Sstevel@tonic-gate 		pri->syslast = Psp->pr_stime;
5240Sstevel@tonic-gate 		pri->usrlast = Psp->pr_utime;
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	/*
5280Sstevel@tonic-gate 	 * Now that we have created the victim process,
5290Sstevel@tonic-gate 	 * give ourself a million file descriptors.
5300Sstevel@tonic-gate 	 * This is enough to deal with a multithreaded
5310Sstevel@tonic-gate 	 * victim process that has half a million lwps.
5320Sstevel@tonic-gate 	 */
5330Sstevel@tonic-gate 	rlim.rlim_cur = 1024 * 1024;
5340Sstevel@tonic-gate 	rlim.rlim_max = 1024 * 1024;
5350Sstevel@tonic-gate 	if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) &&
5360Sstevel@tonic-gate 	    getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
5370Sstevel@tonic-gate 		/*
5380Sstevel@tonic-gate 		 * Failing the million, give ourself as many
5390Sstevel@tonic-gate 		 * file descriptors as we can get.
5400Sstevel@tonic-gate 		 */
5410Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
5420Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
5430Sstevel@tonic-gate 	}
5441914Scasper 	(void) enable_extended_FILE_stdio(-1, -1);
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	setoutput(ofd);		/* establish truss output */
5470Sstevel@tonic-gate 	istty = isatty(1);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0)
5500Sstevel@tonic-gate 		abend("setvbuf() failure", NULL);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	/*
5530Sstevel@tonic-gate 	 * Set up signal dispositions.
5540Sstevel@tonic-gate 	 */
5550Sstevel@tonic-gate 	if (created && (oflag || !istty)) {	/* ignore interrupts */
5560Sstevel@tonic-gate 		(void) sigset(SIGHUP, SIG_IGN);
5570Sstevel@tonic-gate 		(void) sigset(SIGINT, SIG_IGN);
5580Sstevel@tonic-gate 		(void) sigset(SIGQUIT, SIG_IGN);
5590Sstevel@tonic-gate 	} else {				/* receive interrupts */
5600Sstevel@tonic-gate 		if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
5610Sstevel@tonic-gate 			(void) sigset(SIGHUP, intr);
5620Sstevel@tonic-gate 		if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
5630Sstevel@tonic-gate 			(void) sigset(SIGINT, intr);
5640Sstevel@tonic-gate 		if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
5650Sstevel@tonic-gate 			(void) sigset(SIGQUIT, intr);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
5680Sstevel@tonic-gate 	(void) sigset(SIGUSR1, intr);
5690Sstevel@tonic-gate 	(void) sigset(SIGUSR2, intr);
5700Sstevel@tonic-gate 	(void) sigset(SIGPIPE, intr);
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	/* don't accumulate zombie children */
5730Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_IGN);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	/* create shared mem space for global mutexes */
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	sharedmem = (fflag || Dynpat != NULL || ngrab > 1);
5780Sstevel@tonic-gate 	gps = (void *)mmap(NULL, sizeof (struct global_psinfo),
5790Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE,
5800Sstevel@tonic-gate 	    MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE),
5810Sstevel@tonic-gate 	    -1, (off_t)0);
5820Sstevel@tonic-gate 	if (gps == MAP_FAILED)
5830Sstevel@tonic-gate 		abend("cannot allocate ", "memory for counts");
5840Sstevel@tonic-gate 	i = sharedmem? USYNC_PROCESS : USYNC_THREAD;
5850Sstevel@tonic-gate 	(void) mutex_init(&gps->ps_mutex0, i, NULL);
5860Sstevel@tonic-gate 	(void) mutex_init(&gps->ps_mutex1, i, NULL);
5870Sstevel@tonic-gate 	(void) mutex_init(&gps->fork_lock, i, NULL);
5880Sstevel@tonic-gate 	(void) cond_init(&gps->fork_cv, i, NULL);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	/* config tmp file if counting and following */
5920Sstevel@tonic-gate 	if (fflag && cflag) {
5930Sstevel@tonic-gate 		char *tmps = tempnam("/var/tmp", "truss");
5940Sstevel@tonic-gate 		sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600);
5950Sstevel@tonic-gate 		if (sfd == -1)
5960Sstevel@tonic-gate 			abend("Error creating tmpfile", NULL);
5970Sstevel@tonic-gate 		if (unlink(tmps) == -1)
5980Sstevel@tonic-gate 			abend("Error unlinking tmpfile", NULL);
5990Sstevel@tonic-gate 		free(tmps);
6000Sstevel@tonic-gate 		tmps = NULL;
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (created) {
6040Sstevel@tonic-gate 		per_proc_init();
6050Sstevel@tonic-gate 		procadd(created, NULL);
606*12273SCasper.Dik@Sun.COM 		show_cred(pri, TRUE, FALSE);
6070Sstevel@tonic-gate 	} else {		/* grab the specified processes */
6080Sstevel@tonic-gate 		int gotone = FALSE;
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 		i = 0;
6110Sstevel@tonic-gate 		while (i < ngrab) {		/* grab first process */
6120Sstevel@tonic-gate 			if (grabit(pri, &grab[i++])) {
6130Sstevel@tonic-gate 				Psp = Pstatus(Proc);
6140Sstevel@tonic-gate 				Lsp = &Psp->pr_lwp;
6150Sstevel@tonic-gate 				gotone = TRUE;
6160Sstevel@tonic-gate 				break;
6170Sstevel@tonic-gate 			}
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 		if (!gotone)
6200Sstevel@tonic-gate 			abend(NULL, NULL);
6210Sstevel@tonic-gate 		per_proc_init();
6220Sstevel@tonic-gate 		while (i < ngrab) {		/* grab the remainder */
6230Sstevel@tonic-gate 			proc_set_t *set = &grab[i++];
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 			(void) mutex_lock(&truss_lock);
6263235Sraf 			switch (fork()) {
6270Sstevel@tonic-gate 			case -1:
6280Sstevel@tonic-gate 				(void) fprintf(stderr,
6290Sstevel@tonic-gate 			"%s: cannot fork to control process, pid# %d\n",
63011798SRoger.Faulkner@Sun.COM 				    command, (int)set->pid);
6310Sstevel@tonic-gate 				/* FALLTHROUGH */
6320Sstevel@tonic-gate 			default:
6330Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
6340Sstevel@tonic-gate 				continue;	/* parent carries on */
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 			case 0:			/* child grabs process */
6370Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
6380Sstevel@tonic-gate 				Pfree(Proc);
6390Sstevel@tonic-gate 				descendent = TRUE;
6400Sstevel@tonic-gate 				if (grabit(pri, set)) {
6410Sstevel@tonic-gate 					Psp = Pstatus(Proc);
6420Sstevel@tonic-gate 					Lsp = &Psp->pr_lwp;
6430Sstevel@tonic-gate 					per_proc_init();
6440Sstevel@tonic-gate 					break;
6450Sstevel@tonic-gate 				}
6460Sstevel@tonic-gate 				exit(2);
6470Sstevel@tonic-gate 			}
6480Sstevel@tonic-gate 			break;
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 		free(grab);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	/*
6550Sstevel@tonic-gate 	 * If running setuid-root, become root for real to avoid
6560Sstevel@tonic-gate 	 * affecting the per-user limitation on the maximum number
6570Sstevel@tonic-gate 	 * of processes (one benefit of running setuid-root).
6580Sstevel@tonic-gate 	 */
6590Sstevel@tonic-gate 	if (Rgid != Egid)
6600Sstevel@tonic-gate 		(void) setgid(Egid);
6610Sstevel@tonic-gate 	if (Ruid != Euid)
6620Sstevel@tonic-gate 		(void) setuid(Euid);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	if (!created && aflag && prismember(&trace, SYS_execve)) {
6650Sstevel@tonic-gate 		psargs(pri);
6660Sstevel@tonic-gate 		Flush();
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	if (created && Pstate(Proc) != PS_STOP)	/* assertion */
6700Sstevel@tonic-gate 		if (!(interrupt | sigusr1))
6710Sstevel@tonic-gate 			abend("ASSERT error: process is not stopped", NULL);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	traceeven = trace;		/* trace these system calls */
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/* trace these regardless, even if we don't report results */
6760Sstevel@tonic-gate 	praddset(&traceeven, SYS_exit);
6770Sstevel@tonic-gate 	praddset(&traceeven, SYS_lwp_create);
6780Sstevel@tonic-gate 	praddset(&traceeven, SYS_lwp_exit);
6790Sstevel@tonic-gate 	praddset(&traceeven, SYS_execve);
68011798SRoger.Faulkner@Sun.COM 	praddset(&traceeven, SYS_openat);
68111798SRoger.Faulkner@Sun.COM 	praddset(&traceeven, SYS_openat64);
6820Sstevel@tonic-gate 	praddset(&traceeven, SYS_open);
6830Sstevel@tonic-gate 	praddset(&traceeven, SYS_open64);
6840Sstevel@tonic-gate 	praddset(&traceeven, SYS_vfork);
6853235Sraf 	praddset(&traceeven, SYS_forksys);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/* for I/O buffer dumps, force tracing of read()s and write()s */
6880Sstevel@tonic-gate 	if (!isemptyset(&readfd)) {
6890Sstevel@tonic-gate 		praddset(&traceeven, SYS_read);
6900Sstevel@tonic-gate 		praddset(&traceeven, SYS_readv);
6910Sstevel@tonic-gate 		praddset(&traceeven, SYS_pread);
6920Sstevel@tonic-gate 		praddset(&traceeven, SYS_pread64);
6930Sstevel@tonic-gate 		praddset(&traceeven, SYS_recv);
6940Sstevel@tonic-gate 		praddset(&traceeven, SYS_recvfrom);
6950Sstevel@tonic-gate 		praddset(&traceeven, SYS_recvmsg);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 	if (!isemptyset(&writefd)) {
6980Sstevel@tonic-gate 		praddset(&traceeven, SYS_write);
6990Sstevel@tonic-gate 		praddset(&traceeven, SYS_writev);
7000Sstevel@tonic-gate 		praddset(&traceeven, SYS_pwrite);
7010Sstevel@tonic-gate 		praddset(&traceeven, SYS_pwrite64);
7020Sstevel@tonic-gate 		praddset(&traceeven, SYS_send);
7030Sstevel@tonic-gate 		praddset(&traceeven, SYS_sendto);
7040Sstevel@tonic-gate 		praddset(&traceeven, SYS_sendmsg);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if (cflag || Eflag) {
7080Sstevel@tonic-gate 		Psetsysentry(Proc, &traceeven);
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 	Psetsysexit(Proc, &traceeven);
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	/* special case -- cannot trace sysexit because context is changed */
7130Sstevel@tonic-gate 	if (prismember(&trace, SYS_context)) {
7140Sstevel@tonic-gate 		(void) Psysentry(Proc, SYS_context, TRUE);
7150Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_context, FALSE);
7160Sstevel@tonic-gate 		prdelset(&traceeven, SYS_context);
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/* special case -- trace exec() on entry to get the args */
7200Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_execve, TRUE);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/* special case -- sysexit never reached */
7230Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_exit, TRUE);
7240Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_lwp_exit, TRUE);
7250Sstevel@tonic-gate 	(void) Psysexit(Proc, SYS_exit, FALSE);
7260Sstevel@tonic-gate 	(void) Psysexit(Proc, SYS_lwp_exit, FALSE);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	Psetsignal(Proc, &signals);	/* trace these signals */
7290Sstevel@tonic-gate 	Psetfault(Proc, &faults);	/* trace these faults */
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	/* for function call tracing */
7320Sstevel@tonic-gate 	if (Dynpat != NULL) {
7330Sstevel@tonic-gate 		/* trace these regardless, to deal with function calls */
7340Sstevel@tonic-gate 		(void) Pfault(Proc, FLTBPT, TRUE);
7350Sstevel@tonic-gate 		(void) Pfault(Proc, FLTTRACE, TRUE);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		/* needed for x86 */
7380Sstevel@tonic-gate 		(void) Psetflags(Proc, PR_BPTADJ);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 		/*
7410Sstevel@tonic-gate 		 * Find functions and set breakpoints on grabbed process.
7420Sstevel@tonic-gate 		 * A process stopped on exec() gets its breakpoints set below.
7430Sstevel@tonic-gate 		 */
7440Sstevel@tonic-gate 		if ((Lsp->pr_why != PR_SYSENTRY &&
7450Sstevel@tonic-gate 		    Lsp->pr_why != PR_SYSEXIT) ||
74611798SRoger.Faulkner@Sun.COM 		    Lsp->pr_what != SYS_execve) {
7470Sstevel@tonic-gate 			establish_breakpoints();
7480Sstevel@tonic-gate 			establish_stacks();
7490Sstevel@tonic-gate 		}
7500Sstevel@tonic-gate 	}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	/*
7530Sstevel@tonic-gate 	 * Use asynchronous-stop for multithreaded truss.
7540Sstevel@tonic-gate 	 * truss runs one lwp for each lwp in the target process.
7550Sstevel@tonic-gate 	 */
7560Sstevel@tonic-gate 	(void) Psetflags(Proc, PR_ASYNC);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	/* flush out all tracing flags now. */
7590Sstevel@tonic-gate 	Psync(Proc);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/*
7620Sstevel@tonic-gate 	 * If we grabbed a running process, set it running again.
7630Sstevel@tonic-gate 	 * Since we are tracing lwp_create() and lwp_exit(), the
7640Sstevel@tonic-gate 	 * lwps will not change in the process until we create all
7650Sstevel@tonic-gate 	 * of the truss worker threads.
7660Sstevel@tonic-gate 	 * We leave a created process stopped so its exec() can be reported.
7670Sstevel@tonic-gate 	 */
7680Sstevel@tonic-gate 	first = created? FALSE : TRUE;
7690Sstevel@tonic-gate 	if (!created &&
7700Sstevel@tonic-gate 	    ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
7710Sstevel@tonic-gate 	    (Lsp->pr_flags & PR_DSTOP)))
7720Sstevel@tonic-gate 		first = FALSE;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	main_thread(first);
7750Sstevel@tonic-gate 	return (0);
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate /*
7793235Sraf  * Called from main() and from control() after fork().
7800Sstevel@tonic-gate  */
7810Sstevel@tonic-gate void
main_thread(int first)7820Sstevel@tonic-gate main_thread(int first)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	private_t *pri = get_private();
7850Sstevel@tonic-gate 	struct tms tms;
7860Sstevel@tonic-gate 	int flags;
7870Sstevel@tonic-gate 	int retc;
7880Sstevel@tonic-gate 	int i;
7890Sstevel@tonic-gate 	int count;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/*
7921132Sraf 	 * Block all signals in the main thread.
7931132Sraf 	 * Some worker thread will receive signals.
7941132Sraf 	 */
7951132Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
7961132Sraf 
7971132Sraf 	/*
7980Sstevel@tonic-gate 	 * If we are dealing with a previously hung process,
7990Sstevel@tonic-gate 	 * arrange not to leave it hung on the same system call.
8000Sstevel@tonic-gate 	 */
8010Sstevel@tonic-gate 	primary_lwp = (first && Pstate(Proc) == PS_STOP)?
80211798SRoger.Faulkner@Sun.COM 	    Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * Create worker threads to match the lwps in the target process.
8060Sstevel@tonic-gate 	 */
8070Sstevel@tonic-gate 	truss_nlwp = 0;
8080Sstevel@tonic-gate 	truss_maxlwp = 1;
8090Sstevel@tonic-gate 	truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
8100Sstevel@tonic-gate 	truss_lwpid[0] = 0;
8110Sstevel@tonic-gate 	count = 0;
8120Sstevel@tonic-gate 	(void) Plwp_iter(Proc, create_thread, &count);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (count == 0) {
8150Sstevel@tonic-gate 		(void) printf("(Warning: no matching active LWPs found, "
8160Sstevel@tonic-gate 		    "waiting)\n");
8170Sstevel@tonic-gate 		Flush();
8180Sstevel@tonic-gate 	}
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	/*
8210Sstevel@tonic-gate 	 * Set all of the truss worker threads running now.
8220Sstevel@tonic-gate 	 */
8230Sstevel@tonic-gate 	(void) mutex_lock(&truss_lock);
8240Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
8250Sstevel@tonic-gate 		if (truss_lwpid[i])
8260Sstevel@tonic-gate 			(void) thr_continue(truss_lwpid[i]);
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	/*
8311132Sraf 	 * Wait until all worker threads terminate.
8320Sstevel@tonic-gate 	 */
8331132Sraf 	while (thr_join(0, NULL, NULL) == 0)
8341132Sraf 		continue;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	(void) Punsetflags(Proc, PR_ASYNC);
8370Sstevel@tonic-gate 	Psync(Proc);
8380Sstevel@tonic-gate 	if (sigusr1)
8390Sstevel@tonic-gate 		letgo(pri);
8400Sstevel@tonic-gate 	flags = PRELEASE_CLEAR;
8410Sstevel@tonic-gate 	if (leave_hung)
8420Sstevel@tonic-gate 		flags |= PRELEASE_HANG;
8430Sstevel@tonic-gate 	Prelease(Proc, flags);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	procdel();
8460Sstevel@tonic-gate 	retc = (leave_hung? 0 : wait4all());
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	if (!descendent) {
8490Sstevel@tonic-gate 		interrupt = 0;	/* another interrupt kills the report */
8500Sstevel@tonic-gate 		if (cflag) {
8510Sstevel@tonic-gate 			if (fflag)
8520Sstevel@tonic-gate 				file_to_parent();
8530Sstevel@tonic-gate 			report(pri, times(&tms) - starttime);
8540Sstevel@tonic-gate 		}
8550Sstevel@tonic-gate 	} else if (cflag && fflag) {
8560Sstevel@tonic-gate 		child_to_file();
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	exit(retc);	/* exit with exit status of created process, else 0 */
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate void *
worker_thread(void * arg)8630Sstevel@tonic-gate worker_thread(void *arg)
8640Sstevel@tonic-gate {
8650Sstevel@tonic-gate 	struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
8660Sstevel@tonic-gate 	const pstatus_t *Psp = Pstatus(Proc);
8670Sstevel@tonic-gate 	const lwpstatus_t *Lsp = Lstatus(Lwp);
8680Sstevel@tonic-gate 	struct syscount *scp;
8690Sstevel@tonic-gate 	lwpid_t who = Lsp->pr_lwpid;
8700Sstevel@tonic-gate 	int first = (who == primary_lwp);
8710Sstevel@tonic-gate 	private_t *pri = get_private();
8720Sstevel@tonic-gate 	int req_flag = 0;
8731132Sraf 	int leave_it_hung = FALSE;
8740Sstevel@tonic-gate 	int reset_traps = FALSE;
8750Sstevel@tonic-gate 	int gcode;
8760Sstevel@tonic-gate 	int what;
8770Sstevel@tonic-gate 	int ow_in_effect = 0;
8780Sstevel@tonic-gate 	long ow_syscall = 0;
8790Sstevel@tonic-gate 	long ow_subcode = 0;
8800Sstevel@tonic-gate 	char *ow_string = NULL;
8810Sstevel@tonic-gate 	sysset_t full_set;
8820Sstevel@tonic-gate 	sysset_t running_set;
8830Sstevel@tonic-gate 	int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	pri->Lwp = Lwp;
8860Sstevel@tonic-gate 	pri->lwpstat = Lsp;
8870Sstevel@tonic-gate 	pri->syslast = Lsp->pr_stime;
8880Sstevel@tonic-gate 	pri->usrlast = Lsp->pr_utime;
8890Sstevel@tonic-gate 	make_pname(pri, 0);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	prfillset(&full_set);
8920Sstevel@tonic-gate 
8931132Sraf 	/* we were created with all signals blocked; unblock them */
8941132Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL);
8951132Sraf 
8960Sstevel@tonic-gate 	/*
8971132Sraf 	 * Run this loop until the victim lwp terminates or we receive
8981132Sraf 	 * a termination condition (leave_hung | interrupt | sigusr1).
8990Sstevel@tonic-gate 	 */
9000Sstevel@tonic-gate 	for (;;) {
9010Sstevel@tonic-gate 		if (interrupt | sigusr1) {
9020Sstevel@tonic-gate 			(void) Lstop(Lwp, MILLISEC);
9030Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_RUN)
9040Sstevel@tonic-gate 				break;
9050Sstevel@tonic-gate 		}
9060Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_RUN) {
9070Sstevel@tonic-gate 			/* millisecond timeout is for sleeping syscalls */
9080Sstevel@tonic-gate 			uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 			/*
9110Sstevel@tonic-gate 			 * If we are to leave this lwp stopped in sympathy
9120Sstevel@tonic-gate 			 * with another lwp that has been left hung, or if
9130Sstevel@tonic-gate 			 * we have been interrupted or instructed to release
9140Sstevel@tonic-gate 			 * our victim process, and this lwp is stopped but
9150Sstevel@tonic-gate 			 * not on an event of interest to /proc, then just
9160Sstevel@tonic-gate 			 * leave it in that state.
9170Sstevel@tonic-gate 			 */
9180Sstevel@tonic-gate 			if ((leave_hung | interrupt | sigusr1) &&
9190Sstevel@tonic-gate 			    (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
9200Sstevel@tonic-gate 			    == PR_STOPPED)
9210Sstevel@tonic-gate 				break;
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 			(void) Lwait(Lwp, tout);
9240Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_RUN &&
9250Sstevel@tonic-gate 			    tout != 0 && !(interrupt | sigusr1)) {
9260Sstevel@tonic-gate 				(void) mutex_lock(&truss_lock);
9270Sstevel@tonic-gate 				if ((Lsp->pr_flags & PR_STOPPED) &&
9280Sstevel@tonic-gate 				    Lsp->pr_why == PR_JOBCONTROL)
9290Sstevel@tonic-gate 					req_flag = jobcontrol(pri, dotrace);
9300Sstevel@tonic-gate 				else
9310Sstevel@tonic-gate 					req_flag = requested(pri, req_flag,
9320Sstevel@tonic-gate 					    dotrace);
9330Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
9340Sstevel@tonic-gate 			}
9350Sstevel@tonic-gate 			continue;
9360Sstevel@tonic-gate 		}
9370Sstevel@tonic-gate 		data_model = Psp->pr_dmodel;
9380Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_UNDEAD)
9390Sstevel@tonic-gate 			break;
9400Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_LOST) {	/* we lost control */
9410Sstevel@tonic-gate 			/*
9420Sstevel@tonic-gate 			 * After exec(), only one LWP remains in the process.
9430Sstevel@tonic-gate 			 * /proc makes the thread following that LWP receive
9440Sstevel@tonic-gate 			 * EAGAIN (PS_LOST) if the program being exec()ed
9450Sstevel@tonic-gate 			 * is a set-id program.  Every other controlling
9460Sstevel@tonic-gate 			 * thread receives ENOENT (because its LWP vanished).
9470Sstevel@tonic-gate 			 * We are the controlling thread for the exec()ing LWP.
9480Sstevel@tonic-gate 			 * We must wait until all of our siblings terminate
9490Sstevel@tonic-gate 			 * before attempting to reopen the process.
9500Sstevel@tonic-gate 			 */
9510Sstevel@tonic-gate 			(void) mutex_lock(&truss_lock);
9520Sstevel@tonic-gate 			while (truss_nlwp > 1)
9530Sstevel@tonic-gate 				(void) cond_wait(&truss_cv, &truss_lock);
9540Sstevel@tonic-gate 			if (Preopen(Proc) == 0) { /* we got control back */
9550Sstevel@tonic-gate 				/*
9560Sstevel@tonic-gate 				 * We have to free and re-grab the LWP.
9570Sstevel@tonic-gate 				 * The process is guaranteed to be at exit
9580Sstevel@tonic-gate 				 * from exec() or execve() and have only
9590Sstevel@tonic-gate 				 * one LWP, namely this one, and the LWP
9600Sstevel@tonic-gate 				 * is guaranteed to have lwpid == 1.
9610Sstevel@tonic-gate 				 * This "cannot fail".
9620Sstevel@tonic-gate 				 */
9630Sstevel@tonic-gate 				who = 1;
9640Sstevel@tonic-gate 				Lfree(Lwp);
9650Sstevel@tonic-gate 				pri->Lwp = Lwp =
96611798SRoger.Faulkner@Sun.COM 				    Lgrab(Proc, who, &gcode);
9670Sstevel@tonic-gate 				if (Lwp == NULL)
9680Sstevel@tonic-gate 					abend("Lgrab error: ",
96911798SRoger.Faulkner@Sun.COM 					    Lgrab_error(gcode));
9700Sstevel@tonic-gate 				pri->lwpstat = Lsp = Lstatus(Lwp);
9710Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
9720Sstevel@tonic-gate 				continue;
9730Sstevel@tonic-gate 			}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 			/* we really lost it */
9760Sstevel@tonic-gate 			if (pri->exec_string && *pri->exec_string) {
9770Sstevel@tonic-gate 				if (pri->exec_pname[0] != '\0')
9780Sstevel@tonic-gate 					(void) fputs(pri->exec_pname, stdout);
9790Sstevel@tonic-gate 				timestamp(pri);
9800Sstevel@tonic-gate 				(void) fputs(pri->exec_string, stdout);
9810Sstevel@tonic-gate 				(void) fputc('\n', stdout);
9820Sstevel@tonic-gate 			} else if (pri->length) {
9830Sstevel@tonic-gate 				(void) fputc('\n', stdout);
9840Sstevel@tonic-gate 			}
9850Sstevel@tonic-gate 			if (pri->sys_valid)
9860Sstevel@tonic-gate 				(void) printf(
9870Sstevel@tonic-gate 			"%s\t*** cannot trace across exec() of %s ***\n",
98811798SRoger.Faulkner@Sun.COM 				    pri->pname, pri->sys_path);
9890Sstevel@tonic-gate 			else
9900Sstevel@tonic-gate 				(void) printf(
9910Sstevel@tonic-gate 				"%s\t*** lost control of process ***\n",
99211798SRoger.Faulkner@Sun.COM 				    pri->pname);
9930Sstevel@tonic-gate 			pri->length = 0;
9940Sstevel@tonic-gate 			Flush();
9950Sstevel@tonic-gate 			(void) mutex_unlock(&truss_lock);
9960Sstevel@tonic-gate 			break;
9970Sstevel@tonic-gate 		}
9980Sstevel@tonic-gate 		if (Lstate(Lwp) != PS_STOP) {
9990Sstevel@tonic-gate 			(void) fprintf(stderr,
100011798SRoger.Faulkner@Sun.COM 			    "%s: state = %d\n", command, Lstate(Lwp));
10010Sstevel@tonic-gate 			abend(pri->pname, "uncaught status of subject lwp");
10020Sstevel@tonic-gate 		}
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 		make_pname(pri, 0);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 		what = Lsp->pr_what;
10090Sstevel@tonic-gate 		req_flag = 0;
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 		switch (Lsp->pr_why) {
10120Sstevel@tonic-gate 		case PR_REQUESTED:
10130Sstevel@tonic-gate 			break;
10140Sstevel@tonic-gate 		case PR_SIGNALLED:
10150Sstevel@tonic-gate 			req_flag = signalled(pri, req_flag, dotrace);
10160Sstevel@tonic-gate 			if (Sflag && !first && prismember(&sighang, what))
10170Sstevel@tonic-gate 				leave_it_hung = TRUE;
10180Sstevel@tonic-gate 			break;
10190Sstevel@tonic-gate 		case PR_FAULTED:
10200Sstevel@tonic-gate 			if (what == FLTBPT) {
10210Sstevel@tonic-gate 				int rval;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 				(void) Pstop(Proc, 0);
10240Sstevel@tonic-gate 				rval = function_trace(pri, first, 0, dotrace);
10250Sstevel@tonic-gate 				if (rval == 1)
10260Sstevel@tonic-gate 					leave_it_hung = TRUE;
10270Sstevel@tonic-gate 				if (rval >= 0)
10280Sstevel@tonic-gate 					break;
10290Sstevel@tonic-gate 			}
10300Sstevel@tonic-gate 			if (faulted(pri, dotrace) &&
10310Sstevel@tonic-gate 			    Mflag && !first && prismember(&flthang, what))
10320Sstevel@tonic-gate 				leave_it_hung = TRUE;
10330Sstevel@tonic-gate 			break;
10340Sstevel@tonic-gate 		case PR_JOBCONTROL:	/* can't happen except first time */
10350Sstevel@tonic-gate 			req_flag = jobcontrol(pri, dotrace);
10360Sstevel@tonic-gate 			break;
10370Sstevel@tonic-gate 		case PR_SYSENTRY:
10380Sstevel@tonic-gate 			/* protect ourself from operating system error */
10390Sstevel@tonic-gate 			if (what <= 0 || what > PRMAXSYS)
10400Sstevel@tonic-gate 				what = PRMAXSYS;
10410Sstevel@tonic-gate 			pri->length = 0;
10420Sstevel@tonic-gate 			/*
10430Sstevel@tonic-gate 			 * ow_in_effect checks to see whether or not we
10440Sstevel@tonic-gate 			 * are attempting to quantify the time spent in
10450Sstevel@tonic-gate 			 * a one way system call.  This is necessary as
10460Sstevel@tonic-gate 			 * some system calls never return, yet it is desireable
10470Sstevel@tonic-gate 			 * to determine how much time the traced process
10480Sstevel@tonic-gate 			 * spends in these calls.  To do this, a one way
10490Sstevel@tonic-gate 			 * flag is set on SYSENTRY when the call is recieved.
10500Sstevel@tonic-gate 			 * After this, the call mask for the SYSENTRY events
10510Sstevel@tonic-gate 			 * is filled so that the traced process will stop
10520Sstevel@tonic-gate 			 * on the entry to the very next system call.
10530Sstevel@tonic-gate 			 * This appears to the the best way to determine
10540Sstevel@tonic-gate 			 * system time elapsed between a one way system call.
10550Sstevel@tonic-gate 			 * Once the next call occurs, values that have been
10560Sstevel@tonic-gate 			 * stashed are used to record the correct syscall
10570Sstevel@tonic-gate 			 * and time, and the SYSENTRY event mask is restored
10580Sstevel@tonic-gate 			 * so that the traced process may continue.
10590Sstevel@tonic-gate 			 */
10600Sstevel@tonic-gate 			if (dotrace && ow_in_effect) {
10610Sstevel@tonic-gate 				if (cflag) {
10620Sstevel@tonic-gate 					(void) mutex_lock(&count_lock);
10630Sstevel@tonic-gate 					scp = Cp->syscount[ow_syscall];
10640Sstevel@tonic-gate 					if (ow_subcode != -1)
10650Sstevel@tonic-gate 						scp += ow_subcode;
10660Sstevel@tonic-gate 					scp->count++;
10670Sstevel@tonic-gate 					accumulate(&scp->stime,
10680Sstevel@tonic-gate 					    &Lsp->pr_stime, &pri->syslast);
10690Sstevel@tonic-gate 					accumulate(&Cp->usrtotal,
10700Sstevel@tonic-gate 					    &Lsp->pr_utime, &pri->usrlast);
10710Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
10720Sstevel@tonic-gate 					pri->usrlast = Lsp->pr_utime;
10730Sstevel@tonic-gate 					(void) mutex_unlock(&count_lock);
10740Sstevel@tonic-gate 				} else if (Eflag) {
10750Sstevel@tonic-gate 					putpname(pri);
10760Sstevel@tonic-gate 					timestamp(pri);
10770Sstevel@tonic-gate 					(void) printf("%s\n", ow_string);
10780Sstevel@tonic-gate 					free(ow_string);
10790Sstevel@tonic-gate 					ow_string = NULL;
10800Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
10810Sstevel@tonic-gate 				}
10820Sstevel@tonic-gate 				ow_in_effect = 0;
10830Sstevel@tonic-gate 				Psetsysentry(Proc, &running_set);
10840Sstevel@tonic-gate 			}
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 			/*
10870Sstevel@tonic-gate 			 * Special cases.  Most syscalls are traced on exit.
10880Sstevel@tonic-gate 			 */
10890Sstevel@tonic-gate 			switch (what) {
10900Sstevel@tonic-gate 			case SYS_exit:			/* exit() */
10910Sstevel@tonic-gate 			case SYS_lwp_exit:		/* lwp_exit() */
10920Sstevel@tonic-gate 			case SYS_context:		/* [get|set]context() */
10930Sstevel@tonic-gate 				if (dotrace && cflag &&
10940Sstevel@tonic-gate 				    prismember(&trace, what)) {
10950Sstevel@tonic-gate 					ow_in_effect = 1;
10960Sstevel@tonic-gate 					ow_syscall = what;
10970Sstevel@tonic-gate 					ow_subcode = getsubcode(pri);
10980Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
10990Sstevel@tonic-gate 					running_set =
11000Sstevel@tonic-gate 					    (Pstatus(Proc))->pr_sysentry;
11010Sstevel@tonic-gate 					Psetsysentry(Proc, &full_set);
11020Sstevel@tonic-gate 				} else if (dotrace && Eflag &&
11030Sstevel@tonic-gate 				    prismember(&trace, what)) {
11040Sstevel@tonic-gate 					(void) sysentry(pri, dotrace);
11050Sstevel@tonic-gate 					ow_in_effect = 1;
11060Sstevel@tonic-gate 					ow_string = my_malloc(
11070Sstevel@tonic-gate 					    strlen(pri->sys_string) + 1, NULL);
11080Sstevel@tonic-gate 					(void) strcpy(ow_string,
11090Sstevel@tonic-gate 					    pri->sys_string);
11100Sstevel@tonic-gate 					running_set =
11110Sstevel@tonic-gate 					    (Pstatus(Proc))->pr_sysentry;
11120Sstevel@tonic-gate 					Psetsysentry(Proc, &full_set);
11130Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
11140Sstevel@tonic-gate 				} else if (dotrace &&
11150Sstevel@tonic-gate 				    prismember(&trace, what)) {
11160Sstevel@tonic-gate 					(void) sysentry(pri, dotrace);
11170Sstevel@tonic-gate 					putpname(pri);
11180Sstevel@tonic-gate 					timestamp(pri);
11190Sstevel@tonic-gate 					pri->length +=
112011798SRoger.Faulkner@Sun.COM 					    printf("%s\n", pri->sys_string);
11210Sstevel@tonic-gate 					Flush();
11220Sstevel@tonic-gate 				}
11230Sstevel@tonic-gate 				pri->sys_leng = 0;
11240Sstevel@tonic-gate 				*pri->sys_string = '\0';
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 				if (what == SYS_exit)
11270Sstevel@tonic-gate 					exit_called = TRUE;
11280Sstevel@tonic-gate 				break;
11290Sstevel@tonic-gate 			case SYS_execve:
1130*12273SCasper.Dik@Sun.COM 				show_cred(pri, FALSE, TRUE);
11310Sstevel@tonic-gate 				(void) sysentry(pri, dotrace);
11320Sstevel@tonic-gate 				if (dotrace && !cflag &&
11330Sstevel@tonic-gate 				    prismember(&trace, what)) {
11340Sstevel@tonic-gate 					pri->exec_string =
113511798SRoger.Faulkner@Sun.COM 					    my_realloc(pri->exec_string,
113611798SRoger.Faulkner@Sun.COM 					    strlen(pri->sys_string) + 1,
113711798SRoger.Faulkner@Sun.COM 					    NULL);
11380Sstevel@tonic-gate 					(void) strcpy(pri->exec_pname,
113911798SRoger.Faulkner@Sun.COM 					    pri->pname);
11400Sstevel@tonic-gate 					(void) strcpy(pri->exec_string,
114111798SRoger.Faulkner@Sun.COM 					    pri->sys_string);
11420Sstevel@tonic-gate 					pri->length += strlen(pri->sys_string);
11430Sstevel@tonic-gate 					pri->exec_lwpid = Lsp->pr_lwpid;
11440Sstevel@tonic-gate 				}
11450Sstevel@tonic-gate 				pri->sys_leng = 0;
11460Sstevel@tonic-gate 				*pri->sys_string = '\0';
11470Sstevel@tonic-gate 				break;
11480Sstevel@tonic-gate 			default:
11490Sstevel@tonic-gate 				if (dotrace && (cflag || Eflag) &&
11500Sstevel@tonic-gate 				    prismember(&trace, what)) {
11510Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
11520Sstevel@tonic-gate 				}
11530Sstevel@tonic-gate 				break;
11540Sstevel@tonic-gate 			}
11550Sstevel@tonic-gate 			if (dotrace && Tflag && !first &&
11560Sstevel@tonic-gate 			    (prismember(&syshang, what) ||
11570Sstevel@tonic-gate 			    (exit_called && prismember(&syshang, SYS_exit))))
11580Sstevel@tonic-gate 				leave_it_hung = TRUE;
11590Sstevel@tonic-gate 			break;
11600Sstevel@tonic-gate 		case PR_SYSEXIT:
11610Sstevel@tonic-gate 			/* check for write open of a /proc file */
116211798SRoger.Faulkner@Sun.COM 			if (what == SYS_openat || what == SYS_openat64 ||
116311798SRoger.Faulkner@Sun.COM 			    what == SYS_open || what == SYS_open64) {
116411798SRoger.Faulkner@Sun.COM 				int readonly;
116511798SRoger.Faulkner@Sun.COM 
11660Sstevel@tonic-gate 				(void) sysentry(pri, dotrace);
11670Sstevel@tonic-gate 				pri->Errno = Lsp->pr_errno;
11680Sstevel@tonic-gate 				pri->ErrPriv = Lsp->pr_errpriv;
116911798SRoger.Faulkner@Sun.COM 				readonly =
117011798SRoger.Faulkner@Sun.COM 				    ((what == SYS_openat ||
117111798SRoger.Faulkner@Sun.COM 				    what == SYS_openat64) &&
117211798SRoger.Faulkner@Sun.COM 				    pri->sys_nargs > 2 &&
117311798SRoger.Faulkner@Sun.COM 				    (pri->sys_args[2]&0x3) == O_RDONLY) ||
117411798SRoger.Faulkner@Sun.COM 				    ((what == SYS_open ||
117511798SRoger.Faulkner@Sun.COM 				    what == SYS_open64) &&
117611798SRoger.Faulkner@Sun.COM 				    pri->sys_nargs > 1 &&
117711798SRoger.Faulkner@Sun.COM 				    (pri->sys_args[1]&0x3) == O_RDONLY);
11780Sstevel@tonic-gate 				if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
117911798SRoger.Faulkner@Sun.COM 				    pri->sys_valid && !readonly) {
11800Sstevel@tonic-gate 					int rv = checkproc(pri);
11810Sstevel@tonic-gate 					if (rv == 1 && Fflag != PGRAB_FORCE) {
11820Sstevel@tonic-gate 						/*
11830Sstevel@tonic-gate 						 * The process opened itself
11840Sstevel@tonic-gate 						 * and no -F flag was specified.
11850Sstevel@tonic-gate 						 * Just print the open() call
11860Sstevel@tonic-gate 						 * and let go of the process.
11870Sstevel@tonic-gate 						 */
11880Sstevel@tonic-gate 						if (dotrace && !cflag &&
11890Sstevel@tonic-gate 						    prismember(&trace, what)) {
11900Sstevel@tonic-gate 							putpname(pri);
11910Sstevel@tonic-gate 							timestamp(pri);
11920Sstevel@tonic-gate 							(void) printf("%s\n",
11930Sstevel@tonic-gate 							    pri->sys_string);
11940Sstevel@tonic-gate 							Flush();
11950Sstevel@tonic-gate 						}
11961132Sraf 						sigusr1 = TRUE;
11970Sstevel@tonic-gate 						(void) mutex_unlock(
119811798SRoger.Faulkner@Sun.COM 						    &truss_lock);
11990Sstevel@tonic-gate 						goto out;
12000Sstevel@tonic-gate 					}
12010Sstevel@tonic-gate 					if (rv == 2) {
12020Sstevel@tonic-gate 						/*
12030Sstevel@tonic-gate 						 * Process opened someone else.
12040Sstevel@tonic-gate 						 * The open is being reissued.
12050Sstevel@tonic-gate 						 * Don't report this one.
12060Sstevel@tonic-gate 						 */
12070Sstevel@tonic-gate 						pri->sys_leng = 0;
12080Sstevel@tonic-gate 						*pri->sys_string = '\0';
12090Sstevel@tonic-gate 						pri->sys_nargs = 0;
12100Sstevel@tonic-gate 						break;
12110Sstevel@tonic-gate 					}
12120Sstevel@tonic-gate 				}
12130Sstevel@tonic-gate 			}
121411798SRoger.Faulkner@Sun.COM 			if (what == SYS_execve && pri->Errno == 0) {
12150Sstevel@tonic-gate 				/*
12160Sstevel@tonic-gate 				 * Refresh the data model on exec() in case it
12170Sstevel@tonic-gate 				 * is different from the parent.  Lwait()
12180Sstevel@tonic-gate 				 * doesn't update process-wide status, so we
12190Sstevel@tonic-gate 				 * have to explicitly call Pstopstatus() to get
12200Sstevel@tonic-gate 				 * the new state.
12210Sstevel@tonic-gate 				 */
12220Sstevel@tonic-gate 				(void) Pstopstatus(Proc, PCNULL, 0);
12230Sstevel@tonic-gate 				data_model = Psp->pr_dmodel;
12240Sstevel@tonic-gate 			}
12250Sstevel@tonic-gate 			if (sysexit(pri, dotrace))
12260Sstevel@tonic-gate 				Flush();
12270Sstevel@tonic-gate 			if (what == SYS_lwp_create && pri->Rval1 != 0) {
12280Sstevel@tonic-gate 				struct ps_lwphandle *new_Lwp;
12290Sstevel@tonic-gate 				lwpid_t lwpid;
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 				if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
12321132Sraf 					(void) thr_sigsetmask(SIG_SETMASK,
12331132Sraf 					    &fillset, NULL);
12340Sstevel@tonic-gate 					if (thr_create(NULL, 0, worker_thread,
12350Sstevel@tonic-gate 					    new_Lwp, THR_BOUND | THR_SUSPENDED,
12360Sstevel@tonic-gate 					    &lwpid) != 0)
12370Sstevel@tonic-gate 						abend("cannot create lwp ",
12380Sstevel@tonic-gate 						    "to follow child lwp");
12390Sstevel@tonic-gate 					insert_lwpid(lwpid);
12400Sstevel@tonic-gate 					(void) thr_continue(lwpid);
12411132Sraf 					(void) thr_sigsetmask(SIG_SETMASK,
12421132Sraf 					    &emptyset, NULL);
12430Sstevel@tonic-gate 				}
12440Sstevel@tonic-gate 			}
12450Sstevel@tonic-gate 			pri->sys_nargs = 0;
12460Sstevel@tonic-gate 			if (dotrace && Tflag && !first &&
12470Sstevel@tonic-gate 			    prismember(&syshang, what))
12480Sstevel@tonic-gate 				leave_it_hung = TRUE;
124911798SRoger.Faulkner@Sun.COM 			if (what == SYS_execve && pri->Errno == 0) {
12500Sstevel@tonic-gate 				is_vfork_child = FALSE;
12510Sstevel@tonic-gate 				reset_breakpoints();
12520Sstevel@tonic-gate 				/*
12530Sstevel@tonic-gate 				 * exec() resets the calling LWP's lwpid to 1.
12540Sstevel@tonic-gate 				 * If the LWP has changed its lwpid, then
12550Sstevel@tonic-gate 				 * we have to free and re-grab the LWP
12560Sstevel@tonic-gate 				 * in order to keep libproc consistent.
12570Sstevel@tonic-gate 				 * This "cannot fail".
12580Sstevel@tonic-gate 				 */
12590Sstevel@tonic-gate 				if (who != Lsp->pr_lwpid) {
12600Sstevel@tonic-gate 					/*
12610Sstevel@tonic-gate 					 * We must wait for all of our
12620Sstevel@tonic-gate 					 * siblings to terminate.
12630Sstevel@tonic-gate 					 */
12640Sstevel@tonic-gate 					while (truss_nlwp > 1)
12650Sstevel@tonic-gate 						(void) cond_wait(&truss_cv,
126611798SRoger.Faulkner@Sun.COM 						    &truss_lock);
12670Sstevel@tonic-gate 					who = Lsp->pr_lwpid;
12680Sstevel@tonic-gate 					Lfree(Lwp);
12690Sstevel@tonic-gate 					pri->Lwp = Lwp =
127011798SRoger.Faulkner@Sun.COM 					    Lgrab(Proc, who, &gcode);
12710Sstevel@tonic-gate 					if (Lwp == NULL)
12720Sstevel@tonic-gate 						abend("Lgrab error: ",
127311798SRoger.Faulkner@Sun.COM 						    Lgrab_error(gcode));
12740Sstevel@tonic-gate 					pri->lwpstat = Lsp = Lstatus(Lwp);
12750Sstevel@tonic-gate 				}
12760Sstevel@tonic-gate 			}
12770Sstevel@tonic-gate 			break;
12780Sstevel@tonic-gate 		default:
12790Sstevel@tonic-gate 			req_flag = 0;
12800Sstevel@tonic-gate 			(void) fprintf(stderr,
128111798SRoger.Faulkner@Sun.COM 			    "unknown reason for stopping: %d/%d\n",
128211798SRoger.Faulkner@Sun.COM 			    Lsp->pr_why, what);
12830Sstevel@tonic-gate 			abend(NULL, NULL);
12840Sstevel@tonic-gate 		}
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 		if (pri->child) {	/* controlled process fork()ed */
12870Sstevel@tonic-gate 			if (fflag || Dynpat != NULL)  {
12880Sstevel@tonic-gate 				if (Lsp->pr_why == PR_SYSEXIT &&
12893235Sraf 				    (Lsp->pr_what == SYS_vfork ||
12903235Sraf 				    (Lsp->pr_what == SYS_forksys &&
12913235Sraf 				    Lsp->pr_sysarg[0] == 2))) {
12920Sstevel@tonic-gate 					is_vfork_child = TRUE;
12933235Sraf 					(void) Pstop(Proc, 0);
12943235Sraf 				}
12950Sstevel@tonic-gate 				if (control(pri, pri->child)) {
12960Sstevel@tonic-gate 					(void) mutex_unlock(&truss_lock);
12970Sstevel@tonic-gate 					pri->child = 0;
12980Sstevel@tonic-gate 					if (!fflag) {
12990Sstevel@tonic-gate 						/*
13000Sstevel@tonic-gate 						 * If this is vfork(), then
13010Sstevel@tonic-gate 						 * this clears the breakpoints
13020Sstevel@tonic-gate 						 * in the parent's address space
13030Sstevel@tonic-gate 						 * as well as in the child's.
13040Sstevel@tonic-gate 						 */
13050Sstevel@tonic-gate 						clear_breakpoints();
13060Sstevel@tonic-gate 						Prelease(Proc, PRELEASE_CLEAR);
13070Sstevel@tonic-gate 						_exit(0);
13080Sstevel@tonic-gate 					}
13090Sstevel@tonic-gate 					main_thread(FALSE);
13100Sstevel@tonic-gate 					/* NOTREACHED */
13110Sstevel@tonic-gate 				}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 				/*
13140Sstevel@tonic-gate 				 * Here, we are still the parent truss.
13153235Sraf 				 * If the child messes with the breakpoints and
13160Sstevel@tonic-gate 				 * this is vfork(), we have to set them again.
13170Sstevel@tonic-gate 				 */
13185355Srh87107 				if (Dynpat != NULL && is_vfork_child && !fflag)
13190Sstevel@tonic-gate 					reset_traps = TRUE;
13200Sstevel@tonic-gate 				is_vfork_child = FALSE;
13210Sstevel@tonic-gate 			}
13220Sstevel@tonic-gate 			pri->child = 0;
13230Sstevel@tonic-gate 		}
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 		if (leave_it_hung) {
13260Sstevel@tonic-gate 			(void) mutex_unlock(&truss_lock);
13270Sstevel@tonic-gate 			break;
13280Sstevel@tonic-gate 		}
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 		if (reset_traps) {
13310Sstevel@tonic-gate 			/*
13320Sstevel@tonic-gate 			 * To recover from vfork, we must catch the lwp
13330Sstevel@tonic-gate 			 * that issued the vfork() when it returns to user
13340Sstevel@tonic-gate 			 * level, with all other lwps remaining stopped.
13353235Sraf 			 * For this purpose, we have directed all lwps to
13363235Sraf 			 * stop and we now set the vfork()ing lwp running
13373235Sraf 			 * with the PRSTEP flag.  We expect to capture it
13383235Sraf 			 * when it stops again showing PR_FAULTED/FLTTRACE.
13390Sstevel@tonic-gate 			 * We are holding truss_lock, so no other threads
13400Sstevel@tonic-gate 			 * in truss will set any other lwps in the victim
13410Sstevel@tonic-gate 			 * process running.
13420Sstevel@tonic-gate 			 */
13430Sstevel@tonic-gate 			reset_traps = FALSE;
13440Sstevel@tonic-gate 			(void) Lsetrun(Lwp, 0, PRSTEP);
13450Sstevel@tonic-gate 			do {
13460Sstevel@tonic-gate 				(void) Lwait(Lwp, 0);
13470Sstevel@tonic-gate 			} while (Lstate(Lwp) == PS_RUN);
13480Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_STOP &&
13490Sstevel@tonic-gate 			    Lsp->pr_why == PR_FAULTED &&
13500Sstevel@tonic-gate 			    Lsp->pr_what == FLTTRACE) {
13510Sstevel@tonic-gate 				reestablish_traps();
13520Sstevel@tonic-gate 				(void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
13530Sstevel@tonic-gate 			} else {
13540Sstevel@tonic-gate 				(void) printf("%s\t*** Expected PR_FAULTED/"
135511798SRoger.Faulkner@Sun.COM 				    "FLTTRACE stop following vfork()\n",
135611798SRoger.Faulkner@Sun.COM 				    pri->pname);
13570Sstevel@tonic-gate 			}
13580Sstevel@tonic-gate 		}
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_STOP) {
13610Sstevel@tonic-gate 			int flags = 0;
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 			if (interrupt | sigusr1) {
13640Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
13650Sstevel@tonic-gate 				break;
13660Sstevel@tonic-gate 			}
13670Sstevel@tonic-gate 			/*
13680Sstevel@tonic-gate 			 * If we must leave this lwp hung is sympathy with
13690Sstevel@tonic-gate 			 * another lwp that is being left hung on purpose,
13700Sstevel@tonic-gate 			 * then push the state onward toward PR_REQUESTED.
13710Sstevel@tonic-gate 			 */
13720Sstevel@tonic-gate 			if (leave_hung) {
13730Sstevel@tonic-gate 				if (Lsp->pr_why == PR_REQUESTED) {
13740Sstevel@tonic-gate 					(void) mutex_unlock(&truss_lock);
13750Sstevel@tonic-gate 					break;
13760Sstevel@tonic-gate 				}
13770Sstevel@tonic-gate 				flags |= PRSTOP;
13780Sstevel@tonic-gate 			}
13790Sstevel@tonic-gate 			if (Lsetrun(Lwp, 0, flags) != 0 &&
13800Sstevel@tonic-gate 			    Lstate(Lwp) != PS_LOST &&
13810Sstevel@tonic-gate 			    Lstate(Lwp) != PS_UNDEAD) {
13820Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
13830Sstevel@tonic-gate 				perror("Lsetrun");
13840Sstevel@tonic-gate 				abend("cannot start subject lwp", NULL);
13850Sstevel@tonic-gate 				/* NOTREACHED */
13860Sstevel@tonic-gate 			}
13870Sstevel@tonic-gate 		}
13880Sstevel@tonic-gate 		first = FALSE;
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 		(void) mutex_unlock(&truss_lock);
13910Sstevel@tonic-gate 	}
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate out:
13941132Sraf 	/* block all signals in preparation for exiting */
13951132Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
13961132Sraf 
13971132Sraf 	if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST)
13981132Sraf 		(void) mutex_lock(&truss_lock);
13991132Sraf 	else {
14000Sstevel@tonic-gate 		(void) Lstop(Lwp, MILLISEC);
14010Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
14020Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_STOP &&
14030Sstevel@tonic-gate 		    Lsp->pr_why == PR_FAULTED &&
14040Sstevel@tonic-gate 		    Lsp->pr_what == FLTBPT)
14050Sstevel@tonic-gate 			(void) function_trace(pri, 0, 1, dotrace);
14060Sstevel@tonic-gate 	}
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	if (dotrace && ow_in_effect) {
14090Sstevel@tonic-gate 		if (cflag) {
14100Sstevel@tonic-gate 			(void) mutex_lock(&count_lock);
14110Sstevel@tonic-gate 			scp = Cp->syscount[ow_syscall];
14120Sstevel@tonic-gate 			if (ow_subcode != -1)
14130Sstevel@tonic-gate 				scp += ow_subcode;
14140Sstevel@tonic-gate 			scp->count++;
14150Sstevel@tonic-gate 			accumulate(&scp->stime,
14160Sstevel@tonic-gate 			    &Lsp->pr_stime, &pri->syslast);
14170Sstevel@tonic-gate 			accumulate(&Cp->usrtotal,
14180Sstevel@tonic-gate 			    &Lsp->pr_utime, &pri->usrlast);
14190Sstevel@tonic-gate 			pri->syslast = Lsp->pr_stime;
14200Sstevel@tonic-gate 			pri->usrlast = Lsp->pr_utime;
14210Sstevel@tonic-gate 			(void) mutex_unlock(&count_lock);
14220Sstevel@tonic-gate 		} else if (Eflag) {
14230Sstevel@tonic-gate 			putpname(pri);
14240Sstevel@tonic-gate 			timestamp(pri);
14250Sstevel@tonic-gate 			(void) printf("%s\n", ow_string);
14260Sstevel@tonic-gate 			free(ow_string);
14270Sstevel@tonic-gate 			ow_string = NULL;
14280Sstevel@tonic-gate 			pri->syslast = Lsp->pr_stime;
14290Sstevel@tonic-gate 		}
14300Sstevel@tonic-gate 		ow_in_effect = 0;
14310Sstevel@tonic-gate 		Psetsysentry(Proc, &running_set);
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 
14341132Sraf 	if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) {
14351132Sraf 		/*
14361132Sraf 		 * The victim thread has exited or we lost control of
14371132Sraf 		 * the process.  Remove ourself from the list of all
14381132Sraf 		 * truss threads and notify everyone waiting for this.
14391132Sraf 		 */
14401132Sraf 		lwpid_t my_id = thr_self();
14411132Sraf 		int i;
14421132Sraf 
14431132Sraf 		for (i = 0; i < truss_maxlwp; i++) {
14441132Sraf 			if (truss_lwpid[i] == my_id) {
14451132Sraf 				truss_lwpid[i] = 0;
14461132Sraf 				break;
14471132Sraf 			}
14481132Sraf 		}
14491132Sraf 		if (--truss_nlwp != 0) {
14501132Sraf 			(void) cond_broadcast(&truss_cv);
14511132Sraf 		} else {
14521132Sraf 			/*
14531132Sraf 			 * The last truss worker thread is terminating.
14541132Sraf 			 * The address space is gone (UNDEAD) or is
14551132Sraf 			 * inaccessible (LOST) so we cannot clear the
14561132Sraf 			 * breakpoints.  Just report the htable stats.
14571132Sraf 			 */
14581132Sraf 			report_htable_stats();
14591132Sraf 		}
14601132Sraf 	} else {
14611132Sraf 		/*
14621132Sraf 		 * The victim thread is not a zombie thread, and we have not
14631132Sraf 		 * lost control of the process.  We must have gotten here due
14641132Sraf 		 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
14651132Sraf 		 * In these cases, we must carefully uninstrument the process
14661132Sraf 		 * and either set it running or leave it stopped and abandoned.
14671132Sraf 		 */
14681132Sraf 		static int nstopped = 0;
14691132Sraf 		static int cleared = 0;
14701132Sraf 
14711132Sraf 		if (leave_it_hung)
14721132Sraf 			leave_hung = TRUE;
14731132Sraf 		if ((leave_hung | interrupt | sigusr1) == 0)
14741132Sraf 			abend("(leave_hung | interrupt | sigusr1) == 0", NULL);
14751132Sraf 
14761132Sraf 		/*
14771132Sraf 		 * The first truss thread through here needs to instruct all
14781132Sraf 		 * application threads to stop -- they're not necessarily
14791132Sraf 		 * going to stop on their own.
14801132Sraf 		 */
14811132Sraf 		if (nstopped++ == 0)
14821132Sraf 			(void) Pdstop(Proc);
14831132Sraf 
14841132Sraf 		/*
14851132Sraf 		 * Notify all other worker threads about the reason
14861132Sraf 		 * for being here (leave_hung || interrupt || sigusr1).
14871132Sraf 		 */
14881132Sraf 		broadcast_signals();
14891132Sraf 
14901132Sraf 		/*
14911132Sraf 		 * Once the last thread has reached this point, then and
14921132Sraf 		 * only then is it safe to remove breakpoints and other
14931132Sraf 		 * instrumentation.  Since breakpoints are executed without
14941132Sraf 		 * truss_lock held, a monitor thread can't exit until all
14951132Sraf 		 * breakpoints have been removed, and we can't be sure the
14961132Sraf 		 * procedure to execute a breakpoint won't temporarily
14971132Sraf 		 * reinstall a breakpont.  Accordingly, we need to wait
14981132Sraf 		 * until all threads are in a known state.
14991132Sraf 		 */
15001132Sraf 		while (nstopped != truss_nlwp)
15011132Sraf 			(void) cond_wait(&truss_cv, &truss_lock);
15021132Sraf 
15031132Sraf 		/*
15041132Sraf 		 * All truss threads have reached this point.
15051132Sraf 		 * One of them clears the breakpoints and
15061132Sraf 		 * wakes up everybody else to finish up.
15071132Sraf 		 */
15081132Sraf 		if (cleared++ == 0) {
15091132Sraf 			/*
15101132Sraf 			 * All threads should already be stopped,
15111132Sraf 			 * but just to be safe...
15121132Sraf 			 */
15131132Sraf 			(void) Pstop(Proc, MILLISEC);
15141132Sraf 			clear_breakpoints();
15151132Sraf 			(void) Psysexit(Proc, SYS_vfork, FALSE);
15163235Sraf 			(void) Psysexit(Proc, SYS_forksys, FALSE);
15171132Sraf 			(void) Punsetflags(Proc, PR_FORK);
15181132Sraf 			Psync(Proc);
15191132Sraf 			fflag = 0;
15201132Sraf 			(void) cond_broadcast(&truss_cv);
15211132Sraf 		}
15221132Sraf 
15231132Sraf 		if (!leave_hung && Lstate(Lwp) == PS_STOP)
15241132Sraf 			(void) Lsetrun(Lwp, 0, 0);
15251132Sraf 	}
15261132Sraf 
15270Sstevel@tonic-gate 	(void) Lfree(Lwp);
15280Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
15291132Sraf 	return (NULL);
15300Sstevel@tonic-gate }
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate /*
15330Sstevel@tonic-gate  * Give a base date for time stamps, adjusted to the
15340Sstevel@tonic-gate  * stop time of the selected (first or created) process.
15350Sstevel@tonic-gate  */
15360Sstevel@tonic-gate void
setup_basetime(hrtime_t basehrtime,struct timeval * basedate)15370Sstevel@tonic-gate setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
15380Sstevel@tonic-gate {
15390Sstevel@tonic-gate 	const pstatus_t *Psp = Pstatus(Proc);
15400Sstevel@tonic-gate 	(void) mutex_lock(&count_lock);
15410Sstevel@tonic-gate 	Cp->basetime = Psp->pr_lwp.pr_tstamp;
15420Sstevel@tonic-gate 	(void) mutex_unlock(&count_lock);
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	if ((dflag|Dflag) && !cflag) {
15450Sstevel@tonic-gate 		const struct tm *ptm;
15460Sstevel@tonic-gate 		const char *ptime;
15470Sstevel@tonic-gate 		const char *pdst;
15480Sstevel@tonic-gate 		hrtime_t delta = basehrtime -
154911798SRoger.Faulkner@Sun.COM 		    ((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
155011798SRoger.Faulkner@Sun.COM 		    Cp->basetime.tv_nsec);
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 		if (delta > 0) {
15530Sstevel@tonic-gate 			basedate->tv_sec -= (time_t)(delta / NANOSEC);
15540Sstevel@tonic-gate 			basedate->tv_usec -= (delta % NANOSEC) / 1000;
15550Sstevel@tonic-gate 			if (basedate->tv_usec < 0) {
15560Sstevel@tonic-gate 				basedate->tv_sec--;
15570Sstevel@tonic-gate 				basedate->tv_usec += MICROSEC;
15580Sstevel@tonic-gate 			}
15590Sstevel@tonic-gate 		}
15600Sstevel@tonic-gate 		ptm = localtime(&basedate->tv_sec);
15610Sstevel@tonic-gate 		ptime = asctime(ptm);
15620Sstevel@tonic-gate 		if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
15630Sstevel@tonic-gate 			pdst = "???";
15640Sstevel@tonic-gate 		if (dflag) {
15650Sstevel@tonic-gate 			(void) printf(
15660Sstevel@tonic-gate 			    "Base time stamp:  %ld.%4.4ld  [ %.20s%s %.4s ]\n",
15670Sstevel@tonic-gate 			    basedate->tv_sec, basedate->tv_usec / 100,
15680Sstevel@tonic-gate 			    ptime, pdst, ptime + 20);
15690Sstevel@tonic-gate 			Flush();
15700Sstevel@tonic-gate 		}
15710Sstevel@tonic-gate 	}
15720Sstevel@tonic-gate }
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate /*
15750Sstevel@tonic-gate  * Performs per-process initializations. If truss is following a victim
15760Sstevel@tonic-gate  * process it will fork additional truss processes to follow new processes
15770Sstevel@tonic-gate  * created.  Here is where each new truss process gets its per-process data
15780Sstevel@tonic-gate  * initialized.
15790Sstevel@tonic-gate  */
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate void
per_proc_init()15820Sstevel@tonic-gate per_proc_init()
15830Sstevel@tonic-gate {
15840Sstevel@tonic-gate 	void *pmem;
15850Sstevel@tonic-gate 	struct timeval basedate;
15860Sstevel@tonic-gate 	hrtime_t basehrtime;
15870Sstevel@tonic-gate 	struct syscount *scp;
15880Sstevel@tonic-gate 	int i;
15890Sstevel@tonic-gate 	timestruc_t c_basetime;
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate 	/* Make sure we only configure the basetime for the first truss proc */
15920Sstevel@tonic-gate 
15930Sstevel@tonic-gate 	if (Cp == NULL) {
15940Sstevel@tonic-gate 		pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
15950Sstevel@tonic-gate 		    sizeof (struct syscount), NULL);
15960Sstevel@tonic-gate 		Cp = (struct counts *)pmem;
15970Sstevel@tonic-gate 		basehrtime = gethrtime();
15980Sstevel@tonic-gate 		(void) gettimeofday(&basedate, NULL);
15990Sstevel@tonic-gate 		setup_basetime(basehrtime, &basedate);
16000Sstevel@tonic-gate 	}
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	c_basetime = Cp->basetime;
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	(void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
16050Sstevel@tonic-gate 	    sizeof (struct syscount));
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	Cp->basetime = c_basetime;
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 	if (fcall_tbl != NULL)
16100Sstevel@tonic-gate 		destroy_hash(fcall_tbl);
16110Sstevel@tonic-gate 	fcall_tbl = init_hash(4096);
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	(void) mutex_lock(&count_lock);
16140Sstevel@tonic-gate 	scp = (struct syscount *)(Cp + 1);
16150Sstevel@tonic-gate 	for (i = 0; i <= PRMAXSYS; i++) {
16160Sstevel@tonic-gate 		Cp->syscount[i] = scp;
16170Sstevel@tonic-gate 		scp += nsubcodes(i);
16180Sstevel@tonic-gate 	}
16190Sstevel@tonic-gate 	(void) mutex_unlock(&count_lock);
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate /*
16240Sstevel@tonic-gate  * Writes child state to a tempfile where it can be read and
16250Sstevel@tonic-gate  * accumulated by the parent process. The file descriptor is shared
16260Sstevel@tonic-gate  * among the processes.  Ordering of writes does not matter, it is, however,
16270Sstevel@tonic-gate  * necessary to ensure that all writes are atomic.
16280Sstevel@tonic-gate  */
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate void
child_to_file()16310Sstevel@tonic-gate child_to_file()
16320Sstevel@tonic-gate {
16330Sstevel@tonic-gate 	hiter_t *itr;
16340Sstevel@tonic-gate 	hentry_t *ntry;
16350Sstevel@tonic-gate 	hdntry_t fentry;
16360Sstevel@tonic-gate 	char *s = NULL;
16370Sstevel@tonic-gate 	char *t = NULL;
16380Sstevel@tonic-gate 	unsigned char *buf = NULL;
16390Sstevel@tonic-gate 	size_t bufsz = 0;
16400Sstevel@tonic-gate 	size_t i = 0;
16410Sstevel@tonic-gate 	size_t j = 0;
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	/* ensure that we are in fact a child process */
16440Sstevel@tonic-gate 	if (!descendent)
16450Sstevel@tonic-gate 		return;
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/* enumerate fcall_tbl (tbl locked until freed) */
16480Sstevel@tonic-gate 	if (Dynpat != NULL) {
16490Sstevel@tonic-gate 		itr = iterate_hash(fcall_tbl);
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 		ntry = iter_next(itr);
16520Sstevel@tonic-gate 		while (ntry != NULL) {
16530Sstevel@tonic-gate 			fentry.type = HD_hashntry;
16540Sstevel@tonic-gate 			fentry.count = ntry->count;
16550Sstevel@tonic-gate 			s = ntry->key;
16560Sstevel@tonic-gate 			t = ntry->lib;
16570Sstevel@tonic-gate 			i = strlen(s) + 1;
16580Sstevel@tonic-gate 			j = strlen(t) + 1;
16590Sstevel@tonic-gate 			fentry.sz_key = i;
16600Sstevel@tonic-gate 			fentry.sz_lib = j;
16610Sstevel@tonic-gate 			if (i + sizeof (fentry) > bufsz) {
16620Sstevel@tonic-gate 				buf = my_realloc(buf, i + j + sizeof (fentry),
16630Sstevel@tonic-gate 				    NULL);
16640Sstevel@tonic-gate 				bufsz = i + j + sizeof (fentry);
16650Sstevel@tonic-gate 			}
16660Sstevel@tonic-gate 			(void) memcpy(buf, &fentry, sizeof (fentry));
16670Sstevel@tonic-gate 			(void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
16680Sstevel@tonic-gate 			(void) strlcpy((char *)(buf + sizeof (fentry) + j),
16690Sstevel@tonic-gate 			    s, i);
16700Sstevel@tonic-gate 			if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
16710Sstevel@tonic-gate 				abend("Error writing to tmp file", NULL);
16720Sstevel@tonic-gate 			ntry = iter_next(itr);
16730Sstevel@tonic-gate 		}
16740Sstevel@tonic-gate 		iter_free(itr);
16750Sstevel@tonic-gate 	}
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	/* Now write the count/syscount structs down */
16780Sstevel@tonic-gate 	bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
16790Sstevel@tonic-gate 	    sizeof (struct syscount));
16800Sstevel@tonic-gate 	buf = my_realloc(buf, bufsz, NULL);
16810Sstevel@tonic-gate 	fentry.type = HD_cts_syscts;
16820Sstevel@tonic-gate 	fentry.count = 0;	/* undefined, really */
16830Sstevel@tonic-gate 	fentry.sz_key = bufsz - sizeof (fentry);
16840Sstevel@tonic-gate 	fentry.sz_lib = 0;	/* also undefined */
16850Sstevel@tonic-gate 	(void) memcpy(buf, &fentry, sizeof (fentry));
16860Sstevel@tonic-gate 	(void) memcpy((char *)(buf + sizeof (fentry)), Cp,
16870Sstevel@tonic-gate 	    bufsz - sizeof (fentry));
16880Sstevel@tonic-gate 	if (write(sfd, buf, bufsz) == -1)
16890Sstevel@tonic-gate 		abend("Error writing cts/syscts to tmpfile", NULL);
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	free(buf);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate /*
16950Sstevel@tonic-gate  * The following reads entries from the tempfile back to the parent
16960Sstevel@tonic-gate  * so that information can be collected and summed for overall statistics.
16970Sstevel@tonic-gate  * This reads records out of the tempfile.  If they are hash table entries,
16980Sstevel@tonic-gate  * the record is merged with the hash table kept by the parent process.
16990Sstevel@tonic-gate  * If the information is a struct count/struct syscount pair, they are
17000Sstevel@tonic-gate  * copied and added into the count/syscount array kept by the parent.
17010Sstevel@tonic-gate  */
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate void
file_to_parent()17040Sstevel@tonic-gate file_to_parent()
17050Sstevel@tonic-gate {
17060Sstevel@tonic-gate 	hdntry_t ntry;
17070Sstevel@tonic-gate 	char *s = NULL;
17080Sstevel@tonic-gate 	char *t = NULL;
17090Sstevel@tonic-gate 	size_t c_offset = 0;
17100Sstevel@tonic-gate 	size_t filesz;
17110Sstevel@tonic-gate 	size_t t_strsz = 0;
17120Sstevel@tonic-gate 	size_t s_strsz = 0;
17130Sstevel@tonic-gate 	struct stat fsi;
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	if (descendent)
17160Sstevel@tonic-gate 		return;
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate 	if (fstat(sfd, &fsi) == -1)
17190Sstevel@tonic-gate 		abend("Error stat-ing tempfile", NULL);
17200Sstevel@tonic-gate 	filesz = fsi.st_size;
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	while (c_offset < filesz) {
17230Sstevel@tonic-gate 		/* first get hdntry */
17240Sstevel@tonic-gate 		if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
17250Sstevel@tonic-gate 		    sizeof (hdntry_t))
17260Sstevel@tonic-gate 			abend("Unable to perform full read of hdntry", NULL);
17270Sstevel@tonic-gate 		c_offset += sizeof (hdntry_t);
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 		switch (ntry.type) {
17300Sstevel@tonic-gate 		case HD_hashntry:
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 			/* first get lib string */
17330Sstevel@tonic-gate 			if (ntry.sz_lib > t_strsz) {
17340Sstevel@tonic-gate 				t = my_realloc(t, ntry.sz_lib, NULL);
17350Sstevel@tonic-gate 				t_strsz = ntry.sz_lib;
17360Sstevel@tonic-gate 			}
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 			(void) memset(t, 0, t_strsz);
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 			/* now actually get the string */
17410Sstevel@tonic-gate 			if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
17420Sstevel@tonic-gate 				abend("Unable to perform full read of lib str",
17430Sstevel@tonic-gate 				    NULL);
17440Sstevel@tonic-gate 			c_offset += ntry.sz_lib;
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 			/* now get key string */
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 			if (ntry.sz_key > s_strsz) {
17490Sstevel@tonic-gate 				s = my_realloc(s, ntry.sz_key, NULL);
17500Sstevel@tonic-gate 				s_strsz = ntry.sz_key;
17510Sstevel@tonic-gate 			}
17520Sstevel@tonic-gate 			(void) memset(s, 0, s_strsz);
17530Sstevel@tonic-gate 			if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
17540Sstevel@tonic-gate 				abend("Unable to perform full read of key str",
17550Sstevel@tonic-gate 				    NULL);
17560Sstevel@tonic-gate 			c_offset += ntry.sz_key;
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 			add_fcall(fcall_tbl, t, s, ntry.count);
17590Sstevel@tonic-gate 			break;
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 		case HD_cts_syscts:
17620Sstevel@tonic-gate 		{
17630Sstevel@tonic-gate 			struct counts *ncp;
17640Sstevel@tonic-gate 			size_t bfsz = sizeof (struct counts) + maxsyscalls()
17650Sstevel@tonic-gate 			    * sizeof (struct syscount);
17660Sstevel@tonic-gate 			int i;
17670Sstevel@tonic-gate 			struct syscount *sscp;
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 			if (ntry.sz_key != bfsz)
17700Sstevel@tonic-gate 				abend("cts/syscts size does not sanity check",
17710Sstevel@tonic-gate 				    NULL);
17720Sstevel@tonic-gate 			ncp = my_malloc(ntry.sz_key, NULL);
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 			if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
17750Sstevel@tonic-gate 			    ntry.sz_key)
17760Sstevel@tonic-gate 				abend("Unable to perform full read of cts",
17770Sstevel@tonic-gate 				    NULL);
17780Sstevel@tonic-gate 			c_offset += ntry.sz_key;
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 			sscp = (struct syscount *)(ncp + 1);
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 			(void) mutex_lock(&count_lock);
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 			Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
17850Sstevel@tonic-gate 			Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
17860Sstevel@tonic-gate 			if (Cp->usrtotal.tv_nsec >= NANOSEC) {
17870Sstevel@tonic-gate 				Cp->usrtotal.tv_nsec -= NANOSEC;
17880Sstevel@tonic-gate 				Cp->usrtotal.tv_sec++;
17890Sstevel@tonic-gate 			}
17900Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSYS; i++) {
17910Sstevel@tonic-gate 				ncp->syscount[i] = sscp;
17920Sstevel@tonic-gate 				sscp += nsubcodes(i);
17930Sstevel@tonic-gate 			}
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 			for (i = 0; i <= PRMAXFAULT; i++) {
17960Sstevel@tonic-gate 				Cp->fltcount[i] += ncp->fltcount[i];
17970Sstevel@tonic-gate 			}
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSIG; i++) {
18000Sstevel@tonic-gate 				Cp->sigcount[i] += ncp->sigcount[i];
18010Sstevel@tonic-gate 			}
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSYS; i++) {
18040Sstevel@tonic-gate 				struct syscount *scp = Cp->syscount[i];
18050Sstevel@tonic-gate 				struct syscount *nscp = ncp->syscount[i];
18060Sstevel@tonic-gate 				int n = nsubcodes(i);
18070Sstevel@tonic-gate 				int subcode;
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 				for (subcode = 0; subcode < n; subcode++,
18100Sstevel@tonic-gate 				    scp++, nscp++) {
18110Sstevel@tonic-gate 					scp->count += nscp->count;
18120Sstevel@tonic-gate 					scp->error += nscp->error;
18130Sstevel@tonic-gate 					scp->stime.tv_sec += nscp->stime.tv_sec;
18140Sstevel@tonic-gate 					scp->stime.tv_nsec +=
18150Sstevel@tonic-gate 					    nscp->stime.tv_nsec;
18160Sstevel@tonic-gate 					if (scp->stime.tv_nsec >= NANOSEC) {
18170Sstevel@tonic-gate 						scp->stime.tv_nsec -= NANOSEC;
18180Sstevel@tonic-gate 						scp->stime.tv_sec++;
18190Sstevel@tonic-gate 					}
18200Sstevel@tonic-gate 				}
18210Sstevel@tonic-gate 			}
18220Sstevel@tonic-gate 			(void) mutex_unlock(&count_lock);
18230Sstevel@tonic-gate 			free(ncp);
18240Sstevel@tonic-gate 			break;
18250Sstevel@tonic-gate 		}
18260Sstevel@tonic-gate 		default:
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 			abend("Unknown file entry type encountered", NULL);
18290Sstevel@tonic-gate 			break;
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 		}
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 		if (fstat(sfd, &fsi) == -1)
18340Sstevel@tonic-gate 			abend("Error stat-ing tempfile", NULL);
18350Sstevel@tonic-gate 		filesz = fsi.st_size;
18360Sstevel@tonic-gate 	}
18370Sstevel@tonic-gate 	if (s != NULL)
18380Sstevel@tonic-gate 		free(s);
18390Sstevel@tonic-gate 	if (t != NULL)
18400Sstevel@tonic-gate 		free(t);
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate void
make_pname(private_t * pri,id_t tid)18440Sstevel@tonic-gate make_pname(private_t *pri, id_t tid)
18450Sstevel@tonic-gate {
18460Sstevel@tonic-gate 	if (!cflag) {
18470Sstevel@tonic-gate 		int ff = (fflag || ngrab > 1);
18480Sstevel@tonic-gate 		int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
18490Sstevel@tonic-gate 		pid_t pid = Pstatus(Proc)->pr_pid;
18500Sstevel@tonic-gate 		id_t lwpid = pri->lwpstat->pr_lwpid;
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 		if (ff != pri->pparam.ff ||
18530Sstevel@tonic-gate 		    lf != pri->pparam.lf ||
18540Sstevel@tonic-gate 		    pid != pri->pparam.pid ||
18550Sstevel@tonic-gate 		    lwpid != pri->pparam.lwpid ||
18560Sstevel@tonic-gate 		    tid != pri->pparam.tid) {
18570Sstevel@tonic-gate 			char *s = pri->pname;
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 			if (ff)
18600Sstevel@tonic-gate 				s += sprintf(s, "%d", (int)pid);
18610Sstevel@tonic-gate 			if (lf)
18620Sstevel@tonic-gate 				s += sprintf(s, "/%d", (int)lwpid);
18630Sstevel@tonic-gate 			if (tid)
18640Sstevel@tonic-gate 				s += sprintf(s, "@%d", (int)tid);
18650Sstevel@tonic-gate 			if (ff || lf)
18660Sstevel@tonic-gate 				*s++ = ':', *s++ = '\t';
18670Sstevel@tonic-gate 			if (ff && lf && s < pri->pname + 9)
18680Sstevel@tonic-gate 				*s++ = '\t';
18690Sstevel@tonic-gate 			*s = '\0';
18700Sstevel@tonic-gate 			pri->pparam.ff = ff;
18710Sstevel@tonic-gate 			pri->pparam.lf = lf;
18720Sstevel@tonic-gate 			pri->pparam.pid = pid;
18730Sstevel@tonic-gate 			pri->pparam.lwpid = lwpid;
18740Sstevel@tonic-gate 			pri->pparam.tid = tid;
18750Sstevel@tonic-gate 		}
18760Sstevel@tonic-gate 	}
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate /*
18800Sstevel@tonic-gate  * Print the pri->pname[] string, if any.
18810Sstevel@tonic-gate  */
18820Sstevel@tonic-gate void
putpname(private_t * pri)18830Sstevel@tonic-gate putpname(private_t *pri)
18840Sstevel@tonic-gate {
18850Sstevel@tonic-gate 	if (pri->pname[0])
18860Sstevel@tonic-gate 		(void) fputs(pri->pname, stdout);
18870Sstevel@tonic-gate }
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate /*
18900Sstevel@tonic-gate  * Print the timestamp, if requested (-d, -D, or -E).
18910Sstevel@tonic-gate  */
18920Sstevel@tonic-gate void
timestamp(private_t * pri)18930Sstevel@tonic-gate timestamp(private_t *pri)
18940Sstevel@tonic-gate {
18950Sstevel@tonic-gate 	const lwpstatus_t *Lsp = pri->lwpstat;
18960Sstevel@tonic-gate 	int seconds;
18970Sstevel@tonic-gate 	int fraction;
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
19000Sstevel@tonic-gate 		return;
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
19030Sstevel@tonic-gate 	fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
19040Sstevel@tonic-gate 	if (fraction < 0) {
19050Sstevel@tonic-gate 		seconds--;
19060Sstevel@tonic-gate 		fraction += NANOSEC;
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 	/* fraction in 1/10 milliseconds, rounded up */
19090Sstevel@tonic-gate 	fraction = (fraction + 50000) / 100000;
19100Sstevel@tonic-gate 	if (fraction >= (MILLISEC * 10)) {
19110Sstevel@tonic-gate 		seconds++;
19120Sstevel@tonic-gate 		fraction -= (MILLISEC * 10);
19130Sstevel@tonic-gate 	}
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	if (dflag)		/* time stamp */
19160Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	if (Dflag) {		/* time delta */
19190Sstevel@tonic-gate 		int oseconds = pri->seconds;
19200Sstevel@tonic-gate 		int ofraction = pri->fraction;
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 		pri->seconds = seconds;
19230Sstevel@tonic-gate 		pri->fraction = fraction;
19240Sstevel@tonic-gate 		seconds -= oseconds;
19250Sstevel@tonic-gate 		fraction -= ofraction;
19260Sstevel@tonic-gate 		if (fraction < 0) {
19270Sstevel@tonic-gate 			seconds--;
19280Sstevel@tonic-gate 			fraction += (MILLISEC * 10);
19290Sstevel@tonic-gate 		}
19300Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
19310Sstevel@tonic-gate 	}
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	if (Eflag) {
19340Sstevel@tonic-gate 		seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
19350Sstevel@tonic-gate 		fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 		if (fraction < 0) {
19380Sstevel@tonic-gate 			seconds--;
19390Sstevel@tonic-gate 			fraction += NANOSEC;
19400Sstevel@tonic-gate 		}
19410Sstevel@tonic-gate 		/* fraction in 1/10 milliseconds, rounded up */
19420Sstevel@tonic-gate 		fraction = (fraction + 50000) / 100000;
19430Sstevel@tonic-gate 		if (fraction >= (MILLISEC * 10)) {
19440Sstevel@tonic-gate 			seconds++;
19450Sstevel@tonic-gate 			fraction -= (MILLISEC * 10);
19460Sstevel@tonic-gate 		}
19470Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
19480Sstevel@tonic-gate 	}
19490Sstevel@tonic-gate }
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate /*
19520Sstevel@tonic-gate  * Create output file, being careful about
19530Sstevel@tonic-gate  * suid/sgid and file descriptor 0, 1, 2 issues.
19540Sstevel@tonic-gate  */
19550Sstevel@tonic-gate int
xcreat(char * path)19560Sstevel@tonic-gate xcreat(char *path)
19570Sstevel@tonic-gate {
19580Sstevel@tonic-gate 	int fd;
19590Sstevel@tonic-gate 	int mode = 0666;
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	if (Euid == Ruid && Egid == Rgid)	/* not set-id */
19620Sstevel@tonic-gate 		fd = creat(path, mode);
19630Sstevel@tonic-gate 	else if (access(path, F_OK) != 0) {	/* file doesn't exist */
19640Sstevel@tonic-gate 		/* if directory permissions OK, create file & set ownership */
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 		char *dir;
19670Sstevel@tonic-gate 		char *p;
19680Sstevel@tonic-gate 		char dot[4];
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 		/* generate path for directory containing file */
19710Sstevel@tonic-gate 		if ((p = strrchr(path, '/')) == NULL) {	/* no '/' */
19720Sstevel@tonic-gate 			p = dir = dot;
19730Sstevel@tonic-gate 			*p++ = '.';		/* current directory */
19740Sstevel@tonic-gate 			*p = '\0';
19750Sstevel@tonic-gate 		} else if (p == path) {			/* leading '/' */
19760Sstevel@tonic-gate 			p = dir = dot;
19770Sstevel@tonic-gate 			*p++ = '/';		/* root directory */
19780Sstevel@tonic-gate 			*p = '\0';
19790Sstevel@tonic-gate 		} else {				/* embedded '/' */
19800Sstevel@tonic-gate 			dir = path;		/* directory path */
19810Sstevel@tonic-gate 			*p = '\0';
19820Sstevel@tonic-gate 		}
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate 		if (access(dir, W_OK|X_OK) != 0) {
19850Sstevel@tonic-gate 			/* not writeable/searchable */
19860Sstevel@tonic-gate 			*p = '/';
19870Sstevel@tonic-gate 			fd = -1;
19880Sstevel@tonic-gate 		} else {	/* create file and set ownership correctly */
19890Sstevel@tonic-gate 			*p = '/';
19900Sstevel@tonic-gate 			if ((fd = creat(path, mode)) >= 0)
19910Sstevel@tonic-gate 				(void) chown(path, (int)Ruid, (int)Rgid);
19920Sstevel@tonic-gate 		}
19930Sstevel@tonic-gate 	} else if (access(path, W_OK) != 0)	/* file not writeable */
19940Sstevel@tonic-gate 		fd = -1;
19950Sstevel@tonic-gate 	else
19960Sstevel@tonic-gate 		fd = creat(path, mode);
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 	/*
19990Sstevel@tonic-gate 	 * Make sure it's not one of 0, 1, or 2.
20000Sstevel@tonic-gate 	 * This allows truss to work when spawned by init(1m).
20010Sstevel@tonic-gate 	 */
20020Sstevel@tonic-gate 	if (0 <= fd && fd <= 2) {
20030Sstevel@tonic-gate 		int dfd = fcntl(fd, F_DUPFD, 3);
20040Sstevel@tonic-gate 		(void) close(fd);
20050Sstevel@tonic-gate 		fd = dfd;
20060Sstevel@tonic-gate 	}
20070Sstevel@tonic-gate 
20080Sstevel@tonic-gate 	/*
20090Sstevel@tonic-gate 	 * Mark it close-on-exec so created processes don't inherit it.
20100Sstevel@tonic-gate 	 */
20110Sstevel@tonic-gate 	if (fd >= 0)
20120Sstevel@tonic-gate 		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	return (fd);
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate void
setoutput(int ofd)20180Sstevel@tonic-gate setoutput(int ofd)
20190Sstevel@tonic-gate {
20200Sstevel@tonic-gate 	if (ofd < 0) {
20210Sstevel@tonic-gate 		(void) close(1);
20220Sstevel@tonic-gate 		(void) fcntl(2, F_DUPFD, 1);
20230Sstevel@tonic-gate 	} else if (ofd != 1) {
20240Sstevel@tonic-gate 		(void) close(1);
20250Sstevel@tonic-gate 		(void) fcntl(ofd, F_DUPFD, 1);
20260Sstevel@tonic-gate 		(void) close(ofd);
20270Sstevel@tonic-gate 		/* if no stderr, make it the same file */
20280Sstevel@tonic-gate 		if ((ofd = dup(2)) < 0)
20290Sstevel@tonic-gate 			(void) fcntl(1, F_DUPFD, 2);
20300Sstevel@tonic-gate 		else
20310Sstevel@tonic-gate 			(void) close(ofd);
20320Sstevel@tonic-gate 	}
20330Sstevel@tonic-gate }
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate /*
20360Sstevel@tonic-gate  * Accumulate time differencies:  a += e - s;
20370Sstevel@tonic-gate  */
20380Sstevel@tonic-gate void
accumulate(timestruc_t * ap,const timestruc_t * ep,const timestruc_t * sp)20390Sstevel@tonic-gate accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
20400Sstevel@tonic-gate {
20410Sstevel@tonic-gate 	ap->tv_sec += ep->tv_sec - sp->tv_sec;
20420Sstevel@tonic-gate 	ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
20430Sstevel@tonic-gate 	if (ap->tv_nsec >= NANOSEC) {
20440Sstevel@tonic-gate 		ap->tv_nsec -= NANOSEC;
20450Sstevel@tonic-gate 		ap->tv_sec++;
20460Sstevel@tonic-gate 	} else if (ap->tv_nsec < 0) {
20470Sstevel@tonic-gate 		ap->tv_nsec += NANOSEC;
20480Sstevel@tonic-gate 		ap->tv_sec--;
20490Sstevel@tonic-gate 	}
20500Sstevel@tonic-gate }
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate int
lib_sort(const void * p1,const void * p2)20530Sstevel@tonic-gate lib_sort(const void *p1, const void *p2)
20540Sstevel@tonic-gate {
20550Sstevel@tonic-gate 	int cmpr = 0;
20560Sstevel@tonic-gate 	long i;
20570Sstevel@tonic-gate 	long j;
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 	hentry_t *t1 = (hentry_t *)p1;
20600Sstevel@tonic-gate 	hentry_t *t2 = (hentry_t *)p2;
20610Sstevel@tonic-gate 
20620Sstevel@tonic-gate 	char *p = t1->lib;
20630Sstevel@tonic-gate 	char *q = t2->lib;
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	if ((cmpr = strcmp(p, q)) == 0) {
20660Sstevel@tonic-gate 		i = t1->count;
20670Sstevel@tonic-gate 		j = t2->count;
20680Sstevel@tonic-gate 		if (i > j)
20690Sstevel@tonic-gate 			return (-1);
20700Sstevel@tonic-gate 		else if (i < j)
20710Sstevel@tonic-gate 			return (1);
20720Sstevel@tonic-gate 		else {
20730Sstevel@tonic-gate 			p = t1->key;
20740Sstevel@tonic-gate 			q = t2->key;
20750Sstevel@tonic-gate 			return (strcmp(p, q));
20760Sstevel@tonic-gate 		}
20770Sstevel@tonic-gate 	} else
20780Sstevel@tonic-gate 		return (cmpr);
20790Sstevel@tonic-gate }
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate void
report(private_t * pri,time_t lapse)20820Sstevel@tonic-gate report(private_t *pri, time_t lapse)	/* elapsed time, clock ticks */
20830Sstevel@tonic-gate {
20840Sstevel@tonic-gate 	int i;
20850Sstevel@tonic-gate 	long count;
20860Sstevel@tonic-gate 	const char *name;
20870Sstevel@tonic-gate 	long error;
20880Sstevel@tonic-gate 	long total;
20890Sstevel@tonic-gate 	long errtot;
20900Sstevel@tonic-gate 	timestruc_t tickzero;
20910Sstevel@tonic-gate 	timestruc_t ticks;
20920Sstevel@tonic-gate 	timestruc_t ticktot;
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	if (descendent)
20950Sstevel@tonic-gate 		return;
20960Sstevel@tonic-gate 
20970Sstevel@tonic-gate 	for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
20980Sstevel@tonic-gate 		if ((count = Cp->fltcount[i]) != 0) {
20990Sstevel@tonic-gate 			if (total == 0)		/* produce header */
21000Sstevel@tonic-gate 				(void) printf("faults -------------\n");
21010Sstevel@tonic-gate 
21020Sstevel@tonic-gate 			name = proc_fltname(i, pri->flt_name,
210311798SRoger.Faulkner@Sun.COM 			    sizeof (pri->flt_name));
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 			(void) printf("%s%s\t%4ld\n", name,
210611798SRoger.Faulkner@Sun.COM 			    (((int)strlen(name) < 8)?
210711798SRoger.Faulkner@Sun.COM 			    (const char *)"\t" : (const char *)""),
210811798SRoger.Faulkner@Sun.COM 			    count);
21090Sstevel@tonic-gate 			total += count;
21100Sstevel@tonic-gate 		}
21110Sstevel@tonic-gate 	}
21120Sstevel@tonic-gate 	if (total && !interrupt)
21130Sstevel@tonic-gate 		(void) printf("total:\t\t%4ld\n\n", total);
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
21160Sstevel@tonic-gate 		if ((count = Cp->sigcount[i]) != 0) {
21170Sstevel@tonic-gate 			if (total == 0)		/* produce header */
21180Sstevel@tonic-gate 				(void) printf("signals ------------\n");
21190Sstevel@tonic-gate 			name = signame(pri, i);
21200Sstevel@tonic-gate 			(void) printf("%s%s\t%4ld\n", name,
212111798SRoger.Faulkner@Sun.COM 			    (((int)strlen(name) < 8)?
212211798SRoger.Faulkner@Sun.COM 			    (const char *)"\t" : (const char *)""),
212311798SRoger.Faulkner@Sun.COM 			    count);
21240Sstevel@tonic-gate 			total += count;
21250Sstevel@tonic-gate 		}
21260Sstevel@tonic-gate 	}
21270Sstevel@tonic-gate 	if (total && !interrupt)
21280Sstevel@tonic-gate 		(void) printf("total:\t\t%4ld\n\n", total);
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	if ((Dynpat != NULL) && !interrupt) {
21310Sstevel@tonic-gate 		size_t elem = elements_in_table(fcall_tbl);
21320Sstevel@tonic-gate 		hiter_t *itr = iterate_hash(fcall_tbl);
21330Sstevel@tonic-gate 		hentry_t *tmp = iter_next(itr);
21340Sstevel@tonic-gate 		hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
21350Sstevel@tonic-gate 		i = 0;
21360Sstevel@tonic-gate 		while ((tmp != NULL) && (i < elem)) {
21370Sstevel@tonic-gate 			stbl[i].prev = tmp->prev;
21380Sstevel@tonic-gate 			stbl[i].next = tmp->next;
21390Sstevel@tonic-gate 			stbl[i].lib = tmp->lib;
21400Sstevel@tonic-gate 			stbl[i].key = tmp->key;
21410Sstevel@tonic-gate 			stbl[i].count = tmp->count;
21420Sstevel@tonic-gate 			tmp = iter_next(itr);
21430Sstevel@tonic-gate 			i++;
21440Sstevel@tonic-gate 		}
21450Sstevel@tonic-gate 		qsort((void *)stbl, elem, sizeof (hentry_t),
21460Sstevel@tonic-gate 		    lib_sort);
21470Sstevel@tonic-gate 		(void) printf(
214811798SRoger.Faulkner@Sun.COM 		    "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
21490Sstevel@tonic-gate 		for (i = 0; i < elem; i++) {
21500Sstevel@tonic-gate 			(void) printf("%-20s %-40s %ld\n", stbl[i].lib,
21510Sstevel@tonic-gate 			    stbl[i].key, stbl[i].count);
21520Sstevel@tonic-gate 		}
21530Sstevel@tonic-gate 		iter_free(itr);
21540Sstevel@tonic-gate 		free(stbl);
21550Sstevel@tonic-gate 		itr = NULL;
21560Sstevel@tonic-gate 	}
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	if (!interrupt)
21590Sstevel@tonic-gate 		(void) printf(
21600Sstevel@tonic-gate 		"\nsyscall               seconds   calls  errors\n");
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 	total = errtot = 0;
21630Sstevel@tonic-gate 	tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
21640Sstevel@tonic-gate 	tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
21650Sstevel@tonic-gate 	for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
21660Sstevel@tonic-gate 		struct syscount *scp = Cp->syscount[i];
21670Sstevel@tonic-gate 		int n = nsubcodes(i);
21680Sstevel@tonic-gate 		int subcode;
21690Sstevel@tonic-gate 
21700Sstevel@tonic-gate 		for (subcode = 0; subcode < n; subcode++, scp++) {
21710Sstevel@tonic-gate 			if ((count = scp->count) != 0 || scp->error) {
21720Sstevel@tonic-gate 				(void) printf("%-19.19s ",
217311798SRoger.Faulkner@Sun.COM 				    sysname(pri, i, subcode));
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 				ticks = scp->stime;
21760Sstevel@tonic-gate 				accumulate(&ticktot, &ticks, &tickzero);
21770Sstevel@tonic-gate 				prtim(&ticks);
21780Sstevel@tonic-gate 
21790Sstevel@tonic-gate 				(void) printf(" %7ld", count);
21800Sstevel@tonic-gate 				if ((error = scp->error) != 0)
21810Sstevel@tonic-gate 					(void) printf(" %7ld", error);
21820Sstevel@tonic-gate 				(void) fputc('\n', stdout);
21830Sstevel@tonic-gate 				total += count;
21840Sstevel@tonic-gate 				errtot += error;
21850Sstevel@tonic-gate 			}
21860Sstevel@tonic-gate 		}
21870Sstevel@tonic-gate 	}
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	if (!interrupt) {
21900Sstevel@tonic-gate 		(void) printf(
21910Sstevel@tonic-gate 		"                     --------  ------   ----\n");
21920Sstevel@tonic-gate 		(void) printf("sys totals:         ");
21930Sstevel@tonic-gate 		prtim(&ticktot);
21940Sstevel@tonic-gate 		(void) printf(" %7ld %6ld\n", total, errtot);
21950Sstevel@tonic-gate 	}
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 	if (!interrupt) {
21980Sstevel@tonic-gate 		(void) printf("usr time:           ");
21990Sstevel@tonic-gate 		prtim(&Cp->usrtotal);
22000Sstevel@tonic-gate 		(void) fputc('\n', stdout);
22010Sstevel@tonic-gate 	}
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	if (!interrupt) {
22040Sstevel@tonic-gate 		int hz = (int)sysconf(_SC_CLK_TCK);
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 		ticks.tv_sec = lapse / hz;
22070Sstevel@tonic-gate 		ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
22080Sstevel@tonic-gate 		(void) printf("elapsed:            ");
22090Sstevel@tonic-gate 		prtim(&ticks);
22100Sstevel@tonic-gate 		(void) fputc('\n', stdout);
22110Sstevel@tonic-gate 	}
22120Sstevel@tonic-gate }
22130Sstevel@tonic-gate 
22140Sstevel@tonic-gate void
prtim(timestruc_t * tp)22150Sstevel@tonic-gate prtim(timestruc_t *tp)
22160Sstevel@tonic-gate {
22170Sstevel@tonic-gate 	time_t sec;
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	if ((sec = tp->tv_sec) != 0)			/* whole seconds */
22200Sstevel@tonic-gate 		(void) printf("%5lu", sec);
22210Sstevel@tonic-gate 	else
22220Sstevel@tonic-gate 		(void) printf("     ");
22230Sstevel@tonic-gate 
22240Sstevel@tonic-gate 	(void) printf(".%3.3ld", tp->tv_nsec/1000000);	/* fraction */
22250Sstevel@tonic-gate }
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate /*
22280Sstevel@tonic-gate  * Gather process id's.
22290Sstevel@tonic-gate  * Return 0 on success, != 0 on failure.
22300Sstevel@tonic-gate  */
22310Sstevel@tonic-gate void
pids(char * arg,proc_set_t * grab)22320Sstevel@tonic-gate pids(char *arg, proc_set_t *grab)
22330Sstevel@tonic-gate {
22340Sstevel@tonic-gate 	pid_t pid = -1;
22350Sstevel@tonic-gate 	int i;
22360Sstevel@tonic-gate 	const char *lwps = NULL;
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 	if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
22390Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
22400Sstevel@tonic-gate 		    command, arg, Pgrab_error(i));
22410Sstevel@tonic-gate 		return;
22420Sstevel@tonic-gate 	}
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	for (i = 0; i < ngrab; i++)
22450Sstevel@tonic-gate 		if (grab[i].pid == pid)	/* duplicate */
22460Sstevel@tonic-gate 			break;
22470Sstevel@tonic-gate 
22480Sstevel@tonic-gate 	if (i == ngrab) {
22490Sstevel@tonic-gate 		grab[ngrab].pid = pid;
22500Sstevel@tonic-gate 		grab[ngrab].lwps = lwps;
22510Sstevel@tonic-gate 		ngrab++;
22520Sstevel@tonic-gate 	} else {
22530Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
22540Sstevel@tonic-gate 		    command, (int)pid);
22550Sstevel@tonic-gate 	}
22560Sstevel@tonic-gate }
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate /*
22590Sstevel@tonic-gate  * Report psargs string.
22600Sstevel@tonic-gate  */
22610Sstevel@tonic-gate void
psargs(private_t * pri)22620Sstevel@tonic-gate psargs(private_t *pri)
22630Sstevel@tonic-gate {
22640Sstevel@tonic-gate 	pid_t pid = Pstatus(Proc)->pr_pid;
22650Sstevel@tonic-gate 	psinfo_t psinfo;
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 	if (proc_get_psinfo(pid, &psinfo) == 0)
22680Sstevel@tonic-gate 		(void) printf("%spsargs: %.64s\n",
226911798SRoger.Faulkner@Sun.COM 		    pri->pname, psinfo.pr_psargs);
22700Sstevel@tonic-gate 	else {
22710Sstevel@tonic-gate 		perror("psargs()");
22720Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
227311798SRoger.Faulkner@Sun.COM 		    pri->pname, (int)pid);
22740Sstevel@tonic-gate 	}
22750Sstevel@tonic-gate }
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate char *
fetchstring(private_t * pri,long addr,int maxleng)22780Sstevel@tonic-gate fetchstring(private_t *pri, long addr, int maxleng)
22790Sstevel@tonic-gate {
22800Sstevel@tonic-gate 	int nbyte;
22810Sstevel@tonic-gate 	int leng = 0;
22820Sstevel@tonic-gate 	char string[41];
22830Sstevel@tonic-gate 
22840Sstevel@tonic-gate 	string[40] = '\0';
22850Sstevel@tonic-gate 	if (pri->str_bsize == 0)  /* initial allocation of string buffer */
22860Sstevel@tonic-gate 		pri->str_buffer =
228711798SRoger.Faulkner@Sun.COM 		    my_malloc(pri->str_bsize = 16, "string buffer");
22880Sstevel@tonic-gate 	*pri->str_buffer = '\0';
22890Sstevel@tonic-gate 
22900Sstevel@tonic-gate 	for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
22910Sstevel@tonic-gate 		if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
22920Sstevel@tonic-gate 			return (leng? pri->str_buffer : NULL);
22930Sstevel@tonic-gate 		if (nbyte > 0 &&
22940Sstevel@tonic-gate 		    (nbyte = strlen(string)) > 0) {
22950Sstevel@tonic-gate 			while (leng + nbyte >= pri->str_bsize)
22960Sstevel@tonic-gate 				pri->str_buffer =
229711798SRoger.Faulkner@Sun.COM 				    my_realloc(pri->str_buffer,
229811798SRoger.Faulkner@Sun.COM 				    pri->str_bsize *= 2, "string buffer");
22990Sstevel@tonic-gate 			(void) strcpy(pri->str_buffer+leng, string);
23000Sstevel@tonic-gate 			leng += nbyte;
23010Sstevel@tonic-gate 		}
23020Sstevel@tonic-gate 	}
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate 	if (leng > maxleng)
23050Sstevel@tonic-gate 		leng = maxleng;
23060Sstevel@tonic-gate 	pri->str_buffer[leng] = '\0';
23070Sstevel@tonic-gate 
23080Sstevel@tonic-gate 	return (pri->str_buffer);
23090Sstevel@tonic-gate }
23100Sstevel@tonic-gate 
2311*12273SCasper.Dik@Sun.COM static priv_set_t *
getset(prpriv_t * p,priv_ptype_t set)2312*12273SCasper.Dik@Sun.COM getset(prpriv_t *p, priv_ptype_t set)
2313*12273SCasper.Dik@Sun.COM {
2314*12273SCasper.Dik@Sun.COM 	return ((priv_set_t *)
2315*12273SCasper.Dik@Sun.COM 	    &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]);
2316*12273SCasper.Dik@Sun.COM }
2317*12273SCasper.Dik@Sun.COM 
23180Sstevel@tonic-gate void
show_cred(private_t * pri,int new,int loadonly)2319*12273SCasper.Dik@Sun.COM show_cred(private_t *pri, int new, int loadonly)
23200Sstevel@tonic-gate {
23210Sstevel@tonic-gate 	prcred_t cred;
2322*12273SCasper.Dik@Sun.COM 	prpriv_t *privs;
23230Sstevel@tonic-gate 
23240Sstevel@tonic-gate 	if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
2325*12273SCasper.Dik@Sun.COM 		perror("show_cred() - credential");
23260Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot get credentials\n", pri->pname);
23270Sstevel@tonic-gate 		return;
23280Sstevel@tonic-gate 	}
2329*12273SCasper.Dik@Sun.COM 	if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) {
2330*12273SCasper.Dik@Sun.COM 		perror("show_cred() - privileges");
2331*12273SCasper.Dik@Sun.COM 		(void) printf("%s\t*** Cannot get privileges\n", pri->pname);
2332*12273SCasper.Dik@Sun.COM 		return;
2333*12273SCasper.Dik@Sun.COM 	}
23340Sstevel@tonic-gate 
2335*12273SCasper.Dik@Sun.COM 	if (!loadonly && !cflag && prismember(&trace, SYS_execve)) {
23360Sstevel@tonic-gate 		if (new)
23370Sstevel@tonic-gate 			credentials = cred;
23380Sstevel@tonic-gate 		if ((new && cred.pr_ruid != cred.pr_suid) ||
23390Sstevel@tonic-gate 		    cred.pr_ruid != credentials.pr_ruid ||
23400Sstevel@tonic-gate 		    cred.pr_suid != credentials.pr_suid)
23410Sstevel@tonic-gate 			(void) printf(
23420Sstevel@tonic-gate 		"%s    *** SUID: ruid/euid/suid = %d / %d / %d  ***\n",
234311798SRoger.Faulkner@Sun.COM 			    pri->pname,
234411798SRoger.Faulkner@Sun.COM 			    (int)cred.pr_ruid,
234511798SRoger.Faulkner@Sun.COM 			    (int)cred.pr_euid,
234611798SRoger.Faulkner@Sun.COM 			    (int)cred.pr_suid);
23470Sstevel@tonic-gate 		if ((new && cred.pr_rgid != cred.pr_sgid) ||
23480Sstevel@tonic-gate 		    cred.pr_rgid != credentials.pr_rgid ||
23490Sstevel@tonic-gate 		    cred.pr_sgid != credentials.pr_sgid)
23500Sstevel@tonic-gate 			(void) printf(
23510Sstevel@tonic-gate 		"%s    *** SGID: rgid/egid/sgid = %d / %d / %d  ***\n",
235211798SRoger.Faulkner@Sun.COM 			    pri->pname,
235311798SRoger.Faulkner@Sun.COM 			    (int)cred.pr_rgid,
235411798SRoger.Faulkner@Sun.COM 			    (int)cred.pr_egid,
235511798SRoger.Faulkner@Sun.COM 			    (int)cred.pr_sgid);
2356*12273SCasper.Dik@Sun.COM 		if (privdata != NULL && cred.pr_euid != 0) {
2357*12273SCasper.Dik@Sun.COM 			priv_set_t *npset = getset(privs, PRIV_PERMITTED);
2358*12273SCasper.Dik@Sun.COM 			priv_set_t *opset = getset(privdata, PRIV_PERMITTED);
2359*12273SCasper.Dik@Sun.COM 			char *s, *t;
2360*12273SCasper.Dik@Sun.COM 			if (!priv_issubset(npset, opset)) {
2361*12273SCasper.Dik@Sun.COM 				/* Use the to be freed privdata as scratch */
2362*12273SCasper.Dik@Sun.COM 				priv_inverse(opset);
2363*12273SCasper.Dik@Sun.COM 				priv_intersect(npset, opset);
2364*12273SCasper.Dik@Sun.COM 				s = priv_set_to_str(opset, ',', PRIV_STR_SHORT);
2365*12273SCasper.Dik@Sun.COM 				t = priv_set_to_str(npset, ',', PRIV_STR_SHORT);
2366*12273SCasper.Dik@Sun.COM 				(void) printf("%s    *** FPRIV: P/E: %s ***\n",
2367*12273SCasper.Dik@Sun.COM 				    pri->pname,
2368*12273SCasper.Dik@Sun.COM 				    strlen(s) > strlen(t) ? t : s);
2369*12273SCasper.Dik@Sun.COM 				free(s);
2370*12273SCasper.Dik@Sun.COM 				free(t);
2371*12273SCasper.Dik@Sun.COM 			}
2372*12273SCasper.Dik@Sun.COM 		}
23730Sstevel@tonic-gate 	}
23740Sstevel@tonic-gate 
2375*12273SCasper.Dik@Sun.COM 	if (privdata != NULL)
2376*12273SCasper.Dik@Sun.COM 		free(privdata);
23770Sstevel@tonic-gate 	credentials = cred;
2378*12273SCasper.Dik@Sun.COM 	privdata = privs;
23790Sstevel@tonic-gate }
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate /*
23820Sstevel@tonic-gate  * Take control of a child process.
23830Sstevel@tonic-gate  * We come here with truss_lock held.
23840Sstevel@tonic-gate  */
23850Sstevel@tonic-gate int
control(private_t * pri,pid_t pid)23860Sstevel@tonic-gate control(private_t *pri, pid_t pid)
23870Sstevel@tonic-gate {
23880Sstevel@tonic-gate 	const pstatus_t *Psp;
23890Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
23900Sstevel@tonic-gate 	pid_t childpid = 0;
23910Sstevel@tonic-gate 	long flags;
23920Sstevel@tonic-gate 	int rc;
23930Sstevel@tonic-gate 
23940Sstevel@tonic-gate 	(void) mutex_lock(&gps->fork_lock);
23950Sstevel@tonic-gate 	while (gps->fork_pid != 0)
23960Sstevel@tonic-gate 		(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
23970Sstevel@tonic-gate 	gps->fork_pid = getpid();	/* parent pid */
23983235Sraf 	if ((childpid = fork()) == -1) {
23990Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot fork() to control process #%d\n",
240011798SRoger.Faulkner@Sun.COM 		    pri->pname, (int)pid);
24010Sstevel@tonic-gate 		Flush();
24020Sstevel@tonic-gate 		gps->fork_pid = 0;
24030Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
24040Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
24050Sstevel@tonic-gate 		release(pri, pid);
24060Sstevel@tonic-gate 		return (FALSE);
24070Sstevel@tonic-gate 	}
24080Sstevel@tonic-gate 
24090Sstevel@tonic-gate 	if (childpid != 0) {
24100Sstevel@tonic-gate 		/*
24110Sstevel@tonic-gate 		 * The parent carries on, after a brief pause.
24120Sstevel@tonic-gate 		 * The parent must wait until the child executes procadd(pid).
24130Sstevel@tonic-gate 		 */
24140Sstevel@tonic-gate 		while (gps->fork_pid != childpid)
24150Sstevel@tonic-gate 			(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
24160Sstevel@tonic-gate 		gps->fork_pid = 0;
24170Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
24180Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
24190Sstevel@tonic-gate 		return (FALSE);
24200Sstevel@tonic-gate 	}
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 	childpid = getpid();
24230Sstevel@tonic-gate 	descendent = TRUE;
24240Sstevel@tonic-gate 	exit_called = FALSE;
24250Sstevel@tonic-gate 	Pfree(Proc);	/* forget old process */
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate 	/*
24280Sstevel@tonic-gate 	 * The parent process owns the shared gps->fork_lock.
24290Sstevel@tonic-gate 	 * The child must grab it again.
24300Sstevel@tonic-gate 	 */
24310Sstevel@tonic-gate 	(void) mutex_lock(&gps->fork_lock);
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	/*
24340Sstevel@tonic-gate 	 * Child grabs the process and retains the tracing flags.
24350Sstevel@tonic-gate 	 */
24360Sstevel@tonic-gate 	if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
24370Sstevel@tonic-gate 		(void) fprintf(stderr,
243811798SRoger.Faulkner@Sun.COM 		    "%s: cannot control child process, pid# %d: %s\n",
243911798SRoger.Faulkner@Sun.COM 		    command, (int)pid, Pgrab_error(rc));
24400Sstevel@tonic-gate 		gps->fork_pid = childpid;
24410Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
24420Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
24430Sstevel@tonic-gate 		exit(2);
24440Sstevel@tonic-gate 	}
24450Sstevel@tonic-gate 
24460Sstevel@tonic-gate 	per_proc_init();
24470Sstevel@tonic-gate 	/*
24480Sstevel@tonic-gate 	 * Add ourself to the set of truss processes
24490Sstevel@tonic-gate 	 * and notify the parent to carry on.
24500Sstevel@tonic-gate 	 */
24510Sstevel@tonic-gate 	procadd(pid, NULL);
24520Sstevel@tonic-gate 	gps->fork_pid = childpid;
24530Sstevel@tonic-gate 	(void) cond_broadcast(&gps->fork_cv);
24540Sstevel@tonic-gate 	(void) mutex_unlock(&gps->fork_lock);
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	/*
24570Sstevel@tonic-gate 	 * We may have grabbed the child before it is fully stopped on exit
24580Sstevel@tonic-gate 	 * from fork.  Wait one second (at most) for it to settle down.
24590Sstevel@tonic-gate 	 */
24600Sstevel@tonic-gate 	(void) Pwait(Proc, MILLISEC);
24610Sstevel@tonic-gate 	if (Rdb_agent != NULL)
24620Sstevel@tonic-gate 		Rdb_agent = Prd_agent(Proc);
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	Psp = Pstatus(Proc);
24650Sstevel@tonic-gate 	Lsp = &Psp->pr_lwp;
24660Sstevel@tonic-gate 	pri->lwpstat = Lsp;
24670Sstevel@tonic-gate 	data_model = Psp->pr_dmodel;
24680Sstevel@tonic-gate 
24690Sstevel@tonic-gate 	make_pname(pri, 0);
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	pri->syslast = Psp->pr_stime;
24720Sstevel@tonic-gate 	pri->usrlast = Psp->pr_utime;
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 	flags = PR_FORK | PR_ASYNC;
24750Sstevel@tonic-gate 	if (Dynpat != NULL)
24760Sstevel@tonic-gate 		flags |= PR_BPTADJ;	/* needed for x86 */
24770Sstevel@tonic-gate 	(void) Psetflags(Proc, flags);
24780Sstevel@tonic-gate 
24790Sstevel@tonic-gate 	return (TRUE);
24800Sstevel@tonic-gate }
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate /*
24830Sstevel@tonic-gate  * Take control of an existing process.
24840Sstevel@tonic-gate  */
24850Sstevel@tonic-gate int
grabit(private_t * pri,proc_set_t * set)24860Sstevel@tonic-gate grabit(private_t *pri, proc_set_t *set)
24870Sstevel@tonic-gate {
24880Sstevel@tonic-gate 	const pstatus_t *Psp;
24890Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
24900Sstevel@tonic-gate 	int gcode;
24910Sstevel@tonic-gate 
24920Sstevel@tonic-gate 	/*
24930Sstevel@tonic-gate 	 * Don't force the takeover unless the -F option was specified.
24940Sstevel@tonic-gate 	 */
24950Sstevel@tonic-gate 	if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
24960Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: %d\n",
249711798SRoger.Faulkner@Sun.COM 		    command, Pgrab_error(gcode), (int)set->pid);
24980Sstevel@tonic-gate 		pri->lwpstat = NULL;
24990Sstevel@tonic-gate 		return (FALSE);
25000Sstevel@tonic-gate 	}
25010Sstevel@tonic-gate 	Psp = Pstatus(Proc);
25020Sstevel@tonic-gate 	Lsp = &Psp->pr_lwp;
25030Sstevel@tonic-gate 	pri->lwpstat = Lsp;
25040Sstevel@tonic-gate 
25050Sstevel@tonic-gate 	make_pname(pri, 0);
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	data_model = Psp->pr_dmodel;
25080Sstevel@tonic-gate 	pri->syslast = Psp->pr_stime;
25090Sstevel@tonic-gate 	pri->usrlast = Psp->pr_utime;
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	if (fflag || Dynpat != NULL)
25120Sstevel@tonic-gate 		(void) Psetflags(Proc, PR_FORK);
25130Sstevel@tonic-gate 	else
25140Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_FORK);
25150Sstevel@tonic-gate 	procadd(set->pid, set->lwps);
2516*12273SCasper.Dik@Sun.COM 	show_cred(pri, TRUE, FALSE);
25170Sstevel@tonic-gate 	return (TRUE);
25180Sstevel@tonic-gate }
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate /*
25210Sstevel@tonic-gate  * Release process from control.
25220Sstevel@tonic-gate  */
25230Sstevel@tonic-gate void
release(private_t * pri,pid_t pid)25240Sstevel@tonic-gate release(private_t *pri, pid_t pid)
25250Sstevel@tonic-gate {
25260Sstevel@tonic-gate 	/*
25270Sstevel@tonic-gate 	 * The process in question is the child of a traced process.
25280Sstevel@tonic-gate 	 * We are here to turn off the inherited tracing flags.
25290Sstevel@tonic-gate 	 */
25300Sstevel@tonic-gate 	int fd;
25310Sstevel@tonic-gate 	char ctlname[100];
25320Sstevel@tonic-gate 	long ctl[2];
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 	ctl[0] = PCSET;
25350Sstevel@tonic-gate 	ctl[1] = PR_RLC;
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 	/* process is freshly forked, no need for exclusive open */
25380Sstevel@tonic-gate 	(void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
25390Sstevel@tonic-gate 	if ((fd = open(ctlname, O_WRONLY)) < 0 ||
25400Sstevel@tonic-gate 	    write(fd, (char *)ctl, sizeof (ctl)) < 0) {
25410Sstevel@tonic-gate 		perror("release()");
25420Sstevel@tonic-gate 		(void) printf(
254311798SRoger.Faulkner@Sun.COM 		    "%s\t*** Cannot release child process, pid# %d\n",
254411798SRoger.Faulkner@Sun.COM 		    pri->pname, (int)pid);
25450Sstevel@tonic-gate 		Flush();
25460Sstevel@tonic-gate 	}
25470Sstevel@tonic-gate 	if (fd >= 0)	/* run-on-last-close sets the process running */
25480Sstevel@tonic-gate 		(void) close(fd);
25490Sstevel@tonic-gate }
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate void
intr(int sig)25520Sstevel@tonic-gate intr(int sig)
25530Sstevel@tonic-gate {
25540Sstevel@tonic-gate 	/*
25550Sstevel@tonic-gate 	 * SIGUSR1 is special.  It is used by one truss process to tell
25560Sstevel@tonic-gate 	 * another truss process to release its controlled process.
25570Sstevel@tonic-gate 	 * SIGUSR2 is also special.  It is used to wake up threads waiting
25580Sstevel@tonic-gate 	 * for a victim lwp to stop after an event that will leave the
25590Sstevel@tonic-gate 	 * process hung (stopped and abandoned) has occurred.
25600Sstevel@tonic-gate 	 */
25610Sstevel@tonic-gate 	if (sig == SIGUSR1) {
25620Sstevel@tonic-gate 		sigusr1 = TRUE;
25630Sstevel@tonic-gate 	} else if (sig == SIGUSR2) {
25640Sstevel@tonic-gate 		void *value;
25650Sstevel@tonic-gate 		private_t *pri;
25660Sstevel@tonic-gate 		struct ps_lwphandle *Lwp;
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 		if (thr_getspecific(private_key, &value) == 0 &&
25690Sstevel@tonic-gate 		    (pri = value) != NULL &&
25700Sstevel@tonic-gate 		    (Lwp = pri->Lwp) != NULL)
25710Sstevel@tonic-gate 			(void) Lstop(Lwp, MILLISEC / 10);
25720Sstevel@tonic-gate 	} else {
25730Sstevel@tonic-gate 		interrupt = sig;
25740Sstevel@tonic-gate 	}
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate void
errmsg(const char * s,const char * q)25780Sstevel@tonic-gate errmsg(const char *s, const char *q)
25790Sstevel@tonic-gate {
25800Sstevel@tonic-gate 	char msg[512];
25810Sstevel@tonic-gate 
25820Sstevel@tonic-gate 	if (s || q) {
25830Sstevel@tonic-gate 		msg[0] = '\0';
25840Sstevel@tonic-gate 		if (command) {
25850Sstevel@tonic-gate 			(void) strcpy(msg, command);
25860Sstevel@tonic-gate 			(void) strcat(msg, ": ");
25870Sstevel@tonic-gate 		}
25880Sstevel@tonic-gate 		if (s)
25890Sstevel@tonic-gate 			(void) strcat(msg, s);
25900Sstevel@tonic-gate 		if (q)
25910Sstevel@tonic-gate 			(void) strcat(msg, q);
25920Sstevel@tonic-gate 		(void) strcat(msg, "\n");
25930Sstevel@tonic-gate 		(void) write(2, msg, (size_t)strlen(msg));
25940Sstevel@tonic-gate 	}
25950Sstevel@tonic-gate }
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate void
abend(const char * s,const char * q)25980Sstevel@tonic-gate abend(const char *s, const char *q)
25990Sstevel@tonic-gate {
26001132Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
26010Sstevel@tonic-gate 	if (Proc) {
26020Sstevel@tonic-gate 		Flush();
26030Sstevel@tonic-gate 		errmsg(s, q);
26040Sstevel@tonic-gate 		clear_breakpoints();
26050Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_ASYNC);
26060Sstevel@tonic-gate 		Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
26070Sstevel@tonic-gate 		procdel();
26080Sstevel@tonic-gate 		(void) wait4all();
26090Sstevel@tonic-gate 	} else {
26100Sstevel@tonic-gate 		errmsg(s, q);
26110Sstevel@tonic-gate 	}
26120Sstevel@tonic-gate 	exit(2);
26130Sstevel@tonic-gate }
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate /*
26160Sstevel@tonic-gate  * Allocate memory.
26170Sstevel@tonic-gate  * If allocation fails then print a message and abort.
26180Sstevel@tonic-gate  */
26190Sstevel@tonic-gate void *
my_realloc(void * buf,size_t size,const char * msg)26200Sstevel@tonic-gate my_realloc(void *buf, size_t size, const char *msg)
26210Sstevel@tonic-gate {
26220Sstevel@tonic-gate 	if ((buf = realloc(buf, size)) == NULL) {
26230Sstevel@tonic-gate 		if (msg != NULL)
26240Sstevel@tonic-gate 			abend("cannot allocate ", msg);
26250Sstevel@tonic-gate 		else
26260Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
26270Sstevel@tonic-gate 	}
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate 	return (buf);
26300Sstevel@tonic-gate }
26310Sstevel@tonic-gate 
26320Sstevel@tonic-gate void *
my_calloc(size_t nelem,size_t elsize,const char * msg)26330Sstevel@tonic-gate my_calloc(size_t nelem, size_t elsize, const char *msg)
26340Sstevel@tonic-gate {
26350Sstevel@tonic-gate 	void *buf = NULL;
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	if ((buf = calloc(nelem, elsize)) == NULL) {
26380Sstevel@tonic-gate 		if (msg != NULL)
26390Sstevel@tonic-gate 			abend("cannot allocate ", msg);
26400Sstevel@tonic-gate 		else
26410Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
26420Sstevel@tonic-gate 	}
26430Sstevel@tonic-gate 
26440Sstevel@tonic-gate 	return (buf);
26450Sstevel@tonic-gate }
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate void *
my_malloc(size_t size,const char * msg)26480Sstevel@tonic-gate my_malloc(size_t size, const char *msg)
26490Sstevel@tonic-gate {
26500Sstevel@tonic-gate 	return (my_realloc(NULL, size, msg));
26510Sstevel@tonic-gate }
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate int
wait4all()26540Sstevel@tonic-gate wait4all()
26550Sstevel@tonic-gate {
26560Sstevel@tonic-gate 	int i;
26570Sstevel@tonic-gate 	pid_t pid;
26580Sstevel@tonic-gate 	int rc = 0;
26590Sstevel@tonic-gate 	int status;
26600Sstevel@tonic-gate 
26610Sstevel@tonic-gate 	for (i = 0; i < 10; i++) {
26620Sstevel@tonic-gate 		while ((pid = wait(&status)) != -1) {
26630Sstevel@tonic-gate 			/* return exit() code of the created process */
26640Sstevel@tonic-gate 			if (pid == created) {
26650Sstevel@tonic-gate 				if (WIFEXITED(status))
26660Sstevel@tonic-gate 					rc = WEXITSTATUS(status);
26670Sstevel@tonic-gate 				else
26680Sstevel@tonic-gate 					rc |= 0x80; /* +128 to indicate sig */
26690Sstevel@tonic-gate 			}
26700Sstevel@tonic-gate 		}
26710Sstevel@tonic-gate 		if (errno != EINTR && errno != ERESTART)
26720Sstevel@tonic-gate 			break;
26730Sstevel@tonic-gate 	}
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate 	if (i >= 10)	/* repeated interrupts */
26760Sstevel@tonic-gate 		rc = 2;
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 	return (rc);
26790Sstevel@tonic-gate }
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate void
letgo(private_t * pri)26820Sstevel@tonic-gate letgo(private_t *pri)
26830Sstevel@tonic-gate {
26840Sstevel@tonic-gate 	(void) printf("%s\t*** process otherwise traced, releasing ...\n",
268511798SRoger.Faulkner@Sun.COM 	    pri->pname);
26860Sstevel@tonic-gate }
26870Sstevel@tonic-gate 
26880Sstevel@tonic-gate /*
26890Sstevel@tonic-gate  * Test for empty set.
26900Sstevel@tonic-gate  * support routine used by isemptyset() macro.
26910Sstevel@tonic-gate  */
26920Sstevel@tonic-gate int
is_empty(const uint32_t * sp,size_t n)26930Sstevel@tonic-gate is_empty(const uint32_t *sp,	/* pointer to set (array of int32's) */
26940Sstevel@tonic-gate 	size_t n)		/* number of int32's in set */
26950Sstevel@tonic-gate {
26960Sstevel@tonic-gate 	if (n) {
26970Sstevel@tonic-gate 		do {
26980Sstevel@tonic-gate 			if (*sp++)
26990Sstevel@tonic-gate 				return (FALSE);
27000Sstevel@tonic-gate 		} while (--n);
27010Sstevel@tonic-gate 	}
27020Sstevel@tonic-gate 
27030Sstevel@tonic-gate 	return (TRUE);
27040Sstevel@tonic-gate }
27050Sstevel@tonic-gate 
27060Sstevel@tonic-gate /*
27070Sstevel@tonic-gate  * OR the second set into the first.
27080Sstevel@tonic-gate  * The sets must be the same size.
27090Sstevel@tonic-gate  */
27100Sstevel@tonic-gate void
or_set(uint32_t * sp1,const uint32_t * sp2,size_t n)27110Sstevel@tonic-gate or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
27120Sstevel@tonic-gate {
27130Sstevel@tonic-gate 	if (n) {
27140Sstevel@tonic-gate 		do {
27150Sstevel@tonic-gate 			*sp1++ |= *sp2++;
27160Sstevel@tonic-gate 		} while (--n);
27170Sstevel@tonic-gate 	}
27180Sstevel@tonic-gate }
2719