xref: /titanic_52/usr/src/lib/libdtrace/common/dt_consume.c (revision aea650180b31dd5423d26fc0e8ae6b3a4dc50137)
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