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