xref: /titanic_53/usr/src/cmd/truss/main.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
35*7c478bd9Sstevel@tonic-gate #include <ctype.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <memory.h>
38*7c478bd9Sstevel@tonic-gate #include <signal.h>
39*7c478bd9Sstevel@tonic-gate #include <wait.h>
40*7c478bd9Sstevel@tonic-gate #include <limits.h>
41*7c478bd9Sstevel@tonic-gate #include <errno.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/times.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/fstyp.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/fsid.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/resource.h>
50*7c478bd9Sstevel@tonic-gate #include <libproc.h>
51*7c478bd9Sstevel@tonic-gate #include "ramdata.h"
52*7c478bd9Sstevel@tonic-gate #include "proto.h"
53*7c478bd9Sstevel@tonic-gate #include "htbl.h"
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * The user can trace individual threads by using the 'pid/1,3-6,8-' syntax.
57*7c478bd9Sstevel@tonic-gate  * This structure keeps track of pid/lwp specifications.  If there are no LWPs
58*7c478bd9Sstevel@tonic-gate  * specified, then 'lwps' will be NULL.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate typedef struct proc_set {
61*7c478bd9Sstevel@tonic-gate 	pid_t		pid;
62*7c478bd9Sstevel@tonic-gate 	const char 	*lwps;
63*7c478bd9Sstevel@tonic-gate } proc_set_t;
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * Function prototypes for static routines in this file.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate void	setup_basetime(hrtime_t, struct timeval *);
69*7c478bd9Sstevel@tonic-gate int	xcreat(char *);
70*7c478bd9Sstevel@tonic-gate void	setoutput(int);
71*7c478bd9Sstevel@tonic-gate void	report(private_t *, time_t);
72*7c478bd9Sstevel@tonic-gate void	prtim(timestruc_t *);
73*7c478bd9Sstevel@tonic-gate void	pids(char *, proc_set_t *);
74*7c478bd9Sstevel@tonic-gate void	psargs(private_t *);
75*7c478bd9Sstevel@tonic-gate int	control(private_t *, pid_t);
76*7c478bd9Sstevel@tonic-gate int	grabit(private_t *, proc_set_t *);
77*7c478bd9Sstevel@tonic-gate void	release(private_t *, pid_t);
78*7c478bd9Sstevel@tonic-gate void	intr(int);
79*7c478bd9Sstevel@tonic-gate int	wait4all(void);
80*7c478bd9Sstevel@tonic-gate void	letgo(private_t *);
81*7c478bd9Sstevel@tonic-gate void	child_to_file();
82*7c478bd9Sstevel@tonic-gate void	file_to_parent();
83*7c478bd9Sstevel@tonic-gate void	per_proc_init();
84*7c478bd9Sstevel@tonic-gate int	lib_sort(const void *, const void *);
85*7c478bd9Sstevel@tonic-gate int	key_sort(const void *, const void *);
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate void	*worker_thread(void *);
88*7c478bd9Sstevel@tonic-gate void	main_thread(int);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /*
91*7c478bd9Sstevel@tonic-gate  * Test for empty set.
92*7c478bd9Sstevel@tonic-gate  * is_empty() should not be called directly.
93*7c478bd9Sstevel@tonic-gate  */
94*7c478bd9Sstevel@tonic-gate int	is_empty(const uint32_t *, size_t);
95*7c478bd9Sstevel@tonic-gate #define	isemptyset(sp) \
96*7c478bd9Sstevel@tonic-gate 	is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t))
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /*
99*7c478bd9Sstevel@tonic-gate  * OR the second set into the first set.
100*7c478bd9Sstevel@tonic-gate  * or_set() should not be called directly.
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate void	or_set(uint32_t *, const uint32_t *, size_t);
103*7c478bd9Sstevel@tonic-gate #define	prorset(sp1, sp2) \
104*7c478bd9Sstevel@tonic-gate 	or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \
105*7c478bd9Sstevel@tonic-gate 	sizeof (*(sp1)) / sizeof (uint32_t))
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /* fetch or allocate thread-private data */
108*7c478bd9Sstevel@tonic-gate private_t *
109*7c478bd9Sstevel@tonic-gate get_private()
110*7c478bd9Sstevel@tonic-gate {
111*7c478bd9Sstevel@tonic-gate 	void *value;
112*7c478bd9Sstevel@tonic-gate 	private_t *pri = NULL;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	if (thr_getspecific(private_key, &value) == 0)
115*7c478bd9Sstevel@tonic-gate 		pri = value;
116*7c478bd9Sstevel@tonic-gate 	if (pri == NULL) {
117*7c478bd9Sstevel@tonic-gate 		pri = my_malloc(sizeof (*pri), NULL);
118*7c478bd9Sstevel@tonic-gate 		(void) memset(pri, 0, sizeof (*pri));
119*7c478bd9Sstevel@tonic-gate 		pri->sys_path = my_malloc(pri->sys_psize = 16, NULL);
120*7c478bd9Sstevel@tonic-gate 		pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL);
121*7c478bd9Sstevel@tonic-gate 		if (thr_setspecific(private_key, pri) == ENOMEM)
122*7c478bd9Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
123*7c478bd9Sstevel@tonic-gate 	}
124*7c478bd9Sstevel@tonic-gate 	return (pri);
125*7c478bd9Sstevel@tonic-gate }
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /* destructor function for thread-private data */
128*7c478bd9Sstevel@tonic-gate void
129*7c478bd9Sstevel@tonic-gate free_private(void *value)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	private_t *pri = value;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if (pri->sys_path)
134*7c478bd9Sstevel@tonic-gate 		free(pri->sys_path);
135*7c478bd9Sstevel@tonic-gate 	if (pri->sys_string)
136*7c478bd9Sstevel@tonic-gate 		free(pri->sys_string);
137*7c478bd9Sstevel@tonic-gate 	if (pri->exec_string)
138*7c478bd9Sstevel@tonic-gate 		free(pri->exec_string);
139*7c478bd9Sstevel@tonic-gate 	if (pri->str_buffer)
140*7c478bd9Sstevel@tonic-gate 		free(pri->str_buffer);
141*7c478bd9Sstevel@tonic-gate 	free(pri);
142*7c478bd9Sstevel@tonic-gate }
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate /*
145*7c478bd9Sstevel@tonic-gate  * This is called by the main thread (via create_thread())
146*7c478bd9Sstevel@tonic-gate  * and is also called from other threads in worker_thread()
147*7c478bd9Sstevel@tonic-gate  * while holding truss_lock.  No further locking is required.
148*7c478bd9Sstevel@tonic-gate  */
149*7c478bd9Sstevel@tonic-gate void
150*7c478bd9Sstevel@tonic-gate insert_lwpid(lwpid_t lwpid)
151*7c478bd9Sstevel@tonic-gate {
152*7c478bd9Sstevel@tonic-gate 	int i;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	truss_nlwp++;
155*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
156*7c478bd9Sstevel@tonic-gate 		if (truss_lwpid[i] == 0)
157*7c478bd9Sstevel@tonic-gate 			break;
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 	if (i == truss_maxlwp) {
160*7c478bd9Sstevel@tonic-gate 		/* double the size of the array */
161*7c478bd9Sstevel@tonic-gate 		truss_lwpid = my_realloc(truss_lwpid,
162*7c478bd9Sstevel@tonic-gate 			truss_maxlwp * 2 * sizeof (lwpid_t), NULL);
163*7c478bd9Sstevel@tonic-gate 		(void) memset(&truss_lwpid[truss_maxlwp], 0,
164*7c478bd9Sstevel@tonic-gate 			truss_maxlwp * sizeof (lwpid_t));
165*7c478bd9Sstevel@tonic-gate 		truss_maxlwp *= 2;
166*7c478bd9Sstevel@tonic-gate 	}
167*7c478bd9Sstevel@tonic-gate 	truss_lwpid[i] = lwpid;
168*7c478bd9Sstevel@tonic-gate }
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate /*
171*7c478bd9Sstevel@tonic-gate  * This is called from the main thread while holding truss_lock.
172*7c478bd9Sstevel@tonic-gate  */
173*7c478bd9Sstevel@tonic-gate void
174*7c478bd9Sstevel@tonic-gate delete_lwpid(lwpid_t lwpid)
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	static int int_notified = FALSE;
177*7c478bd9Sstevel@tonic-gate 	static int usr1_notified = FALSE;
178*7c478bd9Sstevel@tonic-gate 	static int usr2_notified = FALSE;
179*7c478bd9Sstevel@tonic-gate 	int i;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	if (--truss_nlwp <= 1)	/* notify controller of the exec()ing LWP */
182*7c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&truss_cv);
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
185*7c478bd9Sstevel@tonic-gate 		if (truss_lwpid[i] == lwpid) {
186*7c478bd9Sstevel@tonic-gate 			truss_lwpid[i] = 0;
187*7c478bd9Sstevel@tonic-gate 			break;
188*7c478bd9Sstevel@tonic-gate 		}
189*7c478bd9Sstevel@tonic-gate 	}
190*7c478bd9Sstevel@tonic-gate 	if (interrupt && !int_notified) {
191*7c478bd9Sstevel@tonic-gate 		int_notified = TRUE;
192*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
193*7c478bd9Sstevel@tonic-gate 			if (truss_lwpid[i] != 0)
194*7c478bd9Sstevel@tonic-gate 				(void) thr_kill(truss_lwpid[i], interrupt);
195*7c478bd9Sstevel@tonic-gate 		}
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate 	if (sigusr1 && !usr1_notified) {
198*7c478bd9Sstevel@tonic-gate 		usr1_notified = TRUE;
199*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
200*7c478bd9Sstevel@tonic-gate 			if (truss_lwpid[i] != 0)
201*7c478bd9Sstevel@tonic-gate 				(void) thr_kill(truss_lwpid[i], SIGUSR1);
202*7c478bd9Sstevel@tonic-gate 		}
203*7c478bd9Sstevel@tonic-gate 	}
204*7c478bd9Sstevel@tonic-gate 	if (leave_hung && !usr2_notified) {
205*7c478bd9Sstevel@tonic-gate 		usr2_notified = TRUE;
206*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
207*7c478bd9Sstevel@tonic-gate 			if (truss_lwpid[i] != 0)
208*7c478bd9Sstevel@tonic-gate 				(void) thr_kill(truss_lwpid[i], SIGUSR2);
209*7c478bd9Sstevel@tonic-gate 		}
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate static struct ps_lwphandle *
214*7c478bd9Sstevel@tonic-gate grab_lwp(lwpid_t who)
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *Lwp;
217*7c478bd9Sstevel@tonic-gate 	int gcode;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) {
220*7c478bd9Sstevel@tonic-gate 		if (gcode != G_NOPROC) {
221*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
222*7c478bd9Sstevel@tonic-gate 				"%s: cannot grab LWP %u in process %d,"
223*7c478bd9Sstevel@tonic-gate 				" reason: %s\n",
224*7c478bd9Sstevel@tonic-gate 				command, who, (int)Pstatus(Proc)->pr_pid,
225*7c478bd9Sstevel@tonic-gate 				Lgrab_error(gcode));
226*7c478bd9Sstevel@tonic-gate 			interrupt = SIGTERM;	/* post an interrupt */
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 	}
229*7c478bd9Sstevel@tonic-gate 	return (Lwp);
230*7c478bd9Sstevel@tonic-gate }
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate /*
233*7c478bd9Sstevel@tonic-gate  * Iteration function called for each initial lwp in the controlled process.
234*7c478bd9Sstevel@tonic-gate  */
235*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
236*7c478bd9Sstevel@tonic-gate int
237*7c478bd9Sstevel@tonic-gate create_thread(void *arg, const lwpstatus_t *Lsp)
238*7c478bd9Sstevel@tonic-gate {
239*7c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *new_Lwp;
240*7c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
241*7c478bd9Sstevel@tonic-gate 	int *count = arg;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid))
244*7c478bd9Sstevel@tonic-gate 		*count += 1;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) {
247*7c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, 0, worker_thread, new_Lwp,
248*7c478bd9Sstevel@tonic-gate 		    THR_BOUND | THR_SUSPENDED, &lwpid) != 0)
249*7c478bd9Sstevel@tonic-gate 			abend("cannot create lwp to follow child lwp", NULL);
250*7c478bd9Sstevel@tonic-gate 		insert_lwpid(lwpid);
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 	return (0);
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate int
256*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	private_t *pri;
259*7c478bd9Sstevel@tonic-gate 	struct tms tms;
260*7c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
261*7c478bd9Sstevel@tonic-gate 	int ofd = -1;
262*7c478bd9Sstevel@tonic-gate 	int opt;
263*7c478bd9Sstevel@tonic-gate 	int i;
264*7c478bd9Sstevel@tonic-gate 	int first;
265*7c478bd9Sstevel@tonic-gate 	int errflg = FALSE;
266*7c478bd9Sstevel@tonic-gate 	int badname = FALSE;
267*7c478bd9Sstevel@tonic-gate 	proc_set_t *grab = NULL;
268*7c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp;
269*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
270*7c478bd9Sstevel@tonic-gate 	int sharedmem;
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	/* a few of these need to be initialized to NULL */
273*7c478bd9Sstevel@tonic-gate 	Cp = NULL;
274*7c478bd9Sstevel@tonic-gate 	fcall_tbl = NULL;
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	/*
277*7c478bd9Sstevel@tonic-gate 	 * Make sure fd's 0, 1, and 2 are allocated,
278*7c478bd9Sstevel@tonic-gate 	 * just in case truss was invoked from init.
279*7c478bd9Sstevel@tonic-gate 	 */
280*7c478bd9Sstevel@tonic-gate 	while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2)
281*7c478bd9Sstevel@tonic-gate 		;
282*7c478bd9Sstevel@tonic-gate 	if (i > 2)
283*7c478bd9Sstevel@tonic-gate 		(void) close(i);
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	starttime = times(&tms);	/* for elapsed timing */
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/* this should be per-traced-process */
288*7c478bd9Sstevel@tonic-gate 	pagesize = sysconf(_SC_PAGESIZE);
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* command name (e.g., "truss") */
291*7c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
292*7c478bd9Sstevel@tonic-gate 		command++;
293*7c478bd9Sstevel@tonic-gate 	else
294*7c478bd9Sstevel@tonic-gate 		command = argv[0];
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	/* set up the initial private data */
297*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&truss_lock, USYNC_THREAD, NULL);
298*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&count_lock, USYNC_THREAD, NULL);
299*7c478bd9Sstevel@tonic-gate 	(void) cond_init(&truss_cv, USYNC_THREAD, NULL);
300*7c478bd9Sstevel@tonic-gate 	if (thr_keycreate(&private_key, free_private) == ENOMEM)
301*7c478bd9Sstevel@tonic-gate 		abend("memory allocation failure", NULL);
302*7c478bd9Sstevel@tonic-gate 	pri = get_private();
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	Euid = geteuid();
305*7c478bd9Sstevel@tonic-gate 	Egid = getegid();
306*7c478bd9Sstevel@tonic-gate 	Ruid = getuid();
307*7c478bd9Sstevel@tonic-gate 	Rgid = getgid();
308*7c478bd9Sstevel@tonic-gate 	ancestor = getpid();
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	prfillset(&trace);	/* default: trace all system calls */
311*7c478bd9Sstevel@tonic-gate 	premptyset(&verbose);	/* default: no syscall verbosity */
312*7c478bd9Sstevel@tonic-gate 	premptyset(&rawout);	/* default: no raw syscall interpretation */
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	prfillset(&signals);	/* default: trace all signals */
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	prfillset(&faults);	/* default: trace all faults */
317*7c478bd9Sstevel@tonic-gate 	prdelset(&faults, FLTPAGE);	/* except this one */
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	premptyset(&readfd);	/* default: dump no buffers */
320*7c478bd9Sstevel@tonic-gate 	premptyset(&writefd);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	premptyset(&syshang);	/* default: hang on no system calls */
323*7c478bd9Sstevel@tonic-gate 	premptyset(&sighang);	/* default: hang on no signals */
324*7c478bd9Sstevel@tonic-gate 	premptyset(&flthang);	/* default: hang on no faults */
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate #define	OPTIONS	"FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
327*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
328*7c478bd9Sstevel@tonic-gate 		switch (opt) {
329*7c478bd9Sstevel@tonic-gate 		case 'F':		/* force grabbing (no O_EXCL) */
330*7c478bd9Sstevel@tonic-gate 			Fflag = PGRAB_FORCE;
331*7c478bd9Sstevel@tonic-gate 			break;
332*7c478bd9Sstevel@tonic-gate 		case 'p':		/* grab processes */
333*7c478bd9Sstevel@tonic-gate 			pflag = TRUE;
334*7c478bd9Sstevel@tonic-gate 			break;
335*7c478bd9Sstevel@tonic-gate 		case 'f':		/* follow children */
336*7c478bd9Sstevel@tonic-gate 			fflag = TRUE;
337*7c478bd9Sstevel@tonic-gate 			break;
338*7c478bd9Sstevel@tonic-gate 		case 'c':		/* don't trace, just count */
339*7c478bd9Sstevel@tonic-gate 			cflag = TRUE;
340*7c478bd9Sstevel@tonic-gate 			iflag = TRUE;	/* implies no interruptable syscalls */
341*7c478bd9Sstevel@tonic-gate 			break;
342*7c478bd9Sstevel@tonic-gate 		case 'a':		/* display argument lists */
343*7c478bd9Sstevel@tonic-gate 			aflag = TRUE;
344*7c478bd9Sstevel@tonic-gate 			break;
345*7c478bd9Sstevel@tonic-gate 		case 'e':		/* display environments */
346*7c478bd9Sstevel@tonic-gate 			eflag = TRUE;
347*7c478bd9Sstevel@tonic-gate 			break;
348*7c478bd9Sstevel@tonic-gate 		case 'i':		/* don't show interruptable syscalls */
349*7c478bd9Sstevel@tonic-gate 			iflag = TRUE;
350*7c478bd9Sstevel@tonic-gate 			break;
351*7c478bd9Sstevel@tonic-gate 		case 'l':		/* show lwp id for each syscall */
352*7c478bd9Sstevel@tonic-gate 			lflag = TRUE;
353*7c478bd9Sstevel@tonic-gate 			break;
354*7c478bd9Sstevel@tonic-gate 		case 'h':		/* debugging: report hash stats */
355*7c478bd9Sstevel@tonic-gate 			hflag = TRUE;
356*7c478bd9Sstevel@tonic-gate 			break;
357*7c478bd9Sstevel@tonic-gate 		case 'd':		/* show time stamps */
358*7c478bd9Sstevel@tonic-gate 			dflag = TRUE;
359*7c478bd9Sstevel@tonic-gate 			break;
360*7c478bd9Sstevel@tonic-gate 		case 'D':		/* show time deltas */
361*7c478bd9Sstevel@tonic-gate 			Dflag = TRUE;
362*7c478bd9Sstevel@tonic-gate 			break;
363*7c478bd9Sstevel@tonic-gate 		case 'E':
364*7c478bd9Sstevel@tonic-gate 			Eflag = TRUE;	/* show syscall times */
365*7c478bd9Sstevel@tonic-gate 			break;
366*7c478bd9Sstevel@tonic-gate 		case 't':		/* system calls to trace */
367*7c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &trace, &tflag))
368*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
369*7c478bd9Sstevel@tonic-gate 			break;
370*7c478bd9Sstevel@tonic-gate 		case 'T':		/* system calls to hang process */
371*7c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &syshang, &Tflag))
372*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
373*7c478bd9Sstevel@tonic-gate 			break;
374*7c478bd9Sstevel@tonic-gate 		case 'v':		/* verbose interpretation of syscalls */
375*7c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &verbose, &vflag))
376*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
377*7c478bd9Sstevel@tonic-gate 			break;
378*7c478bd9Sstevel@tonic-gate 		case 'x':		/* raw interpretation of syscalls */
379*7c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &rawout, &xflag))
380*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
381*7c478bd9Sstevel@tonic-gate 			break;
382*7c478bd9Sstevel@tonic-gate 		case 's':		/* signals to trace */
383*7c478bd9Sstevel@tonic-gate 			if (siglist(pri, optarg, &signals, &sflag))
384*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
385*7c478bd9Sstevel@tonic-gate 			break;
386*7c478bd9Sstevel@tonic-gate 		case 'S':		/* signals to hang process */
387*7c478bd9Sstevel@tonic-gate 			if (siglist(pri, optarg, &sighang, &Sflag))
388*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
389*7c478bd9Sstevel@tonic-gate 			break;
390*7c478bd9Sstevel@tonic-gate 		case 'm':		/* machine faults to trace */
391*7c478bd9Sstevel@tonic-gate 			if (fltlist(optarg, &faults, &mflag))
392*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
393*7c478bd9Sstevel@tonic-gate 			break;
394*7c478bd9Sstevel@tonic-gate 		case 'M':		/* machine faults to hang process */
395*7c478bd9Sstevel@tonic-gate 			if (fltlist(optarg, &flthang, &Mflag))
396*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
397*7c478bd9Sstevel@tonic-gate 			break;
398*7c478bd9Sstevel@tonic-gate 		case 'u':		/* user library functions to trace */
399*7c478bd9Sstevel@tonic-gate 			if (liblist(optarg, 0))
400*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
401*7c478bd9Sstevel@tonic-gate 			break;
402*7c478bd9Sstevel@tonic-gate 		case 'U':		/* user library functions to hang */
403*7c478bd9Sstevel@tonic-gate 			if (liblist(optarg, 1))
404*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
405*7c478bd9Sstevel@tonic-gate 			break;
406*7c478bd9Sstevel@tonic-gate 		case 'r':		/* show contents of read(fd) */
407*7c478bd9Sstevel@tonic-gate 			if (fdlist(optarg, &readfd))
408*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
409*7c478bd9Sstevel@tonic-gate 			break;
410*7c478bd9Sstevel@tonic-gate 		case 'w':		/* show contents of write(fd) */
411*7c478bd9Sstevel@tonic-gate 			if (fdlist(optarg, &writefd))
412*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
413*7c478bd9Sstevel@tonic-gate 			break;
414*7c478bd9Sstevel@tonic-gate 		case 'o':		/* output file for trace */
415*7c478bd9Sstevel@tonic-gate 			oflag = TRUE;
416*7c478bd9Sstevel@tonic-gate 			if (ofd >= 0)
417*7c478bd9Sstevel@tonic-gate 				(void) close(ofd);
418*7c478bd9Sstevel@tonic-gate 			if ((ofd = xcreat(optarg)) < 0) {
419*7c478bd9Sstevel@tonic-gate 				perror(optarg);
420*7c478bd9Sstevel@tonic-gate 				badname = TRUE;
421*7c478bd9Sstevel@tonic-gate 			}
422*7c478bd9Sstevel@tonic-gate 			break;
423*7c478bd9Sstevel@tonic-gate 		default:
424*7c478bd9Sstevel@tonic-gate 			errflg = TRUE;
425*7c478bd9Sstevel@tonic-gate 			break;
426*7c478bd9Sstevel@tonic-gate 		}
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	if (badname)
430*7c478bd9Sstevel@tonic-gate 		exit(2);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	/* if -a or -e was specified, force tracing of exec() */
433*7c478bd9Sstevel@tonic-gate 	if (aflag || eflag) {
434*7c478bd9Sstevel@tonic-gate 		praddset(&trace, SYS_exec);
435*7c478bd9Sstevel@tonic-gate 		praddset(&trace, SYS_execve);
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	/*
439*7c478bd9Sstevel@tonic-gate 	 * Make sure that all system calls, signals, and machine faults
440*7c478bd9Sstevel@tonic-gate 	 * that hang the process are added to their trace sets.
441*7c478bd9Sstevel@tonic-gate 	 */
442*7c478bd9Sstevel@tonic-gate 	prorset(&trace, &syshang);
443*7c478bd9Sstevel@tonic-gate 	prorset(&signals, &sighang);
444*7c478bd9Sstevel@tonic-gate 	prorset(&faults, &flthang);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	argc -= optind;
447*7c478bd9Sstevel@tonic-gate 	argv += optind;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	/* collect the specified process ids */
450*7c478bd9Sstevel@tonic-gate 	if (pflag && argc > 0) {
451*7c478bd9Sstevel@tonic-gate 		grab = my_malloc(argc * sizeof (proc_set_t),
452*7c478bd9Sstevel@tonic-gate 			"memory for process-ids");
453*7c478bd9Sstevel@tonic-gate 		while (argc-- > 0)
454*7c478bd9Sstevel@tonic-gate 			pids(*argv++, grab);
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	if (errflg || (argc <= 0 && ngrab <= 0)) {
458*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
459*7c478bd9Sstevel@tonic-gate 	"usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
460*7c478bd9Sstevel@tonic-gate 			command);
461*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
462*7c478bd9Sstevel@tonic-gate 	"\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
463*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
464*7c478bd9Sstevel@tonic-gate 	"\t[-o outfile]  command | -p pid[/lwps] ...\n");
465*7c478bd9Sstevel@tonic-gate 		exit(2);
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	if (argc > 0) {		/* create the controlled process */
469*7c478bd9Sstevel@tonic-gate 		int err;
470*7c478bd9Sstevel@tonic-gate 		char path[PATH_MAX];
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 		Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
473*7c478bd9Sstevel@tonic-gate 		if (Proc == NULL) {
474*7c478bd9Sstevel@tonic-gate 			switch (err) {
475*7c478bd9Sstevel@tonic-gate 			case C_PERM:
476*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
477*7c478bd9Sstevel@tonic-gate 					"%s: cannot trace set-id or "
478*7c478bd9Sstevel@tonic-gate 					"unreadable object file: %s\n",
479*7c478bd9Sstevel@tonic-gate 					command, path);
480*7c478bd9Sstevel@tonic-gate 				break;
481*7c478bd9Sstevel@tonic-gate 			case C_LP64:
482*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
483*7c478bd9Sstevel@tonic-gate 					"%s: cannot control _LP64 "
484*7c478bd9Sstevel@tonic-gate 					"program: %s\n",
485*7c478bd9Sstevel@tonic-gate 					command, path);
486*7c478bd9Sstevel@tonic-gate 				break;
487*7c478bd9Sstevel@tonic-gate 			case C_NOEXEC:
488*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
489*7c478bd9Sstevel@tonic-gate 					"%s: cannot execute program: %s\n",
490*7c478bd9Sstevel@tonic-gate 					command, argv[0]);
491*7c478bd9Sstevel@tonic-gate 				break;
492*7c478bd9Sstevel@tonic-gate 			case C_NOENT:
493*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
494*7c478bd9Sstevel@tonic-gate 					"%s: cannot find program: %s\n",
495*7c478bd9Sstevel@tonic-gate 					command, argv[0]);
496*7c478bd9Sstevel@tonic-gate 				break;
497*7c478bd9Sstevel@tonic-gate 			case C_STRANGE:
498*7c478bd9Sstevel@tonic-gate 				break;
499*7c478bd9Sstevel@tonic-gate 			default:
500*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s\n",
501*7c478bd9Sstevel@tonic-gate 					command, Pcreate_error(err));
502*7c478bd9Sstevel@tonic-gate 				break;
503*7c478bd9Sstevel@tonic-gate 			}
504*7c478bd9Sstevel@tonic-gate 			exit(2);
505*7c478bd9Sstevel@tonic-gate 		}
506*7c478bd9Sstevel@tonic-gate 		if (fflag || Dynpat != NULL)
507*7c478bd9Sstevel@tonic-gate 			(void) Psetflags(Proc, PR_FORK);
508*7c478bd9Sstevel@tonic-gate 		else
509*7c478bd9Sstevel@tonic-gate 			(void) Punsetflags(Proc, PR_FORK);
510*7c478bd9Sstevel@tonic-gate 		Psp = Pstatus(Proc);
511*7c478bd9Sstevel@tonic-gate 		Lsp = &Psp->pr_lwp;
512*7c478bd9Sstevel@tonic-gate 		pri->lwpstat = Lsp;
513*7c478bd9Sstevel@tonic-gate 		data_model = Psp->pr_dmodel;
514*7c478bd9Sstevel@tonic-gate 		created = Psp->pr_pid;
515*7c478bd9Sstevel@tonic-gate 		make_pname(pri, 0);
516*7c478bd9Sstevel@tonic-gate 		(void) sysentry(pri, 1);
517*7c478bd9Sstevel@tonic-gate 		pri->length = 0;
518*7c478bd9Sstevel@tonic-gate 		if (!cflag && prismember(&trace, SYS_execve)) {
519*7c478bd9Sstevel@tonic-gate 			pri->exec_string = my_realloc(pri->exec_string,
520*7c478bd9Sstevel@tonic-gate 				strlen(pri->sys_string) + 1, NULL);
521*7c478bd9Sstevel@tonic-gate 			(void) strcpy(pri->exec_pname, pri->pname);
522*7c478bd9Sstevel@tonic-gate 			(void) strcpy(pri->exec_string, pri->sys_string);
523*7c478bd9Sstevel@tonic-gate 			pri->length += strlen(pri->sys_string);
524*7c478bd9Sstevel@tonic-gate 			pri->exec_lwpid = pri->lwpstat->pr_lwpid;
525*7c478bd9Sstevel@tonic-gate 			pri->sys_leng = 0;
526*7c478bd9Sstevel@tonic-gate 			*pri->sys_string = '\0';
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		pri->syslast = Psp->pr_stime;
529*7c478bd9Sstevel@tonic-gate 		pri->usrlast = Psp->pr_utime;
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	/*
533*7c478bd9Sstevel@tonic-gate 	 * Now that we have created the victim process,
534*7c478bd9Sstevel@tonic-gate 	 * give ourself a million file descriptors.
535*7c478bd9Sstevel@tonic-gate 	 * This is enough to deal with a multithreaded
536*7c478bd9Sstevel@tonic-gate 	 * victim process that has half a million lwps.
537*7c478bd9Sstevel@tonic-gate 	 */
538*7c478bd9Sstevel@tonic-gate 	rlim.rlim_cur = 1024 * 1024;
539*7c478bd9Sstevel@tonic-gate 	rlim.rlim_max = 1024 * 1024;
540*7c478bd9Sstevel@tonic-gate 	if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) &&
541*7c478bd9Sstevel@tonic-gate 	    getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
542*7c478bd9Sstevel@tonic-gate 		/*
543*7c478bd9Sstevel@tonic-gate 		 * Failing the million, give ourself as many
544*7c478bd9Sstevel@tonic-gate 		 * file descriptors as we can get.
545*7c478bd9Sstevel@tonic-gate 		 */
546*7c478bd9Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
547*7c478bd9Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
548*7c478bd9Sstevel@tonic-gate 	}
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	setoutput(ofd);		/* establish truss output */
551*7c478bd9Sstevel@tonic-gate 	istty = isatty(1);
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0)
554*7c478bd9Sstevel@tonic-gate 		abend("setvbuf() failure", NULL);
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	/*
557*7c478bd9Sstevel@tonic-gate 	 * Set up signal dispositions.
558*7c478bd9Sstevel@tonic-gate 	 */
559*7c478bd9Sstevel@tonic-gate 	if (created && (oflag || !istty)) {	/* ignore interrupts */
560*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, SIG_IGN);
561*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGINT, SIG_IGN);
562*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGQUIT, SIG_IGN);
563*7c478bd9Sstevel@tonic-gate 	} else {				/* receive interrupts */
564*7c478bd9Sstevel@tonic-gate 		if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
565*7c478bd9Sstevel@tonic-gate 			(void) sigset(SIGHUP, intr);
566*7c478bd9Sstevel@tonic-gate 		if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
567*7c478bd9Sstevel@tonic-gate 			(void) sigset(SIGINT, intr);
568*7c478bd9Sstevel@tonic-gate 		if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
569*7c478bd9Sstevel@tonic-gate 			(void) sigset(SIGQUIT, intr);
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
572*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGUSR1, intr);
573*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGUSR2, intr);
574*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPIPE, intr);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	/* don't accumulate zombie children */
577*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_IGN);
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 	/* create shared mem space for global mutexes */
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	sharedmem = (fflag || Dynpat != NULL || ngrab > 1);
582*7c478bd9Sstevel@tonic-gate 	gps = (void *)mmap(NULL, sizeof (struct global_psinfo),
583*7c478bd9Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE,
584*7c478bd9Sstevel@tonic-gate 	    MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE),
585*7c478bd9Sstevel@tonic-gate 	    -1, (off_t)0);
586*7c478bd9Sstevel@tonic-gate 	if (gps == MAP_FAILED)
587*7c478bd9Sstevel@tonic-gate 		abend("cannot allocate ", "memory for counts");
588*7c478bd9Sstevel@tonic-gate 	i = sharedmem? USYNC_PROCESS : USYNC_THREAD;
589*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&gps->ps_mutex0, i, NULL);
590*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&gps->ps_mutex1, i, NULL);
591*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&gps->fork_lock, i, NULL);
592*7c478bd9Sstevel@tonic-gate 	(void) cond_init(&gps->fork_cv, i, NULL);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	/* config tmp file if counting and following */
596*7c478bd9Sstevel@tonic-gate 	if (fflag && cflag) {
597*7c478bd9Sstevel@tonic-gate 		char *tmps = tempnam("/var/tmp", "truss");
598*7c478bd9Sstevel@tonic-gate 		sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600);
599*7c478bd9Sstevel@tonic-gate 		if (sfd == -1)
600*7c478bd9Sstevel@tonic-gate 			abend("Error creating tmpfile", NULL);
601*7c478bd9Sstevel@tonic-gate 		if (unlink(tmps) == -1)
602*7c478bd9Sstevel@tonic-gate 			abend("Error unlinking tmpfile", NULL);
603*7c478bd9Sstevel@tonic-gate 		free(tmps);
604*7c478bd9Sstevel@tonic-gate 		tmps = NULL;
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (created) {
608*7c478bd9Sstevel@tonic-gate 		per_proc_init();
609*7c478bd9Sstevel@tonic-gate 		procadd(created, NULL);
610*7c478bd9Sstevel@tonic-gate 		show_cred(pri, TRUE);
611*7c478bd9Sstevel@tonic-gate 	} else {		/* grab the specified processes */
612*7c478bd9Sstevel@tonic-gate 		int gotone = FALSE;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 		i = 0;
615*7c478bd9Sstevel@tonic-gate 		while (i < ngrab) {		/* grab first process */
616*7c478bd9Sstevel@tonic-gate 			if (grabit(pri, &grab[i++])) {
617*7c478bd9Sstevel@tonic-gate 				Psp = Pstatus(Proc);
618*7c478bd9Sstevel@tonic-gate 				Lsp = &Psp->pr_lwp;
619*7c478bd9Sstevel@tonic-gate 				gotone = TRUE;
620*7c478bd9Sstevel@tonic-gate 				break;
621*7c478bd9Sstevel@tonic-gate 			}
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate 		if (!gotone)
624*7c478bd9Sstevel@tonic-gate 			abend(NULL, NULL);
625*7c478bd9Sstevel@tonic-gate 		per_proc_init();
626*7c478bd9Sstevel@tonic-gate 		while (i < ngrab) {		/* grab the remainder */
627*7c478bd9Sstevel@tonic-gate 			proc_set_t *set = &grab[i++];
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&truss_lock);
630*7c478bd9Sstevel@tonic-gate 			switch (fork1()) {
631*7c478bd9Sstevel@tonic-gate 			case -1:
632*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
633*7c478bd9Sstevel@tonic-gate 			"%s: cannot fork to control process, pid# %d\n",
634*7c478bd9Sstevel@tonic-gate 					command, (int)set->pid);
635*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
636*7c478bd9Sstevel@tonic-gate 			default:
637*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
638*7c478bd9Sstevel@tonic-gate 				continue;	/* parent carries on */
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 			case 0:			/* child grabs process */
641*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
642*7c478bd9Sstevel@tonic-gate 				Pfree(Proc);
643*7c478bd9Sstevel@tonic-gate 				descendent = TRUE;
644*7c478bd9Sstevel@tonic-gate 				if (grabit(pri, set)) {
645*7c478bd9Sstevel@tonic-gate 					Psp = Pstatus(Proc);
646*7c478bd9Sstevel@tonic-gate 					Lsp = &Psp->pr_lwp;
647*7c478bd9Sstevel@tonic-gate 					per_proc_init();
648*7c478bd9Sstevel@tonic-gate 					break;
649*7c478bd9Sstevel@tonic-gate 				}
650*7c478bd9Sstevel@tonic-gate 				exit(2);
651*7c478bd9Sstevel@tonic-gate 			}
652*7c478bd9Sstevel@tonic-gate 			break;
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 		free(grab);
655*7c478bd9Sstevel@tonic-gate 	}
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	/*
659*7c478bd9Sstevel@tonic-gate 	 * If running setuid-root, become root for real to avoid
660*7c478bd9Sstevel@tonic-gate 	 * affecting the per-user limitation on the maximum number
661*7c478bd9Sstevel@tonic-gate 	 * of processes (one benefit of running setuid-root).
662*7c478bd9Sstevel@tonic-gate 	 */
663*7c478bd9Sstevel@tonic-gate 	if (Rgid != Egid)
664*7c478bd9Sstevel@tonic-gate 		(void) setgid(Egid);
665*7c478bd9Sstevel@tonic-gate 	if (Ruid != Euid)
666*7c478bd9Sstevel@tonic-gate 		(void) setuid(Euid);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	if (!created && aflag && prismember(&trace, SYS_execve)) {
669*7c478bd9Sstevel@tonic-gate 		psargs(pri);
670*7c478bd9Sstevel@tonic-gate 		Flush();
671*7c478bd9Sstevel@tonic-gate 	}
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	if (created && Pstate(Proc) != PS_STOP)	/* assertion */
674*7c478bd9Sstevel@tonic-gate 		if (!(interrupt | sigusr1))
675*7c478bd9Sstevel@tonic-gate 			abend("ASSERT error: process is not stopped", NULL);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	traceeven = trace;		/* trace these system calls */
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	/* trace these regardless, even if we don't report results */
680*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_exit);
681*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_lwp_create);
682*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_lwp_exit);
683*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_exec);
684*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_execve);
685*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_open);
686*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_open64);
687*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_forkall);
688*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_vfork);
689*7c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_fork1);
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 	/* for I/O buffer dumps, force tracing of read()s and write()s */
692*7c478bd9Sstevel@tonic-gate 	if (!isemptyset(&readfd)) {
693*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_read);
694*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_readv);
695*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pread);
696*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pread64);
697*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_recv);
698*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_recvfrom);
699*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_recvmsg);
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate 	if (!isemptyset(&writefd)) {
702*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_write);
703*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_writev);
704*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pwrite);
705*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pwrite64);
706*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_send);
707*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_sendto);
708*7c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_sendmsg);
709*7c478bd9Sstevel@tonic-gate 	}
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	if (cflag || Eflag) {
712*7c478bd9Sstevel@tonic-gate 		Psetsysentry(Proc, &traceeven);
713*7c478bd9Sstevel@tonic-gate 	}
714*7c478bd9Sstevel@tonic-gate 	Psetsysexit(Proc, &traceeven);
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	/* special case -- cannot trace sysexit because context is changed */
717*7c478bd9Sstevel@tonic-gate 	if (prismember(&trace, SYS_context)) {
718*7c478bd9Sstevel@tonic-gate 		(void) Psysentry(Proc, SYS_context, TRUE);
719*7c478bd9Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_context, FALSE);
720*7c478bd9Sstevel@tonic-gate 		prdelset(&traceeven, SYS_context);
721*7c478bd9Sstevel@tonic-gate 	}
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	/* special case -- sysexit not traced by OS */
724*7c478bd9Sstevel@tonic-gate 	if (prismember(&trace, SYS_evtrapret)) {
725*7c478bd9Sstevel@tonic-gate 		(void) Psysentry(Proc, SYS_evtrapret, TRUE);
726*7c478bd9Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_evtrapret, FALSE);
727*7c478bd9Sstevel@tonic-gate 		prdelset(&traceeven, SYS_evtrapret);
728*7c478bd9Sstevel@tonic-gate 	}
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	/* special case -- trace exec() on entry to get the args */
731*7c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_exec, TRUE);
732*7c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_execve, TRUE);
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	/* special case -- sysexit never reached */
735*7c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_exit, TRUE);
736*7c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_lwp_exit, TRUE);
737*7c478bd9Sstevel@tonic-gate 	(void) Psysexit(Proc, SYS_exit, FALSE);
738*7c478bd9Sstevel@tonic-gate 	(void) Psysexit(Proc, SYS_lwp_exit, FALSE);
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	Psetsignal(Proc, &signals);	/* trace these signals */
741*7c478bd9Sstevel@tonic-gate 	Psetfault(Proc, &faults);	/* trace these faults */
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	/* for function call tracing */
744*7c478bd9Sstevel@tonic-gate 	if (Dynpat != NULL) {
745*7c478bd9Sstevel@tonic-gate 		/* trace these regardless, to deal with function calls */
746*7c478bd9Sstevel@tonic-gate 		(void) Pfault(Proc, FLTBPT, TRUE);
747*7c478bd9Sstevel@tonic-gate 		(void) Pfault(Proc, FLTTRACE, TRUE);
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 		/* needed for x86 */
750*7c478bd9Sstevel@tonic-gate 		(void) Psetflags(Proc, PR_BPTADJ);
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 		/*
753*7c478bd9Sstevel@tonic-gate 		 * Find functions and set breakpoints on grabbed process.
754*7c478bd9Sstevel@tonic-gate 		 * A process stopped on exec() gets its breakpoints set below.
755*7c478bd9Sstevel@tonic-gate 		 */
756*7c478bd9Sstevel@tonic-gate 		if ((Lsp->pr_why != PR_SYSENTRY &&
757*7c478bd9Sstevel@tonic-gate 		    Lsp->pr_why != PR_SYSEXIT) ||
758*7c478bd9Sstevel@tonic-gate 		    (Lsp->pr_what != SYS_exec &&
759*7c478bd9Sstevel@tonic-gate 		    Lsp->pr_what != SYS_execve)) {
760*7c478bd9Sstevel@tonic-gate 			establish_breakpoints();
761*7c478bd9Sstevel@tonic-gate 			establish_stacks();
762*7c478bd9Sstevel@tonic-gate 		}
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	/*
766*7c478bd9Sstevel@tonic-gate 	 * Use asynchronous-stop for multithreaded truss.
767*7c478bd9Sstevel@tonic-gate 	 * truss runs one lwp for each lwp in the target process.
768*7c478bd9Sstevel@tonic-gate 	 */
769*7c478bd9Sstevel@tonic-gate 	(void) Psetflags(Proc, PR_ASYNC);
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	/* flush out all tracing flags now. */
772*7c478bd9Sstevel@tonic-gate 	Psync(Proc);
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 	/*
775*7c478bd9Sstevel@tonic-gate 	 * If we grabbed a running process, set it running again.
776*7c478bd9Sstevel@tonic-gate 	 * Since we are tracing lwp_create() and lwp_exit(), the
777*7c478bd9Sstevel@tonic-gate 	 * lwps will not change in the process until we create all
778*7c478bd9Sstevel@tonic-gate 	 * of the truss worker threads.
779*7c478bd9Sstevel@tonic-gate 	 * We leave a created process stopped so its exec() can be reported.
780*7c478bd9Sstevel@tonic-gate 	 */
781*7c478bd9Sstevel@tonic-gate 	first = created? FALSE : TRUE;
782*7c478bd9Sstevel@tonic-gate 	if (!created &&
783*7c478bd9Sstevel@tonic-gate 	    ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
784*7c478bd9Sstevel@tonic-gate 	    (Lsp->pr_flags & PR_DSTOP)))
785*7c478bd9Sstevel@tonic-gate 		first = FALSE;
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	main_thread(first);
788*7c478bd9Sstevel@tonic-gate 	return (0);
789*7c478bd9Sstevel@tonic-gate }
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate /*
792*7c478bd9Sstevel@tonic-gate  * Called from main() and from control() after fork1().
793*7c478bd9Sstevel@tonic-gate  */
794*7c478bd9Sstevel@tonic-gate void
795*7c478bd9Sstevel@tonic-gate main_thread(int first)
796*7c478bd9Sstevel@tonic-gate {
797*7c478bd9Sstevel@tonic-gate 	private_t *pri = get_private();
798*7c478bd9Sstevel@tonic-gate 	sigset_t mask;
799*7c478bd9Sstevel@tonic-gate 	struct tms tms;
800*7c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
801*7c478bd9Sstevel@tonic-gate 	void *status;
802*7c478bd9Sstevel@tonic-gate 	int flags;
803*7c478bd9Sstevel@tonic-gate 	int retc;
804*7c478bd9Sstevel@tonic-gate 	int i;
805*7c478bd9Sstevel@tonic-gate 	int count;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	/*
808*7c478bd9Sstevel@tonic-gate 	 * If we are dealing with a previously hung process,
809*7c478bd9Sstevel@tonic-gate 	 * arrange not to leave it hung on the same system call.
810*7c478bd9Sstevel@tonic-gate 	 */
811*7c478bd9Sstevel@tonic-gate 	primary_lwp = (first && Pstate(Proc) == PS_STOP)?
812*7c478bd9Sstevel@tonic-gate 		Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	/*
815*7c478bd9Sstevel@tonic-gate 	 * Create worker threads to match the lwps in the target process.
816*7c478bd9Sstevel@tonic-gate 	 * Clear our signal mask so that worker threads are unblocked.
817*7c478bd9Sstevel@tonic-gate 	 */
818*7c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&mask);
819*7c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
820*7c478bd9Sstevel@tonic-gate 	truss_nlwp = 0;
821*7c478bd9Sstevel@tonic-gate 	truss_maxlwp = 1;
822*7c478bd9Sstevel@tonic-gate 	truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
823*7c478bd9Sstevel@tonic-gate 	truss_lwpid[0] = 0;
824*7c478bd9Sstevel@tonic-gate 	count = 0;
825*7c478bd9Sstevel@tonic-gate 	(void) Plwp_iter(Proc, create_thread, &count);
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	if (count == 0) {
828*7c478bd9Sstevel@tonic-gate 		(void) printf("(Warning: no matching active LWPs found, "
829*7c478bd9Sstevel@tonic-gate 		    "waiting)\n");
830*7c478bd9Sstevel@tonic-gate 		Flush();
831*7c478bd9Sstevel@tonic-gate 	}
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	/*
834*7c478bd9Sstevel@tonic-gate 	 * Block all signals in the main thread.
835*7c478bd9Sstevel@tonic-gate 	 * Some worker thread will receive signals.
836*7c478bd9Sstevel@tonic-gate 	 */
837*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&mask);
838*7c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	/*
841*7c478bd9Sstevel@tonic-gate 	 * Set all of the truss worker threads running now.
842*7c478bd9Sstevel@tonic-gate 	 */
843*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&truss_lock);
844*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
845*7c478bd9Sstevel@tonic-gate 		if (truss_lwpid[i])
846*7c478bd9Sstevel@tonic-gate 			(void) thr_continue(truss_lwpid[i]);
847*7c478bd9Sstevel@tonic-gate 	}
848*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	/*
851*7c478bd9Sstevel@tonic-gate 	 * Wait until all lwps terminate.
852*7c478bd9Sstevel@tonic-gate 	 */
853*7c478bd9Sstevel@tonic-gate 	while (thr_join(0, &lwpid, &status) == 0) {
854*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
855*7c478bd9Sstevel@tonic-gate 		if (status != NULL)
856*7c478bd9Sstevel@tonic-gate 			leave_hung = TRUE;
857*7c478bd9Sstevel@tonic-gate 		delete_lwpid(lwpid);
858*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&truss_lock);
859*7c478bd9Sstevel@tonic-gate 	}
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	(void) Punsetflags(Proc, PR_ASYNC);
862*7c478bd9Sstevel@tonic-gate 	Psync(Proc);
863*7c478bd9Sstevel@tonic-gate 	if (sigusr1)
864*7c478bd9Sstevel@tonic-gate 		letgo(pri);
865*7c478bd9Sstevel@tonic-gate 	report_htable_stats();
866*7c478bd9Sstevel@tonic-gate 	clear_breakpoints();
867*7c478bd9Sstevel@tonic-gate 	flags = PRELEASE_CLEAR;
868*7c478bd9Sstevel@tonic-gate 	if (leave_hung)
869*7c478bd9Sstevel@tonic-gate 		flags |= PRELEASE_HANG;
870*7c478bd9Sstevel@tonic-gate 	Prelease(Proc, flags);
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	procdel();
873*7c478bd9Sstevel@tonic-gate 	retc = (leave_hung? 0 : wait4all());
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	if (!descendent) {
876*7c478bd9Sstevel@tonic-gate 		interrupt = 0;	/* another interrupt kills the report */
877*7c478bd9Sstevel@tonic-gate 		if (cflag) {
878*7c478bd9Sstevel@tonic-gate 			if (fflag)
879*7c478bd9Sstevel@tonic-gate 				file_to_parent();
880*7c478bd9Sstevel@tonic-gate 			report(pri, times(&tms) - starttime);
881*7c478bd9Sstevel@tonic-gate 		}
882*7c478bd9Sstevel@tonic-gate 	} else if (cflag && fflag) {
883*7c478bd9Sstevel@tonic-gate 		child_to_file();
884*7c478bd9Sstevel@tonic-gate 	}
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	exit(retc);	/* exit with exit status of created process, else 0 */
887*7c478bd9Sstevel@tonic-gate }
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate void *
890*7c478bd9Sstevel@tonic-gate worker_thread(void *arg)
891*7c478bd9Sstevel@tonic-gate {
892*7c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
893*7c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp = Pstatus(Proc);
894*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp = Lstatus(Lwp);
895*7c478bd9Sstevel@tonic-gate 	struct syscount *scp;
896*7c478bd9Sstevel@tonic-gate 	lwpid_t who = Lsp->pr_lwpid;
897*7c478bd9Sstevel@tonic-gate 	int first = (who == primary_lwp);
898*7c478bd9Sstevel@tonic-gate 	private_t *pri = get_private();
899*7c478bd9Sstevel@tonic-gate 	int req_flag = 0;
900*7c478bd9Sstevel@tonic-gate 	intptr_t leave_it_hung = FALSE;
901*7c478bd9Sstevel@tonic-gate 	int reset_traps = FALSE;
902*7c478bd9Sstevel@tonic-gate 	int gcode;
903*7c478bd9Sstevel@tonic-gate 	int what;
904*7c478bd9Sstevel@tonic-gate 	int ow_in_effect = 0;
905*7c478bd9Sstevel@tonic-gate 	long ow_syscall = 0;
906*7c478bd9Sstevel@tonic-gate 	long ow_subcode = 0;
907*7c478bd9Sstevel@tonic-gate 	char *ow_string = NULL;
908*7c478bd9Sstevel@tonic-gate 	sysset_t full_set;
909*7c478bd9Sstevel@tonic-gate 	sysset_t running_set;
910*7c478bd9Sstevel@tonic-gate 	int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	static int nstopped = 0;
913*7c478bd9Sstevel@tonic-gate 	static int go = 0;
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	pri->Lwp = Lwp;
916*7c478bd9Sstevel@tonic-gate 	pri->lwpstat = Lsp;
917*7c478bd9Sstevel@tonic-gate 	pri->syslast = Lsp->pr_stime;
918*7c478bd9Sstevel@tonic-gate 	pri->usrlast = Lsp->pr_utime;
919*7c478bd9Sstevel@tonic-gate 	make_pname(pri, 0);
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	prfillset(&full_set);
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	/*
924*7c478bd9Sstevel@tonic-gate 	 * Run this loop until the victim lwp terminates.
925*7c478bd9Sstevel@tonic-gate 	 */
926*7c478bd9Sstevel@tonic-gate 	for (;;) {
927*7c478bd9Sstevel@tonic-gate 		if (interrupt | sigusr1) {
928*7c478bd9Sstevel@tonic-gate 			(void) Lstop(Lwp, MILLISEC);
929*7c478bd9Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_RUN)
930*7c478bd9Sstevel@tonic-gate 				break;
931*7c478bd9Sstevel@tonic-gate 		}
932*7c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_RUN) {
933*7c478bd9Sstevel@tonic-gate 			/* millisecond timeout is for sleeping syscalls */
934*7c478bd9Sstevel@tonic-gate 			uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 			/*
937*7c478bd9Sstevel@tonic-gate 			 * If we are to leave this lwp stopped in sympathy
938*7c478bd9Sstevel@tonic-gate 			 * with another lwp that has been left hung, or if
939*7c478bd9Sstevel@tonic-gate 			 * we have been interrupted or instructed to release
940*7c478bd9Sstevel@tonic-gate 			 * our victim process, and this lwp is stopped but
941*7c478bd9Sstevel@tonic-gate 			 * not on an event of interest to /proc, then just
942*7c478bd9Sstevel@tonic-gate 			 * leave it in that state.
943*7c478bd9Sstevel@tonic-gate 			 */
944*7c478bd9Sstevel@tonic-gate 			if ((leave_hung | interrupt | sigusr1) &&
945*7c478bd9Sstevel@tonic-gate 			    (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
946*7c478bd9Sstevel@tonic-gate 			    == PR_STOPPED)
947*7c478bd9Sstevel@tonic-gate 				break;
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 			(void) Lwait(Lwp, tout);
950*7c478bd9Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_RUN &&
951*7c478bd9Sstevel@tonic-gate 			    tout != 0 && !(interrupt | sigusr1)) {
952*7c478bd9Sstevel@tonic-gate 				(void) mutex_lock(&truss_lock);
953*7c478bd9Sstevel@tonic-gate 				if ((Lsp->pr_flags & PR_STOPPED) &&
954*7c478bd9Sstevel@tonic-gate 				    Lsp->pr_why == PR_JOBCONTROL)
955*7c478bd9Sstevel@tonic-gate 					req_flag = jobcontrol(pri, dotrace);
956*7c478bd9Sstevel@tonic-gate 				else
957*7c478bd9Sstevel@tonic-gate 					req_flag = requested(pri, req_flag,
958*7c478bd9Sstevel@tonic-gate 					    dotrace);
959*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
960*7c478bd9Sstevel@tonic-gate 			}
961*7c478bd9Sstevel@tonic-gate 			continue;
962*7c478bd9Sstevel@tonic-gate 		}
963*7c478bd9Sstevel@tonic-gate 		data_model = Psp->pr_dmodel;
964*7c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_UNDEAD)
965*7c478bd9Sstevel@tonic-gate 			break;
966*7c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_LOST) {	/* we lost control */
967*7c478bd9Sstevel@tonic-gate 			/*
968*7c478bd9Sstevel@tonic-gate 			 * After exec(), only one LWP remains in the process.
969*7c478bd9Sstevel@tonic-gate 			 * /proc makes the thread following that LWP receive
970*7c478bd9Sstevel@tonic-gate 			 * EAGAIN (PS_LOST) if the program being exec()ed
971*7c478bd9Sstevel@tonic-gate 			 * is a set-id program.  Every other controlling
972*7c478bd9Sstevel@tonic-gate 			 * thread receives ENOENT (because its LWP vanished).
973*7c478bd9Sstevel@tonic-gate 			 * We are the controlling thread for the exec()ing LWP.
974*7c478bd9Sstevel@tonic-gate 			 * We must wait until all of our siblings terminate
975*7c478bd9Sstevel@tonic-gate 			 * before attempting to reopen the process.
976*7c478bd9Sstevel@tonic-gate 			 */
977*7c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&truss_lock);
978*7c478bd9Sstevel@tonic-gate 			while (truss_nlwp > 1)
979*7c478bd9Sstevel@tonic-gate 				(void) cond_wait(&truss_cv, &truss_lock);
980*7c478bd9Sstevel@tonic-gate 			if (Preopen(Proc) == 0) { /* we got control back */
981*7c478bd9Sstevel@tonic-gate 				/*
982*7c478bd9Sstevel@tonic-gate 				 * We have to free and re-grab the LWP.
983*7c478bd9Sstevel@tonic-gate 				 * The process is guaranteed to be at exit
984*7c478bd9Sstevel@tonic-gate 				 * from exec() or execve() and have only
985*7c478bd9Sstevel@tonic-gate 				 * one LWP, namely this one, and the LWP
986*7c478bd9Sstevel@tonic-gate 				 * is guaranteed to have lwpid == 1.
987*7c478bd9Sstevel@tonic-gate 				 * This "cannot fail".
988*7c478bd9Sstevel@tonic-gate 				 */
989*7c478bd9Sstevel@tonic-gate 				who = 1;
990*7c478bd9Sstevel@tonic-gate 				Lfree(Lwp);
991*7c478bd9Sstevel@tonic-gate 				pri->Lwp = Lwp =
992*7c478bd9Sstevel@tonic-gate 					Lgrab(Proc, who, &gcode);
993*7c478bd9Sstevel@tonic-gate 				if (Lwp == NULL)
994*7c478bd9Sstevel@tonic-gate 					abend("Lgrab error: ",
995*7c478bd9Sstevel@tonic-gate 						Lgrab_error(gcode));
996*7c478bd9Sstevel@tonic-gate 				pri->lwpstat = Lsp = Lstatus(Lwp);
997*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
998*7c478bd9Sstevel@tonic-gate 				continue;
999*7c478bd9Sstevel@tonic-gate 			}
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 			/* we really lost it */
1002*7c478bd9Sstevel@tonic-gate 			if (pri->exec_string && *pri->exec_string) {
1003*7c478bd9Sstevel@tonic-gate 				if (pri->exec_pname[0] != '\0')
1004*7c478bd9Sstevel@tonic-gate 					(void) fputs(pri->exec_pname, stdout);
1005*7c478bd9Sstevel@tonic-gate 				timestamp(pri);
1006*7c478bd9Sstevel@tonic-gate 				(void) fputs(pri->exec_string, stdout);
1007*7c478bd9Sstevel@tonic-gate 				(void) fputc('\n', stdout);
1008*7c478bd9Sstevel@tonic-gate 			} else if (pri->length) {
1009*7c478bd9Sstevel@tonic-gate 				(void) fputc('\n', stdout);
1010*7c478bd9Sstevel@tonic-gate 			}
1011*7c478bd9Sstevel@tonic-gate 			if (pri->sys_valid)
1012*7c478bd9Sstevel@tonic-gate 				(void) printf(
1013*7c478bd9Sstevel@tonic-gate 			"%s\t*** cannot trace across exec() of %s ***\n",
1014*7c478bd9Sstevel@tonic-gate 					pri->pname, pri->sys_path);
1015*7c478bd9Sstevel@tonic-gate 			else
1016*7c478bd9Sstevel@tonic-gate 				(void) printf(
1017*7c478bd9Sstevel@tonic-gate 				"%s\t*** lost control of process ***\n",
1018*7c478bd9Sstevel@tonic-gate 					pri->pname);
1019*7c478bd9Sstevel@tonic-gate 			pri->length = 0;
1020*7c478bd9Sstevel@tonic-gate 			Flush();
1021*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&truss_lock);
1022*7c478bd9Sstevel@tonic-gate 			break;
1023*7c478bd9Sstevel@tonic-gate 		}
1024*7c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) != PS_STOP) {
1025*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1026*7c478bd9Sstevel@tonic-gate 				"%s: state = %d\n", command, Lstate(Lwp));
1027*7c478bd9Sstevel@tonic-gate 			abend(pri->pname, "uncaught status of subject lwp");
1028*7c478bd9Sstevel@tonic-gate 		}
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 		make_pname(pri, 0);
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 		what = Lsp->pr_what;
1035*7c478bd9Sstevel@tonic-gate 		req_flag = 0;
1036*7c478bd9Sstevel@tonic-gate 
1037*7c478bd9Sstevel@tonic-gate 		switch (Lsp->pr_why) {
1038*7c478bd9Sstevel@tonic-gate 		case PR_REQUESTED:
1039*7c478bd9Sstevel@tonic-gate 			break;
1040*7c478bd9Sstevel@tonic-gate 		case PR_SIGNALLED:
1041*7c478bd9Sstevel@tonic-gate 			req_flag = signalled(pri, req_flag, dotrace);
1042*7c478bd9Sstevel@tonic-gate 			if (Sflag && !first && prismember(&sighang, what))
1043*7c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
1044*7c478bd9Sstevel@tonic-gate 			break;
1045*7c478bd9Sstevel@tonic-gate 		case PR_FAULTED:
1046*7c478bd9Sstevel@tonic-gate 			if (what == FLTBPT) {
1047*7c478bd9Sstevel@tonic-gate 				int rval;
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 				(void) Pstop(Proc, 0);
1050*7c478bd9Sstevel@tonic-gate 				rval = function_trace(pri, first, 0, dotrace);
1051*7c478bd9Sstevel@tonic-gate 				if (rval == 1)
1052*7c478bd9Sstevel@tonic-gate 					leave_it_hung = TRUE;
1053*7c478bd9Sstevel@tonic-gate 				if (rval >= 0)
1054*7c478bd9Sstevel@tonic-gate 					break;
1055*7c478bd9Sstevel@tonic-gate 			}
1056*7c478bd9Sstevel@tonic-gate 			if (faulted(pri, dotrace) &&
1057*7c478bd9Sstevel@tonic-gate 			    Mflag && !first && prismember(&flthang, what))
1058*7c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
1059*7c478bd9Sstevel@tonic-gate 			break;
1060*7c478bd9Sstevel@tonic-gate 		case PR_JOBCONTROL:	/* can't happen except first time */
1061*7c478bd9Sstevel@tonic-gate 			req_flag = jobcontrol(pri, dotrace);
1062*7c478bd9Sstevel@tonic-gate 			break;
1063*7c478bd9Sstevel@tonic-gate 		case PR_SYSENTRY:
1064*7c478bd9Sstevel@tonic-gate 			/* protect ourself from operating system error */
1065*7c478bd9Sstevel@tonic-gate 			if (what <= 0 || what > PRMAXSYS)
1066*7c478bd9Sstevel@tonic-gate 				what = PRMAXSYS;
1067*7c478bd9Sstevel@tonic-gate 			pri->length = 0;
1068*7c478bd9Sstevel@tonic-gate 			/*
1069*7c478bd9Sstevel@tonic-gate 			 * ow_in_effect checks to see whether or not we
1070*7c478bd9Sstevel@tonic-gate 			 * are attempting to quantify the time spent in
1071*7c478bd9Sstevel@tonic-gate 			 * a one way system call.  This is necessary as
1072*7c478bd9Sstevel@tonic-gate 			 * some system calls never return, yet it is desireable
1073*7c478bd9Sstevel@tonic-gate 			 * to determine how much time the traced process
1074*7c478bd9Sstevel@tonic-gate 			 * spends in these calls.  To do this, a one way
1075*7c478bd9Sstevel@tonic-gate 			 * flag is set on SYSENTRY when the call is recieved.
1076*7c478bd9Sstevel@tonic-gate 			 * After this, the call mask for the SYSENTRY events
1077*7c478bd9Sstevel@tonic-gate 			 * is filled so that the traced process will stop
1078*7c478bd9Sstevel@tonic-gate 			 * on the entry to the very next system call.
1079*7c478bd9Sstevel@tonic-gate 			 * This appears to the the best way to determine
1080*7c478bd9Sstevel@tonic-gate 			 * system time elapsed between a one way system call.
1081*7c478bd9Sstevel@tonic-gate 			 * Once the next call occurs, values that have been
1082*7c478bd9Sstevel@tonic-gate 			 * stashed are used to record the correct syscall
1083*7c478bd9Sstevel@tonic-gate 			 * and time, and the SYSENTRY event mask is restored
1084*7c478bd9Sstevel@tonic-gate 			 * so that the traced process may continue.
1085*7c478bd9Sstevel@tonic-gate 			 */
1086*7c478bd9Sstevel@tonic-gate 			if (dotrace && ow_in_effect) {
1087*7c478bd9Sstevel@tonic-gate 				if (cflag) {
1088*7c478bd9Sstevel@tonic-gate 					(void) mutex_lock(&count_lock);
1089*7c478bd9Sstevel@tonic-gate 					scp = Cp->syscount[ow_syscall];
1090*7c478bd9Sstevel@tonic-gate 					if (ow_subcode != -1)
1091*7c478bd9Sstevel@tonic-gate 						scp += ow_subcode;
1092*7c478bd9Sstevel@tonic-gate 					scp->count++;
1093*7c478bd9Sstevel@tonic-gate 					accumulate(&scp->stime,
1094*7c478bd9Sstevel@tonic-gate 					    &Lsp->pr_stime, &pri->syslast);
1095*7c478bd9Sstevel@tonic-gate 					accumulate(&Cp->usrtotal,
1096*7c478bd9Sstevel@tonic-gate 					    &Lsp->pr_utime, &pri->usrlast);
1097*7c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
1098*7c478bd9Sstevel@tonic-gate 					pri->usrlast = Lsp->pr_utime;
1099*7c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&count_lock);
1100*7c478bd9Sstevel@tonic-gate 				} else if (Eflag) {
1101*7c478bd9Sstevel@tonic-gate 					putpname(pri);
1102*7c478bd9Sstevel@tonic-gate 					timestamp(pri);
1103*7c478bd9Sstevel@tonic-gate 					(void) printf("%s\n", ow_string);
1104*7c478bd9Sstevel@tonic-gate 					free(ow_string);
1105*7c478bd9Sstevel@tonic-gate 					ow_string = NULL;
1106*7c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
1107*7c478bd9Sstevel@tonic-gate 				}
1108*7c478bd9Sstevel@tonic-gate 				ow_in_effect = 0;
1109*7c478bd9Sstevel@tonic-gate 				Psetsysentry(Proc, &running_set);
1110*7c478bd9Sstevel@tonic-gate 			}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 			/*
1113*7c478bd9Sstevel@tonic-gate 			 * Special cases.  Most syscalls are traced on exit.
1114*7c478bd9Sstevel@tonic-gate 			 */
1115*7c478bd9Sstevel@tonic-gate 			switch (what) {
1116*7c478bd9Sstevel@tonic-gate 			case SYS_exit:			/* exit() */
1117*7c478bd9Sstevel@tonic-gate 			case SYS_lwp_exit:		/* lwp_exit() */
1118*7c478bd9Sstevel@tonic-gate 			case SYS_context:		/* [get|set]context() */
1119*7c478bd9Sstevel@tonic-gate 			case SYS_evtrapret:		/* evtrapret() */
1120*7c478bd9Sstevel@tonic-gate 				if (dotrace && cflag &&
1121*7c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
1122*7c478bd9Sstevel@tonic-gate 					ow_in_effect = 1;
1123*7c478bd9Sstevel@tonic-gate 					ow_syscall = what;
1124*7c478bd9Sstevel@tonic-gate 					ow_subcode = getsubcode(pri);
1125*7c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
1126*7c478bd9Sstevel@tonic-gate 					running_set =
1127*7c478bd9Sstevel@tonic-gate 					    (Pstatus(Proc))->pr_sysentry;
1128*7c478bd9Sstevel@tonic-gate 					Psetsysentry(Proc, &full_set);
1129*7c478bd9Sstevel@tonic-gate 				} else if (dotrace && Eflag &&
1130*7c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
1131*7c478bd9Sstevel@tonic-gate 					(void) sysentry(pri, dotrace);
1132*7c478bd9Sstevel@tonic-gate 					ow_in_effect = 1;
1133*7c478bd9Sstevel@tonic-gate 					ow_string = my_malloc(
1134*7c478bd9Sstevel@tonic-gate 					    strlen(pri->sys_string) + 1, NULL);
1135*7c478bd9Sstevel@tonic-gate 					(void) strcpy(ow_string,
1136*7c478bd9Sstevel@tonic-gate 					    pri->sys_string);
1137*7c478bd9Sstevel@tonic-gate 					running_set =
1138*7c478bd9Sstevel@tonic-gate 					    (Pstatus(Proc))->pr_sysentry;
1139*7c478bd9Sstevel@tonic-gate 					Psetsysentry(Proc, &full_set);
1140*7c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
1141*7c478bd9Sstevel@tonic-gate 				} else if (dotrace &&
1142*7c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
1143*7c478bd9Sstevel@tonic-gate 					(void) sysentry(pri, dotrace);
1144*7c478bd9Sstevel@tonic-gate 					putpname(pri);
1145*7c478bd9Sstevel@tonic-gate 					timestamp(pri);
1146*7c478bd9Sstevel@tonic-gate 					pri->length +=
1147*7c478bd9Sstevel@tonic-gate 						printf("%s\n", pri->sys_string);
1148*7c478bd9Sstevel@tonic-gate 					Flush();
1149*7c478bd9Sstevel@tonic-gate 				}
1150*7c478bd9Sstevel@tonic-gate 				pri->sys_leng = 0;
1151*7c478bd9Sstevel@tonic-gate 				*pri->sys_string = '\0';
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 				if (what == SYS_exit)
1154*7c478bd9Sstevel@tonic-gate 					exit_called = TRUE;
1155*7c478bd9Sstevel@tonic-gate 				break;
1156*7c478bd9Sstevel@tonic-gate 			case SYS_exec:
1157*7c478bd9Sstevel@tonic-gate 			case SYS_execve:
1158*7c478bd9Sstevel@tonic-gate 				(void) sysentry(pri, dotrace);
1159*7c478bd9Sstevel@tonic-gate 				if (dotrace && !cflag &&
1160*7c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
1161*7c478bd9Sstevel@tonic-gate 					pri->exec_string =
1162*7c478bd9Sstevel@tonic-gate 						my_realloc(pri->exec_string,
1163*7c478bd9Sstevel@tonic-gate 						strlen(pri->sys_string) + 1,
1164*7c478bd9Sstevel@tonic-gate 						NULL);
1165*7c478bd9Sstevel@tonic-gate 					(void) strcpy(pri->exec_pname,
1166*7c478bd9Sstevel@tonic-gate 						pri->pname);
1167*7c478bd9Sstevel@tonic-gate 					(void) strcpy(pri->exec_string,
1168*7c478bd9Sstevel@tonic-gate 						pri->sys_string);
1169*7c478bd9Sstevel@tonic-gate 					pri->length += strlen(pri->sys_string);
1170*7c478bd9Sstevel@tonic-gate 					pri->exec_lwpid = Lsp->pr_lwpid;
1171*7c478bd9Sstevel@tonic-gate 				}
1172*7c478bd9Sstevel@tonic-gate 				pri->sys_leng = 0;
1173*7c478bd9Sstevel@tonic-gate 				*pri->sys_string = '\0';
1174*7c478bd9Sstevel@tonic-gate 				break;
1175*7c478bd9Sstevel@tonic-gate 			default:
1176*7c478bd9Sstevel@tonic-gate 				if (dotrace && (cflag || Eflag) &&
1177*7c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
1178*7c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
1179*7c478bd9Sstevel@tonic-gate 				}
1180*7c478bd9Sstevel@tonic-gate 				break;
1181*7c478bd9Sstevel@tonic-gate 			}
1182*7c478bd9Sstevel@tonic-gate 			if (dotrace && Tflag && !first &&
1183*7c478bd9Sstevel@tonic-gate 			    (prismember(&syshang, what) ||
1184*7c478bd9Sstevel@tonic-gate 			    (exit_called && prismember(&syshang, SYS_exit))))
1185*7c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
1186*7c478bd9Sstevel@tonic-gate 			break;
1187*7c478bd9Sstevel@tonic-gate 		case PR_SYSEXIT:
1188*7c478bd9Sstevel@tonic-gate 			/* check for write open of a /proc file */
1189*7c478bd9Sstevel@tonic-gate 			if ((what == SYS_open || what == SYS_open64)) {
1190*7c478bd9Sstevel@tonic-gate 				(void) sysentry(pri, dotrace);
1191*7c478bd9Sstevel@tonic-gate 				pri->Errno = Lsp->pr_errno;
1192*7c478bd9Sstevel@tonic-gate 				pri->ErrPriv = Lsp->pr_errpriv;
1193*7c478bd9Sstevel@tonic-gate 				if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
1194*7c478bd9Sstevel@tonic-gate 				    pri->sys_valid &&
1195*7c478bd9Sstevel@tonic-gate 				    (pri->sys_nargs > 1 &&
1196*7c478bd9Sstevel@tonic-gate 				    (pri->sys_args[1]&0x3) != O_RDONLY)) {
1197*7c478bd9Sstevel@tonic-gate 					int rv = checkproc(pri);
1198*7c478bd9Sstevel@tonic-gate 					if (rv == 1 && Fflag != PGRAB_FORCE) {
1199*7c478bd9Sstevel@tonic-gate 						/*
1200*7c478bd9Sstevel@tonic-gate 						 * The process opened itself
1201*7c478bd9Sstevel@tonic-gate 						 * and no -F flag was specified.
1202*7c478bd9Sstevel@tonic-gate 						 * Just print the open() call
1203*7c478bd9Sstevel@tonic-gate 						 * and let go of the process.
1204*7c478bd9Sstevel@tonic-gate 						 */
1205*7c478bd9Sstevel@tonic-gate 						if (dotrace && !cflag &&
1206*7c478bd9Sstevel@tonic-gate 						    prismember(&trace, what)) {
1207*7c478bd9Sstevel@tonic-gate 							putpname(pri);
1208*7c478bd9Sstevel@tonic-gate 							timestamp(pri);
1209*7c478bd9Sstevel@tonic-gate 							(void) printf("%s\n",
1210*7c478bd9Sstevel@tonic-gate 							    pri->sys_string);
1211*7c478bd9Sstevel@tonic-gate 							Flush();
1212*7c478bd9Sstevel@tonic-gate 						}
1213*7c478bd9Sstevel@tonic-gate 						sigusr1 = 1;
1214*7c478bd9Sstevel@tonic-gate 						(void) mutex_unlock(
1215*7c478bd9Sstevel@tonic-gate 							&truss_lock);
1216*7c478bd9Sstevel@tonic-gate 						goto out;
1217*7c478bd9Sstevel@tonic-gate 					}
1218*7c478bd9Sstevel@tonic-gate 					if (rv == 2) {
1219*7c478bd9Sstevel@tonic-gate 						/*
1220*7c478bd9Sstevel@tonic-gate 						 * Process opened someone else.
1221*7c478bd9Sstevel@tonic-gate 						 * The open is being reissued.
1222*7c478bd9Sstevel@tonic-gate 						 * Don't report this one.
1223*7c478bd9Sstevel@tonic-gate 						 */
1224*7c478bd9Sstevel@tonic-gate 						pri->sys_leng = 0;
1225*7c478bd9Sstevel@tonic-gate 						*pri->sys_string = '\0';
1226*7c478bd9Sstevel@tonic-gate 						pri->sys_nargs = 0;
1227*7c478bd9Sstevel@tonic-gate 						break;
1228*7c478bd9Sstevel@tonic-gate 					}
1229*7c478bd9Sstevel@tonic-gate 				}
1230*7c478bd9Sstevel@tonic-gate 			}
1231*7c478bd9Sstevel@tonic-gate 			if ((what == SYS_exec || what == SYS_execve) &&
1232*7c478bd9Sstevel@tonic-gate 			    pri->Errno == 0) {
1233*7c478bd9Sstevel@tonic-gate 				/*
1234*7c478bd9Sstevel@tonic-gate 				 * Refresh the data model on exec() in case it
1235*7c478bd9Sstevel@tonic-gate 				 * is different from the parent.  Lwait()
1236*7c478bd9Sstevel@tonic-gate 				 * doesn't update process-wide status, so we
1237*7c478bd9Sstevel@tonic-gate 				 * have to explicitly call Pstopstatus() to get
1238*7c478bd9Sstevel@tonic-gate 				 * the new state.
1239*7c478bd9Sstevel@tonic-gate 				 */
1240*7c478bd9Sstevel@tonic-gate 				(void) Pstopstatus(Proc, PCNULL, 0);
1241*7c478bd9Sstevel@tonic-gate 				data_model = Psp->pr_dmodel;
1242*7c478bd9Sstevel@tonic-gate 			}
1243*7c478bd9Sstevel@tonic-gate 			if (sysexit(pri, dotrace))
1244*7c478bd9Sstevel@tonic-gate 				Flush();
1245*7c478bd9Sstevel@tonic-gate 			if (what == SYS_lwp_create && pri->Rval1 != 0) {
1246*7c478bd9Sstevel@tonic-gate 				struct ps_lwphandle *new_Lwp;
1247*7c478bd9Sstevel@tonic-gate 				lwpid_t lwpid;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 				if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
1250*7c478bd9Sstevel@tonic-gate 					if (thr_create(NULL, 0, worker_thread,
1251*7c478bd9Sstevel@tonic-gate 					    new_Lwp, THR_BOUND | THR_SUSPENDED,
1252*7c478bd9Sstevel@tonic-gate 					    &lwpid) != 0)
1253*7c478bd9Sstevel@tonic-gate 						abend("cannot create lwp ",
1254*7c478bd9Sstevel@tonic-gate 						    "to follow child lwp");
1255*7c478bd9Sstevel@tonic-gate 					insert_lwpid(lwpid);
1256*7c478bd9Sstevel@tonic-gate 					(void) thr_continue(lwpid);
1257*7c478bd9Sstevel@tonic-gate 				}
1258*7c478bd9Sstevel@tonic-gate 			}
1259*7c478bd9Sstevel@tonic-gate 			pri->sys_nargs = 0;
1260*7c478bd9Sstevel@tonic-gate 			if (dotrace && Tflag && !first &&
1261*7c478bd9Sstevel@tonic-gate 			    prismember(&syshang, what))
1262*7c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
1263*7c478bd9Sstevel@tonic-gate 			if ((what == SYS_exec || what == SYS_execve) &&
1264*7c478bd9Sstevel@tonic-gate 			    pri->Errno == 0) {
1265*7c478bd9Sstevel@tonic-gate 				is_vfork_child = FALSE;
1266*7c478bd9Sstevel@tonic-gate 				reset_breakpoints();
1267*7c478bd9Sstevel@tonic-gate 				/*
1268*7c478bd9Sstevel@tonic-gate 				 * exec() resets the calling LWP's lwpid to 1.
1269*7c478bd9Sstevel@tonic-gate 				 * If the LWP has changed its lwpid, then
1270*7c478bd9Sstevel@tonic-gate 				 * we have to free and re-grab the LWP
1271*7c478bd9Sstevel@tonic-gate 				 * in order to keep libproc consistent.
1272*7c478bd9Sstevel@tonic-gate 				 * This "cannot fail".
1273*7c478bd9Sstevel@tonic-gate 				 */
1274*7c478bd9Sstevel@tonic-gate 				if (who != Lsp->pr_lwpid) {
1275*7c478bd9Sstevel@tonic-gate 					/*
1276*7c478bd9Sstevel@tonic-gate 					 * We must wait for all of our
1277*7c478bd9Sstevel@tonic-gate 					 * siblings to terminate.
1278*7c478bd9Sstevel@tonic-gate 					 */
1279*7c478bd9Sstevel@tonic-gate 					while (truss_nlwp > 1)
1280*7c478bd9Sstevel@tonic-gate 						(void) cond_wait(&truss_cv,
1281*7c478bd9Sstevel@tonic-gate 							&truss_lock);
1282*7c478bd9Sstevel@tonic-gate 					who = Lsp->pr_lwpid;
1283*7c478bd9Sstevel@tonic-gate 					Lfree(Lwp);
1284*7c478bd9Sstevel@tonic-gate 					pri->Lwp = Lwp =
1285*7c478bd9Sstevel@tonic-gate 						Lgrab(Proc, who, &gcode);
1286*7c478bd9Sstevel@tonic-gate 					if (Lwp == NULL)
1287*7c478bd9Sstevel@tonic-gate 						abend("Lgrab error: ",
1288*7c478bd9Sstevel@tonic-gate 							Lgrab_error(gcode));
1289*7c478bd9Sstevel@tonic-gate 					pri->lwpstat = Lsp = Lstatus(Lwp);
1290*7c478bd9Sstevel@tonic-gate 				}
1291*7c478bd9Sstevel@tonic-gate 			}
1292*7c478bd9Sstevel@tonic-gate 			break;
1293*7c478bd9Sstevel@tonic-gate 		default:
1294*7c478bd9Sstevel@tonic-gate 			req_flag = 0;
1295*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1296*7c478bd9Sstevel@tonic-gate 				"unknown reason for stopping: %d/%d\n",
1297*7c478bd9Sstevel@tonic-gate 				Lsp->pr_why, what);
1298*7c478bd9Sstevel@tonic-gate 			abend(NULL, NULL);
1299*7c478bd9Sstevel@tonic-gate 		}
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 		if (pri->child) {	/* controlled process fork()ed */
1302*7c478bd9Sstevel@tonic-gate 			if (fflag || Dynpat != NULL)  {
1303*7c478bd9Sstevel@tonic-gate 				if (Lsp->pr_why == PR_SYSEXIT &&
1304*7c478bd9Sstevel@tonic-gate 				    Lsp->pr_what == SYS_vfork)
1305*7c478bd9Sstevel@tonic-gate 					is_vfork_child = TRUE;
1306*7c478bd9Sstevel@tonic-gate 				if (control(pri, pri->child)) {
1307*7c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&truss_lock);
1308*7c478bd9Sstevel@tonic-gate 					pri->child = 0;
1309*7c478bd9Sstevel@tonic-gate 					if (!fflag) {
1310*7c478bd9Sstevel@tonic-gate 						/*
1311*7c478bd9Sstevel@tonic-gate 						 * If this is vfork(), then
1312*7c478bd9Sstevel@tonic-gate 						 * this clears the breakpoints
1313*7c478bd9Sstevel@tonic-gate 						 * in the parent's address space
1314*7c478bd9Sstevel@tonic-gate 						 * as well as in the child's.
1315*7c478bd9Sstevel@tonic-gate 						 */
1316*7c478bd9Sstevel@tonic-gate 						clear_breakpoints();
1317*7c478bd9Sstevel@tonic-gate 						Prelease(Proc, PRELEASE_CLEAR);
1318*7c478bd9Sstevel@tonic-gate 						_exit(0);
1319*7c478bd9Sstevel@tonic-gate 					}
1320*7c478bd9Sstevel@tonic-gate 					main_thread(FALSE);
1321*7c478bd9Sstevel@tonic-gate 					/* NOTREACHED */
1322*7c478bd9Sstevel@tonic-gate 				}
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 				/*
1325*7c478bd9Sstevel@tonic-gate 				 * Here, we are still the parent truss.
1326*7c478bd9Sstevel@tonic-gate 				 * If the child messed with the breakpoints and
1327*7c478bd9Sstevel@tonic-gate 				 * this is vfork(), we have to set them again.
1328*7c478bd9Sstevel@tonic-gate 				 */
1329*7c478bd9Sstevel@tonic-gate 				if (Dynpat != NULL && is_vfork_child)
1330*7c478bd9Sstevel@tonic-gate 					reset_traps = TRUE;
1331*7c478bd9Sstevel@tonic-gate 				is_vfork_child = FALSE;
1332*7c478bd9Sstevel@tonic-gate 			}
1333*7c478bd9Sstevel@tonic-gate 			pri->child = 0;
1334*7c478bd9Sstevel@tonic-gate 		}
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 		if (leave_it_hung) {
1337*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&truss_lock);
1338*7c478bd9Sstevel@tonic-gate 			break;
1339*7c478bd9Sstevel@tonic-gate 		}
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 		if (reset_traps) {
1342*7c478bd9Sstevel@tonic-gate 			/*
1343*7c478bd9Sstevel@tonic-gate 			 * To recover from vfork, we must catch the lwp
1344*7c478bd9Sstevel@tonic-gate 			 * that issued the vfork() when it returns to user
1345*7c478bd9Sstevel@tonic-gate 			 * level, with all other lwps remaining stopped.
1346*7c478bd9Sstevel@tonic-gate 			 * For this purpose, we direct all lwps to stop
1347*7c478bd9Sstevel@tonic-gate 			 * and set the vfork()ing lwp running with the
1348*7c478bd9Sstevel@tonic-gate 			 * PRSTEP flag.  We expect to capture it when
1349*7c478bd9Sstevel@tonic-gate 			 * it stops again showing PR_FAULTED/FLTTRACE.
1350*7c478bd9Sstevel@tonic-gate 			 * We are holding truss_lock, so no other threads
1351*7c478bd9Sstevel@tonic-gate 			 * in truss will set any other lwps in the victim
1352*7c478bd9Sstevel@tonic-gate 			 * process running.
1353*7c478bd9Sstevel@tonic-gate 			 */
1354*7c478bd9Sstevel@tonic-gate 			reset_traps = FALSE;
1355*7c478bd9Sstevel@tonic-gate 			(void) Pstop(Proc, 0);
1356*7c478bd9Sstevel@tonic-gate 			(void) Lsetrun(Lwp, 0, PRSTEP);
1357*7c478bd9Sstevel@tonic-gate 			do {
1358*7c478bd9Sstevel@tonic-gate 				(void) Lwait(Lwp, 0);
1359*7c478bd9Sstevel@tonic-gate 			} while (Lstate(Lwp) == PS_RUN);
1360*7c478bd9Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_STOP &&
1361*7c478bd9Sstevel@tonic-gate 			    Lsp->pr_why == PR_FAULTED &&
1362*7c478bd9Sstevel@tonic-gate 			    Lsp->pr_what == FLTTRACE) {
1363*7c478bd9Sstevel@tonic-gate 				reestablish_traps();
1364*7c478bd9Sstevel@tonic-gate 				(void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
1365*7c478bd9Sstevel@tonic-gate 			} else {
1366*7c478bd9Sstevel@tonic-gate 				(void) printf("%s\t*** Expected PR_FAULTED/"
1367*7c478bd9Sstevel@tonic-gate 					"FLTTRACE stop following vfork()\n",
1368*7c478bd9Sstevel@tonic-gate 					pri->pname);
1369*7c478bd9Sstevel@tonic-gate 			}
1370*7c478bd9Sstevel@tonic-gate 		}
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_STOP) {
1373*7c478bd9Sstevel@tonic-gate 			int flags = 0;
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 			if (interrupt | sigusr1) {
1376*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
1377*7c478bd9Sstevel@tonic-gate 				break;
1378*7c478bd9Sstevel@tonic-gate 			}
1379*7c478bd9Sstevel@tonic-gate 			/*
1380*7c478bd9Sstevel@tonic-gate 			 * If we must leave this lwp hung is sympathy with
1381*7c478bd9Sstevel@tonic-gate 			 * another lwp that is being left hung on purpose,
1382*7c478bd9Sstevel@tonic-gate 			 * then push the state onward toward PR_REQUESTED.
1383*7c478bd9Sstevel@tonic-gate 			 */
1384*7c478bd9Sstevel@tonic-gate 			if (leave_hung) {
1385*7c478bd9Sstevel@tonic-gate 				if (Lsp->pr_why == PR_REQUESTED) {
1386*7c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&truss_lock);
1387*7c478bd9Sstevel@tonic-gate 					break;
1388*7c478bd9Sstevel@tonic-gate 				}
1389*7c478bd9Sstevel@tonic-gate 				flags |= PRSTOP;
1390*7c478bd9Sstevel@tonic-gate 			}
1391*7c478bd9Sstevel@tonic-gate 			if (Lsetrun(Lwp, 0, flags) != 0 &&
1392*7c478bd9Sstevel@tonic-gate 			    Lstate(Lwp) != PS_LOST &&
1393*7c478bd9Sstevel@tonic-gate 			    Lstate(Lwp) != PS_UNDEAD) {
1394*7c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
1395*7c478bd9Sstevel@tonic-gate 				perror("Lsetrun");
1396*7c478bd9Sstevel@tonic-gate 				abend("cannot start subject lwp", NULL);
1397*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1398*7c478bd9Sstevel@tonic-gate 			}
1399*7c478bd9Sstevel@tonic-gate 		}
1400*7c478bd9Sstevel@tonic-gate 		first = FALSE;
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&truss_lock);
1403*7c478bd9Sstevel@tonic-gate 	}
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate out:
1406*7c478bd9Sstevel@tonic-gate 	if (Lstate(Lwp) != PS_UNDEAD) {
1407*7c478bd9Sstevel@tonic-gate 		(void) Lstop(Lwp, MILLISEC);
1408*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
1409*7c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_STOP &&
1410*7c478bd9Sstevel@tonic-gate 		    Lsp->pr_why == PR_FAULTED &&
1411*7c478bd9Sstevel@tonic-gate 		    Lsp->pr_what == FLTBPT)
1412*7c478bd9Sstevel@tonic-gate 			(void) function_trace(pri, 0, 1, dotrace);
1413*7c478bd9Sstevel@tonic-gate 	} else {
1414*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
1415*7c478bd9Sstevel@tonic-gate 	}
1416*7c478bd9Sstevel@tonic-gate 
1417*7c478bd9Sstevel@tonic-gate 	/*
1418*7c478bd9Sstevel@tonic-gate 	 * The first thread through needs to instruct all other
1419*7c478bd9Sstevel@tonic-gate 	 * threads to stop -- they're not going to stop on their own.
1420*7c478bd9Sstevel@tonic-gate 	 */
1421*7c478bd9Sstevel@tonic-gate 	if (nstopped == 0)
1422*7c478bd9Sstevel@tonic-gate 		(void) Pdstop(Proc);
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	/*
1425*7c478bd9Sstevel@tonic-gate 	 * Once the last thread has reached this point, then and only then is
1426*7c478bd9Sstevel@tonic-gate 	 * it safe to remove breakpoints and other instrumentation. Since
1427*7c478bd9Sstevel@tonic-gate 	 * breakpoints are executed without truss_lock held, a monitor thread
1428*7c478bd9Sstevel@tonic-gate 	 * can't exit until all breakpoints have been removed, and we can't
1429*7c478bd9Sstevel@tonic-gate 	 * be sure the procedure to execute a breakpoint won't temporarily
1430*7c478bd9Sstevel@tonic-gate 	 * reinstall a breakpont. Accordingly, we need to wait until all
1431*7c478bd9Sstevel@tonic-gate 	 * threads are in a known state.
1432*7c478bd9Sstevel@tonic-gate 	 */
1433*7c478bd9Sstevel@tonic-gate 	if (++nstopped == truss_nlwp) {
1434*7c478bd9Sstevel@tonic-gate 		/*
1435*7c478bd9Sstevel@tonic-gate 		 * All threads should already be sufficiently stopped, but
1436*7c478bd9Sstevel@tonic-gate 		 * just to be safe...
1437*7c478bd9Sstevel@tonic-gate 		 */
1438*7c478bd9Sstevel@tonic-gate 		(void) Pstop(Proc, MILLISEC);
1439*7c478bd9Sstevel@tonic-gate 		clear_breakpoints();
1440*7c478bd9Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_forkall, FALSE);
1441*7c478bd9Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_vfork, FALSE);
1442*7c478bd9Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_fork1, FALSE);
1443*7c478bd9Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_FORK);
1444*7c478bd9Sstevel@tonic-gate 		Psync(Proc);
1445*7c478bd9Sstevel@tonic-gate 		fflag = 0;
1446*7c478bd9Sstevel@tonic-gate 		go = 1;
1447*7c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&truss_cv);
1448*7c478bd9Sstevel@tonic-gate 	} else {
1449*7c478bd9Sstevel@tonic-gate 		while (!go)
1450*7c478bd9Sstevel@tonic-gate 			(void) cond_wait(&truss_cv, &truss_lock);
1451*7c478bd9Sstevel@tonic-gate 	}
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	if (!leave_it_hung && Lstate(Lwp) == PS_STOP)
1454*7c478bd9Sstevel@tonic-gate 		(void) Lsetrun(Lwp, 0, 0);
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
1457*7c478bd9Sstevel@tonic-gate 
1458*7c478bd9Sstevel@tonic-gate 	if (dotrace && ow_in_effect) {
1459*7c478bd9Sstevel@tonic-gate 		if (cflag) {
1460*7c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&count_lock);
1461*7c478bd9Sstevel@tonic-gate 			scp = Cp->syscount[ow_syscall];
1462*7c478bd9Sstevel@tonic-gate 			if (ow_subcode != -1)
1463*7c478bd9Sstevel@tonic-gate 				scp += ow_subcode;
1464*7c478bd9Sstevel@tonic-gate 			scp->count++;
1465*7c478bd9Sstevel@tonic-gate 			accumulate(&scp->stime,
1466*7c478bd9Sstevel@tonic-gate 			    &Lsp->pr_stime, &pri->syslast);
1467*7c478bd9Sstevel@tonic-gate 			accumulate(&Cp->usrtotal,
1468*7c478bd9Sstevel@tonic-gate 			    &Lsp->pr_utime, &pri->usrlast);
1469*7c478bd9Sstevel@tonic-gate 			pri->syslast = Lsp->pr_stime;
1470*7c478bd9Sstevel@tonic-gate 			pri->usrlast = Lsp->pr_utime;
1471*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&count_lock);
1472*7c478bd9Sstevel@tonic-gate 		} else if (Eflag) {
1473*7c478bd9Sstevel@tonic-gate 			putpname(pri);
1474*7c478bd9Sstevel@tonic-gate 			timestamp(pri);
1475*7c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", ow_string);
1476*7c478bd9Sstevel@tonic-gate 			free(ow_string);
1477*7c478bd9Sstevel@tonic-gate 			ow_string = NULL;
1478*7c478bd9Sstevel@tonic-gate 			pri->syslast = Lsp->pr_stime;
1479*7c478bd9Sstevel@tonic-gate 		}
1480*7c478bd9Sstevel@tonic-gate 		ow_in_effect = 0;
1481*7c478bd9Sstevel@tonic-gate 		Psetsysentry(Proc, &running_set);
1482*7c478bd9Sstevel@tonic-gate 	}
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&truss_lock);	/* fork1() protection */
1485*7c478bd9Sstevel@tonic-gate 	(void) Lfree(Lwp);
1486*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 	return ((void *)leave_it_hung);
1489*7c478bd9Sstevel@tonic-gate }
1490*7c478bd9Sstevel@tonic-gate 
1491*7c478bd9Sstevel@tonic-gate /*
1492*7c478bd9Sstevel@tonic-gate  * Give a base date for time stamps, adjusted to the
1493*7c478bd9Sstevel@tonic-gate  * stop time of the selected (first or created) process.
1494*7c478bd9Sstevel@tonic-gate  */
1495*7c478bd9Sstevel@tonic-gate void
1496*7c478bd9Sstevel@tonic-gate setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
1497*7c478bd9Sstevel@tonic-gate {
1498*7c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp = Pstatus(Proc);
1499*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&count_lock);
1500*7c478bd9Sstevel@tonic-gate 	Cp->basetime = Psp->pr_lwp.pr_tstamp;
1501*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&count_lock);
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	if ((dflag|Dflag) && !cflag) {
1504*7c478bd9Sstevel@tonic-gate 		const struct tm *ptm;
1505*7c478bd9Sstevel@tonic-gate 		const char *ptime;
1506*7c478bd9Sstevel@tonic-gate 		const char *pdst;
1507*7c478bd9Sstevel@tonic-gate 		hrtime_t delta = basehrtime -
1508*7c478bd9Sstevel@tonic-gate 			((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
1509*7c478bd9Sstevel@tonic-gate 			Cp->basetime.tv_nsec);
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 		if (delta > 0) {
1512*7c478bd9Sstevel@tonic-gate 			basedate->tv_sec -= (time_t)(delta / NANOSEC);
1513*7c478bd9Sstevel@tonic-gate 			basedate->tv_usec -= (delta % NANOSEC) / 1000;
1514*7c478bd9Sstevel@tonic-gate 			if (basedate->tv_usec < 0) {
1515*7c478bd9Sstevel@tonic-gate 				basedate->tv_sec--;
1516*7c478bd9Sstevel@tonic-gate 				basedate->tv_usec += MICROSEC;
1517*7c478bd9Sstevel@tonic-gate 			}
1518*7c478bd9Sstevel@tonic-gate 		}
1519*7c478bd9Sstevel@tonic-gate 		ptm = localtime(&basedate->tv_sec);
1520*7c478bd9Sstevel@tonic-gate 		ptime = asctime(ptm);
1521*7c478bd9Sstevel@tonic-gate 		if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
1522*7c478bd9Sstevel@tonic-gate 			pdst = "???";
1523*7c478bd9Sstevel@tonic-gate 		if (dflag) {
1524*7c478bd9Sstevel@tonic-gate 			(void) printf(
1525*7c478bd9Sstevel@tonic-gate 			    "Base time stamp:  %ld.%4.4ld  [ %.20s%s %.4s ]\n",
1526*7c478bd9Sstevel@tonic-gate 			    basedate->tv_sec, basedate->tv_usec / 100,
1527*7c478bd9Sstevel@tonic-gate 			    ptime, pdst, ptime + 20);
1528*7c478bd9Sstevel@tonic-gate 			Flush();
1529*7c478bd9Sstevel@tonic-gate 		}
1530*7c478bd9Sstevel@tonic-gate 	}
1531*7c478bd9Sstevel@tonic-gate }
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate /*
1534*7c478bd9Sstevel@tonic-gate  * Performs per-process initializations. If truss is following a victim
1535*7c478bd9Sstevel@tonic-gate  * process it will fork additional truss processes to follow new processes
1536*7c478bd9Sstevel@tonic-gate  * created.  Here is where each new truss process gets its per-process data
1537*7c478bd9Sstevel@tonic-gate  * initialized.
1538*7c478bd9Sstevel@tonic-gate  */
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate void
1541*7c478bd9Sstevel@tonic-gate per_proc_init()
1542*7c478bd9Sstevel@tonic-gate {
1543*7c478bd9Sstevel@tonic-gate 	void *pmem;
1544*7c478bd9Sstevel@tonic-gate 	struct timeval basedate;
1545*7c478bd9Sstevel@tonic-gate 	hrtime_t basehrtime;
1546*7c478bd9Sstevel@tonic-gate 	struct syscount *scp;
1547*7c478bd9Sstevel@tonic-gate 	int i;
1548*7c478bd9Sstevel@tonic-gate 	timestruc_t c_basetime;
1549*7c478bd9Sstevel@tonic-gate 
1550*7c478bd9Sstevel@tonic-gate 	/* Make sure we only configure the basetime for the first truss proc */
1551*7c478bd9Sstevel@tonic-gate 
1552*7c478bd9Sstevel@tonic-gate 	if (Cp == NULL) {
1553*7c478bd9Sstevel@tonic-gate 		pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
1554*7c478bd9Sstevel@tonic-gate 		    sizeof (struct syscount), NULL);
1555*7c478bd9Sstevel@tonic-gate 		Cp = (struct counts *)pmem;
1556*7c478bd9Sstevel@tonic-gate 		basehrtime = gethrtime();
1557*7c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&basedate, NULL);
1558*7c478bd9Sstevel@tonic-gate 		setup_basetime(basehrtime, &basedate);
1559*7c478bd9Sstevel@tonic-gate 	}
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate 	c_basetime = Cp->basetime;
1562*7c478bd9Sstevel@tonic-gate 
1563*7c478bd9Sstevel@tonic-gate 	(void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
1564*7c478bd9Sstevel@tonic-gate 	    sizeof (struct syscount));
1565*7c478bd9Sstevel@tonic-gate 
1566*7c478bd9Sstevel@tonic-gate 	Cp->basetime = c_basetime;
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 	if (fcall_tbl != NULL)
1569*7c478bd9Sstevel@tonic-gate 		destroy_hash(fcall_tbl);
1570*7c478bd9Sstevel@tonic-gate 	fcall_tbl = init_hash(4096);
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&count_lock);
1573*7c478bd9Sstevel@tonic-gate 	scp = (struct syscount *)(Cp + 1);
1574*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= PRMAXSYS; i++) {
1575*7c478bd9Sstevel@tonic-gate 		Cp->syscount[i] = scp;
1576*7c478bd9Sstevel@tonic-gate 		scp += nsubcodes(i);
1577*7c478bd9Sstevel@tonic-gate 	}
1578*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&count_lock);
1579*7c478bd9Sstevel@tonic-gate }
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 
1582*7c478bd9Sstevel@tonic-gate /*
1583*7c478bd9Sstevel@tonic-gate  * Writes child state to a tempfile where it can be read and
1584*7c478bd9Sstevel@tonic-gate  * accumulated by the parent process. The file descriptor is shared
1585*7c478bd9Sstevel@tonic-gate  * among the processes.  Ordering of writes does not matter, it is, however,
1586*7c478bd9Sstevel@tonic-gate  * necessary to ensure that all writes are atomic.
1587*7c478bd9Sstevel@tonic-gate  */
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate void
1590*7c478bd9Sstevel@tonic-gate child_to_file()
1591*7c478bd9Sstevel@tonic-gate {
1592*7c478bd9Sstevel@tonic-gate 	hiter_t *itr;
1593*7c478bd9Sstevel@tonic-gate 	hentry_t *ntry;
1594*7c478bd9Sstevel@tonic-gate 	hdntry_t fentry;
1595*7c478bd9Sstevel@tonic-gate 	char *s = NULL;
1596*7c478bd9Sstevel@tonic-gate 	char *t = NULL;
1597*7c478bd9Sstevel@tonic-gate 	unsigned char *buf = NULL;
1598*7c478bd9Sstevel@tonic-gate 	size_t bufsz = 0;
1599*7c478bd9Sstevel@tonic-gate 	size_t i = 0;
1600*7c478bd9Sstevel@tonic-gate 	size_t j = 0;
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 	/* ensure that we are in fact a child process */
1603*7c478bd9Sstevel@tonic-gate 	if (!descendent)
1604*7c478bd9Sstevel@tonic-gate 		return;
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate 	/* enumerate fcall_tbl (tbl locked until freed) */
1607*7c478bd9Sstevel@tonic-gate 	if (Dynpat != NULL) {
1608*7c478bd9Sstevel@tonic-gate 		itr = iterate_hash(fcall_tbl);
1609*7c478bd9Sstevel@tonic-gate 
1610*7c478bd9Sstevel@tonic-gate 		ntry = iter_next(itr);
1611*7c478bd9Sstevel@tonic-gate 		while (ntry != NULL) {
1612*7c478bd9Sstevel@tonic-gate 			fentry.type = HD_hashntry;
1613*7c478bd9Sstevel@tonic-gate 			fentry.count = ntry->count;
1614*7c478bd9Sstevel@tonic-gate 			s = ntry->key;
1615*7c478bd9Sstevel@tonic-gate 			t = ntry->lib;
1616*7c478bd9Sstevel@tonic-gate 			i = strlen(s) + 1;
1617*7c478bd9Sstevel@tonic-gate 			j = strlen(t) + 1;
1618*7c478bd9Sstevel@tonic-gate 			fentry.sz_key = i;
1619*7c478bd9Sstevel@tonic-gate 			fentry.sz_lib = j;
1620*7c478bd9Sstevel@tonic-gate 			if (i + sizeof (fentry) > bufsz) {
1621*7c478bd9Sstevel@tonic-gate 				buf = my_realloc(buf, i + j + sizeof (fentry),
1622*7c478bd9Sstevel@tonic-gate 				    NULL);
1623*7c478bd9Sstevel@tonic-gate 				bufsz = i + j + sizeof (fentry);
1624*7c478bd9Sstevel@tonic-gate 			}
1625*7c478bd9Sstevel@tonic-gate 			(void) memcpy(buf, &fentry, sizeof (fentry));
1626*7c478bd9Sstevel@tonic-gate 			(void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
1627*7c478bd9Sstevel@tonic-gate 			(void) strlcpy((char *)(buf + sizeof (fentry) + j),
1628*7c478bd9Sstevel@tonic-gate 			    s, i);
1629*7c478bd9Sstevel@tonic-gate 			if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
1630*7c478bd9Sstevel@tonic-gate 				abend("Error writing to tmp file", NULL);
1631*7c478bd9Sstevel@tonic-gate 			ntry = iter_next(itr);
1632*7c478bd9Sstevel@tonic-gate 		}
1633*7c478bd9Sstevel@tonic-gate 		iter_free(itr);
1634*7c478bd9Sstevel@tonic-gate 	}
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 	/* Now write the count/syscount structs down */
1637*7c478bd9Sstevel@tonic-gate 	bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
1638*7c478bd9Sstevel@tonic-gate 	    sizeof (struct syscount));
1639*7c478bd9Sstevel@tonic-gate 	buf = my_realloc(buf, bufsz, NULL);
1640*7c478bd9Sstevel@tonic-gate 	fentry.type = HD_cts_syscts;
1641*7c478bd9Sstevel@tonic-gate 	fentry.count = 0;	/* undefined, really */
1642*7c478bd9Sstevel@tonic-gate 	fentry.sz_key = bufsz - sizeof (fentry);
1643*7c478bd9Sstevel@tonic-gate 	fentry.sz_lib = 0;	/* also undefined */
1644*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buf, &fentry, sizeof (fentry));
1645*7c478bd9Sstevel@tonic-gate 	(void) memcpy((char *)(buf + sizeof (fentry)), Cp,
1646*7c478bd9Sstevel@tonic-gate 	    bufsz - sizeof (fentry));
1647*7c478bd9Sstevel@tonic-gate 	if (write(sfd, buf, bufsz) == -1)
1648*7c478bd9Sstevel@tonic-gate 		abend("Error writing cts/syscts to tmpfile", NULL);
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 	free(buf);
1651*7c478bd9Sstevel@tonic-gate }
1652*7c478bd9Sstevel@tonic-gate 
1653*7c478bd9Sstevel@tonic-gate /*
1654*7c478bd9Sstevel@tonic-gate  * The following reads entries from the tempfile back to the parent
1655*7c478bd9Sstevel@tonic-gate  * so that information can be collected and summed for overall statistics.
1656*7c478bd9Sstevel@tonic-gate  * This reads records out of the tempfile.  If they are hash table entries,
1657*7c478bd9Sstevel@tonic-gate  * the record is merged with the hash table kept by the parent process.
1658*7c478bd9Sstevel@tonic-gate  * If the information is a struct count/struct syscount pair, they are
1659*7c478bd9Sstevel@tonic-gate  * copied and added into the count/syscount array kept by the parent.
1660*7c478bd9Sstevel@tonic-gate  */
1661*7c478bd9Sstevel@tonic-gate 
1662*7c478bd9Sstevel@tonic-gate void
1663*7c478bd9Sstevel@tonic-gate file_to_parent()
1664*7c478bd9Sstevel@tonic-gate {
1665*7c478bd9Sstevel@tonic-gate 	hdntry_t ntry;
1666*7c478bd9Sstevel@tonic-gate 	char *s = NULL;
1667*7c478bd9Sstevel@tonic-gate 	char *t = NULL;
1668*7c478bd9Sstevel@tonic-gate 	size_t c_offset = 0;
1669*7c478bd9Sstevel@tonic-gate 	size_t filesz;
1670*7c478bd9Sstevel@tonic-gate 	size_t t_strsz = 0;
1671*7c478bd9Sstevel@tonic-gate 	size_t s_strsz = 0;
1672*7c478bd9Sstevel@tonic-gate 	struct stat fsi;
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 	if (descendent)
1675*7c478bd9Sstevel@tonic-gate 		return;
1676*7c478bd9Sstevel@tonic-gate 
1677*7c478bd9Sstevel@tonic-gate 	if (fstat(sfd, &fsi) == -1)
1678*7c478bd9Sstevel@tonic-gate 		abend("Error stat-ing tempfile", NULL);
1679*7c478bd9Sstevel@tonic-gate 	filesz = fsi.st_size;
1680*7c478bd9Sstevel@tonic-gate 
1681*7c478bd9Sstevel@tonic-gate 	while (c_offset < filesz) {
1682*7c478bd9Sstevel@tonic-gate 		/* first get hdntry */
1683*7c478bd9Sstevel@tonic-gate 		if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
1684*7c478bd9Sstevel@tonic-gate 		    sizeof (hdntry_t))
1685*7c478bd9Sstevel@tonic-gate 			abend("Unable to perform full read of hdntry", NULL);
1686*7c478bd9Sstevel@tonic-gate 		c_offset += sizeof (hdntry_t);
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 		switch (ntry.type) {
1689*7c478bd9Sstevel@tonic-gate 		case HD_hashntry:
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 			/* first get lib string */
1692*7c478bd9Sstevel@tonic-gate 			if (ntry.sz_lib > t_strsz) {
1693*7c478bd9Sstevel@tonic-gate 				t = my_realloc(t, ntry.sz_lib, NULL);
1694*7c478bd9Sstevel@tonic-gate 				t_strsz = ntry.sz_lib;
1695*7c478bd9Sstevel@tonic-gate 			}
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 			(void) memset(t, 0, t_strsz);
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate 			/* now actually get the string */
1700*7c478bd9Sstevel@tonic-gate 			if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
1701*7c478bd9Sstevel@tonic-gate 				abend("Unable to perform full read of lib str",
1702*7c478bd9Sstevel@tonic-gate 				    NULL);
1703*7c478bd9Sstevel@tonic-gate 			c_offset += ntry.sz_lib;
1704*7c478bd9Sstevel@tonic-gate 
1705*7c478bd9Sstevel@tonic-gate 			/* now get key string */
1706*7c478bd9Sstevel@tonic-gate 
1707*7c478bd9Sstevel@tonic-gate 			if (ntry.sz_key > s_strsz) {
1708*7c478bd9Sstevel@tonic-gate 				s = my_realloc(s, ntry.sz_key, NULL);
1709*7c478bd9Sstevel@tonic-gate 				s_strsz = ntry.sz_key;
1710*7c478bd9Sstevel@tonic-gate 			}
1711*7c478bd9Sstevel@tonic-gate 			(void) memset(s, 0, s_strsz);
1712*7c478bd9Sstevel@tonic-gate 			if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
1713*7c478bd9Sstevel@tonic-gate 				abend("Unable to perform full read of key str",
1714*7c478bd9Sstevel@tonic-gate 				    NULL);
1715*7c478bd9Sstevel@tonic-gate 			c_offset += ntry.sz_key;
1716*7c478bd9Sstevel@tonic-gate 
1717*7c478bd9Sstevel@tonic-gate 			add_fcall(fcall_tbl, t, s, ntry.count);
1718*7c478bd9Sstevel@tonic-gate 			break;
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 		case HD_cts_syscts:
1721*7c478bd9Sstevel@tonic-gate 		{
1722*7c478bd9Sstevel@tonic-gate 			struct counts *ncp;
1723*7c478bd9Sstevel@tonic-gate 			size_t bfsz = sizeof (struct counts) + maxsyscalls()
1724*7c478bd9Sstevel@tonic-gate 			    * sizeof (struct syscount);
1725*7c478bd9Sstevel@tonic-gate 			int i;
1726*7c478bd9Sstevel@tonic-gate 			struct syscount *sscp;
1727*7c478bd9Sstevel@tonic-gate 
1728*7c478bd9Sstevel@tonic-gate 			if (ntry.sz_key != bfsz)
1729*7c478bd9Sstevel@tonic-gate 				abend("cts/syscts size does not sanity check",
1730*7c478bd9Sstevel@tonic-gate 				    NULL);
1731*7c478bd9Sstevel@tonic-gate 			ncp = my_malloc(ntry.sz_key, NULL);
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate 			if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
1734*7c478bd9Sstevel@tonic-gate 			    ntry.sz_key)
1735*7c478bd9Sstevel@tonic-gate 				abend("Unable to perform full read of cts",
1736*7c478bd9Sstevel@tonic-gate 				    NULL);
1737*7c478bd9Sstevel@tonic-gate 			c_offset += ntry.sz_key;
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate 			sscp = (struct syscount *)(ncp + 1);
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&count_lock);
1742*7c478bd9Sstevel@tonic-gate 
1743*7c478bd9Sstevel@tonic-gate 			Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
1744*7c478bd9Sstevel@tonic-gate 			Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
1745*7c478bd9Sstevel@tonic-gate 			if (Cp->usrtotal.tv_nsec >= NANOSEC) {
1746*7c478bd9Sstevel@tonic-gate 				Cp->usrtotal.tv_nsec -= NANOSEC;
1747*7c478bd9Sstevel@tonic-gate 				Cp->usrtotal.tv_sec++;
1748*7c478bd9Sstevel@tonic-gate 			}
1749*7c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSYS; i++) {
1750*7c478bd9Sstevel@tonic-gate 				ncp->syscount[i] = sscp;
1751*7c478bd9Sstevel@tonic-gate 				sscp += nsubcodes(i);
1752*7c478bd9Sstevel@tonic-gate 			}
1753*7c478bd9Sstevel@tonic-gate 
1754*7c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXFAULT; i++) {
1755*7c478bd9Sstevel@tonic-gate 				Cp->fltcount[i] += ncp->fltcount[i];
1756*7c478bd9Sstevel@tonic-gate 			}
1757*7c478bd9Sstevel@tonic-gate 
1758*7c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSIG; i++) {
1759*7c478bd9Sstevel@tonic-gate 				Cp->sigcount[i] += ncp->sigcount[i];
1760*7c478bd9Sstevel@tonic-gate 			}
1761*7c478bd9Sstevel@tonic-gate 
1762*7c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSYS; i++) {
1763*7c478bd9Sstevel@tonic-gate 				struct syscount *scp = Cp->syscount[i];
1764*7c478bd9Sstevel@tonic-gate 				struct syscount *nscp = ncp->syscount[i];
1765*7c478bd9Sstevel@tonic-gate 				int n = nsubcodes(i);
1766*7c478bd9Sstevel@tonic-gate 				int subcode;
1767*7c478bd9Sstevel@tonic-gate 
1768*7c478bd9Sstevel@tonic-gate 				for (subcode = 0; subcode < n; subcode++,
1769*7c478bd9Sstevel@tonic-gate 				    scp++, nscp++) {
1770*7c478bd9Sstevel@tonic-gate 					scp->count += nscp->count;
1771*7c478bd9Sstevel@tonic-gate 					scp->error += nscp->error;
1772*7c478bd9Sstevel@tonic-gate 					scp->stime.tv_sec += nscp->stime.tv_sec;
1773*7c478bd9Sstevel@tonic-gate 					scp->stime.tv_nsec +=
1774*7c478bd9Sstevel@tonic-gate 					    nscp->stime.tv_nsec;
1775*7c478bd9Sstevel@tonic-gate 					if (scp->stime.tv_nsec >= NANOSEC) {
1776*7c478bd9Sstevel@tonic-gate 						scp->stime.tv_nsec -= NANOSEC;
1777*7c478bd9Sstevel@tonic-gate 						scp->stime.tv_sec++;
1778*7c478bd9Sstevel@tonic-gate 					}
1779*7c478bd9Sstevel@tonic-gate 				}
1780*7c478bd9Sstevel@tonic-gate 			}
1781*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&count_lock);
1782*7c478bd9Sstevel@tonic-gate 			free(ncp);
1783*7c478bd9Sstevel@tonic-gate 			break;
1784*7c478bd9Sstevel@tonic-gate 		}
1785*7c478bd9Sstevel@tonic-gate 		default:
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 			abend("Unknown file entry type encountered", NULL);
1788*7c478bd9Sstevel@tonic-gate 			break;
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate 		}
1791*7c478bd9Sstevel@tonic-gate 
1792*7c478bd9Sstevel@tonic-gate 		if (fstat(sfd, &fsi) == -1)
1793*7c478bd9Sstevel@tonic-gate 			abend("Error stat-ing tempfile", NULL);
1794*7c478bd9Sstevel@tonic-gate 		filesz = fsi.st_size;
1795*7c478bd9Sstevel@tonic-gate 	}
1796*7c478bd9Sstevel@tonic-gate 	if (s != NULL)
1797*7c478bd9Sstevel@tonic-gate 		free(s);
1798*7c478bd9Sstevel@tonic-gate 	if (t != NULL)
1799*7c478bd9Sstevel@tonic-gate 		free(t);
1800*7c478bd9Sstevel@tonic-gate }
1801*7c478bd9Sstevel@tonic-gate 
1802*7c478bd9Sstevel@tonic-gate void
1803*7c478bd9Sstevel@tonic-gate make_pname(private_t *pri, id_t tid)
1804*7c478bd9Sstevel@tonic-gate {
1805*7c478bd9Sstevel@tonic-gate 	if (!cflag) {
1806*7c478bd9Sstevel@tonic-gate 		int ff = (fflag || ngrab > 1);
1807*7c478bd9Sstevel@tonic-gate 		int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
1808*7c478bd9Sstevel@tonic-gate 		pid_t pid = Pstatus(Proc)->pr_pid;
1809*7c478bd9Sstevel@tonic-gate 		id_t lwpid = pri->lwpstat->pr_lwpid;
1810*7c478bd9Sstevel@tonic-gate 
1811*7c478bd9Sstevel@tonic-gate 		if (ff != pri->pparam.ff ||
1812*7c478bd9Sstevel@tonic-gate 		    lf != pri->pparam.lf ||
1813*7c478bd9Sstevel@tonic-gate 		    pid != pri->pparam.pid ||
1814*7c478bd9Sstevel@tonic-gate 		    lwpid != pri->pparam.lwpid ||
1815*7c478bd9Sstevel@tonic-gate 		    tid != pri->pparam.tid) {
1816*7c478bd9Sstevel@tonic-gate 			char *s = pri->pname;
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate 			if (ff)
1819*7c478bd9Sstevel@tonic-gate 				s += sprintf(s, "%d", (int)pid);
1820*7c478bd9Sstevel@tonic-gate 			if (lf)
1821*7c478bd9Sstevel@tonic-gate 				s += sprintf(s, "/%d", (int)lwpid);
1822*7c478bd9Sstevel@tonic-gate 			if (tid)
1823*7c478bd9Sstevel@tonic-gate 				s += sprintf(s, "@%d", (int)tid);
1824*7c478bd9Sstevel@tonic-gate 			if (ff || lf)
1825*7c478bd9Sstevel@tonic-gate 				*s++ = ':', *s++ = '\t';
1826*7c478bd9Sstevel@tonic-gate 			if (ff && lf && s < pri->pname + 9)
1827*7c478bd9Sstevel@tonic-gate 				*s++ = '\t';
1828*7c478bd9Sstevel@tonic-gate 			*s = '\0';
1829*7c478bd9Sstevel@tonic-gate 			pri->pparam.ff = ff;
1830*7c478bd9Sstevel@tonic-gate 			pri->pparam.lf = lf;
1831*7c478bd9Sstevel@tonic-gate 			pri->pparam.pid = pid;
1832*7c478bd9Sstevel@tonic-gate 			pri->pparam.lwpid = lwpid;
1833*7c478bd9Sstevel@tonic-gate 			pri->pparam.tid = tid;
1834*7c478bd9Sstevel@tonic-gate 		}
1835*7c478bd9Sstevel@tonic-gate 	}
1836*7c478bd9Sstevel@tonic-gate }
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate /*
1839*7c478bd9Sstevel@tonic-gate  * Print the pri->pname[] string, if any.
1840*7c478bd9Sstevel@tonic-gate  */
1841*7c478bd9Sstevel@tonic-gate void
1842*7c478bd9Sstevel@tonic-gate putpname(private_t *pri)
1843*7c478bd9Sstevel@tonic-gate {
1844*7c478bd9Sstevel@tonic-gate 	if (pri->pname[0])
1845*7c478bd9Sstevel@tonic-gate 		(void) fputs(pri->pname, stdout);
1846*7c478bd9Sstevel@tonic-gate }
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate /*
1849*7c478bd9Sstevel@tonic-gate  * Print the timestamp, if requested (-d, -D, or -E).
1850*7c478bd9Sstevel@tonic-gate  */
1851*7c478bd9Sstevel@tonic-gate void
1852*7c478bd9Sstevel@tonic-gate timestamp(private_t *pri)
1853*7c478bd9Sstevel@tonic-gate {
1854*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp = pri->lwpstat;
1855*7c478bd9Sstevel@tonic-gate 	int seconds;
1856*7c478bd9Sstevel@tonic-gate 	int fraction;
1857*7c478bd9Sstevel@tonic-gate 
1858*7c478bd9Sstevel@tonic-gate 	if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
1859*7c478bd9Sstevel@tonic-gate 		return;
1860*7c478bd9Sstevel@tonic-gate 
1861*7c478bd9Sstevel@tonic-gate 	seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
1862*7c478bd9Sstevel@tonic-gate 	fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
1863*7c478bd9Sstevel@tonic-gate 	if (fraction < 0) {
1864*7c478bd9Sstevel@tonic-gate 		seconds--;
1865*7c478bd9Sstevel@tonic-gate 		fraction += NANOSEC;
1866*7c478bd9Sstevel@tonic-gate 	}
1867*7c478bd9Sstevel@tonic-gate 	/* fraction in 1/10 milliseconds, rounded up */
1868*7c478bd9Sstevel@tonic-gate 	fraction = (fraction + 50000) / 100000;
1869*7c478bd9Sstevel@tonic-gate 	if (fraction >= (MILLISEC * 10)) {
1870*7c478bd9Sstevel@tonic-gate 		seconds++;
1871*7c478bd9Sstevel@tonic-gate 		fraction -= (MILLISEC * 10);
1872*7c478bd9Sstevel@tonic-gate 	}
1873*7c478bd9Sstevel@tonic-gate 
1874*7c478bd9Sstevel@tonic-gate 	if (dflag)		/* time stamp */
1875*7c478bd9Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
1876*7c478bd9Sstevel@tonic-gate 
1877*7c478bd9Sstevel@tonic-gate 	if (Dflag) {		/* time delta */
1878*7c478bd9Sstevel@tonic-gate 		int oseconds = pri->seconds;
1879*7c478bd9Sstevel@tonic-gate 		int ofraction = pri->fraction;
1880*7c478bd9Sstevel@tonic-gate 
1881*7c478bd9Sstevel@tonic-gate 		pri->seconds = seconds;
1882*7c478bd9Sstevel@tonic-gate 		pri->fraction = fraction;
1883*7c478bd9Sstevel@tonic-gate 		seconds -= oseconds;
1884*7c478bd9Sstevel@tonic-gate 		fraction -= ofraction;
1885*7c478bd9Sstevel@tonic-gate 		if (fraction < 0) {
1886*7c478bd9Sstevel@tonic-gate 			seconds--;
1887*7c478bd9Sstevel@tonic-gate 			fraction += (MILLISEC * 10);
1888*7c478bd9Sstevel@tonic-gate 		}
1889*7c478bd9Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
1890*7c478bd9Sstevel@tonic-gate 	}
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate 	if (Eflag) {
1893*7c478bd9Sstevel@tonic-gate 		seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
1894*7c478bd9Sstevel@tonic-gate 		fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
1895*7c478bd9Sstevel@tonic-gate 
1896*7c478bd9Sstevel@tonic-gate 		if (fraction < 0) {
1897*7c478bd9Sstevel@tonic-gate 			seconds--;
1898*7c478bd9Sstevel@tonic-gate 			fraction += NANOSEC;
1899*7c478bd9Sstevel@tonic-gate 		}
1900*7c478bd9Sstevel@tonic-gate 		/* fraction in 1/10 milliseconds, rounded up */
1901*7c478bd9Sstevel@tonic-gate 		fraction = (fraction + 50000) / 100000;
1902*7c478bd9Sstevel@tonic-gate 		if (fraction >= (MILLISEC * 10)) {
1903*7c478bd9Sstevel@tonic-gate 			seconds++;
1904*7c478bd9Sstevel@tonic-gate 			fraction -= (MILLISEC * 10);
1905*7c478bd9Sstevel@tonic-gate 		}
1906*7c478bd9Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
1907*7c478bd9Sstevel@tonic-gate 	}
1908*7c478bd9Sstevel@tonic-gate }
1909*7c478bd9Sstevel@tonic-gate 
1910*7c478bd9Sstevel@tonic-gate /*
1911*7c478bd9Sstevel@tonic-gate  * Create output file, being careful about
1912*7c478bd9Sstevel@tonic-gate  * suid/sgid and file descriptor 0, 1, 2 issues.
1913*7c478bd9Sstevel@tonic-gate  */
1914*7c478bd9Sstevel@tonic-gate int
1915*7c478bd9Sstevel@tonic-gate xcreat(char *path)
1916*7c478bd9Sstevel@tonic-gate {
1917*7c478bd9Sstevel@tonic-gate 	int fd;
1918*7c478bd9Sstevel@tonic-gate 	int mode = 0666;
1919*7c478bd9Sstevel@tonic-gate 
1920*7c478bd9Sstevel@tonic-gate 	if (Euid == Ruid && Egid == Rgid)	/* not set-id */
1921*7c478bd9Sstevel@tonic-gate 		fd = creat(path, mode);
1922*7c478bd9Sstevel@tonic-gate 	else if (access(path, F_OK) != 0) {	/* file doesn't exist */
1923*7c478bd9Sstevel@tonic-gate 		/* if directory permissions OK, create file & set ownership */
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 		char *dir;
1926*7c478bd9Sstevel@tonic-gate 		char *p;
1927*7c478bd9Sstevel@tonic-gate 		char dot[4];
1928*7c478bd9Sstevel@tonic-gate 
1929*7c478bd9Sstevel@tonic-gate 		/* generate path for directory containing file */
1930*7c478bd9Sstevel@tonic-gate 		if ((p = strrchr(path, '/')) == NULL) {	/* no '/' */
1931*7c478bd9Sstevel@tonic-gate 			p = dir = dot;
1932*7c478bd9Sstevel@tonic-gate 			*p++ = '.';		/* current directory */
1933*7c478bd9Sstevel@tonic-gate 			*p = '\0';
1934*7c478bd9Sstevel@tonic-gate 		} else if (p == path) {			/* leading '/' */
1935*7c478bd9Sstevel@tonic-gate 			p = dir = dot;
1936*7c478bd9Sstevel@tonic-gate 			*p++ = '/';		/* root directory */
1937*7c478bd9Sstevel@tonic-gate 			*p = '\0';
1938*7c478bd9Sstevel@tonic-gate 		} else {				/* embedded '/' */
1939*7c478bd9Sstevel@tonic-gate 			dir = path;		/* directory path */
1940*7c478bd9Sstevel@tonic-gate 			*p = '\0';
1941*7c478bd9Sstevel@tonic-gate 		}
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 		if (access(dir, W_OK|X_OK) != 0) {
1944*7c478bd9Sstevel@tonic-gate 			/* not writeable/searchable */
1945*7c478bd9Sstevel@tonic-gate 			*p = '/';
1946*7c478bd9Sstevel@tonic-gate 			fd = -1;
1947*7c478bd9Sstevel@tonic-gate 		} else {	/* create file and set ownership correctly */
1948*7c478bd9Sstevel@tonic-gate 			*p = '/';
1949*7c478bd9Sstevel@tonic-gate 			if ((fd = creat(path, mode)) >= 0)
1950*7c478bd9Sstevel@tonic-gate 				(void) chown(path, (int)Ruid, (int)Rgid);
1951*7c478bd9Sstevel@tonic-gate 		}
1952*7c478bd9Sstevel@tonic-gate 	} else if (access(path, W_OK) != 0)	/* file not writeable */
1953*7c478bd9Sstevel@tonic-gate 		fd = -1;
1954*7c478bd9Sstevel@tonic-gate 	else
1955*7c478bd9Sstevel@tonic-gate 		fd = creat(path, mode);
1956*7c478bd9Sstevel@tonic-gate 
1957*7c478bd9Sstevel@tonic-gate 	/*
1958*7c478bd9Sstevel@tonic-gate 	 * Make sure it's not one of 0, 1, or 2.
1959*7c478bd9Sstevel@tonic-gate 	 * This allows truss to work when spawned by init(1m).
1960*7c478bd9Sstevel@tonic-gate 	 */
1961*7c478bd9Sstevel@tonic-gate 	if (0 <= fd && fd <= 2) {
1962*7c478bd9Sstevel@tonic-gate 		int dfd = fcntl(fd, F_DUPFD, 3);
1963*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1964*7c478bd9Sstevel@tonic-gate 		fd = dfd;
1965*7c478bd9Sstevel@tonic-gate 	}
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate 	/*
1968*7c478bd9Sstevel@tonic-gate 	 * Mark it close-on-exec so created processes don't inherit it.
1969*7c478bd9Sstevel@tonic-gate 	 */
1970*7c478bd9Sstevel@tonic-gate 	if (fd >= 0)
1971*7c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 	return (fd);
1974*7c478bd9Sstevel@tonic-gate }
1975*7c478bd9Sstevel@tonic-gate 
1976*7c478bd9Sstevel@tonic-gate void
1977*7c478bd9Sstevel@tonic-gate setoutput(int ofd)
1978*7c478bd9Sstevel@tonic-gate {
1979*7c478bd9Sstevel@tonic-gate 	if (ofd < 0) {
1980*7c478bd9Sstevel@tonic-gate 		(void) close(1);
1981*7c478bd9Sstevel@tonic-gate 		(void) fcntl(2, F_DUPFD, 1);
1982*7c478bd9Sstevel@tonic-gate 	} else if (ofd != 1) {
1983*7c478bd9Sstevel@tonic-gate 		(void) close(1);
1984*7c478bd9Sstevel@tonic-gate 		(void) fcntl(ofd, F_DUPFD, 1);
1985*7c478bd9Sstevel@tonic-gate 		(void) close(ofd);
1986*7c478bd9Sstevel@tonic-gate 		/* if no stderr, make it the same file */
1987*7c478bd9Sstevel@tonic-gate 		if ((ofd = dup(2)) < 0)
1988*7c478bd9Sstevel@tonic-gate 			(void) fcntl(1, F_DUPFD, 2);
1989*7c478bd9Sstevel@tonic-gate 		else
1990*7c478bd9Sstevel@tonic-gate 			(void) close(ofd);
1991*7c478bd9Sstevel@tonic-gate 	}
1992*7c478bd9Sstevel@tonic-gate }
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate /*
1995*7c478bd9Sstevel@tonic-gate  * Accumulate time differencies:  a += e - s;
1996*7c478bd9Sstevel@tonic-gate  */
1997*7c478bd9Sstevel@tonic-gate void
1998*7c478bd9Sstevel@tonic-gate accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
1999*7c478bd9Sstevel@tonic-gate {
2000*7c478bd9Sstevel@tonic-gate 	ap->tv_sec += ep->tv_sec - sp->tv_sec;
2001*7c478bd9Sstevel@tonic-gate 	ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
2002*7c478bd9Sstevel@tonic-gate 	if (ap->tv_nsec >= NANOSEC) {
2003*7c478bd9Sstevel@tonic-gate 		ap->tv_nsec -= NANOSEC;
2004*7c478bd9Sstevel@tonic-gate 		ap->tv_sec++;
2005*7c478bd9Sstevel@tonic-gate 	} else if (ap->tv_nsec < 0) {
2006*7c478bd9Sstevel@tonic-gate 		ap->tv_nsec += NANOSEC;
2007*7c478bd9Sstevel@tonic-gate 		ap->tv_sec--;
2008*7c478bd9Sstevel@tonic-gate 	}
2009*7c478bd9Sstevel@tonic-gate }
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate int
2012*7c478bd9Sstevel@tonic-gate lib_sort(const void *p1, const void *p2)
2013*7c478bd9Sstevel@tonic-gate {
2014*7c478bd9Sstevel@tonic-gate 	int cmpr = 0;
2015*7c478bd9Sstevel@tonic-gate 	long i;
2016*7c478bd9Sstevel@tonic-gate 	long j;
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 	hentry_t *t1 = (hentry_t *)p1;
2019*7c478bd9Sstevel@tonic-gate 	hentry_t *t2 = (hentry_t *)p2;
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 	char *p = t1->lib;
2022*7c478bd9Sstevel@tonic-gate 	char *q = t2->lib;
2023*7c478bd9Sstevel@tonic-gate 
2024*7c478bd9Sstevel@tonic-gate 	if ((cmpr = strcmp(p, q)) == 0) {
2025*7c478bd9Sstevel@tonic-gate 		i = t1->count;
2026*7c478bd9Sstevel@tonic-gate 		j = t2->count;
2027*7c478bd9Sstevel@tonic-gate 		if (i > j)
2028*7c478bd9Sstevel@tonic-gate 			return (-1);
2029*7c478bd9Sstevel@tonic-gate 		else if (i < j)
2030*7c478bd9Sstevel@tonic-gate 			return (1);
2031*7c478bd9Sstevel@tonic-gate 		else {
2032*7c478bd9Sstevel@tonic-gate 			p = t1->key;
2033*7c478bd9Sstevel@tonic-gate 			q = t2->key;
2034*7c478bd9Sstevel@tonic-gate 			return (strcmp(p, q));
2035*7c478bd9Sstevel@tonic-gate 		}
2036*7c478bd9Sstevel@tonic-gate 	} else
2037*7c478bd9Sstevel@tonic-gate 		return (cmpr);
2038*7c478bd9Sstevel@tonic-gate }
2039*7c478bd9Sstevel@tonic-gate 
2040*7c478bd9Sstevel@tonic-gate void
2041*7c478bd9Sstevel@tonic-gate report(private_t *pri, time_t lapse)	/* elapsed time, clock ticks */
2042*7c478bd9Sstevel@tonic-gate {
2043*7c478bd9Sstevel@tonic-gate 	int i;
2044*7c478bd9Sstevel@tonic-gate 	long count;
2045*7c478bd9Sstevel@tonic-gate 	const char *name;
2046*7c478bd9Sstevel@tonic-gate 	long error;
2047*7c478bd9Sstevel@tonic-gate 	long total;
2048*7c478bd9Sstevel@tonic-gate 	long errtot;
2049*7c478bd9Sstevel@tonic-gate 	timestruc_t tickzero;
2050*7c478bd9Sstevel@tonic-gate 	timestruc_t ticks;
2051*7c478bd9Sstevel@tonic-gate 	timestruc_t ticktot;
2052*7c478bd9Sstevel@tonic-gate 
2053*7c478bd9Sstevel@tonic-gate 	if (descendent)
2054*7c478bd9Sstevel@tonic-gate 		return;
2055*7c478bd9Sstevel@tonic-gate 
2056*7c478bd9Sstevel@tonic-gate 	for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
2057*7c478bd9Sstevel@tonic-gate 		if ((count = Cp->fltcount[i]) != 0) {
2058*7c478bd9Sstevel@tonic-gate 			if (total == 0)		/* produce header */
2059*7c478bd9Sstevel@tonic-gate 				(void) printf("faults -------------\n");
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate 			name = proc_fltname(i, pri->flt_name,
2062*7c478bd9Sstevel@tonic-gate 				sizeof (pri->flt_name));
2063*7c478bd9Sstevel@tonic-gate 
2064*7c478bd9Sstevel@tonic-gate 			(void) printf("%s%s\t%4ld\n", name,
2065*7c478bd9Sstevel@tonic-gate 				(((int)strlen(name) < 8)?
2066*7c478bd9Sstevel@tonic-gate 				    (const char *)"\t" : (const char *)""),
2067*7c478bd9Sstevel@tonic-gate 				count);
2068*7c478bd9Sstevel@tonic-gate 			total += count;
2069*7c478bd9Sstevel@tonic-gate 		}
2070*7c478bd9Sstevel@tonic-gate 	}
2071*7c478bd9Sstevel@tonic-gate 	if (total && !interrupt)
2072*7c478bd9Sstevel@tonic-gate 		(void) printf("total:\t\t%4ld\n\n", total);
2073*7c478bd9Sstevel@tonic-gate 
2074*7c478bd9Sstevel@tonic-gate 	for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
2075*7c478bd9Sstevel@tonic-gate 		if ((count = Cp->sigcount[i]) != 0) {
2076*7c478bd9Sstevel@tonic-gate 			if (total == 0)		/* produce header */
2077*7c478bd9Sstevel@tonic-gate 				(void) printf("signals ------------\n");
2078*7c478bd9Sstevel@tonic-gate 			name = signame(pri, i);
2079*7c478bd9Sstevel@tonic-gate 			(void) printf("%s%s\t%4ld\n", name,
2080*7c478bd9Sstevel@tonic-gate 				(((int)strlen(name) < 8)?
2081*7c478bd9Sstevel@tonic-gate 				    (const char *)"\t" : (const char *)""),
2082*7c478bd9Sstevel@tonic-gate 				count);
2083*7c478bd9Sstevel@tonic-gate 			total += count;
2084*7c478bd9Sstevel@tonic-gate 		}
2085*7c478bd9Sstevel@tonic-gate 	}
2086*7c478bd9Sstevel@tonic-gate 	if (total && !interrupt)
2087*7c478bd9Sstevel@tonic-gate 		(void) printf("total:\t\t%4ld\n\n", total);
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate 	if ((Dynpat != NULL) && !interrupt) {
2090*7c478bd9Sstevel@tonic-gate 		size_t elem = elements_in_table(fcall_tbl);
2091*7c478bd9Sstevel@tonic-gate 		hiter_t *itr = iterate_hash(fcall_tbl);
2092*7c478bd9Sstevel@tonic-gate 		hentry_t *tmp = iter_next(itr);
2093*7c478bd9Sstevel@tonic-gate 		hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
2094*7c478bd9Sstevel@tonic-gate 		i = 0;
2095*7c478bd9Sstevel@tonic-gate 		while ((tmp != NULL) && (i < elem)) {
2096*7c478bd9Sstevel@tonic-gate 			stbl[i].prev = tmp->prev;
2097*7c478bd9Sstevel@tonic-gate 			stbl[i].next = tmp->next;
2098*7c478bd9Sstevel@tonic-gate 			stbl[i].lib = tmp->lib;
2099*7c478bd9Sstevel@tonic-gate 			stbl[i].key = tmp->key;
2100*7c478bd9Sstevel@tonic-gate 			stbl[i].count = tmp->count;
2101*7c478bd9Sstevel@tonic-gate 			tmp = iter_next(itr);
2102*7c478bd9Sstevel@tonic-gate 			i++;
2103*7c478bd9Sstevel@tonic-gate 		}
2104*7c478bd9Sstevel@tonic-gate 		qsort((void *)stbl, elem, sizeof (hentry_t),
2105*7c478bd9Sstevel@tonic-gate 		    lib_sort);
2106*7c478bd9Sstevel@tonic-gate 		(void) printf(
2107*7c478bd9Sstevel@tonic-gate 			"\n%-20s %-40s %s\n", "Library:", "Function", "calls");
2108*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < elem; i++) {
2109*7c478bd9Sstevel@tonic-gate 			(void) printf("%-20s %-40s %ld\n", stbl[i].lib,
2110*7c478bd9Sstevel@tonic-gate 			    stbl[i].key, stbl[i].count);
2111*7c478bd9Sstevel@tonic-gate 		}
2112*7c478bd9Sstevel@tonic-gate 		iter_free(itr);
2113*7c478bd9Sstevel@tonic-gate 		free(stbl);
2114*7c478bd9Sstevel@tonic-gate 		itr = NULL;
2115*7c478bd9Sstevel@tonic-gate 	}
2116*7c478bd9Sstevel@tonic-gate 
2117*7c478bd9Sstevel@tonic-gate 	if (!interrupt)
2118*7c478bd9Sstevel@tonic-gate 		(void) printf(
2119*7c478bd9Sstevel@tonic-gate 		"\nsyscall               seconds   calls  errors\n");
2120*7c478bd9Sstevel@tonic-gate 
2121*7c478bd9Sstevel@tonic-gate 	total = errtot = 0;
2122*7c478bd9Sstevel@tonic-gate 	tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
2123*7c478bd9Sstevel@tonic-gate 	tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
2124*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
2125*7c478bd9Sstevel@tonic-gate 		struct syscount *scp = Cp->syscount[i];
2126*7c478bd9Sstevel@tonic-gate 		int n = nsubcodes(i);
2127*7c478bd9Sstevel@tonic-gate 		int subcode;
2128*7c478bd9Sstevel@tonic-gate 
2129*7c478bd9Sstevel@tonic-gate 		for (subcode = 0; subcode < n; subcode++, scp++) {
2130*7c478bd9Sstevel@tonic-gate 			if ((count = scp->count) != 0 || scp->error) {
2131*7c478bd9Sstevel@tonic-gate 				(void) printf("%-19.19s ",
2132*7c478bd9Sstevel@tonic-gate 					sysname(pri, i, subcode));
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 				ticks = scp->stime;
2135*7c478bd9Sstevel@tonic-gate 				accumulate(&ticktot, &ticks, &tickzero);
2136*7c478bd9Sstevel@tonic-gate 				prtim(&ticks);
2137*7c478bd9Sstevel@tonic-gate 
2138*7c478bd9Sstevel@tonic-gate 				(void) printf(" %7ld", count);
2139*7c478bd9Sstevel@tonic-gate 				if ((error = scp->error) != 0)
2140*7c478bd9Sstevel@tonic-gate 					(void) printf(" %7ld", error);
2141*7c478bd9Sstevel@tonic-gate 				(void) fputc('\n', stdout);
2142*7c478bd9Sstevel@tonic-gate 				total += count;
2143*7c478bd9Sstevel@tonic-gate 				errtot += error;
2144*7c478bd9Sstevel@tonic-gate 			}
2145*7c478bd9Sstevel@tonic-gate 		}
2146*7c478bd9Sstevel@tonic-gate 	}
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate 	if (!interrupt) {
2149*7c478bd9Sstevel@tonic-gate 		(void) printf(
2150*7c478bd9Sstevel@tonic-gate 		"                     --------  ------   ----\n");
2151*7c478bd9Sstevel@tonic-gate 		(void) printf("sys totals:         ");
2152*7c478bd9Sstevel@tonic-gate 		prtim(&ticktot);
2153*7c478bd9Sstevel@tonic-gate 		(void) printf(" %7ld %6ld\n", total, errtot);
2154*7c478bd9Sstevel@tonic-gate 	}
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate 	if (!interrupt) {
2157*7c478bd9Sstevel@tonic-gate 		(void) printf("usr time:           ");
2158*7c478bd9Sstevel@tonic-gate 		prtim(&Cp->usrtotal);
2159*7c478bd9Sstevel@tonic-gate 		(void) fputc('\n', stdout);
2160*7c478bd9Sstevel@tonic-gate 	}
2161*7c478bd9Sstevel@tonic-gate 
2162*7c478bd9Sstevel@tonic-gate 	if (!interrupt) {
2163*7c478bd9Sstevel@tonic-gate 		int hz = (int)sysconf(_SC_CLK_TCK);
2164*7c478bd9Sstevel@tonic-gate 
2165*7c478bd9Sstevel@tonic-gate 		ticks.tv_sec = lapse / hz;
2166*7c478bd9Sstevel@tonic-gate 		ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
2167*7c478bd9Sstevel@tonic-gate 		(void) printf("elapsed:            ");
2168*7c478bd9Sstevel@tonic-gate 		prtim(&ticks);
2169*7c478bd9Sstevel@tonic-gate 		(void) fputc('\n', stdout);
2170*7c478bd9Sstevel@tonic-gate 	}
2171*7c478bd9Sstevel@tonic-gate }
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate void
2174*7c478bd9Sstevel@tonic-gate prtim(timestruc_t *tp)
2175*7c478bd9Sstevel@tonic-gate {
2176*7c478bd9Sstevel@tonic-gate 	time_t sec;
2177*7c478bd9Sstevel@tonic-gate 
2178*7c478bd9Sstevel@tonic-gate 	if ((sec = tp->tv_sec) != 0)			/* whole seconds */
2179*7c478bd9Sstevel@tonic-gate 		(void) printf("%5lu", sec);
2180*7c478bd9Sstevel@tonic-gate 	else
2181*7c478bd9Sstevel@tonic-gate 		(void) printf("     ");
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	(void) printf(".%3.3ld", tp->tv_nsec/1000000);	/* fraction */
2184*7c478bd9Sstevel@tonic-gate }
2185*7c478bd9Sstevel@tonic-gate 
2186*7c478bd9Sstevel@tonic-gate /*
2187*7c478bd9Sstevel@tonic-gate  * Gather process id's.
2188*7c478bd9Sstevel@tonic-gate  * Return 0 on success, != 0 on failure.
2189*7c478bd9Sstevel@tonic-gate  */
2190*7c478bd9Sstevel@tonic-gate void
2191*7c478bd9Sstevel@tonic-gate pids(char *arg, proc_set_t *grab)
2192*7c478bd9Sstevel@tonic-gate {
2193*7c478bd9Sstevel@tonic-gate 	pid_t pid = -1;
2194*7c478bd9Sstevel@tonic-gate 	int i;
2195*7c478bd9Sstevel@tonic-gate 	const char *lwps = NULL;
2196*7c478bd9Sstevel@tonic-gate 
2197*7c478bd9Sstevel@tonic-gate 	if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
2198*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
2199*7c478bd9Sstevel@tonic-gate 		    command, arg, Pgrab_error(i));
2200*7c478bd9Sstevel@tonic-gate 		return;
2201*7c478bd9Sstevel@tonic-gate 	}
2202*7c478bd9Sstevel@tonic-gate 
2203*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ngrab; i++)
2204*7c478bd9Sstevel@tonic-gate 		if (grab[i].pid == pid)	/* duplicate */
2205*7c478bd9Sstevel@tonic-gate 			break;
2206*7c478bd9Sstevel@tonic-gate 
2207*7c478bd9Sstevel@tonic-gate 	if (i == ngrab) {
2208*7c478bd9Sstevel@tonic-gate 		grab[ngrab].pid = pid;
2209*7c478bd9Sstevel@tonic-gate 		grab[ngrab].lwps = lwps;
2210*7c478bd9Sstevel@tonic-gate 		ngrab++;
2211*7c478bd9Sstevel@tonic-gate 	} else {
2212*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
2213*7c478bd9Sstevel@tonic-gate 		    command, (int)pid);
2214*7c478bd9Sstevel@tonic-gate 	}
2215*7c478bd9Sstevel@tonic-gate }
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate /*
2218*7c478bd9Sstevel@tonic-gate  * Report psargs string.
2219*7c478bd9Sstevel@tonic-gate  */
2220*7c478bd9Sstevel@tonic-gate void
2221*7c478bd9Sstevel@tonic-gate psargs(private_t *pri)
2222*7c478bd9Sstevel@tonic-gate {
2223*7c478bd9Sstevel@tonic-gate 	pid_t pid = Pstatus(Proc)->pr_pid;
2224*7c478bd9Sstevel@tonic-gate 	psinfo_t psinfo;
2225*7c478bd9Sstevel@tonic-gate 
2226*7c478bd9Sstevel@tonic-gate 	if (proc_get_psinfo(pid, &psinfo) == 0)
2227*7c478bd9Sstevel@tonic-gate 		(void) printf("%spsargs: %.64s\n",
2228*7c478bd9Sstevel@tonic-gate 			pri->pname, psinfo.pr_psargs);
2229*7c478bd9Sstevel@tonic-gate 	else {
2230*7c478bd9Sstevel@tonic-gate 		perror("psargs()");
2231*7c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
2232*7c478bd9Sstevel@tonic-gate 			pri->pname, (int)pid);
2233*7c478bd9Sstevel@tonic-gate 	}
2234*7c478bd9Sstevel@tonic-gate }
2235*7c478bd9Sstevel@tonic-gate 
2236*7c478bd9Sstevel@tonic-gate char *
2237*7c478bd9Sstevel@tonic-gate fetchstring(private_t *pri, long addr, int maxleng)
2238*7c478bd9Sstevel@tonic-gate {
2239*7c478bd9Sstevel@tonic-gate 	int nbyte;
2240*7c478bd9Sstevel@tonic-gate 	int leng = 0;
2241*7c478bd9Sstevel@tonic-gate 	char string[41];
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate 	string[40] = '\0';
2244*7c478bd9Sstevel@tonic-gate 	if (pri->str_bsize == 0)  /* initial allocation of string buffer */
2245*7c478bd9Sstevel@tonic-gate 		pri->str_buffer =
2246*7c478bd9Sstevel@tonic-gate 			my_malloc(pri->str_bsize = 16, "string buffer");
2247*7c478bd9Sstevel@tonic-gate 	*pri->str_buffer = '\0';
2248*7c478bd9Sstevel@tonic-gate 
2249*7c478bd9Sstevel@tonic-gate 	for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
2250*7c478bd9Sstevel@tonic-gate 		if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
2251*7c478bd9Sstevel@tonic-gate 			return (leng? pri->str_buffer : NULL);
2252*7c478bd9Sstevel@tonic-gate 		if (nbyte > 0 &&
2253*7c478bd9Sstevel@tonic-gate 		    (nbyte = strlen(string)) > 0) {
2254*7c478bd9Sstevel@tonic-gate 			while (leng + nbyte >= pri->str_bsize)
2255*7c478bd9Sstevel@tonic-gate 				pri->str_buffer =
2256*7c478bd9Sstevel@tonic-gate 					my_realloc(pri->str_buffer,
2257*7c478bd9Sstevel@tonic-gate 					pri->str_bsize *= 2, "string buffer");
2258*7c478bd9Sstevel@tonic-gate 			(void) strcpy(pri->str_buffer+leng, string);
2259*7c478bd9Sstevel@tonic-gate 			leng += nbyte;
2260*7c478bd9Sstevel@tonic-gate 		}
2261*7c478bd9Sstevel@tonic-gate 	}
2262*7c478bd9Sstevel@tonic-gate 
2263*7c478bd9Sstevel@tonic-gate 	if (leng > maxleng)
2264*7c478bd9Sstevel@tonic-gate 		leng = maxleng;
2265*7c478bd9Sstevel@tonic-gate 	pri->str_buffer[leng] = '\0';
2266*7c478bd9Sstevel@tonic-gate 
2267*7c478bd9Sstevel@tonic-gate 	return (pri->str_buffer);
2268*7c478bd9Sstevel@tonic-gate }
2269*7c478bd9Sstevel@tonic-gate 
2270*7c478bd9Sstevel@tonic-gate void
2271*7c478bd9Sstevel@tonic-gate show_cred(private_t *pri, int new)
2272*7c478bd9Sstevel@tonic-gate {
2273*7c478bd9Sstevel@tonic-gate 	prcred_t cred;
2274*7c478bd9Sstevel@tonic-gate 
2275*7c478bd9Sstevel@tonic-gate 	if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
2276*7c478bd9Sstevel@tonic-gate 		perror("show_cred()");
2277*7c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot get credentials\n", pri->pname);
2278*7c478bd9Sstevel@tonic-gate 		return;
2279*7c478bd9Sstevel@tonic-gate 	}
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate 	if (!cflag && prismember(&trace, SYS_exec)) {
2282*7c478bd9Sstevel@tonic-gate 		if (new)
2283*7c478bd9Sstevel@tonic-gate 			credentials = cred;
2284*7c478bd9Sstevel@tonic-gate 		if ((new && cred.pr_ruid != cred.pr_suid) ||
2285*7c478bd9Sstevel@tonic-gate 		    cred.pr_ruid != credentials.pr_ruid ||
2286*7c478bd9Sstevel@tonic-gate 		    cred.pr_suid != credentials.pr_suid)
2287*7c478bd9Sstevel@tonic-gate 			(void) printf(
2288*7c478bd9Sstevel@tonic-gate 		"%s    *** SUID: ruid/euid/suid = %d / %d / %d  ***\n",
2289*7c478bd9Sstevel@tonic-gate 			pri->pname,
2290*7c478bd9Sstevel@tonic-gate 			(int)cred.pr_ruid,
2291*7c478bd9Sstevel@tonic-gate 			(int)cred.pr_euid,
2292*7c478bd9Sstevel@tonic-gate 			(int)cred.pr_suid);
2293*7c478bd9Sstevel@tonic-gate 		if ((new && cred.pr_rgid != cred.pr_sgid) ||
2294*7c478bd9Sstevel@tonic-gate 		    cred.pr_rgid != credentials.pr_rgid ||
2295*7c478bd9Sstevel@tonic-gate 		    cred.pr_sgid != credentials.pr_sgid)
2296*7c478bd9Sstevel@tonic-gate 			(void) printf(
2297*7c478bd9Sstevel@tonic-gate 		"%s    *** SGID: rgid/egid/sgid = %d / %d / %d  ***\n",
2298*7c478bd9Sstevel@tonic-gate 			pri->pname,
2299*7c478bd9Sstevel@tonic-gate 			(int)cred.pr_rgid,
2300*7c478bd9Sstevel@tonic-gate 			(int)cred.pr_egid,
2301*7c478bd9Sstevel@tonic-gate 			(int)cred.pr_sgid);
2302*7c478bd9Sstevel@tonic-gate 	}
2303*7c478bd9Sstevel@tonic-gate 
2304*7c478bd9Sstevel@tonic-gate 	credentials = cred;
2305*7c478bd9Sstevel@tonic-gate }
2306*7c478bd9Sstevel@tonic-gate 
2307*7c478bd9Sstevel@tonic-gate /*
2308*7c478bd9Sstevel@tonic-gate  * Take control of a child process.
2309*7c478bd9Sstevel@tonic-gate  * We come here with truss_lock held.
2310*7c478bd9Sstevel@tonic-gate  */
2311*7c478bd9Sstevel@tonic-gate int
2312*7c478bd9Sstevel@tonic-gate control(private_t *pri, pid_t pid)
2313*7c478bd9Sstevel@tonic-gate {
2314*7c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp;
2315*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
2316*7c478bd9Sstevel@tonic-gate 	pid_t childpid = 0;
2317*7c478bd9Sstevel@tonic-gate 	long flags;
2318*7c478bd9Sstevel@tonic-gate 	int rc;
2319*7c478bd9Sstevel@tonic-gate 
2320*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&gps->fork_lock);
2321*7c478bd9Sstevel@tonic-gate 	while (gps->fork_pid != 0)
2322*7c478bd9Sstevel@tonic-gate 		(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2323*7c478bd9Sstevel@tonic-gate 	gps->fork_pid = getpid();	/* parent pid */
2324*7c478bd9Sstevel@tonic-gate 	if ((childpid = fork1()) == -1) {
2325*7c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot fork() to control process #%d\n",
2326*7c478bd9Sstevel@tonic-gate 			pri->pname, (int)pid);
2327*7c478bd9Sstevel@tonic-gate 		Flush();
2328*7c478bd9Sstevel@tonic-gate 		gps->fork_pid = 0;
2329*7c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
2330*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
2331*7c478bd9Sstevel@tonic-gate 		release(pri, pid);
2332*7c478bd9Sstevel@tonic-gate 		return (FALSE);
2333*7c478bd9Sstevel@tonic-gate 	}
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 	if (childpid != 0) {
2336*7c478bd9Sstevel@tonic-gate 		/*
2337*7c478bd9Sstevel@tonic-gate 		 * The parent carries on, after a brief pause.
2338*7c478bd9Sstevel@tonic-gate 		 * The parent must wait until the child executes procadd(pid).
2339*7c478bd9Sstevel@tonic-gate 		 */
2340*7c478bd9Sstevel@tonic-gate 		while (gps->fork_pid != childpid)
2341*7c478bd9Sstevel@tonic-gate 			(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
2342*7c478bd9Sstevel@tonic-gate 		gps->fork_pid = 0;
2343*7c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
2344*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
2345*7c478bd9Sstevel@tonic-gate 		return (FALSE);
2346*7c478bd9Sstevel@tonic-gate 	}
2347*7c478bd9Sstevel@tonic-gate 
2348*7c478bd9Sstevel@tonic-gate 	childpid = getpid();
2349*7c478bd9Sstevel@tonic-gate 	descendent = TRUE;
2350*7c478bd9Sstevel@tonic-gate 	exit_called = FALSE;
2351*7c478bd9Sstevel@tonic-gate 	Pfree(Proc);	/* forget old process */
2352*7c478bd9Sstevel@tonic-gate 
2353*7c478bd9Sstevel@tonic-gate 	/*
2354*7c478bd9Sstevel@tonic-gate 	 * The parent process owns the shared gps->fork_lock.
2355*7c478bd9Sstevel@tonic-gate 	 * The child must grab it again.
2356*7c478bd9Sstevel@tonic-gate 	 */
2357*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&gps->fork_lock);
2358*7c478bd9Sstevel@tonic-gate 
2359*7c478bd9Sstevel@tonic-gate 	/*
2360*7c478bd9Sstevel@tonic-gate 	 * Child grabs the process and retains the tracing flags.
2361*7c478bd9Sstevel@tonic-gate 	 */
2362*7c478bd9Sstevel@tonic-gate 	if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
2363*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
2364*7c478bd9Sstevel@tonic-gate 			"%s: cannot control child process, pid# %d: %s\n",
2365*7c478bd9Sstevel@tonic-gate 			command, (int)pid, Pgrab_error(rc));
2366*7c478bd9Sstevel@tonic-gate 		gps->fork_pid = childpid;
2367*7c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
2368*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
2369*7c478bd9Sstevel@tonic-gate 		exit(2);
2370*7c478bd9Sstevel@tonic-gate 	}
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate 	per_proc_init();
2373*7c478bd9Sstevel@tonic-gate 	/*
2374*7c478bd9Sstevel@tonic-gate 	 * Add ourself to the set of truss processes
2375*7c478bd9Sstevel@tonic-gate 	 * and notify the parent to carry on.
2376*7c478bd9Sstevel@tonic-gate 	 */
2377*7c478bd9Sstevel@tonic-gate 	procadd(pid, NULL);
2378*7c478bd9Sstevel@tonic-gate 	gps->fork_pid = childpid;
2379*7c478bd9Sstevel@tonic-gate 	(void) cond_broadcast(&gps->fork_cv);
2380*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&gps->fork_lock);
2381*7c478bd9Sstevel@tonic-gate 
2382*7c478bd9Sstevel@tonic-gate 	/*
2383*7c478bd9Sstevel@tonic-gate 	 * We may have grabbed the child before it is fully stopped on exit
2384*7c478bd9Sstevel@tonic-gate 	 * from fork.  Wait one second (at most) for it to settle down.
2385*7c478bd9Sstevel@tonic-gate 	 */
2386*7c478bd9Sstevel@tonic-gate 	(void) Pwait(Proc, MILLISEC);
2387*7c478bd9Sstevel@tonic-gate 	if (Rdb_agent != NULL)
2388*7c478bd9Sstevel@tonic-gate 		Rdb_agent = Prd_agent(Proc);
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 	Psp = Pstatus(Proc);
2391*7c478bd9Sstevel@tonic-gate 	Lsp = &Psp->pr_lwp;
2392*7c478bd9Sstevel@tonic-gate 	pri->lwpstat = Lsp;
2393*7c478bd9Sstevel@tonic-gate 	data_model = Psp->pr_dmodel;
2394*7c478bd9Sstevel@tonic-gate 
2395*7c478bd9Sstevel@tonic-gate 	make_pname(pri, 0);
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate 	if (Lsp->pr_why != PR_SYSEXIT ||
2398*7c478bd9Sstevel@tonic-gate 	    (Lsp->pr_what != SYS_forkall &&
2399*7c478bd9Sstevel@tonic-gate 	    Lsp->pr_what != SYS_vfork &&
2400*7c478bd9Sstevel@tonic-gate 	    Lsp->pr_what != SYS_fork1))
2401*7c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Expected SYSEXIT, fork1,forkall,vfork\n",
2402*7c478bd9Sstevel@tonic-gate 			pri->pname);
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate 	pri->syslast = Psp->pr_stime;
2405*7c478bd9Sstevel@tonic-gate 	pri->usrlast = Psp->pr_utime;
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate 	flags = PR_FORK | PR_ASYNC;
2408*7c478bd9Sstevel@tonic-gate 	if (Dynpat != NULL)
2409*7c478bd9Sstevel@tonic-gate 		flags |= PR_BPTADJ;	/* needed for x86 */
2410*7c478bd9Sstevel@tonic-gate 	(void) Psetflags(Proc, flags);
2411*7c478bd9Sstevel@tonic-gate 
2412*7c478bd9Sstevel@tonic-gate 	return (TRUE);
2413*7c478bd9Sstevel@tonic-gate }
2414*7c478bd9Sstevel@tonic-gate 
2415*7c478bd9Sstevel@tonic-gate /*
2416*7c478bd9Sstevel@tonic-gate  * Take control of an existing process.
2417*7c478bd9Sstevel@tonic-gate  */
2418*7c478bd9Sstevel@tonic-gate int
2419*7c478bd9Sstevel@tonic-gate grabit(private_t *pri, proc_set_t *set)
2420*7c478bd9Sstevel@tonic-gate {
2421*7c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp;
2422*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
2423*7c478bd9Sstevel@tonic-gate 	int gcode;
2424*7c478bd9Sstevel@tonic-gate 
2425*7c478bd9Sstevel@tonic-gate 	/*
2426*7c478bd9Sstevel@tonic-gate 	 * Don't force the takeover unless the -F option was specified.
2427*7c478bd9Sstevel@tonic-gate 	 */
2428*7c478bd9Sstevel@tonic-gate 	if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
2429*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: %d\n",
2430*7c478bd9Sstevel@tonic-gate 			command, Pgrab_error(gcode), (int)set->pid);
2431*7c478bd9Sstevel@tonic-gate 		pri->lwpstat = NULL;
2432*7c478bd9Sstevel@tonic-gate 		return (FALSE);
2433*7c478bd9Sstevel@tonic-gate 	}
2434*7c478bd9Sstevel@tonic-gate 	Psp = Pstatus(Proc);
2435*7c478bd9Sstevel@tonic-gate 	Lsp = &Psp->pr_lwp;
2436*7c478bd9Sstevel@tonic-gate 	pri->lwpstat = Lsp;
2437*7c478bd9Sstevel@tonic-gate 
2438*7c478bd9Sstevel@tonic-gate 	make_pname(pri, 0);
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 	data_model = Psp->pr_dmodel;
2441*7c478bd9Sstevel@tonic-gate 	pri->syslast = Psp->pr_stime;
2442*7c478bd9Sstevel@tonic-gate 	pri->usrlast = Psp->pr_utime;
2443*7c478bd9Sstevel@tonic-gate 
2444*7c478bd9Sstevel@tonic-gate 	if (fflag || Dynpat != NULL)
2445*7c478bd9Sstevel@tonic-gate 		(void) Psetflags(Proc, PR_FORK);
2446*7c478bd9Sstevel@tonic-gate 	else
2447*7c478bd9Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_FORK);
2448*7c478bd9Sstevel@tonic-gate 	procadd(set->pid, set->lwps);
2449*7c478bd9Sstevel@tonic-gate 	show_cred(pri, TRUE);
2450*7c478bd9Sstevel@tonic-gate 	return (TRUE);
2451*7c478bd9Sstevel@tonic-gate }
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate /*
2454*7c478bd9Sstevel@tonic-gate  * Release process from control.
2455*7c478bd9Sstevel@tonic-gate  */
2456*7c478bd9Sstevel@tonic-gate void
2457*7c478bd9Sstevel@tonic-gate release(private_t *pri, pid_t pid)
2458*7c478bd9Sstevel@tonic-gate {
2459*7c478bd9Sstevel@tonic-gate 	/*
2460*7c478bd9Sstevel@tonic-gate 	 * The process in question is the child of a traced process.
2461*7c478bd9Sstevel@tonic-gate 	 * We are here to turn off the inherited tracing flags.
2462*7c478bd9Sstevel@tonic-gate 	 */
2463*7c478bd9Sstevel@tonic-gate 	int fd;
2464*7c478bd9Sstevel@tonic-gate 	char ctlname[100];
2465*7c478bd9Sstevel@tonic-gate 	long ctl[2];
2466*7c478bd9Sstevel@tonic-gate 
2467*7c478bd9Sstevel@tonic-gate 	ctl[0] = PCSET;
2468*7c478bd9Sstevel@tonic-gate 	ctl[1] = PR_RLC;
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate 	/* process is freshly forked, no need for exclusive open */
2471*7c478bd9Sstevel@tonic-gate 	(void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
2472*7c478bd9Sstevel@tonic-gate 	if ((fd = open(ctlname, O_WRONLY)) < 0 ||
2473*7c478bd9Sstevel@tonic-gate 	    write(fd, (char *)ctl, sizeof (ctl)) < 0) {
2474*7c478bd9Sstevel@tonic-gate 		perror("release()");
2475*7c478bd9Sstevel@tonic-gate 		(void) printf(
2476*7c478bd9Sstevel@tonic-gate 			"%s\t*** Cannot release child process, pid# %d\n",
2477*7c478bd9Sstevel@tonic-gate 			pri->pname, (int)pid);
2478*7c478bd9Sstevel@tonic-gate 		Flush();
2479*7c478bd9Sstevel@tonic-gate 	}
2480*7c478bd9Sstevel@tonic-gate 	if (fd >= 0)	/* run-on-last-close sets the process running */
2481*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
2482*7c478bd9Sstevel@tonic-gate }
2483*7c478bd9Sstevel@tonic-gate 
2484*7c478bd9Sstevel@tonic-gate void
2485*7c478bd9Sstevel@tonic-gate intr(int sig)
2486*7c478bd9Sstevel@tonic-gate {
2487*7c478bd9Sstevel@tonic-gate 	/*
2488*7c478bd9Sstevel@tonic-gate 	 * SIGUSR1 is special.  It is used by one truss process to tell
2489*7c478bd9Sstevel@tonic-gate 	 * another truss process to release its controlled process.
2490*7c478bd9Sstevel@tonic-gate 	 * SIGUSR2 is also special.  It is used to wake up threads waiting
2491*7c478bd9Sstevel@tonic-gate 	 * for a victim lwp to stop after an event that will leave the
2492*7c478bd9Sstevel@tonic-gate 	 * process hung (stopped and abandoned) has occurred.
2493*7c478bd9Sstevel@tonic-gate 	 */
2494*7c478bd9Sstevel@tonic-gate 	if (sig == SIGUSR1) {
2495*7c478bd9Sstevel@tonic-gate 		sigusr1 = TRUE;
2496*7c478bd9Sstevel@tonic-gate 	} else if (sig == SIGUSR2) {
2497*7c478bd9Sstevel@tonic-gate 		void *value;
2498*7c478bd9Sstevel@tonic-gate 		private_t *pri;
2499*7c478bd9Sstevel@tonic-gate 		struct ps_lwphandle *Lwp;
2500*7c478bd9Sstevel@tonic-gate 
2501*7c478bd9Sstevel@tonic-gate 		if (thr_getspecific(private_key, &value) == 0 &&
2502*7c478bd9Sstevel@tonic-gate 		    (pri = value) != NULL &&
2503*7c478bd9Sstevel@tonic-gate 		    (Lwp = pri->Lwp) != NULL)
2504*7c478bd9Sstevel@tonic-gate 			(void) Lstop(Lwp, MILLISEC / 10);
2505*7c478bd9Sstevel@tonic-gate 	} else {
2506*7c478bd9Sstevel@tonic-gate 		interrupt = sig;
2507*7c478bd9Sstevel@tonic-gate 	}
2508*7c478bd9Sstevel@tonic-gate }
2509*7c478bd9Sstevel@tonic-gate 
2510*7c478bd9Sstevel@tonic-gate void
2511*7c478bd9Sstevel@tonic-gate errmsg(const char *s, const char *q)
2512*7c478bd9Sstevel@tonic-gate {
2513*7c478bd9Sstevel@tonic-gate 	char msg[512];
2514*7c478bd9Sstevel@tonic-gate 
2515*7c478bd9Sstevel@tonic-gate 	if (s || q) {
2516*7c478bd9Sstevel@tonic-gate 		msg[0] = '\0';
2517*7c478bd9Sstevel@tonic-gate 		if (command) {
2518*7c478bd9Sstevel@tonic-gate 			(void) strcpy(msg, command);
2519*7c478bd9Sstevel@tonic-gate 			(void) strcat(msg, ": ");
2520*7c478bd9Sstevel@tonic-gate 		}
2521*7c478bd9Sstevel@tonic-gate 		if (s)
2522*7c478bd9Sstevel@tonic-gate 			(void) strcat(msg, s);
2523*7c478bd9Sstevel@tonic-gate 		if (q)
2524*7c478bd9Sstevel@tonic-gate 			(void) strcat(msg, q);
2525*7c478bd9Sstevel@tonic-gate 		(void) strcat(msg, "\n");
2526*7c478bd9Sstevel@tonic-gate 		(void) write(2, msg, (size_t)strlen(msg));
2527*7c478bd9Sstevel@tonic-gate 	}
2528*7c478bd9Sstevel@tonic-gate }
2529*7c478bd9Sstevel@tonic-gate 
2530*7c478bd9Sstevel@tonic-gate void
2531*7c478bd9Sstevel@tonic-gate abend(const char *s, const char *q)
2532*7c478bd9Sstevel@tonic-gate {
2533*7c478bd9Sstevel@tonic-gate 	sigset_t mask;
2534*7c478bd9Sstevel@tonic-gate 
2535*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&mask);
2536*7c478bd9Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_SETMASK, &mask, NULL);
2537*7c478bd9Sstevel@tonic-gate 	if (Proc) {
2538*7c478bd9Sstevel@tonic-gate 		Flush();
2539*7c478bd9Sstevel@tonic-gate 		errmsg(s, q);
2540*7c478bd9Sstevel@tonic-gate 		clear_breakpoints();
2541*7c478bd9Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_ASYNC);
2542*7c478bd9Sstevel@tonic-gate 		Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
2543*7c478bd9Sstevel@tonic-gate 		procdel();
2544*7c478bd9Sstevel@tonic-gate 		(void) wait4all();
2545*7c478bd9Sstevel@tonic-gate 	} else {
2546*7c478bd9Sstevel@tonic-gate 		errmsg(s, q);
2547*7c478bd9Sstevel@tonic-gate 	}
2548*7c478bd9Sstevel@tonic-gate 	exit(2);
2549*7c478bd9Sstevel@tonic-gate }
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate /*
2552*7c478bd9Sstevel@tonic-gate  * Allocate memory.
2553*7c478bd9Sstevel@tonic-gate  * If allocation fails then print a message and abort.
2554*7c478bd9Sstevel@tonic-gate  */
2555*7c478bd9Sstevel@tonic-gate void *
2556*7c478bd9Sstevel@tonic-gate my_realloc(void *buf, size_t size, const char *msg)
2557*7c478bd9Sstevel@tonic-gate {
2558*7c478bd9Sstevel@tonic-gate 	if ((buf = realloc(buf, size)) == NULL) {
2559*7c478bd9Sstevel@tonic-gate 		if (msg != NULL)
2560*7c478bd9Sstevel@tonic-gate 			abend("cannot allocate ", msg);
2561*7c478bd9Sstevel@tonic-gate 		else
2562*7c478bd9Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
2563*7c478bd9Sstevel@tonic-gate 	}
2564*7c478bd9Sstevel@tonic-gate 
2565*7c478bd9Sstevel@tonic-gate 	return (buf);
2566*7c478bd9Sstevel@tonic-gate }
2567*7c478bd9Sstevel@tonic-gate 
2568*7c478bd9Sstevel@tonic-gate void *
2569*7c478bd9Sstevel@tonic-gate my_calloc(size_t nelem, size_t elsize, const char *msg)
2570*7c478bd9Sstevel@tonic-gate {
2571*7c478bd9Sstevel@tonic-gate 	void *buf = NULL;
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 	if ((buf = calloc(nelem, elsize)) == NULL) {
2574*7c478bd9Sstevel@tonic-gate 		if (msg != NULL)
2575*7c478bd9Sstevel@tonic-gate 			abend("cannot allocate ", msg);
2576*7c478bd9Sstevel@tonic-gate 		else
2577*7c478bd9Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
2578*7c478bd9Sstevel@tonic-gate 	}
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate 	return (buf);
2581*7c478bd9Sstevel@tonic-gate }
2582*7c478bd9Sstevel@tonic-gate 
2583*7c478bd9Sstevel@tonic-gate void *
2584*7c478bd9Sstevel@tonic-gate my_malloc(size_t size, const char *msg)
2585*7c478bd9Sstevel@tonic-gate {
2586*7c478bd9Sstevel@tonic-gate 	return (my_realloc(NULL, size, msg));
2587*7c478bd9Sstevel@tonic-gate }
2588*7c478bd9Sstevel@tonic-gate 
2589*7c478bd9Sstevel@tonic-gate int
2590*7c478bd9Sstevel@tonic-gate wait4all()
2591*7c478bd9Sstevel@tonic-gate {
2592*7c478bd9Sstevel@tonic-gate 	int i;
2593*7c478bd9Sstevel@tonic-gate 	pid_t pid;
2594*7c478bd9Sstevel@tonic-gate 	int rc = 0;
2595*7c478bd9Sstevel@tonic-gate 	int status;
2596*7c478bd9Sstevel@tonic-gate 
2597*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 10; i++) {
2598*7c478bd9Sstevel@tonic-gate 		while ((pid = wait(&status)) != -1) {
2599*7c478bd9Sstevel@tonic-gate 			/* return exit() code of the created process */
2600*7c478bd9Sstevel@tonic-gate 			if (pid == created) {
2601*7c478bd9Sstevel@tonic-gate 				if (WIFEXITED(status))
2602*7c478bd9Sstevel@tonic-gate 					rc = WEXITSTATUS(status);
2603*7c478bd9Sstevel@tonic-gate 				else
2604*7c478bd9Sstevel@tonic-gate 					rc |= 0x80; /* +128 to indicate sig */
2605*7c478bd9Sstevel@tonic-gate 			}
2606*7c478bd9Sstevel@tonic-gate 		}
2607*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR && errno != ERESTART)
2608*7c478bd9Sstevel@tonic-gate 			break;
2609*7c478bd9Sstevel@tonic-gate 	}
2610*7c478bd9Sstevel@tonic-gate 
2611*7c478bd9Sstevel@tonic-gate 	if (i >= 10)	/* repeated interrupts */
2612*7c478bd9Sstevel@tonic-gate 		rc = 2;
2613*7c478bd9Sstevel@tonic-gate 
2614*7c478bd9Sstevel@tonic-gate 	return (rc);
2615*7c478bd9Sstevel@tonic-gate }
2616*7c478bd9Sstevel@tonic-gate 
2617*7c478bd9Sstevel@tonic-gate void
2618*7c478bd9Sstevel@tonic-gate letgo(private_t *pri)
2619*7c478bd9Sstevel@tonic-gate {
2620*7c478bd9Sstevel@tonic-gate 	(void) printf("%s\t*** process otherwise traced, releasing ...\n",
2621*7c478bd9Sstevel@tonic-gate 		pri->pname);
2622*7c478bd9Sstevel@tonic-gate }
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate /*
2625*7c478bd9Sstevel@tonic-gate  * Test for empty set.
2626*7c478bd9Sstevel@tonic-gate  * support routine used by isemptyset() macro.
2627*7c478bd9Sstevel@tonic-gate  */
2628*7c478bd9Sstevel@tonic-gate int
2629*7c478bd9Sstevel@tonic-gate is_empty(const uint32_t *sp,	/* pointer to set (array of int32's) */
2630*7c478bd9Sstevel@tonic-gate 	size_t n)		/* number of int32's in set */
2631*7c478bd9Sstevel@tonic-gate {
2632*7c478bd9Sstevel@tonic-gate 	if (n) {
2633*7c478bd9Sstevel@tonic-gate 		do {
2634*7c478bd9Sstevel@tonic-gate 			if (*sp++)
2635*7c478bd9Sstevel@tonic-gate 				return (FALSE);
2636*7c478bd9Sstevel@tonic-gate 		} while (--n);
2637*7c478bd9Sstevel@tonic-gate 	}
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate 	return (TRUE);
2640*7c478bd9Sstevel@tonic-gate }
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate /*
2643*7c478bd9Sstevel@tonic-gate  * OR the second set into the first.
2644*7c478bd9Sstevel@tonic-gate  * The sets must be the same size.
2645*7c478bd9Sstevel@tonic-gate  */
2646*7c478bd9Sstevel@tonic-gate void
2647*7c478bd9Sstevel@tonic-gate or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
2648*7c478bd9Sstevel@tonic-gate {
2649*7c478bd9Sstevel@tonic-gate 	if (n) {
2650*7c478bd9Sstevel@tonic-gate 		do {
2651*7c478bd9Sstevel@tonic-gate 			*sp1++ |= *sp2++;
2652*7c478bd9Sstevel@tonic-gate 		} while (--n);
2653*7c478bd9Sstevel@tonic-gate 	}
2654*7c478bd9Sstevel@tonic-gate }
2655