17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 56e0bee74Sjhaslam * Common Development and Distribution License (the "License"). 66e0bee74Sjhaslam * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2296400bb6SJonathan Haslam * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 262b6389efSBryan Cantrill /* 2733093f5bSBryan Cantrill * Copyright (c) 2013, Joyent, Inc. All rights reserved. 28e5803b76SAdam H. Leventhal * Copyright (c) 2012 by Delphix. All rights reserved. 292b6389efSBryan Cantrill */ 302b6389efSBryan Cantrill 317c478bd9Sstevel@tonic-gate #include <stdlib.h> 327c478bd9Sstevel@tonic-gate #include <strings.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <limits.h> 367c478bd9Sstevel@tonic-gate #include <assert.h> 377c478bd9Sstevel@tonic-gate #include <ctype.h> 387c478bd9Sstevel@tonic-gate #include <alloca.h> 397c478bd9Sstevel@tonic-gate #include <dt_impl.h> 40e5803b76SAdam H. Leventhal #include <dt_pq.h> 417c478bd9Sstevel@tonic-gate 426e0bee74Sjhaslam #define DT_MASK_LO 0x00000000FFFFFFFFULL 436e0bee74Sjhaslam 44a1b5e537Sbmc /* 45a1b5e537Sbmc * We declare this here because (1) we need it and (2) we want to avoid a 46a1b5e537Sbmc * dependency on libm in libdtrace. 47a1b5e537Sbmc */ 48a1b5e537Sbmc static long double 49a1b5e537Sbmc dt_fabsl(long double x) 50a1b5e537Sbmc { 51a1b5e537Sbmc if (x < 0) 52a1b5e537Sbmc return (-x); 53a1b5e537Sbmc 54a1b5e537Sbmc return (x); 55a1b5e537Sbmc } 56a1b5e537Sbmc 5733093f5bSBryan Cantrill static int 5833093f5bSBryan Cantrill dt_ndigits(long long val) 5933093f5bSBryan Cantrill { 6033093f5bSBryan Cantrill int rval = 1; 6133093f5bSBryan Cantrill long long cmp = 10; 6233093f5bSBryan Cantrill 6333093f5bSBryan Cantrill if (val < 0) { 6433093f5bSBryan Cantrill val = val == INT64_MIN ? INT64_MAX : -val; 6533093f5bSBryan Cantrill rval++; 6633093f5bSBryan Cantrill } 6733093f5bSBryan Cantrill 6833093f5bSBryan Cantrill while (val > cmp && cmp > 0) { 6933093f5bSBryan Cantrill rval++; 7033093f5bSBryan Cantrill cmp *= 10; 7133093f5bSBryan Cantrill } 7233093f5bSBryan Cantrill 7333093f5bSBryan Cantrill return (rval < 4 ? 4 : rval); 7433093f5bSBryan Cantrill } 7533093f5bSBryan Cantrill 766e0bee74Sjhaslam /* 776e0bee74Sjhaslam * 128-bit arithmetic functions needed to support the stddev() aggregating 786e0bee74Sjhaslam * action. 796e0bee74Sjhaslam */ 806e0bee74Sjhaslam static int 816e0bee74Sjhaslam dt_gt_128(uint64_t *a, uint64_t *b) 826e0bee74Sjhaslam { 836e0bee74Sjhaslam return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0])); 846e0bee74Sjhaslam } 856e0bee74Sjhaslam 866e0bee74Sjhaslam static int 876e0bee74Sjhaslam dt_ge_128(uint64_t *a, uint64_t *b) 886e0bee74Sjhaslam { 896e0bee74Sjhaslam return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0])); 906e0bee74Sjhaslam } 916e0bee74Sjhaslam 926e0bee74Sjhaslam static int 936e0bee74Sjhaslam dt_le_128(uint64_t *a, uint64_t *b) 946e0bee74Sjhaslam { 956e0bee74Sjhaslam return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0])); 966e0bee74Sjhaslam } 976e0bee74Sjhaslam 986e0bee74Sjhaslam /* 996e0bee74Sjhaslam * Shift the 128-bit value in a by b. If b is positive, shift left. 1006e0bee74Sjhaslam * If b is negative, shift right. 1016e0bee74Sjhaslam */ 1026e0bee74Sjhaslam static void 1036e0bee74Sjhaslam dt_shift_128(uint64_t *a, int b) 1046e0bee74Sjhaslam { 1056e0bee74Sjhaslam uint64_t mask; 1066e0bee74Sjhaslam 1076e0bee74Sjhaslam if (b == 0) 1086e0bee74Sjhaslam return; 1096e0bee74Sjhaslam 1106e0bee74Sjhaslam if (b < 0) { 1116e0bee74Sjhaslam b = -b; 1126e0bee74Sjhaslam if (b >= 64) { 1136e0bee74Sjhaslam a[0] = a[1] >> (b - 64); 1146e0bee74Sjhaslam a[1] = 0; 1156e0bee74Sjhaslam } else { 1166e0bee74Sjhaslam a[0] >>= b; 1176e0bee74Sjhaslam mask = 1LL << (64 - b); 1186e0bee74Sjhaslam mask -= 1; 1196e0bee74Sjhaslam a[0] |= ((a[1] & mask) << (64 - b)); 1206e0bee74Sjhaslam a[1] >>= b; 1216e0bee74Sjhaslam } 1226e0bee74Sjhaslam } else { 1236e0bee74Sjhaslam if (b >= 64) { 1246e0bee74Sjhaslam a[1] = a[0] << (b - 64); 1256e0bee74Sjhaslam a[0] = 0; 1266e0bee74Sjhaslam } else { 1276e0bee74Sjhaslam a[1] <<= b; 1286e0bee74Sjhaslam mask = a[0] >> (64 - b); 1296e0bee74Sjhaslam a[1] |= mask; 1306e0bee74Sjhaslam a[0] <<= b; 1316e0bee74Sjhaslam } 1326e0bee74Sjhaslam } 1336e0bee74Sjhaslam } 1346e0bee74Sjhaslam 1356e0bee74Sjhaslam static int 1366e0bee74Sjhaslam dt_nbits_128(uint64_t *a) 1376e0bee74Sjhaslam { 1386e0bee74Sjhaslam int nbits = 0; 1396e0bee74Sjhaslam uint64_t tmp[2]; 1406e0bee74Sjhaslam uint64_t zero[2] = { 0, 0 }; 1416e0bee74Sjhaslam 1426e0bee74Sjhaslam tmp[0] = a[0]; 1436e0bee74Sjhaslam tmp[1] = a[1]; 1446e0bee74Sjhaslam 1456e0bee74Sjhaslam dt_shift_128(tmp, -1); 1466e0bee74Sjhaslam while (dt_gt_128(tmp, zero)) { 1476e0bee74Sjhaslam dt_shift_128(tmp, -1); 1486e0bee74Sjhaslam nbits++; 1496e0bee74Sjhaslam } 1506e0bee74Sjhaslam 1516e0bee74Sjhaslam return (nbits); 1526e0bee74Sjhaslam } 1536e0bee74Sjhaslam 1546e0bee74Sjhaslam static void 1556e0bee74Sjhaslam dt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference) 1566e0bee74Sjhaslam { 1576e0bee74Sjhaslam uint64_t result[2]; 1586e0bee74Sjhaslam 1596e0bee74Sjhaslam result[0] = minuend[0] - subtrahend[0]; 1606e0bee74Sjhaslam result[1] = minuend[1] - subtrahend[1] - 1616e0bee74Sjhaslam (minuend[0] < subtrahend[0] ? 1 : 0); 1626e0bee74Sjhaslam 1636e0bee74Sjhaslam difference[0] = result[0]; 1646e0bee74Sjhaslam difference[1] = result[1]; 1656e0bee74Sjhaslam } 1666e0bee74Sjhaslam 1676e0bee74Sjhaslam static void 1686e0bee74Sjhaslam dt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) 1696e0bee74Sjhaslam { 1706e0bee74Sjhaslam uint64_t result[2]; 1716e0bee74Sjhaslam 1726e0bee74Sjhaslam result[0] = addend1[0] + addend2[0]; 1736e0bee74Sjhaslam result[1] = addend1[1] + addend2[1] + 1746e0bee74Sjhaslam (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); 1756e0bee74Sjhaslam 1766e0bee74Sjhaslam sum[0] = result[0]; 1776e0bee74Sjhaslam sum[1] = result[1]; 1786e0bee74Sjhaslam } 1796e0bee74Sjhaslam 1806e0bee74Sjhaslam /* 1816e0bee74Sjhaslam * The basic idea is to break the 2 64-bit values into 4 32-bit values, 1826e0bee74Sjhaslam * use native multiplication on those, and then re-combine into the 1836e0bee74Sjhaslam * resulting 128-bit value. 1846e0bee74Sjhaslam * 1856e0bee74Sjhaslam * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) = 1866e0bee74Sjhaslam * hi1 * hi2 << 64 + 1876e0bee74Sjhaslam * hi1 * lo2 << 32 + 1886e0bee74Sjhaslam * hi2 * lo1 << 32 + 1896e0bee74Sjhaslam * lo1 * lo2 1906e0bee74Sjhaslam */ 1916e0bee74Sjhaslam static void 1926e0bee74Sjhaslam dt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product) 1936e0bee74Sjhaslam { 1946e0bee74Sjhaslam uint64_t hi1, hi2, lo1, lo2; 1956e0bee74Sjhaslam uint64_t tmp[2]; 1966e0bee74Sjhaslam 1976e0bee74Sjhaslam hi1 = factor1 >> 32; 1986e0bee74Sjhaslam hi2 = factor2 >> 32; 1996e0bee74Sjhaslam 2006e0bee74Sjhaslam lo1 = factor1 & DT_MASK_LO; 2016e0bee74Sjhaslam lo2 = factor2 & DT_MASK_LO; 2026e0bee74Sjhaslam 2036e0bee74Sjhaslam product[0] = lo1 * lo2; 2046e0bee74Sjhaslam product[1] = hi1 * hi2; 2056e0bee74Sjhaslam 2066e0bee74Sjhaslam tmp[0] = hi1 * lo2; 2076e0bee74Sjhaslam tmp[1] = 0; 2086e0bee74Sjhaslam dt_shift_128(tmp, 32); 2096e0bee74Sjhaslam dt_add_128(product, tmp, product); 2106e0bee74Sjhaslam 2116e0bee74Sjhaslam tmp[0] = hi2 * lo1; 2126e0bee74Sjhaslam tmp[1] = 0; 2136e0bee74Sjhaslam dt_shift_128(tmp, 32); 2146e0bee74Sjhaslam dt_add_128(product, tmp, product); 2156e0bee74Sjhaslam } 2166e0bee74Sjhaslam 2176e0bee74Sjhaslam /* 2186e0bee74Sjhaslam * This is long-hand division. 2196e0bee74Sjhaslam * 2206e0bee74Sjhaslam * We initialize subtrahend by shifting divisor left as far as possible. We 2216e0bee74Sjhaslam * loop, comparing subtrahend to dividend: if subtrahend is smaller, we 2226e0bee74Sjhaslam * subtract and set the appropriate bit in the result. We then shift 2236e0bee74Sjhaslam * subtrahend right by one bit for the next comparison. 2246e0bee74Sjhaslam */ 2256e0bee74Sjhaslam static void 2266e0bee74Sjhaslam dt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient) 2276e0bee74Sjhaslam { 2286e0bee74Sjhaslam uint64_t result[2] = { 0, 0 }; 2296e0bee74Sjhaslam uint64_t remainder[2]; 2306e0bee74Sjhaslam uint64_t subtrahend[2]; 2316e0bee74Sjhaslam uint64_t divisor_128[2]; 2326e0bee74Sjhaslam uint64_t mask[2] = { 1, 0 }; 2336e0bee74Sjhaslam int log = 0; 2346e0bee74Sjhaslam 2356e0bee74Sjhaslam assert(divisor != 0); 2366e0bee74Sjhaslam 2376e0bee74Sjhaslam divisor_128[0] = divisor; 2386e0bee74Sjhaslam divisor_128[1] = 0; 2396e0bee74Sjhaslam 2406e0bee74Sjhaslam remainder[0] = dividend[0]; 2416e0bee74Sjhaslam remainder[1] = dividend[1]; 2426e0bee74Sjhaslam 2436e0bee74Sjhaslam subtrahend[0] = divisor; 2446e0bee74Sjhaslam subtrahend[1] = 0; 2456e0bee74Sjhaslam 2466e0bee74Sjhaslam while (divisor > 0) { 2476e0bee74Sjhaslam log++; 2486e0bee74Sjhaslam divisor >>= 1; 2496e0bee74Sjhaslam } 2506e0bee74Sjhaslam 2516e0bee74Sjhaslam dt_shift_128(subtrahend, 128 - log); 2526e0bee74Sjhaslam dt_shift_128(mask, 128 - log); 2536e0bee74Sjhaslam 2546e0bee74Sjhaslam while (dt_ge_128(remainder, divisor_128)) { 2556e0bee74Sjhaslam if (dt_ge_128(remainder, subtrahend)) { 2566e0bee74Sjhaslam dt_subtract_128(remainder, subtrahend, remainder); 2576e0bee74Sjhaslam result[0] |= mask[0]; 2586e0bee74Sjhaslam result[1] |= mask[1]; 2596e0bee74Sjhaslam } 2606e0bee74Sjhaslam 2616e0bee74Sjhaslam dt_shift_128(subtrahend, -1); 2626e0bee74Sjhaslam dt_shift_128(mask, -1); 2636e0bee74Sjhaslam } 2646e0bee74Sjhaslam 2656e0bee74Sjhaslam quotient[0] = result[0]; 2666e0bee74Sjhaslam quotient[1] = result[1]; 2676e0bee74Sjhaslam } 2686e0bee74Sjhaslam 2696e0bee74Sjhaslam /* 2706e0bee74Sjhaslam * This is the long-hand method of calculating a square root. 2716e0bee74Sjhaslam * The algorithm is as follows: 2726e0bee74Sjhaslam * 2736e0bee74Sjhaslam * 1. Group the digits by 2 from the right. 2746e0bee74Sjhaslam * 2. Over the leftmost group, find the largest single-digit number 2756e0bee74Sjhaslam * whose square is less than that group. 2766e0bee74Sjhaslam * 3. Subtract the result of the previous step (2 or 4, depending) and 2776e0bee74Sjhaslam * bring down the next two-digit group. 2786e0bee74Sjhaslam * 4. For the result R we have so far, find the largest single-digit number 2796e0bee74Sjhaslam * x such that 2 * R * 10 * x + x^2 is less than the result from step 3. 2806e0bee74Sjhaslam * (Note that this is doubling R and performing a decimal left-shift by 1 2816e0bee74Sjhaslam * and searching for the appropriate decimal to fill the one's place.) 2826e0bee74Sjhaslam * The value x is the next digit in the square root. 2836e0bee74Sjhaslam * Repeat steps 3 and 4 until the desired precision is reached. (We're 2846e0bee74Sjhaslam * dealing with integers, so the above is sufficient.) 2856e0bee74Sjhaslam * 2866e0bee74Sjhaslam * In decimal, the square root of 582,734 would be calculated as so: 2876e0bee74Sjhaslam * 2886e0bee74Sjhaslam * __7__6__3 2896e0bee74Sjhaslam * | 58 27 34 2906e0bee74Sjhaslam * -49 (7^2 == 49 => 7 is the first digit in the square root) 2916e0bee74Sjhaslam * -- 2926e0bee74Sjhaslam * 9 27 (Subtract and bring down the next group.) 2936e0bee74Sjhaslam * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in 2946e0bee74Sjhaslam * ----- the square root) 2956e0bee74Sjhaslam * 51 34 (Subtract and bring down the next group.) 2966e0bee74Sjhaslam * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in 2976e0bee74Sjhaslam * ----- the square root) 2986e0bee74Sjhaslam * 5 65 (remainder) 2996e0bee74Sjhaslam * 3006e0bee74Sjhaslam * The above algorithm applies similarly in binary, but note that the 3016e0bee74Sjhaslam * only possible non-zero value for x in step 4 is 1, so step 4 becomes a 3026e0bee74Sjhaslam * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the 3036e0bee74Sjhaslam * preceding difference? 3046e0bee74Sjhaslam * 3056e0bee74Sjhaslam * In binary, the square root of 11011011 would be calculated as so: 3066e0bee74Sjhaslam * 3076e0bee74Sjhaslam * __1__1__1__0 3086e0bee74Sjhaslam * | 11 01 10 11 3096e0bee74Sjhaslam * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1) 3106e0bee74Sjhaslam * -- 3116e0bee74Sjhaslam * 10 01 10 11 3126e0bee74Sjhaslam * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1) 3136e0bee74Sjhaslam * ----- 3146e0bee74Sjhaslam * 1 00 10 11 3156e0bee74Sjhaslam * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1) 3166e0bee74Sjhaslam * ------- 3176e0bee74Sjhaslam * 1 01 11 3186e0bee74Sjhaslam * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0) 3196e0bee74Sjhaslam * 3206e0bee74Sjhaslam */ 3216e0bee74Sjhaslam static uint64_t 3226e0bee74Sjhaslam dt_sqrt_128(uint64_t *square) 3236e0bee74Sjhaslam { 3246e0bee74Sjhaslam uint64_t result[2] = { 0, 0 }; 3256e0bee74Sjhaslam uint64_t diff[2] = { 0, 0 }; 3266e0bee74Sjhaslam uint64_t one[2] = { 1, 0 }; 3276e0bee74Sjhaslam uint64_t next_pair[2]; 3286e0bee74Sjhaslam uint64_t next_try[2]; 3296e0bee74Sjhaslam uint64_t bit_pairs, pair_shift; 3306e0bee74Sjhaslam int i; 3316e0bee74Sjhaslam 3326e0bee74Sjhaslam bit_pairs = dt_nbits_128(square) / 2; 3336e0bee74Sjhaslam pair_shift = bit_pairs * 2; 3346e0bee74Sjhaslam 3356e0bee74Sjhaslam for (i = 0; i <= bit_pairs; i++) { 3366e0bee74Sjhaslam /* 3376e0bee74Sjhaslam * Bring down the next pair of bits. 3386e0bee74Sjhaslam */ 3396e0bee74Sjhaslam next_pair[0] = square[0]; 3406e0bee74Sjhaslam next_pair[1] = square[1]; 3416e0bee74Sjhaslam dt_shift_128(next_pair, -pair_shift); 3426e0bee74Sjhaslam next_pair[0] &= 0x3; 3436e0bee74Sjhaslam next_pair[1] = 0; 3446e0bee74Sjhaslam 3456e0bee74Sjhaslam dt_shift_128(diff, 2); 3466e0bee74Sjhaslam dt_add_128(diff, next_pair, diff); 3476e0bee74Sjhaslam 3486e0bee74Sjhaslam /* 3496e0bee74Sjhaslam * next_try = R << 2 + 1 3506e0bee74Sjhaslam */ 3516e0bee74Sjhaslam next_try[0] = result[0]; 3526e0bee74Sjhaslam next_try[1] = result[1]; 3536e0bee74Sjhaslam dt_shift_128(next_try, 2); 3546e0bee74Sjhaslam dt_add_128(next_try, one, next_try); 3556e0bee74Sjhaslam 3566e0bee74Sjhaslam if (dt_le_128(next_try, diff)) { 3576e0bee74Sjhaslam dt_subtract_128(diff, next_try, diff); 3586e0bee74Sjhaslam dt_shift_128(result, 1); 3596e0bee74Sjhaslam dt_add_128(result, one, result); 3606e0bee74Sjhaslam } else { 3616e0bee74Sjhaslam dt_shift_128(result, 1); 3626e0bee74Sjhaslam } 3636e0bee74Sjhaslam 3646e0bee74Sjhaslam pair_shift -= 2; 3656e0bee74Sjhaslam } 3666e0bee74Sjhaslam 3676e0bee74Sjhaslam assert(result[1] == 0); 3686e0bee74Sjhaslam 3696e0bee74Sjhaslam return (result[0]); 3706e0bee74Sjhaslam } 3716e0bee74Sjhaslam 3726e0bee74Sjhaslam uint64_t 3736e0bee74Sjhaslam dt_stddev(uint64_t *data, uint64_t normal) 3746e0bee74Sjhaslam { 3756e0bee74Sjhaslam uint64_t avg_of_squares[2]; 3766e0bee74Sjhaslam uint64_t square_of_avg[2]; 3776e0bee74Sjhaslam int64_t norm_avg; 3786e0bee74Sjhaslam uint64_t diff[2]; 3796e0bee74Sjhaslam 3806e0bee74Sjhaslam /* 3816e0bee74Sjhaslam * The standard approximation for standard deviation is 3826e0bee74Sjhaslam * sqrt(average(x**2) - average(x)**2), i.e. the square root 3836e0bee74Sjhaslam * of the average of the squares minus the square of the average. 3846e0bee74Sjhaslam */ 3856e0bee74Sjhaslam dt_divide_128(data + 2, normal, avg_of_squares); 3866e0bee74Sjhaslam dt_divide_128(avg_of_squares, data[0], avg_of_squares); 3876e0bee74Sjhaslam 3886e0bee74Sjhaslam norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0]; 3896e0bee74Sjhaslam 3906e0bee74Sjhaslam if (norm_avg < 0) 3916e0bee74Sjhaslam norm_avg = -norm_avg; 3926e0bee74Sjhaslam 3936e0bee74Sjhaslam dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg); 3946e0bee74Sjhaslam 3956e0bee74Sjhaslam dt_subtract_128(avg_of_squares, square_of_avg, diff); 3966e0bee74Sjhaslam 3976e0bee74Sjhaslam return (dt_sqrt_128(diff)); 3986e0bee74Sjhaslam } 3996e0bee74Sjhaslam 4007c478bd9Sstevel@tonic-gate static int 4017c478bd9Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last, 4027c478bd9Sstevel@tonic-gate dtrace_bufdesc_t *buf, size_t offs) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd; 4057c478bd9Sstevel@tonic-gate dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd; 406a1b5e537Sbmc char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub; 4077c478bd9Sstevel@tonic-gate dtrace_flowkind_t flow = DTRACEFLOW_NONE; 4087c478bd9Sstevel@tonic-gate const char *str = NULL; 4097c478bd9Sstevel@tonic-gate static const char *e_str[2] = { " -> ", " => " }; 4107c478bd9Sstevel@tonic-gate static const char *r_str[2] = { " <- ", " <= " }; 411a1b5e537Sbmc static const char *ent = "entry", *ret = "return"; 412a1b5e537Sbmc static int entlen = 0, retlen = 0; 4137c478bd9Sstevel@tonic-gate dtrace_epid_t next, id = epd->dtepd_epid; 4147c478bd9Sstevel@tonic-gate int rval; 4157c478bd9Sstevel@tonic-gate 416a1b5e537Sbmc if (entlen == 0) { 417a1b5e537Sbmc assert(retlen == 0); 418a1b5e537Sbmc entlen = strlen(ent); 419a1b5e537Sbmc retlen = strlen(ret); 420a1b5e537Sbmc } 421a1b5e537Sbmc 422a1b5e537Sbmc /* 423a1b5e537Sbmc * If the name of the probe is "entry" or ends with "-entry", we 424a1b5e537Sbmc * treat it as an entry; if it is "return" or ends with "-return", 425a1b5e537Sbmc * we treat it as a return. (This allows application-provided probes 426a1b5e537Sbmc * like "method-entry" or "function-entry" to participate in flow 427a1b5e537Sbmc * indentation -- without accidentally misinterpreting popular probe 428a1b5e537Sbmc * names like "carpentry", "gentry" or "Coventry".) 429a1b5e537Sbmc */ 430a1b5e537Sbmc if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' && 431a1b5e537Sbmc (sub == n || sub[-1] == '-')) { 4327c478bd9Sstevel@tonic-gate flow = DTRACEFLOW_ENTRY; 4337c478bd9Sstevel@tonic-gate str = e_str[strcmp(p, "syscall") == 0]; 434a1b5e537Sbmc } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' && 435a1b5e537Sbmc (sub == n || sub[-1] == '-')) { 4367c478bd9Sstevel@tonic-gate flow = DTRACEFLOW_RETURN; 4377c478bd9Sstevel@tonic-gate str = r_str[strcmp(p, "syscall") == 0]; 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * If we're going to indent this, we need to check the ID of our last 4427c478bd9Sstevel@tonic-gate * call. If we're looking at the same probe ID but a different EPID, 4437c478bd9Sstevel@tonic-gate * we _don't_ want to indent. (Yes, there are some minor holes in 4447c478bd9Sstevel@tonic-gate * this scheme -- it's a heuristic.) 4457c478bd9Sstevel@tonic-gate */ 4467c478bd9Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY) { 4477c478bd9Sstevel@tonic-gate if ((last != DTRACE_EPIDNONE && id != last && 4487c478bd9Sstevel@tonic-gate pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id)) 4497c478bd9Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* 4537c478bd9Sstevel@tonic-gate * If we're going to unindent this, it's more difficult to see if 4547c478bd9Sstevel@tonic-gate * we don't actually want to unindent it -- we need to look at the 4557c478bd9Sstevel@tonic-gate * _next_ EPID. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN) { 4587c478bd9Sstevel@tonic-gate offs += epd->dtepd_size; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate do { 461e5803b76SAdam H. Leventhal if (offs >= buf->dtbd_size) 4627c478bd9Sstevel@tonic-gate goto out; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (next == DTRACE_EPIDNONE) 4677c478bd9Sstevel@tonic-gate offs += sizeof (id); 4687c478bd9Sstevel@tonic-gate } while (next == DTRACE_EPIDNONE); 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0) 4717c478bd9Sstevel@tonic-gate return (rval); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate if (next != id && npd->dtpd_id == pd->dtpd_id) 4747c478bd9Sstevel@tonic-gate flow = DTRACEFLOW_NONE; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate out: 4787c478bd9Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) { 4797c478bd9Sstevel@tonic-gate data->dtpda_prefix = str; 4807c478bd9Sstevel@tonic-gate } else { 4817c478bd9Sstevel@tonic-gate data->dtpda_prefix = "| "; 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0) 4857c478bd9Sstevel@tonic-gate data->dtpda_indent -= 2; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate data->dtpda_flow = flow; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate return (0); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate static int 4937c478bd9Sstevel@tonic-gate dt_nullprobe() 4947c478bd9Sstevel@tonic-gate { 4957c478bd9Sstevel@tonic-gate return (DTRACE_CONSUME_THIS); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate static int 4997c478bd9Sstevel@tonic-gate dt_nullrec() 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 50433093f5bSBryan Cantrill static void 50533093f5bSBryan Cantrill dt_quantize_total(dtrace_hdl_t *dtp, int64_t datum, long double *total) 50633093f5bSBryan Cantrill { 50733093f5bSBryan Cantrill long double val = dt_fabsl((long double)datum); 50833093f5bSBryan Cantrill 50933093f5bSBryan Cantrill if (dtp->dt_options[DTRACEOPT_AGGZOOM] == DTRACEOPT_UNSET) { 51033093f5bSBryan Cantrill *total += val; 51133093f5bSBryan Cantrill return; 51233093f5bSBryan Cantrill } 51333093f5bSBryan Cantrill 51433093f5bSBryan Cantrill /* 51533093f5bSBryan Cantrill * If we're zooming in on an aggregation, we want the height of the 51633093f5bSBryan Cantrill * highest value to be approximately 95% of total bar height -- so we 51733093f5bSBryan Cantrill * adjust up by the reciprocal of DTRACE_AGGZOOM_MAX when comparing to 51833093f5bSBryan Cantrill * our highest value. 51933093f5bSBryan Cantrill */ 52033093f5bSBryan Cantrill val *= 1 / DTRACE_AGGZOOM_MAX; 52133093f5bSBryan Cantrill 52233093f5bSBryan Cantrill if (*total < val) 52333093f5bSBryan Cantrill *total = val; 52433093f5bSBryan Cantrill } 52533093f5bSBryan Cantrill 52633093f5bSBryan Cantrill static int 52733093f5bSBryan Cantrill dt_print_quanthdr(dtrace_hdl_t *dtp, FILE *fp, int width) 52833093f5bSBryan Cantrill { 52933093f5bSBryan Cantrill return (dt_printf(dtp, fp, "\n%*s %41s %-9s\n", 53033093f5bSBryan Cantrill width ? width : 16, width ? "key" : "value", 53133093f5bSBryan Cantrill "------------- Distribution -------------", "count")); 53233093f5bSBryan Cantrill } 53333093f5bSBryan Cantrill 53433093f5bSBryan Cantrill static int 53533093f5bSBryan Cantrill dt_print_quanthdr_packed(dtrace_hdl_t *dtp, FILE *fp, int width, 53633093f5bSBryan Cantrill const dtrace_aggdata_t *aggdata, dtrace_actkind_t action) 53733093f5bSBryan Cantrill { 53833093f5bSBryan Cantrill int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin; 53933093f5bSBryan Cantrill int minwidth, maxwidth, i; 54033093f5bSBryan Cantrill 54133093f5bSBryan Cantrill assert(action == DTRACEAGG_QUANTIZE || action == DTRACEAGG_LQUANTIZE); 54233093f5bSBryan Cantrill 54333093f5bSBryan Cantrill if (action == DTRACEAGG_QUANTIZE) { 54433093f5bSBryan Cantrill if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET) 54533093f5bSBryan Cantrill min--; 54633093f5bSBryan Cantrill 54733093f5bSBryan Cantrill if (max < DTRACE_QUANTIZE_NBUCKETS - 1) 54833093f5bSBryan Cantrill max++; 54933093f5bSBryan Cantrill 55033093f5bSBryan Cantrill minwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(min)); 55133093f5bSBryan Cantrill maxwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(max)); 55233093f5bSBryan Cantrill } else { 55333093f5bSBryan Cantrill maxwidth = 8; 55433093f5bSBryan Cantrill minwidth = maxwidth - 1; 55533093f5bSBryan Cantrill max++; 55633093f5bSBryan Cantrill } 55733093f5bSBryan Cantrill 55833093f5bSBryan Cantrill if (dt_printf(dtp, fp, "\n%*s %*s .", 55933093f5bSBryan Cantrill width, width > 0 ? "key" : "", minwidth, "min") < 0) 56033093f5bSBryan Cantrill return (-1); 56133093f5bSBryan Cantrill 56233093f5bSBryan Cantrill for (i = min; i <= max; i++) { 56333093f5bSBryan Cantrill if (dt_printf(dtp, fp, "-") < 0) 56433093f5bSBryan Cantrill return (-1); 56533093f5bSBryan Cantrill } 56633093f5bSBryan Cantrill 56733093f5bSBryan Cantrill return (dt_printf(dtp, fp, ". %*s | count\n", -maxwidth, "max")); 56833093f5bSBryan Cantrill } 56933093f5bSBryan Cantrill 57033093f5bSBryan Cantrill /* 57133093f5bSBryan Cantrill * We use a subset of the Unicode Block Elements (U+2588 through U+258F, 57233093f5bSBryan Cantrill * inclusive) to represent aggregations via UTF-8 -- which are expressed via 57333093f5bSBryan Cantrill * 3-byte UTF-8 sequences. 57433093f5bSBryan Cantrill */ 57533093f5bSBryan Cantrill #define DTRACE_AGGUTF8_FULL 0x2588 57633093f5bSBryan Cantrill #define DTRACE_AGGUTF8_BASE 0x258f 57733093f5bSBryan Cantrill #define DTRACE_AGGUTF8_LEVELS 8 57833093f5bSBryan Cantrill 57933093f5bSBryan Cantrill #define DTRACE_AGGUTF8_BYTE0(val) (0xe0 | ((val) >> 12)) 58033093f5bSBryan Cantrill #define DTRACE_AGGUTF8_BYTE1(val) (0x80 | (((val) >> 6) & 0x3f)) 58133093f5bSBryan Cantrill #define DTRACE_AGGUTF8_BYTE2(val) (0x80 | ((val) & 0x3f)) 58233093f5bSBryan Cantrill 58333093f5bSBryan Cantrill static int 58433093f5bSBryan Cantrill dt_print_quantline_utf8(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 58533093f5bSBryan Cantrill uint64_t normal, long double total) 58633093f5bSBryan Cantrill { 58733093f5bSBryan Cantrill uint_t len = 40, i, whole, partial; 58833093f5bSBryan Cantrill long double f = (dt_fabsl((long double)val) * len) / total; 58933093f5bSBryan Cantrill const char *spaces = " "; 59033093f5bSBryan Cantrill 59133093f5bSBryan Cantrill whole = (uint_t)f; 59233093f5bSBryan Cantrill partial = (uint_t)((f - (long double)(uint_t)f) * 59333093f5bSBryan Cantrill (long double)DTRACE_AGGUTF8_LEVELS); 59433093f5bSBryan Cantrill 59533093f5bSBryan Cantrill if (dt_printf(dtp, fp, "|") < 0) 59633093f5bSBryan Cantrill return (-1); 59733093f5bSBryan Cantrill 59833093f5bSBryan Cantrill for (i = 0; i < whole; i++) { 59933093f5bSBryan Cantrill if (dt_printf(dtp, fp, "%c%c%c", 60033093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE0(DTRACE_AGGUTF8_FULL), 60133093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE1(DTRACE_AGGUTF8_FULL), 60233093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE2(DTRACE_AGGUTF8_FULL)) < 0) 60333093f5bSBryan Cantrill return (-1); 60433093f5bSBryan Cantrill } 60533093f5bSBryan Cantrill 60633093f5bSBryan Cantrill if (partial != 0) { 60733093f5bSBryan Cantrill partial = DTRACE_AGGUTF8_BASE - (partial - 1); 60833093f5bSBryan Cantrill 60933093f5bSBryan Cantrill if (dt_printf(dtp, fp, "%c%c%c", 61033093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE0(partial), 61133093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE1(partial), 61233093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE2(partial)) < 0) 61333093f5bSBryan Cantrill return (-1); 61433093f5bSBryan Cantrill 61533093f5bSBryan Cantrill i++; 61633093f5bSBryan Cantrill } 61733093f5bSBryan Cantrill 61833093f5bSBryan Cantrill return (dt_printf(dtp, fp, "%s %-9lld\n", spaces + i, 61933093f5bSBryan Cantrill (long long)val / normal)); 62033093f5bSBryan Cantrill } 62133093f5bSBryan Cantrill 62233093f5bSBryan Cantrill static int 623a1b5e537Sbmc dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val, 624a1b5e537Sbmc uint64_t normal, long double total, char positives, char negatives) 625a1b5e537Sbmc { 626a1b5e537Sbmc long double f; 627a1b5e537Sbmc uint_t depth, len = 40; 628a1b5e537Sbmc 629a1b5e537Sbmc const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 630a1b5e537Sbmc const char *spaces = " "; 631a1b5e537Sbmc 632a1b5e537Sbmc assert(strlen(ats) == len && strlen(spaces) == len); 633a1b5e537Sbmc assert(!(total == 0 && (positives || negatives))); 634a1b5e537Sbmc assert(!(val < 0 && !negatives)); 635a1b5e537Sbmc assert(!(val > 0 && !positives)); 636a1b5e537Sbmc assert(!(val != 0 && total == 0)); 637a1b5e537Sbmc 638a1b5e537Sbmc if (!negatives) { 639a1b5e537Sbmc if (positives) { 64033093f5bSBryan Cantrill if (dtp->dt_encoding == DT_ENCODING_UTF8) { 64133093f5bSBryan Cantrill return (dt_print_quantline_utf8(dtp, fp, val, 64233093f5bSBryan Cantrill normal, total)); 64333093f5bSBryan Cantrill } 64433093f5bSBryan Cantrill 645a1b5e537Sbmc f = (dt_fabsl((long double)val) * len) / total; 646a1b5e537Sbmc depth = (uint_t)(f + 0.5); 647a1b5e537Sbmc } else { 648a1b5e537Sbmc depth = 0; 649a1b5e537Sbmc } 650a1b5e537Sbmc 651a1b5e537Sbmc return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth, 652a1b5e537Sbmc spaces + depth, (long long)val / normal)); 653a1b5e537Sbmc } 654a1b5e537Sbmc 655a1b5e537Sbmc if (!positives) { 656a1b5e537Sbmc f = (dt_fabsl((long double)val) * len) / total; 657a1b5e537Sbmc depth = (uint_t)(f + 0.5); 658a1b5e537Sbmc 659a1b5e537Sbmc return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth, 660a1b5e537Sbmc ats + len - depth, (long long)val / normal)); 661a1b5e537Sbmc } 662a1b5e537Sbmc 663a1b5e537Sbmc /* 664a1b5e537Sbmc * If we're here, we have both positive and negative bucket values. 665a1b5e537Sbmc * To express this graphically, we're going to generate both positive 666a1b5e537Sbmc * and negative bars separated by a centerline. These bars are half 667a1b5e537Sbmc * the size of normal quantize()/lquantize() bars, so we divide the 668a1b5e537Sbmc * length in half before calculating the bar length. 669a1b5e537Sbmc */ 670a1b5e537Sbmc len /= 2; 671a1b5e537Sbmc ats = &ats[len]; 672a1b5e537Sbmc spaces = &spaces[len]; 673a1b5e537Sbmc 674a1b5e537Sbmc f = (dt_fabsl((long double)val) * len) / total; 675a1b5e537Sbmc depth = (uint_t)(f + 0.5); 676a1b5e537Sbmc 677a1b5e537Sbmc if (val <= 0) { 678a1b5e537Sbmc return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth, 679a1b5e537Sbmc ats + len - depth, len, "", (long long)val / normal)); 680a1b5e537Sbmc } else { 681a1b5e537Sbmc return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "", 682a1b5e537Sbmc ats + len - depth, spaces + depth, 683a1b5e537Sbmc (long long)val / normal)); 684a1b5e537Sbmc } 685a1b5e537Sbmc } 686a1b5e537Sbmc 68733093f5bSBryan Cantrill /* 68833093f5bSBryan Cantrill * As with UTF-8 printing of aggregations, we use a subset of the Unicode 68933093f5bSBryan Cantrill * Block Elements (U+2581 through U+2588, inclusive) to represent our packed 69033093f5bSBryan Cantrill * aggregation. 69133093f5bSBryan Cantrill */ 69233093f5bSBryan Cantrill #define DTRACE_AGGPACK_BASE 0x2581 69333093f5bSBryan Cantrill #define DTRACE_AGGPACK_LEVELS 8 69433093f5bSBryan Cantrill 69533093f5bSBryan Cantrill static int 69633093f5bSBryan Cantrill dt_print_packed(dtrace_hdl_t *dtp, FILE *fp, 69733093f5bSBryan Cantrill long double datum, long double total) 69833093f5bSBryan Cantrill { 69933093f5bSBryan Cantrill static boolean_t utf8_checked = B_FALSE; 70033093f5bSBryan Cantrill static boolean_t utf8; 70133093f5bSBryan Cantrill char *ascii = "__xxxxXX"; 70233093f5bSBryan Cantrill char *neg = "vvvvVV"; 70333093f5bSBryan Cantrill unsigned int len; 70433093f5bSBryan Cantrill long double val; 70533093f5bSBryan Cantrill 70633093f5bSBryan Cantrill if (!utf8_checked) { 70733093f5bSBryan Cantrill char *term; 70833093f5bSBryan Cantrill 70933093f5bSBryan Cantrill /* 71033093f5bSBryan Cantrill * We want to determine if we can reasonably emit UTF-8 for our 71133093f5bSBryan Cantrill * packed aggregation. To do this, we will check for terminals 71233093f5bSBryan Cantrill * that are known to be primitive to emit UTF-8 on these. 71333093f5bSBryan Cantrill */ 71433093f5bSBryan Cantrill utf8_checked = B_TRUE; 71533093f5bSBryan Cantrill 71633093f5bSBryan Cantrill if (dtp->dt_encoding == DT_ENCODING_ASCII) { 71733093f5bSBryan Cantrill utf8 = B_FALSE; 71833093f5bSBryan Cantrill } else if (dtp->dt_encoding == DT_ENCODING_UTF8) { 71933093f5bSBryan Cantrill utf8 = B_TRUE; 72033093f5bSBryan Cantrill } else if ((term = getenv("TERM")) != NULL && 72133093f5bSBryan Cantrill (strcmp(term, "sun") == 0 || 72233093f5bSBryan Cantrill strcmp(term, "sun-color") == 0) || 72333093f5bSBryan Cantrill strcmp(term, "dumb") == 0) { 72433093f5bSBryan Cantrill utf8 = B_FALSE; 72533093f5bSBryan Cantrill } else { 72633093f5bSBryan Cantrill utf8 = B_TRUE; 72733093f5bSBryan Cantrill } 72833093f5bSBryan Cantrill } 72933093f5bSBryan Cantrill 73033093f5bSBryan Cantrill if (datum == 0) 73133093f5bSBryan Cantrill return (dt_printf(dtp, fp, " ")); 73233093f5bSBryan Cantrill 73333093f5bSBryan Cantrill if (datum < 0) { 73433093f5bSBryan Cantrill len = strlen(neg); 73533093f5bSBryan Cantrill val = dt_fabsl(datum * (len - 1)) / total; 73633093f5bSBryan Cantrill return (dt_printf(dtp, fp, "%c", neg[(uint_t)(val + 0.5)])); 73733093f5bSBryan Cantrill } 73833093f5bSBryan Cantrill 73933093f5bSBryan Cantrill if (utf8) { 74033093f5bSBryan Cantrill int block = DTRACE_AGGPACK_BASE + (unsigned int)(((datum * 74133093f5bSBryan Cantrill (DTRACE_AGGPACK_LEVELS - 1)) / total) + 0.5); 74233093f5bSBryan Cantrill 74333093f5bSBryan Cantrill return (dt_printf(dtp, fp, "%c%c%c", 74433093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE0(block), 74533093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE1(block), 74633093f5bSBryan Cantrill DTRACE_AGGUTF8_BYTE2(block))); 74733093f5bSBryan Cantrill } 74833093f5bSBryan Cantrill 74933093f5bSBryan Cantrill len = strlen(ascii); 75033093f5bSBryan Cantrill val = (datum * (len - 1)) / total; 75133093f5bSBryan Cantrill return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)])); 75233093f5bSBryan Cantrill } 75333093f5bSBryan Cantrill 754a1b5e537Sbmc int 7557c478bd9Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 7567c478bd9Sstevel@tonic-gate size_t size, uint64_t normal) 7577c478bd9Sstevel@tonic-gate { 758a1b5e537Sbmc const int64_t *data = addr; 7597c478bd9Sstevel@tonic-gate int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1; 760a1b5e537Sbmc long double total = 0; 761a1b5e537Sbmc char positives = 0, negatives = 0; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 7647c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0) 7677c478bd9Sstevel@tonic-gate first_bin++; 7687c478bd9Sstevel@tonic-gate 769a1b5e537Sbmc if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) { 770a1b5e537Sbmc /* 77133093f5bSBryan Cantrill * There isn't any data. This is possible if the aggregation 77233093f5bSBryan Cantrill * has been clear()'d or if negative increment values have been 77333093f5bSBryan Cantrill * used. Regardless, we'll print the buckets around 0. 774a1b5e537Sbmc */ 775a1b5e537Sbmc first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1; 776a1b5e537Sbmc last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1; 777a1b5e537Sbmc } else { 7787c478bd9Sstevel@tonic-gate if (first_bin > 0) 7797c478bd9Sstevel@tonic-gate first_bin--; 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate while (last_bin > 0 && data[last_bin] == 0) 7827c478bd9Sstevel@tonic-gate last_bin--; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1) 7857c478bd9Sstevel@tonic-gate last_bin++; 786a1b5e537Sbmc } 7877c478bd9Sstevel@tonic-gate 788a1b5e537Sbmc for (i = first_bin; i <= last_bin; i++) { 789a1b5e537Sbmc positives |= (data[i] > 0); 790a1b5e537Sbmc negatives |= (data[i] < 0); 79133093f5bSBryan Cantrill dt_quantize_total(dtp, data[i], &total); 792a1b5e537Sbmc } 7937c478bd9Sstevel@tonic-gate 79433093f5bSBryan Cantrill if (dt_print_quanthdr(dtp, fp, 0) < 0) 7957c478bd9Sstevel@tonic-gate return (-1); 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 798a1b5e537Sbmc if (dt_printf(dtp, fp, "%16lld ", 799a1b5e537Sbmc (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0) 800a1b5e537Sbmc return (-1); 8017c478bd9Sstevel@tonic-gate 802a1b5e537Sbmc if (dt_print_quantline(dtp, fp, data[i], normal, total, 803a1b5e537Sbmc positives, negatives) < 0) 8047c478bd9Sstevel@tonic-gate return (-1); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate return (0); 8087c478bd9Sstevel@tonic-gate } 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate int 81133093f5bSBryan Cantrill dt_print_quantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 81233093f5bSBryan Cantrill size_t size, const dtrace_aggdata_t *aggdata) 81333093f5bSBryan Cantrill { 81433093f5bSBryan Cantrill const int64_t *data = addr; 81533093f5bSBryan Cantrill long double total = 0, count = 0; 81633093f5bSBryan Cantrill int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin, i; 81733093f5bSBryan Cantrill int64_t minval, maxval; 81833093f5bSBryan Cantrill 81933093f5bSBryan Cantrill if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) 82033093f5bSBryan Cantrill return (dt_set_errno(dtp, EDT_DMISMATCH)); 82133093f5bSBryan Cantrill 82233093f5bSBryan Cantrill if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET) 82333093f5bSBryan Cantrill min--; 82433093f5bSBryan Cantrill 82533093f5bSBryan Cantrill if (max < DTRACE_QUANTIZE_NBUCKETS - 1) 82633093f5bSBryan Cantrill max++; 82733093f5bSBryan Cantrill 82833093f5bSBryan Cantrill minval = DTRACE_QUANTIZE_BUCKETVAL(min); 82933093f5bSBryan Cantrill maxval = DTRACE_QUANTIZE_BUCKETVAL(max); 83033093f5bSBryan Cantrill 83133093f5bSBryan Cantrill if (dt_printf(dtp, fp, " %*lld :", dt_ndigits(minval), 83233093f5bSBryan Cantrill (long long)minval) < 0) 83333093f5bSBryan Cantrill return (-1); 83433093f5bSBryan Cantrill 83533093f5bSBryan Cantrill for (i = min; i <= max; i++) { 83633093f5bSBryan Cantrill dt_quantize_total(dtp, data[i], &total); 83733093f5bSBryan Cantrill count += data[i]; 83833093f5bSBryan Cantrill } 83933093f5bSBryan Cantrill 84033093f5bSBryan Cantrill for (i = min; i <= max; i++) { 84133093f5bSBryan Cantrill if (dt_print_packed(dtp, fp, data[i], total) < 0) 84233093f5bSBryan Cantrill return (-1); 84333093f5bSBryan Cantrill } 84433093f5bSBryan Cantrill 84533093f5bSBryan Cantrill if (dt_printf(dtp, fp, ": %*lld | %lld\n", 84633093f5bSBryan Cantrill -dt_ndigits(maxval), (long long)maxval, (long long)count) < 0) 84733093f5bSBryan Cantrill return (-1); 84833093f5bSBryan Cantrill 84933093f5bSBryan Cantrill return (0); 85033093f5bSBryan Cantrill } 85133093f5bSBryan Cantrill 85233093f5bSBryan Cantrill int 8537c478bd9Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 8547c478bd9Sstevel@tonic-gate size_t size, uint64_t normal) 8557c478bd9Sstevel@tonic-gate { 856a1b5e537Sbmc const int64_t *data = addr; 8577c478bd9Sstevel@tonic-gate int i, first_bin, last_bin, base; 858a1b5e537Sbmc uint64_t arg; 859a1b5e537Sbmc long double total = 0; 8607c478bd9Sstevel@tonic-gate uint16_t step, levels; 861a1b5e537Sbmc char positives = 0, negatives = 0; 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate if (size < sizeof (uint64_t)) 8647c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate arg = *data++; 8677c478bd9Sstevel@tonic-gate size -= sizeof (uint64_t); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate base = DTRACE_LQUANTIZE_BASE(arg); 8707c478bd9Sstevel@tonic-gate step = DTRACE_LQUANTIZE_STEP(arg); 8717c478bd9Sstevel@tonic-gate levels = DTRACE_LQUANTIZE_LEVELS(arg); 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate first_bin = 0; 8747c478bd9Sstevel@tonic-gate last_bin = levels + 1; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate if (size != sizeof (uint64_t) * (levels + 2)) 8777c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH)); 8787c478bd9Sstevel@tonic-gate 879187eccf8Sbmc while (first_bin <= levels + 1 && data[first_bin] == 0) 8807c478bd9Sstevel@tonic-gate first_bin++; 8817c478bd9Sstevel@tonic-gate 882187eccf8Sbmc if (first_bin > levels + 1) { 883a1b5e537Sbmc first_bin = 0; 884a1b5e537Sbmc last_bin = 2; 885a1b5e537Sbmc } else { 8867c478bd9Sstevel@tonic-gate if (first_bin > 0) 8877c478bd9Sstevel@tonic-gate first_bin--; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate while (last_bin > 0 && data[last_bin] == 0) 8907c478bd9Sstevel@tonic-gate last_bin--; 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate if (last_bin < levels + 1) 8937c478bd9Sstevel@tonic-gate last_bin++; 894a1b5e537Sbmc } 8957c478bd9Sstevel@tonic-gate 896a1b5e537Sbmc for (i = first_bin; i <= last_bin; i++) { 897a1b5e537Sbmc positives |= (data[i] > 0); 898a1b5e537Sbmc negatives |= (data[i] < 0); 89933093f5bSBryan Cantrill dt_quantize_total(dtp, data[i], &total); 900a1b5e537Sbmc } 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 9037c478bd9Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0) 9047c478bd9Sstevel@tonic-gate return (-1); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) { 9077c478bd9Sstevel@tonic-gate char c[32]; 9087c478bd9Sstevel@tonic-gate int err; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate if (i == 0) { 91133093f5bSBryan Cantrill (void) snprintf(c, sizeof (c), "< %d", base); 9127c478bd9Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 9137c478bd9Sstevel@tonic-gate } else if (i == levels + 1) { 9147c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), ">= %d", 9157c478bd9Sstevel@tonic-gate base + (levels * step)); 9167c478bd9Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c); 9177c478bd9Sstevel@tonic-gate } else { 9187c478bd9Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16d ", 9197c478bd9Sstevel@tonic-gate base + (i - 1) * step); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 922a1b5e537Sbmc if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal, 923a1b5e537Sbmc total, positives, negatives) < 0) 9247c478bd9Sstevel@tonic-gate return (-1); 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate return (0); 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate 93033093f5bSBryan Cantrill /*ARGSUSED*/ 93133093f5bSBryan Cantrill int 93233093f5bSBryan Cantrill dt_print_lquantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 93333093f5bSBryan Cantrill size_t size, const dtrace_aggdata_t *aggdata) 93433093f5bSBryan Cantrill { 93533093f5bSBryan Cantrill const int64_t *data = addr; 93633093f5bSBryan Cantrill long double total = 0, count = 0; 93733093f5bSBryan Cantrill int min, max, base, err; 93833093f5bSBryan Cantrill uint64_t arg; 93933093f5bSBryan Cantrill uint16_t step, levels; 94033093f5bSBryan Cantrill char c[32]; 94133093f5bSBryan Cantrill unsigned int i; 94233093f5bSBryan Cantrill 94333093f5bSBryan Cantrill if (size < sizeof (uint64_t)) 94433093f5bSBryan Cantrill return (dt_set_errno(dtp, EDT_DMISMATCH)); 94533093f5bSBryan Cantrill 94633093f5bSBryan Cantrill arg = *data++; 94733093f5bSBryan Cantrill size -= sizeof (uint64_t); 94833093f5bSBryan Cantrill 94933093f5bSBryan Cantrill base = DTRACE_LQUANTIZE_BASE(arg); 95033093f5bSBryan Cantrill step = DTRACE_LQUANTIZE_STEP(arg); 95133093f5bSBryan Cantrill levels = DTRACE_LQUANTIZE_LEVELS(arg); 95233093f5bSBryan Cantrill 95333093f5bSBryan Cantrill if (size != sizeof (uint64_t) * (levels + 2)) 95433093f5bSBryan Cantrill return (dt_set_errno(dtp, EDT_DMISMATCH)); 95533093f5bSBryan Cantrill 95633093f5bSBryan Cantrill min = 0; 95733093f5bSBryan Cantrill max = levels + 1; 95833093f5bSBryan Cantrill 95933093f5bSBryan Cantrill if (min == 0) { 96033093f5bSBryan Cantrill (void) snprintf(c, sizeof (c), "< %d", base); 96133093f5bSBryan Cantrill err = dt_printf(dtp, fp, "%8s :", c); 96233093f5bSBryan Cantrill } else { 96333093f5bSBryan Cantrill err = dt_printf(dtp, fp, "%8d :", base + (min - 1) * step); 96433093f5bSBryan Cantrill } 96533093f5bSBryan Cantrill 96633093f5bSBryan Cantrill if (err < 0) 96733093f5bSBryan Cantrill return (-1); 96833093f5bSBryan Cantrill 96933093f5bSBryan Cantrill for (i = min; i <= max; i++) { 97033093f5bSBryan Cantrill dt_quantize_total(dtp, data[i], &total); 97133093f5bSBryan Cantrill count += data[i]; 97233093f5bSBryan Cantrill } 97333093f5bSBryan Cantrill 97433093f5bSBryan Cantrill for (i = min; i <= max; i++) { 97533093f5bSBryan Cantrill if (dt_print_packed(dtp, fp, data[i], total) < 0) 97633093f5bSBryan Cantrill return (-1); 97733093f5bSBryan Cantrill } 97833093f5bSBryan Cantrill 97933093f5bSBryan Cantrill (void) snprintf(c, sizeof (c), ">= %d", base + (levels * step)); 98033093f5bSBryan Cantrill return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count)); 98133093f5bSBryan Cantrill } 98233093f5bSBryan Cantrill 9832b6389efSBryan Cantrill int 9842b6389efSBryan Cantrill dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr, 9852b6389efSBryan Cantrill size_t size, uint64_t normal) 9862b6389efSBryan Cantrill { 9872b6389efSBryan Cantrill int i, first_bin, last_bin, bin = 1, order, levels; 9882b6389efSBryan Cantrill uint16_t factor, low, high, nsteps; 9892b6389efSBryan Cantrill const int64_t *data = addr; 9902b6389efSBryan Cantrill int64_t value = 1, next, step; 9912b6389efSBryan Cantrill char positives = 0, negatives = 0; 9922b6389efSBryan Cantrill long double total = 0; 9932b6389efSBryan Cantrill uint64_t arg; 9942b6389efSBryan Cantrill char c[32]; 9952b6389efSBryan Cantrill 9962b6389efSBryan Cantrill if (size < sizeof (uint64_t)) 9972b6389efSBryan Cantrill return (dt_set_errno(dtp, EDT_DMISMATCH)); 9982b6389efSBryan Cantrill 9992b6389efSBryan Cantrill arg = *data++; 10002b6389efSBryan Cantrill size -= sizeof (uint64_t); 10012b6389efSBryan Cantrill 10022b6389efSBryan Cantrill factor = DTRACE_LLQUANTIZE_FACTOR(arg); 10032b6389efSBryan Cantrill low = DTRACE_LLQUANTIZE_LOW(arg); 10042b6389efSBryan Cantrill high = DTRACE_LLQUANTIZE_HIGH(arg); 10052b6389efSBryan Cantrill nsteps = DTRACE_LLQUANTIZE_NSTEP(arg); 10062b6389efSBryan Cantrill 10072b6389efSBryan Cantrill /* 10082b6389efSBryan Cantrill * We don't expect to be handed invalid llquantize() parameters here, 10092b6389efSBryan Cantrill * but sanity check them (to a degree) nonetheless. 10102b6389efSBryan Cantrill */ 10112b6389efSBryan Cantrill if (size > INT32_MAX || factor < 2 || low >= high || 10122b6389efSBryan Cantrill nsteps == 0 || factor > nsteps) 10132b6389efSBryan Cantrill return (dt_set_errno(dtp, EDT_DMISMATCH)); 10142b6389efSBryan Cantrill 10152b6389efSBryan Cantrill levels = (int)size / sizeof (uint64_t); 10162b6389efSBryan Cantrill 10172b6389efSBryan Cantrill first_bin = 0; 10182b6389efSBryan Cantrill last_bin = levels - 1; 10192b6389efSBryan Cantrill 10202b6389efSBryan Cantrill while (first_bin < levels && data[first_bin] == 0) 10212b6389efSBryan Cantrill first_bin++; 10222b6389efSBryan Cantrill 10232b6389efSBryan Cantrill if (first_bin == levels) { 10242b6389efSBryan Cantrill first_bin = 0; 10252b6389efSBryan Cantrill last_bin = 1; 10262b6389efSBryan Cantrill } else { 10272b6389efSBryan Cantrill if (first_bin > 0) 10282b6389efSBryan Cantrill first_bin--; 10292b6389efSBryan Cantrill 10302b6389efSBryan Cantrill while (last_bin > 0 && data[last_bin] == 0) 10312b6389efSBryan Cantrill last_bin--; 10322b6389efSBryan Cantrill 10332b6389efSBryan Cantrill if (last_bin < levels - 1) 10342b6389efSBryan Cantrill last_bin++; 10352b6389efSBryan Cantrill } 10362b6389efSBryan Cantrill 10372b6389efSBryan Cantrill for (i = first_bin; i <= last_bin; i++) { 10382b6389efSBryan Cantrill positives |= (data[i] > 0); 10392b6389efSBryan Cantrill negatives |= (data[i] < 0); 104033093f5bSBryan Cantrill dt_quantize_total(dtp, data[i], &total); 10412b6389efSBryan Cantrill } 10422b6389efSBryan Cantrill 10432b6389efSBryan Cantrill if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value", 10442b6389efSBryan Cantrill "------------- Distribution -------------", "count") < 0) 10452b6389efSBryan Cantrill return (-1); 10462b6389efSBryan Cantrill 10472b6389efSBryan Cantrill for (order = 0; order < low; order++) 10482b6389efSBryan Cantrill value *= factor; 10492b6389efSBryan Cantrill 10502b6389efSBryan Cantrill next = value * factor; 10512b6389efSBryan Cantrill step = next > nsteps ? next / nsteps : 1; 10522b6389efSBryan Cantrill 10532b6389efSBryan Cantrill if (first_bin == 0) { 10542b6389efSBryan Cantrill (void) snprintf(c, sizeof (c), "< %lld", value); 10552b6389efSBryan Cantrill 10562b6389efSBryan Cantrill if (dt_printf(dtp, fp, "%16s ", c) < 0) 10572b6389efSBryan Cantrill return (-1); 10582b6389efSBryan Cantrill 10592b6389efSBryan Cantrill if (dt_print_quantline(dtp, fp, data[0], normal, 10602b6389efSBryan Cantrill total, positives, negatives) < 0) 10612b6389efSBryan Cantrill return (-1); 10622b6389efSBryan Cantrill } 10632b6389efSBryan Cantrill 10642b6389efSBryan Cantrill while (order <= high) { 10652b6389efSBryan Cantrill if (bin >= first_bin && bin <= last_bin) { 10662b6389efSBryan Cantrill if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0) 10672b6389efSBryan Cantrill return (-1); 10682b6389efSBryan Cantrill 10692b6389efSBryan Cantrill if (dt_print_quantline(dtp, fp, data[bin], 10702b6389efSBryan Cantrill normal, total, positives, negatives) < 0) 10712b6389efSBryan Cantrill return (-1); 10722b6389efSBryan Cantrill } 10732b6389efSBryan Cantrill 10742b6389efSBryan Cantrill assert(value < next); 10752b6389efSBryan Cantrill bin++; 10762b6389efSBryan Cantrill 10772b6389efSBryan Cantrill if ((value += step) != next) 10782b6389efSBryan Cantrill continue; 10792b6389efSBryan Cantrill 10802b6389efSBryan Cantrill next = value * factor; 10812b6389efSBryan Cantrill step = next > nsteps ? next / nsteps : 1; 10822b6389efSBryan Cantrill order++; 10832b6389efSBryan Cantrill } 10842b6389efSBryan Cantrill 10852b6389efSBryan Cantrill if (last_bin < bin) 10862b6389efSBryan Cantrill return (0); 10872b6389efSBryan Cantrill 10882b6389efSBryan Cantrill assert(last_bin == bin); 10892b6389efSBryan Cantrill (void) snprintf(c, sizeof (c), ">= %lld", value); 10902b6389efSBryan Cantrill 10912b6389efSBryan Cantrill if (dt_printf(dtp, fp, "%16s ", c) < 0) 10922b6389efSBryan Cantrill return (-1); 10932b6389efSBryan Cantrill 10942b6389efSBryan Cantrill return (dt_print_quantline(dtp, fp, data[bin], normal, 10952b6389efSBryan Cantrill total, positives, negatives)); 10962b6389efSBryan Cantrill } 10972b6389efSBryan Cantrill 10987c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10997c478bd9Sstevel@tonic-gate static int 11007c478bd9Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 11017c478bd9Sstevel@tonic-gate size_t size, uint64_t normal) 11027c478bd9Sstevel@tonic-gate { 11037c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 11046e0bee74Sjhaslam int64_t *data = (int64_t *)addr; 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, " %16lld", data[0] ? 11076e0bee74Sjhaslam (long long)(data[1] / (int64_t)normal / data[0]) : 0)); 11086e0bee74Sjhaslam } 11096e0bee74Sjhaslam 11106e0bee74Sjhaslam /*ARGSUSED*/ 11116e0bee74Sjhaslam static int 11126e0bee74Sjhaslam dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 11136e0bee74Sjhaslam size_t size, uint64_t normal) 11146e0bee74Sjhaslam { 11156e0bee74Sjhaslam /* LINTED - alignment */ 11166e0bee74Sjhaslam uint64_t *data = (uint64_t *)addr; 11176e0bee74Sjhaslam 11186e0bee74Sjhaslam return (dt_printf(dtp, fp, " %16llu", data[0] ? 11196e0bee74Sjhaslam (unsigned long long) dt_stddev(data, normal) : 0)); 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 112333093f5bSBryan Cantrill static int 11247c478bd9Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, 11251ea5f93dSBryan Cantrill size_t nbytes, int width, int quiet, int forceraw) 11267c478bd9Sstevel@tonic-gate { 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * If the byte stream is a series of printable characters, followed by 11297c478bd9Sstevel@tonic-gate * a terminating byte, we print it out as a string. Otherwise, we 11307c478bd9Sstevel@tonic-gate * assume that it's something else and just print the bytes. 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate int i, j, margin = 5; 11337c478bd9Sstevel@tonic-gate char *c = (char *)addr; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate if (nbytes == 0) 11367c478bd9Sstevel@tonic-gate return (0); 11377c478bd9Sstevel@tonic-gate 11381ea5f93dSBryan Cantrill if (forceraw) 11391ea5f93dSBryan Cantrill goto raw; 11401ea5f93dSBryan Cantrill 11417c478bd9Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET) 11427c478bd9Sstevel@tonic-gate goto raw; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate for (i = 0; i < nbytes; i++) { 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * We define a "printable character" to be one for which 11477c478bd9Sstevel@tonic-gate * isprint(3C) returns non-zero, isspace(3C) returns non-zero, 11487c478bd9Sstevel@tonic-gate * or a character which is either backspace or the bell. 11497c478bd9Sstevel@tonic-gate * Backspace and the bell are regrettably special because 11507c478bd9Sstevel@tonic-gate * they fail the first two tests -- and yet they are entirely 11517c478bd9Sstevel@tonic-gate * printable. These are the only two control characters that 11527c478bd9Sstevel@tonic-gate * have meaning for the terminal and for which isprint(3C) and 11537c478bd9Sstevel@tonic-gate * isspace(3C) return 0. 11547c478bd9Sstevel@tonic-gate */ 11557c478bd9Sstevel@tonic-gate if (isprint(c[i]) || isspace(c[i]) || 11567c478bd9Sstevel@tonic-gate c[i] == '\b' || c[i] == '\a') 11577c478bd9Sstevel@tonic-gate continue; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate if (c[i] == '\0' && i > 0) { 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * This looks like it might be a string. Before we 11627c478bd9Sstevel@tonic-gate * assume that it is indeed a string, check the 11637c478bd9Sstevel@tonic-gate * remainder of the byte range; if it contains 11647c478bd9Sstevel@tonic-gate * additional non-nul characters, we'll assume that 11657c478bd9Sstevel@tonic-gate * it's a binary stream that just happens to look like 11667c478bd9Sstevel@tonic-gate * a string, and we'll print out the individual bytes. 11677c478bd9Sstevel@tonic-gate */ 11687c478bd9Sstevel@tonic-gate for (j = i + 1; j < nbytes; j++) { 11697c478bd9Sstevel@tonic-gate if (c[j] != '\0') 11707c478bd9Sstevel@tonic-gate break; 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate if (j != nbytes) 11747c478bd9Sstevel@tonic-gate break; 11757c478bd9Sstevel@tonic-gate 117633093f5bSBryan Cantrill if (quiet) { 11777c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, "%s", c)); 117833093f5bSBryan Cantrill } else { 117933093f5bSBryan Cantrill return (dt_printf(dtp, fp, " %s%*s", 118033093f5bSBryan Cantrill width < 0 ? " " : "", width, c)); 118133093f5bSBryan Cantrill } 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate break; 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate if (i == nbytes) { 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * The byte range is all printable characters, but there is 11907c478bd9Sstevel@tonic-gate * no trailing nul byte. We'll assume that it's a string and 11917c478bd9Sstevel@tonic-gate * print it as such. 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate char *s = alloca(nbytes + 1); 11947c478bd9Sstevel@tonic-gate bcopy(c, s, nbytes); 11957c478bd9Sstevel@tonic-gate s[nbytes] = '\0'; 11967c478bd9Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, s)); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate raw: 12007c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0) 12017c478bd9Sstevel@tonic-gate return (-1); 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) 12047c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0) 12057c478bd9Sstevel@tonic-gate return (-1); 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0) 12087c478bd9Sstevel@tonic-gate return (-1); 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate for (i = 0; i < nbytes; i += 16) { 12127c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0) 12137c478bd9Sstevel@tonic-gate return (-1); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 12167c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0) 12177c478bd9Sstevel@tonic-gate return (-1); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate while (j++ % 16) { 12217c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 12227c478bd9Sstevel@tonic-gate return (-1); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0) 12267c478bd9Sstevel@tonic-gate return (-1); 12277c478bd9Sstevel@tonic-gate 12287c478bd9Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) { 12297c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "%c", 12307c478bd9Sstevel@tonic-gate c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0) 12317c478bd9Sstevel@tonic-gate return (-1); 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 12357c478bd9Sstevel@tonic-gate return (-1); 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate return (0); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate int 12427c478bd9Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 1243a1b5e537Sbmc caddr_t addr, int depth, int size) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate dtrace_syminfo_t dts; 12467c478bd9Sstevel@tonic-gate GElf_Sym sym; 12477c478bd9Sstevel@tonic-gate int i, indent; 12487c478bd9Sstevel@tonic-gate char c[PATH_MAX * 2]; 1249a1b5e537Sbmc uint64_t pc; 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 12527c478bd9Sstevel@tonic-gate return (-1); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate if (format == NULL) 12557c478bd9Sstevel@tonic-gate format = "%s"; 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 12587c478bd9Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 12597c478bd9Sstevel@tonic-gate else 12607c478bd9Sstevel@tonic-gate indent = _dtrace_stkindent; 12617c478bd9Sstevel@tonic-gate 1262a1b5e537Sbmc for (i = 0; i < depth; i++) { 1263a1b5e537Sbmc switch (size) { 1264a1b5e537Sbmc case sizeof (uint32_t): 1265a1b5e537Sbmc /* LINTED - alignment */ 1266a1b5e537Sbmc pc = *((uint32_t *)addr); 1267a1b5e537Sbmc break; 1268a1b5e537Sbmc 1269a1b5e537Sbmc case sizeof (uint64_t): 1270a1b5e537Sbmc /* LINTED - alignment */ 1271a1b5e537Sbmc pc = *((uint64_t *)addr); 1272a1b5e537Sbmc break; 1273a1b5e537Sbmc 1274a1b5e537Sbmc default: 1275a1b5e537Sbmc return (dt_set_errno(dtp, EDT_BADSTACKPC)); 1276a1b5e537Sbmc } 1277a1b5e537Sbmc 1278a1b5e537Sbmc if (pc == NULL) 1279a1b5e537Sbmc break; 1280a1b5e537Sbmc 1281a1b5e537Sbmc addr += size; 1282a1b5e537Sbmc 12837c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s", indent, "") < 0) 12847c478bd9Sstevel@tonic-gate return (-1); 12857c478bd9Sstevel@tonic-gate 1286a1b5e537Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1287a1b5e537Sbmc if (pc > sym.st_value) { 12887c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s+0x%llx", 12897c478bd9Sstevel@tonic-gate dts.dts_object, dts.dts_name, 1290a1b5e537Sbmc pc - sym.st_value); 12917c478bd9Sstevel@tonic-gate } else { 12927c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s", 12937c478bd9Sstevel@tonic-gate dts.dts_object, dts.dts_name); 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate } else { 12967c478bd9Sstevel@tonic-gate /* 12977c478bd9Sstevel@tonic-gate * We'll repeat the lookup, but this time we'll specify 12987c478bd9Sstevel@tonic-gate * a NULL GElf_Sym -- indicating that we're only 12997c478bd9Sstevel@tonic-gate * interested in the containing module. 13007c478bd9Sstevel@tonic-gate */ 1301a1b5e537Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 13027c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 1303a1b5e537Sbmc dts.dts_object, pc); 13047c478bd9Sstevel@tonic-gate } else { 1305a1b5e537Sbmc (void) snprintf(c, sizeof (c), "0x%llx", pc); 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, format, c) < 0) 13107c478bd9Sstevel@tonic-gate return (-1); 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 13137c478bd9Sstevel@tonic-gate return (-1); 13147c478bd9Sstevel@tonic-gate } 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate return (0); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate int 13207c478bd9Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format, 13217c478bd9Sstevel@tonic-gate caddr_t addr, uint64_t arg) 13227c478bd9Sstevel@tonic-gate { 1323a1b5e537Sbmc /* LINTED - alignment */ 1324a1b5e537Sbmc uint64_t *pc = (uint64_t *)addr; 13257c478bd9Sstevel@tonic-gate uint32_t depth = DTRACE_USTACK_NFRAMES(arg); 13267c478bd9Sstevel@tonic-gate uint32_t strsize = DTRACE_USTACK_STRSIZE(arg); 13277c478bd9Sstevel@tonic-gate const char *strbase = addr + (depth + 1) * sizeof (uint64_t); 13287c478bd9Sstevel@tonic-gate const char *str = strsize ? strbase : NULL; 13297c478bd9Sstevel@tonic-gate int err = 0; 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2]; 13327c478bd9Sstevel@tonic-gate struct ps_prochandle *P; 13337c478bd9Sstevel@tonic-gate GElf_Sym sym; 13347c478bd9Sstevel@tonic-gate int i, indent; 13357c478bd9Sstevel@tonic-gate pid_t pid; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate if (depth == 0) 13387c478bd9Sstevel@tonic-gate return (0); 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate pid = (pid_t)*pc++; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0) 13437c478bd9Sstevel@tonic-gate return (-1); 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate if (format == NULL) 13467c478bd9Sstevel@tonic-gate format = "%s"; 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET) 13497c478bd9Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT]; 13507c478bd9Sstevel@tonic-gate else 13517c478bd9Sstevel@tonic-gate indent = _dtrace_stkindent; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate /* 13547c478bd9Sstevel@tonic-gate * Ultimately, we need to add an entry point in the library vector for 13557c478bd9Sstevel@tonic-gate * determining <symbol, offset> from <pid, address>. For now, if 13567c478bd9Sstevel@tonic-gate * this is a vector open, we just print the raw address or string. 13577c478bd9Sstevel@tonic-gate */ 13587c478bd9Sstevel@tonic-gate if (dtp->dt_vector == NULL) 13597c478bd9Sstevel@tonic-gate P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 13607c478bd9Sstevel@tonic-gate else 13617c478bd9Sstevel@tonic-gate P = NULL; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate if (P != NULL) 13647c478bd9Sstevel@tonic-gate dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate for (i = 0; i < depth && pc[i] != NULL; i++) { 1367a1b5e537Sbmc const prmap_t *map; 1368a1b5e537Sbmc 13697c478bd9Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 13707c478bd9Sstevel@tonic-gate break; 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate if (P != NULL && Plookup_by_addr(P, pc[i], 13737c478bd9Sstevel@tonic-gate name, sizeof (name), &sym) == 0) { 13747c478bd9Sstevel@tonic-gate (void) Pobjname(P, pc[i], objname, sizeof (objname)); 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate if (pc[i] > sym.st_value) { 13777c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 13787c478bd9Sstevel@tonic-gate "%s`%s+0x%llx", dt_basename(objname), name, 13797c478bd9Sstevel@tonic-gate (u_longlong_t)(pc[i] - sym.st_value)); 13807c478bd9Sstevel@tonic-gate } else { 13817c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), 13827c478bd9Sstevel@tonic-gate "%s`%s", dt_basename(objname), name); 13837c478bd9Sstevel@tonic-gate } 1384187eccf8Sbmc } else if (str != NULL && str[0] != '\0' && str[0] != '@' && 1385*aea65018SDave Pacheco (P == NULL || (map = Paddr_to_map(P, pc[i])) == NULL || 1386*aea65018SDave Pacheco map->pr_mflags & MA_WRITE)) { 1387a1b5e537Sbmc /* 1388a1b5e537Sbmc * If the current string pointer in the string table 1389a1b5e537Sbmc * does not point to an empty string _and_ the program 1390a1b5e537Sbmc * counter falls in a writable region, we'll use the 1391a1b5e537Sbmc * string from the string table instead of the raw 1392a1b5e537Sbmc * address. This last condition is necessary because 1393a1b5e537Sbmc * some (broken) ustack helpers will return a string 1394a1b5e537Sbmc * even for a program counter that they can't 1395a1b5e537Sbmc * identify. If we have a string for a program 1396a1b5e537Sbmc * counter that falls in a segment that isn't 1397a1b5e537Sbmc * writable, we assume that we have fallen into this 1398*aea65018SDave Pacheco * case and we refuse to use the string. Finally, 1399*aea65018SDave Pacheco * note that if we could not grab the process (e.g., 1400*aea65018SDave Pacheco * because it exited), the information from the helper 1401*aea65018SDave Pacheco * is better than nothing. 1402a1b5e537Sbmc */ 14037c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s", str); 14047c478bd9Sstevel@tonic-gate } else { 14057c478bd9Sstevel@tonic-gate if (P != NULL && Pobjname(P, pc[i], objname, 14067c478bd9Sstevel@tonic-gate sizeof (objname)) != NULL) { 14077c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx", 14087c478bd9Sstevel@tonic-gate dt_basename(objname), (u_longlong_t)pc[i]); 14097c478bd9Sstevel@tonic-gate } else { 14107c478bd9Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "0x%llx", 14117c478bd9Sstevel@tonic-gate (u_longlong_t)pc[i]); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate } 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, format, c)) < 0) 14167c478bd9Sstevel@tonic-gate break; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "\n")) < 0) 14197c478bd9Sstevel@tonic-gate break; 14207c478bd9Sstevel@tonic-gate 1421187eccf8Sbmc if (str != NULL && str[0] == '@') { 1422187eccf8Sbmc /* 1423187eccf8Sbmc * If the first character of the string is an "at" sign, 1424187eccf8Sbmc * then the string is inferred to be an annotation -- 1425187eccf8Sbmc * and it is printed out beneath the frame and offset 1426187eccf8Sbmc * with brackets. 1427187eccf8Sbmc */ 1428187eccf8Sbmc if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0) 1429187eccf8Sbmc break; 1430187eccf8Sbmc 1431187eccf8Sbmc (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]); 1432187eccf8Sbmc 1433187eccf8Sbmc if ((err = dt_printf(dtp, fp, format, c)) < 0) 1434187eccf8Sbmc break; 1435187eccf8Sbmc 1436187eccf8Sbmc if ((err = dt_printf(dtp, fp, "\n")) < 0) 1437187eccf8Sbmc break; 1438187eccf8Sbmc } 1439187eccf8Sbmc 14407c478bd9Sstevel@tonic-gate if (str != NULL) { 14417c478bd9Sstevel@tonic-gate str += strlen(str) + 1; 14427c478bd9Sstevel@tonic-gate if (str - strbase >= strsize) 14437c478bd9Sstevel@tonic-gate str = NULL; 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate if (P != NULL) { 14487c478bd9Sstevel@tonic-gate dt_proc_unlock(dtp, P); 14497c478bd9Sstevel@tonic-gate dt_proc_release(dtp, P); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate return (err); 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 1455a1b5e537Sbmc static int 1456a1b5e537Sbmc dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act) 1457a1b5e537Sbmc { 1458a1b5e537Sbmc /* LINTED - alignment */ 1459a1b5e537Sbmc uint64_t pid = ((uint64_t *)addr)[0]; 1460a1b5e537Sbmc /* LINTED - alignment */ 1461a1b5e537Sbmc uint64_t pc = ((uint64_t *)addr)[1]; 1462a1b5e537Sbmc const char *format = " %-50s"; 1463a1b5e537Sbmc char *s; 1464a1b5e537Sbmc int n, len = 256; 1465a1b5e537Sbmc 1466a1b5e537Sbmc if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) { 1467a1b5e537Sbmc struct ps_prochandle *P; 1468a1b5e537Sbmc 1469a1b5e537Sbmc if ((P = dt_proc_grab(dtp, pid, 1470a1b5e537Sbmc PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) { 1471a1b5e537Sbmc GElf_Sym sym; 1472a1b5e537Sbmc 1473a1b5e537Sbmc dt_proc_lock(dtp, P); 1474a1b5e537Sbmc 1475a1b5e537Sbmc if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0) 1476a1b5e537Sbmc pc = sym.st_value; 1477a1b5e537Sbmc 1478a1b5e537Sbmc dt_proc_unlock(dtp, P); 1479a1b5e537Sbmc dt_proc_release(dtp, P); 1480a1b5e537Sbmc } 1481a1b5e537Sbmc } 1482a1b5e537Sbmc 1483a1b5e537Sbmc do { 1484a1b5e537Sbmc n = len; 1485a1b5e537Sbmc s = alloca(n); 148696400bb6SJonathan Haslam } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n); 1487a1b5e537Sbmc 1488a1b5e537Sbmc return (dt_printf(dtp, fp, format, s)); 1489a1b5e537Sbmc } 1490a1b5e537Sbmc 1491a1b5e537Sbmc int 1492a1b5e537Sbmc dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1493a1b5e537Sbmc { 1494a1b5e537Sbmc /* LINTED - alignment */ 1495a1b5e537Sbmc uint64_t pid = ((uint64_t *)addr)[0]; 1496a1b5e537Sbmc /* LINTED - alignment */ 1497a1b5e537Sbmc uint64_t pc = ((uint64_t *)addr)[1]; 1498a1b5e537Sbmc int err = 0; 1499a1b5e537Sbmc 1500a1b5e537Sbmc char objname[PATH_MAX], c[PATH_MAX * 2]; 1501a1b5e537Sbmc struct ps_prochandle *P; 1502a1b5e537Sbmc 1503a1b5e537Sbmc if (format == NULL) 1504a1b5e537Sbmc format = " %-50s"; 1505a1b5e537Sbmc 1506a1b5e537Sbmc /* 1507a1b5e537Sbmc * See the comment in dt_print_ustack() for the rationale for 1508a1b5e537Sbmc * printing raw addresses in the vectored case. 1509a1b5e537Sbmc */ 1510a1b5e537Sbmc if (dtp->dt_vector == NULL) 1511a1b5e537Sbmc P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 1512a1b5e537Sbmc else 1513a1b5e537Sbmc P = NULL; 1514a1b5e537Sbmc 1515a1b5e537Sbmc if (P != NULL) 1516a1b5e537Sbmc dt_proc_lock(dtp, P); /* lock handle while we perform lookups */ 1517a1b5e537Sbmc 1518a1b5e537Sbmc if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != NULL) { 1519a1b5e537Sbmc (void) snprintf(c, sizeof (c), "%s", dt_basename(objname)); 1520a1b5e537Sbmc } else { 1521a1b5e537Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1522a1b5e537Sbmc } 1523a1b5e537Sbmc 1524a1b5e537Sbmc err = dt_printf(dtp, fp, format, c); 1525a1b5e537Sbmc 1526a1b5e537Sbmc if (P != NULL) { 1527a1b5e537Sbmc dt_proc_unlock(dtp, P); 1528a1b5e537Sbmc dt_proc_release(dtp, P); 1529a1b5e537Sbmc } 1530a1b5e537Sbmc 1531a1b5e537Sbmc return (err); 1532a1b5e537Sbmc } 1533a1b5e537Sbmc 1534a1b5e537Sbmc static int 1535a1b5e537Sbmc dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1536a1b5e537Sbmc { 1537a1b5e537Sbmc /* LINTED - alignment */ 1538a1b5e537Sbmc uint64_t pc = *((uint64_t *)addr); 1539a1b5e537Sbmc dtrace_syminfo_t dts; 1540a1b5e537Sbmc GElf_Sym sym; 1541a1b5e537Sbmc char c[PATH_MAX * 2]; 1542a1b5e537Sbmc 1543a1b5e537Sbmc if (format == NULL) 1544a1b5e537Sbmc format = " %-50s"; 1545a1b5e537Sbmc 1546a1b5e537Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) { 1547a1b5e537Sbmc (void) snprintf(c, sizeof (c), "%s`%s", 1548a1b5e537Sbmc dts.dts_object, dts.dts_name); 1549a1b5e537Sbmc } else { 1550a1b5e537Sbmc /* 1551a1b5e537Sbmc * We'll repeat the lookup, but this time we'll specify a 1552a1b5e537Sbmc * NULL GElf_Sym -- indicating that we're only interested in 1553a1b5e537Sbmc * the containing module. 1554a1b5e537Sbmc */ 1555a1b5e537Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1556a1b5e537Sbmc (void) snprintf(c, sizeof (c), "%s`0x%llx", 1557a1b5e537Sbmc dts.dts_object, (u_longlong_t)pc); 1558a1b5e537Sbmc } else { 1559a1b5e537Sbmc (void) snprintf(c, sizeof (c), "0x%llx", 1560a1b5e537Sbmc (u_longlong_t)pc); 1561a1b5e537Sbmc } 1562a1b5e537Sbmc } 1563a1b5e537Sbmc 1564a1b5e537Sbmc if (dt_printf(dtp, fp, format, c) < 0) 1565a1b5e537Sbmc return (-1); 1566a1b5e537Sbmc 1567a1b5e537Sbmc return (0); 1568a1b5e537Sbmc } 1569a1b5e537Sbmc 1570a1b5e537Sbmc int 1571a1b5e537Sbmc dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr) 1572a1b5e537Sbmc { 1573a1b5e537Sbmc /* LINTED - alignment */ 1574a1b5e537Sbmc uint64_t pc = *((uint64_t *)addr); 1575a1b5e537Sbmc dtrace_syminfo_t dts; 1576a1b5e537Sbmc char c[PATH_MAX * 2]; 1577a1b5e537Sbmc 1578a1b5e537Sbmc if (format == NULL) 1579a1b5e537Sbmc format = " %-50s"; 1580a1b5e537Sbmc 1581a1b5e537Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) { 1582a1b5e537Sbmc (void) snprintf(c, sizeof (c), "%s", dts.dts_object); 1583a1b5e537Sbmc } else { 1584a1b5e537Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc); 1585a1b5e537Sbmc } 1586a1b5e537Sbmc 1587a1b5e537Sbmc if (dt_printf(dtp, fp, format, c) < 0) 1588a1b5e537Sbmc return (-1); 1589a1b5e537Sbmc 1590a1b5e537Sbmc return (0); 1591a1b5e537Sbmc } 1592a1b5e537Sbmc 15937c478bd9Sstevel@tonic-gate typedef struct dt_normal { 15947c478bd9Sstevel@tonic-gate dtrace_aggvarid_t dtnd_id; 15957c478bd9Sstevel@tonic-gate uint64_t dtnd_normal; 15967c478bd9Sstevel@tonic-gate } dt_normal_t; 15977c478bd9Sstevel@tonic-gate 15987c478bd9Sstevel@tonic-gate static int 1599a1b5e537Sbmc dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 16007c478bd9Sstevel@tonic-gate { 16017c478bd9Sstevel@tonic-gate dt_normal_t *normal = arg; 16027c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 16037c478bd9Sstevel@tonic-gate dtrace_aggvarid_t id = normal->dtnd_id; 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 16067c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 16077c478bd9Sstevel@tonic-gate 160830ef842dSbmc if (agg->dtagd_varid != id) 16097c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 16107c478bd9Sstevel@tonic-gate 1611a1b5e537Sbmc ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal; 16127c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NORMALIZE); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate static int 16167c478bd9Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate dt_normal_t normal; 16197c478bd9Sstevel@tonic-gate caddr_t addr; 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 16237c478bd9Sstevel@tonic-gate * normalization value. 16247c478bd9Sstevel@tonic-gate */ 16257c478bd9Sstevel@tonic-gate addr = base + rec->dtrd_offset; 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 16287c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 16317c478bd9Sstevel@tonic-gate normal.dtnd_id = *((dtrace_aggvarid_t *)addr); 16327c478bd9Sstevel@tonic-gate rec++; 16337c478bd9Sstevel@tonic-gate 16347c478bd9Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 16357c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_NORMALIZE) 16387c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate addr = base + rec->dtrd_offset; 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate switch (rec->dtrd_size) { 16437c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 16447c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 16457c478bd9Sstevel@tonic-gate normal.dtnd_normal = *((uint64_t *)addr); 16467c478bd9Sstevel@tonic-gate break; 16477c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 16487c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 16497c478bd9Sstevel@tonic-gate normal.dtnd_normal = *((uint32_t *)addr); 16507c478bd9Sstevel@tonic-gate break; 16517c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 16527c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 16537c478bd9Sstevel@tonic-gate normal.dtnd_normal = *((uint16_t *)addr); 16547c478bd9Sstevel@tonic-gate break; 16557c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 16567c478bd9Sstevel@tonic-gate normal.dtnd_normal = *((uint8_t *)addr); 16577c478bd9Sstevel@tonic-gate break; 16587c478bd9Sstevel@tonic-gate default: 16597c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal); 16637c478bd9Sstevel@tonic-gate 16647c478bd9Sstevel@tonic-gate return (0); 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate static int 1668a1b5e537Sbmc dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg) 16697c478bd9Sstevel@tonic-gate { 16707c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 16717c478bd9Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 16747c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 16757c478bd9Sstevel@tonic-gate 167630ef842dSbmc if (agg->dtagd_varid != id) 16777c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 16787c478bd9Sstevel@tonic-gate 16797c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_DENORMALIZE); 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate static int 1683a1b5e537Sbmc dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg) 16847c478bd9Sstevel@tonic-gate { 16857c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 16867c478bd9Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg); 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 16897c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 16907c478bd9Sstevel@tonic-gate 169130ef842dSbmc if (agg->dtagd_varid != id) 16927c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_CLEAR); 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate typedef struct dt_trunc { 16987c478bd9Sstevel@tonic-gate dtrace_aggvarid_t dttd_id; 16997c478bd9Sstevel@tonic-gate uint64_t dttd_remaining; 17007c478bd9Sstevel@tonic-gate } dt_trunc_t; 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate static int 1703a1b5e537Sbmc dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg) 17047c478bd9Sstevel@tonic-gate { 17057c478bd9Sstevel@tonic-gate dt_trunc_t *trunc = arg; 17067c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc; 17077c478bd9Sstevel@tonic-gate dtrace_aggvarid_t id = trunc->dttd_id; 17087c478bd9Sstevel@tonic-gate 17097c478bd9Sstevel@tonic-gate if (agg->dtagd_nrecs == 0) 17107c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 17117c478bd9Sstevel@tonic-gate 171230ef842dSbmc if (agg->dtagd_varid != id) 17137c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate if (trunc->dttd_remaining == 0) 17167c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_REMOVE); 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate trunc->dttd_remaining--; 17197c478bd9Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT); 17207c478bd9Sstevel@tonic-gate } 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate static int 17237c478bd9Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec) 17247c478bd9Sstevel@tonic-gate { 17257c478bd9Sstevel@tonic-gate dt_trunc_t trunc; 17267c478bd9Sstevel@tonic-gate caddr_t addr; 17277c478bd9Sstevel@tonic-gate int64_t remaining; 17287c478bd9Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate /* 17317c478bd9Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the 17327c478bd9Sstevel@tonic-gate * number of aggregation entries after which the aggregation is to be 17337c478bd9Sstevel@tonic-gate * truncated. 17347c478bd9Sstevel@tonic-gate */ 17357c478bd9Sstevel@tonic-gate addr = base + rec->dtrd_offset; 17367c478bd9Sstevel@tonic-gate 17377c478bd9Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t)) 17387c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 17417c478bd9Sstevel@tonic-gate trunc.dttd_id = *((dtrace_aggvarid_t *)addr); 17427c478bd9Sstevel@tonic-gate rec++; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT) 17457c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_TRUNC) 17487c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC)); 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate addr = base + rec->dtrd_offset; 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate switch (rec->dtrd_size) { 17537c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 17547c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 17557c478bd9Sstevel@tonic-gate remaining = *((int64_t *)addr); 17567c478bd9Sstevel@tonic-gate break; 17577c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 17587c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 17597c478bd9Sstevel@tonic-gate remaining = *((int32_t *)addr); 17607c478bd9Sstevel@tonic-gate break; 17617c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 17627c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 17637c478bd9Sstevel@tonic-gate remaining = *((int16_t *)addr); 17647c478bd9Sstevel@tonic-gate break; 17657c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 17667c478bd9Sstevel@tonic-gate remaining = *((int8_t *)addr); 17677c478bd9Sstevel@tonic-gate break; 17687c478bd9Sstevel@tonic-gate default: 17697c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL)); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate if (remaining < 0) { 17737c478bd9Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted; 17747c478bd9Sstevel@tonic-gate remaining = -remaining; 17757c478bd9Sstevel@tonic-gate } else { 17767c478bd9Sstevel@tonic-gate func = dtrace_aggregate_walk_valrevsorted; 17777c478bd9Sstevel@tonic-gate } 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate assert(remaining >= 0); 17807c478bd9Sstevel@tonic-gate trunc.dttd_remaining = remaining; 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate (void) func(dtp, dt_trunc_agg, &trunc); 17837c478bd9Sstevel@tonic-gate 17847c478bd9Sstevel@tonic-gate return (0); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 178730ef842dSbmc static int 178830ef842dSbmc dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec, 178933093f5bSBryan Cantrill caddr_t addr, size_t size, const dtrace_aggdata_t *aggdata, 179033093f5bSBryan Cantrill uint64_t normal, dt_print_aggdata_t *pd) 17917c478bd9Sstevel@tonic-gate { 179233093f5bSBryan Cantrill int err, width; 17937c478bd9Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 179433093f5bSBryan Cantrill boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack; 179533093f5bSBryan Cantrill dtrace_aggdesc_t *agg = aggdata->dtada_desc; 179633093f5bSBryan Cantrill 179733093f5bSBryan Cantrill static struct { 179833093f5bSBryan Cantrill size_t size; 179933093f5bSBryan Cantrill int width; 180033093f5bSBryan Cantrill int packedwidth; 180133093f5bSBryan Cantrill } *fmt, fmttab[] = { 180233093f5bSBryan Cantrill { sizeof (uint8_t), 3, 3 }, 180333093f5bSBryan Cantrill { sizeof (uint16_t), 5, 5 }, 180433093f5bSBryan Cantrill { sizeof (uint32_t), 8, 8 }, 180533093f5bSBryan Cantrill { sizeof (uint64_t), 16, 16 }, 180633093f5bSBryan Cantrill { 0, -50, 16 } 180733093f5bSBryan Cantrill }; 180833093f5bSBryan Cantrill 180933093f5bSBryan Cantrill if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid) { 181033093f5bSBryan Cantrill dtrace_recdesc_t *r; 181133093f5bSBryan Cantrill 181233093f5bSBryan Cantrill width = 0; 181333093f5bSBryan Cantrill 181433093f5bSBryan Cantrill /* 181533093f5bSBryan Cantrill * To print our quantization header for either an agghist or 181633093f5bSBryan Cantrill * aggpack aggregation, we need to iterate through all of our 181733093f5bSBryan Cantrill * of our records to determine their width. 181833093f5bSBryan Cantrill */ 181933093f5bSBryan Cantrill for (r = rec; !DTRACEACT_ISAGG(r->dtrd_action); r++) { 182033093f5bSBryan Cantrill for (fmt = fmttab; fmt->size && 182133093f5bSBryan Cantrill fmt->size != r->dtrd_size; fmt++) 182233093f5bSBryan Cantrill continue; 182333093f5bSBryan Cantrill 182433093f5bSBryan Cantrill width += fmt->packedwidth + 1; 182533093f5bSBryan Cantrill } 182633093f5bSBryan Cantrill 182733093f5bSBryan Cantrill if (pd->dtpa_agghist) { 182833093f5bSBryan Cantrill if (dt_print_quanthdr(dtp, fp, width) < 0) 182933093f5bSBryan Cantrill return (-1); 183033093f5bSBryan Cantrill } else { 183133093f5bSBryan Cantrill if (dt_print_quanthdr_packed(dtp, fp, 183233093f5bSBryan Cantrill width, aggdata, r->dtrd_action) < 0) 183333093f5bSBryan Cantrill return (-1); 183433093f5bSBryan Cantrill } 183533093f5bSBryan Cantrill 183633093f5bSBryan Cantrill pd->dtpa_agghisthdr = agg->dtagd_varid; 183733093f5bSBryan Cantrill } 183833093f5bSBryan Cantrill 183933093f5bSBryan Cantrill if (pd->dtpa_agghist && DTRACEACT_ISAGG(act)) { 184033093f5bSBryan Cantrill char positives = aggdata->dtada_flags & DTRACE_A_HASPOSITIVES; 184133093f5bSBryan Cantrill char negatives = aggdata->dtada_flags & DTRACE_A_HASNEGATIVES; 184233093f5bSBryan Cantrill int64_t val; 184333093f5bSBryan Cantrill 184433093f5bSBryan Cantrill assert(act == DTRACEAGG_SUM || act == DTRACEAGG_COUNT); 184533093f5bSBryan Cantrill val = (long long)*((uint64_t *)addr); 184633093f5bSBryan Cantrill 184733093f5bSBryan Cantrill if (dt_printf(dtp, fp, " ") < 0) 184833093f5bSBryan Cantrill return (-1); 184933093f5bSBryan Cantrill 185033093f5bSBryan Cantrill return (dt_print_quantline(dtp, fp, val, normal, 185133093f5bSBryan Cantrill aggdata->dtada_total, positives, negatives)); 185233093f5bSBryan Cantrill } 185333093f5bSBryan Cantrill 185433093f5bSBryan Cantrill if (pd->dtpa_aggpack && DTRACEACT_ISAGG(act)) { 185533093f5bSBryan Cantrill switch (act) { 185633093f5bSBryan Cantrill case DTRACEAGG_QUANTIZE: 185733093f5bSBryan Cantrill return (dt_print_quantize_packed(dtp, 185833093f5bSBryan Cantrill fp, addr, size, aggdata)); 185933093f5bSBryan Cantrill case DTRACEAGG_LQUANTIZE: 186033093f5bSBryan Cantrill return (dt_print_lquantize_packed(dtp, 186133093f5bSBryan Cantrill fp, addr, size, aggdata)); 186233093f5bSBryan Cantrill default: 186333093f5bSBryan Cantrill break; 186433093f5bSBryan Cantrill } 186533093f5bSBryan Cantrill } 18667c478bd9Sstevel@tonic-gate 186730ef842dSbmc switch (act) { 186830ef842dSbmc case DTRACEACT_STACK: 186930ef842dSbmc return (dt_print_stack(dtp, fp, NULL, addr, 187030ef842dSbmc rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg)); 18717c478bd9Sstevel@tonic-gate 187230ef842dSbmc case DTRACEACT_USTACK: 187330ef842dSbmc case DTRACEACT_JSTACK: 187430ef842dSbmc return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg)); 18757c478bd9Sstevel@tonic-gate 187630ef842dSbmc case DTRACEACT_USYM: 187730ef842dSbmc case DTRACEACT_UADDR: 187830ef842dSbmc return (dt_print_usym(dtp, fp, addr, act)); 18797c478bd9Sstevel@tonic-gate 188030ef842dSbmc case DTRACEACT_UMOD: 188130ef842dSbmc return (dt_print_umod(dtp, fp, NULL, addr)); 1882a1b5e537Sbmc 188330ef842dSbmc case DTRACEACT_SYM: 188430ef842dSbmc return (dt_print_sym(dtp, fp, NULL, addr)); 1885a1b5e537Sbmc 188630ef842dSbmc case DTRACEACT_MOD: 188730ef842dSbmc return (dt_print_mod(dtp, fp, NULL, addr)); 1888a1b5e537Sbmc 188930ef842dSbmc case DTRACEAGG_QUANTIZE: 189030ef842dSbmc return (dt_print_quantize(dtp, fp, addr, size, normal)); 1891a1b5e537Sbmc 189230ef842dSbmc case DTRACEAGG_LQUANTIZE: 189330ef842dSbmc return (dt_print_lquantize(dtp, fp, addr, size, normal)); 18947c478bd9Sstevel@tonic-gate 18952b6389efSBryan Cantrill case DTRACEAGG_LLQUANTIZE: 18962b6389efSBryan Cantrill return (dt_print_llquantize(dtp, fp, addr, size, normal)); 18972b6389efSBryan Cantrill 189830ef842dSbmc case DTRACEAGG_AVG: 189930ef842dSbmc return (dt_print_average(dtp, fp, addr, size, normal)); 19007c478bd9Sstevel@tonic-gate 19016e0bee74Sjhaslam case DTRACEAGG_STDDEV: 19026e0bee74Sjhaslam return (dt_print_stddev(dtp, fp, addr, size, normal)); 19036e0bee74Sjhaslam 190430ef842dSbmc default: 190530ef842dSbmc break; 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate 190833093f5bSBryan Cantrill for (fmt = fmttab; fmt->size && fmt->size != size; fmt++) 190933093f5bSBryan Cantrill continue; 191033093f5bSBryan Cantrill 191133093f5bSBryan Cantrill width = packed ? fmt->packedwidth : fmt->width; 191233093f5bSBryan Cantrill 19137c478bd9Sstevel@tonic-gate switch (size) { 19147c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 191533093f5bSBryan Cantrill err = dt_printf(dtp, fp, " %*lld", width, 19167c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 19177c478bd9Sstevel@tonic-gate (long long)*((uint64_t *)addr) / normal); 19187c478bd9Sstevel@tonic-gate break; 19197c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 19207c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 192133093f5bSBryan Cantrill err = dt_printf(dtp, fp, " %*d", width, *((uint32_t *)addr) / 19227c478bd9Sstevel@tonic-gate (uint32_t)normal); 19237c478bd9Sstevel@tonic-gate break; 19247c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 19257c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 192633093f5bSBryan Cantrill err = dt_printf(dtp, fp, " %*d", width, *((uint16_t *)addr) / 19277c478bd9Sstevel@tonic-gate (uint32_t)normal); 19287c478bd9Sstevel@tonic-gate break; 19297c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 193033093f5bSBryan Cantrill err = dt_printf(dtp, fp, " %*d", width, *((uint8_t *)addr) / 19317c478bd9Sstevel@tonic-gate (uint32_t)normal); 19327c478bd9Sstevel@tonic-gate break; 19337c478bd9Sstevel@tonic-gate default: 193433093f5bSBryan Cantrill err = dt_print_bytes(dtp, fp, addr, size, width, 0, 0); 19357c478bd9Sstevel@tonic-gate break; 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 193830ef842dSbmc return (err); 193930ef842dSbmc } 194030ef842dSbmc 194130ef842dSbmc int 194230ef842dSbmc dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg) 194330ef842dSbmc { 194430ef842dSbmc int i, aggact = 0; 194530ef842dSbmc dt_print_aggdata_t *pd = arg; 194630ef842dSbmc const dtrace_aggdata_t *aggdata = aggsdata[0]; 194730ef842dSbmc dtrace_aggdesc_t *agg = aggdata->dtada_desc; 194830ef842dSbmc FILE *fp = pd->dtpa_fp; 194930ef842dSbmc dtrace_hdl_t *dtp = pd->dtpa_dtp; 195030ef842dSbmc dtrace_recdesc_t *rec; 195130ef842dSbmc dtrace_actkind_t act; 195230ef842dSbmc caddr_t addr; 195330ef842dSbmc size_t size; 195430ef842dSbmc 195533093f5bSBryan Cantrill pd->dtpa_agghist = (aggdata->dtada_flags & DTRACE_A_TOTAL); 195633093f5bSBryan Cantrill pd->dtpa_aggpack = (aggdata->dtada_flags & DTRACE_A_MINMAXBIN); 195733093f5bSBryan Cantrill 195830ef842dSbmc /* 195930ef842dSbmc * Iterate over each record description in the key, printing the traced 196030ef842dSbmc * data, skipping the first datum (the tuple member created by the 196130ef842dSbmc * compiler). 196230ef842dSbmc */ 196330ef842dSbmc for (i = 1; i < agg->dtagd_nrecs; i++) { 196430ef842dSbmc rec = &agg->dtagd_rec[i]; 196530ef842dSbmc act = rec->dtrd_action; 196630ef842dSbmc addr = aggdata->dtada_data + rec->dtrd_offset; 196730ef842dSbmc size = rec->dtrd_size; 196830ef842dSbmc 196930ef842dSbmc if (DTRACEACT_ISAGG(act)) { 197030ef842dSbmc aggact = i; 197130ef842dSbmc break; 197230ef842dSbmc } 197330ef842dSbmc 197433093f5bSBryan Cantrill if (dt_print_datum(dtp, fp, rec, addr, 197533093f5bSBryan Cantrill size, aggdata, 1, pd) < 0) 197630ef842dSbmc return (-1); 197730ef842dSbmc 197830ef842dSbmc if (dt_buffered_flush(dtp, NULL, rec, aggdata, 197930ef842dSbmc DTRACE_BUFDATA_AGGKEY) < 0) 19807c478bd9Sstevel@tonic-gate return (-1); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 198330ef842dSbmc assert(aggact != 0); 19847c478bd9Sstevel@tonic-gate 198530ef842dSbmc for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) { 198630ef842dSbmc uint64_t normal; 198730ef842dSbmc 198830ef842dSbmc aggdata = aggsdata[i]; 198930ef842dSbmc agg = aggdata->dtada_desc; 199030ef842dSbmc rec = &agg->dtagd_rec[aggact]; 199130ef842dSbmc act = rec->dtrd_action; 199230ef842dSbmc addr = aggdata->dtada_data + rec->dtrd_offset; 199330ef842dSbmc size = rec->dtrd_size; 199430ef842dSbmc 199530ef842dSbmc assert(DTRACEACT_ISAGG(act)); 199630ef842dSbmc normal = aggdata->dtada_normal; 199730ef842dSbmc 199833093f5bSBryan Cantrill if (dt_print_datum(dtp, fp, rec, addr, 199933093f5bSBryan Cantrill size, aggdata, normal, pd) < 0) 200030ef842dSbmc return (-1); 200130ef842dSbmc 200230ef842dSbmc if (dt_buffered_flush(dtp, NULL, rec, aggdata, 200330ef842dSbmc DTRACE_BUFDATA_AGGVAL) < 0) 20047c478bd9Sstevel@tonic-gate return (-1); 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate if (!pd->dtpa_allunprint) 20077c478bd9Sstevel@tonic-gate agg->dtagd_flags |= DTRACE_AGD_PRINTED; 20087c478bd9Sstevel@tonic-gate } 20097c478bd9Sstevel@tonic-gate 201033093f5bSBryan Cantrill if (!pd->dtpa_agghist && !pd->dtpa_aggpack) { 201130ef842dSbmc if (dt_printf(dtp, fp, "\n") < 0) 201230ef842dSbmc return (-1); 201333093f5bSBryan Cantrill } 201430ef842dSbmc 201530ef842dSbmc if (dt_buffered_flush(dtp, NULL, NULL, aggdata, 201630ef842dSbmc DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) 201730ef842dSbmc return (-1); 201830ef842dSbmc 201930ef842dSbmc return (0); 202030ef842dSbmc } 202130ef842dSbmc 202230ef842dSbmc int 202330ef842dSbmc dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg) 202430ef842dSbmc { 202530ef842dSbmc dt_print_aggdata_t *pd = arg; 202630ef842dSbmc dtrace_aggdesc_t *agg = aggdata->dtada_desc; 202730ef842dSbmc dtrace_aggvarid_t aggvarid = pd->dtpa_id; 202830ef842dSbmc 202930ef842dSbmc if (pd->dtpa_allunprint) { 203030ef842dSbmc if (agg->dtagd_flags & DTRACE_AGD_PRINTED) 203130ef842dSbmc return (0); 203230ef842dSbmc } else { 203330ef842dSbmc /* 203430ef842dSbmc * If we're not printing all unprinted aggregations, then the 203530ef842dSbmc * aggregation variable ID denotes a specific aggregation 203630ef842dSbmc * variable that we should print -- skip any other aggregations 203730ef842dSbmc * that we encounter. 203830ef842dSbmc */ 203930ef842dSbmc if (agg->dtagd_nrecs == 0) 204030ef842dSbmc return (0); 204130ef842dSbmc 204230ef842dSbmc if (aggvarid != agg->dtagd_varid) 204330ef842dSbmc return (0); 204430ef842dSbmc } 204530ef842dSbmc 204630ef842dSbmc return (dt_print_aggs(&aggdata, 1, arg)); 204730ef842dSbmc } 2048a1b5e537Sbmc 2049a1b5e537Sbmc int 2050a1b5e537Sbmc dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data, 2051a1b5e537Sbmc const char *option, const char *value) 2052a1b5e537Sbmc { 2053a1b5e537Sbmc int len, rval; 2054a1b5e537Sbmc char *msg; 2055a1b5e537Sbmc const char *errstr; 2056a1b5e537Sbmc dtrace_setoptdata_t optdata; 2057a1b5e537Sbmc 2058a1b5e537Sbmc bzero(&optdata, sizeof (optdata)); 2059a1b5e537Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval); 2060a1b5e537Sbmc 2061a1b5e537Sbmc if (dtrace_setopt(dtp, option, value) == 0) { 2062a1b5e537Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval); 2063a1b5e537Sbmc optdata.dtsda_probe = data; 2064a1b5e537Sbmc optdata.dtsda_option = option; 2065a1b5e537Sbmc optdata.dtsda_handle = dtp; 2066a1b5e537Sbmc 2067a1b5e537Sbmc if ((rval = dt_handle_setopt(dtp, &optdata)) != 0) 2068a1b5e537Sbmc return (rval); 2069a1b5e537Sbmc 2070a1b5e537Sbmc return (0); 2071a1b5e537Sbmc } 2072a1b5e537Sbmc 2073a1b5e537Sbmc errstr = dtrace_errmsg(dtp, dtrace_errno(dtp)); 2074a1b5e537Sbmc len = strlen(option) + strlen(value) + strlen(errstr) + 80; 2075a1b5e537Sbmc msg = alloca(len); 2076a1b5e537Sbmc 2077a1b5e537Sbmc (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n", 2078a1b5e537Sbmc option, value, errstr); 2079a1b5e537Sbmc 2080a1b5e537Sbmc if ((rval = dt_handle_liberr(dtp, data, msg)) == 0) 2081a1b5e537Sbmc return (0); 2082a1b5e537Sbmc 2083a1b5e537Sbmc return (rval); 2084a1b5e537Sbmc } 2085a1b5e537Sbmc 20867c478bd9Sstevel@tonic-gate static int 2087e5803b76SAdam H. Leventhal dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, 2088e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf, boolean_t just_one, 20897c478bd9Sstevel@tonic-gate dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg) 20907c478bd9Sstevel@tonic-gate { 20917c478bd9Sstevel@tonic-gate dtrace_epid_t id; 2092e5803b76SAdam H. Leventhal size_t offs; 20937c478bd9Sstevel@tonic-gate int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET); 20947c478bd9Sstevel@tonic-gate int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET); 20957c478bd9Sstevel@tonic-gate int rval, i, n; 20961ea5f93dSBryan Cantrill uint64_t tracememsize = 0; 20977c478bd9Sstevel@tonic-gate dtrace_probedata_t data; 20987c478bd9Sstevel@tonic-gate uint64_t drops; 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate bzero(&data, sizeof (data)); 21017c478bd9Sstevel@tonic-gate data.dtpda_handle = dtp; 21027c478bd9Sstevel@tonic-gate data.dtpda_cpu = cpu; 2103e5803b76SAdam H. Leventhal data.dtpda_flow = dtp->dt_flow; 2104e5803b76SAdam H. Leventhal data.dtpda_indent = dtp->dt_indent; 2105e5803b76SAdam H. Leventhal data.dtpda_prefix = dtp->dt_prefix; 21067c478bd9Sstevel@tonic-gate 2107e5803b76SAdam H. Leventhal for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) { 21087c478bd9Sstevel@tonic-gate dtrace_eprobedesc_t *epd; 21097c478bd9Sstevel@tonic-gate 21107c478bd9Sstevel@tonic-gate /* 21117c478bd9Sstevel@tonic-gate * We're guaranteed to have an ID. 21127c478bd9Sstevel@tonic-gate */ 21137c478bd9Sstevel@tonic-gate id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs); 21147c478bd9Sstevel@tonic-gate 21157c478bd9Sstevel@tonic-gate if (id == DTRACE_EPIDNONE) { 21167c478bd9Sstevel@tonic-gate /* 21177c478bd9Sstevel@tonic-gate * This is filler to assure proper alignment of the 21187c478bd9Sstevel@tonic-gate * next record; we simply ignore it. 21197c478bd9Sstevel@tonic-gate */ 21207c478bd9Sstevel@tonic-gate offs += sizeof (id); 21217c478bd9Sstevel@tonic-gate continue; 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate 21247c478bd9Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc, 21257c478bd9Sstevel@tonic-gate &data.dtpda_pdesc)) != 0) 21267c478bd9Sstevel@tonic-gate return (rval); 21277c478bd9Sstevel@tonic-gate 21287c478bd9Sstevel@tonic-gate epd = data.dtpda_edesc; 21297c478bd9Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs; 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) { 21327c478bd9Sstevel@tonic-gate rval = dt_handle(dtp, &data); 21337c478bd9Sstevel@tonic-gate 21347c478bd9Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 21357c478bd9Sstevel@tonic-gate goto nextepid; 21367c478bd9Sstevel@tonic-gate 21377c478bd9Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ERROR) 21387c478bd9Sstevel@tonic-gate return (-1); 21397c478bd9Sstevel@tonic-gate } 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate if (flow) 2142e5803b76SAdam H. Leventhal (void) dt_flowindent(dtp, &data, dtp->dt_last_epid, 2143e5803b76SAdam H. Leventhal buf, offs); 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate rval = (*efunc)(&data, arg); 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate if (flow) { 21487c478bd9Sstevel@tonic-gate if (data.dtpda_flow == DTRACEFLOW_ENTRY) 21497c478bd9Sstevel@tonic-gate data.dtpda_indent += 2; 21507c478bd9Sstevel@tonic-gate } 21517c478bd9Sstevel@tonic-gate 21527c478bd9Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 21537c478bd9Sstevel@tonic-gate goto nextepid; 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 21567c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 21597c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate for (i = 0; i < epd->dtepd_nrecs; i++) { 2162e5803b76SAdam H. Leventhal caddr_t addr; 21637c478bd9Sstevel@tonic-gate dtrace_recdesc_t *rec = &epd->dtepd_rec[i]; 21647c478bd9Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action; 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs + 21677c478bd9Sstevel@tonic-gate rec->dtrd_offset; 21687c478bd9Sstevel@tonic-gate addr = data.dtpda_data; 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate if (act == DTRACEACT_LIBACT) { 2171a1b5e537Sbmc uint64_t arg = rec->dtrd_arg; 21727c478bd9Sstevel@tonic-gate dtrace_aggvarid_t id; 21737c478bd9Sstevel@tonic-gate 2174a1b5e537Sbmc switch (arg) { 2175a1b5e537Sbmc case DT_ACT_CLEAR: 21767c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 21777c478bd9Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 21787c478bd9Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 21797c478bd9Sstevel@tonic-gate dt_clear_agg, &id); 21807c478bd9Sstevel@tonic-gate continue; 21817c478bd9Sstevel@tonic-gate 2182a1b5e537Sbmc case DT_ACT_DENORMALIZE: 21837c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 21847c478bd9Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr); 21857c478bd9Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, 21867c478bd9Sstevel@tonic-gate dt_denormalize_agg, &id); 21877c478bd9Sstevel@tonic-gate continue; 21887c478bd9Sstevel@tonic-gate 2189a1b5e537Sbmc case DT_ACT_FTRUNCATE: 2190a1b5e537Sbmc if (fp == NULL) 2191a1b5e537Sbmc continue; 2192a1b5e537Sbmc 2193a1b5e537Sbmc (void) fflush(fp); 2194a1b5e537Sbmc (void) ftruncate(fileno(fp), 0); 2195a1b5e537Sbmc (void) fseeko(fp, 0, SEEK_SET); 2196a1b5e537Sbmc continue; 2197a1b5e537Sbmc 2198a1b5e537Sbmc case DT_ACT_NORMALIZE: 21997c478bd9Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 22007c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, 22017c478bd9Sstevel@tonic-gate EDT_BADNORMAL)); 22027c478bd9Sstevel@tonic-gate 22037c478bd9Sstevel@tonic-gate if (dt_normalize(dtp, 22047c478bd9Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 22057c478bd9Sstevel@tonic-gate return (-1); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate i++; 22087c478bd9Sstevel@tonic-gate continue; 2209a1b5e537Sbmc 2210a1b5e537Sbmc case DT_ACT_SETOPT: { 2211a1b5e537Sbmc uint64_t *opts = dtp->dt_options; 2212a1b5e537Sbmc dtrace_recdesc_t *valrec; 2213a1b5e537Sbmc uint32_t valsize; 2214a1b5e537Sbmc caddr_t val; 2215a1b5e537Sbmc int rv; 2216a1b5e537Sbmc 2217a1b5e537Sbmc if (i == epd->dtepd_nrecs - 1) { 2218a1b5e537Sbmc return (dt_set_errno(dtp, 2219a1b5e537Sbmc EDT_BADSETOPT)); 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate 2222a1b5e537Sbmc valrec = &epd->dtepd_rec[++i]; 2223a1b5e537Sbmc valsize = valrec->dtrd_size; 2224a1b5e537Sbmc 2225a1b5e537Sbmc if (valrec->dtrd_action != act || 2226a1b5e537Sbmc valrec->dtrd_arg != arg) { 2227a1b5e537Sbmc return (dt_set_errno(dtp, 2228a1b5e537Sbmc EDT_BADSETOPT)); 2229a1b5e537Sbmc } 2230a1b5e537Sbmc 2231a1b5e537Sbmc if (valsize > sizeof (uint64_t)) { 2232a1b5e537Sbmc val = buf->dtbd_data + offs + 2233a1b5e537Sbmc valrec->dtrd_offset; 2234a1b5e537Sbmc } else { 2235a1b5e537Sbmc val = "1"; 2236a1b5e537Sbmc } 2237a1b5e537Sbmc 2238a1b5e537Sbmc rv = dt_setopt(dtp, &data, addr, val); 2239a1b5e537Sbmc 2240a1b5e537Sbmc if (rv != 0) 2241a1b5e537Sbmc return (-1); 2242a1b5e537Sbmc 2243a1b5e537Sbmc flow = (opts[DTRACEOPT_FLOWINDENT] != 2244a1b5e537Sbmc DTRACEOPT_UNSET); 2245a1b5e537Sbmc quiet = (opts[DTRACEOPT_QUIET] != 2246a1b5e537Sbmc DTRACEOPT_UNSET); 2247a1b5e537Sbmc 2248a1b5e537Sbmc continue; 2249a1b5e537Sbmc } 2250a1b5e537Sbmc 2251a1b5e537Sbmc case DT_ACT_TRUNC: 22527c478bd9Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1) 22537c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, 22547c478bd9Sstevel@tonic-gate EDT_BADTRUNC)); 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate if (dt_trunc(dtp, 22577c478bd9Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0) 22587c478bd9Sstevel@tonic-gate return (-1); 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate i++; 22617c478bd9Sstevel@tonic-gate continue; 22627c478bd9Sstevel@tonic-gate 2263a1b5e537Sbmc default: 22647c478bd9Sstevel@tonic-gate continue; 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate } 22677c478bd9Sstevel@tonic-gate 22681ea5f93dSBryan Cantrill if (act == DTRACEACT_TRACEMEM_DYNSIZE && 22691ea5f93dSBryan Cantrill rec->dtrd_size == sizeof (uint64_t)) { 2270e7987fc3SRichard Lowe /* LINTED - alignment */ 22711ea5f93dSBryan Cantrill tracememsize = *((unsigned long long *)addr); 22721ea5f93dSBryan Cantrill continue; 22731ea5f93dSBryan Cantrill } 22741ea5f93dSBryan Cantrill 22757c478bd9Sstevel@tonic-gate rval = (*rfunc)(&data, rec, arg); 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT) 22787c478bd9Sstevel@tonic-gate continue; 22797c478bd9Sstevel@tonic-gate 22807c478bd9Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT) 22817c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 22827c478bd9Sstevel@tonic-gate 22837c478bd9Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS) 22847c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 22857c478bd9Sstevel@tonic-gate 22867c478bd9Sstevel@tonic-gate if (act == DTRACEACT_STACK) { 2287a1b5e537Sbmc int depth = rec->dtrd_arg; 2288a1b5e537Sbmc 2289a1b5e537Sbmc if (dt_print_stack(dtp, fp, NULL, addr, depth, 2290a1b5e537Sbmc rec->dtrd_size / depth) < 0) 22917c478bd9Sstevel@tonic-gate return (-1); 22927c478bd9Sstevel@tonic-gate goto nextrec; 22937c478bd9Sstevel@tonic-gate } 22947c478bd9Sstevel@tonic-gate 22957c478bd9Sstevel@tonic-gate if (act == DTRACEACT_USTACK || 22967c478bd9Sstevel@tonic-gate act == DTRACEACT_JSTACK) { 22977c478bd9Sstevel@tonic-gate if (dt_print_ustack(dtp, fp, NULL, 22987c478bd9Sstevel@tonic-gate addr, rec->dtrd_arg) < 0) 22997c478bd9Sstevel@tonic-gate return (-1); 23007c478bd9Sstevel@tonic-gate goto nextrec; 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate 2303a1b5e537Sbmc if (act == DTRACEACT_SYM) { 2304a1b5e537Sbmc if (dt_print_sym(dtp, fp, NULL, addr) < 0) 2305a1b5e537Sbmc return (-1); 2306a1b5e537Sbmc goto nextrec; 2307a1b5e537Sbmc } 2308a1b5e537Sbmc 2309a1b5e537Sbmc if (act == DTRACEACT_MOD) { 2310a1b5e537Sbmc if (dt_print_mod(dtp, fp, NULL, addr) < 0) 2311a1b5e537Sbmc return (-1); 2312a1b5e537Sbmc goto nextrec; 2313a1b5e537Sbmc } 2314a1b5e537Sbmc 2315a1b5e537Sbmc if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) { 2316a1b5e537Sbmc if (dt_print_usym(dtp, fp, addr, act) < 0) 2317a1b5e537Sbmc return (-1); 2318a1b5e537Sbmc goto nextrec; 2319a1b5e537Sbmc } 2320a1b5e537Sbmc 2321a1b5e537Sbmc if (act == DTRACEACT_UMOD) { 2322a1b5e537Sbmc if (dt_print_umod(dtp, fp, NULL, addr) < 0) 2323a1b5e537Sbmc return (-1); 2324a1b5e537Sbmc goto nextrec; 2325a1b5e537Sbmc } 2326a1b5e537Sbmc 23277c478bd9Sstevel@tonic-gate if (DTRACEACT_ISPRINTFLIKE(act)) { 23287c478bd9Sstevel@tonic-gate void *fmtdata; 23297c478bd9Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, FILE *, void *, 23307c478bd9Sstevel@tonic-gate const dtrace_probedata_t *, 23317c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *, uint_t, 23327c478bd9Sstevel@tonic-gate const void *buf, size_t); 23337c478bd9Sstevel@tonic-gate 23347c478bd9Sstevel@tonic-gate if ((fmtdata = dt_format_lookup(dtp, 23357c478bd9Sstevel@tonic-gate rec->dtrd_format)) == NULL) 23367c478bd9Sstevel@tonic-gate goto nofmt; 23377c478bd9Sstevel@tonic-gate 23387c478bd9Sstevel@tonic-gate switch (act) { 23397c478bd9Sstevel@tonic-gate case DTRACEACT_PRINTF: 23407c478bd9Sstevel@tonic-gate func = dtrace_fprintf; 23417c478bd9Sstevel@tonic-gate break; 23427c478bd9Sstevel@tonic-gate case DTRACEACT_PRINTA: 23437c478bd9Sstevel@tonic-gate func = dtrace_fprinta; 23447c478bd9Sstevel@tonic-gate break; 23457c478bd9Sstevel@tonic-gate case DTRACEACT_SYSTEM: 23467c478bd9Sstevel@tonic-gate func = dtrace_system; 23477c478bd9Sstevel@tonic-gate break; 23487c478bd9Sstevel@tonic-gate case DTRACEACT_FREOPEN: 23497c478bd9Sstevel@tonic-gate func = dtrace_freopen; 23507c478bd9Sstevel@tonic-gate break; 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate 23537c478bd9Sstevel@tonic-gate n = (*func)(dtp, fp, fmtdata, &data, 23547c478bd9Sstevel@tonic-gate rec, epd->dtepd_nrecs - i, 23557c478bd9Sstevel@tonic-gate (uchar_t *)buf->dtbd_data + offs, 23567c478bd9Sstevel@tonic-gate buf->dtbd_size - offs); 23577c478bd9Sstevel@tonic-gate 23587c478bd9Sstevel@tonic-gate if (n < 0) 23597c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 23607c478bd9Sstevel@tonic-gate 23617c478bd9Sstevel@tonic-gate if (n > 0) 23627c478bd9Sstevel@tonic-gate i += n - 1; 23637c478bd9Sstevel@tonic-gate goto nextrec; 23647c478bd9Sstevel@tonic-gate } 23657c478bd9Sstevel@tonic-gate 2366deef35fdSEric Schrock /* 2367deef35fdSEric Schrock * If this is a DIF expression, and the record has a 2368deef35fdSEric Schrock * format set, this indicates we have a CTF type name 2369deef35fdSEric Schrock * associated with the data and we should try to print 2370deef35fdSEric Schrock * it out by type. 2371deef35fdSEric Schrock */ 2372deef35fdSEric Schrock if (act == DTRACEACT_DIFEXPR) { 2373deef35fdSEric Schrock const char *strdata = dt_strdata_lookup(dtp, 2374deef35fdSEric Schrock rec->dtrd_format); 2375deef35fdSEric Schrock if (strdata != NULL) { 2376deef35fdSEric Schrock n = dtrace_print(dtp, fp, strdata, 2377deef35fdSEric Schrock addr, rec->dtrd_size); 2378deef35fdSEric Schrock 2379deef35fdSEric Schrock /* 2380deef35fdSEric Schrock * dtrace_print() will return -1 on 2381deef35fdSEric Schrock * error, or return the number of bytes 2382deef35fdSEric Schrock * consumed. It will return 0 if the 2383deef35fdSEric Schrock * type couldn't be determined, and we 2384deef35fdSEric Schrock * should fall through to the normal 2385deef35fdSEric Schrock * trace method. 2386deef35fdSEric Schrock */ 2387deef35fdSEric Schrock if (n < 0) 2388deef35fdSEric Schrock return (-1); 2389deef35fdSEric Schrock 2390deef35fdSEric Schrock if (n > 0) 2391deef35fdSEric Schrock goto nextrec; 2392deef35fdSEric Schrock } 2393deef35fdSEric Schrock } 2394deef35fdSEric Schrock 23957c478bd9Sstevel@tonic-gate nofmt: 23967c478bd9Sstevel@tonic-gate if (act == DTRACEACT_PRINTA) { 23977c478bd9Sstevel@tonic-gate dt_print_aggdata_t pd; 239830ef842dSbmc dtrace_aggvarid_t *aggvars; 239930ef842dSbmc int j, naggvars = 0; 240030ef842dSbmc size_t size = ((epd->dtepd_nrecs - i) * 240130ef842dSbmc sizeof (dtrace_aggvarid_t)); 24027c478bd9Sstevel@tonic-gate 240330ef842dSbmc if ((aggvars = dt_alloc(dtp, size)) == NULL) 240430ef842dSbmc return (-1); 240530ef842dSbmc 240630ef842dSbmc /* 240730ef842dSbmc * This might be a printa() with multiple 240830ef842dSbmc * aggregation variables. We need to scan 240930ef842dSbmc * forward through the records until we find 241030ef842dSbmc * a record from a different statement. 241130ef842dSbmc */ 241230ef842dSbmc for (j = i; j < epd->dtepd_nrecs; j++) { 241330ef842dSbmc dtrace_recdesc_t *nrec; 241430ef842dSbmc caddr_t naddr; 241530ef842dSbmc 241630ef842dSbmc nrec = &epd->dtepd_rec[j]; 241730ef842dSbmc 241830ef842dSbmc if (nrec->dtrd_uarg != rec->dtrd_uarg) 241930ef842dSbmc break; 242030ef842dSbmc 242130ef842dSbmc if (nrec->dtrd_action != act) { 242230ef842dSbmc return (dt_set_errno(dtp, 242330ef842dSbmc EDT_BADAGG)); 242430ef842dSbmc } 242530ef842dSbmc 242630ef842dSbmc naddr = buf->dtbd_data + offs + 242730ef842dSbmc nrec->dtrd_offset; 242830ef842dSbmc 242930ef842dSbmc aggvars[naggvars++] = 243030ef842dSbmc /* LINTED - alignment */ 243130ef842dSbmc *((dtrace_aggvarid_t *)naddr); 243230ef842dSbmc } 243330ef842dSbmc 243430ef842dSbmc i = j - 1; 24357c478bd9Sstevel@tonic-gate bzero(&pd, sizeof (pd)); 24367c478bd9Sstevel@tonic-gate pd.dtpa_dtp = dtp; 24377c478bd9Sstevel@tonic-gate pd.dtpa_fp = fp; 243830ef842dSbmc 243930ef842dSbmc assert(naggvars >= 1); 244030ef842dSbmc 244130ef842dSbmc if (naggvars == 1) { 244230ef842dSbmc pd.dtpa_id = aggvars[0]; 244330ef842dSbmc dt_free(dtp, aggvars); 24447c478bd9Sstevel@tonic-gate 24457c478bd9Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0 || 244630ef842dSbmc dtrace_aggregate_walk_sorted(dtp, 24477c478bd9Sstevel@tonic-gate dt_print_agg, &pd) < 0) 24487c478bd9Sstevel@tonic-gate return (-1); 244930ef842dSbmc goto nextrec; 245030ef842dSbmc } 24517c478bd9Sstevel@tonic-gate 245230ef842dSbmc if (dt_printf(dtp, fp, "\n") < 0 || 245330ef842dSbmc dtrace_aggregate_walk_joined(dtp, aggvars, 245430ef842dSbmc naggvars, dt_print_aggs, &pd) < 0) { 245530ef842dSbmc dt_free(dtp, aggvars); 245630ef842dSbmc return (-1); 245730ef842dSbmc } 245830ef842dSbmc 245930ef842dSbmc dt_free(dtp, aggvars); 24607c478bd9Sstevel@tonic-gate goto nextrec; 24617c478bd9Sstevel@tonic-gate } 24627c478bd9Sstevel@tonic-gate 24631ea5f93dSBryan Cantrill if (act == DTRACEACT_TRACEMEM) { 24641ea5f93dSBryan Cantrill if (tracememsize == 0 || 24651ea5f93dSBryan Cantrill tracememsize > rec->dtrd_size) { 24661ea5f93dSBryan Cantrill tracememsize = rec->dtrd_size; 24671ea5f93dSBryan Cantrill } 24681ea5f93dSBryan Cantrill 24691ea5f93dSBryan Cantrill n = dt_print_bytes(dtp, fp, addr, 247033093f5bSBryan Cantrill tracememsize, -33, quiet, 1); 24711ea5f93dSBryan Cantrill 24721ea5f93dSBryan Cantrill tracememsize = 0; 24731ea5f93dSBryan Cantrill 24741ea5f93dSBryan Cantrill if (n < 0) 24751ea5f93dSBryan Cantrill return (-1); 24761ea5f93dSBryan Cantrill 24771ea5f93dSBryan Cantrill goto nextrec; 24781ea5f93dSBryan Cantrill } 24791ea5f93dSBryan Cantrill 24807c478bd9Sstevel@tonic-gate switch (rec->dtrd_size) { 24817c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 24827c478bd9Sstevel@tonic-gate n = dt_printf(dtp, fp, 24837c478bd9Sstevel@tonic-gate quiet ? "%lld" : " %16lld", 24847c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 24857c478bd9Sstevel@tonic-gate *((unsigned long long *)addr)); 24867c478bd9Sstevel@tonic-gate break; 24877c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 24887c478bd9Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %8d", 24897c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 24907c478bd9Sstevel@tonic-gate *((uint32_t *)addr)); 24917c478bd9Sstevel@tonic-gate break; 24927c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 24937c478bd9Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %5d", 24947c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 24957c478bd9Sstevel@tonic-gate *((uint16_t *)addr)); 24967c478bd9Sstevel@tonic-gate break; 24977c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 24987c478bd9Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %3d", 24997c478bd9Sstevel@tonic-gate *((uint8_t *)addr)); 25007c478bd9Sstevel@tonic-gate break; 25017c478bd9Sstevel@tonic-gate default: 25027c478bd9Sstevel@tonic-gate n = dt_print_bytes(dtp, fp, addr, 250333093f5bSBryan Cantrill rec->dtrd_size, -33, quiet, 0); 25047c478bd9Sstevel@tonic-gate break; 25057c478bd9Sstevel@tonic-gate } 25067c478bd9Sstevel@tonic-gate 25077c478bd9Sstevel@tonic-gate if (n < 0) 25087c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate nextrec: 251130ef842dSbmc if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0) 25127c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */ 25137c478bd9Sstevel@tonic-gate } 25147c478bd9Sstevel@tonic-gate 25157c478bd9Sstevel@tonic-gate /* 25167c478bd9Sstevel@tonic-gate * Call the record callback with a NULL record to indicate 25177c478bd9Sstevel@tonic-gate * that we're done processing this EPID. 25187c478bd9Sstevel@tonic-gate */ 25197c478bd9Sstevel@tonic-gate rval = (*rfunc)(&data, NULL, arg); 25207c478bd9Sstevel@tonic-gate nextepid: 25217c478bd9Sstevel@tonic-gate offs += epd->dtepd_size; 2522e5803b76SAdam H. Leventhal dtp->dt_last_epid = id; 2523e5803b76SAdam H. Leventhal if (just_one) { 2524e5803b76SAdam H. Leventhal buf->dtbd_oldest = offs; 2525e5803b76SAdam H. Leventhal break; 2526e5803b76SAdam H. Leventhal } 25277c478bd9Sstevel@tonic-gate } 25287c478bd9Sstevel@tonic-gate 2529e5803b76SAdam H. Leventhal dtp->dt_flow = data.dtpda_flow; 2530e5803b76SAdam H. Leventhal dtp->dt_indent = data.dtpda_indent; 2531e5803b76SAdam H. Leventhal dtp->dt_prefix = data.dtpda_prefix; 25327c478bd9Sstevel@tonic-gate 25337c478bd9Sstevel@tonic-gate if ((drops = buf->dtbd_drops) == 0) 25347c478bd9Sstevel@tonic-gate return (0); 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate /* 25377c478bd9Sstevel@tonic-gate * Explicitly zero the drops to prevent us from processing them again. 25387c478bd9Sstevel@tonic-gate */ 25397c478bd9Sstevel@tonic-gate buf->dtbd_drops = 0; 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops)); 25427c478bd9Sstevel@tonic-gate } 25437c478bd9Sstevel@tonic-gate 2544e5803b76SAdam H. Leventhal /* 2545e5803b76SAdam H. Leventhal * Reduce memory usage by shrinking the buffer if it's no more than half full. 2546e5803b76SAdam H. Leventhal * Note, we need to preserve the alignment of the data at dtbd_oldest, which is 2547e5803b76SAdam H. Leventhal * only 4-byte aligned. 2548e5803b76SAdam H. Leventhal */ 2549e5803b76SAdam H. Leventhal static void 2550e5803b76SAdam H. Leventhal dt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize) 2551e5803b76SAdam H. Leventhal { 2552e5803b76SAdam H. Leventhal uint64_t used = buf->dtbd_size - buf->dtbd_oldest; 2553e5803b76SAdam H. Leventhal if (used < cursize / 2) { 2554e5803b76SAdam H. Leventhal int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2555e5803b76SAdam H. Leventhal char *newdata = dt_alloc(dtp, used + misalign); 2556e5803b76SAdam H. Leventhal if (newdata == NULL) 2557e5803b76SAdam H. Leventhal return; 2558e5803b76SAdam H. Leventhal bzero(newdata, misalign); 2559e5803b76SAdam H. Leventhal bcopy(buf->dtbd_data + buf->dtbd_oldest, 2560e5803b76SAdam H. Leventhal newdata + misalign, used); 2561e5803b76SAdam H. Leventhal dt_free(dtp, buf->dtbd_data); 2562e5803b76SAdam H. Leventhal buf->dtbd_oldest = misalign; 2563e5803b76SAdam H. Leventhal buf->dtbd_size = used + misalign; 2564e5803b76SAdam H. Leventhal buf->dtbd_data = newdata; 2565e5803b76SAdam H. Leventhal } 2566e5803b76SAdam H. Leventhal } 2567e5803b76SAdam H. Leventhal 2568e5803b76SAdam H. Leventhal /* 2569e5803b76SAdam H. Leventhal * If the ring buffer has wrapped, the data is not in order. Rearrange it 2570e5803b76SAdam H. Leventhal * so that it is. Note, we need to preserve the alignment of the data at 2571e5803b76SAdam H. Leventhal * dtbd_oldest, which is only 4-byte aligned. 2572e5803b76SAdam H. Leventhal */ 2573e5803b76SAdam H. Leventhal static int 2574e5803b76SAdam H. Leventhal dt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2575e5803b76SAdam H. Leventhal { 2576e5803b76SAdam H. Leventhal int misalign; 2577e5803b76SAdam H. Leventhal char *newdata, *ndp; 2578e5803b76SAdam H. Leventhal 2579e5803b76SAdam H. Leventhal if (buf->dtbd_oldest == 0) 2580e5803b76SAdam H. Leventhal return (0); 2581e5803b76SAdam H. Leventhal 2582e5803b76SAdam H. Leventhal misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1); 2583e5803b76SAdam H. Leventhal newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign); 2584e5803b76SAdam H. Leventhal 2585e5803b76SAdam H. Leventhal if (newdata == NULL) 2586e5803b76SAdam H. Leventhal return (-1); 2587e5803b76SAdam H. Leventhal 2588e5803b76SAdam H. Leventhal assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1))); 2589e5803b76SAdam H. Leventhal 2590e5803b76SAdam H. Leventhal bzero(ndp, misalign); 2591e5803b76SAdam H. Leventhal ndp += misalign; 2592e5803b76SAdam H. Leventhal 2593e5803b76SAdam H. Leventhal bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp, 2594e5803b76SAdam H. Leventhal buf->dtbd_size - buf->dtbd_oldest); 2595e5803b76SAdam H. Leventhal ndp += buf->dtbd_size - buf->dtbd_oldest; 2596e5803b76SAdam H. Leventhal 2597e5803b76SAdam H. Leventhal bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest); 2598e5803b76SAdam H. Leventhal 2599e5803b76SAdam H. Leventhal dt_free(dtp, buf->dtbd_data); 2600e5803b76SAdam H. Leventhal buf->dtbd_oldest = 0; 2601e5803b76SAdam H. Leventhal buf->dtbd_data = newdata; 2602e5803b76SAdam H. Leventhal buf->dtbd_size += misalign; 2603e5803b76SAdam H. Leventhal 2604e5803b76SAdam H. Leventhal return (0); 2605e5803b76SAdam H. Leventhal } 2606e5803b76SAdam H. Leventhal 2607e5803b76SAdam H. Leventhal static void 2608e5803b76SAdam H. Leventhal dt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf) 2609e5803b76SAdam H. Leventhal { 2610e5803b76SAdam H. Leventhal dt_free(dtp, buf->dtbd_data); 2611e5803b76SAdam H. Leventhal dt_free(dtp, buf); 2612e5803b76SAdam H. Leventhal } 2613e5803b76SAdam H. Leventhal 2614e5803b76SAdam H. Leventhal /* 2615e5803b76SAdam H. Leventhal * Returns 0 on success, in which case *cbp will be filled in if we retrieved 2616e5803b76SAdam H. Leventhal * data, or NULL if there is no data for this CPU. 2617e5803b76SAdam H. Leventhal * Returns -1 on failure and sets dt_errno. 2618e5803b76SAdam H. Leventhal */ 2619e5803b76SAdam H. Leventhal static int 2620e5803b76SAdam H. Leventhal dt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp) 2621e5803b76SAdam H. Leventhal { 2622e5803b76SAdam H. Leventhal dtrace_optval_t size; 2623e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf)); 2624e5803b76SAdam H. Leventhal int error; 2625e5803b76SAdam H. Leventhal 2626e5803b76SAdam H. Leventhal if (buf == NULL) 2627e5803b76SAdam H. Leventhal return (-1); 2628e5803b76SAdam H. Leventhal 2629e5803b76SAdam H. Leventhal (void) dtrace_getopt(dtp, "bufsize", &size); 2630e5803b76SAdam H. Leventhal buf->dtbd_data = dt_alloc(dtp, size); 2631e5803b76SAdam H. Leventhal if (buf->dtbd_data == NULL) { 2632e5803b76SAdam H. Leventhal dt_free(dtp, buf); 2633e5803b76SAdam H. Leventhal return (-1); 2634e5803b76SAdam H. Leventhal } 2635e5803b76SAdam H. Leventhal buf->dtbd_size = size; 2636e5803b76SAdam H. Leventhal buf->dtbd_cpu = cpu; 2637e5803b76SAdam H. Leventhal 2638e5803b76SAdam H. Leventhal if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) { 2639e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 2640e5803b76SAdam H. Leventhal /* 2641e5803b76SAdam H. Leventhal * If we failed with ENOENT, it may be because the 2642e5803b76SAdam H. Leventhal * CPU was unconfigured -- this is okay. Any other 2643e5803b76SAdam H. Leventhal * error, however, is unexpected. 2644e5803b76SAdam H. Leventhal */ 2645e5803b76SAdam H. Leventhal if (errno == ENOENT) { 2646e5803b76SAdam H. Leventhal *bufp = NULL; 2647e5803b76SAdam H. Leventhal return (0); 2648e5803b76SAdam H. Leventhal } 2649e5803b76SAdam H. Leventhal 2650e5803b76SAdam H. Leventhal return (dt_set_errno(dtp, errno)); 2651e5803b76SAdam H. Leventhal } 2652e5803b76SAdam H. Leventhal 2653e5803b76SAdam H. Leventhal error = dt_unring_buf(dtp, buf); 2654e5803b76SAdam H. Leventhal if (error != 0) { 2655e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 2656e5803b76SAdam H. Leventhal return (error); 2657e5803b76SAdam H. Leventhal } 2658e5803b76SAdam H. Leventhal dt_realloc_buf(dtp, buf, size); 2659e5803b76SAdam H. Leventhal 2660e5803b76SAdam H. Leventhal *bufp = buf; 2661e5803b76SAdam H. Leventhal return (0); 2662e5803b76SAdam H. Leventhal } 2663e5803b76SAdam H. Leventhal 26647c478bd9Sstevel@tonic-gate typedef struct dt_begin { 26657c478bd9Sstevel@tonic-gate dtrace_consume_probe_f *dtbgn_probefunc; 26667c478bd9Sstevel@tonic-gate dtrace_consume_rec_f *dtbgn_recfunc; 26677c478bd9Sstevel@tonic-gate void *dtbgn_arg; 26687c478bd9Sstevel@tonic-gate dtrace_handle_err_f *dtbgn_errhdlr; 26697c478bd9Sstevel@tonic-gate void *dtbgn_errarg; 26707c478bd9Sstevel@tonic-gate int dtbgn_beginonly; 26717c478bd9Sstevel@tonic-gate } dt_begin_t; 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate static int 26747c478bd9Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg) 26757c478bd9Sstevel@tonic-gate { 2676e5803b76SAdam H. Leventhal dt_begin_t *begin = arg; 26777c478bd9Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc; 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 26807c478bd9Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 26817c478bd9Sstevel@tonic-gate 26827c478bd9Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 26837c478bd9Sstevel@tonic-gate if (!(r1 && r2)) 26847c478bd9Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 26857c478bd9Sstevel@tonic-gate } else { 26867c478bd9Sstevel@tonic-gate if (r1 && r2) 26877c478bd9Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT); 26887c478bd9Sstevel@tonic-gate } 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate /* 26917c478bd9Sstevel@tonic-gate * We have a record that we're interested in. Now call the underlying 26927c478bd9Sstevel@tonic-gate * probe function... 26937c478bd9Sstevel@tonic-gate */ 26947c478bd9Sstevel@tonic-gate return (begin->dtbgn_probefunc(data, begin->dtbgn_arg)); 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate 26977c478bd9Sstevel@tonic-gate static int 26987c478bd9Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data, 26997c478bd9Sstevel@tonic-gate const dtrace_recdesc_t *rec, void *arg) 27007c478bd9Sstevel@tonic-gate { 2701e5803b76SAdam H. Leventhal dt_begin_t *begin = arg; 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg)); 27047c478bd9Sstevel@tonic-gate } 27057c478bd9Sstevel@tonic-gate 27067c478bd9Sstevel@tonic-gate static int 2707a1b5e537Sbmc dt_consume_begin_error(const dtrace_errdata_t *data, void *arg) 27087c478bd9Sstevel@tonic-gate { 27097c478bd9Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg; 27107c478bd9Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dteda_pdesc; 27117c478bd9Sstevel@tonic-gate 27127c478bd9Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0); 27137c478bd9Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0); 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate if (begin->dtbgn_beginonly) { 27167c478bd9Sstevel@tonic-gate if (!(r1 && r2)) 27177c478bd9Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 27187c478bd9Sstevel@tonic-gate } else { 27197c478bd9Sstevel@tonic-gate if (r1 && r2) 27207c478bd9Sstevel@tonic-gate return (DTRACE_HANDLE_OK); 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg)); 27247c478bd9Sstevel@tonic-gate } 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate static int 2727e5803b76SAdam H. Leventhal dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, 27287c478bd9Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 27297c478bd9Sstevel@tonic-gate { 27307c478bd9Sstevel@tonic-gate /* 27317c478bd9Sstevel@tonic-gate * There's this idea that the BEGIN probe should be processed before 27327c478bd9Sstevel@tonic-gate * everything else, and that the END probe should be processed after 27337c478bd9Sstevel@tonic-gate * anything else. In the common case, this is pretty easy to deal 27347c478bd9Sstevel@tonic-gate * with. However, a situation may arise where the BEGIN enabling and 27357c478bd9Sstevel@tonic-gate * END enabling are on the same CPU, and some enabling in the middle 27367c478bd9Sstevel@tonic-gate * occurred on a different CPU. To deal with this (blech!) we need to 27377c478bd9Sstevel@tonic-gate * consume the BEGIN buffer up until the end of the BEGIN probe, and 27387c478bd9Sstevel@tonic-gate * then set it aside. We will then process every other CPU, and then 27397c478bd9Sstevel@tonic-gate * we'll return to the BEGIN CPU and process the rest of the data 27407c478bd9Sstevel@tonic-gate * (which will inevitably include the END probe, if any). Making this 27417c478bd9Sstevel@tonic-gate * even more complicated (!) is the library's ERROR enabling. Because 27427c478bd9Sstevel@tonic-gate * this enabling is processed before we even get into the consume call 27437c478bd9Sstevel@tonic-gate * back, any ERROR firing would result in the library's ERROR enabling 27447c478bd9Sstevel@tonic-gate * being processed twice -- once in our first pass (for BEGIN probes), 27457c478bd9Sstevel@tonic-gate * and again in our second pass (for everything but BEGIN probes). To 27467c478bd9Sstevel@tonic-gate * deal with this, we interpose on the ERROR handler to assure that we 27477c478bd9Sstevel@tonic-gate * only process ERROR enablings induced by BEGIN enablings in the 27487c478bd9Sstevel@tonic-gate * first pass, and that we only process ERROR enablings _not_ induced 27497c478bd9Sstevel@tonic-gate * by BEGIN enablings in the second pass. 27507c478bd9Sstevel@tonic-gate */ 2751e5803b76SAdam H. Leventhal 27527c478bd9Sstevel@tonic-gate dt_begin_t begin; 27537c478bd9Sstevel@tonic-gate processorid_t cpu = dtp->dt_beganon; 27547c478bd9Sstevel@tonic-gate int rval, i; 27557c478bd9Sstevel@tonic-gate static int max_ncpus; 2756e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf; 27577c478bd9Sstevel@tonic-gate 27587c478bd9Sstevel@tonic-gate dtp->dt_beganon = -1; 27597c478bd9Sstevel@tonic-gate 2760e5803b76SAdam H. Leventhal if (dt_get_buf(dtp, cpu, &buf) != 0) 2761e5803b76SAdam H. Leventhal return (-1); 2762e5803b76SAdam H. Leventhal if (buf == NULL) 27637c478bd9Sstevel@tonic-gate return (0); 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) { 27667c478bd9Sstevel@tonic-gate /* 27677c478bd9Sstevel@tonic-gate * This is the simple case. We're either not stopped, or if 27687c478bd9Sstevel@tonic-gate * we are, we actually processed any END probes on another 27697c478bd9Sstevel@tonic-gate * CPU. We can simply consume this buffer and return. 27707c478bd9Sstevel@tonic-gate */ 2771e5803b76SAdam H. Leventhal rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2772e5803b76SAdam H. Leventhal pf, rf, arg); 2773e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 2774e5803b76SAdam H. Leventhal return (rval); 27757c478bd9Sstevel@tonic-gate } 27767c478bd9Sstevel@tonic-gate 27777c478bd9Sstevel@tonic-gate begin.dtbgn_probefunc = pf; 27787c478bd9Sstevel@tonic-gate begin.dtbgn_recfunc = rf; 27797c478bd9Sstevel@tonic-gate begin.dtbgn_arg = arg; 27807c478bd9Sstevel@tonic-gate begin.dtbgn_beginonly = 1; 27817c478bd9Sstevel@tonic-gate 27827c478bd9Sstevel@tonic-gate /* 27837c478bd9Sstevel@tonic-gate * We need to interpose on the ERROR handler to be sure that we 27847c478bd9Sstevel@tonic-gate * only process ERRORs induced by BEGIN. 27857c478bd9Sstevel@tonic-gate */ 27867c478bd9Sstevel@tonic-gate begin.dtbgn_errhdlr = dtp->dt_errhdlr; 27877c478bd9Sstevel@tonic-gate begin.dtbgn_errarg = dtp->dt_errarg; 27887c478bd9Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 27897c478bd9Sstevel@tonic-gate dtp->dt_errarg = &begin; 27907c478bd9Sstevel@tonic-gate 2791e5803b76SAdam H. Leventhal rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2792e5803b76SAdam H. Leventhal dt_consume_begin_probe, dt_consume_begin_record, &begin); 27937c478bd9Sstevel@tonic-gate 27947c478bd9Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 27957c478bd9Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 27967c478bd9Sstevel@tonic-gate 2797e5803b76SAdam H. Leventhal if (rval != 0) { 2798e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 27997c478bd9Sstevel@tonic-gate return (rval); 2800e5803b76SAdam H. Leventhal } 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate if (max_ncpus == 0) 28037c478bd9Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 28047c478bd9Sstevel@tonic-gate 28057c478bd9Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 2806e5803b76SAdam H. Leventhal dtrace_bufdesc_t *nbuf; 28077c478bd9Sstevel@tonic-gate if (i == cpu) 28087c478bd9Sstevel@tonic-gate continue; 28097c478bd9Sstevel@tonic-gate 2810e5803b76SAdam H. Leventhal if (dt_get_buf(dtp, i, &nbuf) != 0) { 2811e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 2812e5803b76SAdam H. Leventhal return (-1); 2813e5803b76SAdam H. Leventhal } 2814e5803b76SAdam H. Leventhal if (nbuf == NULL) 28157c478bd9Sstevel@tonic-gate continue; 28167c478bd9Sstevel@tonic-gate 2817e5803b76SAdam H. Leventhal rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE, 2818e5803b76SAdam H. Leventhal pf, rf, arg); 2819e5803b76SAdam H. Leventhal dt_put_buf(dtp, nbuf); 2820e5803b76SAdam H. Leventhal if (rval != 0) { 2821e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 28227c478bd9Sstevel@tonic-gate return (rval); 28237c478bd9Sstevel@tonic-gate } 28247c478bd9Sstevel@tonic-gate } 28257c478bd9Sstevel@tonic-gate 28267c478bd9Sstevel@tonic-gate /* 28277c478bd9Sstevel@tonic-gate * Okay -- we're done with the other buffers. Now we want to 28287c478bd9Sstevel@tonic-gate * reconsume the first buffer -- but this time we're looking for 28297c478bd9Sstevel@tonic-gate * everything _but_ BEGIN. And of course, in order to only consume 28307c478bd9Sstevel@tonic-gate * those ERRORs _not_ associated with BEGIN, we need to reinstall our 28317c478bd9Sstevel@tonic-gate * ERROR interposition function... 28327c478bd9Sstevel@tonic-gate */ 28337c478bd9Sstevel@tonic-gate begin.dtbgn_beginonly = 0; 28347c478bd9Sstevel@tonic-gate 28357c478bd9Sstevel@tonic-gate assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr); 28367c478bd9Sstevel@tonic-gate assert(begin.dtbgn_errarg == dtp->dt_errarg); 28377c478bd9Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error; 28387c478bd9Sstevel@tonic-gate dtp->dt_errarg = &begin; 28397c478bd9Sstevel@tonic-gate 2840e5803b76SAdam H. Leventhal rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE, 2841e5803b76SAdam H. Leventhal dt_consume_begin_probe, dt_consume_begin_record, &begin); 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr; 28447c478bd9Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg; 28457c478bd9Sstevel@tonic-gate 28467c478bd9Sstevel@tonic-gate return (rval); 28477c478bd9Sstevel@tonic-gate } 28487c478bd9Sstevel@tonic-gate 2849e5803b76SAdam H. Leventhal /* ARGSUSED */ 2850e5803b76SAdam H. Leventhal static uint64_t 2851e5803b76SAdam H. Leventhal dt_buf_oldest(void *elem, void *arg) 2852e5803b76SAdam H. Leventhal { 2853e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf = elem; 2854e5803b76SAdam H. Leventhal size_t offs = buf->dtbd_oldest; 2855e5803b76SAdam H. Leventhal 2856e5803b76SAdam H. Leventhal while (offs < buf->dtbd_size) { 2857e5803b76SAdam H. Leventhal dtrace_rechdr_t *dtrh = 28587894022eSRichard Lowe /* LINTED - alignment */ 2859e5803b76SAdam H. Leventhal (dtrace_rechdr_t *)(buf->dtbd_data + offs); 2860e5803b76SAdam H. Leventhal if (dtrh->dtrh_epid == DTRACE_EPIDNONE) { 2861e5803b76SAdam H. Leventhal offs += sizeof (dtrace_epid_t); 2862e5803b76SAdam H. Leventhal } else { 2863e5803b76SAdam H. Leventhal return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh)); 2864e5803b76SAdam H. Leventhal } 2865e5803b76SAdam H. Leventhal } 2866e5803b76SAdam H. Leventhal 2867e5803b76SAdam H. Leventhal /* There are no records left; use the time the buffer was retrieved. */ 2868e5803b76SAdam H. Leventhal return (buf->dtbd_timestamp); 2869e5803b76SAdam H. Leventhal } 2870e5803b76SAdam H. Leventhal 28717c478bd9Sstevel@tonic-gate int 28727c478bd9Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, 28737c478bd9Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg) 28747c478bd9Sstevel@tonic-gate { 28757c478bd9Sstevel@tonic-gate dtrace_optval_t size; 28767c478bd9Sstevel@tonic-gate static int max_ncpus; 28777c478bd9Sstevel@tonic-gate int i, rval; 28787c478bd9Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE]; 28797c478bd9Sstevel@tonic-gate hrtime_t now = gethrtime(); 28807c478bd9Sstevel@tonic-gate 28817c478bd9Sstevel@tonic-gate if (dtp->dt_lastswitch != 0) { 28827c478bd9Sstevel@tonic-gate if (now - dtp->dt_lastswitch < interval) 28837c478bd9Sstevel@tonic-gate return (0); 28847c478bd9Sstevel@tonic-gate 28857c478bd9Sstevel@tonic-gate dtp->dt_lastswitch += interval; 28867c478bd9Sstevel@tonic-gate } else { 28877c478bd9Sstevel@tonic-gate dtp->dt_lastswitch = now; 28887c478bd9Sstevel@tonic-gate } 28897c478bd9Sstevel@tonic-gate 28907c478bd9Sstevel@tonic-gate if (!dtp->dt_active) 28917c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate if (max_ncpus == 0) 28947c478bd9Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 28957c478bd9Sstevel@tonic-gate 28967c478bd9Sstevel@tonic-gate if (pf == NULL) 28977c478bd9Sstevel@tonic-gate pf = (dtrace_consume_probe_f *)dt_nullprobe; 28987c478bd9Sstevel@tonic-gate 28997c478bd9Sstevel@tonic-gate if (rf == NULL) 29007c478bd9Sstevel@tonic-gate rf = (dtrace_consume_rec_f *)dt_nullrec; 29017c478bd9Sstevel@tonic-gate 2902e5803b76SAdam H. Leventhal if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) { 29037c478bd9Sstevel@tonic-gate /* 2904e5803b76SAdam H. Leventhal * The output will not be in the order it was traced. Rather, 2905e5803b76SAdam H. Leventhal * we will consume all of the data from each CPU's buffer in 2906e5803b76SAdam H. Leventhal * turn. We apply special handling for the records from BEGIN 2907e5803b76SAdam H. Leventhal * and END probes so that they are consumed first and last, 2908e5803b76SAdam H. Leventhal * respectively. 2909e5803b76SAdam H. Leventhal * 29107c478bd9Sstevel@tonic-gate * If we have just begun, we want to first process the CPU that 29117c478bd9Sstevel@tonic-gate * executed the BEGIN probe (if any). 29127c478bd9Sstevel@tonic-gate */ 2913e5803b76SAdam H. Leventhal if (dtp->dt_active && dtp->dt_beganon != -1 && 2914e5803b76SAdam H. Leventhal (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0) 29157c478bd9Sstevel@tonic-gate return (rval); 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) { 2918e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf; 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate /* 2921e5803b76SAdam H. Leventhal * If we have stopped, we want to process the CPU on 2922e5803b76SAdam H. Leventhal * which the END probe was processed only _after_ we 2923e5803b76SAdam H. Leventhal * have processed everything else. 29247c478bd9Sstevel@tonic-gate */ 29257c478bd9Sstevel@tonic-gate if (dtp->dt_stopped && (i == dtp->dt_endedon)) 29267c478bd9Sstevel@tonic-gate continue; 29277c478bd9Sstevel@tonic-gate 2928e5803b76SAdam H. Leventhal if (dt_get_buf(dtp, i, &buf) != 0) 2929e5803b76SAdam H. Leventhal return (-1); 2930e5803b76SAdam H. Leventhal if (buf == NULL) 29317c478bd9Sstevel@tonic-gate continue; 29327c478bd9Sstevel@tonic-gate 2933e5803b76SAdam H. Leventhal dtp->dt_flow = 0; 2934e5803b76SAdam H. Leventhal dtp->dt_indent = 0; 2935e5803b76SAdam H. Leventhal dtp->dt_prefix = NULL; 2936e5803b76SAdam H. Leventhal rval = dt_consume_cpu(dtp, fp, i, 2937e5803b76SAdam H. Leventhal buf, B_FALSE, pf, rf, arg); 2938e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 2939e5803b76SAdam H. Leventhal if (rval != 0) 29407c478bd9Sstevel@tonic-gate return (rval); 29417c478bd9Sstevel@tonic-gate } 2942e5803b76SAdam H. Leventhal if (dtp->dt_stopped) { 2943e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf; 29447c478bd9Sstevel@tonic-gate 2945e5803b76SAdam H. Leventhal if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0) 2946e5803b76SAdam H. Leventhal return (-1); 2947e5803b76SAdam H. Leventhal if (buf == NULL) 29487c478bd9Sstevel@tonic-gate return (0); 29497c478bd9Sstevel@tonic-gate 2950e5803b76SAdam H. Leventhal rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon, 2951e5803b76SAdam H. Leventhal buf, B_FALSE, pf, rf, arg); 2952e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 2953e5803b76SAdam H. Leventhal return (rval); 2954e5803b76SAdam H. Leventhal } 2955e5803b76SAdam H. Leventhal } else { 29567c478bd9Sstevel@tonic-gate /* 2957e5803b76SAdam H. Leventhal * The output will be in the order it was traced (or for 2958e5803b76SAdam H. Leventhal * speculations, when it was committed). We retrieve a buffer 2959e5803b76SAdam H. Leventhal * from each CPU and put it into a priority queue, which sorts 2960e5803b76SAdam H. Leventhal * based on the first entry in the buffer. This is sufficient 2961e5803b76SAdam H. Leventhal * because entries within a buffer are already sorted. 2962e5803b76SAdam H. Leventhal * 2963e5803b76SAdam H. Leventhal * We then consume records one at a time, always consuming the 2964e5803b76SAdam H. Leventhal * oldest record, as determined by the priority queue. When 2965e5803b76SAdam H. Leventhal * we reach the end of the time covered by these buffers, 2966e5803b76SAdam H. Leventhal * we need to stop and retrieve more records on the next pass. 2967e5803b76SAdam H. Leventhal * The kernel tells us the time covered by each buffer, in 2968e5803b76SAdam H. Leventhal * dtbd_timestamp. The first buffer's timestamp tells us the 2969e5803b76SAdam H. Leventhal * time covered by all buffers, as subsequently retrieved 2970e5803b76SAdam H. Leventhal * buffers will cover to a more recent time. 29717c478bd9Sstevel@tonic-gate */ 29727c478bd9Sstevel@tonic-gate 2973e5803b76SAdam H. Leventhal uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t)); 2974e5803b76SAdam H. Leventhal uint64_t first_timestamp = 0; 2975e5803b76SAdam H. Leventhal uint_t cookie = 0; 2976e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf; 2977e5803b76SAdam H. Leventhal 2978e5803b76SAdam H. Leventhal bzero(drops, max_ncpus * sizeof (uint64_t)); 2979e5803b76SAdam H. Leventhal 2980e5803b76SAdam H. Leventhal if (dtp->dt_bufq == NULL) { 2981e5803b76SAdam H. Leventhal dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2, 2982e5803b76SAdam H. Leventhal dt_buf_oldest, NULL); 2983e5803b76SAdam H. Leventhal if (dtp->dt_bufq == NULL) /* ENOMEM */ 2984e5803b76SAdam H. Leventhal return (-1); 29857c478bd9Sstevel@tonic-gate } 29867c478bd9Sstevel@tonic-gate 2987e5803b76SAdam H. Leventhal /* Retrieve data from each CPU. */ 2988e5803b76SAdam H. Leventhal (void) dtrace_getopt(dtp, "bufsize", &size); 2989e5803b76SAdam H. Leventhal for (i = 0; i < max_ncpus; i++) { 2990e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf; 2991e5803b76SAdam H. Leventhal 2992e5803b76SAdam H. Leventhal if (dt_get_buf(dtp, i, &buf) != 0) 2993e5803b76SAdam H. Leventhal return (-1); 2994e5803b76SAdam H. Leventhal if (buf != NULL) { 2995e5803b76SAdam H. Leventhal if (first_timestamp == 0) 2996e5803b76SAdam H. Leventhal first_timestamp = buf->dtbd_timestamp; 2997e5803b76SAdam H. Leventhal assert(buf->dtbd_timestamp >= first_timestamp); 2998e5803b76SAdam H. Leventhal 2999e5803b76SAdam H. Leventhal dt_pq_insert(dtp->dt_bufq, buf); 3000e5803b76SAdam H. Leventhal drops[i] = buf->dtbd_drops; 3001e5803b76SAdam H. Leventhal buf->dtbd_drops = 0; 3002e5803b76SAdam H. Leventhal } 3003e5803b76SAdam H. Leventhal } 3004e5803b76SAdam H. Leventhal 3005e5803b76SAdam H. Leventhal /* Consume records. */ 3006e5803b76SAdam H. Leventhal for (;;) { 3007e5803b76SAdam H. Leventhal dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq); 3008e5803b76SAdam H. Leventhal uint64_t timestamp; 3009e5803b76SAdam H. Leventhal 3010e5803b76SAdam H. Leventhal if (buf == NULL) 3011e5803b76SAdam H. Leventhal break; 3012e5803b76SAdam H. Leventhal 3013e5803b76SAdam H. Leventhal timestamp = dt_buf_oldest(buf, dtp); 3014e5803b76SAdam H. Leventhal assert(timestamp >= dtp->dt_last_timestamp); 3015e5803b76SAdam H. Leventhal dtp->dt_last_timestamp = timestamp; 3016e5803b76SAdam H. Leventhal 3017e5803b76SAdam H. Leventhal if (timestamp == buf->dtbd_timestamp) { 3018e5803b76SAdam H. Leventhal /* 3019e5803b76SAdam H. Leventhal * We've reached the end of the time covered 3020e5803b76SAdam H. Leventhal * by this buffer. If this is the oldest 3021e5803b76SAdam H. Leventhal * buffer, we must do another pass 3022e5803b76SAdam H. Leventhal * to retrieve more data. 3023e5803b76SAdam H. Leventhal */ 3024e5803b76SAdam H. Leventhal dt_put_buf(dtp, buf); 3025e5803b76SAdam H. Leventhal if (timestamp == first_timestamp && 3026e5803b76SAdam H. Leventhal !dtp->dt_stopped) 3027e5803b76SAdam H. Leventhal break; 3028e5803b76SAdam H. Leventhal continue; 3029e5803b76SAdam H. Leventhal } 3030e5803b76SAdam H. Leventhal 3031e5803b76SAdam H. Leventhal if ((rval = dt_consume_cpu(dtp, fp, 3032e5803b76SAdam H. Leventhal buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0) 3033e5803b76SAdam H. Leventhal return (rval); 3034e5803b76SAdam H. Leventhal dt_pq_insert(dtp->dt_bufq, buf); 3035e5803b76SAdam H. Leventhal } 3036e5803b76SAdam H. Leventhal 3037e5803b76SAdam H. Leventhal /* Consume drops. */ 3038e5803b76SAdam H. Leventhal for (i = 0; i < max_ncpus; i++) { 3039e5803b76SAdam H. Leventhal if (drops[i] != 0) { 3040e5803b76SAdam H. Leventhal int error = dt_handle_cpudrop(dtp, i, 3041e5803b76SAdam H. Leventhal DTRACEDROP_PRINCIPAL, drops[i]); 3042e5803b76SAdam H. Leventhal if (error != 0) 3043e5803b76SAdam H. Leventhal return (error); 3044e5803b76SAdam H. Leventhal } 3045e5803b76SAdam H. Leventhal } 3046e5803b76SAdam H. Leventhal 3047e5803b76SAdam H. Leventhal /* 3048e5803b76SAdam H. Leventhal * Reduce memory usage by re-allocating smaller buffers 3049e5803b76SAdam H. Leventhal * for the "remnants". 3050e5803b76SAdam H. Leventhal */ 3051e5803b76SAdam H. Leventhal while (buf = dt_pq_walk(dtp->dt_bufq, &cookie)) 3052e5803b76SAdam H. Leventhal dt_realloc_buf(dtp, buf, buf->dtbd_size); 3053e5803b76SAdam H. Leventhal } 3054e5803b76SAdam H. Leventhal 3055e5803b76SAdam H. Leventhal return (0); 30567c478bd9Sstevel@tonic-gate } 3057