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 #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <assert.h> 30*7c478bd9Sstevel@tonic-gate #include <dtrace.h> 31*7c478bd9Sstevel@tonic-gate #include <limits.h> 32*7c478bd9Sstevel@tonic-gate #include <link.h> 33*7c478bd9Sstevel@tonic-gate #include <priv.h> 34*7c478bd9Sstevel@tonic-gate #include <signal.h> 35*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 36*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 37*7c478bd9Sstevel@tonic-gate #include <stdio.h> 38*7c478bd9Sstevel@tonic-gate #include <string.h> 39*7c478bd9Sstevel@tonic-gate #include <strings.h> 40*7c478bd9Sstevel@tonic-gate #include <errno.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 42*7c478bd9Sstevel@tonic-gate #include <libproc.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate static char *g_pname; 45*7c478bd9Sstevel@tonic-gate static dtrace_hdl_t *g_dtp; 46*7c478bd9Sstevel@tonic-gate struct ps_prochandle *g_pr; 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate #define E_SUCCESS 0 49*7c478bd9Sstevel@tonic-gate #define E_ERROR 1 50*7c478bd9Sstevel@tonic-gate #define E_USAGE 2 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate /* 53*7c478bd9Sstevel@tonic-gate * For hold times we use a global associative array since for mutexes, in 54*7c478bd9Sstevel@tonic-gate * user-land, it's not invalid to release a sychonization primitive that 55*7c478bd9Sstevel@tonic-gate * another thread acquired; rwlocks require a thread-local associative array 56*7c478bd9Sstevel@tonic-gate * since multiple thread can hold the same lock for reading. Note that we 57*7c478bd9Sstevel@tonic-gate * ignore recursive mutex acquisitions and releases as they don't truly 58*7c478bd9Sstevel@tonic-gate * affect lock contention. 59*7c478bd9Sstevel@tonic-gate */ 60*7c478bd9Sstevel@tonic-gate static const char *g_hold_init = 61*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-acquire\n" 62*7c478bd9Sstevel@tonic-gate "{\n" 63*7c478bd9Sstevel@tonic-gate " self->rwhold[arg0] = timestamp;\n" 64*7c478bd9Sstevel@tonic-gate "}\n" 65*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-acquire\n" 66*7c478bd9Sstevel@tonic-gate "/arg1 == 0/\n" 67*7c478bd9Sstevel@tonic-gate "{\n" 68*7c478bd9Sstevel@tonic-gate " mtxhold[arg0] = timestamp;\n" 69*7c478bd9Sstevel@tonic-gate "}\n"; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate static const char *g_hold_histogram = 72*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-release\n" 73*7c478bd9Sstevel@tonic-gate "/self->rwhold[arg0] && arg1 == 1/\n" 74*7c478bd9Sstevel@tonic-gate "{\n" 75*7c478bd9Sstevel@tonic-gate " @rw_w_hold[arg0, ustack()] =\n" 76*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->rwhold[arg0]);\n" 77*7c478bd9Sstevel@tonic-gate " self->rwhold[arg0] = 0;\n" 78*7c478bd9Sstevel@tonic-gate "}\n" 79*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-release\n" 80*7c478bd9Sstevel@tonic-gate "/self->rwhold[arg0]/\n" 81*7c478bd9Sstevel@tonic-gate "{\n" 82*7c478bd9Sstevel@tonic-gate " @rw_r_hold[arg0, ustack()] =\n" 83*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->rwhold[arg0]);\n" 84*7c478bd9Sstevel@tonic-gate " self->rwhold[arg0] = 0;\n" 85*7c478bd9Sstevel@tonic-gate "}\n" 86*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-release\n" 87*7c478bd9Sstevel@tonic-gate "/mtxhold[arg0] && arg1 == 0/\n" 88*7c478bd9Sstevel@tonic-gate "{\n" 89*7c478bd9Sstevel@tonic-gate " @mtx_hold[arg0, ustack()] = quantize(timestamp - mtxhold[arg0]);\n" 90*7c478bd9Sstevel@tonic-gate " mtxhold[arg0] = 0;\n" 91*7c478bd9Sstevel@tonic-gate "}\n"; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate static const char *g_hold_times = 94*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-release\n" 95*7c478bd9Sstevel@tonic-gate "/self->rwhold[arg0] && arg1 == 1/\n" 96*7c478bd9Sstevel@tonic-gate "{\n" 97*7c478bd9Sstevel@tonic-gate " @rw_w_hold[arg0, ustack(5)] = avg(timestamp - self->rwhold[arg0]);\n" 98*7c478bd9Sstevel@tonic-gate " self->rwhold[arg0] = 0;\n" 99*7c478bd9Sstevel@tonic-gate "}\n" 100*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-release\n" 101*7c478bd9Sstevel@tonic-gate "/self->rwhold[arg0]/\n" 102*7c478bd9Sstevel@tonic-gate "{\n" 103*7c478bd9Sstevel@tonic-gate " @rw_r_hold[arg0, ustack(5)] = avg(timestamp - self->rwhold[arg0]);\n" 104*7c478bd9Sstevel@tonic-gate " self->rwhold[arg0] = 0;\n" 105*7c478bd9Sstevel@tonic-gate "}\n" 106*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-release\n" 107*7c478bd9Sstevel@tonic-gate "/mtxhold[arg0] && arg1 == 0/\n" 108*7c478bd9Sstevel@tonic-gate "{\n" 109*7c478bd9Sstevel@tonic-gate " @mtx_hold[arg0, ustack(5)] = avg(timestamp - mtxhold[arg0]);\n" 110*7c478bd9Sstevel@tonic-gate " mtxhold[arg0] = 0;\n" 111*7c478bd9Sstevel@tonic-gate "}\n"; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate /* 115*7c478bd9Sstevel@tonic-gate * For contention, we use thread-local associative arrays since we're tracing 116*7c478bd9Sstevel@tonic-gate * a single thread's activity in libc and multiple threads can be blocking or 117*7c478bd9Sstevel@tonic-gate * spinning on the same sychonization primitive. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate static const char *g_ctnd_init = 120*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-block\n" 121*7c478bd9Sstevel@tonic-gate "{\n" 122*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = timestamp;\n" 123*7c478bd9Sstevel@tonic-gate "}\n" 124*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-block\n" 125*7c478bd9Sstevel@tonic-gate "{\n" 126*7c478bd9Sstevel@tonic-gate " self->mtxblock[arg0] = timestamp;\n" 127*7c478bd9Sstevel@tonic-gate "}\n" 128*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-spin\n" 129*7c478bd9Sstevel@tonic-gate "{\n" 130*7c478bd9Sstevel@tonic-gate " self->mtxspin[arg0] = timestamp;\n" 131*7c478bd9Sstevel@tonic-gate "}\n"; 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate static const char *g_ctnd_histogram = 134*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-blocked\n" 135*7c478bd9Sstevel@tonic-gate "/self->rwblock[arg0] && arg1 == 1 && arg2 != 0/\n" 136*7c478bd9Sstevel@tonic-gate "{\n" 137*7c478bd9Sstevel@tonic-gate " @rw_w_block[arg0, ustack()] =\n" 138*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->rwblock[arg0]);\n" 139*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = 0;\n" 140*7c478bd9Sstevel@tonic-gate "}\n" 141*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-blocked\n" 142*7c478bd9Sstevel@tonic-gate "/self->rwblock[arg0] && arg2 != 0/\n" 143*7c478bd9Sstevel@tonic-gate "{\n" 144*7c478bd9Sstevel@tonic-gate " @rw_r_block[arg0, ustack()] =\n" 145*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->rwblock[arg0]);\n" 146*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = 0;\n" 147*7c478bd9Sstevel@tonic-gate "}\n" 148*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-blocked\n" 149*7c478bd9Sstevel@tonic-gate "/self->rwblock[arg0]/\n" 150*7c478bd9Sstevel@tonic-gate "{\n" 151*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = 0;\n" 152*7c478bd9Sstevel@tonic-gate "}\n" 153*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-spun\n" 154*7c478bd9Sstevel@tonic-gate "/self->mtxspin[arg0] && arg1 != 0/\n" 155*7c478bd9Sstevel@tonic-gate "{\n" 156*7c478bd9Sstevel@tonic-gate " @mtx_spin[arg0, ustack()] =\n" 157*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->mtxspin[arg0]);\n" 158*7c478bd9Sstevel@tonic-gate " self->mtxspin[arg0] = 0;\n" 159*7c478bd9Sstevel@tonic-gate "}\n" 160*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-spun\n" 161*7c478bd9Sstevel@tonic-gate "/self->mtxspin[arg0]/\n" 162*7c478bd9Sstevel@tonic-gate "{\n" 163*7c478bd9Sstevel@tonic-gate " @mtx_vain_spin[arg0, ustack()] =\n" 164*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->mtxspin[arg0]);\n" 165*7c478bd9Sstevel@tonic-gate " self->mtxspin[arg0] = 0;\n" 166*7c478bd9Sstevel@tonic-gate "}\n" 167*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-blocked\n" 168*7c478bd9Sstevel@tonic-gate "/self->mtxblock[arg0] && arg1 != 0/\n" 169*7c478bd9Sstevel@tonic-gate "{\n" 170*7c478bd9Sstevel@tonic-gate " @mtx_block[arg0, ustack()] =\n" 171*7c478bd9Sstevel@tonic-gate " quantize(timestamp - self->mtxblock[arg0]);\n" 172*7c478bd9Sstevel@tonic-gate " self->mtxblock[arg0] = 0;\n" 173*7c478bd9Sstevel@tonic-gate "}\n" 174*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-blocked\n" 175*7c478bd9Sstevel@tonic-gate "/self->mtxblock[arg0]/\n" 176*7c478bd9Sstevel@tonic-gate "{\n" 177*7c478bd9Sstevel@tonic-gate " self->mtxblock[arg0] = 0;\n" 178*7c478bd9Sstevel@tonic-gate "}\n"; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate static const char *g_ctnd_times = 182*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-blocked\n" 183*7c478bd9Sstevel@tonic-gate "/self->rwblock[arg0] && arg1 == 1 && arg2 != 0/\n" 184*7c478bd9Sstevel@tonic-gate "{\n" 185*7c478bd9Sstevel@tonic-gate " @rw_w_block[arg0, ustack(5)] =\n" 186*7c478bd9Sstevel@tonic-gate " avg(timestamp - self->rwblock[arg0]);\n" 187*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = 0;\n" 188*7c478bd9Sstevel@tonic-gate "}\n" 189*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-blocked\n" 190*7c478bd9Sstevel@tonic-gate "/self->rwblock[arg0] && arg2 != 0/\n" 191*7c478bd9Sstevel@tonic-gate "{\n" 192*7c478bd9Sstevel@tonic-gate " @rw_r_block[arg0, ustack(5)] =\n" 193*7c478bd9Sstevel@tonic-gate " avg(timestamp - self->rwblock[arg0]);\n" 194*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = 0;\n" 195*7c478bd9Sstevel@tonic-gate "}\n" 196*7c478bd9Sstevel@tonic-gate "plockstat$target:::rw-blocked\n" 197*7c478bd9Sstevel@tonic-gate "/self->rwblock[arg0]/\n" 198*7c478bd9Sstevel@tonic-gate "{\n" 199*7c478bd9Sstevel@tonic-gate " self->rwblock[arg0] = 0;\n" 200*7c478bd9Sstevel@tonic-gate "}\n" 201*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-spun\n" 202*7c478bd9Sstevel@tonic-gate "/self->mtxspin[arg0] && arg1 != 0/\n" 203*7c478bd9Sstevel@tonic-gate "{\n" 204*7c478bd9Sstevel@tonic-gate " @mtx_spin[arg0, ustack(5)] =\n" 205*7c478bd9Sstevel@tonic-gate " avg(timestamp - self->mtxspin[arg0]);\n" 206*7c478bd9Sstevel@tonic-gate " self->mtxspin[arg0] = 0;\n" 207*7c478bd9Sstevel@tonic-gate "}\n" 208*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-spun\n" 209*7c478bd9Sstevel@tonic-gate "/self->mtxspin[arg0]/\n" 210*7c478bd9Sstevel@tonic-gate "{\n" 211*7c478bd9Sstevel@tonic-gate " @mtx_vain_spin[arg0, ustack(5)] =\n" 212*7c478bd9Sstevel@tonic-gate " avg(timestamp - self->mtxspin[arg0]);\n" 213*7c478bd9Sstevel@tonic-gate " self->mtxspin[arg0] = 0;\n" 214*7c478bd9Sstevel@tonic-gate "}\n" 215*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-blocked\n" 216*7c478bd9Sstevel@tonic-gate "/self->mtxblock[arg0] && arg1 != 0/\n" 217*7c478bd9Sstevel@tonic-gate "{\n" 218*7c478bd9Sstevel@tonic-gate " @mtx_block[arg0, ustack(5)] =\n" 219*7c478bd9Sstevel@tonic-gate " avg(timestamp - self->mtxblock[arg0]);\n" 220*7c478bd9Sstevel@tonic-gate " self->mtxblock[arg0] = 0;\n" 221*7c478bd9Sstevel@tonic-gate "}\n" 222*7c478bd9Sstevel@tonic-gate "plockstat$target:::mutex-blocked\n" 223*7c478bd9Sstevel@tonic-gate "/self->mtxblock[arg0]/\n" 224*7c478bd9Sstevel@tonic-gate "{\n" 225*7c478bd9Sstevel@tonic-gate " self->mtxblock[arg0] = 0;\n" 226*7c478bd9Sstevel@tonic-gate "}\n"; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate static char g_prog[2048]; 229*7c478bd9Sstevel@tonic-gate static size_t g_proglen; 230*7c478bd9Sstevel@tonic-gate static int g_opt_V, g_opt_s; 231*7c478bd9Sstevel@tonic-gate static int g_intr; 232*7c478bd9Sstevel@tonic-gate static dtrace_optval_t g_nframes; 233*7c478bd9Sstevel@tonic-gate static ulong_t g_nent = ULONG_MAX; 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate #define PLOCKSTAT_OPTSTR "n:ps:e:vx:ACHV" 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate static void 238*7c478bd9Sstevel@tonic-gate usage(void) 239*7c478bd9Sstevel@tonic-gate { 240*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Usage:\n" 241*7c478bd9Sstevel@tonic-gate "\t%s [-vACHV] [-n count] [-s depth] [-e secs] [-x opt[=val]]\n" 242*7c478bd9Sstevel@tonic-gate "\t command [arg...]\n" 243*7c478bd9Sstevel@tonic-gate "\t%s [-vACHV] [-n count] [-s depth] [-e secs] [-x opt[=val]]\n" 244*7c478bd9Sstevel@tonic-gate "\t -p pid\n", g_pname, g_pname); 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate exit(E_USAGE); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate static void 250*7c478bd9Sstevel@tonic-gate verror(const char *fmt, va_list ap) 251*7c478bd9Sstevel@tonic-gate { 252*7c478bd9Sstevel@tonic-gate int error = errno; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", g_pname); 255*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate if (fmt[strlen(fmt) - 1] != '\n') 258*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, ": %s\n", strerror(error)); 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 262*7c478bd9Sstevel@tonic-gate static void 263*7c478bd9Sstevel@tonic-gate fatal(const char *fmt, ...) 264*7c478bd9Sstevel@tonic-gate { 265*7c478bd9Sstevel@tonic-gate va_list ap; 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 268*7c478bd9Sstevel@tonic-gate verror(fmt, ap); 269*7c478bd9Sstevel@tonic-gate va_end(ap); 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate if (g_pr != NULL && g_dtp != NULL) 272*7c478bd9Sstevel@tonic-gate dtrace_proc_release(g_dtp, g_pr); 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate exit(E_ERROR); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 278*7c478bd9Sstevel@tonic-gate static void 279*7c478bd9Sstevel@tonic-gate dfatal(const char *fmt, ...) 280*7c478bd9Sstevel@tonic-gate { 281*7c478bd9Sstevel@tonic-gate va_list ap; 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", g_pname); 286*7c478bd9Sstevel@tonic-gate if (fmt != NULL) 287*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate va_end(ap); 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') { 292*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, ": %s\n", 293*7c478bd9Sstevel@tonic-gate dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); 294*7c478bd9Sstevel@tonic-gate } else if (fmt == NULL) { 295*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", 296*7c478bd9Sstevel@tonic-gate dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate if (g_pr != NULL) { 300*7c478bd9Sstevel@tonic-gate dtrace_proc_continue(g_dtp, g_pr); 301*7c478bd9Sstevel@tonic-gate dtrace_proc_release(g_dtp, g_pr); 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate exit(E_ERROR); 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 308*7c478bd9Sstevel@tonic-gate static void 309*7c478bd9Sstevel@tonic-gate notice(const char *fmt, ...) 310*7c478bd9Sstevel@tonic-gate { 311*7c478bd9Sstevel@tonic-gate va_list ap; 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 314*7c478bd9Sstevel@tonic-gate verror(fmt, ap); 315*7c478bd9Sstevel@tonic-gate va_end(ap); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate static void 319*7c478bd9Sstevel@tonic-gate dprog_add(const char *prog) 320*7c478bd9Sstevel@tonic-gate { 321*7c478bd9Sstevel@tonic-gate size_t len = strlen(prog); 322*7c478bd9Sstevel@tonic-gate bcopy(prog, g_prog + g_proglen, len + 1); 323*7c478bd9Sstevel@tonic-gate g_proglen += len; 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate static void 327*7c478bd9Sstevel@tonic-gate dprog_compile(void) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate dtrace_prog_t *prog; 330*7c478bd9Sstevel@tonic-gate dtrace_proginfo_t info; 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate if (g_opt_V) { 333*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: vvvv D program vvvv\n", g_pname); 334*7c478bd9Sstevel@tonic-gate (void) fputs(g_prog, stderr); 335*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ^^^^ D program ^^^^\n", g_pname); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate if ((prog = dtrace_program_strcompile(g_dtp, g_prog, 339*7c478bd9Sstevel@tonic-gate DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL) 340*7c478bd9Sstevel@tonic-gate dfatal("failed to compile program"); 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate if (dtrace_program_exec(g_dtp, prog, &info) == -1) 343*7c478bd9Sstevel@tonic-gate dfatal("failed to enable probes"); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate static void 347*7c478bd9Sstevel@tonic-gate print_header(const char *aggname) 348*7c478bd9Sstevel@tonic-gate { 349*7c478bd9Sstevel@tonic-gate if (strcmp(aggname, "mtx_hold") == 0) { 350*7c478bd9Sstevel@tonic-gate (void) printf("\nMutex hold\n\n"); 351*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "mtx_block") == 0) { 352*7c478bd9Sstevel@tonic-gate (void) printf("\nMutex block\n\n"); 353*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "mtx_spin") == 0) { 354*7c478bd9Sstevel@tonic-gate (void) printf("\nMutex spin\n\n"); 355*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "mtx_vain_spin") == 0) { 356*7c478bd9Sstevel@tonic-gate (void) printf("\nMutex unsuccessful spin\n\n"); 357*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "rw_r_hold") == 0) { 358*7c478bd9Sstevel@tonic-gate (void) printf("\nR/W reader hold\n\n"); 359*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "rw_w_hold") == 0) { 360*7c478bd9Sstevel@tonic-gate (void) printf("\nR/W writer hold\n\n"); 361*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "rw_r_block") == 0) { 362*7c478bd9Sstevel@tonic-gate (void) printf("\nR/W reader block\n\n"); 363*7c478bd9Sstevel@tonic-gate } else if (strcmp(aggname, "rw_w_block") == 0) { 364*7c478bd9Sstevel@tonic-gate (void) printf("\nR/W writer block\n\n"); 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate void 369*7c478bd9Sstevel@tonic-gate print_legend(void) 370*7c478bd9Sstevel@tonic-gate { 371*7c478bd9Sstevel@tonic-gate (void) printf("%5s %8s %-28s %s\n", "Count", "nsec", "Lock", "Caller"); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate void 375*7c478bd9Sstevel@tonic-gate print_bar(void) 376*7c478bd9Sstevel@tonic-gate { 377*7c478bd9Sstevel@tonic-gate (void) printf("---------------------------------------" 378*7c478bd9Sstevel@tonic-gate "----------------------------------------\n"); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate void 382*7c478bd9Sstevel@tonic-gate print_histogram_header(void) 383*7c478bd9Sstevel@tonic-gate { 384*7c478bd9Sstevel@tonic-gate (void) printf("\n%10s ---- Time Distribution --- %5s %s\n", 385*7c478bd9Sstevel@tonic-gate "nsec", "count", "Stack"); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate /* 389*7c478bd9Sstevel@tonic-gate * Convert an address to a symbolic string or a numeric string. If nolocks 390*7c478bd9Sstevel@tonic-gate * is set, we return an error code if this symbol appears to be a mutex- or 391*7c478bd9Sstevel@tonic-gate * rwlock-related symbol in libc so the caller has a chance to find a more 392*7c478bd9Sstevel@tonic-gate * helpful symbol. 393*7c478bd9Sstevel@tonic-gate */ 394*7c478bd9Sstevel@tonic-gate static int 395*7c478bd9Sstevel@tonic-gate getsym(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size, 396*7c478bd9Sstevel@tonic-gate int nolocks) 397*7c478bd9Sstevel@tonic-gate { 398*7c478bd9Sstevel@tonic-gate char name[256]; 399*7c478bd9Sstevel@tonic-gate GElf_Sym sym; 400*7c478bd9Sstevel@tonic-gate prsyminfo_t info; 401*7c478bd9Sstevel@tonic-gate size_t len; 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate if (P == NULL || Pxlookup_by_addr(P, addr, name, sizeof (name), 404*7c478bd9Sstevel@tonic-gate &sym, &info) != 0) { 405*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, size, "%#lx", addr); 406*7c478bd9Sstevel@tonic-gate return (0); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate if (info.prs_lmid != LM_ID_BASE) { 410*7c478bd9Sstevel@tonic-gate len = snprintf(buf, size, "LM%lu`", info.prs_lmid); 411*7c478bd9Sstevel@tonic-gate buf += len; 412*7c478bd9Sstevel@tonic-gate size -= len; 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate len = snprintf(buf, size, "%s`%s", info.prs_object, info.prs_name); 416*7c478bd9Sstevel@tonic-gate buf += len; 417*7c478bd9Sstevel@tonic-gate size -= len; 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (sym.st_value != addr) 420*7c478bd9Sstevel@tonic-gate len = snprintf(buf, size, "+%#lx", addr - sym.st_value); 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate if (nolocks && strcmp("libc.so.1", info.prs_object) == 0 && 423*7c478bd9Sstevel@tonic-gate (strstr("mutex", info.prs_name) == 0 || 424*7c478bd9Sstevel@tonic-gate strstr("rw", info.prs_name) == 0)) 425*7c478bd9Sstevel@tonic-gate return (-1); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate return (0); 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 431*7c478bd9Sstevel@tonic-gate static int 432*7c478bd9Sstevel@tonic-gate process_aggregate(dtrace_aggdata_t *agg, void *arg) 433*7c478bd9Sstevel@tonic-gate { 434*7c478bd9Sstevel@tonic-gate static dtrace_aggid_t last = DTRACE_AGGIDNONE; 435*7c478bd9Sstevel@tonic-gate static uint_t nent; 436*7c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *aggdesc = agg->dtada_desc; 437*7c478bd9Sstevel@tonic-gate caddr_t data = agg->dtada_data; 438*7c478bd9Sstevel@tonic-gate dtrace_recdesc_t *rec; 439*7c478bd9Sstevel@tonic-gate uint64_t *a, count, avg; 440*7c478bd9Sstevel@tonic-gate char buf[40]; 441*7c478bd9Sstevel@tonic-gate uintptr_t lock; 442*7c478bd9Sstevel@tonic-gate pid_t pid; 443*7c478bd9Sstevel@tonic-gate uint64_t *stack; 444*7c478bd9Sstevel@tonic-gate struct ps_prochandle *P; 445*7c478bd9Sstevel@tonic-gate int i, j; 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate if (aggdesc->dtagd_id != last) { 448*7c478bd9Sstevel@tonic-gate print_header(aggdesc->dtagd_name); 449*7c478bd9Sstevel@tonic-gate nent = 0; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate if (nent >= g_nent) 452*7c478bd9Sstevel@tonic-gate goto out; 453*7c478bd9Sstevel@tonic-gate nent++; 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate rec = aggdesc->dtagd_rec; 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /*LINTED - alignment*/ 458*7c478bd9Sstevel@tonic-gate lock = (uintptr_t)*(uint64_t *)(data + rec[1].dtrd_offset); 459*7c478bd9Sstevel@tonic-gate /*LINTED - alignment*/ 460*7c478bd9Sstevel@tonic-gate stack = (uint64_t *)(data + rec[2].dtrd_offset); 461*7c478bd9Sstevel@tonic-gate /*LINTED - alignment*/ 462*7c478bd9Sstevel@tonic-gate a = (uint64_t *)(data + rec[aggdesc->dtagd_nrecs - 1].dtrd_offset); 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate if (!g_opt_s) { 465*7c478bd9Sstevel@tonic-gate if (aggdesc->dtagd_id != last) { 466*7c478bd9Sstevel@tonic-gate print_legend(); 467*7c478bd9Sstevel@tonic-gate print_bar(); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate count = a[0]; 471*7c478bd9Sstevel@tonic-gate avg = a[1] / a[0]; 472*7c478bd9Sstevel@tonic-gate } else { 473*7c478bd9Sstevel@tonic-gate print_bar(); 474*7c478bd9Sstevel@tonic-gate print_legend(); 475*7c478bd9Sstevel@tonic-gate count = avg = 0; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate for (i = DTRACE_QUANTIZE_ZEROBUCKET, j = 0; 478*7c478bd9Sstevel@tonic-gate i < DTRACE_QUANTIZE_NBUCKETS; i++, j++) { 479*7c478bd9Sstevel@tonic-gate count += a[i]; 480*7c478bd9Sstevel@tonic-gate avg += a[i] << (j - 64); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate avg /= count; 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate (void) printf("%5llu %8llu ", (u_longlong_t)count, (u_longlong_t)avg); 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate pid = stack[0]; 489*7c478bd9Sstevel@tonic-gate P = dtrace_proc_grab(g_dtp, pid, PGRAB_RDONLY); 490*7c478bd9Sstevel@tonic-gate 491*7c478bd9Sstevel@tonic-gate (void) getsym(P, lock, buf, sizeof (buf), 0); 492*7c478bd9Sstevel@tonic-gate (void) printf("%-28s ", buf); 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate for (i = 2; i <= 5; i++) { 495*7c478bd9Sstevel@tonic-gate if (getsym(P, stack[i], buf, sizeof (buf), 1) == 0) 496*7c478bd9Sstevel@tonic-gate break; 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate (void) printf("%s\n", buf); 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate if (g_opt_s) { 501*7c478bd9Sstevel@tonic-gate int stack_done = 0; 502*7c478bd9Sstevel@tonic-gate int quant_done = 0; 503*7c478bd9Sstevel@tonic-gate int first_bin, last_bin; 504*7c478bd9Sstevel@tonic-gate uint64_t bin_size; 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate print_histogram_header(); 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate for (first_bin = DTRACE_QUANTIZE_ZEROBUCKET; 509*7c478bd9Sstevel@tonic-gate a[first_bin] == 0; first_bin++) 510*7c478bd9Sstevel@tonic-gate continue; 511*7c478bd9Sstevel@tonic-gate for (last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 63; 512*7c478bd9Sstevel@tonic-gate a[last_bin] == 0; last_bin--) 513*7c478bd9Sstevel@tonic-gate continue; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate for (i = 0; !stack_done || !quant_done; i++) { 516*7c478bd9Sstevel@tonic-gate if (!stack_done) { 517*7c478bd9Sstevel@tonic-gate (void) getsym(P, stack[i + 2], buf, 518*7c478bd9Sstevel@tonic-gate sizeof (buf), 0); 519*7c478bd9Sstevel@tonic-gate } else { 520*7c478bd9Sstevel@tonic-gate buf[0] = '\0'; 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate if (!quant_done) { 524*7c478bd9Sstevel@tonic-gate bin_size = a[first_bin]; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate (void) printf("%10llu |%-24.*s| %5llu %s\n", 527*7c478bd9Sstevel@tonic-gate 1ULL << 528*7c478bd9Sstevel@tonic-gate (first_bin - DTRACE_QUANTIZE_ZEROBUCKET), 529*7c478bd9Sstevel@tonic-gate (int)(24.0 * bin_size / count), 530*7c478bd9Sstevel@tonic-gate "@@@@@@@@@@@@@@@@@@@@@@@@@@", 531*7c478bd9Sstevel@tonic-gate (u_longlong_t)bin_size, buf); 532*7c478bd9Sstevel@tonic-gate } else { 533*7c478bd9Sstevel@tonic-gate (void) printf("%43s %s\n", "", buf); 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate if (i + 1 >= g_nframes || stack[i + 3] == 0) 537*7c478bd9Sstevel@tonic-gate stack_done = 1; 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate if (first_bin++ == last_bin) 540*7c478bd9Sstevel@tonic-gate quant_done = 1; 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate } 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate dtrace_proc_release(g_dtp, P); 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate out: 547*7c478bd9Sstevel@tonic-gate last = aggdesc->dtagd_id; 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate static int 553*7c478bd9Sstevel@tonic-gate prochandler(struct ps_prochandle *P) 554*7c478bd9Sstevel@tonic-gate { 555*7c478bd9Sstevel@tonic-gate const psinfo_t *prp = Ppsinfo(P); 556*7c478bd9Sstevel@tonic-gate int pid = Pstatus(P)->pr_pid; 557*7c478bd9Sstevel@tonic-gate char name[SIG2STR_MAX]; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate switch (Pstate(P)) { 560*7c478bd9Sstevel@tonic-gate case PS_UNDEAD: 561*7c478bd9Sstevel@tonic-gate /* 562*7c478bd9Sstevel@tonic-gate * Ideally we would like to always report pr_wstat here, but it 563*7c478bd9Sstevel@tonic-gate * isn't possible given current /proc semantics. If we grabbed 564*7c478bd9Sstevel@tonic-gate * the process, Ppsinfo() will either fail or return a zeroed 565*7c478bd9Sstevel@tonic-gate * psinfo_t depending on how far the parent is in reaping it. 566*7c478bd9Sstevel@tonic-gate * When /proc provides a stable pr_wstat in the status file, 567*7c478bd9Sstevel@tonic-gate * this code can be improved by examining this new pr_wstat. 568*7c478bd9Sstevel@tonic-gate */ 569*7c478bd9Sstevel@tonic-gate if (prp != NULL && WIFSIGNALED(prp->pr_wstat)) { 570*7c478bd9Sstevel@tonic-gate notice("pid %d terminated by %s\n", pid, 571*7c478bd9Sstevel@tonic-gate proc_signame(WTERMSIG(prp->pr_wstat), 572*7c478bd9Sstevel@tonic-gate name, sizeof (name))); 573*7c478bd9Sstevel@tonic-gate } else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) { 574*7c478bd9Sstevel@tonic-gate notice("pid %d exited with status %d\n", 575*7c478bd9Sstevel@tonic-gate pid, WEXITSTATUS(prp->pr_wstat)); 576*7c478bd9Sstevel@tonic-gate } else { 577*7c478bd9Sstevel@tonic-gate notice("pid %d has exited\n", pid); 578*7c478bd9Sstevel@tonic-gate } 579*7c478bd9Sstevel@tonic-gate return (1); 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate case PS_LOST: 582*7c478bd9Sstevel@tonic-gate notice("pid %d exec'd a set-id or unobservable program\n", pid); 583*7c478bd9Sstevel@tonic-gate return (1); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate return (0); 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 590*7c478bd9Sstevel@tonic-gate static void 591*7c478bd9Sstevel@tonic-gate intr(int signo) 592*7c478bd9Sstevel@tonic-gate { 593*7c478bd9Sstevel@tonic-gate g_intr = 1; 594*7c478bd9Sstevel@tonic-gate } 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate int 597*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 598*7c478bd9Sstevel@tonic-gate { 599*7c478bd9Sstevel@tonic-gate ucred_t *ucp; 600*7c478bd9Sstevel@tonic-gate int err; 601*7c478bd9Sstevel@tonic-gate int opt_C = 0, opt_H = 0, opt_p = 0, opt_v = 0; 602*7c478bd9Sstevel@tonic-gate char c, *p, *end; 603*7c478bd9Sstevel@tonic-gate struct sigaction act; 604*7c478bd9Sstevel@tonic-gate int done = 0; 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate if ((g_pname = strrchr(argv[0], '/')) == NULL) 607*7c478bd9Sstevel@tonic-gate g_pname = argv[0]; 608*7c478bd9Sstevel@tonic-gate else 609*7c478bd9Sstevel@tonic-gate argv[0] = ++g_pname; /* for getopt() */ 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * Make sure we have the required dtrace_proc privilege. 613*7c478bd9Sstevel@tonic-gate */ 614*7c478bd9Sstevel@tonic-gate if ((ucp = ucred_get(getpid())) != NULL) { 615*7c478bd9Sstevel@tonic-gate const priv_set_t *psp; 616*7c478bd9Sstevel@tonic-gate if ((psp = ucred_getprivset(ucp, PRIV_EFFECTIVE)) != NULL && 617*7c478bd9Sstevel@tonic-gate !priv_ismember(psp, PRIV_DTRACE_PROC)) { 618*7c478bd9Sstevel@tonic-gate fatal("dtrace_proc privilege required\n"); 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate 621*7c478bd9Sstevel@tonic-gate ucred_free(ucp); 622*7c478bd9Sstevel@tonic-gate } 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) { 625*7c478bd9Sstevel@tonic-gate switch (c) { 626*7c478bd9Sstevel@tonic-gate case 'n': 627*7c478bd9Sstevel@tonic-gate errno = 0; 628*7c478bd9Sstevel@tonic-gate g_nent = strtoul(optarg, &end, 10); 629*7c478bd9Sstevel@tonic-gate if (*end != '\0' || errno != 0) { 630*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: invalid count " 631*7c478bd9Sstevel@tonic-gate "'%s'\n", g_pname, optarg); 632*7c478bd9Sstevel@tonic-gate usage(); 633*7c478bd9Sstevel@tonic-gate } 634*7c478bd9Sstevel@tonic-gate break; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate case 'p': 637*7c478bd9Sstevel@tonic-gate opt_p = 1; 638*7c478bd9Sstevel@tonic-gate break; 639*7c478bd9Sstevel@tonic-gate 640*7c478bd9Sstevel@tonic-gate case 'v': 641*7c478bd9Sstevel@tonic-gate opt_v = 1; 642*7c478bd9Sstevel@tonic-gate break; 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate case 'A': 645*7c478bd9Sstevel@tonic-gate opt_C = opt_H = 1; 646*7c478bd9Sstevel@tonic-gate break; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate case 'C': 649*7c478bd9Sstevel@tonic-gate opt_C = 1; 650*7c478bd9Sstevel@tonic-gate break; 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate case 'H': 653*7c478bd9Sstevel@tonic-gate opt_H = 1; 654*7c478bd9Sstevel@tonic-gate break; 655*7c478bd9Sstevel@tonic-gate 656*7c478bd9Sstevel@tonic-gate case 'V': 657*7c478bd9Sstevel@tonic-gate g_opt_V = 1; 658*7c478bd9Sstevel@tonic-gate break; 659*7c478bd9Sstevel@tonic-gate 660*7c478bd9Sstevel@tonic-gate default: 661*7c478bd9Sstevel@tonic-gate if (strchr(PLOCKSTAT_OPTSTR, c) == NULL) 662*7c478bd9Sstevel@tonic-gate usage(); 663*7c478bd9Sstevel@tonic-gate } 664*7c478bd9Sstevel@tonic-gate } 665*7c478bd9Sstevel@tonic-gate 666*7c478bd9Sstevel@tonic-gate /* 667*7c478bd9Sstevel@tonic-gate * We need a command or at least one pid. 668*7c478bd9Sstevel@tonic-gate */ 669*7c478bd9Sstevel@tonic-gate if (argc == optind) 670*7c478bd9Sstevel@tonic-gate usage(); 671*7c478bd9Sstevel@tonic-gate 672*7c478bd9Sstevel@tonic-gate if (opt_C == 0 && opt_H == 0) 673*7c478bd9Sstevel@tonic-gate opt_C = 1; 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL) 676*7c478bd9Sstevel@tonic-gate fatal("failed to initialize dtrace: %s\n", 677*7c478bd9Sstevel@tonic-gate dtrace_errmsg(NULL, err)); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate if (dtrace_setopt(g_dtp, "aggsize", "256k") == -1) 680*7c478bd9Sstevel@tonic-gate dfatal("failed to set 'aggsize'"); 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate if (dtrace_setopt(g_dtp, "aggrate", "1sec") == -1) 683*7c478bd9Sstevel@tonic-gate dfatal("failed to set 'aggrate'"); 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* 686*7c478bd9Sstevel@tonic-gate * Take a second pass through to look for options that set options now 687*7c478bd9Sstevel@tonic-gate * that we have an open dtrace handle. 688*7c478bd9Sstevel@tonic-gate */ 689*7c478bd9Sstevel@tonic-gate optind = 1; 690*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) { 691*7c478bd9Sstevel@tonic-gate switch (c) { 692*7c478bd9Sstevel@tonic-gate case 's': 693*7c478bd9Sstevel@tonic-gate g_opt_s = 1; 694*7c478bd9Sstevel@tonic-gate if (dtrace_setopt(g_dtp, "ustackframes", optarg) == -1) 695*7c478bd9Sstevel@tonic-gate dfatal("failed to set 'ustackframes'"); 696*7c478bd9Sstevel@tonic-gate break; 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate case 'x': 699*7c478bd9Sstevel@tonic-gate if ((p = strchr(optarg, '=')) != NULL) 700*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate if (dtrace_setopt(g_dtp, optarg, p) != 0) 703*7c478bd9Sstevel@tonic-gate dfatal("failed to set -x %s", optarg); 704*7c478bd9Sstevel@tonic-gate break; 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate case 'e': 707*7c478bd9Sstevel@tonic-gate errno = 0; 708*7c478bd9Sstevel@tonic-gate (void) strtoul(optarg, &end, 10); 709*7c478bd9Sstevel@tonic-gate if (*optarg == '-' || *end != '\0' || errno != 0) { 710*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: invalid timeout " 711*7c478bd9Sstevel@tonic-gate "'%s'\n", g_pname, optarg); 712*7c478bd9Sstevel@tonic-gate usage(); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate /* 716*7c478bd9Sstevel@tonic-gate * Construct a DTrace enabling that will exit after 717*7c478bd9Sstevel@tonic-gate * the specified number of seconds. 718*7c478bd9Sstevel@tonic-gate */ 719*7c478bd9Sstevel@tonic-gate dprog_add("BEGIN\n{\n\tend = timestamp + "); 720*7c478bd9Sstevel@tonic-gate dprog_add(optarg); 721*7c478bd9Sstevel@tonic-gate dprog_add(" * 1000000000;\n}\n"); 722*7c478bd9Sstevel@tonic-gate dprog_add("tick-10hz\n/timestamp >= end/\n"); 723*7c478bd9Sstevel@tonic-gate dprog_add("{\n\texit(0);\n}\n"); 724*7c478bd9Sstevel@tonic-gate break; 725*7c478bd9Sstevel@tonic-gate } 726*7c478bd9Sstevel@tonic-gate } 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate argc -= optind; 729*7c478bd9Sstevel@tonic-gate argv += optind; 730*7c478bd9Sstevel@tonic-gate 731*7c478bd9Sstevel@tonic-gate if (opt_H) { 732*7c478bd9Sstevel@tonic-gate dprog_add(g_hold_init); 733*7c478bd9Sstevel@tonic-gate if (g_opt_s == NULL) 734*7c478bd9Sstevel@tonic-gate dprog_add(g_hold_times); 735*7c478bd9Sstevel@tonic-gate else 736*7c478bd9Sstevel@tonic-gate dprog_add(g_hold_histogram); 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate if (opt_C) { 740*7c478bd9Sstevel@tonic-gate dprog_add(g_ctnd_init); 741*7c478bd9Sstevel@tonic-gate if (g_opt_s == NULL) 742*7c478bd9Sstevel@tonic-gate dprog_add(g_ctnd_times); 743*7c478bd9Sstevel@tonic-gate else 744*7c478bd9Sstevel@tonic-gate dprog_add(g_ctnd_histogram); 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate if (opt_p) { 748*7c478bd9Sstevel@tonic-gate ulong_t pid; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate if (argc > 1) { 751*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: only one pid is allowed\n", 752*7c478bd9Sstevel@tonic-gate g_pname); 753*7c478bd9Sstevel@tonic-gate usage(); 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate errno = 0; 757*7c478bd9Sstevel@tonic-gate pid = strtoul(argv[0], &end, 10); 758*7c478bd9Sstevel@tonic-gate if (*end != '\0' || errno != 0 || (pid_t)pid != pid) { 759*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: invalid pid '%s'\n", 760*7c478bd9Sstevel@tonic-gate g_pname, argv[0]); 761*7c478bd9Sstevel@tonic-gate usage(); 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate if ((g_pr = dtrace_proc_grab(g_dtp, (pid_t)pid, 0)) == NULL) 765*7c478bd9Sstevel@tonic-gate dfatal(NULL); 766*7c478bd9Sstevel@tonic-gate } else { 767*7c478bd9Sstevel@tonic-gate if ((g_pr = dtrace_proc_create(g_dtp, argv[0], argv)) == NULL) 768*7c478bd9Sstevel@tonic-gate dfatal(NULL); 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate dprog_compile(); 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask); 774*7c478bd9Sstevel@tonic-gate act.sa_flags = 0; 775*7c478bd9Sstevel@tonic-gate act.sa_handler = intr; 776*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGINT, &act, NULL); 777*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGTERM, &act, NULL); 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate if (dtrace_go(g_dtp) != 0) 780*7c478bd9Sstevel@tonic-gate dfatal("dtrace_go()"); 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate if (dtrace_getopt(g_dtp, "ustackframes", &g_nframes) != 0) 783*7c478bd9Sstevel@tonic-gate dfatal("failed to get 'ustackframes'"); 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate dtrace_proc_continue(g_dtp, g_pr); 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate if (opt_v) 788*7c478bd9Sstevel@tonic-gate (void) printf("%s: tracing enabled for pid %d\n", g_pname, 789*7c478bd9Sstevel@tonic-gate (int)Pstatus(g_pr)->pr_pid); 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate while (!done) { 792*7c478bd9Sstevel@tonic-gate (void) sleep(1); 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate if (dtrace_status(g_dtp) == DTRACE_STATUS_EXITED) 795*7c478bd9Sstevel@tonic-gate done = 1; 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate /* Done if the user hits control-C. */ 798*7c478bd9Sstevel@tonic-gate if (g_intr) 799*7c478bd9Sstevel@tonic-gate done = 1; 800*7c478bd9Sstevel@tonic-gate 801*7c478bd9Sstevel@tonic-gate if (prochandler(g_pr) == 1) 802*7c478bd9Sstevel@tonic-gate done = 1; 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate if (dtrace_aggregate_snap(g_dtp) != 0) 805*7c478bd9Sstevel@tonic-gate dfatal("failed to add to aggregate"); 806*7c478bd9Sstevel@tonic-gate } 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate if (dtrace_aggregate_snap(g_dtp) != 0) 809*7c478bd9Sstevel@tonic-gate dfatal("failed to add to aggregate"); 810*7c478bd9Sstevel@tonic-gate 811*7c478bd9Sstevel@tonic-gate if (dtrace_aggregate_walk_valrevsorted(g_dtp, 812*7c478bd9Sstevel@tonic-gate process_aggregate, NULL) != 0) 813*7c478bd9Sstevel@tonic-gate dfatal("failed to print aggregations"); 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate dtrace_close(g_dtp); 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate return (0); 818*7c478bd9Sstevel@tonic-gate } 819