10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*5984Sjhaslam * Common Development and Distribution License (the "License"). 6*5984Sjhaslam * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5984Sjhaslam * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <stdlib.h> 290Sstevel@tonic-gate #include <strings.h> 300Sstevel@tonic-gate #include <errno.h> 310Sstevel@tonic-gate #include <unistd.h> 320Sstevel@tonic-gate #include <limits.h> 330Sstevel@tonic-gate #include <assert.h> 340Sstevel@tonic-gate #include <ctype.h> 350Sstevel@tonic-gate #include <alloca.h> 36457Sbmc #include <dt_impl.h> 370Sstevel@tonic-gate 38*5984Sjhaslam #define DT_MASK_LO 0x00000000FFFFFFFFULL 39*5984Sjhaslam 40457Sbmc /* 41457Sbmc * We declare this here because (1) we need it and (2) we want to avoid a 42457Sbmc * dependency on libm in libdtrace. 43457Sbmc */ 44457Sbmc static long double 45457Sbmc dt_fabsl(long double x) 46457Sbmc { 47457Sbmc if (x < 0) 48457Sbmc return (-x); 49457Sbmc 50457Sbmc return (x); 51457Sbmc } 520Sstevel@tonic-gate 53*5984Sjhaslam /* 54*5984Sjhaslam * 128-bit arithmetic functions needed to support the stddev() aggregating 55*5984Sjhaslam * action. 56*5984Sjhaslam */ 57*5984Sjhaslam static int 58*5984Sjhaslam dt_gt_128(uint64_t *a, uint64_t *b) 59*5984Sjhaslam { 60*5984Sjhaslam return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0])); 61*5984Sjhaslam } 62*5984Sjhaslam 63*5984Sjhaslam static int 64*5984Sjhaslam dt_ge_128(uint64_t *a, uint64_t *b) 65*5984Sjhaslam { 66*5984Sjhaslam return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0])); 67*5984Sjhaslam } 68*5984Sjhaslam 69*5984Sjhaslam static int 70*5984Sjhaslam dt_le_128(uint64_t *a, uint64_t *b) 71*5984Sjhaslam { 72*5984Sjhaslam return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0])); 73*5984Sjhaslam } 74*5984Sjhaslam 75*5984Sjhaslam /* 76*5984Sjhaslam * Shift the 128-bit value in a by b. If b is positive, shift left. 77*5984Sjhaslam * If b is negative, shift right. 78*5984Sjhaslam */ 79*5984Sjhaslam static void 80*5984Sjhaslam dt_shift_128(uint64_t *a, int b) 81*5984Sjhaslam { 82*5984Sjhaslam uint64_t mask; 83*5984Sjhaslam 84*5984Sjhaslam if (b == 0) 85*5984Sjhaslam return; 86*5984Sjhaslam 87*5984Sjhaslam if (b < 0) { 88*5984Sjhaslam b = -b; 89*5984Sjhaslam if (b >= 64) { 90*5984Sjhaslam a[0] = a[1] >> (b - 64); 91*5984Sjhaslam a[1] = 0; 92*5984Sjhaslam } else { 93*5984Sjhaslam a[0] >>= b; 94*5984Sjhaslam mask = 1LL << (64 - b); 95*5984Sjhaslam mask -= 1; 96*5984Sjhaslam a[0] |= ((a[1] & mask) << (64 - b)); 97*5984Sjhaslam a[1] >>= b; 98*5984Sjhaslam } 99*5984Sjhaslam } else { 100*5984Sjhaslam if (b >= 64) { 101*5984Sjhaslam a[1] = a[0] << (b - 64); 102*5984Sjhaslam a[0] = 0; 103*5984Sjhaslam } else { 104*5984Sjhaslam a[1] <<= b; 105*5984Sjhaslam mask = a[0] >> (64 - b); 106*5984Sjhaslam a[1] |= mask; 107*5984Sjhaslam a[0] <<= b; 108*5984Sjhaslam } 109*5984Sjhaslam } 110*5984Sjhaslam } 111*5984Sjhaslam 112*5984Sjhaslam static int 113*5984Sjhaslam dt_nbits_128(uint64_t *a) 114*5984Sjhaslam { 115*5984Sjhaslam int nbits = 0; 116*5984Sjhaslam uint64_t tmp[2]; 117*5984Sjhaslam uint64_t zero[2] = { 0, 0 }; 118*5984Sjhaslam 119*5984Sjhaslam tmp[0] = a[0]; 120*5984Sjhaslam tmp[1] = a[1]; 121*5984Sjhaslam 122*5984Sjhaslam dt_shift_128(tmp, -1); 123*5984Sjhaslam while (dt_gt_128(tmp, zero)) { 124*5984Sjhaslam dt_shift_128(tmp, -1); 125*5984Sjhaslam nbits++; 126*5984Sjhaslam } 127*5984Sjhaslam 128*5984Sjhaslam return (nbits); 129*5984Sjhaslam } 130*5984Sjhaslam 131*5984Sjhaslam static void 132*5984Sjhaslam dt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference) 133*5984Sjhaslam { 134*5984Sjhaslam uint64_t result[2]; 135*5984Sjhaslam 136*5984Sjhaslam result[0] = minuend[0] - subtrahend[0]; 137*5984Sjhaslam result[1] = minuend[1] - subtrahend[1] - 138*5984Sjhaslam (minuend[0] < subtrahend[0] ? 1 : 0); 139*5984Sjhaslam 140*5984Sjhaslam difference[0] = result[0]; 141*5984Sjhaslam difference[1] = result[1]; 142*5984Sjhaslam } 143*5984Sjhaslam 144*5984Sjhaslam static void 145*5984Sjhaslam dt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) 146*5984Sjhaslam { 147*5984Sjhaslam uint64_t result[2]; 148*5984Sjhaslam 149*5984Sjhaslam result[0] = addend1[0] + addend2[0]; 150*5984Sjhaslam result[1] = addend1[1] + addend2[1] + 151*5984Sjhaslam (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); 152*5984Sjhaslam 153*5984Sjhaslam sum[0] = result[0]; 154*5984Sjhaslam sum[1] = result[1]; 155*5984Sjhaslam } 156*5984Sjhaslam 157*5984Sjhaslam /* 158*5984Sjhaslam * The basic idea is to break the 2 64-bit values into 4 32-bit values, 159*5984Sjhaslam * use native multiplication on those, and then re-combine into the 160*5984Sjhaslam * resulting 128-bit value. 161*5984Sjhaslam * 162*5984Sjhaslam * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) = 163*5984Sjhaslam * hi1 * hi2 << 64 + 164*5984Sjhaslam * hi1 * lo2 << 32 + 165*5984Sjhaslam * hi2 * lo1 << 32 + 166*5984Sjhaslam * lo1 * lo2 167*5984Sjhaslam */ 168*5984Sjhaslam static void 169*5984Sjhaslam dt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product) 170*5984Sjhaslam { 171*5984Sjhaslam uint64_t hi1, hi2, lo1, lo2; 172*5984Sjhaslam uint64_t tmp[2]; 173*5984Sjhaslam 174*5984Sjhaslam hi1 = factor1 >> 32; 175*5984Sjhaslam hi2 = factor2 >> 32; 176*5984Sjhaslam 177*5984Sjhaslam lo1 = factor1 & DT_MASK_LO; 178*5984Sjhaslam lo2 = factor2 & DT_MASK_LO; 179*5984Sjhaslam 180*5984Sjhaslam product[0] = lo1 * lo2; 181*5984Sjhaslam product[1] = hi1 * hi2; 182*5984Sjhaslam 183*5984Sjhaslam tmp[0] = hi1 * lo2; 184*5984Sjhaslam tmp[1] = 0; 185*5984Sjhaslam dt_shift_128(tmp, 32); 186*5984Sjhaslam dt_add_128(product, tmp, product); 187*5984Sjhaslam 188*5984Sjhaslam tmp[0] = hi2 * lo1; 189*5984Sjhaslam tmp[1] = 0; 190*5984Sjhaslam dt_shift_128(tmp, 32); 191*5984Sjhaslam dt_add_128(product, tmp, product); 192*5984Sjhaslam } 193*5984Sjhaslam 194*5984Sjhaslam /* 195*5984Sjhaslam * This is long-hand division. 196*5984Sjhaslam * 197*5984Sjhaslam * We initialize subtrahend by shifting divisor left as far as possible. We 198*5984Sjhaslam * loop, comparing subtrahend to dividend: if subtrahend is smaller, we 199*5984Sjhaslam * subtract and set the appropriate bit in the result. We then shift 200*5984Sjhaslam * subtrahend right by one bit for the next comparison. 201*5984Sjhaslam */ 202*5984Sjhaslam static void 203*5984Sjhaslam dt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient) 204*5984Sjhaslam { 205*5984Sjhaslam uint64_t result[2] = { 0, 0 }; 206*5984Sjhaslam uint64_t remainder[2]; 207*5984Sjhaslam uint64_t subtrahend[2]; 208*5984Sjhaslam uint64_t divisor_128[2]; 209*5984Sjhaslam uint64_t mask[2] = { 1, 0 }; 210*5984Sjhaslam int log = 0; 211*5984Sjhaslam 212*5984Sjhaslam assert(divisor != 0); 213*5984Sjhaslam 214*5984Sjhaslam divisor_128[0] = divisor; 215*5984Sjhaslam divisor_128[1] = 0; 216*5984Sjhaslam 217*5984Sjhaslam remainder[0] = dividend[0]; 218*5984Sjhaslam remainder[1] = dividend[1]; 219*5984Sjhaslam 220*5984Sjhaslam subtrahend[0] = divisor; 221*5984Sjhaslam subtrahend[1] = 0; 222*5984Sjhaslam 223*5984Sjhaslam while (divisor > 0) { 224*5984Sjhaslam log++; 225*5984Sjhaslam divisor >>= 1; 226*5984Sjhaslam } 227*5984Sjhaslam 228*5984Sjhaslam dt_shift_128(subtrahend, 128 - log); 229*5984Sjhaslam dt_shift_128(mask, 128 - log); 230*5984Sjhaslam 231*5984Sjhaslam while (dt_ge_128(remainder, divisor_128)) { 232*5984Sjhaslam if (dt_ge_128(remainder, subtrahend)) { 233*5984Sjhaslam dt_subtract_128(remainder, subtrahend, remainder); 234*5984Sjhaslam result[0] |= mask[0]; 235*5984Sjhaslam result[1] |= mask[1]; 236*5984Sjhaslam } 237*5984Sjhaslam 238*5984Sjhaslam dt_shift_128(subtrahend, -1); 239*5984Sjhaslam dt_shift_128(mask, -1); 240*5984Sjhaslam } 241*5984Sjhaslam 242*5984Sjhaslam quotient[0] = result[0]; 243*5984Sjhaslam quotient[1] = result[1]; 244*5984Sjhaslam } 245*5984Sjhaslam 246*5984Sjhaslam /* 247*5984Sjhaslam * This is the long-hand method of calculating a square root. 248*5984Sjhaslam * The algorithm is as follows: 249*5984Sjhaslam * 250*5984Sjhaslam * 1. Group the digits by 2 from the right. 251*5984Sjhaslam * 2. Over the leftmost group, find the largest single-digit number 252*5984Sjhaslam * whose square is less than that group. 253*5984Sjhaslam * 3. Subtract the result of the previous step (2 or 4, depending) and 254*5984Sjhaslam * bring down the next two-digit group. 255*5984Sjhaslam * 4. For the result R we have so far, find the largest single-digit number 256*5984Sjhaslam * x such that 2 * R * 10 * x + x^2 is less than the result from step 3. 257*5984Sjhaslam * (Note that this is doubling R and performing a decimal left-shift by 1 258*5984Sjhaslam * and searching for the appropriate decimal to fill the one's place.) 259*5984Sjhaslam * The value x is the next digit in the square root. 260*5984Sjhaslam * Repeat steps 3 and 4 until the desired precision is reached. (We're 261*5984Sjhaslam * dealing with integers, so the above is sufficient.) 262*5984Sjhaslam * 263*5984Sjhaslam * In decimal, the square root of 582,734 would be calculated as so: 264*5984Sjhaslam * 265*5984Sjhaslam * __7__6__3 266*5984Sjhaslam * | 58 27 34 267*5984Sjhaslam * -49 (7^2 == 49 => 7 is the first digit in the square root) 268*5984Sjhaslam * -- 269*5984Sjhaslam * 9 27 (Subtract and bring down the next group.) 270*5984Sjhaslam * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in 271*5984Sjhaslam * ----- the square root) 272*5984Sjhaslam * 51 34 (Subtract and bring down the next group.) 273*5984Sjhaslam * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in 274*5984Sjhaslam * ----- the square root) 275*5984Sjhaslam * 5 65 (remainder) 276*5984Sjhaslam * 277*5984Sjhaslam * The above algorithm applies similarly in binary, but note that the 278*5984Sjhaslam * only possible non-zero value for x in step 4 is 1, so step 4 becomes a 279*5984Sjhaslam * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the 280*5984Sjhaslam * preceding difference? 281*5984Sjhaslam * 282*5984Sjhaslam * In binary, the square root of 11011011 would be calculated as so: 283*5984Sjhaslam * 284*5984Sjhaslam * __1__1__1__0 285*5984Sjhaslam * | 11 01 10 11 286*5984Sjhaslam * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1) 287*5984Sjhaslam * -- 288*5984Sjhaslam * 10 01 10 11 289*5984Sjhaslam * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1) 290*5984Sjhaslam * ----- 291*5984Sjhaslam * 1 00 10 11 292*5984Sjhaslam * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1) 293*5984Sjhaslam * ------- 294*5984Sjhaslam * 1 01 11 295*5984Sjhaslam * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0) 296*5984Sjhaslam * 297*5984Sjhaslam */ 298*5984Sjhaslam static uint64_t 299*5984Sjhaslam dt_sqrt_128(uint64_t *square) 300*5984Sjhaslam { 301*5984Sjhaslam uint64_t result[2] = { 0, 0 }; 302*5984Sjhaslam uint64_t diff[2] = { 0, 0 }; 303*5984Sjhaslam uint64_t one[2] = { 1, 0 }; 304*5984Sjhaslam uint64_t next_pair[2]; 305*5984Sjhaslam uint64_t next_try[2]; 306*5984Sjhaslam uint64_t bit_pairs, pair_shift; 307*5984Sjhaslam int i; 308*5984Sjhaslam 309*5984Sjhaslam bit_pairs = dt_nbits_128(square) / 2; 310*5984Sjhaslam pair_shift = bit_pairs * 2; 311*5984Sjhaslam 312*5984Sjhaslam for (i = 0; i <= bit_pairs; i++) { 313*5984Sjhaslam /* 314*5984Sjhaslam * Bring down the next pair of bits. 315*5984Sjhaslam */ 316*5984Sjhaslam next_pair[0] = square[0]; 317*5984Sjhaslam next_pair[1] = square[1]; 318*5984Sjhaslam dt_shift_128(next_pair, -pair_shift); 319*5984Sjhaslam next_pair[0] &= 0x3; 320*5984Sjhaslam next_pair[1] = 0; 321*5984Sjhaslam 322*5984Sjhaslam dt_shift_128(diff, 2); 323*5984Sjhaslam dt_add_128(diff, next_pair, diff); 324*5984Sjhaslam 325*5984Sjhaslam /* 326*5984Sjhaslam * next_try = R << 2 + 1 327*5984Sjhaslam */ 328*5984Sjhaslam next_try[0] = result[0]; 329*5984Sjhaslam next_try[1] = result[1]; 330*5984Sjhaslam dt_shift_128(next_try, 2); 331*5984Sjhaslam dt_add_128(next_try, one, next_try); 332*5984Sjhaslam 333*5984Sjhaslam if (dt_le_128(next_try, diff)) { 334*5984Sjhaslam dt_subtract_128(diff, next_try, diff); 335*5984Sjhaslam dt_shift_128(result, 1); 336*5984Sjhaslam dt_add_128(result, one, result); 337*5984Sjhaslam } else { 338*5984Sjhaslam dt_shift_128(result, 1); 339*5984Sjhaslam } 340*5984Sjhaslam 341*5984Sjhaslam pair_shift -= 2; 342*5984Sjhaslam } 343*5984Sjhaslam 344*5984Sjhaslam assert(result[1] == 0); 345*5984Sjhaslam 346*5984Sjhaslam return (result[0]); 347*5984Sjhaslam } 348*5984Sjhaslam 349*5984Sjhaslam uint64_t 350*5984Sjhaslam dt_stddev(uint64_t *data, uint64_t normal) 351*5984Sjhaslam { 352*5984Sjhaslam uint64_t avg_of_squares[2]; 353*5984Sjhaslam uint64_t square_of_avg[2]; 354*5984Sjhaslam int64_t norm_avg; 355*5984Sjhaslam uint64_t diff[2]; 356*5984Sjhaslam 357*5984Sjhaslam /* 358*5984Sjhaslam * The standard approximation for standard deviation is 359*5984Sjhaslam * sqrt(average(x**2) - average(x)**2), i.e. the square root 360*5984Sjhaslam * of the average of the squares minus the square of the average. 361*5984Sjhaslam */ 362*5984Sjhaslam dt_divide_128(data + 2, normal, avg_of_squares); 363*5984Sjhaslam dt_divide_128(avg_of_squares, data[0], avg_of_squares); 364*5984Sjhaslam 365*5984Sjhaslam norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0]; 366*5984Sjhaslam 367*5984Sjhaslam if (norm_avg < 0) 368*5984Sjhaslam norm_avg = -norm_avg; 369*5984Sjhaslam 370*5984Sjhaslam dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg); 371*5984Sjhaslam 372*5984Sjhaslam dt_subtract_128(avg_of_squares, square_of_avg, diff); 373*5984Sjhaslam 374*5984Sjhaslam return (dt_sqrt_128(diff)); 375*5984Sjhaslam } 376*5984Sjhaslam 3770Sstevel@tonic-gate static int 3780Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 3790Sstevel@tonic-gate dtrace_bufdesc_t *buf, size_t offs) 3800Sstevel@tonic-gate { 3810Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 3820Sstevel@tonic-gate dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 383457Sbmc char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub; 3840Sstevel@tonic-gate dtrace_flowkind_t flow = DTRACEFLOW_NONE; 3850Sstevel@tonic-gate const char *str = NULL; 3860Sstevel@tonic-gate static const char *e_str[2] = { " -> ", " => " }; 3870Sstevel@tonic-gate static const char *r_str[2] = { " <- ", " <= " }; 388457Sbmc static const char *ent = "entry", *ret = "return"; 389457Sbmc static int entlen = 0, retlen = 0; 3900Sstevel@tonic-gate dtrace_epid_t next, id = epd->dtepd_epid; 3910Sstevel@tonic-gate int rval; 3920Sstevel@tonic-gate 393457Sbmc if (entlen == 0) { 394457Sbmc assert(retlen == 0); 395457Sbmc entlen = strlen(ent); 396457Sbmc retlen = strlen(ret); 397457Sbmc } 398457Sbmc 399457Sbmc /* 400457Sbmc * If the name of the probe is "entry" or ends with "-entry", we 401457Sbmc * treat it as an entry; if it is "return" or ends with "-return", 402457Sbmc * we treat it as a return. (This allows application-provided probes 403457Sbmc * like "method-entry" or "function-entry" to participate in flow 404457Sbmc * indentation -- without accidentally misinterpreting popular probe 405457Sbmc * names like "carpentry", "gentry" or "Coventry".) 406457Sbmc */ 407457Sbmc if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' && 408457Sbmc (sub == n || sub[-1] == '-')) { 4090Sstevel@tonic-gate flow = DTRACEFLOW_ENTRY; 4100Sstevel@tonic-gate str = e_str[strcmp(p, "syscall") == 0]; 411457Sbmc } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' && 412457Sbmc (sub == n || sub[-1] == '-')) { 4130Sstevel@tonic-gate flow = DTRACEFLOW_RETURN; 4140Sstevel@tonic-gate str = r_str[strcmp(p, "syscall") == 0]; 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * If we're going to indent this, we need to check the ID of our last 4190Sstevel@tonic-gate * call. If we're looking at the same probe ID but a different EPID, 4200Sstevel@tonic-gate * we _don't_ want to indent. (Yes, there are some minor holes in 4210Sstevel@tonic-gate * this scheme -- it's a heuristic.) 4220Sstevel@tonic-gate */ 4230Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY) { 4240Sstevel@tonic-gate if ((last != DTRACE_EPIDNONE && id != last && 4250Sstevel@tonic-gate pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 4260Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate /* 4300Sstevel@tonic-gate * If we're going to unindent this, it's more difficult to see if 4310Sstevel@tonic-gate * we don't actually want to unindent it -- we need to look at the 4320Sstevel@tonic-gate * _next_ EPID. 4330Sstevel@tonic-gate */ 4340Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN) { 4350Sstevel@tonic-gate offs += epd->dtepd_size; 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate do { 4380Sstevel@tonic-gate if (offs >= buf->dtbd_size) { 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * We're at the end -- maybe. If the oldest 4410Sstevel@tonic-gate * record is non-zero, we need to wrap. 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate if (buf->dtbd_oldest != 0) { 4440Sstevel@tonic-gate offs = 0; 4450Sstevel@tonic-gate } else { 4460Sstevel@tonic-gate goto out; 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate if (next == DTRACE_EPIDNONE) 4530Sstevel@tonic-gate offs += sizeof (id); 4540Sstevel@tonic-gate } while (next == DTRACE_EPIDNONE); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 4570Sstevel@tonic-gate return (rval); 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate if (next != id && npd->dtpd_id == pd->dtpd_id) 4600Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate out: 4640Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 4650Sstevel@tonic-gate data->dtpda_prefix = str; 4660Sstevel@tonic-gate } else { 4670Sstevel@tonic-gate data->dtpda_prefix = "| "; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 4710Sstevel@tonic-gate data->dtpda_indent -= 2; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate data->dtpda_flow = flow; 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate return (0); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate static int 4790Sstevel@tonic-gate dt_nullprobe() 4800Sstevel@tonic-gate { 4810Sstevel@tonic-gate return (DTRACE_CONSUME_THIS); 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate static int 4850Sstevel@tonic-gate dt_nullrec() 4860Sstevel@tonic-gate { 4870Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate int 491457Sbmc dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 492457Sbmc uint64_t normal, long double total, char positives, char negatives) 493457Sbmc { 494457Sbmc long double f; 495457Sbmc uint_t depth, len = 40; 496457Sbmc 497457Sbmc const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 498457Sbmc const char *spaces = " "; 499457Sbmc 500457Sbmc assert(strlen(ats) == len && strlen(spaces) == len); 501457Sbmc assert(!(total == 0 && (positives || negatives))); 502457Sbmc assert(!(val < 0 && !negatives)); 503457Sbmc assert(!(val > 0 && !positives)); 504457Sbmc assert(!(val != 0 && total == 0)); 505457Sbmc 506457Sbmc if (!negatives) { 507457Sbmc if (positives) { 508457Sbmc f = (dt_fabsl((long double)val) * len) / total; 509457Sbmc depth = (uint_t)(f + 0.5); 510457Sbmc } else { 511457Sbmc depth = 0; 512457Sbmc } 513457Sbmc 514457Sbmc return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth, 515457Sbmc spaces + depth, (long long)val / normal)); 516457Sbmc } 517457Sbmc 518457Sbmc if (!positives) { 519457Sbmc f = (dt_fabsl((long double)val) * len) / total; 520457Sbmc depth = (uint_t)(f + 0.5); 521457Sbmc 522457Sbmc return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth, 523457Sbmc ats + len - depth, (long long)val / normal)); 524457Sbmc } 525457Sbmc 526457Sbmc /* 527457Sbmc * If we're here, we have both positive and negative bucket values. 528457Sbmc * To express this graphically, we're going to generate both positive 529457Sbmc * and negative bars separated by a centerline. These bars are half 530457Sbmc * the size of normal quantize()/lquantize() bars, so we divide the 531457Sbmc * length in half before calculating the bar length. 532457Sbmc */ 533457Sbmc len /= 2; 534457Sbmc ats = &ats[len]; 535457Sbmc spaces = &spaces[len]; 536457Sbmc 537457Sbmc f = (dt_fabsl((long double)val) * len) / total; 538457Sbmc depth = (uint_t)(f + 0.5); 539457Sbmc 540457Sbmc if (val <= 0) { 541457Sbmc return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth, 542457Sbmc ats + len - depth, len, "", (long long)val / normal)); 543457Sbmc } else { 544457Sbmc return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "", 545457Sbmc ats + len - depth, spaces + depth, 546457Sbmc (long long)val / normal)); 547457Sbmc } 548457Sbmc } 549457Sbmc 550457Sbmc int 5510Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 5520Sstevel@tonic-gate size_t size, uint64_t normal) 5530Sstevel@tonic-gate { 554457Sbmc const int64_t *data = addr; 5550Sstevel@tonic-gate int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 556457Sbmc long double total = 0; 557457Sbmc char positives = 0, negatives = 0; 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 5600Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 5630Sstevel@tonic-gate first_bin++; 5640Sstevel@tonic-gate 565457Sbmc if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) { 566457Sbmc /* 567457Sbmc * There isn't any data. This is possible if (and only if) 568457Sbmc * negative increment values have been used. In this case, 569457Sbmc * we'll print the buckets around 0. 570457Sbmc */ 571457Sbmc first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; 572457Sbmc last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; 573457Sbmc } else { 574457Sbmc if (first_bin > 0) 575457Sbmc first_bin--; 5760Sstevel@tonic-gate 577457Sbmc while (last_bin > 0 && data[last_bin] == 0) 578457Sbmc last_bin--; 5790Sstevel@tonic-gate 580457Sbmc if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 581457Sbmc last_bin++; 582457Sbmc } 583457Sbmc 584457Sbmc for (i = first_bin; i <= last_bin; i++) { 585457Sbmc positives |= (data[i] > 0); 586457Sbmc negatives |= (data[i] < 0); 587457Sbmc total += dt_fabsl((long double)data[i]); 588457Sbmc } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 5910Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 5920Sstevel@tonic-gate return (-1); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 595457Sbmc if (dt_printf(dtp, fp, "%16lld ", 596457Sbmc (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0) 597457Sbmc return (-1); 5980Sstevel@tonic-gate 599457Sbmc if (dt_print_quantline(dtp, fp, data[i], normal, total, 600457Sbmc positives, negatives) < 0) 6010Sstevel@tonic-gate return (-1); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate return (0); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate int 6080Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 6090Sstevel@tonic-gate size_t size, uint64_t normal) 6100Sstevel@tonic-gate { 611457Sbmc const int64_t *data = addr; 6120Sstevel@tonic-gate int i, first_bin, last_bin, base; 613457Sbmc uint64_t arg; 614457Sbmc long double total = 0; 6150Sstevel@tonic-gate uint16_t step, levels; 616457Sbmc char positives = 0, negatives = 0; 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (size < sizeof (uint64_t)) 6190Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate arg = *data++; 6220Sstevel@tonic-gate size -= sizeof (uint64_t); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate base = DTRACE_LQUANTIZE_BASE(arg); 6250Sstevel@tonic-gate step = DTRACE_LQUANTIZE_STEP(arg); 6260Sstevel@tonic-gate levels = DTRACE_LQUANTIZE_LEVELS(arg); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate first_bin = 0; 6290Sstevel@tonic-gate last_bin = levels + 1; 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (size != sizeof (uint64_t) * (levels + 2)) 6320Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 6330Sstevel@tonic-gate 634491Sbmc while (first_bin <= levels + 1 && data[first_bin] == 0) 6350Sstevel@tonic-gate first_bin++; 6360Sstevel@tonic-gate 637491Sbmc if (first_bin > levels + 1) { 638457Sbmc first_bin = 0; 639457Sbmc last_bin = 2; 640457Sbmc } else { 641457Sbmc if (first_bin > 0) 642457Sbmc first_bin--; 6430Sstevel@tonic-gate 644457Sbmc while (last_bin > 0 && data[last_bin] == 0) 645457Sbmc last_bin--; 6460Sstevel@tonic-gate 647457Sbmc if (last_bin < levels + 1) 648457Sbmc last_bin++; 649457Sbmc } 6500Sstevel@tonic-gate 651457Sbmc for (i = first_bin; i <= last_bin; i++) { 652457Sbmc positives |= (data[i] > 0); 653457Sbmc negatives |= (data[i] < 0); 654457Sbmc total += dt_fabsl((long double)data[i]); 655457Sbmc } 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 6580Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 6590Sstevel@tonic-gate return (-1); 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 6620Sstevel@tonic-gate char c[32]; 6630Sstevel@tonic-gate int err; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate if (i == 0) { 6660Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "< %d", 6670Sstevel@tonic-gate base / (uint32_t)normal); 6680Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 6690Sstevel@tonic-gate } else if (i == levels + 1) { 6700Sstevel@tonic-gate (void) snprintf(c, sizeof (c), ">= %d", 6710Sstevel@tonic-gate base + (levels * step)); 6720Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 6730Sstevel@tonic-gate } else { 6740Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16d ", 6750Sstevel@tonic-gate base + (i - 1) * step); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 678457Sbmc if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal, 679457Sbmc total, positives, negatives) < 0) 6800Sstevel@tonic-gate return (-1); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate return (0); 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate /*ARGSUSED*/ 6870Sstevel@tonic-gate static int 6880Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 6890Sstevel@tonic-gate size_t size, uint64_t normal) 6900Sstevel@tonic-gate { 6910Sstevel@tonic-gate /* LINTED - alignment */ 692*5984Sjhaslam int64_t *data = (int64_t *)addr; 693*5984Sjhaslam 694*5984Sjhaslam return (dt_printf(dtp, fp, " %16lld", data[0] ? 695*5984Sjhaslam (long long)(data[1] / (int64_t)normal / data[0]) : 0)); 696*5984Sjhaslam } 697*5984Sjhaslam 698*5984Sjhaslam /*ARGSUSED*/ 699*5984Sjhaslam static int 700*5984Sjhaslam dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 701*5984Sjhaslam size_t size, uint64_t normal) 702*5984Sjhaslam { 703*5984Sjhaslam /* LINTED - alignment */ 7040Sstevel@tonic-gate uint64_t *data = (uint64_t *)addr; 7050Sstevel@tonic-gate 706*5984Sjhaslam return (dt_printf(dtp, fp, " %16llu", data[0] ? 707*5984Sjhaslam (unsigned long long) dt_stddev(data, normal) : 0)); 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /*ARGSUSED*/ 7110Sstevel@tonic-gate int 7120Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 7130Sstevel@tonic-gate size_t nbytes, int width, int quiet) 7140Sstevel@tonic-gate { 7150Sstevel@tonic-gate /* 7160Sstevel@tonic-gate * If the byte stream is a series of printable characters, followed by 7170Sstevel@tonic-gate * a terminating byte, we print it out as a string. Otherwise, we 7180Sstevel@tonic-gate * assume that it's something else and just print the bytes. 7190Sstevel@tonic-gate */ 7200Sstevel@tonic-gate int i, j, margin = 5; 7210Sstevel@tonic-gate char *c = (char *)addr; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate if (nbytes == 0) 7240Sstevel@tonic-gate return (0); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 7270Sstevel@tonic-gate goto raw; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate for (i = 0; i < nbytes; i++) { 7300Sstevel@tonic-gate /* 7310Sstevel@tonic-gate * We define a "printable character" to be one for which 7320Sstevel@tonic-gate * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 7330Sstevel@tonic-gate * or a character which is either backspace or the bell. 7340Sstevel@tonic-gate * Backspace and the bell are regrettably special because 7350Sstevel@tonic-gate * they fail the first two tests -- and yet they are entirely 7360Sstevel@tonic-gate * printable. These are the only two control characters that 7370Sstevel@tonic-gate * have meaning for the terminal and for which isprint(3C) and 7380Sstevel@tonic-gate * isspace(3C) return 0. 7390Sstevel@tonic-gate */ 7400Sstevel@tonic-gate if (isprint(c[i]) || isspace(c[i]) || 7410Sstevel@tonic-gate c[i] == '\b' || c[i] == '\a') 7420Sstevel@tonic-gate continue; 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate if (c[i] == '\0' && i > 0) { 7450Sstevel@tonic-gate /* 7460Sstevel@tonic-gate * This looks like it might be a string. Before we 7470Sstevel@tonic-gate * assume that it is indeed a string, check the 7480Sstevel@tonic-gate * remainder of the byte range; if it contains 7490Sstevel@tonic-gate * additional non-nul characters, we'll assume that 7500Sstevel@tonic-gate * it's a binary stream that just happens to look like 7510Sstevel@tonic-gate * a string, and we'll print out the individual bytes. 7520Sstevel@tonic-gate */ 7530Sstevel@tonic-gate for (j = i + 1; j < nbytes; j++) { 7540Sstevel@tonic-gate if (c[j] != '\0') 7550Sstevel@tonic-gate break; 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate if (j != nbytes) 7590Sstevel@tonic-gate break; 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate if (quiet) 7620Sstevel@tonic-gate return (dt_printf(dtp, fp, "%s", c)); 7630Sstevel@tonic-gate else 7640Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, c)); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate break; 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate if (i == nbytes) { 7710Sstevel@tonic-gate /* 7720Sstevel@tonic-gate * The byte range is all printable characters, but there is 7730Sstevel@tonic-gate * no trailing nul byte. We'll assume that it's a string and 7740Sstevel@tonic-gate * print it as such. 7750Sstevel@tonic-gate */ 7760Sstevel@tonic-gate char *s = alloca(nbytes + 1); 7770Sstevel@tonic-gate bcopy(c, s, nbytes); 7780Sstevel@tonic-gate s[nbytes] = '\0'; 7790Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, s)); 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate raw: 7830Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 7840Sstevel@tonic-gate return (-1); 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate for (i = 0; i < 16; i++) 7870Sstevel@tonic-gate if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 7880Sstevel@tonic-gate return (-1); 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 7910Sstevel@tonic-gate return (-1); 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate for (i = 0; i < nbytes; i += 16) { 7950Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 7960Sstevel@tonic-gate return (-1); 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 7990Sstevel@tonic-gate if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 8000Sstevel@tonic-gate return (-1); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate while (j++ % 16) { 8040Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 8050Sstevel@tonic-gate return (-1); 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 8090Sstevel@tonic-gate return (-1); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 8120Sstevel@tonic-gate if (dt_printf(dtp, fp, "%c", 8130Sstevel@tonic-gate c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 8140Sstevel@tonic-gate return (-1); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 8180Sstevel@tonic-gate return (-1); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate return (0); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate int 8250Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 826457Sbmc caddr_t addr, int depth, int size) 8270Sstevel@tonic-gate { 8280Sstevel@tonic-gate dtrace_syminfo_t dts; 8290Sstevel@tonic-gate GElf_Sym sym; 8300Sstevel@tonic-gate int i, indent; 8310Sstevel@tonic-gate char c[PATH_MAX * 2]; 832457Sbmc uint64_t pc; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 8350Sstevel@tonic-gate return (-1); 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate if (format == NULL) 8380Sstevel@tonic-gate format = "%s"; 8390Sstevel@tonic-gate 8400Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 8410Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 8420Sstevel@tonic-gate else 8430Sstevel@tonic-gate indent = _dtrace_stkindent; 8440Sstevel@tonic-gate 845457Sbmc for (i = 0; i < depth; i++) { 846457Sbmc switch (size) { 847457Sbmc case sizeof (uint32_t): 848457Sbmc /* LINTED - alignment */ 849457Sbmc pc = *((uint32_t *)addr); 850457Sbmc break; 851457Sbmc 852457Sbmc case sizeof (uint64_t): 853457Sbmc /* LINTED - alignment */ 854457Sbmc pc = *((uint64_t *)addr); 855457Sbmc break; 856457Sbmc 857457Sbmc default: 858457Sbmc return (dt_set_errno(dtp, EDT_BADSTACKPC)); 859457Sbmc } 860457Sbmc 861457Sbmc if (pc == NULL) 862457Sbmc break; 863457Sbmc 864457Sbmc addr += size; 865457Sbmc 8660Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 8670Sstevel@tonic-gate return (-1); 8680Sstevel@tonic-gate 869457Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 870457Sbmc if (pc > sym.st_value) { 8710Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 8720Sstevel@tonic-gate dts.dts_object, dts.dts_name, 873457Sbmc pc - sym.st_value); 8740Sstevel@tonic-gate } else { 8750Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s", 8760Sstevel@tonic-gate dts.dts_object, dts.dts_name); 8770Sstevel@tonic-gate } 8780Sstevel@tonic-gate } else { 8790Sstevel@tonic-gate /* 8800Sstevel@tonic-gate * We'll repeat the lookup, but this time we'll specify 8810Sstevel@tonic-gate * a NULL GElf_Sym -- indicating that we're only 8820Sstevel@tonic-gate * interested in the containing module. 8830Sstevel@tonic-gate */ 884457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 8850Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 886457Sbmc dts.dts_object, pc); 8870Sstevel@tonic-gate } else { 888457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", pc); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate if (dt_printf(dtp, fp, format, c) < 0) 8930Sstevel@tonic-gate return (-1); 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 8960Sstevel@tonic-gate return (-1); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate return (0); 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate int 9030Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 9040Sstevel@tonic-gate caddr_t addr, uint64_t arg) 9050Sstevel@tonic-gate { 906457Sbmc /* LINTED - alignment */ 907457Sbmc uint64_t *pc = (uint64_t *)addr; 9080Sstevel@tonic-gate uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 9090Sstevel@tonic-gate uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 9100Sstevel@tonic-gate const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 9110Sstevel@tonic-gate const char *str = strsize ? strbase : NULL; 9120Sstevel@tonic-gate int err = 0; 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 9150Sstevel@tonic-gate struct ps_prochandle *P; 9160Sstevel@tonic-gate GElf_Sym sym; 9170Sstevel@tonic-gate int i, indent; 9180Sstevel@tonic-gate pid_t pid; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate if (depth == 0) 9210Sstevel@tonic-gate return (0); 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate pid = (pid_t)*pc++; 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 9260Sstevel@tonic-gate return (-1); 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate if (format == NULL) 9290Sstevel@tonic-gate format = "%s"; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 9320Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 9330Sstevel@tonic-gate else 9340Sstevel@tonic-gate indent = _dtrace_stkindent; 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate /* 9370Sstevel@tonic-gate * Ultimately, we need to add an entry point in the library vector for 9380Sstevel@tonic-gate * determining <symbol, offset> from <pid, address>. For now, if 9390Sstevel@tonic-gate * this is a vector open, we just print the raw address or string. 9400Sstevel@tonic-gate */ 9410Sstevel@tonic-gate if (dtp->dt_vector == NULL) 9420Sstevel@tonic-gate P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 9430Sstevel@tonic-gate else 9440Sstevel@tonic-gate P = NULL; 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate if (P != NULL) 9470Sstevel@tonic-gate dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate for (i = 0; i < depth && pc[i] != NULL; i++) { 950457Sbmc const prmap_t *map; 951457Sbmc 9520Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 9530Sstevel@tonic-gate break; 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate if (P != NULL && Plookup_by_addr(P, pc[i], 9560Sstevel@tonic-gate name, sizeof (name), &sym) == 0) { 9570Sstevel@tonic-gate (void) Pobjname(P, pc[i], objname, sizeof (objname)); 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate if (pc[i] > sym.st_value) { 9600Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 9610Sstevel@tonic-gate "%s`%s+0x%llx", dt_basename(objname), name, 9620Sstevel@tonic-gate (u_longlong_t)(pc[i] - sym.st_value)); 9630Sstevel@tonic-gate } else { 9640Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 9650Sstevel@tonic-gate "%s`%s", dt_basename(objname), name); 9660Sstevel@tonic-gate } 967491Sbmc } else if (str != NULL && str[0] != '\0' && str[0] != '@' && 968457Sbmc (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL || 969457Sbmc (map->pr_mflags & MA_WRITE)))) { 970457Sbmc /* 971457Sbmc * If the current string pointer in the string table 972457Sbmc * does not point to an empty string _and_ the program 973457Sbmc * counter falls in a writable region, we'll use the 974457Sbmc * string from the string table instead of the raw 975457Sbmc * address. This last condition is necessary because 976457Sbmc * some (broken) ustack helpers will return a string 977457Sbmc * even for a program counter that they can't 978457Sbmc * identify. If we have a string for a program 979457Sbmc * counter that falls in a segment that isn't 980457Sbmc * writable, we assume that we have fallen into this 981457Sbmc * case and we refuse to use the string. 982457Sbmc */ 9830Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s", str); 9840Sstevel@tonic-gate } else { 9850Sstevel@tonic-gate if (P != NULL && Pobjname(P, pc[i], objname, 9860Sstevel@tonic-gate sizeof (objname)) != NULL) { 9870Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 9880Sstevel@tonic-gate dt_basename(objname), (u_longlong_t)pc[i]); 9890Sstevel@tonic-gate } else { 9900Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "0x%llx", 9910Sstevel@tonic-gate (u_longlong_t)pc[i]); 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate } 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, format, c)) < 0) 9960Sstevel@tonic-gate break; 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "\n")) < 0) 9990Sstevel@tonic-gate break; 10000Sstevel@tonic-gate 1001491Sbmc if (str != NULL && str[0] == '@') { 1002491Sbmc /* 1003491Sbmc * If the first character of the string is an "at" sign, 1004491Sbmc * then the string is inferred to be an annotation -- 1005491Sbmc * and it is printed out beneath the frame and offset 1006491Sbmc * with brackets. 1007491Sbmc */ 1008491Sbmc if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 1009491Sbmc break; 1010491Sbmc 1011491Sbmc (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]); 1012491Sbmc 1013491Sbmc if ((err = dt_printf(dtp, fp, format, c)) < 0) 1014491Sbmc break; 1015491Sbmc 1016491Sbmc if ((err = dt_printf(dtp, fp, "\n")) < 0) 1017491Sbmc break; 1018491Sbmc } 1019491Sbmc 10200Sstevel@tonic-gate if (str != NULL) { 10210Sstevel@tonic-gate str += strlen(str) + 1; 10220Sstevel@tonic-gate if (str - strbase >= strsize) 10230Sstevel@tonic-gate str = NULL; 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate if (P != NULL) { 10280Sstevel@tonic-gate dt_proc_unlock(dtp, P); 10290Sstevel@tonic-gate dt_proc_release(dtp, P); 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate 10320Sstevel@tonic-gate return (err); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate 1035457Sbmc static int 1036457Sbmc dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act) 1037457Sbmc { 1038457Sbmc /* LINTED - alignment */ 1039457Sbmc uint64_t pid = ((uint64_t *)addr)[0]; 1040457Sbmc /* LINTED - alignment */ 1041457Sbmc uint64_t pc = ((uint64_t *)addr)[1]; 1042457Sbmc const char *format = " %-50s"; 1043457Sbmc char *s; 1044457Sbmc int n, len = 256; 1045457Sbmc 1046457Sbmc if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) { 1047457Sbmc struct ps_prochandle *P; 1048457Sbmc 1049457Sbmc if ((P = dt_proc_grab(dtp, pid, 1050457Sbmc PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) { 1051457Sbmc GElf_Sym sym; 1052457Sbmc 1053457Sbmc dt_proc_lock(dtp, P); 1054457Sbmc 1055457Sbmc if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0) 1056457Sbmc pc = sym.st_value; 1057457Sbmc 1058457Sbmc dt_proc_unlock(dtp, P); 1059457Sbmc dt_proc_release(dtp, P); 1060457Sbmc } 1061457Sbmc } 1062457Sbmc 1063457Sbmc do { 1064457Sbmc n = len; 1065457Sbmc s = alloca(n); 1066457Sbmc } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) >= n); 1067457Sbmc 1068457Sbmc return (dt_printf(dtp, fp, format, s)); 1069457Sbmc } 1070457Sbmc 1071457Sbmc int 1072457Sbmc dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1073457Sbmc { 1074457Sbmc /* LINTED - alignment */ 1075457Sbmc uint64_t pid = ((uint64_t *)addr)[0]; 1076457Sbmc /* LINTED - alignment */ 1077457Sbmc uint64_t pc = ((uint64_t *)addr)[1]; 1078457Sbmc int err = 0; 1079457Sbmc 1080457Sbmc char objname[PATH_MAX], c[PATH_MAX * 2]; 1081457Sbmc struct ps_prochandle *P; 1082457Sbmc 1083457Sbmc if (format == NULL) 1084457Sbmc format = " %-50s"; 1085457Sbmc 1086457Sbmc /* 1087457Sbmc * See the comment in dt_print_ustack() for the rationale for 1088457Sbmc * printing raw addresses in the vectored case. 1089457Sbmc */ 1090457Sbmc if (dtp->dt_vector == NULL) 1091457Sbmc P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1092457Sbmc else 1093457Sbmc P = NULL; 1094457Sbmc 1095457Sbmc if (P != NULL) 1096457Sbmc dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 1097457Sbmc 1098457Sbmc if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != NULL) { 1099457Sbmc (void) snprintf(c, sizeof (c), "%s", dt_basename(objname)); 1100457Sbmc } else { 1101457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1102457Sbmc } 1103457Sbmc 1104457Sbmc err = dt_printf(dtp, fp, format, c); 1105457Sbmc 1106457Sbmc if (P != NULL) { 1107457Sbmc dt_proc_unlock(dtp, P); 1108457Sbmc dt_proc_release(dtp, P); 1109457Sbmc } 1110457Sbmc 1111457Sbmc return (err); 1112457Sbmc } 1113457Sbmc 1114457Sbmc static int 1115457Sbmc dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1116457Sbmc { 1117457Sbmc /* LINTED - alignment */ 1118457Sbmc uint64_t pc = *((uint64_t *)addr); 1119457Sbmc dtrace_syminfo_t dts; 1120457Sbmc GElf_Sym sym; 1121457Sbmc char c[PATH_MAX * 2]; 1122457Sbmc 1123457Sbmc if (format == NULL) 1124457Sbmc format = " %-50s"; 1125457Sbmc 1126457Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1127457Sbmc (void) snprintf(c, sizeof (c), "%s`%s", 1128457Sbmc dts.dts_object, dts.dts_name); 1129457Sbmc } else { 1130457Sbmc /* 1131457Sbmc * We'll repeat the lookup, but this time we'll specify a 1132457Sbmc * NULL GElf_Sym -- indicating that we're only interested in 1133457Sbmc * the containing module. 1134457Sbmc */ 1135457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1136457Sbmc (void) snprintf(c, sizeof (c), "%s`0x%llx", 1137457Sbmc dts.dts_object, (u_longlong_t)pc); 1138457Sbmc } else { 1139457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", 1140457Sbmc (u_longlong_t)pc); 1141457Sbmc } 1142457Sbmc } 1143457Sbmc 1144457Sbmc if (dt_printf(dtp, fp, format, c) < 0) 1145457Sbmc return (-1); 1146457Sbmc 1147457Sbmc return (0); 1148457Sbmc } 1149457Sbmc 1150457Sbmc int 1151457Sbmc dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1152457Sbmc { 1153457Sbmc /* LINTED - alignment */ 1154457Sbmc uint64_t pc = *((uint64_t *)addr); 1155457Sbmc dtrace_syminfo_t dts; 1156457Sbmc char c[PATH_MAX * 2]; 1157457Sbmc 1158457Sbmc if (format == NULL) 1159457Sbmc format = " %-50s"; 1160457Sbmc 1161457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1162457Sbmc (void) snprintf(c, sizeof (c), "%s", dts.dts_object); 1163457Sbmc } else { 1164457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1165457Sbmc } 1166457Sbmc 1167457Sbmc if (dt_printf(dtp, fp, format, c) < 0) 1168457Sbmc return (-1); 1169457Sbmc 1170457Sbmc return (0); 1171457Sbmc } 1172457Sbmc 11730Sstevel@tonic-gate typedef struct dt_normal { 11740Sstevel@tonic-gate dtrace_aggvarid_t dtnd_id; 11750Sstevel@tonic-gate uint64_t dtnd_normal; 11760Sstevel@tonic-gate } dt_normal_t; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate static int 1179457Sbmc dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 11800Sstevel@tonic-gate { 11810Sstevel@tonic-gate dt_normal_t *normal = arg; 11820Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 11830Sstevel@tonic-gate dtrace_aggvarid_t id = normal->dtnd_id; 11840Sstevel@tonic-gate 11850Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 11860Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 11870Sstevel@tonic-gate 11881017Sbmc if (agg->dtagd_varid != id) 11890Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 11900Sstevel@tonic-gate 1191457Sbmc ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal; 11920Sstevel@tonic-gate return (DTRACE_AGGWALK_NORMALIZE); 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate static int 11960Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 11970Sstevel@tonic-gate { 11980Sstevel@tonic-gate dt_normal_t normal; 11990Sstevel@tonic-gate caddr_t addr; 12000Sstevel@tonic-gate 12010Sstevel@tonic-gate /* 12020Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 12030Sstevel@tonic-gate * normalization value. 12040Sstevel@tonic-gate */ 12050Sstevel@tonic-gate addr = base + rec->dtrd_offset; 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 12080Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 12090Sstevel@tonic-gate 12100Sstevel@tonic-gate /* LINTED - alignment */ 12110Sstevel@tonic-gate normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 12120Sstevel@tonic-gate rec++; 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 12150Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_NORMALIZE) 12180Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate addr = base + rec->dtrd_offset; 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate switch (rec->dtrd_size) { 12230Sstevel@tonic-gate case sizeof (uint64_t): 12240Sstevel@tonic-gate /* LINTED - alignment */ 12250Sstevel@tonic-gate normal.dtnd_normal = *((uint64_t *)addr); 12260Sstevel@tonic-gate break; 12270Sstevel@tonic-gate case sizeof (uint32_t): 12280Sstevel@tonic-gate /* LINTED - alignment */ 12290Sstevel@tonic-gate normal.dtnd_normal = *((uint32_t *)addr); 12300Sstevel@tonic-gate break; 12310Sstevel@tonic-gate case sizeof (uint16_t): 12320Sstevel@tonic-gate /* LINTED - alignment */ 12330Sstevel@tonic-gate normal.dtnd_normal = *((uint16_t *)addr); 12340Sstevel@tonic-gate break; 12350Sstevel@tonic-gate case sizeof (uint8_t): 12360Sstevel@tonic-gate normal.dtnd_normal = *((uint8_t *)addr); 12370Sstevel@tonic-gate break; 12380Sstevel@tonic-gate default: 12390Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate return (0); 12450Sstevel@tonic-gate } 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate static int 1248457Sbmc dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 12490Sstevel@tonic-gate { 12500Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 12510Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 12540Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 12550Sstevel@tonic-gate 12561017Sbmc if (agg->dtagd_varid != id) 12570Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate return (DTRACE_AGGWALK_DENORMALIZE); 12600Sstevel@tonic-gate } 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate static int 1263457Sbmc dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg) 12640Sstevel@tonic-gate { 12650Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 12660Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 12690Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 12700Sstevel@tonic-gate 12711017Sbmc if (agg->dtagd_varid != id) 12720Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate return (DTRACE_AGGWALK_CLEAR); 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate typedef struct dt_trunc { 12780Sstevel@tonic-gate dtrace_aggvarid_t dttd_id; 12790Sstevel@tonic-gate uint64_t dttd_remaining; 12800Sstevel@tonic-gate } dt_trunc_t; 12810Sstevel@tonic-gate 12820Sstevel@tonic-gate static int 1283457Sbmc dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg) 12840Sstevel@tonic-gate { 12850Sstevel@tonic-gate dt_trunc_t *trunc = arg; 12860Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 12870Sstevel@tonic-gate dtrace_aggvarid_t id = trunc->dttd_id; 12880Sstevel@tonic-gate 12890Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 12900Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 12910Sstevel@tonic-gate 12921017Sbmc if (agg->dtagd_varid != id) 12930Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate if (trunc->dttd_remaining == 0) 12960Sstevel@tonic-gate return (DTRACE_AGGWALK_REMOVE); 12970Sstevel@tonic-gate 12980Sstevel@tonic-gate trunc->dttd_remaining--; 12990Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 13000Sstevel@tonic-gate } 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate static int 13030Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 13040Sstevel@tonic-gate { 13050Sstevel@tonic-gate dt_trunc_t trunc; 13060Sstevel@tonic-gate caddr_t addr; 13070Sstevel@tonic-gate int64_t remaining; 13080Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 13090Sstevel@tonic-gate 13100Sstevel@tonic-gate /* 13110Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 13120Sstevel@tonic-gate * number of aggregation entries after which the aggregation is to be 13130Sstevel@tonic-gate * truncated. 13140Sstevel@tonic-gate */ 13150Sstevel@tonic-gate addr = base + rec->dtrd_offset; 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 13180Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate /* LINTED - alignment */ 13210Sstevel@tonic-gate trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 13220Sstevel@tonic-gate rec++; 13230Sstevel@tonic-gate 13240Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 13250Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_TRUNC) 13280Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate addr = base + rec->dtrd_offset; 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate switch (rec->dtrd_size) { 13330Sstevel@tonic-gate case sizeof (uint64_t): 13340Sstevel@tonic-gate /* LINTED - alignment */ 13350Sstevel@tonic-gate remaining = *((int64_t *)addr); 13360Sstevel@tonic-gate break; 13370Sstevel@tonic-gate case sizeof (uint32_t): 13380Sstevel@tonic-gate /* LINTED - alignment */ 13390Sstevel@tonic-gate remaining = *((int32_t *)addr); 13400Sstevel@tonic-gate break; 13410Sstevel@tonic-gate case sizeof (uint16_t): 13420Sstevel@tonic-gate /* LINTED - alignment */ 13430Sstevel@tonic-gate remaining = *((int16_t *)addr); 13440Sstevel@tonic-gate break; 13450Sstevel@tonic-gate case sizeof (uint8_t): 13460Sstevel@tonic-gate remaining = *((int8_t *)addr); 13470Sstevel@tonic-gate break; 13480Sstevel@tonic-gate default: 13490Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 13500Sstevel@tonic-gate } 13510Sstevel@tonic-gate 13520Sstevel@tonic-gate if (remaining < 0) { 13530Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted; 13540Sstevel@tonic-gate remaining = -remaining; 13550Sstevel@tonic-gate } else { 13560Sstevel@tonic-gate func = dtrace_aggregate_walk_valrevsorted; 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate assert(remaining >= 0); 13600Sstevel@tonic-gate trunc.dttd_remaining = remaining; 13610Sstevel@tonic-gate 13620Sstevel@tonic-gate (void) func(dtp, dt_trunc_agg, &trunc); 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate return (0); 13650Sstevel@tonic-gate } 13660Sstevel@tonic-gate 13671017Sbmc static int 13681017Sbmc dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, 13691017Sbmc caddr_t addr, size_t size, uint64_t normal) 13701017Sbmc { 13711017Sbmc int err; 13721017Sbmc dtrace_actkind_t act = rec->dtrd_action; 13731017Sbmc 13741017Sbmc switch (act) { 13751017Sbmc case DTRACEACT_STACK: 13761017Sbmc return (dt_print_stack(dtp, fp, NULL, addr, 13771017Sbmc rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg)); 13781017Sbmc 13791017Sbmc case DTRACEACT_USTACK: 13801017Sbmc case DTRACEACT_JSTACK: 13811017Sbmc return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg)); 13821017Sbmc 13831017Sbmc case DTRACEACT_USYM: 13841017Sbmc case DTRACEACT_UADDR: 13851017Sbmc return (dt_print_usym(dtp, fp, addr, act)); 13861017Sbmc 13871017Sbmc case DTRACEACT_UMOD: 13881017Sbmc return (dt_print_umod(dtp, fp, NULL, addr)); 13891017Sbmc 13901017Sbmc case DTRACEACT_SYM: 13911017Sbmc return (dt_print_sym(dtp, fp, NULL, addr)); 13921017Sbmc 13931017Sbmc case DTRACEACT_MOD: 13941017Sbmc return (dt_print_mod(dtp, fp, NULL, addr)); 13951017Sbmc 13961017Sbmc case DTRACEAGG_QUANTIZE: 13971017Sbmc return (dt_print_quantize(dtp, fp, addr, size, normal)); 13981017Sbmc 13991017Sbmc case DTRACEAGG_LQUANTIZE: 14001017Sbmc return (dt_print_lquantize(dtp, fp, addr, size, normal)); 14011017Sbmc 14021017Sbmc case DTRACEAGG_AVG: 14031017Sbmc return (dt_print_average(dtp, fp, addr, size, normal)); 14041017Sbmc 1405*5984Sjhaslam case DTRACEAGG_STDDEV: 1406*5984Sjhaslam return (dt_print_stddev(dtp, fp, addr, size, normal)); 1407*5984Sjhaslam 14081017Sbmc default: 14091017Sbmc break; 14101017Sbmc } 14111017Sbmc 14121017Sbmc switch (size) { 14131017Sbmc case sizeof (uint64_t): 14141017Sbmc err = dt_printf(dtp, fp, " %16lld", 14151017Sbmc /* LINTED - alignment */ 14161017Sbmc (long long)*((uint64_t *)addr) / normal); 14171017Sbmc break; 14181017Sbmc case sizeof (uint32_t): 14191017Sbmc /* LINTED - alignment */ 14201017Sbmc err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) / 14211017Sbmc (uint32_t)normal); 14221017Sbmc break; 14231017Sbmc case sizeof (uint16_t): 14241017Sbmc /* LINTED - alignment */ 14251017Sbmc err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) / 14261017Sbmc (uint32_t)normal); 14271017Sbmc break; 14281017Sbmc case sizeof (uint8_t): 14291017Sbmc err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) / 14301017Sbmc (uint32_t)normal); 14311017Sbmc break; 14321017Sbmc default: 14331017Sbmc err = dt_print_bytes(dtp, fp, addr, size, 50, 0); 14341017Sbmc break; 14351017Sbmc } 14361017Sbmc 14371017Sbmc return (err); 14381017Sbmc } 14391017Sbmc 14401017Sbmc int 14411017Sbmc dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 14421017Sbmc { 14431017Sbmc int i, aggact = 0; 14441017Sbmc dt_print_aggdata_t *pd = arg; 14451017Sbmc const dtrace_aggdata_t *aggdata = aggsdata[0]; 14461017Sbmc dtrace_aggdesc_t *agg = aggdata->dtada_desc; 14471017Sbmc FILE *fp = pd->dtpa_fp; 14481017Sbmc dtrace_hdl_t *dtp = pd->dtpa_dtp; 14491017Sbmc dtrace_recdesc_t *rec; 14501017Sbmc dtrace_actkind_t act; 14511017Sbmc caddr_t addr; 14521017Sbmc size_t size; 14531017Sbmc 14541017Sbmc /* 14551017Sbmc * Iterate over each record description in the key, printing the traced 14561017Sbmc * data, skipping the first datum (the tuple member created by the 14571017Sbmc * compiler). 14581017Sbmc */ 14591017Sbmc for (i = 1; i < agg->dtagd_nrecs; i++) { 14601017Sbmc rec = &agg->dtagd_rec[i]; 14611017Sbmc act = rec->dtrd_action; 14621017Sbmc addr = aggdata->dtada_data + rec->dtrd_offset; 14631017Sbmc size = rec->dtrd_size; 14641017Sbmc 14651017Sbmc if (DTRACEACT_ISAGG(act)) { 14661017Sbmc aggact = i; 14671017Sbmc break; 14681017Sbmc } 14691017Sbmc 14701017Sbmc if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0) 14711017Sbmc return (-1); 14721017Sbmc 14731017Sbmc if (dt_buffered_flush(dtp, NULL, rec, aggdata, 14741017Sbmc DTRACE_BUFDATA_AGGKEY) < 0) 14751017Sbmc return (-1); 14761017Sbmc } 14771017Sbmc 14781017Sbmc assert(aggact != 0); 14791017Sbmc 14801017Sbmc for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) { 14811017Sbmc uint64_t normal; 14821017Sbmc 14831017Sbmc aggdata = aggsdata[i]; 14841017Sbmc agg = aggdata->dtada_desc; 14851017Sbmc rec = &agg->dtagd_rec[aggact]; 14861017Sbmc act = rec->dtrd_action; 14871017Sbmc addr = aggdata->dtada_data + rec->dtrd_offset; 14881017Sbmc size = rec->dtrd_size; 14891017Sbmc 14901017Sbmc assert(DTRACEACT_ISAGG(act)); 14911017Sbmc normal = aggdata->dtada_normal; 14921017Sbmc 14931017Sbmc if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0) 14941017Sbmc return (-1); 14951017Sbmc 14961017Sbmc if (dt_buffered_flush(dtp, NULL, rec, aggdata, 14971017Sbmc DTRACE_BUFDATA_AGGVAL) < 0) 14981017Sbmc return (-1); 14991017Sbmc 15001017Sbmc if (!pd->dtpa_allunprint) 15011017Sbmc agg->dtagd_flags |= DTRACE_AGD_PRINTED; 15021017Sbmc } 15031017Sbmc 15041017Sbmc if (dt_printf(dtp, fp, "\n") < 0) 15051017Sbmc return (-1); 15061017Sbmc 15071017Sbmc if (dt_buffered_flush(dtp, NULL, NULL, aggdata, 15081017Sbmc DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) 15091017Sbmc return (-1); 15101017Sbmc 15111017Sbmc return (0); 15121017Sbmc } 15131017Sbmc 15140Sstevel@tonic-gate int 1515457Sbmc dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg) 15160Sstevel@tonic-gate { 15170Sstevel@tonic-gate dt_print_aggdata_t *pd = arg; 15180Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 15190Sstevel@tonic-gate dtrace_aggvarid_t aggvarid = pd->dtpa_id; 15200Sstevel@tonic-gate 15210Sstevel@tonic-gate if (pd->dtpa_allunprint) { 15220Sstevel@tonic-gate if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 15230Sstevel@tonic-gate return (0); 15240Sstevel@tonic-gate } else { 15250Sstevel@tonic-gate /* 15260Sstevel@tonic-gate * If we're not printing all unprinted aggregations, then the 15270Sstevel@tonic-gate * aggregation variable ID denotes a specific aggregation 15280Sstevel@tonic-gate * variable that we should print -- skip any other aggregations 15290Sstevel@tonic-gate * that we encounter. 15300Sstevel@tonic-gate */ 15310Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 15320Sstevel@tonic-gate return (0); 15330Sstevel@tonic-gate 15341017Sbmc if (aggvarid != agg->dtagd_varid) 15350Sstevel@tonic-gate return (0); 15360Sstevel@tonic-gate } 15370Sstevel@tonic-gate 15381017Sbmc return (dt_print_aggs(&aggdata, 1, arg)); 15390Sstevel@tonic-gate } 15400Sstevel@tonic-gate 1541457Sbmc int 1542457Sbmc dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 1543457Sbmc const char *option, const char *value) 1544457Sbmc { 1545457Sbmc int len, rval; 1546457Sbmc char *msg; 1547457Sbmc const char *errstr; 1548457Sbmc dtrace_setoptdata_t optdata; 1549457Sbmc 1550457Sbmc bzero(&optdata, sizeof (optdata)); 1551457Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval); 1552457Sbmc 1553457Sbmc if (dtrace_setopt(dtp, option, value) == 0) { 1554457Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval); 1555457Sbmc optdata.dtsda_probe = data; 1556457Sbmc optdata.dtsda_option = option; 1557457Sbmc optdata.dtsda_handle = dtp; 1558457Sbmc 1559457Sbmc if ((rval = dt_handle_setopt(dtp, &optdata)) != 0) 1560457Sbmc return (rval); 1561457Sbmc 1562457Sbmc return (0); 1563457Sbmc } 1564457Sbmc 1565457Sbmc errstr = dtrace_errmsg(dtp, dtrace_errno(dtp)); 1566457Sbmc len = strlen(option) + strlen(value) + strlen(errstr) + 80; 1567457Sbmc msg = alloca(len); 1568457Sbmc 1569457Sbmc (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n", 1570457Sbmc option, value, errstr); 1571457Sbmc 1572457Sbmc if ((rval = dt_handle_liberr(dtp, data, msg)) == 0) 1573457Sbmc return (0); 1574457Sbmc 1575457Sbmc return (rval); 1576457Sbmc } 1577457Sbmc 15780Sstevel@tonic-gate static int 15790Sstevel@tonic-gate dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf, 15800Sstevel@tonic-gate dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 15810Sstevel@tonic-gate { 15820Sstevel@tonic-gate dtrace_epid_t id; 15830Sstevel@tonic-gate size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size; 15840Sstevel@tonic-gate int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 15850Sstevel@tonic-gate int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 15860Sstevel@tonic-gate int rval, i, n; 15870Sstevel@tonic-gate dtrace_epid_t last = DTRACE_EPIDNONE; 15880Sstevel@tonic-gate dtrace_probedata_t data; 15890Sstevel@tonic-gate uint64_t drops; 15900Sstevel@tonic-gate caddr_t addr; 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate bzero(&data, sizeof (data)); 15930Sstevel@tonic-gate data.dtpda_handle = dtp; 15940Sstevel@tonic-gate data.dtpda_cpu = cpu; 15950Sstevel@tonic-gate 15960Sstevel@tonic-gate again: 15970Sstevel@tonic-gate for (offs = start; offs < end; ) { 15980Sstevel@tonic-gate dtrace_eprobedesc_t *epd; 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate /* 16010Sstevel@tonic-gate * We're guaranteed to have an ID. 16020Sstevel@tonic-gate */ 16030Sstevel@tonic-gate id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate if (id == DTRACE_EPIDNONE) { 16060Sstevel@tonic-gate /* 16070Sstevel@tonic-gate * This is filler to assure proper alignment of the 16080Sstevel@tonic-gate * next record; we simply ignore it. 16090Sstevel@tonic-gate */ 16100Sstevel@tonic-gate offs += sizeof (id); 16110Sstevel@tonic-gate continue; 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 16150Sstevel@tonic-gate &data.dtpda_pdesc)) != 0) 16160Sstevel@tonic-gate return (rval); 16170Sstevel@tonic-gate 16180Sstevel@tonic-gate epd = data.dtpda_edesc; 16190Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs; 16200Sstevel@tonic-gate 16210Sstevel@tonic-gate if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 16220Sstevel@tonic-gate rval = dt_handle(dtp, &data); 16230Sstevel@tonic-gate 16240Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 16250Sstevel@tonic-gate goto nextepid; 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ERROR) 16280Sstevel@tonic-gate return (-1); 16290Sstevel@tonic-gate } 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate if (flow) 16320Sstevel@tonic-gate (void) dt_flowindent(dtp, &data, last, buf, offs); 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate rval = (*efunc)(&data, arg); 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate if (flow) { 16370Sstevel@tonic-gate if (data.dtpda_flow == DTRACEFLOW_ENTRY) 16380Sstevel@tonic-gate data.dtpda_indent += 2; 16390Sstevel@tonic-gate } 16400Sstevel@tonic-gate 16410Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 16420Sstevel@tonic-gate goto nextepid; 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 16450Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 16480Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate for (i = 0; i < epd->dtepd_nrecs; i++) { 16510Sstevel@tonic-gate dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 16520Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 16530Sstevel@tonic-gate 16540Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs + 16550Sstevel@tonic-gate rec->dtrd_offset; 16560Sstevel@tonic-gate addr = data.dtpda_data; 16570Sstevel@tonic-gate 16580Sstevel@tonic-gate if (act == DTRACEACT_LIBACT) { 1659457Sbmc uint64_t arg = rec->dtrd_arg; 1660457Sbmc dtrace_aggvarid_t id; 16610Sstevel@tonic-gate 1662457Sbmc switch (arg) { 1663457Sbmc case DT_ACT_CLEAR: 16640Sstevel@tonic-gate /* LINTED - alignment */ 16650Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 16660Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 16670Sstevel@tonic-gate dt_clear_agg, &id); 16680Sstevel@tonic-gate continue; 16690Sstevel@tonic-gate 1670457Sbmc case DT_ACT_DENORMALIZE: 16710Sstevel@tonic-gate /* LINTED - alignment */ 16720Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 16730Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 16740Sstevel@tonic-gate dt_denormalize_agg, &id); 16750Sstevel@tonic-gate continue; 1676457Sbmc 1677457Sbmc case DT_ACT_FTRUNCATE: 1678457Sbmc if (fp == NULL) 1679457Sbmc continue; 16800Sstevel@tonic-gate 1681457Sbmc (void) fflush(fp); 1682457Sbmc (void) ftruncate(fileno(fp), 0); 1683457Sbmc (void) fseeko(fp, 0, SEEK_SET); 1684457Sbmc continue; 1685457Sbmc 1686457Sbmc case DT_ACT_NORMALIZE: 16870Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 16880Sstevel@tonic-gate return (dt_set_errno(dtp, 16890Sstevel@tonic-gate EDT_BADNORMAL)); 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate if (dt_normalize(dtp, 16920Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 16930Sstevel@tonic-gate return (-1); 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate i++; 16960Sstevel@tonic-gate continue; 1697457Sbmc 1698457Sbmc case DT_ACT_SETOPT: { 1699457Sbmc uint64_t *opts = dtp->dt_options; 1700457Sbmc dtrace_recdesc_t *valrec; 1701457Sbmc uint32_t valsize; 1702457Sbmc caddr_t val; 1703457Sbmc int rv; 1704457Sbmc 1705457Sbmc if (i == epd->dtepd_nrecs - 1) { 1706457Sbmc return (dt_set_errno(dtp, 1707457Sbmc EDT_BADSETOPT)); 1708457Sbmc } 1709457Sbmc 1710457Sbmc valrec = &epd->dtepd_rec[++i]; 1711457Sbmc valsize = valrec->dtrd_size; 1712457Sbmc 1713457Sbmc if (valrec->dtrd_action != act || 1714457Sbmc valrec->dtrd_arg != arg) { 1715457Sbmc return (dt_set_errno(dtp, 1716457Sbmc EDT_BADSETOPT)); 1717457Sbmc } 1718457Sbmc 1719457Sbmc if (valsize > sizeof (uint64_t)) { 1720457Sbmc val = buf->dtbd_data + offs + 1721457Sbmc valrec->dtrd_offset; 1722457Sbmc } else { 1723457Sbmc val = "1"; 1724457Sbmc } 1725457Sbmc 1726457Sbmc rv = dt_setopt(dtp, &data, addr, val); 1727457Sbmc 1728457Sbmc if (rv != 0) 1729457Sbmc return (-1); 1730457Sbmc 1731457Sbmc flow = (opts[DTRACEOPT_FLOWINDENT] != 1732457Sbmc DTRACEOPT_UNSET); 1733457Sbmc quiet = (opts[DTRACEOPT_QUIET] != 1734457Sbmc DTRACEOPT_UNSET); 1735457Sbmc 1736457Sbmc continue; 17370Sstevel@tonic-gate } 17380Sstevel@tonic-gate 1739457Sbmc case DT_ACT_TRUNC: 17400Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 17410Sstevel@tonic-gate return (dt_set_errno(dtp, 17420Sstevel@tonic-gate EDT_BADTRUNC)); 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate if (dt_trunc(dtp, 17450Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 17460Sstevel@tonic-gate return (-1); 17470Sstevel@tonic-gate 17480Sstevel@tonic-gate i++; 17490Sstevel@tonic-gate continue; 17500Sstevel@tonic-gate 1751457Sbmc default: 17520Sstevel@tonic-gate continue; 17530Sstevel@tonic-gate } 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate rval = (*rfunc)(&data, rec, arg); 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 17590Sstevel@tonic-gate continue; 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 17620Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 17650Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 17660Sstevel@tonic-gate 17670Sstevel@tonic-gate if (act == DTRACEACT_STACK) { 1768457Sbmc int depth = rec->dtrd_arg; 1769457Sbmc 1770457Sbmc if (dt_print_stack(dtp, fp, NULL, addr, depth, 1771457Sbmc rec->dtrd_size / depth) < 0) 17720Sstevel@tonic-gate return (-1); 17730Sstevel@tonic-gate goto nextrec; 17740Sstevel@tonic-gate } 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate if (act == DTRACEACT_USTACK || 17770Sstevel@tonic-gate act == DTRACEACT_JSTACK) { 17780Sstevel@tonic-gate if (dt_print_ustack(dtp, fp, NULL, 17790Sstevel@tonic-gate addr, rec->dtrd_arg) < 0) 17800Sstevel@tonic-gate return (-1); 17810Sstevel@tonic-gate goto nextrec; 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate 1784457Sbmc if (act == DTRACEACT_SYM) { 1785457Sbmc if (dt_print_sym(dtp, fp, NULL, addr) < 0) 1786457Sbmc return (-1); 1787457Sbmc goto nextrec; 1788457Sbmc } 1789457Sbmc 1790457Sbmc if (act == DTRACEACT_MOD) { 1791457Sbmc if (dt_print_mod(dtp, fp, NULL, addr) < 0) 1792457Sbmc return (-1); 1793457Sbmc goto nextrec; 1794457Sbmc } 1795457Sbmc 1796457Sbmc if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 1797457Sbmc if (dt_print_usym(dtp, fp, addr, act) < 0) 1798457Sbmc return (-1); 1799457Sbmc goto nextrec; 1800457Sbmc } 1801457Sbmc 1802457Sbmc if (act == DTRACEACT_UMOD) { 1803457Sbmc if (dt_print_umod(dtp, fp, NULL, addr) < 0) 1804457Sbmc return (-1); 1805457Sbmc goto nextrec; 1806457Sbmc } 1807457Sbmc 18080Sstevel@tonic-gate if (DTRACEACT_ISPRINTFLIKE(act)) { 18090Sstevel@tonic-gate void *fmtdata; 18100Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, FILE *, void *, 18110Sstevel@tonic-gate const dtrace_probedata_t *, 18120Sstevel@tonic-gate const dtrace_recdesc_t *, uint_t, 18130Sstevel@tonic-gate const void *buf, size_t); 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate if ((fmtdata = dt_format_lookup(dtp, 18160Sstevel@tonic-gate rec->dtrd_format)) == NULL) 18170Sstevel@tonic-gate goto nofmt; 18180Sstevel@tonic-gate 18190Sstevel@tonic-gate switch (act) { 18200Sstevel@tonic-gate case DTRACEACT_PRINTF: 18210Sstevel@tonic-gate func = dtrace_fprintf; 18220Sstevel@tonic-gate break; 18230Sstevel@tonic-gate case DTRACEACT_PRINTA: 18240Sstevel@tonic-gate func = dtrace_fprinta; 18250Sstevel@tonic-gate break; 18260Sstevel@tonic-gate case DTRACEACT_SYSTEM: 18270Sstevel@tonic-gate func = dtrace_system; 18280Sstevel@tonic-gate break; 18290Sstevel@tonic-gate case DTRACEACT_FREOPEN: 18300Sstevel@tonic-gate func = dtrace_freopen; 18310Sstevel@tonic-gate break; 18320Sstevel@tonic-gate } 18330Sstevel@tonic-gate 18340Sstevel@tonic-gate n = (*func)(dtp, fp, fmtdata, &data, 18350Sstevel@tonic-gate rec, epd->dtepd_nrecs - i, 18360Sstevel@tonic-gate (uchar_t *)buf->dtbd_data + offs, 18370Sstevel@tonic-gate buf->dtbd_size - offs); 18380Sstevel@tonic-gate 18390Sstevel@tonic-gate if (n < 0) 18400Sstevel@tonic-gate return (-1); /* errno is set for us */ 18410Sstevel@tonic-gate 18420Sstevel@tonic-gate if (n > 0) 18430Sstevel@tonic-gate i += n - 1; 18440Sstevel@tonic-gate goto nextrec; 18450Sstevel@tonic-gate } 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate nofmt: 18480Sstevel@tonic-gate if (act == DTRACEACT_PRINTA) { 18490Sstevel@tonic-gate dt_print_aggdata_t pd; 18501017Sbmc dtrace_aggvarid_t *aggvars; 18511017Sbmc int j, naggvars = 0; 18521017Sbmc size_t size = ((epd->dtepd_nrecs - i) * 18531017Sbmc sizeof (dtrace_aggvarid_t)); 18540Sstevel@tonic-gate 18551017Sbmc if ((aggvars = dt_alloc(dtp, size)) == NULL) 18561017Sbmc return (-1); 18571017Sbmc 18581017Sbmc /* 18591017Sbmc * This might be a printa() with multiple 18601017Sbmc * aggregation variables. We need to scan 18611017Sbmc * forward through the records until we find 18621017Sbmc * a record from a different statement. 18631017Sbmc */ 18641017Sbmc for (j = i; j < epd->dtepd_nrecs; j++) { 18651017Sbmc dtrace_recdesc_t *nrec; 18661017Sbmc caddr_t naddr; 18671017Sbmc 18681017Sbmc nrec = &epd->dtepd_rec[j]; 18691017Sbmc 18701017Sbmc if (nrec->dtrd_uarg != rec->dtrd_uarg) 18711017Sbmc break; 18721017Sbmc 18731017Sbmc if (nrec->dtrd_action != act) { 18741017Sbmc return (dt_set_errno(dtp, 18751017Sbmc EDT_BADAGG)); 18761017Sbmc } 18771017Sbmc 18781017Sbmc naddr = buf->dtbd_data + offs + 18791017Sbmc nrec->dtrd_offset; 18801017Sbmc 18811017Sbmc aggvars[naggvars++] = 18821017Sbmc /* LINTED - alignment */ 18831017Sbmc *((dtrace_aggvarid_t *)naddr); 18841017Sbmc } 18851017Sbmc 18861017Sbmc i = j - 1; 18870Sstevel@tonic-gate bzero(&pd, sizeof (pd)); 18880Sstevel@tonic-gate pd.dtpa_dtp = dtp; 18890Sstevel@tonic-gate pd.dtpa_fp = fp; 18901017Sbmc 18911017Sbmc assert(naggvars >= 1); 18921017Sbmc 18931017Sbmc if (naggvars == 1) { 18941017Sbmc pd.dtpa_id = aggvars[0]; 18951017Sbmc dt_free(dtp, aggvars); 18961017Sbmc 18971017Sbmc if (dt_printf(dtp, fp, "\n") < 0 || 18981017Sbmc dtrace_aggregate_walk_sorted(dtp, 18991017Sbmc dt_print_agg, &pd) < 0) 19001017Sbmc return (-1); 19011017Sbmc goto nextrec; 19021017Sbmc } 19030Sstevel@tonic-gate 19040Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0 || 19051017Sbmc dtrace_aggregate_walk_joined(dtp, aggvars, 19061017Sbmc naggvars, dt_print_aggs, &pd) < 0) { 19071017Sbmc dt_free(dtp, aggvars); 19080Sstevel@tonic-gate return (-1); 19091017Sbmc } 19100Sstevel@tonic-gate 19111017Sbmc dt_free(dtp, aggvars); 19120Sstevel@tonic-gate goto nextrec; 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate 19150Sstevel@tonic-gate switch (rec->dtrd_size) { 19160Sstevel@tonic-gate case sizeof (uint64_t): 19170Sstevel@tonic-gate n = dt_printf(dtp, fp, 19180Sstevel@tonic-gate quiet ? "%lld" : " %16lld", 19190Sstevel@tonic-gate /* LINTED - alignment */ 19200Sstevel@tonic-gate *((unsigned long long *)addr)); 19210Sstevel@tonic-gate break; 19220Sstevel@tonic-gate case sizeof (uint32_t): 19230Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 19240Sstevel@tonic-gate /* LINTED - alignment */ 19250Sstevel@tonic-gate *((uint32_t *)addr)); 19260Sstevel@tonic-gate break; 19270Sstevel@tonic-gate case sizeof (uint16_t): 19280Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 19290Sstevel@tonic-gate /* LINTED - alignment */ 19300Sstevel@tonic-gate *((uint16_t *)addr)); 19310Sstevel@tonic-gate break; 19320Sstevel@tonic-gate case sizeof (uint8_t): 19330Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 19340Sstevel@tonic-gate *((uint8_t *)addr)); 19350Sstevel@tonic-gate break; 19360Sstevel@tonic-gate default: 19370Sstevel@tonic-gate n = dt_print_bytes(dtp, fp, addr, 19380Sstevel@tonic-gate rec->dtrd_size, 33, quiet); 19390Sstevel@tonic-gate break; 19400Sstevel@tonic-gate } 19410Sstevel@tonic-gate 19420Sstevel@tonic-gate if (n < 0) 19430Sstevel@tonic-gate return (-1); /* errno is set for us */ 19440Sstevel@tonic-gate 19450Sstevel@tonic-gate nextrec: 19461017Sbmc if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0) 19470Sstevel@tonic-gate return (-1); /* errno is set for us */ 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate /* 19510Sstevel@tonic-gate * Call the record callback with a NULL record to indicate 19520Sstevel@tonic-gate * that we're done processing this EPID. 19530Sstevel@tonic-gate */ 19540Sstevel@tonic-gate rval = (*rfunc)(&data, NULL, arg); 19550Sstevel@tonic-gate nextepid: 19560Sstevel@tonic-gate offs += epd->dtepd_size; 19570Sstevel@tonic-gate last = id; 19580Sstevel@tonic-gate } 19590Sstevel@tonic-gate 19600Sstevel@tonic-gate if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) { 19610Sstevel@tonic-gate end = buf->dtbd_oldest; 19620Sstevel@tonic-gate start = 0; 19630Sstevel@tonic-gate goto again; 19640Sstevel@tonic-gate } 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate if ((drops = buf->dtbd_drops) == 0) 19670Sstevel@tonic-gate return (0); 19680Sstevel@tonic-gate 19690Sstevel@tonic-gate /* 19700Sstevel@tonic-gate * Explicitly zero the drops to prevent us from processing them again. 19710Sstevel@tonic-gate */ 19720Sstevel@tonic-gate buf->dtbd_drops = 0; 19730Sstevel@tonic-gate 19740Sstevel@tonic-gate return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate 19770Sstevel@tonic-gate typedef struct dt_begin { 19780Sstevel@tonic-gate dtrace_consume_probe_f *dtbgn_probefunc; 19790Sstevel@tonic-gate dtrace_consume_rec_f *dtbgn_recfunc; 19800Sstevel@tonic-gate void *dtbgn_arg; 19810Sstevel@tonic-gate dtrace_handle_err_f *dtbgn_errhdlr; 19820Sstevel@tonic-gate void *dtbgn_errarg; 19830Sstevel@tonic-gate int dtbgn_beginonly; 19840Sstevel@tonic-gate } dt_begin_t; 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate static int 19870Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 19880Sstevel@tonic-gate { 19890Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 19900Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc; 19910Sstevel@tonic-gate 19920Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 19930Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 19940Sstevel@tonic-gate 19950Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 19960Sstevel@tonic-gate if (!(r1 && r2)) 19970Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 19980Sstevel@tonic-gate } else { 19990Sstevel@tonic-gate if (r1 && r2) 20000Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 20010Sstevel@tonic-gate } 20020Sstevel@tonic-gate 20030Sstevel@tonic-gate /* 20040Sstevel@tonic-gate * We have a record that we're interested in. Now call the underlying 20050Sstevel@tonic-gate * probe function... 20060Sstevel@tonic-gate */ 20070Sstevel@tonic-gate return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 20080Sstevel@tonic-gate } 20090Sstevel@tonic-gate 20100Sstevel@tonic-gate static int 20110Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data, 20120Sstevel@tonic-gate const dtrace_recdesc_t *rec, void *arg) 20130Sstevel@tonic-gate { 20140Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 20150Sstevel@tonic-gate 20160Sstevel@tonic-gate return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 20170Sstevel@tonic-gate } 20180Sstevel@tonic-gate 20190Sstevel@tonic-gate static int 2020457Sbmc dt_consume_begin_error(const dtrace_errdata_t *data, void *arg) 20210Sstevel@tonic-gate { 20220Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 20230Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dteda_pdesc; 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 20260Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 20290Sstevel@tonic-gate if (!(r1 && r2)) 20300Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 20310Sstevel@tonic-gate } else { 20320Sstevel@tonic-gate if (r1 && r2) 20330Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate static int 20400Sstevel@tonic-gate dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf, 20410Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 20420Sstevel@tonic-gate { 20430Sstevel@tonic-gate /* 20440Sstevel@tonic-gate * There's this idea that the BEGIN probe should be processed before 20450Sstevel@tonic-gate * everything else, and that the END probe should be processed after 20460Sstevel@tonic-gate * anything else. In the common case, this is pretty easy to deal 20470Sstevel@tonic-gate * with. However, a situation may arise where the BEGIN enabling and 20480Sstevel@tonic-gate * END enabling are on the same CPU, and some enabling in the middle 20490Sstevel@tonic-gate * occurred on a different CPU. To deal with this (blech!) we need to 20500Sstevel@tonic-gate * consume the BEGIN buffer up until the end of the BEGIN probe, and 20510Sstevel@tonic-gate * then set it aside. We will then process every other CPU, and then 20520Sstevel@tonic-gate * we'll return to the BEGIN CPU and process the rest of the data 20530Sstevel@tonic-gate * (which will inevitably include the END probe, if any). Making this 20540Sstevel@tonic-gate * even more complicated (!) is the library's ERROR enabling. Because 20550Sstevel@tonic-gate * this enabling is processed before we even get into the consume call 20560Sstevel@tonic-gate * back, any ERROR firing would result in the library's ERROR enabling 20570Sstevel@tonic-gate * being processed twice -- once in our first pass (for BEGIN probes), 20580Sstevel@tonic-gate * and again in our second pass (for everything but BEGIN probes). To 20590Sstevel@tonic-gate * deal with this, we interpose on the ERROR handler to assure that we 20600Sstevel@tonic-gate * only process ERROR enablings induced by BEGIN enablings in the 20610Sstevel@tonic-gate * first pass, and that we only process ERROR enablings _not_ induced 20620Sstevel@tonic-gate * by BEGIN enablings in the second pass. 20630Sstevel@tonic-gate */ 20640Sstevel@tonic-gate dt_begin_t begin; 20650Sstevel@tonic-gate processorid_t cpu = dtp->dt_beganon; 20660Sstevel@tonic-gate dtrace_bufdesc_t nbuf; 20670Sstevel@tonic-gate int rval, i; 20680Sstevel@tonic-gate static int max_ncpus; 20690Sstevel@tonic-gate dtrace_optval_t size; 20700Sstevel@tonic-gate 20710Sstevel@tonic-gate dtp->dt_beganon = -1; 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 20740Sstevel@tonic-gate /* 20750Sstevel@tonic-gate * We really don't expect this to fail, but it is at least 20760Sstevel@tonic-gate * technically possible for this to fail with ENOENT. In this 20770Sstevel@tonic-gate * case, we just drive on... 20780Sstevel@tonic-gate */ 20790Sstevel@tonic-gate if (errno == ENOENT) 20800Sstevel@tonic-gate return (0); 20810Sstevel@tonic-gate 20820Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 20860Sstevel@tonic-gate /* 20870Sstevel@tonic-gate * This is the simple case. We're either not stopped, or if 20880Sstevel@tonic-gate * we are, we actually processed any END probes on another 20890Sstevel@tonic-gate * CPU. We can simply consume this buffer and return. 20900Sstevel@tonic-gate */ 20910Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg)); 20920Sstevel@tonic-gate } 20930Sstevel@tonic-gate 20940Sstevel@tonic-gate begin.dtbgn_probefunc = pf; 20950Sstevel@tonic-gate begin.dtbgn_recfunc = rf; 20960Sstevel@tonic-gate begin.dtbgn_arg = arg; 20970Sstevel@tonic-gate begin.dtbgn_beginonly = 1; 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate /* 21000Sstevel@tonic-gate * We need to interpose on the ERROR handler to be sure that we 21010Sstevel@tonic-gate * only process ERRORs induced by BEGIN. 21020Sstevel@tonic-gate */ 21030Sstevel@tonic-gate begin.dtbgn_errhdlr = dtp->dt_errhdlr; 21040Sstevel@tonic-gate begin.dtbgn_errarg = dtp->dt_errarg; 21050Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 21060Sstevel@tonic-gate dtp->dt_errarg = &begin; 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, 21090Sstevel@tonic-gate dt_consume_begin_record, &begin); 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 21120Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate if (rval != 0) 21150Sstevel@tonic-gate return (rval); 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate /* 21180Sstevel@tonic-gate * Now allocate a new buffer. We'll use this to deal with every other 21190Sstevel@tonic-gate * CPU. 21200Sstevel@tonic-gate */ 21210Sstevel@tonic-gate bzero(&nbuf, sizeof (dtrace_bufdesc_t)); 21220Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size); 21230Sstevel@tonic-gate if ((nbuf.dtbd_data = malloc(size)) == NULL) 21240Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 21250Sstevel@tonic-gate 21260Sstevel@tonic-gate if (max_ncpus == 0) 21270Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 21280Sstevel@tonic-gate 21290Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 21300Sstevel@tonic-gate nbuf.dtbd_cpu = i; 21310Sstevel@tonic-gate 21320Sstevel@tonic-gate if (i == cpu) 21330Sstevel@tonic-gate continue; 21340Sstevel@tonic-gate 21350Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) { 21360Sstevel@tonic-gate /* 21370Sstevel@tonic-gate * If we failed with ENOENT, it may be because the 21380Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other 21390Sstevel@tonic-gate * error, however, is unexpected. 21400Sstevel@tonic-gate */ 21410Sstevel@tonic-gate if (errno == ENOENT) 21420Sstevel@tonic-gate continue; 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate free(nbuf.dtbd_data); 21450Sstevel@tonic-gate 21460Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 21470Sstevel@tonic-gate } 21480Sstevel@tonic-gate 21490Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, 21500Sstevel@tonic-gate i, &nbuf, pf, rf, arg)) != 0) { 21510Sstevel@tonic-gate free(nbuf.dtbd_data); 21520Sstevel@tonic-gate return (rval); 21530Sstevel@tonic-gate } 21540Sstevel@tonic-gate } 21550Sstevel@tonic-gate 21560Sstevel@tonic-gate free(nbuf.dtbd_data); 21570Sstevel@tonic-gate 21580Sstevel@tonic-gate /* 21590Sstevel@tonic-gate * Okay -- we're done with the other buffers. Now we want to 21600Sstevel@tonic-gate * reconsume the first buffer -- but this time we're looking for 21610Sstevel@tonic-gate * everything _but_ BEGIN. And of course, in order to only consume 21620Sstevel@tonic-gate * those ERRORs _not_ associated with BEGIN, we need to reinstall our 21630Sstevel@tonic-gate * ERROR interposition function... 21640Sstevel@tonic-gate */ 21650Sstevel@tonic-gate begin.dtbgn_beginonly = 0; 21660Sstevel@tonic-gate 21670Sstevel@tonic-gate assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 21680Sstevel@tonic-gate assert(begin.dtbgn_errarg == dtp->dt_errarg); 21690Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 21700Sstevel@tonic-gate dtp->dt_errarg = &begin; 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe, 21730Sstevel@tonic-gate dt_consume_begin_record, &begin); 21740Sstevel@tonic-gate 21750Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 21760Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate return (rval); 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate int 21820Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 21830Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 21840Sstevel@tonic-gate { 21850Sstevel@tonic-gate dtrace_bufdesc_t *buf = &dtp->dt_buf; 21860Sstevel@tonic-gate dtrace_optval_t size; 21870Sstevel@tonic-gate static int max_ncpus; 21880Sstevel@tonic-gate int i, rval; 21890Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 21900Sstevel@tonic-gate hrtime_t now = gethrtime(); 21910Sstevel@tonic-gate 21920Sstevel@tonic-gate if (dtp->dt_lastswitch != 0) { 21930Sstevel@tonic-gate if (now - dtp->dt_lastswitch < interval) 21940Sstevel@tonic-gate return (0); 21950Sstevel@tonic-gate 21960Sstevel@tonic-gate dtp->dt_lastswitch += interval; 21970Sstevel@tonic-gate } else { 21980Sstevel@tonic-gate dtp->dt_lastswitch = now; 21990Sstevel@tonic-gate } 22000Sstevel@tonic-gate 22010Sstevel@tonic-gate if (!dtp->dt_active) 22020Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 22030Sstevel@tonic-gate 22040Sstevel@tonic-gate if (max_ncpus == 0) 22050Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 22060Sstevel@tonic-gate 22070Sstevel@tonic-gate if (pf == NULL) 22080Sstevel@tonic-gate pf = (dtrace_consume_probe_f *)dt_nullprobe; 22090Sstevel@tonic-gate 22100Sstevel@tonic-gate if (rf == NULL) 22110Sstevel@tonic-gate rf = (dtrace_consume_rec_f *)dt_nullrec; 22120Sstevel@tonic-gate 22130Sstevel@tonic-gate if (buf->dtbd_data == NULL) { 22140Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size); 22150Sstevel@tonic-gate if ((buf->dtbd_data = malloc(size)) == NULL) 22160Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 22170Sstevel@tonic-gate 22180Sstevel@tonic-gate buf->dtbd_size = size; 22190Sstevel@tonic-gate } 22200Sstevel@tonic-gate 22210Sstevel@tonic-gate /* 22220Sstevel@tonic-gate * If we have just begun, we want to first process the CPU that 22230Sstevel@tonic-gate * executed the BEGIN probe (if any). 22240Sstevel@tonic-gate */ 22250Sstevel@tonic-gate if (dtp->dt_active && dtp->dt_beganon != -1) { 22260Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_beganon; 22270Sstevel@tonic-gate if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0) 22280Sstevel@tonic-gate return (rval); 22290Sstevel@tonic-gate } 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 22320Sstevel@tonic-gate buf->dtbd_cpu = i; 22330Sstevel@tonic-gate 22340Sstevel@tonic-gate /* 22350Sstevel@tonic-gate * If we have stopped, we want to process the CPU on which the 22360Sstevel@tonic-gate * END probe was processed only _after_ we have processed 22370Sstevel@tonic-gate * everything else. 22380Sstevel@tonic-gate */ 22390Sstevel@tonic-gate if (dtp->dt_stopped && (i == dtp->dt_endedon)) 22400Sstevel@tonic-gate continue; 22410Sstevel@tonic-gate 22420Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 22430Sstevel@tonic-gate /* 22440Sstevel@tonic-gate * If we failed with ENOENT, it may be because the 22450Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other 22460Sstevel@tonic-gate * error, however, is unexpected. 22470Sstevel@tonic-gate */ 22480Sstevel@tonic-gate if (errno == ENOENT) 22490Sstevel@tonic-gate continue; 22500Sstevel@tonic-gate 22510Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 22520Sstevel@tonic-gate } 22530Sstevel@tonic-gate 22540Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0) 22550Sstevel@tonic-gate return (rval); 22560Sstevel@tonic-gate } 22570Sstevel@tonic-gate 22580Sstevel@tonic-gate if (!dtp->dt_stopped) 22590Sstevel@tonic-gate return (0); 22600Sstevel@tonic-gate 22610Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_endedon; 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 22640Sstevel@tonic-gate /* 22650Sstevel@tonic-gate * This _really_ shouldn't fail, but it is strictly speaking 22660Sstevel@tonic-gate * possible for this to return ENOENT if the CPU that called 22670Sstevel@tonic-gate * the END enabling somehow managed to become unconfigured. 22680Sstevel@tonic-gate * It's unclear how the user can possibly expect anything 22690Sstevel@tonic-gate * rational to happen in this case -- the state has been thrown 22700Sstevel@tonic-gate * out along with the unconfigured CPU -- so we'll just drive 22710Sstevel@tonic-gate * on... 22720Sstevel@tonic-gate */ 22730Sstevel@tonic-gate if (errno == ENOENT) 22740Sstevel@tonic-gate return (0); 22750Sstevel@tonic-gate 22760Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 22770Sstevel@tonic-gate } 22780Sstevel@tonic-gate 22790Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg)); 22800Sstevel@tonic-gate } 2281