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