xref: /illumos-gate/usr/src/cmd/truss/main.c (revision ae2315d9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2153e568b1Sraf 
227c478bd9Sstevel@tonic-gate /*
23134a1f4eSCasper H.S. Dik  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
2443051d27SRobert Mustacchi  * Copyright 2015, Joyent, Inc.
25*ae2315d9SKeith M Wesolowski  * Copyright 2023 Oxide Computer Company
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
31004388ebScasper #include <stdio_ext.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <ctype.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <memory.h>
387c478bd9Sstevel@tonic-gate #include <signal.h>
397c478bd9Sstevel@tonic-gate #include <wait.h>
407c478bd9Sstevel@tonic-gate #include <limits.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate #include <sys/time.h>
447c478bd9Sstevel@tonic-gate #include <sys/times.h>
457c478bd9Sstevel@tonic-gate #include <sys/fstyp.h>
467c478bd9Sstevel@tonic-gate #include <sys/fsid.h>
477c478bd9Sstevel@tonic-gate #include <sys/stat.h>
487c478bd9Sstevel@tonic-gate #include <sys/mman.h>
497c478bd9Sstevel@tonic-gate #include <sys/resource.h>
507c478bd9Sstevel@tonic-gate #include <libproc.h>
51134a1f4eSCasper H.S. Dik #include <priv.h>
527c478bd9Sstevel@tonic-gate #include "ramdata.h"
537c478bd9Sstevel@tonic-gate #include "proto.h"
547c478bd9Sstevel@tonic-gate #include "htbl.h"
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * The user can trace individual threads by using the 'pid/1,3-6,8-' syntax.
587c478bd9Sstevel@tonic-gate  * This structure keeps track of pid/lwp specifications.  If there are no LWPs
597c478bd9Sstevel@tonic-gate  * specified, then 'lwps' will be NULL.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate typedef struct proc_set {
627c478bd9Sstevel@tonic-gate 	pid_t		pid;
63350ffdd5SRobert Mustacchi 	const char	*lwps;
647c478bd9Sstevel@tonic-gate } proc_set_t;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * Function prototypes for static routines in this file.
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate void	setup_basetime(hrtime_t, struct timeval *);
707c478bd9Sstevel@tonic-gate int	xcreat(char *);
717c478bd9Sstevel@tonic-gate void	setoutput(int);
727c478bd9Sstevel@tonic-gate void	report(private_t *, time_t);
737c478bd9Sstevel@tonic-gate void	prtim(timestruc_t *);
747c478bd9Sstevel@tonic-gate void	pids(char *, proc_set_t *);
757c478bd9Sstevel@tonic-gate void	psargs(private_t *);
767c478bd9Sstevel@tonic-gate int	control(private_t *, pid_t);
777c478bd9Sstevel@tonic-gate int	grabit(private_t *, proc_set_t *);
787c478bd9Sstevel@tonic-gate void	release(private_t *, pid_t);
797c478bd9Sstevel@tonic-gate void	intr(int);
807c478bd9Sstevel@tonic-gate int	wait4all(void);
817c478bd9Sstevel@tonic-gate void	letgo(private_t *);
827c478bd9Sstevel@tonic-gate void	child_to_file();
837c478bd9Sstevel@tonic-gate void	file_to_parent();
847c478bd9Sstevel@tonic-gate void	per_proc_init();
857c478bd9Sstevel@tonic-gate int	lib_sort(const void *, const void *);
867c478bd9Sstevel@tonic-gate int	key_sort(const void *, const void *);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate void	*worker_thread(void *);
897c478bd9Sstevel@tonic-gate void	main_thread(int);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * Test for empty set.
937c478bd9Sstevel@tonic-gate  * is_empty() should not be called directly.
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate int	is_empty(const uint32_t *, size_t);
967c478bd9Sstevel@tonic-gate #define	isemptyset(sp) \
977c478bd9Sstevel@tonic-gate 	is_empty((uint32_t *)(sp), sizeof (*(sp)) / sizeof (uint32_t))
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * OR the second set into the first set.
1017c478bd9Sstevel@tonic-gate  * or_set() should not be called directly.
1027c478bd9Sstevel@tonic-gate  */
1037c478bd9Sstevel@tonic-gate void	or_set(uint32_t *, const uint32_t *, size_t);
1047c478bd9Sstevel@tonic-gate #define	prorset(sp1, sp2) \
1057c478bd9Sstevel@tonic-gate 	or_set((uint32_t *)(sp1), (uint32_t *)(sp2), \
1067c478bd9Sstevel@tonic-gate 	sizeof (*(sp1)) / sizeof (uint32_t))
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /* fetch or allocate thread-private data */
1097c478bd9Sstevel@tonic-gate private_t *
get_private()1107c478bd9Sstevel@tonic-gate get_private()
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	void *value;
1137c478bd9Sstevel@tonic-gate 	private_t *pri = NULL;
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	if (thr_getspecific(private_key, &value) == 0)
1167c478bd9Sstevel@tonic-gate 		pri = value;
1177c478bd9Sstevel@tonic-gate 	if (pri == NULL) {
1187c478bd9Sstevel@tonic-gate 		pri = my_malloc(sizeof (*pri), NULL);
1197c478bd9Sstevel@tonic-gate 		(void) memset(pri, 0, sizeof (*pri));
1207c478bd9Sstevel@tonic-gate 		pri->sys_path = my_malloc(pri->sys_psize = 16, NULL);
1217c478bd9Sstevel@tonic-gate 		pri->sys_string = my_malloc(pri->sys_ssize = 32, NULL);
1227c478bd9Sstevel@tonic-gate 		if (thr_setspecific(private_key, pri) == ENOMEM)
1237c478bd9Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 	return (pri);
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /* destructor function for thread-private data */
1297c478bd9Sstevel@tonic-gate void
free_private(void * value)1307c478bd9Sstevel@tonic-gate free_private(void *value)
1317c478bd9Sstevel@tonic-gate {
1327c478bd9Sstevel@tonic-gate 	private_t *pri = value;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (pri->sys_path)
1357c478bd9Sstevel@tonic-gate 		free(pri->sys_path);
1367c478bd9Sstevel@tonic-gate 	if (pri->sys_string)
1377c478bd9Sstevel@tonic-gate 		free(pri->sys_string);
1387c478bd9Sstevel@tonic-gate 	if (pri->exec_string)
1397c478bd9Sstevel@tonic-gate 		free(pri->exec_string);
1407c478bd9Sstevel@tonic-gate 	if (pri->str_buffer)
1417c478bd9Sstevel@tonic-gate 		free(pri->str_buffer);
1427c478bd9Sstevel@tonic-gate 	free(pri);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * This is called by the main thread (via create_thread())
1477c478bd9Sstevel@tonic-gate  * and is also called from other threads in worker_thread()
1487c478bd9Sstevel@tonic-gate  * while holding truss_lock.  No further locking is required.
1497c478bd9Sstevel@tonic-gate  */
1507c478bd9Sstevel@tonic-gate void
insert_lwpid(lwpid_t lwpid)1517c478bd9Sstevel@tonic-gate insert_lwpid(lwpid_t lwpid)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	int i;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	truss_nlwp++;
1567c478bd9Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
1577c478bd9Sstevel@tonic-gate 		if (truss_lwpid[i] == 0)
1587c478bd9Sstevel@tonic-gate 			break;
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	if (i == truss_maxlwp) {
1617c478bd9Sstevel@tonic-gate 		/* double the size of the array */
1627c478bd9Sstevel@tonic-gate 		truss_lwpid = my_realloc(truss_lwpid,
1638fd04b83SRoger A. Faulkner 		    truss_maxlwp * 2 * sizeof (lwpid_t), NULL);
1647c478bd9Sstevel@tonic-gate 		(void) memset(&truss_lwpid[truss_maxlwp], 0,
1658fd04b83SRoger A. Faulkner 		    truss_maxlwp * sizeof (lwpid_t));
1667c478bd9Sstevel@tonic-gate 		truss_maxlwp *= 2;
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 	truss_lwpid[i] = lwpid;
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
17253e568b1Sraf  * This is called from the first worker thread to encounter one of
17353e568b1Sraf  * (leave_hung || interrupt || sigusr1).  It must notify all other
17453e568b1Sraf  * worker threads of the same condition.  truss_lock is held.
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate void
broadcast_signals(void)17753e568b1Sraf broadcast_signals(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	static int int_notified = FALSE;
1807c478bd9Sstevel@tonic-gate 	static int usr1_notified = FALSE;
1817c478bd9Sstevel@tonic-gate 	static int usr2_notified = FALSE;
18253e568b1Sraf 	lwpid_t my_id = thr_self();
18353e568b1Sraf 	lwpid_t lwpid;
1847c478bd9Sstevel@tonic-gate 	int i;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (interrupt && !int_notified) {
1877c478bd9Sstevel@tonic-gate 		int_notified = TRUE;
1887c478bd9Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
18953e568b1Sraf 			if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
19053e568b1Sraf 				(void) thr_kill(lwpid, interrupt);
1917c478bd9Sstevel@tonic-gate 		}
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 	if (sigusr1 && !usr1_notified) {
1947c478bd9Sstevel@tonic-gate 		usr1_notified = TRUE;
1957c478bd9Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
19653e568b1Sraf 			if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
19753e568b1Sraf 				(void) thr_kill(lwpid, SIGUSR1);
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 	if (leave_hung && !usr2_notified) {
2017c478bd9Sstevel@tonic-gate 		usr2_notified = TRUE;
2027c478bd9Sstevel@tonic-gate 		for (i = 0; i < truss_maxlwp; i++) {
20353e568b1Sraf 			if ((lwpid = truss_lwpid[i]) != 0 && lwpid != my_id)
20453e568b1Sraf 				(void) thr_kill(lwpid, SIGUSR2);
2057c478bd9Sstevel@tonic-gate 		}
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate static struct ps_lwphandle *
grab_lwp(lwpid_t who)2107c478bd9Sstevel@tonic-gate grab_lwp(lwpid_t who)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *Lwp;
2137c478bd9Sstevel@tonic-gate 	int gcode;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	if ((Lwp = Lgrab(Proc, who, &gcode)) == NULL) {
2167c478bd9Sstevel@tonic-gate 		if (gcode != G_NOPROC) {
2177c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2188fd04b83SRoger A. Faulkner 			    "%s: cannot grab LWP %u in process %d,"
2198fd04b83SRoger A. Faulkner 			    " reason: %s\n",
2208fd04b83SRoger A. Faulkner 			    command, who, (int)Pstatus(Proc)->pr_pid,
2218fd04b83SRoger A. Faulkner 			    Lgrab_error(gcode));
2227c478bd9Sstevel@tonic-gate 			interrupt = SIGTERM;	/* post an interrupt */
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 	return (Lwp);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate /*
2297c478bd9Sstevel@tonic-gate  * Iteration function called for each initial lwp in the controlled process.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate /* ARGSUSED */
2327c478bd9Sstevel@tonic-gate int
create_thread(void * arg,const lwpstatus_t * Lsp)2337c478bd9Sstevel@tonic-gate create_thread(void *arg, const lwpstatus_t *Lsp)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *new_Lwp;
2367c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
2377c478bd9Sstevel@tonic-gate 	int *count = arg;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	if (lwptrace(Pstatus(Proc)->pr_pid, Lsp->pr_lwpid))
2407c478bd9Sstevel@tonic-gate 		*count += 1;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	if ((new_Lwp = grab_lwp(Lsp->pr_lwpid)) != NULL) {
2437c478bd9Sstevel@tonic-gate 		if (thr_create(NULL, 0, worker_thread, new_Lwp,
2447c478bd9Sstevel@tonic-gate 		    THR_BOUND | THR_SUSPENDED, &lwpid) != 0)
2457c478bd9Sstevel@tonic-gate 			abend("cannot create lwp to follow child lwp", NULL);
2467c478bd9Sstevel@tonic-gate 		insert_lwpid(lwpid);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 	return (0);
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])2527c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate 	private_t *pri;
2557c478bd9Sstevel@tonic-gate 	struct tms tms;
2567c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
2577c478bd9Sstevel@tonic-gate 	int ofd = -1;
2587c478bd9Sstevel@tonic-gate 	int opt;
2597c478bd9Sstevel@tonic-gate 	int i;
2607c478bd9Sstevel@tonic-gate 	int first;
2617c478bd9Sstevel@tonic-gate 	int errflg = FALSE;
2627c478bd9Sstevel@tonic-gate 	int badname = FALSE;
2637c478bd9Sstevel@tonic-gate 	proc_set_t *grab = NULL;
2647c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp;
2657c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
2667c478bd9Sstevel@tonic-gate 	int sharedmem;
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	/* a few of these need to be initialized to NULL */
2697c478bd9Sstevel@tonic-gate 	Cp = NULL;
2707c478bd9Sstevel@tonic-gate 	fcall_tbl = NULL;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * Make sure fd's 0, 1, and 2 are allocated,
2747c478bd9Sstevel@tonic-gate 	 * just in case truss was invoked from init.
2757c478bd9Sstevel@tonic-gate 	 */
2767c478bd9Sstevel@tonic-gate 	while ((i = open("/dev/null", O_RDWR)) >= 0 && i < 2)
2777c478bd9Sstevel@tonic-gate 		;
2787c478bd9Sstevel@tonic-gate 	if (i > 2)
2797c478bd9Sstevel@tonic-gate 		(void) close(i);
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	starttime = times(&tms);	/* for elapsed timing */
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/* this should be per-traced-process */
2847c478bd9Sstevel@tonic-gate 	pagesize = sysconf(_SC_PAGESIZE);
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/* command name (e.g., "truss") */
2877c478bd9Sstevel@tonic-gate 	if ((command = strrchr(argv[0], '/')) != NULL)
2887c478bd9Sstevel@tonic-gate 		command++;
2897c478bd9Sstevel@tonic-gate 	else
2907c478bd9Sstevel@tonic-gate 		command = argv[0];
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* set up the initial private data */
2937c478bd9Sstevel@tonic-gate 	(void) mutex_init(&truss_lock, USYNC_THREAD, NULL);
2947c478bd9Sstevel@tonic-gate 	(void) mutex_init(&count_lock, USYNC_THREAD, NULL);
2957c478bd9Sstevel@tonic-gate 	(void) cond_init(&truss_cv, USYNC_THREAD, NULL);
2967c478bd9Sstevel@tonic-gate 	if (thr_keycreate(&private_key, free_private) == ENOMEM)
2977c478bd9Sstevel@tonic-gate 		abend("memory allocation failure", NULL);
2987c478bd9Sstevel@tonic-gate 	pri = get_private();
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	Euid = geteuid();
3017c478bd9Sstevel@tonic-gate 	Egid = getegid();
3027c478bd9Sstevel@tonic-gate 	Ruid = getuid();
3037c478bd9Sstevel@tonic-gate 	Rgid = getgid();
3047c478bd9Sstevel@tonic-gate 	ancestor = getpid();
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	prfillset(&trace);	/* default: trace all system calls */
3077c478bd9Sstevel@tonic-gate 	premptyset(&verbose);	/* default: no syscall verbosity */
3087c478bd9Sstevel@tonic-gate 	premptyset(&rawout);	/* default: no raw syscall interpretation */
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	prfillset(&signals);	/* default: trace all signals */
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	prfillset(&faults);	/* default: trace all faults */
3137c478bd9Sstevel@tonic-gate 	prdelset(&faults, FLTPAGE);	/* except this one */
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	premptyset(&readfd);	/* default: dump no buffers */
3167c478bd9Sstevel@tonic-gate 	premptyset(&writefd);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	premptyset(&syshang);	/* default: hang on no system calls */
3197c478bd9Sstevel@tonic-gate 	premptyset(&sighang);	/* default: hang on no signals */
3207c478bd9Sstevel@tonic-gate 	premptyset(&flthang);	/* default: hang on no faults */
3217c478bd9Sstevel@tonic-gate 
32253e568b1Sraf 	(void) sigemptyset(&emptyset);	/* for unblocking all signals */
32353e568b1Sraf 	(void) sigfillset(&fillset);	/* for blocking all signals */
32453e568b1Sraf 
3257c478bd9Sstevel@tonic-gate #define	OPTIONS	"FpfcaeildDEht:T:v:x:s:S:m:M:u:U:r:w:o:"
3267c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
3277c478bd9Sstevel@tonic-gate 		switch (opt) {
3287c478bd9Sstevel@tonic-gate 		case 'F':		/* force grabbing (no O_EXCL) */
3297c478bd9Sstevel@tonic-gate 			Fflag = PGRAB_FORCE;
3307c478bd9Sstevel@tonic-gate 			break;
3317c478bd9Sstevel@tonic-gate 		case 'p':		/* grab processes */
3327c478bd9Sstevel@tonic-gate 			pflag = TRUE;
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		case 'f':		/* follow children */
3357c478bd9Sstevel@tonic-gate 			fflag = TRUE;
3367c478bd9Sstevel@tonic-gate 			break;
3377c478bd9Sstevel@tonic-gate 		case 'c':		/* don't trace, just count */
3387c478bd9Sstevel@tonic-gate 			cflag = TRUE;
3397c478bd9Sstevel@tonic-gate 			iflag = TRUE;	/* implies no interruptable syscalls */
3407c478bd9Sstevel@tonic-gate 			break;
3417c478bd9Sstevel@tonic-gate 		case 'a':		/* display argument lists */
3427c478bd9Sstevel@tonic-gate 			aflag = TRUE;
3437c478bd9Sstevel@tonic-gate 			break;
3447c478bd9Sstevel@tonic-gate 		case 'e':		/* display environments */
3457c478bd9Sstevel@tonic-gate 			eflag = TRUE;
3467c478bd9Sstevel@tonic-gate 			break;
3477c478bd9Sstevel@tonic-gate 		case 'i':		/* don't show interruptable syscalls */
3487c478bd9Sstevel@tonic-gate 			iflag = TRUE;
3497c478bd9Sstevel@tonic-gate 			break;
3507c478bd9Sstevel@tonic-gate 		case 'l':		/* show lwp id for each syscall */
3517c478bd9Sstevel@tonic-gate 			lflag = TRUE;
3527c478bd9Sstevel@tonic-gate 			break;
3537c478bd9Sstevel@tonic-gate 		case 'h':		/* debugging: report hash stats */
3547c478bd9Sstevel@tonic-gate 			hflag = TRUE;
3557c478bd9Sstevel@tonic-gate 			break;
3567c478bd9Sstevel@tonic-gate 		case 'd':		/* show time stamps */
3577c478bd9Sstevel@tonic-gate 			dflag = TRUE;
3587c478bd9Sstevel@tonic-gate 			break;
3597c478bd9Sstevel@tonic-gate 		case 'D':		/* show time deltas */
3607c478bd9Sstevel@tonic-gate 			Dflag = TRUE;
3617c478bd9Sstevel@tonic-gate 			break;
3627c478bd9Sstevel@tonic-gate 		case 'E':
3637c478bd9Sstevel@tonic-gate 			Eflag = TRUE;	/* show syscall times */
3647c478bd9Sstevel@tonic-gate 			break;
3657c478bd9Sstevel@tonic-gate 		case 't':		/* system calls to trace */
3667c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &trace, &tflag))
3677c478bd9Sstevel@tonic-gate 				badname = TRUE;
3687c478bd9Sstevel@tonic-gate 			break;
3697c478bd9Sstevel@tonic-gate 		case 'T':		/* system calls to hang process */
3707c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &syshang, &Tflag))
3717c478bd9Sstevel@tonic-gate 				badname = TRUE;
3727c478bd9Sstevel@tonic-gate 			break;
3737c478bd9Sstevel@tonic-gate 		case 'v':		/* verbose interpretation of syscalls */
3747c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &verbose, &vflag))
3757c478bd9Sstevel@tonic-gate 				badname = TRUE;
3767c478bd9Sstevel@tonic-gate 			break;
3777c478bd9Sstevel@tonic-gate 		case 'x':		/* raw interpretation of syscalls */
3787c478bd9Sstevel@tonic-gate 			if (syslist(optarg, &rawout, &xflag))
3797c478bd9Sstevel@tonic-gate 				badname = TRUE;
3807c478bd9Sstevel@tonic-gate 			break;
3817c478bd9Sstevel@tonic-gate 		case 's':		/* signals to trace */
3827c478bd9Sstevel@tonic-gate 			if (siglist(pri, optarg, &signals, &sflag))
3837c478bd9Sstevel@tonic-gate 				badname = TRUE;
3847c478bd9Sstevel@tonic-gate 			break;
3857c478bd9Sstevel@tonic-gate 		case 'S':		/* signals to hang process */
3867c478bd9Sstevel@tonic-gate 			if (siglist(pri, optarg, &sighang, &Sflag))
3877c478bd9Sstevel@tonic-gate 				badname = TRUE;
3887c478bd9Sstevel@tonic-gate 			break;
3897c478bd9Sstevel@tonic-gate 		case 'm':		/* machine faults to trace */
3907c478bd9Sstevel@tonic-gate 			if (fltlist(optarg, &faults, &mflag))
3917c478bd9Sstevel@tonic-gate 				badname = TRUE;
3927c478bd9Sstevel@tonic-gate 			break;
3937c478bd9Sstevel@tonic-gate 		case 'M':		/* machine faults to hang process */
3947c478bd9Sstevel@tonic-gate 			if (fltlist(optarg, &flthang, &Mflag))
3957c478bd9Sstevel@tonic-gate 				badname = TRUE;
3967c478bd9Sstevel@tonic-gate 			break;
3977c478bd9Sstevel@tonic-gate 		case 'u':		/* user library functions to trace */
3987c478bd9Sstevel@tonic-gate 			if (liblist(optarg, 0))
3997c478bd9Sstevel@tonic-gate 				badname = TRUE;
4007c478bd9Sstevel@tonic-gate 			break;
4017c478bd9Sstevel@tonic-gate 		case 'U':		/* user library functions to hang */
4027c478bd9Sstevel@tonic-gate 			if (liblist(optarg, 1))
4037c478bd9Sstevel@tonic-gate 				badname = TRUE;
4047c478bd9Sstevel@tonic-gate 			break;
4057c478bd9Sstevel@tonic-gate 		case 'r':		/* show contents of read(fd) */
4067c478bd9Sstevel@tonic-gate 			if (fdlist(optarg, &readfd))
4077c478bd9Sstevel@tonic-gate 				badname = TRUE;
4087c478bd9Sstevel@tonic-gate 			break;
4097c478bd9Sstevel@tonic-gate 		case 'w':		/* show contents of write(fd) */
4107c478bd9Sstevel@tonic-gate 			if (fdlist(optarg, &writefd))
4117c478bd9Sstevel@tonic-gate 				badname = TRUE;
4127c478bd9Sstevel@tonic-gate 			break;
4137c478bd9Sstevel@tonic-gate 		case 'o':		/* output file for trace */
4147c478bd9Sstevel@tonic-gate 			oflag = TRUE;
4157c478bd9Sstevel@tonic-gate 			if (ofd >= 0)
4167c478bd9Sstevel@tonic-gate 				(void) close(ofd);
4177c478bd9Sstevel@tonic-gate 			if ((ofd = xcreat(optarg)) < 0) {
4187c478bd9Sstevel@tonic-gate 				perror(optarg);
4197c478bd9Sstevel@tonic-gate 				badname = TRUE;
4207c478bd9Sstevel@tonic-gate 			}
4217c478bd9Sstevel@tonic-gate 			break;
4227c478bd9Sstevel@tonic-gate 		default:
4237c478bd9Sstevel@tonic-gate 			errflg = TRUE;
4247c478bd9Sstevel@tonic-gate 			break;
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if (badname)
4297c478bd9Sstevel@tonic-gate 		exit(2);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* if -a or -e was specified, force tracing of exec() */
4328fd04b83SRoger A. Faulkner 	if (aflag || eflag)
4337c478bd9Sstevel@tonic-gate 		praddset(&trace, SYS_execve);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	/*
4367c478bd9Sstevel@tonic-gate 	 * Make sure that all system calls, signals, and machine faults
4377c478bd9Sstevel@tonic-gate 	 * that hang the process are added to their trace sets.
4387c478bd9Sstevel@tonic-gate 	 */
4397c478bd9Sstevel@tonic-gate 	prorset(&trace, &syshang);
4407c478bd9Sstevel@tonic-gate 	prorset(&signals, &sighang);
4417c478bd9Sstevel@tonic-gate 	prorset(&faults, &flthang);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	argc -= optind;
4447c478bd9Sstevel@tonic-gate 	argv += optind;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/* collect the specified process ids */
4477c478bd9Sstevel@tonic-gate 	if (pflag && argc > 0) {
4487c478bd9Sstevel@tonic-gate 		grab = my_malloc(argc * sizeof (proc_set_t),
4498fd04b83SRoger A. Faulkner 		    "memory for process-ids");
4507c478bd9Sstevel@tonic-gate 		while (argc-- > 0)
4517c478bd9Sstevel@tonic-gate 			pids(*argv++, grab);
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (errflg || (argc <= 0 && ngrab <= 0)) {
4557c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4567c478bd9Sstevel@tonic-gate 	"usage:\t%s [-fcaeildDEF] [-[tTvx] [!]syscalls] [-[sS] [!]signals]\\\n",
4578fd04b83SRoger A. Faulkner 		    command);
4587c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4597c478bd9Sstevel@tonic-gate 	"\t[-[mM] [!]faults] [-[rw] [!]fds] [-[uU] [!]libs:[:][!]funcs]\\\n");
4607c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
4618fd04b83SRoger A. Faulkner 		    "\t[-o outfile]  command | -p pid[/lwps] ...\n");
4627c478bd9Sstevel@tonic-gate 		exit(2);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	if (argc > 0) {		/* create the controlled process */
4667c478bd9Sstevel@tonic-gate 		int err;
4677c478bd9Sstevel@tonic-gate 		char path[PATH_MAX];
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		Proc = Pcreate(argv[0], &argv[0], &err, path, sizeof (path));
4707c478bd9Sstevel@tonic-gate 		if (Proc == NULL) {
4717c478bd9Sstevel@tonic-gate 			switch (err) {
4727c478bd9Sstevel@tonic-gate 			case C_PERM:
4737c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
4748fd04b83SRoger A. Faulkner 				    "%s: cannot trace set-id or "
4758fd04b83SRoger A. Faulkner 				    "unreadable object file: %s\n",
4768fd04b83SRoger A. Faulkner 				    command, path);
4777c478bd9Sstevel@tonic-gate 				break;
4787c478bd9Sstevel@tonic-gate 			case C_LP64:
4797c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
4808fd04b83SRoger A. Faulkner 				    "%s: cannot control _LP64 "
4818fd04b83SRoger A. Faulkner 				    "program: %s\n",
4828fd04b83SRoger A. Faulkner 				    command, path);
4837c478bd9Sstevel@tonic-gate 				break;
4847c478bd9Sstevel@tonic-gate 			case C_NOEXEC:
4857c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
4868fd04b83SRoger A. Faulkner 				    "%s: cannot execute program: %s\n",
4878fd04b83SRoger A. Faulkner 				    command, argv[0]);
4887c478bd9Sstevel@tonic-gate 				break;
4897c478bd9Sstevel@tonic-gate 			case C_NOENT:
4907c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
4918fd04b83SRoger A. Faulkner 				    "%s: cannot find program: %s\n",
4928fd04b83SRoger A. Faulkner 				    command, argv[0]);
4937c478bd9Sstevel@tonic-gate 				break;
4947c478bd9Sstevel@tonic-gate 			case C_STRANGE:
4957c478bd9Sstevel@tonic-gate 				break;
4967c478bd9Sstevel@tonic-gate 			default:
4977c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s\n",
4988fd04b83SRoger A. Faulkner 				    command, Pcreate_error(err));
4997c478bd9Sstevel@tonic-gate 				break;
5007c478bd9Sstevel@tonic-gate 			}
5017c478bd9Sstevel@tonic-gate 			exit(2);
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate 		if (fflag || Dynpat != NULL)
5047c478bd9Sstevel@tonic-gate 			(void) Psetflags(Proc, PR_FORK);
5057c478bd9Sstevel@tonic-gate 		else
5067c478bd9Sstevel@tonic-gate 			(void) Punsetflags(Proc, PR_FORK);
5077c478bd9Sstevel@tonic-gate 		Psp = Pstatus(Proc);
5087c478bd9Sstevel@tonic-gate 		Lsp = &Psp->pr_lwp;
5097c478bd9Sstevel@tonic-gate 		pri->lwpstat = Lsp;
5107c478bd9Sstevel@tonic-gate 		data_model = Psp->pr_dmodel;
5117c478bd9Sstevel@tonic-gate 		created = Psp->pr_pid;
5127c478bd9Sstevel@tonic-gate 		make_pname(pri, 0);
5137c478bd9Sstevel@tonic-gate 		(void) sysentry(pri, 1);
5147c478bd9Sstevel@tonic-gate 		pri->length = 0;
5157c478bd9Sstevel@tonic-gate 		if (!cflag && prismember(&trace, SYS_execve)) {
5167c478bd9Sstevel@tonic-gate 			pri->exec_string = my_realloc(pri->exec_string,
5178fd04b83SRoger A. Faulkner 			    strlen(pri->sys_string) + 1, NULL);
5187c478bd9Sstevel@tonic-gate 			(void) strcpy(pri->exec_pname, pri->pname);
5197c478bd9Sstevel@tonic-gate 			(void) strcpy(pri->exec_string, pri->sys_string);
5207c478bd9Sstevel@tonic-gate 			pri->length += strlen(pri->sys_string);
5217c478bd9Sstevel@tonic-gate 			pri->exec_lwpid = pri->lwpstat->pr_lwpid;
5227c478bd9Sstevel@tonic-gate 			pri->sys_leng = 0;
5237c478bd9Sstevel@tonic-gate 			*pri->sys_string = '\0';
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 		pri->syslast = Psp->pr_stime;
5267c478bd9Sstevel@tonic-gate 		pri->usrlast = Psp->pr_utime;
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/*
5307c478bd9Sstevel@tonic-gate 	 * Now that we have created the victim process,
5317c478bd9Sstevel@tonic-gate 	 * give ourself a million file descriptors.
5327c478bd9Sstevel@tonic-gate 	 * This is enough to deal with a multithreaded
5337c478bd9Sstevel@tonic-gate 	 * victim process that has half a million lwps.
5347c478bd9Sstevel@tonic-gate 	 */
5357c478bd9Sstevel@tonic-gate 	rlim.rlim_cur = 1024 * 1024;
5367c478bd9Sstevel@tonic-gate 	rlim.rlim_max = 1024 * 1024;
5377c478bd9Sstevel@tonic-gate 	if ((Euid != 0 || setrlimit(RLIMIT_NOFILE, &rlim) != 0) &&
5387c478bd9Sstevel@tonic-gate 	    getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
5397c478bd9Sstevel@tonic-gate 		/*
5407c478bd9Sstevel@tonic-gate 		 * Failing the million, give ourself as many
5417c478bd9Sstevel@tonic-gate 		 * file descriptors as we can get.
5427c478bd9Sstevel@tonic-gate 		 */
5437c478bd9Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
5447c478bd9Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
5457c478bd9Sstevel@tonic-gate 	}
546004388ebScasper 	(void) enable_extended_FILE_stdio(-1, -1);
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	setoutput(ofd);		/* establish truss output */
5497c478bd9Sstevel@tonic-gate 	istty = isatty(1);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (setvbuf(stdout, (char *)NULL, _IOFBF, MYBUFSIZ) != 0)
5527c478bd9Sstevel@tonic-gate 		abend("setvbuf() failure", NULL);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * Set up signal dispositions.
5567c478bd9Sstevel@tonic-gate 	 */
5577c478bd9Sstevel@tonic-gate 	if (created && (oflag || !istty)) {	/* ignore interrupts */
5587c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, SIG_IGN);
5597c478bd9Sstevel@tonic-gate 		(void) sigset(SIGINT, SIG_IGN);
5607c478bd9Sstevel@tonic-gate 		(void) sigset(SIGQUIT, SIG_IGN);
5617c478bd9Sstevel@tonic-gate 	} else {				/* receive interrupts */
5627c478bd9Sstevel@tonic-gate 		if (sigset(SIGHUP, SIG_IGN) == SIG_DFL)
5637c478bd9Sstevel@tonic-gate 			(void) sigset(SIGHUP, intr);
5647c478bd9Sstevel@tonic-gate 		if (sigset(SIGINT, SIG_IGN) == SIG_DFL)
5657c478bd9Sstevel@tonic-gate 			(void) sigset(SIGINT, intr);
5667c478bd9Sstevel@tonic-gate 		if (sigset(SIGQUIT, SIG_IGN) == SIG_DFL)
5677c478bd9Sstevel@tonic-gate 			(void) sigset(SIGQUIT, intr);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	(void) sigset(SIGTERM, intr);
5707c478bd9Sstevel@tonic-gate 	(void) sigset(SIGUSR1, intr);
5717c478bd9Sstevel@tonic-gate 	(void) sigset(SIGUSR2, intr);
5727c478bd9Sstevel@tonic-gate 	(void) sigset(SIGPIPE, intr);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	/* don't accumulate zombie children */
5757c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCLD, SIG_IGN);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	/* create shared mem space for global mutexes */
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	sharedmem = (fflag || Dynpat != NULL || ngrab > 1);
5807c478bd9Sstevel@tonic-gate 	gps = (void *)mmap(NULL, sizeof (struct global_psinfo),
5817c478bd9Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE,
5827c478bd9Sstevel@tonic-gate 	    MAP_ANON | (sharedmem? MAP_SHARED : MAP_PRIVATE),
5837c478bd9Sstevel@tonic-gate 	    -1, (off_t)0);
5847c478bd9Sstevel@tonic-gate 	if (gps == MAP_FAILED)
5857c478bd9Sstevel@tonic-gate 		abend("cannot allocate ", "memory for counts");
5867c478bd9Sstevel@tonic-gate 	i = sharedmem? USYNC_PROCESS : USYNC_THREAD;
5877c478bd9Sstevel@tonic-gate 	(void) mutex_init(&gps->ps_mutex0, i, NULL);
5887c478bd9Sstevel@tonic-gate 	(void) mutex_init(&gps->ps_mutex1, i, NULL);
5897c478bd9Sstevel@tonic-gate 	(void) mutex_init(&gps->fork_lock, i, NULL);
5907c478bd9Sstevel@tonic-gate 	(void) cond_init(&gps->fork_cv, i, NULL);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	/* config tmp file if counting and following */
5947c478bd9Sstevel@tonic-gate 	if (fflag && cflag) {
5957c478bd9Sstevel@tonic-gate 		char *tmps = tempnam("/var/tmp", "truss");
5967c478bd9Sstevel@tonic-gate 		sfd = open(tmps, O_CREAT|O_APPEND|O_EXCL|O_RDWR, 0600);
5977c478bd9Sstevel@tonic-gate 		if (sfd == -1)
5987c478bd9Sstevel@tonic-gate 			abend("Error creating tmpfile", NULL);
5997c478bd9Sstevel@tonic-gate 		if (unlink(tmps) == -1)
6007c478bd9Sstevel@tonic-gate 			abend("Error unlinking tmpfile", NULL);
6017c478bd9Sstevel@tonic-gate 		free(tmps);
6027c478bd9Sstevel@tonic-gate 		tmps = NULL;
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (created) {
6067c478bd9Sstevel@tonic-gate 		per_proc_init();
6077c478bd9Sstevel@tonic-gate 		procadd(created, NULL);
608134a1f4eSCasper H.S. Dik 		show_cred(pri, TRUE, FALSE);
6097c478bd9Sstevel@tonic-gate 	} else {		/* grab the specified processes */
6107c478bd9Sstevel@tonic-gate 		int gotone = FALSE;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 		i = 0;
6137c478bd9Sstevel@tonic-gate 		while (i < ngrab) {		/* grab first process */
6147c478bd9Sstevel@tonic-gate 			if (grabit(pri, &grab[i++])) {
6157c478bd9Sstevel@tonic-gate 				Psp = Pstatus(Proc);
6167c478bd9Sstevel@tonic-gate 				Lsp = &Psp->pr_lwp;
6177c478bd9Sstevel@tonic-gate 				gotone = TRUE;
6187c478bd9Sstevel@tonic-gate 				break;
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 		if (!gotone)
6227c478bd9Sstevel@tonic-gate 			abend(NULL, NULL);
6237c478bd9Sstevel@tonic-gate 		per_proc_init();
6247c478bd9Sstevel@tonic-gate 		while (i < ngrab) {		/* grab the remainder */
6257c478bd9Sstevel@tonic-gate 			proc_set_t *set = &grab[i++];
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&truss_lock);
628657b1f3dSraf 			switch (fork()) {
6297c478bd9Sstevel@tonic-gate 			case -1:
6307c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
6317c478bd9Sstevel@tonic-gate 			"%s: cannot fork to control process, pid# %d\n",
6328fd04b83SRoger A. Faulkner 				    command, (int)set->pid);
6337c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
6347c478bd9Sstevel@tonic-gate 			default:
6357c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
6367c478bd9Sstevel@tonic-gate 				continue;	/* parent carries on */
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 			case 0:			/* child grabs process */
6397c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
6407c478bd9Sstevel@tonic-gate 				Pfree(Proc);
6417c478bd9Sstevel@tonic-gate 				descendent = TRUE;
6427c478bd9Sstevel@tonic-gate 				if (grabit(pri, set)) {
6437c478bd9Sstevel@tonic-gate 					Psp = Pstatus(Proc);
6447c478bd9Sstevel@tonic-gate 					Lsp = &Psp->pr_lwp;
6457c478bd9Sstevel@tonic-gate 					per_proc_init();
6467c478bd9Sstevel@tonic-gate 					break;
6477c478bd9Sstevel@tonic-gate 				}
6487c478bd9Sstevel@tonic-gate 				exit(2);
6497c478bd9Sstevel@tonic-gate 			}
6507c478bd9Sstevel@tonic-gate 			break;
6517c478bd9Sstevel@tonic-gate 		}
6527c478bd9Sstevel@tonic-gate 		free(grab);
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	/*
6577c478bd9Sstevel@tonic-gate 	 * If running setuid-root, become root for real to avoid
6587c478bd9Sstevel@tonic-gate 	 * affecting the per-user limitation on the maximum number
6597c478bd9Sstevel@tonic-gate 	 * of processes (one benefit of running setuid-root).
6607c478bd9Sstevel@tonic-gate 	 */
6617c478bd9Sstevel@tonic-gate 	if (Rgid != Egid)
6627c478bd9Sstevel@tonic-gate 		(void) setgid(Egid);
6637c478bd9Sstevel@tonic-gate 	if (Ruid != Euid)
6647c478bd9Sstevel@tonic-gate 		(void) setuid(Euid);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (!created && aflag && prismember(&trace, SYS_execve)) {
6677c478bd9Sstevel@tonic-gate 		psargs(pri);
6687c478bd9Sstevel@tonic-gate 		Flush();
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (created && Pstate(Proc) != PS_STOP)	/* assertion */
6727c478bd9Sstevel@tonic-gate 		if (!(interrupt | sigusr1))
6737c478bd9Sstevel@tonic-gate 			abend("ASSERT error: process is not stopped", NULL);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	traceeven = trace;		/* trace these system calls */
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 	/* trace these regardless, even if we don't report results */
6787c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_exit);
6797c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_lwp_create);
6807c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_lwp_exit);
6817c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_execve);
6828fd04b83SRoger A. Faulkner 	praddset(&traceeven, SYS_openat);
6838fd04b83SRoger A. Faulkner 	praddset(&traceeven, SYS_openat64);
6847c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_open);
6857c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_open64);
6867c478bd9Sstevel@tonic-gate 	praddset(&traceeven, SYS_vfork);
687657b1f3dSraf 	praddset(&traceeven, SYS_forksys);
688350ffdd5SRobert Mustacchi 	praddset(&traceeven, SYS_upanic);
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	/* for I/O buffer dumps, force tracing of read()s and write()s */
6917c478bd9Sstevel@tonic-gate 	if (!isemptyset(&readfd)) {
6927c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_read);
6937c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_readv);
6947c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pread);
6957c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pread64);
6967c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_recv);
6977c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_recvfrom);
6987c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_recvmsg);
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 	if (!isemptyset(&writefd)) {
7017c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_write);
7027c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_writev);
7037c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pwrite);
7047c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_pwrite64);
7057c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_send);
7067c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_sendto);
7077c478bd9Sstevel@tonic-gate 		praddset(&traceeven, SYS_sendmsg);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (cflag || Eflag) {
7117c478bd9Sstevel@tonic-gate 		Psetsysentry(Proc, &traceeven);
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 	Psetsysexit(Proc, &traceeven);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/* special case -- cannot trace sysexit because context is changed */
7167c478bd9Sstevel@tonic-gate 	if (prismember(&trace, SYS_context)) {
7177c478bd9Sstevel@tonic-gate 		(void) Psysentry(Proc, SYS_context, TRUE);
7187c478bd9Sstevel@tonic-gate 		(void) Psysexit(Proc, SYS_context, FALSE);
7197c478bd9Sstevel@tonic-gate 		prdelset(&traceeven, SYS_context);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/* special case -- trace exec() on entry to get the args */
7237c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_execve, TRUE);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/* special case -- sysexit never reached */
7267c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_exit, TRUE);
7277c478bd9Sstevel@tonic-gate 	(void) Psysentry(Proc, SYS_lwp_exit, TRUE);
728350ffdd5SRobert Mustacchi 	(void) Psysentry(Proc, SYS_upanic, TRUE);
7297c478bd9Sstevel@tonic-gate 	(void) Psysexit(Proc, SYS_exit, FALSE);
7307c478bd9Sstevel@tonic-gate 	(void) Psysexit(Proc, SYS_lwp_exit, FALSE);
731350ffdd5SRobert Mustacchi 	(void) Psysexit(Proc, SYS_upanic, FALSE);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	Psetsignal(Proc, &signals);	/* trace these signals */
7347c478bd9Sstevel@tonic-gate 	Psetfault(Proc, &faults);	/* trace these faults */
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	/* for function call tracing */
7377c478bd9Sstevel@tonic-gate 	if (Dynpat != NULL) {
7387c478bd9Sstevel@tonic-gate 		/* trace these regardless, to deal with function calls */
7397c478bd9Sstevel@tonic-gate 		(void) Pfault(Proc, FLTBPT, TRUE);
7407c478bd9Sstevel@tonic-gate 		(void) Pfault(Proc, FLTTRACE, TRUE);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		/* needed for x86 */
7437c478bd9Sstevel@tonic-gate 		(void) Psetflags(Proc, PR_BPTADJ);
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		/*
7467c478bd9Sstevel@tonic-gate 		 * Find functions and set breakpoints on grabbed process.
7477c478bd9Sstevel@tonic-gate 		 * A process stopped on exec() gets its breakpoints set below.
7487c478bd9Sstevel@tonic-gate 		 */
7497c478bd9Sstevel@tonic-gate 		if ((Lsp->pr_why != PR_SYSENTRY &&
7507c478bd9Sstevel@tonic-gate 		    Lsp->pr_why != PR_SYSEXIT) ||
7518fd04b83SRoger A. Faulkner 		    Lsp->pr_what != SYS_execve) {
7527c478bd9Sstevel@tonic-gate 			establish_breakpoints();
7537c478bd9Sstevel@tonic-gate 			establish_stacks();
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	/*
7587c478bd9Sstevel@tonic-gate 	 * Use asynchronous-stop for multithreaded truss.
7597c478bd9Sstevel@tonic-gate 	 * truss runs one lwp for each lwp in the target process.
7607c478bd9Sstevel@tonic-gate 	 */
7617c478bd9Sstevel@tonic-gate 	(void) Psetflags(Proc, PR_ASYNC);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	/* flush out all tracing flags now. */
7647c478bd9Sstevel@tonic-gate 	Psync(Proc);
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	/*
7677c478bd9Sstevel@tonic-gate 	 * If we grabbed a running process, set it running again.
7687c478bd9Sstevel@tonic-gate 	 * Since we are tracing lwp_create() and lwp_exit(), the
7697c478bd9Sstevel@tonic-gate 	 * lwps will not change in the process until we create all
7707c478bd9Sstevel@tonic-gate 	 * of the truss worker threads.
7717c478bd9Sstevel@tonic-gate 	 * We leave a created process stopped so its exec() can be reported.
7727c478bd9Sstevel@tonic-gate 	 */
7737c478bd9Sstevel@tonic-gate 	first = created? FALSE : TRUE;
7747c478bd9Sstevel@tonic-gate 	if (!created &&
7757c478bd9Sstevel@tonic-gate 	    ((Pstate(Proc) == PS_STOP && Lsp->pr_why == PR_REQUESTED) ||
7767c478bd9Sstevel@tonic-gate 	    (Lsp->pr_flags & PR_DSTOP)))
7777c478bd9Sstevel@tonic-gate 		first = FALSE;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	main_thread(first);
7807c478bd9Sstevel@tonic-gate 	return (0);
7817c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate /*
784657b1f3dSraf  * Called from main() and from control() after fork().
7857c478bd9Sstevel@tonic-gate  */
7867c478bd9Sstevel@tonic-gate void
main_thread(int first)7877c478bd9Sstevel@tonic-gate main_thread(int first)
7887c478bd9Sstevel@tonic-gate {
7897c478bd9Sstevel@tonic-gate 	private_t *pri = get_private();
7907c478bd9Sstevel@tonic-gate 	struct tms tms;
7917c478bd9Sstevel@tonic-gate 	int flags;
7927c478bd9Sstevel@tonic-gate 	int retc;
7937c478bd9Sstevel@tonic-gate 	int i;
7947c478bd9Sstevel@tonic-gate 	int count;
7957c478bd9Sstevel@tonic-gate 
79653e568b1Sraf 	/*
79753e568b1Sraf 	 * Block all signals in the main thread.
79853e568b1Sraf 	 * Some worker thread will receive signals.
79953e568b1Sraf 	 */
80053e568b1Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
80153e568b1Sraf 
8027c478bd9Sstevel@tonic-gate 	/*
8037c478bd9Sstevel@tonic-gate 	 * If we are dealing with a previously hung process,
8047c478bd9Sstevel@tonic-gate 	 * arrange not to leave it hung on the same system call.
8057c478bd9Sstevel@tonic-gate 	 */
8067c478bd9Sstevel@tonic-gate 	primary_lwp = (first && Pstate(Proc) == PS_STOP)?
8078fd04b83SRoger A. Faulkner 	    Pstatus(Proc)->pr_lwp.pr_lwpid : 0;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	/*
8107c478bd9Sstevel@tonic-gate 	 * Create worker threads to match the lwps in the target process.
8117c478bd9Sstevel@tonic-gate 	 */
8127c478bd9Sstevel@tonic-gate 	truss_nlwp = 0;
8137c478bd9Sstevel@tonic-gate 	truss_maxlwp = 1;
8147c478bd9Sstevel@tonic-gate 	truss_lwpid = my_realloc(truss_lwpid, sizeof (lwpid_t), NULL);
8157c478bd9Sstevel@tonic-gate 	truss_lwpid[0] = 0;
8167c478bd9Sstevel@tonic-gate 	count = 0;
8177c478bd9Sstevel@tonic-gate 	(void) Plwp_iter(Proc, create_thread, &count);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	if (count == 0) {
8207c478bd9Sstevel@tonic-gate 		(void) printf("(Warning: no matching active LWPs found, "
8217c478bd9Sstevel@tonic-gate 		    "waiting)\n");
8227c478bd9Sstevel@tonic-gate 		Flush();
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	/*
8267c478bd9Sstevel@tonic-gate 	 * Set all of the truss worker threads running now.
8277c478bd9Sstevel@tonic-gate 	 */
8287c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&truss_lock);
8297c478bd9Sstevel@tonic-gate 	for (i = 0; i < truss_maxlwp; i++) {
8307c478bd9Sstevel@tonic-gate 		if (truss_lwpid[i])
8317c478bd9Sstevel@tonic-gate 			(void) thr_continue(truss_lwpid[i]);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	/*
83653e568b1Sraf 	 * Wait until all worker threads terminate.
8377c478bd9Sstevel@tonic-gate 	 */
83853e568b1Sraf 	while (thr_join(0, NULL, NULL) == 0)
83953e568b1Sraf 		continue;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	(void) Punsetflags(Proc, PR_ASYNC);
8427c478bd9Sstevel@tonic-gate 	Psync(Proc);
8437c478bd9Sstevel@tonic-gate 	if (sigusr1)
8447c478bd9Sstevel@tonic-gate 		letgo(pri);
8457c478bd9Sstevel@tonic-gate 	flags = PRELEASE_CLEAR;
8467c478bd9Sstevel@tonic-gate 	if (leave_hung)
8477c478bd9Sstevel@tonic-gate 		flags |= PRELEASE_HANG;
8487c478bd9Sstevel@tonic-gate 	Prelease(Proc, flags);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	procdel();
8517c478bd9Sstevel@tonic-gate 	retc = (leave_hung? 0 : wait4all());
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	if (!descendent) {
8547c478bd9Sstevel@tonic-gate 		interrupt = 0;	/* another interrupt kills the report */
8557c478bd9Sstevel@tonic-gate 		if (cflag) {
8567c478bd9Sstevel@tonic-gate 			if (fflag)
8577c478bd9Sstevel@tonic-gate 				file_to_parent();
8587c478bd9Sstevel@tonic-gate 			report(pri, times(&tms) - starttime);
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate 	} else if (cflag && fflag) {
8617c478bd9Sstevel@tonic-gate 		child_to_file();
8627c478bd9Sstevel@tonic-gate 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	exit(retc);	/* exit with exit status of created process, else 0 */
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate void *
worker_thread(void * arg)8687c478bd9Sstevel@tonic-gate worker_thread(void *arg)
8697c478bd9Sstevel@tonic-gate {
8707c478bd9Sstevel@tonic-gate 	struct ps_lwphandle *Lwp = (struct ps_lwphandle *)arg;
8717c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp = Pstatus(Proc);
8727c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp = Lstatus(Lwp);
8737c478bd9Sstevel@tonic-gate 	struct syscount *scp;
8747c478bd9Sstevel@tonic-gate 	lwpid_t who = Lsp->pr_lwpid;
8757c478bd9Sstevel@tonic-gate 	int first = (who == primary_lwp);
8767c478bd9Sstevel@tonic-gate 	private_t *pri = get_private();
8777c478bd9Sstevel@tonic-gate 	int req_flag = 0;
87853e568b1Sraf 	int leave_it_hung = FALSE;
8797c478bd9Sstevel@tonic-gate 	int reset_traps = FALSE;
8807c478bd9Sstevel@tonic-gate 	int gcode;
8817c478bd9Sstevel@tonic-gate 	int what;
8827c478bd9Sstevel@tonic-gate 	int ow_in_effect = 0;
8837c478bd9Sstevel@tonic-gate 	long ow_syscall = 0;
8847c478bd9Sstevel@tonic-gate 	long ow_subcode = 0;
8857c478bd9Sstevel@tonic-gate 	char *ow_string = NULL;
8867c478bd9Sstevel@tonic-gate 	sysset_t full_set;
8877c478bd9Sstevel@tonic-gate 	sysset_t running_set;
8887c478bd9Sstevel@tonic-gate 	int dotrace = lwptrace(Psp->pr_pid, Lsp->pr_lwpid);
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	pri->Lwp = Lwp;
8917c478bd9Sstevel@tonic-gate 	pri->lwpstat = Lsp;
8927c478bd9Sstevel@tonic-gate 	pri->syslast = Lsp->pr_stime;
8937c478bd9Sstevel@tonic-gate 	pri->usrlast = Lsp->pr_utime;
8947c478bd9Sstevel@tonic-gate 	make_pname(pri, 0);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	prfillset(&full_set);
8977c478bd9Sstevel@tonic-gate 
89853e568b1Sraf 	/* we were created with all signals blocked; unblock them */
89953e568b1Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &emptyset, NULL);
90053e568b1Sraf 
9017c478bd9Sstevel@tonic-gate 	/*
90253e568b1Sraf 	 * Run this loop until the victim lwp terminates or we receive
90353e568b1Sraf 	 * a termination condition (leave_hung | interrupt | sigusr1).
9047c478bd9Sstevel@tonic-gate 	 */
9057c478bd9Sstevel@tonic-gate 	for (;;) {
9067c478bd9Sstevel@tonic-gate 		if (interrupt | sigusr1) {
9077c478bd9Sstevel@tonic-gate 			(void) Lstop(Lwp, MILLISEC);
9087c478bd9Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_RUN)
9097c478bd9Sstevel@tonic-gate 				break;
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_RUN) {
9127c478bd9Sstevel@tonic-gate 			/* millisecond timeout is for sleeping syscalls */
9137c478bd9Sstevel@tonic-gate 			uint_t tout = (iflag || req_flag)? 0 : MILLISEC;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 			/*
9167c478bd9Sstevel@tonic-gate 			 * If we are to leave this lwp stopped in sympathy
9177c478bd9Sstevel@tonic-gate 			 * with another lwp that has been left hung, or if
9187c478bd9Sstevel@tonic-gate 			 * we have been interrupted or instructed to release
9197c478bd9Sstevel@tonic-gate 			 * our victim process, and this lwp is stopped but
9207c478bd9Sstevel@tonic-gate 			 * not on an event of interest to /proc, then just
9217c478bd9Sstevel@tonic-gate 			 * leave it in that state.
9227c478bd9Sstevel@tonic-gate 			 */
9237c478bd9Sstevel@tonic-gate 			if ((leave_hung | interrupt | sigusr1) &&
9247c478bd9Sstevel@tonic-gate 			    (Lsp->pr_flags & (PR_STOPPED|PR_ISTOP))
9257c478bd9Sstevel@tonic-gate 			    == PR_STOPPED)
9267c478bd9Sstevel@tonic-gate 				break;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 			(void) Lwait(Lwp, tout);
9297c478bd9Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_RUN &&
9307c478bd9Sstevel@tonic-gate 			    tout != 0 && !(interrupt | sigusr1)) {
9317c478bd9Sstevel@tonic-gate 				(void) mutex_lock(&truss_lock);
9327c478bd9Sstevel@tonic-gate 				if ((Lsp->pr_flags & PR_STOPPED) &&
9337c478bd9Sstevel@tonic-gate 				    Lsp->pr_why == PR_JOBCONTROL)
9347c478bd9Sstevel@tonic-gate 					req_flag = jobcontrol(pri, dotrace);
9357c478bd9Sstevel@tonic-gate 				else
9367c478bd9Sstevel@tonic-gate 					req_flag = requested(pri, req_flag,
9377c478bd9Sstevel@tonic-gate 					    dotrace);
9387c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
9397c478bd9Sstevel@tonic-gate 			}
9407c478bd9Sstevel@tonic-gate 			continue;
9417c478bd9Sstevel@tonic-gate 		}
9427c478bd9Sstevel@tonic-gate 		data_model = Psp->pr_dmodel;
9437c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_UNDEAD)
9447c478bd9Sstevel@tonic-gate 			break;
9457c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_LOST) {	/* we lost control */
9467c478bd9Sstevel@tonic-gate 			/*
9477c478bd9Sstevel@tonic-gate 			 * After exec(), only one LWP remains in the process.
9487c478bd9Sstevel@tonic-gate 			 * /proc makes the thread following that LWP receive
9497c478bd9Sstevel@tonic-gate 			 * EAGAIN (PS_LOST) if the program being exec()ed
9507c478bd9Sstevel@tonic-gate 			 * is a set-id program.  Every other controlling
9517c478bd9Sstevel@tonic-gate 			 * thread receives ENOENT (because its LWP vanished).
9527c478bd9Sstevel@tonic-gate 			 * We are the controlling thread for the exec()ing LWP.
9537c478bd9Sstevel@tonic-gate 			 * We must wait until all of our siblings terminate
9547c478bd9Sstevel@tonic-gate 			 * before attempting to reopen the process.
9557c478bd9Sstevel@tonic-gate 			 */
9567c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&truss_lock);
9577c478bd9Sstevel@tonic-gate 			while (truss_nlwp > 1)
9587c478bd9Sstevel@tonic-gate 				(void) cond_wait(&truss_cv, &truss_lock);
9597c478bd9Sstevel@tonic-gate 			if (Preopen(Proc) == 0) { /* we got control back */
9607c478bd9Sstevel@tonic-gate 				/*
9617c478bd9Sstevel@tonic-gate 				 * We have to free and re-grab the LWP.
9627c478bd9Sstevel@tonic-gate 				 * The process is guaranteed to be at exit
9637c478bd9Sstevel@tonic-gate 				 * from exec() or execve() and have only
9647c478bd9Sstevel@tonic-gate 				 * one LWP, namely this one, and the LWP
9657c478bd9Sstevel@tonic-gate 				 * is guaranteed to have lwpid == 1.
9667c478bd9Sstevel@tonic-gate 				 * This "cannot fail".
9677c478bd9Sstevel@tonic-gate 				 */
9687c478bd9Sstevel@tonic-gate 				who = 1;
9697c478bd9Sstevel@tonic-gate 				Lfree(Lwp);
9707c478bd9Sstevel@tonic-gate 				pri->Lwp = Lwp =
9718fd04b83SRoger A. Faulkner 				    Lgrab(Proc, who, &gcode);
9727c478bd9Sstevel@tonic-gate 				if (Lwp == NULL)
9737c478bd9Sstevel@tonic-gate 					abend("Lgrab error: ",
9748fd04b83SRoger A. Faulkner 					    Lgrab_error(gcode));
9757c478bd9Sstevel@tonic-gate 				pri->lwpstat = Lsp = Lstatus(Lwp);
9767c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
9777c478bd9Sstevel@tonic-gate 				continue;
9787c478bd9Sstevel@tonic-gate 			}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 			/* we really lost it */
9817c478bd9Sstevel@tonic-gate 			if (pri->exec_string && *pri->exec_string) {
9827c478bd9Sstevel@tonic-gate 				if (pri->exec_pname[0] != '\0')
9837c478bd9Sstevel@tonic-gate 					(void) fputs(pri->exec_pname, stdout);
9847c478bd9Sstevel@tonic-gate 				timestamp(pri);
9857c478bd9Sstevel@tonic-gate 				(void) fputs(pri->exec_string, stdout);
9867c478bd9Sstevel@tonic-gate 				(void) fputc('\n', stdout);
9877c478bd9Sstevel@tonic-gate 			} else if (pri->length) {
9887c478bd9Sstevel@tonic-gate 				(void) fputc('\n', stdout);
9897c478bd9Sstevel@tonic-gate 			}
9907c478bd9Sstevel@tonic-gate 			if (pri->sys_valid)
9917c478bd9Sstevel@tonic-gate 				(void) printf(
9927c478bd9Sstevel@tonic-gate 			"%s\t*** cannot trace across exec() of %s ***\n",
9938fd04b83SRoger A. Faulkner 				    pri->pname, pri->sys_path);
9947c478bd9Sstevel@tonic-gate 			else
9957c478bd9Sstevel@tonic-gate 				(void) printf(
9967c478bd9Sstevel@tonic-gate 				"%s\t*** lost control of process ***\n",
9978fd04b83SRoger A. Faulkner 				    pri->pname);
9987c478bd9Sstevel@tonic-gate 			pri->length = 0;
9997c478bd9Sstevel@tonic-gate 			Flush();
10007c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&truss_lock);
10017c478bd9Sstevel@tonic-gate 			break;
10027c478bd9Sstevel@tonic-gate 		}
10037c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) != PS_STOP) {
10047c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
10058fd04b83SRoger A. Faulkner 			    "%s: state = %d\n", command, Lstate(Lwp));
10067c478bd9Sstevel@tonic-gate 			abend(pri->pname, "uncaught status of subject lwp");
10077c478bd9Sstevel@tonic-gate 		}
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 		make_pname(pri, 0);
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		what = Lsp->pr_what;
10147c478bd9Sstevel@tonic-gate 		req_flag = 0;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 		switch (Lsp->pr_why) {
10177c478bd9Sstevel@tonic-gate 		case PR_REQUESTED:
10187c478bd9Sstevel@tonic-gate 			break;
10197c478bd9Sstevel@tonic-gate 		case PR_SIGNALLED:
10207c478bd9Sstevel@tonic-gate 			req_flag = signalled(pri, req_flag, dotrace);
10217c478bd9Sstevel@tonic-gate 			if (Sflag && !first && prismember(&sighang, what))
10227c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
10237c478bd9Sstevel@tonic-gate 			break;
10247c478bd9Sstevel@tonic-gate 		case PR_FAULTED:
10257c478bd9Sstevel@tonic-gate 			if (what == FLTBPT) {
10267c478bd9Sstevel@tonic-gate 				int rval;
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 				(void) Pstop(Proc, 0);
10297c478bd9Sstevel@tonic-gate 				rval = function_trace(pri, first, 0, dotrace);
10307c478bd9Sstevel@tonic-gate 				if (rval == 1)
10317c478bd9Sstevel@tonic-gate 					leave_it_hung = TRUE;
10327c478bd9Sstevel@tonic-gate 				if (rval >= 0)
10337c478bd9Sstevel@tonic-gate 					break;
10347c478bd9Sstevel@tonic-gate 			}
10357c478bd9Sstevel@tonic-gate 			if (faulted(pri, dotrace) &&
10367c478bd9Sstevel@tonic-gate 			    Mflag && !first && prismember(&flthang, what))
10377c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
10387c478bd9Sstevel@tonic-gate 			break;
10397c478bd9Sstevel@tonic-gate 		case PR_JOBCONTROL:	/* can't happen except first time */
10407c478bd9Sstevel@tonic-gate 			req_flag = jobcontrol(pri, dotrace);
10417c478bd9Sstevel@tonic-gate 			break;
10427c478bd9Sstevel@tonic-gate 		case PR_SYSENTRY:
10437c478bd9Sstevel@tonic-gate 			/* protect ourself from operating system error */
10447c478bd9Sstevel@tonic-gate 			if (what <= 0 || what > PRMAXSYS)
10457c478bd9Sstevel@tonic-gate 				what = PRMAXSYS;
10467c478bd9Sstevel@tonic-gate 			pri->length = 0;
10477c478bd9Sstevel@tonic-gate 			/*
10487c478bd9Sstevel@tonic-gate 			 * ow_in_effect checks to see whether or not we
10497c478bd9Sstevel@tonic-gate 			 * are attempting to quantify the time spent in
10507c478bd9Sstevel@tonic-gate 			 * a one way system call.  This is necessary as
10517c478bd9Sstevel@tonic-gate 			 * some system calls never return, yet it is desireable
10527c478bd9Sstevel@tonic-gate 			 * to determine how much time the traced process
10537c478bd9Sstevel@tonic-gate 			 * spends in these calls.  To do this, a one way
10547c478bd9Sstevel@tonic-gate 			 * flag is set on SYSENTRY when the call is recieved.
10557c478bd9Sstevel@tonic-gate 			 * After this, the call mask for the SYSENTRY events
10567c478bd9Sstevel@tonic-gate 			 * is filled so that the traced process will stop
10577c478bd9Sstevel@tonic-gate 			 * on the entry to the very next system call.
10587c478bd9Sstevel@tonic-gate 			 * This appears to the the best way to determine
10597c478bd9Sstevel@tonic-gate 			 * system time elapsed between a one way system call.
10607c478bd9Sstevel@tonic-gate 			 * Once the next call occurs, values that have been
10617c478bd9Sstevel@tonic-gate 			 * stashed are used to record the correct syscall
10627c478bd9Sstevel@tonic-gate 			 * and time, and the SYSENTRY event mask is restored
10637c478bd9Sstevel@tonic-gate 			 * so that the traced process may continue.
10647c478bd9Sstevel@tonic-gate 			 */
10657c478bd9Sstevel@tonic-gate 			if (dotrace && ow_in_effect) {
10667c478bd9Sstevel@tonic-gate 				if (cflag) {
10677c478bd9Sstevel@tonic-gate 					(void) mutex_lock(&count_lock);
10687c478bd9Sstevel@tonic-gate 					scp = Cp->syscount[ow_syscall];
10697c478bd9Sstevel@tonic-gate 					if (ow_subcode != -1)
10707c478bd9Sstevel@tonic-gate 						scp += ow_subcode;
10717c478bd9Sstevel@tonic-gate 					scp->count++;
10727c478bd9Sstevel@tonic-gate 					accumulate(&scp->stime,
10737c478bd9Sstevel@tonic-gate 					    &Lsp->pr_stime, &pri->syslast);
10747c478bd9Sstevel@tonic-gate 					accumulate(&Cp->usrtotal,
10757c478bd9Sstevel@tonic-gate 					    &Lsp->pr_utime, &pri->usrlast);
10767c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
10777c478bd9Sstevel@tonic-gate 					pri->usrlast = Lsp->pr_utime;
10787c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&count_lock);
10797c478bd9Sstevel@tonic-gate 				} else if (Eflag) {
10807c478bd9Sstevel@tonic-gate 					putpname(pri);
10817c478bd9Sstevel@tonic-gate 					timestamp(pri);
10827c478bd9Sstevel@tonic-gate 					(void) printf("%s\n", ow_string);
10837c478bd9Sstevel@tonic-gate 					free(ow_string);
10847c478bd9Sstevel@tonic-gate 					ow_string = NULL;
10857c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
10867c478bd9Sstevel@tonic-gate 				}
10877c478bd9Sstevel@tonic-gate 				ow_in_effect = 0;
10887c478bd9Sstevel@tonic-gate 				Psetsysentry(Proc, &running_set);
10897c478bd9Sstevel@tonic-gate 			}
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 			/*
10927c478bd9Sstevel@tonic-gate 			 * Special cases.  Most syscalls are traced on exit.
10937c478bd9Sstevel@tonic-gate 			 */
10947c478bd9Sstevel@tonic-gate 			switch (what) {
10957c478bd9Sstevel@tonic-gate 			case SYS_exit:			/* exit() */
10967c478bd9Sstevel@tonic-gate 			case SYS_lwp_exit:		/* lwp_exit() */
1097350ffdd5SRobert Mustacchi 			case SYS_upanic:		/* upanic() */
10987c478bd9Sstevel@tonic-gate 			case SYS_context:		/* [get|set]context() */
10997c478bd9Sstevel@tonic-gate 				if (dotrace && cflag &&
11007c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
11017c478bd9Sstevel@tonic-gate 					ow_in_effect = 1;
11027c478bd9Sstevel@tonic-gate 					ow_syscall = what;
11037c478bd9Sstevel@tonic-gate 					ow_subcode = getsubcode(pri);
11047c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
11057c478bd9Sstevel@tonic-gate 					running_set =
11067c478bd9Sstevel@tonic-gate 					    (Pstatus(Proc))->pr_sysentry;
11077c478bd9Sstevel@tonic-gate 					Psetsysentry(Proc, &full_set);
11087c478bd9Sstevel@tonic-gate 				} else if (dotrace && Eflag &&
11097c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
11107c478bd9Sstevel@tonic-gate 					(void) sysentry(pri, dotrace);
11117c478bd9Sstevel@tonic-gate 					ow_in_effect = 1;
11127c478bd9Sstevel@tonic-gate 					ow_string = my_malloc(
11137c478bd9Sstevel@tonic-gate 					    strlen(pri->sys_string) + 1, NULL);
11147c478bd9Sstevel@tonic-gate 					(void) strcpy(ow_string,
11157c478bd9Sstevel@tonic-gate 					    pri->sys_string);
11167c478bd9Sstevel@tonic-gate 					running_set =
11177c478bd9Sstevel@tonic-gate 					    (Pstatus(Proc))->pr_sysentry;
11187c478bd9Sstevel@tonic-gate 					Psetsysentry(Proc, &full_set);
11197c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
11207c478bd9Sstevel@tonic-gate 				} else if (dotrace &&
11217c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
11227c478bd9Sstevel@tonic-gate 					(void) sysentry(pri, dotrace);
11237c478bd9Sstevel@tonic-gate 					putpname(pri);
11247c478bd9Sstevel@tonic-gate 					timestamp(pri);
11257c478bd9Sstevel@tonic-gate 					pri->length +=
11268fd04b83SRoger A. Faulkner 					    printf("%s\n", pri->sys_string);
11277c478bd9Sstevel@tonic-gate 					Flush();
11287c478bd9Sstevel@tonic-gate 				}
11297c478bd9Sstevel@tonic-gate 				pri->sys_leng = 0;
11307c478bd9Sstevel@tonic-gate 				*pri->sys_string = '\0';
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 				if (what == SYS_exit)
11337c478bd9Sstevel@tonic-gate 					exit_called = TRUE;
11347c478bd9Sstevel@tonic-gate 				break;
11357c478bd9Sstevel@tonic-gate 			case SYS_execve:
1136134a1f4eSCasper H.S. Dik 				show_cred(pri, FALSE, TRUE);
11377c478bd9Sstevel@tonic-gate 				(void) sysentry(pri, dotrace);
11387c478bd9Sstevel@tonic-gate 				if (dotrace && !cflag &&
11397c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
11407c478bd9Sstevel@tonic-gate 					pri->exec_string =
11418fd04b83SRoger A. Faulkner 					    my_realloc(pri->exec_string,
11428fd04b83SRoger A. Faulkner 					    strlen(pri->sys_string) + 1,
11438fd04b83SRoger A. Faulkner 					    NULL);
11447c478bd9Sstevel@tonic-gate 					(void) strcpy(pri->exec_pname,
11458fd04b83SRoger A. Faulkner 					    pri->pname);
11467c478bd9Sstevel@tonic-gate 					(void) strcpy(pri->exec_string,
11478fd04b83SRoger A. Faulkner 					    pri->sys_string);
11487c478bd9Sstevel@tonic-gate 					pri->length += strlen(pri->sys_string);
11497c478bd9Sstevel@tonic-gate 					pri->exec_lwpid = Lsp->pr_lwpid;
11507c478bd9Sstevel@tonic-gate 				}
11517c478bd9Sstevel@tonic-gate 				pri->sys_leng = 0;
11527c478bd9Sstevel@tonic-gate 				*pri->sys_string = '\0';
11537c478bd9Sstevel@tonic-gate 				break;
11547c478bd9Sstevel@tonic-gate 			default:
11557c478bd9Sstevel@tonic-gate 				if (dotrace && (cflag || Eflag) &&
11567c478bd9Sstevel@tonic-gate 				    prismember(&trace, what)) {
11577c478bd9Sstevel@tonic-gate 					pri->syslast = Lsp->pr_stime;
11587c478bd9Sstevel@tonic-gate 				}
11597c478bd9Sstevel@tonic-gate 				break;
11607c478bd9Sstevel@tonic-gate 			}
11617c478bd9Sstevel@tonic-gate 			if (dotrace && Tflag && !first &&
11627c478bd9Sstevel@tonic-gate 			    (prismember(&syshang, what) ||
11637c478bd9Sstevel@tonic-gate 			    (exit_called && prismember(&syshang, SYS_exit))))
11647c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
11657c478bd9Sstevel@tonic-gate 			break;
11667c478bd9Sstevel@tonic-gate 		case PR_SYSEXIT:
11677c478bd9Sstevel@tonic-gate 			/* check for write open of a /proc file */
11688fd04b83SRoger A. Faulkner 			if (what == SYS_openat || what == SYS_openat64 ||
11698fd04b83SRoger A. Faulkner 			    what == SYS_open || what == SYS_open64) {
11708fd04b83SRoger A. Faulkner 				int readonly;
11718fd04b83SRoger A. Faulkner 
11727c478bd9Sstevel@tonic-gate 				(void) sysentry(pri, dotrace);
11737c478bd9Sstevel@tonic-gate 				pri->Errno = Lsp->pr_errno;
11747c478bd9Sstevel@tonic-gate 				pri->ErrPriv = Lsp->pr_errpriv;
11758fd04b83SRoger A. Faulkner 				readonly =
11768fd04b83SRoger A. Faulkner 				    ((what == SYS_openat ||
11778fd04b83SRoger A. Faulkner 				    what == SYS_openat64) &&
11788fd04b83SRoger A. Faulkner 				    pri->sys_nargs > 2 &&
11798fd04b83SRoger A. Faulkner 				    (pri->sys_args[2]&0x3) == O_RDONLY) ||
11808fd04b83SRoger A. Faulkner 				    ((what == SYS_open ||
11818fd04b83SRoger A. Faulkner 				    what == SYS_open64) &&
11828fd04b83SRoger A. Faulkner 				    pri->sys_nargs > 1 &&
11838fd04b83SRoger A. Faulkner 				    (pri->sys_args[1]&0x3) == O_RDONLY);
11847c478bd9Sstevel@tonic-gate 				if ((pri->Errno == 0 || pri->Errno == EBUSY) &&
11858fd04b83SRoger A. Faulkner 				    pri->sys_valid && !readonly) {
11867c478bd9Sstevel@tonic-gate 					int rv = checkproc(pri);
11877c478bd9Sstevel@tonic-gate 					if (rv == 1 && Fflag != PGRAB_FORCE) {
11887c478bd9Sstevel@tonic-gate 						/*
11897c478bd9Sstevel@tonic-gate 						 * The process opened itself
11907c478bd9Sstevel@tonic-gate 						 * and no -F flag was specified.
11917c478bd9Sstevel@tonic-gate 						 * Just print the open() call
11927c478bd9Sstevel@tonic-gate 						 * and let go of the process.
11937c478bd9Sstevel@tonic-gate 						 */
11947c478bd9Sstevel@tonic-gate 						if (dotrace && !cflag &&
11957c478bd9Sstevel@tonic-gate 						    prismember(&trace, what)) {
11967c478bd9Sstevel@tonic-gate 							putpname(pri);
11977c478bd9Sstevel@tonic-gate 							timestamp(pri);
11987c478bd9Sstevel@tonic-gate 							(void) printf("%s\n",
11997c478bd9Sstevel@tonic-gate 							    pri->sys_string);
12007c478bd9Sstevel@tonic-gate 							Flush();
12017c478bd9Sstevel@tonic-gate 						}
120253e568b1Sraf 						sigusr1 = TRUE;
12037c478bd9Sstevel@tonic-gate 						(void) mutex_unlock(
12048fd04b83SRoger A. Faulkner 						    &truss_lock);
12057c478bd9Sstevel@tonic-gate 						goto out;
12067c478bd9Sstevel@tonic-gate 					}
12077c478bd9Sstevel@tonic-gate 					if (rv == 2) {
12087c478bd9Sstevel@tonic-gate 						/*
12097c478bd9Sstevel@tonic-gate 						 * Process opened someone else.
12107c478bd9Sstevel@tonic-gate 						 * The open is being reissued.
12117c478bd9Sstevel@tonic-gate 						 * Don't report this one.
12127c478bd9Sstevel@tonic-gate 						 */
12137c478bd9Sstevel@tonic-gate 						pri->sys_leng = 0;
12147c478bd9Sstevel@tonic-gate 						*pri->sys_string = '\0';
12157c478bd9Sstevel@tonic-gate 						pri->sys_nargs = 0;
12167c478bd9Sstevel@tonic-gate 						break;
12177c478bd9Sstevel@tonic-gate 					}
12187c478bd9Sstevel@tonic-gate 				}
12197c478bd9Sstevel@tonic-gate 			}
1220*ae2315d9SKeith M Wesolowski 			if (what == SYS_execve && Lsp->pr_errno == 0) {
12217c478bd9Sstevel@tonic-gate 				/*
12227c478bd9Sstevel@tonic-gate 				 * Refresh the data model on exec() in case it
12237c478bd9Sstevel@tonic-gate 				 * is different from the parent.  Lwait()
12247c478bd9Sstevel@tonic-gate 				 * doesn't update process-wide status, so we
12257c478bd9Sstevel@tonic-gate 				 * have to explicitly call Pstopstatus() to get
12267c478bd9Sstevel@tonic-gate 				 * the new state.
12277c478bd9Sstevel@tonic-gate 				 */
12287c478bd9Sstevel@tonic-gate 				(void) Pstopstatus(Proc, PCNULL, 0);
12297c478bd9Sstevel@tonic-gate 				data_model = Psp->pr_dmodel;
12307c478bd9Sstevel@tonic-gate 			}
12317c478bd9Sstevel@tonic-gate 			if (sysexit(pri, dotrace))
12327c478bd9Sstevel@tonic-gate 				Flush();
12337c478bd9Sstevel@tonic-gate 			if (what == SYS_lwp_create && pri->Rval1 != 0) {
12347c478bd9Sstevel@tonic-gate 				struct ps_lwphandle *new_Lwp;
12357c478bd9Sstevel@tonic-gate 				lwpid_t lwpid;
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 				if ((new_Lwp = grab_lwp(pri->Rval1)) != NULL) {
123853e568b1Sraf 					(void) thr_sigsetmask(SIG_SETMASK,
123953e568b1Sraf 					    &fillset, NULL);
12407c478bd9Sstevel@tonic-gate 					if (thr_create(NULL, 0, worker_thread,
12417c478bd9Sstevel@tonic-gate 					    new_Lwp, THR_BOUND | THR_SUSPENDED,
12427c478bd9Sstevel@tonic-gate 					    &lwpid) != 0)
12437c478bd9Sstevel@tonic-gate 						abend("cannot create lwp ",
12447c478bd9Sstevel@tonic-gate 						    "to follow child lwp");
12457c478bd9Sstevel@tonic-gate 					insert_lwpid(lwpid);
12467c478bd9Sstevel@tonic-gate 					(void) thr_continue(lwpid);
124753e568b1Sraf 					(void) thr_sigsetmask(SIG_SETMASK,
124853e568b1Sraf 					    &emptyset, NULL);
12497c478bd9Sstevel@tonic-gate 				}
12507c478bd9Sstevel@tonic-gate 			}
12517c478bd9Sstevel@tonic-gate 			pri->sys_nargs = 0;
12527c478bd9Sstevel@tonic-gate 			if (dotrace && Tflag && !first &&
12537c478bd9Sstevel@tonic-gate 			    prismember(&syshang, what))
12547c478bd9Sstevel@tonic-gate 				leave_it_hung = TRUE;
12558fd04b83SRoger A. Faulkner 			if (what == SYS_execve && pri->Errno == 0) {
12567c478bd9Sstevel@tonic-gate 				is_vfork_child = FALSE;
12577c478bd9Sstevel@tonic-gate 				reset_breakpoints();
12587c478bd9Sstevel@tonic-gate 				/*
12597c478bd9Sstevel@tonic-gate 				 * exec() resets the calling LWP's lwpid to 1.
12607c478bd9Sstevel@tonic-gate 				 * If the LWP has changed its lwpid, then
12617c478bd9Sstevel@tonic-gate 				 * we have to free and re-grab the LWP
12627c478bd9Sstevel@tonic-gate 				 * in order to keep libproc consistent.
12637c478bd9Sstevel@tonic-gate 				 * This "cannot fail".
12647c478bd9Sstevel@tonic-gate 				 */
12657c478bd9Sstevel@tonic-gate 				if (who != Lsp->pr_lwpid) {
12667c478bd9Sstevel@tonic-gate 					/*
12677c478bd9Sstevel@tonic-gate 					 * We must wait for all of our
12687c478bd9Sstevel@tonic-gate 					 * siblings to terminate.
12697c478bd9Sstevel@tonic-gate 					 */
12707c478bd9Sstevel@tonic-gate 					while (truss_nlwp > 1)
12717c478bd9Sstevel@tonic-gate 						(void) cond_wait(&truss_cv,
12728fd04b83SRoger A. Faulkner 						    &truss_lock);
12737c478bd9Sstevel@tonic-gate 					who = Lsp->pr_lwpid;
12747c478bd9Sstevel@tonic-gate 					Lfree(Lwp);
12757c478bd9Sstevel@tonic-gate 					pri->Lwp = Lwp =
12768fd04b83SRoger A. Faulkner 					    Lgrab(Proc, who, &gcode);
12777c478bd9Sstevel@tonic-gate 					if (Lwp == NULL)
12787c478bd9Sstevel@tonic-gate 						abend("Lgrab error: ",
12798fd04b83SRoger A. Faulkner 						    Lgrab_error(gcode));
12807c478bd9Sstevel@tonic-gate 					pri->lwpstat = Lsp = Lstatus(Lwp);
12817c478bd9Sstevel@tonic-gate 				}
12827c478bd9Sstevel@tonic-gate 			}
12837c478bd9Sstevel@tonic-gate 			break;
12847c478bd9Sstevel@tonic-gate 		default:
12857c478bd9Sstevel@tonic-gate 			req_flag = 0;
12867c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
12878fd04b83SRoger A. Faulkner 			    "unknown reason for stopping: %d/%d\n",
12888fd04b83SRoger A. Faulkner 			    Lsp->pr_why, what);
12897c478bd9Sstevel@tonic-gate 			abend(NULL, NULL);
12907c478bd9Sstevel@tonic-gate 		}
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 		if (pri->child) {	/* controlled process fork()ed */
12937c478bd9Sstevel@tonic-gate 			if (fflag || Dynpat != NULL)  {
12947c478bd9Sstevel@tonic-gate 				if (Lsp->pr_why == PR_SYSEXIT &&
1295657b1f3dSraf 				    (Lsp->pr_what == SYS_vfork ||
1296657b1f3dSraf 				    (Lsp->pr_what == SYS_forksys &&
1297657b1f3dSraf 				    Lsp->pr_sysarg[0] == 2))) {
12987c478bd9Sstevel@tonic-gate 					is_vfork_child = TRUE;
1299657b1f3dSraf 					(void) Pstop(Proc, 0);
1300657b1f3dSraf 				}
13017c478bd9Sstevel@tonic-gate 				if (control(pri, pri->child)) {
13027c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&truss_lock);
13037c478bd9Sstevel@tonic-gate 					pri->child = 0;
13047c478bd9Sstevel@tonic-gate 					if (!fflag) {
13057c478bd9Sstevel@tonic-gate 						/*
13067c478bd9Sstevel@tonic-gate 						 * If this is vfork(), then
13077c478bd9Sstevel@tonic-gate 						 * this clears the breakpoints
13087c478bd9Sstevel@tonic-gate 						 * in the parent's address space
13097c478bd9Sstevel@tonic-gate 						 * as well as in the child's.
13107c478bd9Sstevel@tonic-gate 						 */
13117c478bd9Sstevel@tonic-gate 						clear_breakpoints();
13127c478bd9Sstevel@tonic-gate 						Prelease(Proc, PRELEASE_CLEAR);
13137c478bd9Sstevel@tonic-gate 						_exit(0);
13147c478bd9Sstevel@tonic-gate 					}
13157c478bd9Sstevel@tonic-gate 					main_thread(FALSE);
13167c478bd9Sstevel@tonic-gate 					/* NOTREACHED */
13177c478bd9Sstevel@tonic-gate 				}
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 				/*
13207c478bd9Sstevel@tonic-gate 				 * Here, we are still the parent truss.
1321657b1f3dSraf 				 * If the child messes with the breakpoints and
13227c478bd9Sstevel@tonic-gate 				 * this is vfork(), we have to set them again.
13237c478bd9Sstevel@tonic-gate 				 */
1324ddbf0f5bSrh 				if (Dynpat != NULL && is_vfork_child && !fflag)
13257c478bd9Sstevel@tonic-gate 					reset_traps = TRUE;
13267c478bd9Sstevel@tonic-gate 				is_vfork_child = FALSE;
13277c478bd9Sstevel@tonic-gate 			}
13287c478bd9Sstevel@tonic-gate 			pri->child = 0;
13297c478bd9Sstevel@tonic-gate 		}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 		if (leave_it_hung) {
13327c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&truss_lock);
13337c478bd9Sstevel@tonic-gate 			break;
13347c478bd9Sstevel@tonic-gate 		}
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 		if (reset_traps) {
13377c478bd9Sstevel@tonic-gate 			/*
13387c478bd9Sstevel@tonic-gate 			 * To recover from vfork, we must catch the lwp
13397c478bd9Sstevel@tonic-gate 			 * that issued the vfork() when it returns to user
13407c478bd9Sstevel@tonic-gate 			 * level, with all other lwps remaining stopped.
1341657b1f3dSraf 			 * For this purpose, we have directed all lwps to
1342657b1f3dSraf 			 * stop and we now set the vfork()ing lwp running
1343657b1f3dSraf 			 * with the PRSTEP flag.  We expect to capture it
1344657b1f3dSraf 			 * when it stops again showing PR_FAULTED/FLTTRACE.
13457c478bd9Sstevel@tonic-gate 			 * We are holding truss_lock, so no other threads
13467c478bd9Sstevel@tonic-gate 			 * in truss will set any other lwps in the victim
13477c478bd9Sstevel@tonic-gate 			 * process running.
13487c478bd9Sstevel@tonic-gate 			 */
13497c478bd9Sstevel@tonic-gate 			reset_traps = FALSE;
13507c478bd9Sstevel@tonic-gate 			(void) Lsetrun(Lwp, 0, PRSTEP);
13517c478bd9Sstevel@tonic-gate 			do {
13527c478bd9Sstevel@tonic-gate 				(void) Lwait(Lwp, 0);
13537c478bd9Sstevel@tonic-gate 			} while (Lstate(Lwp) == PS_RUN);
13547c478bd9Sstevel@tonic-gate 			if (Lstate(Lwp) == PS_STOP &&
13557c478bd9Sstevel@tonic-gate 			    Lsp->pr_why == PR_FAULTED &&
13567c478bd9Sstevel@tonic-gate 			    Lsp->pr_what == FLTTRACE) {
13577c478bd9Sstevel@tonic-gate 				reestablish_traps();
13587c478bd9Sstevel@tonic-gate 				(void) Lsetrun(Lwp, 0, PRCFAULT|PRSTOP);
13597c478bd9Sstevel@tonic-gate 			} else {
13607c478bd9Sstevel@tonic-gate 				(void) printf("%s\t*** Expected PR_FAULTED/"
13618fd04b83SRoger A. Faulkner 				    "FLTTRACE stop following vfork()\n",
13628fd04b83SRoger A. Faulkner 				    pri->pname);
13637c478bd9Sstevel@tonic-gate 			}
13647c478bd9Sstevel@tonic-gate 		}
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_STOP) {
13677c478bd9Sstevel@tonic-gate 			int flags = 0;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 			if (interrupt | sigusr1) {
13707c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
13717c478bd9Sstevel@tonic-gate 				break;
13727c478bd9Sstevel@tonic-gate 			}
13737c478bd9Sstevel@tonic-gate 			/*
13747c478bd9Sstevel@tonic-gate 			 * If we must leave this lwp hung is sympathy with
13757c478bd9Sstevel@tonic-gate 			 * another lwp that is being left hung on purpose,
13767c478bd9Sstevel@tonic-gate 			 * then push the state onward toward PR_REQUESTED.
13777c478bd9Sstevel@tonic-gate 			 */
13787c478bd9Sstevel@tonic-gate 			if (leave_hung) {
13797c478bd9Sstevel@tonic-gate 				if (Lsp->pr_why == PR_REQUESTED) {
13807c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&truss_lock);
13817c478bd9Sstevel@tonic-gate 					break;
13827c478bd9Sstevel@tonic-gate 				}
13837c478bd9Sstevel@tonic-gate 				flags |= PRSTOP;
13847c478bd9Sstevel@tonic-gate 			}
13857c478bd9Sstevel@tonic-gate 			if (Lsetrun(Lwp, 0, flags) != 0 &&
13867c478bd9Sstevel@tonic-gate 			    Lstate(Lwp) != PS_LOST &&
13877c478bd9Sstevel@tonic-gate 			    Lstate(Lwp) != PS_UNDEAD) {
13887c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&truss_lock);
13897c478bd9Sstevel@tonic-gate 				perror("Lsetrun");
13907c478bd9Sstevel@tonic-gate 				abend("cannot start subject lwp", NULL);
13917c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
13927c478bd9Sstevel@tonic-gate 			}
13937c478bd9Sstevel@tonic-gate 		}
13947c478bd9Sstevel@tonic-gate 		first = FALSE;
13957c478bd9Sstevel@tonic-gate 
13967c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&truss_lock);
13977c478bd9Sstevel@tonic-gate 	}
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate out:
140053e568b1Sraf 	/* block all signals in preparation for exiting */
140153e568b1Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
140253e568b1Sraf 
140353e568b1Sraf 	if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST)
140453e568b1Sraf 		(void) mutex_lock(&truss_lock);
140553e568b1Sraf 	else {
14067c478bd9Sstevel@tonic-gate 		(void) Lstop(Lwp, MILLISEC);
14077c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&truss_lock);
14087c478bd9Sstevel@tonic-gate 		if (Lstate(Lwp) == PS_STOP &&
14097c478bd9Sstevel@tonic-gate 		    Lsp->pr_why == PR_FAULTED &&
14107c478bd9Sstevel@tonic-gate 		    Lsp->pr_what == FLTBPT)
14117c478bd9Sstevel@tonic-gate 			(void) function_trace(pri, 0, 1, dotrace);
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	if (dotrace && ow_in_effect) {
14157c478bd9Sstevel@tonic-gate 		if (cflag) {
14167c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&count_lock);
14177c478bd9Sstevel@tonic-gate 			scp = Cp->syscount[ow_syscall];
14187c478bd9Sstevel@tonic-gate 			if (ow_subcode != -1)
14197c478bd9Sstevel@tonic-gate 				scp += ow_subcode;
14207c478bd9Sstevel@tonic-gate 			scp->count++;
14217c478bd9Sstevel@tonic-gate 			accumulate(&scp->stime,
14227c478bd9Sstevel@tonic-gate 			    &Lsp->pr_stime, &pri->syslast);
14237c478bd9Sstevel@tonic-gate 			accumulate(&Cp->usrtotal,
14247c478bd9Sstevel@tonic-gate 			    &Lsp->pr_utime, &pri->usrlast);
14257c478bd9Sstevel@tonic-gate 			pri->syslast = Lsp->pr_stime;
14267c478bd9Sstevel@tonic-gate 			pri->usrlast = Lsp->pr_utime;
14277c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&count_lock);
14287c478bd9Sstevel@tonic-gate 		} else if (Eflag) {
14297c478bd9Sstevel@tonic-gate 			putpname(pri);
14307c478bd9Sstevel@tonic-gate 			timestamp(pri);
14317c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", ow_string);
14327c478bd9Sstevel@tonic-gate 			free(ow_string);
14337c478bd9Sstevel@tonic-gate 			ow_string = NULL;
14347c478bd9Sstevel@tonic-gate 			pri->syslast = Lsp->pr_stime;
14357c478bd9Sstevel@tonic-gate 		}
14367c478bd9Sstevel@tonic-gate 		ow_in_effect = 0;
14377c478bd9Sstevel@tonic-gate 		Psetsysentry(Proc, &running_set);
14387c478bd9Sstevel@tonic-gate 	}
14397c478bd9Sstevel@tonic-gate 
144053e568b1Sraf 	if (Lstate(Lwp) == PS_UNDEAD || Lstate(Lwp) == PS_LOST) {
144153e568b1Sraf 		/*
144253e568b1Sraf 		 * The victim thread has exited or we lost control of
144353e568b1Sraf 		 * the process.  Remove ourself from the list of all
144453e568b1Sraf 		 * truss threads and notify everyone waiting for this.
144553e568b1Sraf 		 */
144653e568b1Sraf 		lwpid_t my_id = thr_self();
144753e568b1Sraf 		int i;
144853e568b1Sraf 
144953e568b1Sraf 		for (i = 0; i < truss_maxlwp; i++) {
145053e568b1Sraf 			if (truss_lwpid[i] == my_id) {
145153e568b1Sraf 				truss_lwpid[i] = 0;
145253e568b1Sraf 				break;
145353e568b1Sraf 			}
145453e568b1Sraf 		}
145553e568b1Sraf 		if (--truss_nlwp != 0) {
145653e568b1Sraf 			(void) cond_broadcast(&truss_cv);
145753e568b1Sraf 		} else {
145853e568b1Sraf 			/*
145953e568b1Sraf 			 * The last truss worker thread is terminating.
146053e568b1Sraf 			 * The address space is gone (UNDEAD) or is
146153e568b1Sraf 			 * inaccessible (LOST) so we cannot clear the
146253e568b1Sraf 			 * breakpoints.  Just report the htable stats.
146353e568b1Sraf 			 */
146453e568b1Sraf 			report_htable_stats();
146553e568b1Sraf 		}
146653e568b1Sraf 	} else {
146753e568b1Sraf 		/*
146853e568b1Sraf 		 * The victim thread is not a zombie thread, and we have not
146953e568b1Sraf 		 * lost control of the process.  We must have gotten here due
147053e568b1Sraf 		 * to (leave_hung || leave_it_hung || interrupt || sigusr1).
147153e568b1Sraf 		 * In these cases, we must carefully uninstrument the process
147253e568b1Sraf 		 * and either set it running or leave it stopped and abandoned.
147353e568b1Sraf 		 */
147453e568b1Sraf 		static int nstopped = 0;
147553e568b1Sraf 		static int cleared = 0;
147653e568b1Sraf 
147753e568b1Sraf 		if (leave_it_hung)
147853e568b1Sraf 			leave_hung = TRUE;
147953e568b1Sraf 		if ((leave_hung | interrupt | sigusr1) == 0)
148053e568b1Sraf 			abend("(leave_hung | interrupt | sigusr1) == 0", NULL);
148153e568b1Sraf 
148253e568b1Sraf 		/*
148353e568b1Sraf 		 * The first truss thread through here needs to instruct all
148453e568b1Sraf 		 * application threads to stop -- they're not necessarily
148553e568b1Sraf 		 * going to stop on their own.
148653e568b1Sraf 		 */
148753e568b1Sraf 		if (nstopped++ == 0)
148853e568b1Sraf 			(void) Pdstop(Proc);
148953e568b1Sraf 
149053e568b1Sraf 		/*
149153e568b1Sraf 		 * Notify all other worker threads about the reason
149253e568b1Sraf 		 * for being here (leave_hung || interrupt || sigusr1).
149353e568b1Sraf 		 */
149453e568b1Sraf 		broadcast_signals();
149553e568b1Sraf 
149653e568b1Sraf 		/*
149753e568b1Sraf 		 * Once the last thread has reached this point, then and
149853e568b1Sraf 		 * only then is it safe to remove breakpoints and other
149953e568b1Sraf 		 * instrumentation.  Since breakpoints are executed without
150053e568b1Sraf 		 * truss_lock held, a monitor thread can't exit until all
150153e568b1Sraf 		 * breakpoints have been removed, and we can't be sure the
150253e568b1Sraf 		 * procedure to execute a breakpoint won't temporarily
150353e568b1Sraf 		 * reinstall a breakpont.  Accordingly, we need to wait
150453e568b1Sraf 		 * until all threads are in a known state.
150553e568b1Sraf 		 */
150653e568b1Sraf 		while (nstopped != truss_nlwp)
150753e568b1Sraf 			(void) cond_wait(&truss_cv, &truss_lock);
150853e568b1Sraf 
150953e568b1Sraf 		/*
151053e568b1Sraf 		 * All truss threads have reached this point.
151153e568b1Sraf 		 * One of them clears the breakpoints and
151253e568b1Sraf 		 * wakes up everybody else to finish up.
151353e568b1Sraf 		 */
151453e568b1Sraf 		if (cleared++ == 0) {
151553e568b1Sraf 			/*
151653e568b1Sraf 			 * All threads should already be stopped,
151753e568b1Sraf 			 * but just to be safe...
151853e568b1Sraf 			 */
151953e568b1Sraf 			(void) Pstop(Proc, MILLISEC);
152053e568b1Sraf 			clear_breakpoints();
152153e568b1Sraf 			(void) Psysexit(Proc, SYS_vfork, FALSE);
1522657b1f3dSraf 			(void) Psysexit(Proc, SYS_forksys, FALSE);
152353e568b1Sraf 			(void) Punsetflags(Proc, PR_FORK);
152453e568b1Sraf 			Psync(Proc);
152553e568b1Sraf 			fflag = 0;
152653e568b1Sraf 			(void) cond_broadcast(&truss_cv);
152753e568b1Sraf 		}
152853e568b1Sraf 
152953e568b1Sraf 		if (!leave_hung && Lstate(Lwp) == PS_STOP)
153053e568b1Sraf 			(void) Lsetrun(Lwp, 0, 0);
153153e568b1Sraf 	}
153253e568b1Sraf 
15337c478bd9Sstevel@tonic-gate 	(void) Lfree(Lwp);
15347c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&truss_lock);
153553e568b1Sraf 	return (NULL);
15367c478bd9Sstevel@tonic-gate }
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate /*
15397c478bd9Sstevel@tonic-gate  * Give a base date for time stamps, adjusted to the
15407c478bd9Sstevel@tonic-gate  * stop time of the selected (first or created) process.
15417c478bd9Sstevel@tonic-gate  */
15427c478bd9Sstevel@tonic-gate void
setup_basetime(hrtime_t basehrtime,struct timeval * basedate)15437c478bd9Sstevel@tonic-gate setup_basetime(hrtime_t basehrtime, struct timeval *basedate)
15447c478bd9Sstevel@tonic-gate {
15457c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp = Pstatus(Proc);
15467c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&count_lock);
15477c478bd9Sstevel@tonic-gate 	Cp->basetime = Psp->pr_lwp.pr_tstamp;
15487c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&count_lock);
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	if ((dflag|Dflag) && !cflag) {
15517c478bd9Sstevel@tonic-gate 		const struct tm *ptm;
15527c478bd9Sstevel@tonic-gate 		const char *ptime;
15537c478bd9Sstevel@tonic-gate 		const char *pdst;
15547c478bd9Sstevel@tonic-gate 		hrtime_t delta = basehrtime -
15558fd04b83SRoger A. Faulkner 		    ((hrtime_t)Cp->basetime.tv_sec * NANOSEC +
15568fd04b83SRoger A. Faulkner 		    Cp->basetime.tv_nsec);
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 		if (delta > 0) {
15597c478bd9Sstevel@tonic-gate 			basedate->tv_sec -= (time_t)(delta / NANOSEC);
15607c478bd9Sstevel@tonic-gate 			basedate->tv_usec -= (delta % NANOSEC) / 1000;
15617c478bd9Sstevel@tonic-gate 			if (basedate->tv_usec < 0) {
15627c478bd9Sstevel@tonic-gate 				basedate->tv_sec--;
15637c478bd9Sstevel@tonic-gate 				basedate->tv_usec += MICROSEC;
15647c478bd9Sstevel@tonic-gate 			}
15657c478bd9Sstevel@tonic-gate 		}
15667c478bd9Sstevel@tonic-gate 		ptm = localtime(&basedate->tv_sec);
15677c478bd9Sstevel@tonic-gate 		ptime = asctime(ptm);
15687c478bd9Sstevel@tonic-gate 		if ((pdst = tzname[ptm->tm_isdst ? 1 : 0]) == NULL)
15697c478bd9Sstevel@tonic-gate 			pdst = "???";
15707c478bd9Sstevel@tonic-gate 		if (dflag) {
15717c478bd9Sstevel@tonic-gate 			(void) printf(
15727c478bd9Sstevel@tonic-gate 			    "Base time stamp:  %ld.%4.4ld  [ %.20s%s %.4s ]\n",
15737c478bd9Sstevel@tonic-gate 			    basedate->tv_sec, basedate->tv_usec / 100,
15747c478bd9Sstevel@tonic-gate 			    ptime, pdst, ptime + 20);
15757c478bd9Sstevel@tonic-gate 			Flush();
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 	}
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate /*
15817c478bd9Sstevel@tonic-gate  * Performs per-process initializations. If truss is following a victim
15827c478bd9Sstevel@tonic-gate  * process it will fork additional truss processes to follow new processes
15837c478bd9Sstevel@tonic-gate  * created.  Here is where each new truss process gets its per-process data
15847c478bd9Sstevel@tonic-gate  * initialized.
15857c478bd9Sstevel@tonic-gate  */
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate void
per_proc_init()15887c478bd9Sstevel@tonic-gate per_proc_init()
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	void *pmem;
15917c478bd9Sstevel@tonic-gate 	struct timeval basedate;
15927c478bd9Sstevel@tonic-gate 	hrtime_t basehrtime;
15937c478bd9Sstevel@tonic-gate 	struct syscount *scp;
15947c478bd9Sstevel@tonic-gate 	int i;
15957c478bd9Sstevel@tonic-gate 	timestruc_t c_basetime;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	/* Make sure we only configure the basetime for the first truss proc */
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	if (Cp == NULL) {
16007c478bd9Sstevel@tonic-gate 		pmem = my_malloc(sizeof (struct counts) + maxsyscalls() *
16017c478bd9Sstevel@tonic-gate 		    sizeof (struct syscount), NULL);
16027c478bd9Sstevel@tonic-gate 		Cp = (struct counts *)pmem;
16037c478bd9Sstevel@tonic-gate 		basehrtime = gethrtime();
16047c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&basedate, NULL);
16057c478bd9Sstevel@tonic-gate 		setup_basetime(basehrtime, &basedate);
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	c_basetime = Cp->basetime;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	(void) memset(Cp, 0, sizeof (struct counts) + maxsyscalls() *
16117c478bd9Sstevel@tonic-gate 	    sizeof (struct syscount));
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	Cp->basetime = c_basetime;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	if (fcall_tbl != NULL)
16167c478bd9Sstevel@tonic-gate 		destroy_hash(fcall_tbl);
16177c478bd9Sstevel@tonic-gate 	fcall_tbl = init_hash(4096);
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&count_lock);
16207c478bd9Sstevel@tonic-gate 	scp = (struct syscount *)(Cp + 1);
16217c478bd9Sstevel@tonic-gate 	for (i = 0; i <= PRMAXSYS; i++) {
16227c478bd9Sstevel@tonic-gate 		Cp->syscount[i] = scp;
16237c478bd9Sstevel@tonic-gate 		scp += nsubcodes(i);
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&count_lock);
16267c478bd9Sstevel@tonic-gate }
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate /*
16307c478bd9Sstevel@tonic-gate  * Writes child state to a tempfile where it can be read and
16317c478bd9Sstevel@tonic-gate  * accumulated by the parent process. The file descriptor is shared
16327c478bd9Sstevel@tonic-gate  * among the processes.  Ordering of writes does not matter, it is, however,
16337c478bd9Sstevel@tonic-gate  * necessary to ensure that all writes are atomic.
16347c478bd9Sstevel@tonic-gate  */
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate void
child_to_file()16377c478bd9Sstevel@tonic-gate child_to_file()
16387c478bd9Sstevel@tonic-gate {
16397c478bd9Sstevel@tonic-gate 	hiter_t *itr;
16407c478bd9Sstevel@tonic-gate 	hentry_t *ntry;
16417c478bd9Sstevel@tonic-gate 	hdntry_t fentry;
16427c478bd9Sstevel@tonic-gate 	char *s = NULL;
16437c478bd9Sstevel@tonic-gate 	char *t = NULL;
16447c478bd9Sstevel@tonic-gate 	unsigned char *buf = NULL;
16457c478bd9Sstevel@tonic-gate 	size_t bufsz = 0;
16467c478bd9Sstevel@tonic-gate 	size_t i = 0;
16477c478bd9Sstevel@tonic-gate 	size_t j = 0;
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	/* ensure that we are in fact a child process */
16507c478bd9Sstevel@tonic-gate 	if (!descendent)
16517c478bd9Sstevel@tonic-gate 		return;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	/* enumerate fcall_tbl (tbl locked until freed) */
16547c478bd9Sstevel@tonic-gate 	if (Dynpat != NULL) {
16557c478bd9Sstevel@tonic-gate 		itr = iterate_hash(fcall_tbl);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 		ntry = iter_next(itr);
16587c478bd9Sstevel@tonic-gate 		while (ntry != NULL) {
16597c478bd9Sstevel@tonic-gate 			fentry.type = HD_hashntry;
16607c478bd9Sstevel@tonic-gate 			fentry.count = ntry->count;
16617c478bd9Sstevel@tonic-gate 			s = ntry->key;
16627c478bd9Sstevel@tonic-gate 			t = ntry->lib;
16637c478bd9Sstevel@tonic-gate 			i = strlen(s) + 1;
16647c478bd9Sstevel@tonic-gate 			j = strlen(t) + 1;
16657c478bd9Sstevel@tonic-gate 			fentry.sz_key = i;
16667c478bd9Sstevel@tonic-gate 			fentry.sz_lib = j;
16677c478bd9Sstevel@tonic-gate 			if (i + sizeof (fentry) > bufsz) {
16687c478bd9Sstevel@tonic-gate 				buf = my_realloc(buf, i + j + sizeof (fentry),
16697c478bd9Sstevel@tonic-gate 				    NULL);
16707c478bd9Sstevel@tonic-gate 				bufsz = i + j + sizeof (fentry);
16717c478bd9Sstevel@tonic-gate 			}
16727c478bd9Sstevel@tonic-gate 			(void) memcpy(buf, &fentry, sizeof (fentry));
16737c478bd9Sstevel@tonic-gate 			(void) strlcpy((char *)(buf + sizeof (fentry)), t, j);
16747c478bd9Sstevel@tonic-gate 			(void) strlcpy((char *)(buf + sizeof (fentry) + j),
16757c478bd9Sstevel@tonic-gate 			    s, i);
16767c478bd9Sstevel@tonic-gate 			if (write(sfd, buf, sizeof (fentry) + i + j) == -1)
16777c478bd9Sstevel@tonic-gate 				abend("Error writing to tmp file", NULL);
16787c478bd9Sstevel@tonic-gate 			ntry = iter_next(itr);
16797c478bd9Sstevel@tonic-gate 		}
16807c478bd9Sstevel@tonic-gate 		iter_free(itr);
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	/* Now write the count/syscount structs down */
16847c478bd9Sstevel@tonic-gate 	bufsz = sizeof (fentry) + (sizeof (struct counts) + maxsyscalls() *
16857c478bd9Sstevel@tonic-gate 	    sizeof (struct syscount));
16867c478bd9Sstevel@tonic-gate 	buf = my_realloc(buf, bufsz, NULL);
16877c478bd9Sstevel@tonic-gate 	fentry.type = HD_cts_syscts;
16887c478bd9Sstevel@tonic-gate 	fentry.count = 0;	/* undefined, really */
16897c478bd9Sstevel@tonic-gate 	fentry.sz_key = bufsz - sizeof (fentry);
16907c478bd9Sstevel@tonic-gate 	fentry.sz_lib = 0;	/* also undefined */
16917c478bd9Sstevel@tonic-gate 	(void) memcpy(buf, &fentry, sizeof (fentry));
16927c478bd9Sstevel@tonic-gate 	(void) memcpy((char *)(buf + sizeof (fentry)), Cp,
16937c478bd9Sstevel@tonic-gate 	    bufsz - sizeof (fentry));
16947c478bd9Sstevel@tonic-gate 	if (write(sfd, buf, bufsz) == -1)
16957c478bd9Sstevel@tonic-gate 		abend("Error writing cts/syscts to tmpfile", NULL);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	free(buf);
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate /*
17017c478bd9Sstevel@tonic-gate  * The following reads entries from the tempfile back to the parent
17027c478bd9Sstevel@tonic-gate  * so that information can be collected and summed for overall statistics.
17037c478bd9Sstevel@tonic-gate  * This reads records out of the tempfile.  If they are hash table entries,
17047c478bd9Sstevel@tonic-gate  * the record is merged with the hash table kept by the parent process.
17057c478bd9Sstevel@tonic-gate  * If the information is a struct count/struct syscount pair, they are
17067c478bd9Sstevel@tonic-gate  * copied and added into the count/syscount array kept by the parent.
17077c478bd9Sstevel@tonic-gate  */
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate void
file_to_parent()17107c478bd9Sstevel@tonic-gate file_to_parent()
17117c478bd9Sstevel@tonic-gate {
17127c478bd9Sstevel@tonic-gate 	hdntry_t ntry;
17137c478bd9Sstevel@tonic-gate 	char *s = NULL;
17147c478bd9Sstevel@tonic-gate 	char *t = NULL;
17157c478bd9Sstevel@tonic-gate 	size_t c_offset = 0;
17167c478bd9Sstevel@tonic-gate 	size_t filesz;
17177c478bd9Sstevel@tonic-gate 	size_t t_strsz = 0;
17187c478bd9Sstevel@tonic-gate 	size_t s_strsz = 0;
17197c478bd9Sstevel@tonic-gate 	struct stat fsi;
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	if (descendent)
17227c478bd9Sstevel@tonic-gate 		return;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	if (fstat(sfd, &fsi) == -1)
17257c478bd9Sstevel@tonic-gate 		abend("Error stat-ing tempfile", NULL);
17267c478bd9Sstevel@tonic-gate 	filesz = fsi.st_size;
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	while (c_offset < filesz) {
17297c478bd9Sstevel@tonic-gate 		/* first get hdntry */
17307c478bd9Sstevel@tonic-gate 		if (pread(sfd, &ntry, sizeof (hdntry_t), c_offset) !=
17317c478bd9Sstevel@tonic-gate 		    sizeof (hdntry_t))
17327c478bd9Sstevel@tonic-gate 			abend("Unable to perform full read of hdntry", NULL);
17337c478bd9Sstevel@tonic-gate 		c_offset += sizeof (hdntry_t);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 		switch (ntry.type) {
17367c478bd9Sstevel@tonic-gate 		case HD_hashntry:
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 			/* first get lib string */
17397c478bd9Sstevel@tonic-gate 			if (ntry.sz_lib > t_strsz) {
17407c478bd9Sstevel@tonic-gate 				t = my_realloc(t, ntry.sz_lib, NULL);
17417c478bd9Sstevel@tonic-gate 				t_strsz = ntry.sz_lib;
17427c478bd9Sstevel@tonic-gate 			}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 			(void) memset(t, 0, t_strsz);
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 			/* now actually get the string */
17477c478bd9Sstevel@tonic-gate 			if (pread(sfd, t, ntry.sz_lib, c_offset) != ntry.sz_lib)
17487c478bd9Sstevel@tonic-gate 				abend("Unable to perform full read of lib str",
17497c478bd9Sstevel@tonic-gate 				    NULL);
17507c478bd9Sstevel@tonic-gate 			c_offset += ntry.sz_lib;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 			/* now get key string */
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 			if (ntry.sz_key > s_strsz) {
17557c478bd9Sstevel@tonic-gate 				s = my_realloc(s, ntry.sz_key, NULL);
17567c478bd9Sstevel@tonic-gate 				s_strsz = ntry.sz_key;
17577c478bd9Sstevel@tonic-gate 			}
17587c478bd9Sstevel@tonic-gate 			(void) memset(s, 0, s_strsz);
17597c478bd9Sstevel@tonic-gate 			if (pread(sfd, s, ntry.sz_key, c_offset) != ntry.sz_key)
17607c478bd9Sstevel@tonic-gate 				abend("Unable to perform full read of key str",
17617c478bd9Sstevel@tonic-gate 				    NULL);
17627c478bd9Sstevel@tonic-gate 			c_offset += ntry.sz_key;
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 			add_fcall(fcall_tbl, t, s, ntry.count);
17657c478bd9Sstevel@tonic-gate 			break;
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 		case HD_cts_syscts:
17687c478bd9Sstevel@tonic-gate 		{
17697c478bd9Sstevel@tonic-gate 			struct counts *ncp;
17707c478bd9Sstevel@tonic-gate 			size_t bfsz = sizeof (struct counts) + maxsyscalls()
17717c478bd9Sstevel@tonic-gate 			    * sizeof (struct syscount);
17727c478bd9Sstevel@tonic-gate 			int i;
17737c478bd9Sstevel@tonic-gate 			struct syscount *sscp;
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 			if (ntry.sz_key != bfsz)
17767c478bd9Sstevel@tonic-gate 				abend("cts/syscts size does not sanity check",
17777c478bd9Sstevel@tonic-gate 				    NULL);
17787c478bd9Sstevel@tonic-gate 			ncp = my_malloc(ntry.sz_key, NULL);
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 			if (pread(sfd, ncp, ntry.sz_key, c_offset) !=
17817c478bd9Sstevel@tonic-gate 			    ntry.sz_key)
17827c478bd9Sstevel@tonic-gate 				abend("Unable to perform full read of cts",
17837c478bd9Sstevel@tonic-gate 				    NULL);
17847c478bd9Sstevel@tonic-gate 			c_offset += ntry.sz_key;
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 			sscp = (struct syscount *)(ncp + 1);
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&count_lock);
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 			Cp->usrtotal.tv_sec += ncp->usrtotal.tv_sec;
17917c478bd9Sstevel@tonic-gate 			Cp->usrtotal.tv_nsec += ncp->usrtotal.tv_nsec;
17927c478bd9Sstevel@tonic-gate 			if (Cp->usrtotal.tv_nsec >= NANOSEC) {
17937c478bd9Sstevel@tonic-gate 				Cp->usrtotal.tv_nsec -= NANOSEC;
17947c478bd9Sstevel@tonic-gate 				Cp->usrtotal.tv_sec++;
17957c478bd9Sstevel@tonic-gate 			}
17967c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSYS; i++) {
17977c478bd9Sstevel@tonic-gate 				ncp->syscount[i] = sscp;
17987c478bd9Sstevel@tonic-gate 				sscp += nsubcodes(i);
17997c478bd9Sstevel@tonic-gate 			}
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXFAULT; i++) {
18027c478bd9Sstevel@tonic-gate 				Cp->fltcount[i] += ncp->fltcount[i];
18037c478bd9Sstevel@tonic-gate 			}
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSIG; i++) {
18067c478bd9Sstevel@tonic-gate 				Cp->sigcount[i] += ncp->sigcount[i];
18077c478bd9Sstevel@tonic-gate 			}
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 			for (i = 0; i <= PRMAXSYS; i++) {
18107c478bd9Sstevel@tonic-gate 				struct syscount *scp = Cp->syscount[i];
18117c478bd9Sstevel@tonic-gate 				struct syscount *nscp = ncp->syscount[i];
18127c478bd9Sstevel@tonic-gate 				int n = nsubcodes(i);
18137c478bd9Sstevel@tonic-gate 				int subcode;
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 				for (subcode = 0; subcode < n; subcode++,
18167c478bd9Sstevel@tonic-gate 				    scp++, nscp++) {
18177c478bd9Sstevel@tonic-gate 					scp->count += nscp->count;
18187c478bd9Sstevel@tonic-gate 					scp->error += nscp->error;
18197c478bd9Sstevel@tonic-gate 					scp->stime.tv_sec += nscp->stime.tv_sec;
18207c478bd9Sstevel@tonic-gate 					scp->stime.tv_nsec +=
18217c478bd9Sstevel@tonic-gate 					    nscp->stime.tv_nsec;
18227c478bd9Sstevel@tonic-gate 					if (scp->stime.tv_nsec >= NANOSEC) {
18237c478bd9Sstevel@tonic-gate 						scp->stime.tv_nsec -= NANOSEC;
18247c478bd9Sstevel@tonic-gate 						scp->stime.tv_sec++;
18257c478bd9Sstevel@tonic-gate 					}
18267c478bd9Sstevel@tonic-gate 				}
18277c478bd9Sstevel@tonic-gate 			}
18287c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&count_lock);
18297c478bd9Sstevel@tonic-gate 			free(ncp);
18307c478bd9Sstevel@tonic-gate 			break;
18317c478bd9Sstevel@tonic-gate 		}
18327c478bd9Sstevel@tonic-gate 		default:
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 			abend("Unknown file entry type encountered", NULL);
18357c478bd9Sstevel@tonic-gate 			break;
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 		}
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 		if (fstat(sfd, &fsi) == -1)
18407c478bd9Sstevel@tonic-gate 			abend("Error stat-ing tempfile", NULL);
18417c478bd9Sstevel@tonic-gate 		filesz = fsi.st_size;
18427c478bd9Sstevel@tonic-gate 	}
18437c478bd9Sstevel@tonic-gate 	if (s != NULL)
18447c478bd9Sstevel@tonic-gate 		free(s);
18457c478bd9Sstevel@tonic-gate 	if (t != NULL)
18467c478bd9Sstevel@tonic-gate 		free(t);
18477c478bd9Sstevel@tonic-gate }
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate void
make_pname(private_t * pri,id_t tid)18507c478bd9Sstevel@tonic-gate make_pname(private_t *pri, id_t tid)
18517c478bd9Sstevel@tonic-gate {
18527c478bd9Sstevel@tonic-gate 	if (!cflag) {
18537c478bd9Sstevel@tonic-gate 		int ff = (fflag || ngrab > 1);
18547c478bd9Sstevel@tonic-gate 		int lf = (lflag | tid | (Thr_agent != NULL) | (truss_nlwp > 1));
18557c478bd9Sstevel@tonic-gate 		pid_t pid = Pstatus(Proc)->pr_pid;
18567c478bd9Sstevel@tonic-gate 		id_t lwpid = pri->lwpstat->pr_lwpid;
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 		if (ff != pri->pparam.ff ||
18597c478bd9Sstevel@tonic-gate 		    lf != pri->pparam.lf ||
18607c478bd9Sstevel@tonic-gate 		    pid != pri->pparam.pid ||
18617c478bd9Sstevel@tonic-gate 		    lwpid != pri->pparam.lwpid ||
18627c478bd9Sstevel@tonic-gate 		    tid != pri->pparam.tid) {
18637c478bd9Sstevel@tonic-gate 			char *s = pri->pname;
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 			if (ff)
18667c478bd9Sstevel@tonic-gate 				s += sprintf(s, "%d", (int)pid);
18677c478bd9Sstevel@tonic-gate 			if (lf)
18687c478bd9Sstevel@tonic-gate 				s += sprintf(s, "/%d", (int)lwpid);
18697c478bd9Sstevel@tonic-gate 			if (tid)
18707c478bd9Sstevel@tonic-gate 				s += sprintf(s, "@%d", (int)tid);
18717c478bd9Sstevel@tonic-gate 			if (ff || lf)
18727c478bd9Sstevel@tonic-gate 				*s++ = ':', *s++ = '\t';
18737c478bd9Sstevel@tonic-gate 			if (ff && lf && s < pri->pname + 9)
18747c478bd9Sstevel@tonic-gate 				*s++ = '\t';
18757c478bd9Sstevel@tonic-gate 			*s = '\0';
18767c478bd9Sstevel@tonic-gate 			pri->pparam.ff = ff;
18777c478bd9Sstevel@tonic-gate 			pri->pparam.lf = lf;
18787c478bd9Sstevel@tonic-gate 			pri->pparam.pid = pid;
18797c478bd9Sstevel@tonic-gate 			pri->pparam.lwpid = lwpid;
18807c478bd9Sstevel@tonic-gate 			pri->pparam.tid = tid;
18817c478bd9Sstevel@tonic-gate 		}
18827c478bd9Sstevel@tonic-gate 	}
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate /*
18867c478bd9Sstevel@tonic-gate  * Print the pri->pname[] string, if any.
18877c478bd9Sstevel@tonic-gate  */
18887c478bd9Sstevel@tonic-gate void
putpname(private_t * pri)18897c478bd9Sstevel@tonic-gate putpname(private_t *pri)
18907c478bd9Sstevel@tonic-gate {
18917c478bd9Sstevel@tonic-gate 	if (pri->pname[0])
18927c478bd9Sstevel@tonic-gate 		(void) fputs(pri->pname, stdout);
18937c478bd9Sstevel@tonic-gate }
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate /*
18967c478bd9Sstevel@tonic-gate  * Print the timestamp, if requested (-d, -D, or -E).
18977c478bd9Sstevel@tonic-gate  */
18987c478bd9Sstevel@tonic-gate void
timestamp(private_t * pri)18997c478bd9Sstevel@tonic-gate timestamp(private_t *pri)
19007c478bd9Sstevel@tonic-gate {
19017c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp = pri->lwpstat;
19027c478bd9Sstevel@tonic-gate 	int seconds;
19037c478bd9Sstevel@tonic-gate 	int fraction;
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	if (!(dflag|Dflag|Eflag) || !(Lsp->pr_flags & PR_STOPPED))
19067c478bd9Sstevel@tonic-gate 		return;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	seconds = Lsp->pr_tstamp.tv_sec - Cp->basetime.tv_sec;
19097c478bd9Sstevel@tonic-gate 	fraction = Lsp->pr_tstamp.tv_nsec - Cp->basetime.tv_nsec;
19107c478bd9Sstevel@tonic-gate 	if (fraction < 0) {
19117c478bd9Sstevel@tonic-gate 		seconds--;
19127c478bd9Sstevel@tonic-gate 		fraction += NANOSEC;
19137c478bd9Sstevel@tonic-gate 	}
19147c478bd9Sstevel@tonic-gate 	/* fraction in 1/10 milliseconds, rounded up */
19157c478bd9Sstevel@tonic-gate 	fraction = (fraction + 50000) / 100000;
19167c478bd9Sstevel@tonic-gate 	if (fraction >= (MILLISEC * 10)) {
19177c478bd9Sstevel@tonic-gate 		seconds++;
19187c478bd9Sstevel@tonic-gate 		fraction -= (MILLISEC * 10);
19197c478bd9Sstevel@tonic-gate 	}
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	if (dflag)		/* time stamp */
19227c478bd9Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 	if (Dflag) {		/* time delta */
19257c478bd9Sstevel@tonic-gate 		int oseconds = pri->seconds;
19267c478bd9Sstevel@tonic-gate 		int ofraction = pri->fraction;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 		pri->seconds = seconds;
19297c478bd9Sstevel@tonic-gate 		pri->fraction = fraction;
19307c478bd9Sstevel@tonic-gate 		seconds -= oseconds;
19317c478bd9Sstevel@tonic-gate 		fraction -= ofraction;
19327c478bd9Sstevel@tonic-gate 		if (fraction < 0) {
19337c478bd9Sstevel@tonic-gate 			seconds--;
19347c478bd9Sstevel@tonic-gate 			fraction += (MILLISEC * 10);
19357c478bd9Sstevel@tonic-gate 		}
19367c478bd9Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
19377c478bd9Sstevel@tonic-gate 	}
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate 	if (Eflag) {
19407c478bd9Sstevel@tonic-gate 		seconds = Lsp->pr_stime.tv_sec - pri->syslast.tv_sec;
19417c478bd9Sstevel@tonic-gate 		fraction = Lsp->pr_stime.tv_nsec - pri->syslast.tv_nsec;
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 		if (fraction < 0) {
19447c478bd9Sstevel@tonic-gate 			seconds--;
19457c478bd9Sstevel@tonic-gate 			fraction += NANOSEC;
19467c478bd9Sstevel@tonic-gate 		}
19477c478bd9Sstevel@tonic-gate 		/* fraction in 1/10 milliseconds, rounded up */
19487c478bd9Sstevel@tonic-gate 		fraction = (fraction + 50000) / 100000;
19497c478bd9Sstevel@tonic-gate 		if (fraction >= (MILLISEC * 10)) {
19507c478bd9Sstevel@tonic-gate 			seconds++;
19517c478bd9Sstevel@tonic-gate 			fraction -= (MILLISEC * 10);
19527c478bd9Sstevel@tonic-gate 		}
19537c478bd9Sstevel@tonic-gate 		(void) printf("%2d.%4.4d\t", seconds, fraction);
19547c478bd9Sstevel@tonic-gate 	}
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate /*
19587c478bd9Sstevel@tonic-gate  * Create output file, being careful about
19597c478bd9Sstevel@tonic-gate  * suid/sgid and file descriptor 0, 1, 2 issues.
19607c478bd9Sstevel@tonic-gate  */
19617c478bd9Sstevel@tonic-gate int
xcreat(char * path)19627c478bd9Sstevel@tonic-gate xcreat(char *path)
19637c478bd9Sstevel@tonic-gate {
19647c478bd9Sstevel@tonic-gate 	int fd;
19657c478bd9Sstevel@tonic-gate 	int mode = 0666;
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	if (Euid == Ruid && Egid == Rgid)	/* not set-id */
19687c478bd9Sstevel@tonic-gate 		fd = creat(path, mode);
19697c478bd9Sstevel@tonic-gate 	else if (access(path, F_OK) != 0) {	/* file doesn't exist */
19707c478bd9Sstevel@tonic-gate 		/* if directory permissions OK, create file & set ownership */
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 		char *dir;
19737c478bd9Sstevel@tonic-gate 		char *p;
19747c478bd9Sstevel@tonic-gate 		char dot[4];
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 		/* generate path for directory containing file */
19777c478bd9Sstevel@tonic-gate 		if ((p = strrchr(path, '/')) == NULL) {	/* no '/' */
19787c478bd9Sstevel@tonic-gate 			p = dir = dot;
19797c478bd9Sstevel@tonic-gate 			*p++ = '.';		/* current directory */
19807c478bd9Sstevel@tonic-gate 			*p = '\0';
19817c478bd9Sstevel@tonic-gate 		} else if (p == path) {			/* leading '/' */
19827c478bd9Sstevel@tonic-gate 			p = dir = dot;
19837c478bd9Sstevel@tonic-gate 			*p++ = '/';		/* root directory */
19847c478bd9Sstevel@tonic-gate 			*p = '\0';
19857c478bd9Sstevel@tonic-gate 		} else {				/* embedded '/' */
19867c478bd9Sstevel@tonic-gate 			dir = path;		/* directory path */
19877c478bd9Sstevel@tonic-gate 			*p = '\0';
19887c478bd9Sstevel@tonic-gate 		}
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 		if (access(dir, W_OK|X_OK) != 0) {
19917c478bd9Sstevel@tonic-gate 			/* not writeable/searchable */
19927c478bd9Sstevel@tonic-gate 			*p = '/';
19937c478bd9Sstevel@tonic-gate 			fd = -1;
19947c478bd9Sstevel@tonic-gate 		} else {	/* create file and set ownership correctly */
19957c478bd9Sstevel@tonic-gate 			*p = '/';
19967c478bd9Sstevel@tonic-gate 			if ((fd = creat(path, mode)) >= 0)
19977c478bd9Sstevel@tonic-gate 				(void) chown(path, (int)Ruid, (int)Rgid);
19987c478bd9Sstevel@tonic-gate 		}
19997c478bd9Sstevel@tonic-gate 	} else if (access(path, W_OK) != 0)	/* file not writeable */
20007c478bd9Sstevel@tonic-gate 		fd = -1;
20017c478bd9Sstevel@tonic-gate 	else
20027c478bd9Sstevel@tonic-gate 		fd = creat(path, mode);
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	/*
20057c478bd9Sstevel@tonic-gate 	 * Make sure it's not one of 0, 1, or 2.
2006bbf21555SRichard Lowe 	 * This allows truss to work when spawned by init(8).
20077c478bd9Sstevel@tonic-gate 	 */
20087c478bd9Sstevel@tonic-gate 	if (0 <= fd && fd <= 2) {
20097c478bd9Sstevel@tonic-gate 		int dfd = fcntl(fd, F_DUPFD, 3);
20107c478bd9Sstevel@tonic-gate 		(void) close(fd);
20117c478bd9Sstevel@tonic-gate 		fd = dfd;
20127c478bd9Sstevel@tonic-gate 	}
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	/*
20157c478bd9Sstevel@tonic-gate 	 * Mark it close-on-exec so created processes don't inherit it.
20167c478bd9Sstevel@tonic-gate 	 */
20177c478bd9Sstevel@tonic-gate 	if (fd >= 0)
20187c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	return (fd);
20217c478bd9Sstevel@tonic-gate }
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate void
setoutput(int ofd)20247c478bd9Sstevel@tonic-gate setoutput(int ofd)
20257c478bd9Sstevel@tonic-gate {
20267c478bd9Sstevel@tonic-gate 	if (ofd < 0) {
20277c478bd9Sstevel@tonic-gate 		(void) close(1);
20287c478bd9Sstevel@tonic-gate 		(void) fcntl(2, F_DUPFD, 1);
20297c478bd9Sstevel@tonic-gate 	} else if (ofd != 1) {
20307c478bd9Sstevel@tonic-gate 		(void) close(1);
20317c478bd9Sstevel@tonic-gate 		(void) fcntl(ofd, F_DUPFD, 1);
20327c478bd9Sstevel@tonic-gate 		(void) close(ofd);
20337c478bd9Sstevel@tonic-gate 		/* if no stderr, make it the same file */
20347c478bd9Sstevel@tonic-gate 		if ((ofd = dup(2)) < 0)
20357c478bd9Sstevel@tonic-gate 			(void) fcntl(1, F_DUPFD, 2);
20367c478bd9Sstevel@tonic-gate 		else
20377c478bd9Sstevel@tonic-gate 			(void) close(ofd);
20387c478bd9Sstevel@tonic-gate 	}
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate /*
20427c478bd9Sstevel@tonic-gate  * Accumulate time differencies:  a += e - s;
20437c478bd9Sstevel@tonic-gate  */
20447c478bd9Sstevel@tonic-gate void
accumulate(timestruc_t * ap,const timestruc_t * ep,const timestruc_t * sp)20457c478bd9Sstevel@tonic-gate accumulate(timestruc_t *ap, const timestruc_t *ep, const timestruc_t *sp)
20467c478bd9Sstevel@tonic-gate {
20477c478bd9Sstevel@tonic-gate 	ap->tv_sec += ep->tv_sec - sp->tv_sec;
20487c478bd9Sstevel@tonic-gate 	ap->tv_nsec += ep->tv_nsec - sp->tv_nsec;
20497c478bd9Sstevel@tonic-gate 	if (ap->tv_nsec >= NANOSEC) {
20507c478bd9Sstevel@tonic-gate 		ap->tv_nsec -= NANOSEC;
20517c478bd9Sstevel@tonic-gate 		ap->tv_sec++;
20527c478bd9Sstevel@tonic-gate 	} else if (ap->tv_nsec < 0) {
20537c478bd9Sstevel@tonic-gate 		ap->tv_nsec += NANOSEC;
20547c478bd9Sstevel@tonic-gate 		ap->tv_sec--;
20557c478bd9Sstevel@tonic-gate 	}
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate int
lib_sort(const void * p1,const void * p2)20597c478bd9Sstevel@tonic-gate lib_sort(const void *p1, const void *p2)
20607c478bd9Sstevel@tonic-gate {
20617c478bd9Sstevel@tonic-gate 	int cmpr = 0;
20627c478bd9Sstevel@tonic-gate 	long i;
20637c478bd9Sstevel@tonic-gate 	long j;
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	hentry_t *t1 = (hentry_t *)p1;
20667c478bd9Sstevel@tonic-gate 	hentry_t *t2 = (hentry_t *)p2;
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	char *p = t1->lib;
20697c478bd9Sstevel@tonic-gate 	char *q = t2->lib;
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	if ((cmpr = strcmp(p, q)) == 0) {
20727c478bd9Sstevel@tonic-gate 		i = t1->count;
20737c478bd9Sstevel@tonic-gate 		j = t2->count;
20747c478bd9Sstevel@tonic-gate 		if (i > j)
20757c478bd9Sstevel@tonic-gate 			return (-1);
20767c478bd9Sstevel@tonic-gate 		else if (i < j)
20777c478bd9Sstevel@tonic-gate 			return (1);
20787c478bd9Sstevel@tonic-gate 		else {
20797c478bd9Sstevel@tonic-gate 			p = t1->key;
20807c478bd9Sstevel@tonic-gate 			q = t2->key;
20817c478bd9Sstevel@tonic-gate 			return (strcmp(p, q));
20827c478bd9Sstevel@tonic-gate 		}
20837c478bd9Sstevel@tonic-gate 	} else
20847c478bd9Sstevel@tonic-gate 		return (cmpr);
20857c478bd9Sstevel@tonic-gate }
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate void
report(private_t * pri,time_t lapse)20887c478bd9Sstevel@tonic-gate report(private_t *pri, time_t lapse)	/* elapsed time, clock ticks */
20897c478bd9Sstevel@tonic-gate {
20907c478bd9Sstevel@tonic-gate 	int i;
20917c478bd9Sstevel@tonic-gate 	long count;
20927c478bd9Sstevel@tonic-gate 	const char *name;
20937c478bd9Sstevel@tonic-gate 	long error;
20947c478bd9Sstevel@tonic-gate 	long total;
20957c478bd9Sstevel@tonic-gate 	long errtot;
20967c478bd9Sstevel@tonic-gate 	timestruc_t tickzero;
20977c478bd9Sstevel@tonic-gate 	timestruc_t ticks;
20987c478bd9Sstevel@tonic-gate 	timestruc_t ticktot;
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	if (descendent)
21017c478bd9Sstevel@tonic-gate 		return;
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	for (i = 0, total = 0; i <= PRMAXFAULT && !interrupt; i++) {
21047c478bd9Sstevel@tonic-gate 		if ((count = Cp->fltcount[i]) != 0) {
21057c478bd9Sstevel@tonic-gate 			if (total == 0)		/* produce header */
21067c478bd9Sstevel@tonic-gate 				(void) printf("faults -------------\n");
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 			name = proc_fltname(i, pri->flt_name,
21098fd04b83SRoger A. Faulkner 			    sizeof (pri->flt_name));
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 			(void) printf("%s%s\t%4ld\n", name,
21128fd04b83SRoger A. Faulkner 			    (((int)strlen(name) < 8)?
21138fd04b83SRoger A. Faulkner 			    (const char *)"\t" : (const char *)""),
21148fd04b83SRoger A. Faulkner 			    count);
21157c478bd9Sstevel@tonic-gate 			total += count;
21167c478bd9Sstevel@tonic-gate 		}
21177c478bd9Sstevel@tonic-gate 	}
21187c478bd9Sstevel@tonic-gate 	if (total && !interrupt)
21197c478bd9Sstevel@tonic-gate 		(void) printf("total:\t\t%4ld\n\n", total);
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	for (i = 0, total = 0; i <= PRMAXSIG && !interrupt; i++) {
21227c478bd9Sstevel@tonic-gate 		if ((count = Cp->sigcount[i]) != 0) {
21237c478bd9Sstevel@tonic-gate 			if (total == 0)		/* produce header */
21247c478bd9Sstevel@tonic-gate 				(void) printf("signals ------------\n");
21257c478bd9Sstevel@tonic-gate 			name = signame(pri, i);
21267c478bd9Sstevel@tonic-gate 			(void) printf("%s%s\t%4ld\n", name,
21278fd04b83SRoger A. Faulkner 			    (((int)strlen(name) < 8)?
21288fd04b83SRoger A. Faulkner 			    (const char *)"\t" : (const char *)""),
21298fd04b83SRoger A. Faulkner 			    count);
21307c478bd9Sstevel@tonic-gate 			total += count;
21317c478bd9Sstevel@tonic-gate 		}
21327c478bd9Sstevel@tonic-gate 	}
21337c478bd9Sstevel@tonic-gate 	if (total && !interrupt)
21347c478bd9Sstevel@tonic-gate 		(void) printf("total:\t\t%4ld\n\n", total);
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	if ((Dynpat != NULL) && !interrupt) {
21377c478bd9Sstevel@tonic-gate 		size_t elem = elements_in_table(fcall_tbl);
21387c478bd9Sstevel@tonic-gate 		hiter_t *itr = iterate_hash(fcall_tbl);
21397c478bd9Sstevel@tonic-gate 		hentry_t *tmp = iter_next(itr);
21407c478bd9Sstevel@tonic-gate 		hentry_t *stbl = my_malloc(elem * sizeof (hentry_t), NULL);
21417c478bd9Sstevel@tonic-gate 		i = 0;
21427c478bd9Sstevel@tonic-gate 		while ((tmp != NULL) && (i < elem)) {
21437c478bd9Sstevel@tonic-gate 			stbl[i].prev = tmp->prev;
21447c478bd9Sstevel@tonic-gate 			stbl[i].next = tmp->next;
21457c478bd9Sstevel@tonic-gate 			stbl[i].lib = tmp->lib;
21467c478bd9Sstevel@tonic-gate 			stbl[i].key = tmp->key;
21477c478bd9Sstevel@tonic-gate 			stbl[i].count = tmp->count;
21487c478bd9Sstevel@tonic-gate 			tmp = iter_next(itr);
21497c478bd9Sstevel@tonic-gate 			i++;
21507c478bd9Sstevel@tonic-gate 		}
21517c478bd9Sstevel@tonic-gate 		qsort((void *)stbl, elem, sizeof (hentry_t),
21527c478bd9Sstevel@tonic-gate 		    lib_sort);
21537c478bd9Sstevel@tonic-gate 		(void) printf(
21548fd04b83SRoger A. Faulkner 		    "\n%-20s %-40s %s\n", "Library:", "Function", "calls");
21557c478bd9Sstevel@tonic-gate 		for (i = 0; i < elem; i++) {
21567c478bd9Sstevel@tonic-gate 			(void) printf("%-20s %-40s %ld\n", stbl[i].lib,
21577c478bd9Sstevel@tonic-gate 			    stbl[i].key, stbl[i].count);
21587c478bd9Sstevel@tonic-gate 		}
21597c478bd9Sstevel@tonic-gate 		iter_free(itr);
21607c478bd9Sstevel@tonic-gate 		free(stbl);
21617c478bd9Sstevel@tonic-gate 		itr = NULL;
21627c478bd9Sstevel@tonic-gate 	}
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	if (!interrupt)
21657c478bd9Sstevel@tonic-gate 		(void) printf(
21667c478bd9Sstevel@tonic-gate 		"\nsyscall               seconds   calls  errors\n");
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	total = errtot = 0;
21697c478bd9Sstevel@tonic-gate 	tickzero.tv_sec = ticks.tv_sec = ticktot.tv_sec = 0;
21707c478bd9Sstevel@tonic-gate 	tickzero.tv_nsec = ticks.tv_nsec = ticktot.tv_nsec = 0;
21717c478bd9Sstevel@tonic-gate 	for (i = 0; i <= PRMAXSYS && !interrupt; i++) {
21727c478bd9Sstevel@tonic-gate 		struct syscount *scp = Cp->syscount[i];
21737c478bd9Sstevel@tonic-gate 		int n = nsubcodes(i);
21747c478bd9Sstevel@tonic-gate 		int subcode;
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 		for (subcode = 0; subcode < n; subcode++, scp++) {
21777c478bd9Sstevel@tonic-gate 			if ((count = scp->count) != 0 || scp->error) {
21787c478bd9Sstevel@tonic-gate 				(void) printf("%-19.19s ",
21798fd04b83SRoger A. Faulkner 				    sysname(pri, i, subcode));
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 				ticks = scp->stime;
21827c478bd9Sstevel@tonic-gate 				accumulate(&ticktot, &ticks, &tickzero);
21837c478bd9Sstevel@tonic-gate 				prtim(&ticks);
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 				(void) printf(" %7ld", count);
21867c478bd9Sstevel@tonic-gate 				if ((error = scp->error) != 0)
21877c478bd9Sstevel@tonic-gate 					(void) printf(" %7ld", error);
21887c478bd9Sstevel@tonic-gate 				(void) fputc('\n', stdout);
21897c478bd9Sstevel@tonic-gate 				total += count;
21907c478bd9Sstevel@tonic-gate 				errtot += error;
21917c478bd9Sstevel@tonic-gate 			}
21927c478bd9Sstevel@tonic-gate 		}
21937c478bd9Sstevel@tonic-gate 	}
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	if (!interrupt) {
21967c478bd9Sstevel@tonic-gate 		(void) printf(
21977c478bd9Sstevel@tonic-gate 		"                     --------  ------   ----\n");
21987c478bd9Sstevel@tonic-gate 		(void) printf("sys totals:         ");
21997c478bd9Sstevel@tonic-gate 		prtim(&ticktot);
22007c478bd9Sstevel@tonic-gate 		(void) printf(" %7ld %6ld\n", total, errtot);
22017c478bd9Sstevel@tonic-gate 	}
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 	if (!interrupt) {
22047c478bd9Sstevel@tonic-gate 		(void) printf("usr time:           ");
22057c478bd9Sstevel@tonic-gate 		prtim(&Cp->usrtotal);
22067c478bd9Sstevel@tonic-gate 		(void) fputc('\n', stdout);
22077c478bd9Sstevel@tonic-gate 	}
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (!interrupt) {
22107c478bd9Sstevel@tonic-gate 		int hz = (int)sysconf(_SC_CLK_TCK);
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 		ticks.tv_sec = lapse / hz;
22137c478bd9Sstevel@tonic-gate 		ticks.tv_nsec = (lapse % hz) * (1000000000 / hz);
22147c478bd9Sstevel@tonic-gate 		(void) printf("elapsed:            ");
22157c478bd9Sstevel@tonic-gate 		prtim(&ticks);
22167c478bd9Sstevel@tonic-gate 		(void) fputc('\n', stdout);
22177c478bd9Sstevel@tonic-gate 	}
22187c478bd9Sstevel@tonic-gate }
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate void
prtim(timestruc_t * tp)22217c478bd9Sstevel@tonic-gate prtim(timestruc_t *tp)
22227c478bd9Sstevel@tonic-gate {
22237c478bd9Sstevel@tonic-gate 	time_t sec;
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	if ((sec = tp->tv_sec) != 0)			/* whole seconds */
22267c478bd9Sstevel@tonic-gate 		(void) printf("%5lu", sec);
22277c478bd9Sstevel@tonic-gate 	else
22287c478bd9Sstevel@tonic-gate 		(void) printf("     ");
22297c478bd9Sstevel@tonic-gate 
22307c478bd9Sstevel@tonic-gate 	(void) printf(".%3.3ld", tp->tv_nsec/1000000);	/* fraction */
22317c478bd9Sstevel@tonic-gate }
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate /*
22347c478bd9Sstevel@tonic-gate  * Gather process id's.
22357c478bd9Sstevel@tonic-gate  * Return 0 on success, != 0 on failure.
22367c478bd9Sstevel@tonic-gate  */
22377c478bd9Sstevel@tonic-gate void
pids(char * arg,proc_set_t * grab)22387c478bd9Sstevel@tonic-gate pids(char *arg, proc_set_t *grab)
22397c478bd9Sstevel@tonic-gate {
22407c478bd9Sstevel@tonic-gate 	pid_t pid = -1;
22417c478bd9Sstevel@tonic-gate 	int i;
22427c478bd9Sstevel@tonic-gate 	const char *lwps = NULL;
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	if ((pid = proc_arg_xpsinfo(arg, PR_ARG_PIDS, NULL, &i, &lwps)) < 0) {
22457c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: cannot trace '%s': %s\n",
22467c478bd9Sstevel@tonic-gate 		    command, arg, Pgrab_error(i));
22477c478bd9Sstevel@tonic-gate 		return;
22487c478bd9Sstevel@tonic-gate 	}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	for (i = 0; i < ngrab; i++)
22517c478bd9Sstevel@tonic-gate 		if (grab[i].pid == pid)	/* duplicate */
22527c478bd9Sstevel@tonic-gate 			break;
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	if (i == ngrab) {
22557c478bd9Sstevel@tonic-gate 		grab[ngrab].pid = pid;
22567c478bd9Sstevel@tonic-gate 		grab[ngrab].lwps = lwps;
22577c478bd9Sstevel@tonic-gate 		ngrab++;
22587c478bd9Sstevel@tonic-gate 	} else {
22597c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: duplicate process-id ignored: %d\n",
22607c478bd9Sstevel@tonic-gate 		    command, (int)pid);
22617c478bd9Sstevel@tonic-gate 	}
22627c478bd9Sstevel@tonic-gate }
22637c478bd9Sstevel@tonic-gate 
22647c478bd9Sstevel@tonic-gate /*
22657c478bd9Sstevel@tonic-gate  * Report psargs string.
22667c478bd9Sstevel@tonic-gate  */
22677c478bd9Sstevel@tonic-gate void
psargs(private_t * pri)22687c478bd9Sstevel@tonic-gate psargs(private_t *pri)
22697c478bd9Sstevel@tonic-gate {
22707c478bd9Sstevel@tonic-gate 	pid_t pid = Pstatus(Proc)->pr_pid;
22717c478bd9Sstevel@tonic-gate 	psinfo_t psinfo;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	if (proc_get_psinfo(pid, &psinfo) == 0)
22747c478bd9Sstevel@tonic-gate 		(void) printf("%spsargs: %.64s\n",
22758fd04b83SRoger A. Faulkner 		    pri->pname, psinfo.pr_psargs);
22767c478bd9Sstevel@tonic-gate 	else {
22777c478bd9Sstevel@tonic-gate 		perror("psargs()");
22787c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot read psinfo file for pid %d\n",
22798fd04b83SRoger A. Faulkner 		    pri->pname, (int)pid);
22807c478bd9Sstevel@tonic-gate 	}
22817c478bd9Sstevel@tonic-gate }
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate char *
fetchstring(private_t * pri,long addr,int maxleng)22847c478bd9Sstevel@tonic-gate fetchstring(private_t *pri, long addr, int maxleng)
22857c478bd9Sstevel@tonic-gate {
22867c478bd9Sstevel@tonic-gate 	int nbyte;
22877c478bd9Sstevel@tonic-gate 	int leng = 0;
22887c478bd9Sstevel@tonic-gate 	char string[41];
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate 	string[40] = '\0';
22917c478bd9Sstevel@tonic-gate 	if (pri->str_bsize == 0)  /* initial allocation of string buffer */
22927c478bd9Sstevel@tonic-gate 		pri->str_buffer =
22938fd04b83SRoger A. Faulkner 		    my_malloc(pri->str_bsize = 16, "string buffer");
22947c478bd9Sstevel@tonic-gate 	*pri->str_buffer = '\0';
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	for (nbyte = 40; nbyte == 40 && leng < maxleng; addr += 40) {
22977c478bd9Sstevel@tonic-gate 		if ((nbyte = Pread(Proc, string, 40, addr)) <= 0)
22987c478bd9Sstevel@tonic-gate 			return (leng? pri->str_buffer : NULL);
22997c478bd9Sstevel@tonic-gate 		if (nbyte > 0 &&
23007c478bd9Sstevel@tonic-gate 		    (nbyte = strlen(string)) > 0) {
23017c478bd9Sstevel@tonic-gate 			while (leng + nbyte >= pri->str_bsize)
23027c478bd9Sstevel@tonic-gate 				pri->str_buffer =
23038fd04b83SRoger A. Faulkner 				    my_realloc(pri->str_buffer,
23048fd04b83SRoger A. Faulkner 				    pri->str_bsize *= 2, "string buffer");
23057c478bd9Sstevel@tonic-gate 			(void) strcpy(pri->str_buffer+leng, string);
23067c478bd9Sstevel@tonic-gate 			leng += nbyte;
23077c478bd9Sstevel@tonic-gate 		}
23087c478bd9Sstevel@tonic-gate 	}
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 	if (leng > maxleng)
23117c478bd9Sstevel@tonic-gate 		leng = maxleng;
23127c478bd9Sstevel@tonic-gate 	pri->str_buffer[leng] = '\0';
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	return (pri->str_buffer);
23157c478bd9Sstevel@tonic-gate }
23167c478bd9Sstevel@tonic-gate 
2317134a1f4eSCasper H.S. Dik static priv_set_t *
getset(prpriv_t * p,priv_ptype_t set)2318134a1f4eSCasper H.S. Dik getset(prpriv_t *p, priv_ptype_t set)
2319134a1f4eSCasper H.S. Dik {
2320134a1f4eSCasper H.S. Dik 	return ((priv_set_t *)
2321134a1f4eSCasper H.S. Dik 	    &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]);
2322134a1f4eSCasper H.S. Dik }
2323134a1f4eSCasper H.S. Dik 
23247c478bd9Sstevel@tonic-gate void
show_cred(private_t * pri,int new,int loadonly)2325134a1f4eSCasper H.S. Dik show_cred(private_t *pri, int new, int loadonly)
23267c478bd9Sstevel@tonic-gate {
23277c478bd9Sstevel@tonic-gate 	prcred_t cred;
2328134a1f4eSCasper H.S. Dik 	prpriv_t *privs;
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 	if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) {
2331134a1f4eSCasper H.S. Dik 		perror("show_cred() - credential");
23327c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot get credentials\n", pri->pname);
23337c478bd9Sstevel@tonic-gate 		return;
23347c478bd9Sstevel@tonic-gate 	}
2335134a1f4eSCasper H.S. Dik 	if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) {
2336134a1f4eSCasper H.S. Dik 		perror("show_cred() - privileges");
2337134a1f4eSCasper H.S. Dik 		(void) printf("%s\t*** Cannot get privileges\n", pri->pname);
2338134a1f4eSCasper H.S. Dik 		return;
2339134a1f4eSCasper H.S. Dik 	}
23407c478bd9Sstevel@tonic-gate 
2341134a1f4eSCasper H.S. Dik 	if (!loadonly && !cflag && prismember(&trace, SYS_execve)) {
23427c478bd9Sstevel@tonic-gate 		if (new)
23437c478bd9Sstevel@tonic-gate 			credentials = cred;
23447c478bd9Sstevel@tonic-gate 		if ((new && cred.pr_ruid != cred.pr_suid) ||
23457c478bd9Sstevel@tonic-gate 		    cred.pr_ruid != credentials.pr_ruid ||
23467c478bd9Sstevel@tonic-gate 		    cred.pr_suid != credentials.pr_suid)
23477c478bd9Sstevel@tonic-gate 			(void) printf(
23487c478bd9Sstevel@tonic-gate 		"%s    *** SUID: ruid/euid/suid = %d / %d / %d  ***\n",
23498fd04b83SRoger A. Faulkner 			    pri->pname,
23508fd04b83SRoger A. Faulkner 			    (int)cred.pr_ruid,
23518fd04b83SRoger A. Faulkner 			    (int)cred.pr_euid,
23528fd04b83SRoger A. Faulkner 			    (int)cred.pr_suid);
23537c478bd9Sstevel@tonic-gate 		if ((new && cred.pr_rgid != cred.pr_sgid) ||
23547c478bd9Sstevel@tonic-gate 		    cred.pr_rgid != credentials.pr_rgid ||
23557c478bd9Sstevel@tonic-gate 		    cred.pr_sgid != credentials.pr_sgid)
23567c478bd9Sstevel@tonic-gate 			(void) printf(
23577c478bd9Sstevel@tonic-gate 		"%s    *** SGID: rgid/egid/sgid = %d / %d / %d  ***\n",
23588fd04b83SRoger A. Faulkner 			    pri->pname,
23598fd04b83SRoger A. Faulkner 			    (int)cred.pr_rgid,
23608fd04b83SRoger A. Faulkner 			    (int)cred.pr_egid,
23618fd04b83SRoger A. Faulkner 			    (int)cred.pr_sgid);
2362134a1f4eSCasper H.S. Dik 		if (privdata != NULL && cred.pr_euid != 0) {
2363134a1f4eSCasper H.S. Dik 			priv_set_t *npset = getset(privs, PRIV_PERMITTED);
2364134a1f4eSCasper H.S. Dik 			priv_set_t *opset = getset(privdata, PRIV_PERMITTED);
2365134a1f4eSCasper H.S. Dik 			char *s, *t;
2366134a1f4eSCasper H.S. Dik 			if (!priv_issubset(npset, opset)) {
2367134a1f4eSCasper H.S. Dik 				/* Use the to be freed privdata as scratch */
2368134a1f4eSCasper H.S. Dik 				priv_inverse(opset);
2369134a1f4eSCasper H.S. Dik 				priv_intersect(npset, opset);
2370134a1f4eSCasper H.S. Dik 				s = priv_set_to_str(opset, ',', PRIV_STR_SHORT);
2371134a1f4eSCasper H.S. Dik 				t = priv_set_to_str(npset, ',', PRIV_STR_SHORT);
2372134a1f4eSCasper H.S. Dik 				(void) printf("%s    *** FPRIV: P/E: %s ***\n",
2373134a1f4eSCasper H.S. Dik 				    pri->pname,
2374134a1f4eSCasper H.S. Dik 				    strlen(s) > strlen(t) ? t : s);
2375134a1f4eSCasper H.S. Dik 				free(s);
2376134a1f4eSCasper H.S. Dik 				free(t);
2377134a1f4eSCasper H.S. Dik 			}
2378134a1f4eSCasper H.S. Dik 		}
23797c478bd9Sstevel@tonic-gate 	}
23807c478bd9Sstevel@tonic-gate 
2381134a1f4eSCasper H.S. Dik 	if (privdata != NULL)
238243051d27SRobert Mustacchi 		proc_free_priv(privdata);
23837c478bd9Sstevel@tonic-gate 	credentials = cred;
2384134a1f4eSCasper H.S. Dik 	privdata = privs;
23857c478bd9Sstevel@tonic-gate }
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate /*
23887c478bd9Sstevel@tonic-gate  * Take control of a child process.
23897c478bd9Sstevel@tonic-gate  * We come here with truss_lock held.
23907c478bd9Sstevel@tonic-gate  */
23917c478bd9Sstevel@tonic-gate int
control(private_t * pri,pid_t pid)23927c478bd9Sstevel@tonic-gate control(private_t *pri, pid_t pid)
23937c478bd9Sstevel@tonic-gate {
23947c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp;
23957c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
23967c478bd9Sstevel@tonic-gate 	pid_t childpid = 0;
23977c478bd9Sstevel@tonic-gate 	long flags;
23987c478bd9Sstevel@tonic-gate 	int rc;
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&gps->fork_lock);
24017c478bd9Sstevel@tonic-gate 	while (gps->fork_pid != 0)
24027c478bd9Sstevel@tonic-gate 		(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
24037c478bd9Sstevel@tonic-gate 	gps->fork_pid = getpid();	/* parent pid */
2404657b1f3dSraf 	if ((childpid = fork()) == -1) {
24057c478bd9Sstevel@tonic-gate 		(void) printf("%s\t*** Cannot fork() to control process #%d\n",
24068fd04b83SRoger A. Faulkner 		    pri->pname, (int)pid);
24077c478bd9Sstevel@tonic-gate 		Flush();
24087c478bd9Sstevel@tonic-gate 		gps->fork_pid = 0;
24097c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
24107c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
24117c478bd9Sstevel@tonic-gate 		release(pri, pid);
24127c478bd9Sstevel@tonic-gate 		return (FALSE);
24137c478bd9Sstevel@tonic-gate 	}
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	if (childpid != 0) {
24167c478bd9Sstevel@tonic-gate 		/*
24177c478bd9Sstevel@tonic-gate 		 * The parent carries on, after a brief pause.
24187c478bd9Sstevel@tonic-gate 		 * The parent must wait until the child executes procadd(pid).
24197c478bd9Sstevel@tonic-gate 		 */
24207c478bd9Sstevel@tonic-gate 		while (gps->fork_pid != childpid)
24217c478bd9Sstevel@tonic-gate 			(void) cond_wait(&gps->fork_cv, &gps->fork_lock);
24227c478bd9Sstevel@tonic-gate 		gps->fork_pid = 0;
24237c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
24247c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
24257c478bd9Sstevel@tonic-gate 		return (FALSE);
24267c478bd9Sstevel@tonic-gate 	}
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 	childpid = getpid();
24297c478bd9Sstevel@tonic-gate 	descendent = TRUE;
24307c478bd9Sstevel@tonic-gate 	exit_called = FALSE;
24317c478bd9Sstevel@tonic-gate 	Pfree(Proc);	/* forget old process */
24327c478bd9Sstevel@tonic-gate 
24337c478bd9Sstevel@tonic-gate 	/*
24347c478bd9Sstevel@tonic-gate 	 * The parent process owns the shared gps->fork_lock.
24357c478bd9Sstevel@tonic-gate 	 * The child must grab it again.
24367c478bd9Sstevel@tonic-gate 	 */
24377c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&gps->fork_lock);
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	/*
24407c478bd9Sstevel@tonic-gate 	 * Child grabs the process and retains the tracing flags.
24417c478bd9Sstevel@tonic-gate 	 */
24427c478bd9Sstevel@tonic-gate 	if ((Proc = Pgrab(pid, PGRAB_RETAIN, &rc)) == NULL) {
24437c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
24448fd04b83SRoger A. Faulkner 		    "%s: cannot control child process, pid# %d: %s\n",
24458fd04b83SRoger A. Faulkner 		    command, (int)pid, Pgrab_error(rc));
24467c478bd9Sstevel@tonic-gate 		gps->fork_pid = childpid;
24477c478bd9Sstevel@tonic-gate 		(void) cond_broadcast(&gps->fork_cv);
24487c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&gps->fork_lock);
24497c478bd9Sstevel@tonic-gate 		exit(2);
24507c478bd9Sstevel@tonic-gate 	}
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	per_proc_init();
24537c478bd9Sstevel@tonic-gate 	/*
24547c478bd9Sstevel@tonic-gate 	 * Add ourself to the set of truss processes
24557c478bd9Sstevel@tonic-gate 	 * and notify the parent to carry on.
24567c478bd9Sstevel@tonic-gate 	 */
24577c478bd9Sstevel@tonic-gate 	procadd(pid, NULL);
24587c478bd9Sstevel@tonic-gate 	gps->fork_pid = childpid;
24597c478bd9Sstevel@tonic-gate 	(void) cond_broadcast(&gps->fork_cv);
24607c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&gps->fork_lock);
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	/*
24637c478bd9Sstevel@tonic-gate 	 * We may have grabbed the child before it is fully stopped on exit
24647c478bd9Sstevel@tonic-gate 	 * from fork.  Wait one second (at most) for it to settle down.
24657c478bd9Sstevel@tonic-gate 	 */
24667c478bd9Sstevel@tonic-gate 	(void) Pwait(Proc, MILLISEC);
24677c478bd9Sstevel@tonic-gate 	if (Rdb_agent != NULL)
24687c478bd9Sstevel@tonic-gate 		Rdb_agent = Prd_agent(Proc);
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate 	Psp = Pstatus(Proc);
24717c478bd9Sstevel@tonic-gate 	Lsp = &Psp->pr_lwp;
24727c478bd9Sstevel@tonic-gate 	pri->lwpstat = Lsp;
24737c478bd9Sstevel@tonic-gate 	data_model = Psp->pr_dmodel;
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	make_pname(pri, 0);
24767c478bd9Sstevel@tonic-gate 
24777c478bd9Sstevel@tonic-gate 	pri->syslast = Psp->pr_stime;
24787c478bd9Sstevel@tonic-gate 	pri->usrlast = Psp->pr_utime;
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 	flags = PR_FORK | PR_ASYNC;
24817c478bd9Sstevel@tonic-gate 	if (Dynpat != NULL)
24827c478bd9Sstevel@tonic-gate 		flags |= PR_BPTADJ;	/* needed for x86 */
24837c478bd9Sstevel@tonic-gate 	(void) Psetflags(Proc, flags);
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 	return (TRUE);
24867c478bd9Sstevel@tonic-gate }
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate /*
24897c478bd9Sstevel@tonic-gate  * Take control of an existing process.
24907c478bd9Sstevel@tonic-gate  */
24917c478bd9Sstevel@tonic-gate int
grabit(private_t * pri,proc_set_t * set)24927c478bd9Sstevel@tonic-gate grabit(private_t *pri, proc_set_t *set)
24937c478bd9Sstevel@tonic-gate {
24947c478bd9Sstevel@tonic-gate 	const pstatus_t *Psp;
24957c478bd9Sstevel@tonic-gate 	const lwpstatus_t *Lsp;
24967c478bd9Sstevel@tonic-gate 	int gcode;
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	/*
24997c478bd9Sstevel@tonic-gate 	 * Don't force the takeover unless the -F option was specified.
25007c478bd9Sstevel@tonic-gate 	 */
25017c478bd9Sstevel@tonic-gate 	if ((Proc = Pgrab(set->pid, Fflag, &gcode)) == NULL) {
25027c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s: %d\n",
25038fd04b83SRoger A. Faulkner 		    command, Pgrab_error(gcode), (int)set->pid);
25047c478bd9Sstevel@tonic-gate 		pri->lwpstat = NULL;
25057c478bd9Sstevel@tonic-gate 		return (FALSE);
25067c478bd9Sstevel@tonic-gate 	}
25077c478bd9Sstevel@tonic-gate 	Psp = Pstatus(Proc);
25087c478bd9Sstevel@tonic-gate 	Lsp = &Psp->pr_lwp;
25097c478bd9Sstevel@tonic-gate 	pri->lwpstat = Lsp;
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate 	make_pname(pri, 0);
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	data_model = Psp->pr_dmodel;
25147c478bd9Sstevel@tonic-gate 	pri->syslast = Psp->pr_stime;
25157c478bd9Sstevel@tonic-gate 	pri->usrlast = Psp->pr_utime;
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	if (fflag || Dynpat != NULL)
25187c478bd9Sstevel@tonic-gate 		(void) Psetflags(Proc, PR_FORK);
25197c478bd9Sstevel@tonic-gate 	else
25207c478bd9Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_FORK);
25217c478bd9Sstevel@tonic-gate 	procadd(set->pid, set->lwps);
2522134a1f4eSCasper H.S. Dik 	show_cred(pri, TRUE, FALSE);
25237c478bd9Sstevel@tonic-gate 	return (TRUE);
25247c478bd9Sstevel@tonic-gate }
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate /*
25277c478bd9Sstevel@tonic-gate  * Release process from control.
25287c478bd9Sstevel@tonic-gate  */
25297c478bd9Sstevel@tonic-gate void
release(private_t * pri,pid_t pid)25307c478bd9Sstevel@tonic-gate release(private_t *pri, pid_t pid)
25317c478bd9Sstevel@tonic-gate {
25327c478bd9Sstevel@tonic-gate 	/*
25337c478bd9Sstevel@tonic-gate 	 * The process in question is the child of a traced process.
25347c478bd9Sstevel@tonic-gate 	 * We are here to turn off the inherited tracing flags.
25357c478bd9Sstevel@tonic-gate 	 */
25367c478bd9Sstevel@tonic-gate 	int fd;
25377c478bd9Sstevel@tonic-gate 	char ctlname[100];
25387c478bd9Sstevel@tonic-gate 	long ctl[2];
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	ctl[0] = PCSET;
25417c478bd9Sstevel@tonic-gate 	ctl[1] = PR_RLC;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 	/* process is freshly forked, no need for exclusive open */
25447c478bd9Sstevel@tonic-gate 	(void) sprintf(ctlname, "/proc/%d/ctl", (int)pid);
25457c478bd9Sstevel@tonic-gate 	if ((fd = open(ctlname, O_WRONLY)) < 0 ||
25467c478bd9Sstevel@tonic-gate 	    write(fd, (char *)ctl, sizeof (ctl)) < 0) {
25477c478bd9Sstevel@tonic-gate 		perror("release()");
25487c478bd9Sstevel@tonic-gate 		(void) printf(
25498fd04b83SRoger A. Faulkner 		    "%s\t*** Cannot release child process, pid# %d\n",
25508fd04b83SRoger A. Faulkner 		    pri->pname, (int)pid);
25517c478bd9Sstevel@tonic-gate 		Flush();
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 	if (fd >= 0)	/* run-on-last-close sets the process running */
25547c478bd9Sstevel@tonic-gate 		(void) close(fd);
25557c478bd9Sstevel@tonic-gate }
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate void
intr(int sig)25587c478bd9Sstevel@tonic-gate intr(int sig)
25597c478bd9Sstevel@tonic-gate {
25607c478bd9Sstevel@tonic-gate 	/*
25617c478bd9Sstevel@tonic-gate 	 * SIGUSR1 is special.  It is used by one truss process to tell
25627c478bd9Sstevel@tonic-gate 	 * another truss process to release its controlled process.
25637c478bd9Sstevel@tonic-gate 	 * SIGUSR2 is also special.  It is used to wake up threads waiting
25647c478bd9Sstevel@tonic-gate 	 * for a victim lwp to stop after an event that will leave the
25657c478bd9Sstevel@tonic-gate 	 * process hung (stopped and abandoned) has occurred.
25667c478bd9Sstevel@tonic-gate 	 */
25677c478bd9Sstevel@tonic-gate 	if (sig == SIGUSR1) {
25687c478bd9Sstevel@tonic-gate 		sigusr1 = TRUE;
25697c478bd9Sstevel@tonic-gate 	} else if (sig == SIGUSR2) {
25707c478bd9Sstevel@tonic-gate 		void *value;
25717c478bd9Sstevel@tonic-gate 		private_t *pri;
25727c478bd9Sstevel@tonic-gate 		struct ps_lwphandle *Lwp;
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 		if (thr_getspecific(private_key, &value) == 0 &&
25757c478bd9Sstevel@tonic-gate 		    (pri = value) != NULL &&
25767c478bd9Sstevel@tonic-gate 		    (Lwp = pri->Lwp) != NULL)
25777c478bd9Sstevel@tonic-gate 			(void) Lstop(Lwp, MILLISEC / 10);
25787c478bd9Sstevel@tonic-gate 	} else {
25797c478bd9Sstevel@tonic-gate 		interrupt = sig;
25807c478bd9Sstevel@tonic-gate 	}
25817c478bd9Sstevel@tonic-gate }
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate void
errmsg(const char * s,const char * q)25847c478bd9Sstevel@tonic-gate errmsg(const char *s, const char *q)
25857c478bd9Sstevel@tonic-gate {
25867c478bd9Sstevel@tonic-gate 	char msg[512];
25877c478bd9Sstevel@tonic-gate 
25887c478bd9Sstevel@tonic-gate 	if (s || q) {
25897c478bd9Sstevel@tonic-gate 		msg[0] = '\0';
25907c478bd9Sstevel@tonic-gate 		if (command) {
25917c478bd9Sstevel@tonic-gate 			(void) strcpy(msg, command);
25927c478bd9Sstevel@tonic-gate 			(void) strcat(msg, ": ");
25937c478bd9Sstevel@tonic-gate 		}
25947c478bd9Sstevel@tonic-gate 		if (s)
25957c478bd9Sstevel@tonic-gate 			(void) strcat(msg, s);
25967c478bd9Sstevel@tonic-gate 		if (q)
25977c478bd9Sstevel@tonic-gate 			(void) strcat(msg, q);
25987c478bd9Sstevel@tonic-gate 		(void) strcat(msg, "\n");
25997c478bd9Sstevel@tonic-gate 		(void) write(2, msg, (size_t)strlen(msg));
26007c478bd9Sstevel@tonic-gate 	}
26017c478bd9Sstevel@tonic-gate }
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate void
abend(const char * s,const char * q)26047c478bd9Sstevel@tonic-gate abend(const char *s, const char *q)
26057c478bd9Sstevel@tonic-gate {
260653e568b1Sraf 	(void) thr_sigsetmask(SIG_SETMASK, &fillset, NULL);
26077c478bd9Sstevel@tonic-gate 	if (Proc) {
26087c478bd9Sstevel@tonic-gate 		Flush();
26097c478bd9Sstevel@tonic-gate 		errmsg(s, q);
26107c478bd9Sstevel@tonic-gate 		clear_breakpoints();
26117c478bd9Sstevel@tonic-gate 		(void) Punsetflags(Proc, PR_ASYNC);
26127c478bd9Sstevel@tonic-gate 		Prelease(Proc, created? PRELEASE_KILL : PRELEASE_CLEAR);
26137c478bd9Sstevel@tonic-gate 		procdel();
26147c478bd9Sstevel@tonic-gate 		(void) wait4all();
26157c478bd9Sstevel@tonic-gate 	} else {
26167c478bd9Sstevel@tonic-gate 		errmsg(s, q);
26177c478bd9Sstevel@tonic-gate 	}
26187c478bd9Sstevel@tonic-gate 	exit(2);
26197c478bd9Sstevel@tonic-gate }
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate /*
26227c478bd9Sstevel@tonic-gate  * Allocate memory.
26237c478bd9Sstevel@tonic-gate  * If allocation fails then print a message and abort.
26247c478bd9Sstevel@tonic-gate  */
26257c478bd9Sstevel@tonic-gate void *
my_realloc(void * buf,size_t size,const char * msg)26267c478bd9Sstevel@tonic-gate my_realloc(void *buf, size_t size, const char *msg)
26277c478bd9Sstevel@tonic-gate {
26287c478bd9Sstevel@tonic-gate 	if ((buf = realloc(buf, size)) == NULL) {
26297c478bd9Sstevel@tonic-gate 		if (msg != NULL)
26307c478bd9Sstevel@tonic-gate 			abend("cannot allocate ", msg);
26317c478bd9Sstevel@tonic-gate 		else
26327c478bd9Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
26337c478bd9Sstevel@tonic-gate 	}
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	return (buf);
26367c478bd9Sstevel@tonic-gate }
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate void *
my_calloc(size_t nelem,size_t elsize,const char * msg)26397c478bd9Sstevel@tonic-gate my_calloc(size_t nelem, size_t elsize, const char *msg)
26407c478bd9Sstevel@tonic-gate {
26417c478bd9Sstevel@tonic-gate 	void *buf = NULL;
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 	if ((buf = calloc(nelem, elsize)) == NULL) {
26447c478bd9Sstevel@tonic-gate 		if (msg != NULL)
26457c478bd9Sstevel@tonic-gate 			abend("cannot allocate ", msg);
26467c478bd9Sstevel@tonic-gate 		else
26477c478bd9Sstevel@tonic-gate 			abend("memory allocation failure", NULL);
26487c478bd9Sstevel@tonic-gate 	}
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate 	return (buf);
26517c478bd9Sstevel@tonic-gate }
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate void *
my_malloc(size_t size,const char * msg)26547c478bd9Sstevel@tonic-gate my_malloc(size_t size, const char *msg)
26557c478bd9Sstevel@tonic-gate {
26567c478bd9Sstevel@tonic-gate 	return (my_realloc(NULL, size, msg));
26577c478bd9Sstevel@tonic-gate }
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate int
wait4all()26607c478bd9Sstevel@tonic-gate wait4all()
26617c478bd9Sstevel@tonic-gate {
26627c478bd9Sstevel@tonic-gate 	int i;
26637c478bd9Sstevel@tonic-gate 	pid_t pid;
26647c478bd9Sstevel@tonic-gate 	int rc = 0;
26657c478bd9Sstevel@tonic-gate 	int status;
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	for (i = 0; i < 10; i++) {
26687c478bd9Sstevel@tonic-gate 		while ((pid = wait(&status)) != -1) {
26697c478bd9Sstevel@tonic-gate 			/* return exit() code of the created process */
26707c478bd9Sstevel@tonic-gate 			if (pid == created) {
26717c478bd9Sstevel@tonic-gate 				if (WIFEXITED(status))
26727c478bd9Sstevel@tonic-gate 					rc = WEXITSTATUS(status);
26737c478bd9Sstevel@tonic-gate 				else
26747c478bd9Sstevel@tonic-gate 					rc |= 0x80; /* +128 to indicate sig */
26757c478bd9Sstevel@tonic-gate 			}
26767c478bd9Sstevel@tonic-gate 		}
26777c478bd9Sstevel@tonic-gate 		if (errno != EINTR && errno != ERESTART)
26787c478bd9Sstevel@tonic-gate 			break;
26797c478bd9Sstevel@tonic-gate 	}
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate 	if (i >= 10)	/* repeated interrupts */
26827c478bd9Sstevel@tonic-gate 		rc = 2;
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	return (rc);
26857c478bd9Sstevel@tonic-gate }
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate void
letgo(private_t * pri)26887c478bd9Sstevel@tonic-gate letgo(private_t *pri)
26897c478bd9Sstevel@tonic-gate {
26907c478bd9Sstevel@tonic-gate 	(void) printf("%s\t*** process otherwise traced, releasing ...\n",
26918fd04b83SRoger A. Faulkner 	    pri->pname);
26927c478bd9Sstevel@tonic-gate }
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate /*
26957c478bd9Sstevel@tonic-gate  * Test for empty set.
26967c478bd9Sstevel@tonic-gate  * support routine used by isemptyset() macro.
26977c478bd9Sstevel@tonic-gate  */
26987c478bd9Sstevel@tonic-gate int
is_empty(const uint32_t * sp,size_t n)26997c478bd9Sstevel@tonic-gate is_empty(const uint32_t *sp,	/* pointer to set (array of int32's) */
2700350ffdd5SRobert Mustacchi     size_t n)			/* number of int32's in set */
27017c478bd9Sstevel@tonic-gate {
27027c478bd9Sstevel@tonic-gate 	if (n) {
27037c478bd9Sstevel@tonic-gate 		do {
27047c478bd9Sstevel@tonic-gate 			if (*sp++)
27057c478bd9Sstevel@tonic-gate 				return (FALSE);
27067c478bd9Sstevel@tonic-gate 		} while (--n);
27077c478bd9Sstevel@tonic-gate 	}
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 	return (TRUE);
27107c478bd9Sstevel@tonic-gate }
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate /*
27137c478bd9Sstevel@tonic-gate  * OR the second set into the first.
27147c478bd9Sstevel@tonic-gate  * The sets must be the same size.
27157c478bd9Sstevel@tonic-gate  */
27167c478bd9Sstevel@tonic-gate void
or_set(uint32_t * sp1,const uint32_t * sp2,size_t n)27177c478bd9Sstevel@tonic-gate or_set(uint32_t *sp1, const uint32_t *sp2, size_t n)
27187c478bd9Sstevel@tonic-gate {
27197c478bd9Sstevel@tonic-gate 	if (n) {
27207c478bd9Sstevel@tonic-gate 		do {
27217c478bd9Sstevel@tonic-gate 			*sp1++ |= *sp2++;
27227c478bd9Sstevel@tonic-gate 		} while (--n);
27237c478bd9Sstevel@tonic-gate 	}
27247c478bd9Sstevel@tonic-gate }
2725