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