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