xref: /freebsd/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c (revision 3877025f52ee205fe99ad4ff68229933d57e4bcb)
16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell  * CDDL HEADER START
36ff6d951SJohn Birrell  *
46ff6d951SJohn Birrell  * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell  * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell  * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell  *
86ff6d951SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell  * See the License for the specific language governing permissions
116ff6d951SJohn Birrell  * and limitations under the License.
126ff6d951SJohn Birrell  *
136ff6d951SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell  *
196ff6d951SJohn Birrell  * CDDL HEADER END
206ff6d951SJohn Birrell  */
216ff6d951SJohn Birrell /*
221670a1c2SRui Paulo  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236ff6d951SJohn Birrell  * Use is subject to license terms.
246ff6d951SJohn Birrell  */
256ff6d951SJohn Birrell 
26675cf915SPedro F. Giffuni /*
2793f27766SDomagoj Stolfa  * Copyright (c) 2023, Domagoj Stolfa. All rights reserved.
289747bd8eSMark Johnston  * Copyright (c) 2017, Joyent, Inc. All rights reserved.
2909e6105fSMark Johnston  * Copyright (c) 2012 by Delphix. All rights reserved.
30675cf915SPedro F. Giffuni  */
31675cf915SPedro F. Giffuni 
326ff6d951SJohn Birrell #include <stdlib.h>
336ff6d951SJohn Birrell #include <strings.h>
346ff6d951SJohn Birrell #include <errno.h>
356ff6d951SJohn Birrell #include <unistd.h>
366ff6d951SJohn Birrell #include <limits.h>
376ff6d951SJohn Birrell #include <assert.h>
386ff6d951SJohn Birrell #include <ctype.h>
39bc96366cSSteven Hartland #ifdef illumos
406ff6d951SJohn Birrell #include <alloca.h>
4118737969SJohn Birrell #endif
426ff6d951SJohn Birrell #include <dt_impl.h>
4309e6105fSMark Johnston #include <dt_pq.h>
4493f27766SDomagoj Stolfa #include <dt_oformat.h>
45bc96366cSSteven Hartland #ifndef illumos
460f2bd1e8SRui Paulo #include <libproc_compat.h>
470f2bd1e8SRui Paulo #endif
486ff6d951SJohn Birrell 
496ff6d951SJohn Birrell #define	DT_MASK_LO 0x00000000FFFFFFFFULL
506ff6d951SJohn Birrell 
5193f27766SDomagoj Stolfa #define	dt_format_sym(dtp, addr) dt_print_sym((dtp), NULL, NULL, addr)
5293f27766SDomagoj Stolfa 
5393f27766SDomagoj Stolfa typedef struct dt_prepare_args {
5493f27766SDomagoj Stolfa 	int first_bin;
5593f27766SDomagoj Stolfa 	int last_bin;
5693f27766SDomagoj Stolfa 	union {
5793f27766SDomagoj Stolfa 		struct lquantize_args {
5893f27766SDomagoj Stolfa #define lquantize_step		u.lquantize.step
5993f27766SDomagoj Stolfa #define lquantize_levels	u.lquantize.levels
6093f27766SDomagoj Stolfa #define lquantize_base		u.lquantize.base
6193f27766SDomagoj Stolfa 			int base;
6293f27766SDomagoj Stolfa 			uint16_t step;
6393f27766SDomagoj Stolfa 			uint16_t levels;
6493f27766SDomagoj Stolfa 		} lquantize;
6593f27766SDomagoj Stolfa 		struct llquantize_args {
6693f27766SDomagoj Stolfa #define	llquantize_next		u.llquantize.next
6793f27766SDomagoj Stolfa #define	llquantize_step		u.llquantize.step
6893f27766SDomagoj Stolfa #define	llquantize_value	u.llquantize.value
6993f27766SDomagoj Stolfa #define	llquantize_levels	u.llquantize.levels
7093f27766SDomagoj Stolfa #define	llquantize_order	u.llquantize.order
7193f27766SDomagoj Stolfa #define	llquantize_factor	u.llquantize.factor
7293f27766SDomagoj Stolfa #define	llquantize_low		u.llquantize.low
7393f27766SDomagoj Stolfa #define	llquantize_high		u.llquantize.high
7493f27766SDomagoj Stolfa #define	llquantize_nsteps	u.llquantize.nsteps
7593f27766SDomagoj Stolfa 			int64_t next;
7693f27766SDomagoj Stolfa 			int64_t step;
7793f27766SDomagoj Stolfa 			int64_t value;
7893f27766SDomagoj Stolfa 			int levels;
7993f27766SDomagoj Stolfa 			int order;
8093f27766SDomagoj Stolfa 			uint16_t factor;
8193f27766SDomagoj Stolfa 			uint16_t low;
8293f27766SDomagoj Stolfa 			uint16_t high;
8393f27766SDomagoj Stolfa 			uint16_t nsteps;
8493f27766SDomagoj Stolfa 		} llquantize;
8593f27766SDomagoj Stolfa 	} u;
8693f27766SDomagoj Stolfa } dt_prepare_args_t;
8793f27766SDomagoj Stolfa 
886ff6d951SJohn Birrell /*
896ff6d951SJohn Birrell  * We declare this here because (1) we need it and (2) we want to avoid a
906ff6d951SJohn Birrell  * dependency on libm in libdtrace.
916ff6d951SJohn Birrell  */
926ff6d951SJohn Birrell static long double
dt_fabsl(long double x)936ff6d951SJohn Birrell dt_fabsl(long double x)
946ff6d951SJohn Birrell {
956ff6d951SJohn Birrell 	if (x < 0)
966ff6d951SJohn Birrell 		return (-x);
976ff6d951SJohn Birrell 
986ff6d951SJohn Birrell 	return (x);
996ff6d951SJohn Birrell }
1006ff6d951SJohn Birrell 
101a43f0be9SRui Paulo static int
dt_ndigits(long long val)102a43f0be9SRui Paulo dt_ndigits(long long val)
103a43f0be9SRui Paulo {
104a43f0be9SRui Paulo 	int rval = 1;
105a43f0be9SRui Paulo 	long long cmp = 10;
106a43f0be9SRui Paulo 
107a43f0be9SRui Paulo 	if (val < 0) {
108a43f0be9SRui Paulo 		val = val == INT64_MIN ? INT64_MAX : -val;
109a43f0be9SRui Paulo 		rval++;
110a43f0be9SRui Paulo 	}
111a43f0be9SRui Paulo 
112a43f0be9SRui Paulo 	while (val > cmp && cmp > 0) {
113a43f0be9SRui Paulo 		rval++;
114a43f0be9SRui Paulo 		cmp *= 10;
115a43f0be9SRui Paulo 	}
116a43f0be9SRui Paulo 
117a43f0be9SRui Paulo 	return (rval < 4 ? 4 : rval);
118a43f0be9SRui Paulo }
119a43f0be9SRui Paulo 
1206ff6d951SJohn Birrell /*
1216ff6d951SJohn Birrell  * 128-bit arithmetic functions needed to support the stddev() aggregating
1226ff6d951SJohn Birrell  * action.
1236ff6d951SJohn Birrell  */
1246ff6d951SJohn Birrell static int
dt_gt_128(uint64_t * a,uint64_t * b)1256ff6d951SJohn Birrell dt_gt_128(uint64_t *a, uint64_t *b)
1266ff6d951SJohn Birrell {
1276ff6d951SJohn Birrell 	return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0]));
1286ff6d951SJohn Birrell }
1296ff6d951SJohn Birrell 
1306ff6d951SJohn Birrell static int
dt_ge_128(uint64_t * a,uint64_t * b)1316ff6d951SJohn Birrell dt_ge_128(uint64_t *a, uint64_t *b)
1326ff6d951SJohn Birrell {
1336ff6d951SJohn Birrell 	return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0]));
1346ff6d951SJohn Birrell }
1356ff6d951SJohn Birrell 
1366ff6d951SJohn Birrell static int
dt_le_128(uint64_t * a,uint64_t * b)1376ff6d951SJohn Birrell dt_le_128(uint64_t *a, uint64_t *b)
1386ff6d951SJohn Birrell {
1396ff6d951SJohn Birrell 	return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0]));
1406ff6d951SJohn Birrell }
1416ff6d951SJohn Birrell 
1426ff6d951SJohn Birrell /*
1436ff6d951SJohn Birrell  * Shift the 128-bit value in a by b. If b is positive, shift left.
1446ff6d951SJohn Birrell  * If b is negative, shift right.
1456ff6d951SJohn Birrell  */
1466ff6d951SJohn Birrell static void
dt_shift_128(uint64_t * a,int b)1476ff6d951SJohn Birrell dt_shift_128(uint64_t *a, int b)
1486ff6d951SJohn Birrell {
1496ff6d951SJohn Birrell 	uint64_t mask;
1506ff6d951SJohn Birrell 
1516ff6d951SJohn Birrell 	if (b == 0)
1526ff6d951SJohn Birrell 		return;
1536ff6d951SJohn Birrell 
1546ff6d951SJohn Birrell 	if (b < 0) {
1556ff6d951SJohn Birrell 		b = -b;
1566ff6d951SJohn Birrell 		if (b >= 64) {
1576ff6d951SJohn Birrell 			a[0] = a[1] >> (b - 64);
1586ff6d951SJohn Birrell 			a[1] = 0;
1596ff6d951SJohn Birrell 		} else {
1606ff6d951SJohn Birrell 			a[0] >>= b;
1616ff6d951SJohn Birrell 			mask = 1LL << (64 - b);
1626ff6d951SJohn Birrell 			mask -= 1;
1636ff6d951SJohn Birrell 			a[0] |= ((a[1] & mask) << (64 - b));
1646ff6d951SJohn Birrell 			a[1] >>= b;
1656ff6d951SJohn Birrell 		}
1666ff6d951SJohn Birrell 	} else {
1676ff6d951SJohn Birrell 		if (b >= 64) {
1686ff6d951SJohn Birrell 			a[1] = a[0] << (b - 64);
1696ff6d951SJohn Birrell 			a[0] = 0;
1706ff6d951SJohn Birrell 		} else {
1716ff6d951SJohn Birrell 			a[1] <<= b;
1726ff6d951SJohn Birrell 			mask = a[0] >> (64 - b);
1736ff6d951SJohn Birrell 			a[1] |= mask;
1746ff6d951SJohn Birrell 			a[0] <<= b;
1756ff6d951SJohn Birrell 		}
1766ff6d951SJohn Birrell 	}
1776ff6d951SJohn Birrell }
1786ff6d951SJohn Birrell 
1796ff6d951SJohn Birrell static int
dt_nbits_128(uint64_t * a)1806ff6d951SJohn Birrell dt_nbits_128(uint64_t *a)
1816ff6d951SJohn Birrell {
1826ff6d951SJohn Birrell 	int nbits = 0;
1836ff6d951SJohn Birrell 	uint64_t tmp[2];
1846ff6d951SJohn Birrell 	uint64_t zero[2] = { 0, 0 };
1856ff6d951SJohn Birrell 
1866ff6d951SJohn Birrell 	tmp[0] = a[0];
1876ff6d951SJohn Birrell 	tmp[1] = a[1];
1886ff6d951SJohn Birrell 
1896ff6d951SJohn Birrell 	dt_shift_128(tmp, -1);
1906ff6d951SJohn Birrell 	while (dt_gt_128(tmp, zero)) {
1916ff6d951SJohn Birrell 		dt_shift_128(tmp, -1);
1926ff6d951SJohn Birrell 		nbits++;
1936ff6d951SJohn Birrell 	}
1946ff6d951SJohn Birrell 
1956ff6d951SJohn Birrell 	return (nbits);
1966ff6d951SJohn Birrell }
1976ff6d951SJohn Birrell 
1986ff6d951SJohn Birrell static void
dt_subtract_128(uint64_t * minuend,uint64_t * subtrahend,uint64_t * difference)1996ff6d951SJohn Birrell dt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference)
2006ff6d951SJohn Birrell {
2016ff6d951SJohn Birrell 	uint64_t result[2];
2026ff6d951SJohn Birrell 
2036ff6d951SJohn Birrell 	result[0] = minuend[0] - subtrahend[0];
2046ff6d951SJohn Birrell 	result[1] = minuend[1] - subtrahend[1] -
2056ff6d951SJohn Birrell 	    (minuend[0] < subtrahend[0] ? 1 : 0);
2066ff6d951SJohn Birrell 
2076ff6d951SJohn Birrell 	difference[0] = result[0];
2086ff6d951SJohn Birrell 	difference[1] = result[1];
2096ff6d951SJohn Birrell }
2106ff6d951SJohn Birrell 
2116ff6d951SJohn Birrell static void
dt_add_128(uint64_t * addend1,uint64_t * addend2,uint64_t * sum)2126ff6d951SJohn Birrell dt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum)
2136ff6d951SJohn Birrell {
2146ff6d951SJohn Birrell 	uint64_t result[2];
2156ff6d951SJohn Birrell 
2166ff6d951SJohn Birrell 	result[0] = addend1[0] + addend2[0];
2176ff6d951SJohn Birrell 	result[1] = addend1[1] + addend2[1] +
2186ff6d951SJohn Birrell 	    (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0);
2196ff6d951SJohn Birrell 
2206ff6d951SJohn Birrell 	sum[0] = result[0];
2216ff6d951SJohn Birrell 	sum[1] = result[1];
2226ff6d951SJohn Birrell }
2236ff6d951SJohn Birrell 
2246ff6d951SJohn Birrell /*
2256ff6d951SJohn Birrell  * The basic idea is to break the 2 64-bit values into 4 32-bit values,
2266ff6d951SJohn Birrell  * use native multiplication on those, and then re-combine into the
2276ff6d951SJohn Birrell  * resulting 128-bit value.
2286ff6d951SJohn Birrell  *
2296ff6d951SJohn Birrell  * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) =
2306ff6d951SJohn Birrell  *     hi1 * hi2 << 64 +
2316ff6d951SJohn Birrell  *     hi1 * lo2 << 32 +
2326ff6d951SJohn Birrell  *     hi2 * lo1 << 32 +
2336ff6d951SJohn Birrell  *     lo1 * lo2
2346ff6d951SJohn Birrell  */
2356ff6d951SJohn Birrell static void
dt_multiply_128(uint64_t factor1,uint64_t factor2,uint64_t * product)2366ff6d951SJohn Birrell dt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product)
2376ff6d951SJohn Birrell {
2386ff6d951SJohn Birrell 	uint64_t hi1, hi2, lo1, lo2;
2396ff6d951SJohn Birrell 	uint64_t tmp[2];
2406ff6d951SJohn Birrell 
2416ff6d951SJohn Birrell 	hi1 = factor1 >> 32;
2426ff6d951SJohn Birrell 	hi2 = factor2 >> 32;
2436ff6d951SJohn Birrell 
2446ff6d951SJohn Birrell 	lo1 = factor1 & DT_MASK_LO;
2456ff6d951SJohn Birrell 	lo2 = factor2 & DT_MASK_LO;
2466ff6d951SJohn Birrell 
2476ff6d951SJohn Birrell 	product[0] = lo1 * lo2;
2486ff6d951SJohn Birrell 	product[1] = hi1 * hi2;
2496ff6d951SJohn Birrell 
2506ff6d951SJohn Birrell 	tmp[0] = hi1 * lo2;
2516ff6d951SJohn Birrell 	tmp[1] = 0;
2526ff6d951SJohn Birrell 	dt_shift_128(tmp, 32);
2536ff6d951SJohn Birrell 	dt_add_128(product, tmp, product);
2546ff6d951SJohn Birrell 
2556ff6d951SJohn Birrell 	tmp[0] = hi2 * lo1;
2566ff6d951SJohn Birrell 	tmp[1] = 0;
2576ff6d951SJohn Birrell 	dt_shift_128(tmp, 32);
2586ff6d951SJohn Birrell 	dt_add_128(product, tmp, product);
2596ff6d951SJohn Birrell }
2606ff6d951SJohn Birrell 
2616ff6d951SJohn Birrell /*
2626ff6d951SJohn Birrell  * This is long-hand division.
2636ff6d951SJohn Birrell  *
2646ff6d951SJohn Birrell  * We initialize subtrahend by shifting divisor left as far as possible. We
2656ff6d951SJohn Birrell  * loop, comparing subtrahend to dividend:  if subtrahend is smaller, we
2666ff6d951SJohn Birrell  * subtract and set the appropriate bit in the result.  We then shift
2676ff6d951SJohn Birrell  * subtrahend right by one bit for the next comparison.
2686ff6d951SJohn Birrell  */
2696ff6d951SJohn Birrell static void
dt_divide_128(uint64_t * dividend,uint64_t divisor,uint64_t * quotient)2706ff6d951SJohn Birrell dt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient)
2716ff6d951SJohn Birrell {
2726ff6d951SJohn Birrell 	uint64_t result[2] = { 0, 0 };
2736ff6d951SJohn Birrell 	uint64_t remainder[2];
2746ff6d951SJohn Birrell 	uint64_t subtrahend[2];
2756ff6d951SJohn Birrell 	uint64_t divisor_128[2];
2766ff6d951SJohn Birrell 	uint64_t mask[2] = { 1, 0 };
2776ff6d951SJohn Birrell 	int log = 0;
2786ff6d951SJohn Birrell 
2796ff6d951SJohn Birrell 	assert(divisor != 0);
2806ff6d951SJohn Birrell 
2816ff6d951SJohn Birrell 	divisor_128[0] = divisor;
2826ff6d951SJohn Birrell 	divisor_128[1] = 0;
2836ff6d951SJohn Birrell 
2846ff6d951SJohn Birrell 	remainder[0] = dividend[0];
2856ff6d951SJohn Birrell 	remainder[1] = dividend[1];
2866ff6d951SJohn Birrell 
2876ff6d951SJohn Birrell 	subtrahend[0] = divisor;
2886ff6d951SJohn Birrell 	subtrahend[1] = 0;
2896ff6d951SJohn Birrell 
2906ff6d951SJohn Birrell 	while (divisor > 0) {
2916ff6d951SJohn Birrell 		log++;
2926ff6d951SJohn Birrell 		divisor >>= 1;
2936ff6d951SJohn Birrell 	}
2946ff6d951SJohn Birrell 
2956ff6d951SJohn Birrell 	dt_shift_128(subtrahend, 128 - log);
2966ff6d951SJohn Birrell 	dt_shift_128(mask, 128 - log);
2976ff6d951SJohn Birrell 
2986ff6d951SJohn Birrell 	while (dt_ge_128(remainder, divisor_128)) {
2996ff6d951SJohn Birrell 		if (dt_ge_128(remainder, subtrahend)) {
3006ff6d951SJohn Birrell 			dt_subtract_128(remainder, subtrahend, remainder);
3016ff6d951SJohn Birrell 			result[0] |= mask[0];
3026ff6d951SJohn Birrell 			result[1] |= mask[1];
3036ff6d951SJohn Birrell 		}
3046ff6d951SJohn Birrell 
3056ff6d951SJohn Birrell 		dt_shift_128(subtrahend, -1);
3066ff6d951SJohn Birrell 		dt_shift_128(mask, -1);
3076ff6d951SJohn Birrell 	}
3086ff6d951SJohn Birrell 
3096ff6d951SJohn Birrell 	quotient[0] = result[0];
3106ff6d951SJohn Birrell 	quotient[1] = result[1];
3116ff6d951SJohn Birrell }
3126ff6d951SJohn Birrell 
3136ff6d951SJohn Birrell /*
3146ff6d951SJohn Birrell  * This is the long-hand method of calculating a square root.
3156ff6d951SJohn Birrell  * The algorithm is as follows:
3166ff6d951SJohn Birrell  *
3176ff6d951SJohn Birrell  * 1. Group the digits by 2 from the right.
3186ff6d951SJohn Birrell  * 2. Over the leftmost group, find the largest single-digit number
3196ff6d951SJohn Birrell  *    whose square is less than that group.
3206ff6d951SJohn Birrell  * 3. Subtract the result of the previous step (2 or 4, depending) and
3216ff6d951SJohn Birrell  *    bring down the next two-digit group.
3226ff6d951SJohn Birrell  * 4. For the result R we have so far, find the largest single-digit number
3236ff6d951SJohn Birrell  *    x such that 2 * R * 10 * x + x^2 is less than the result from step 3.
3246ff6d951SJohn Birrell  *    (Note that this is doubling R and performing a decimal left-shift by 1
3256ff6d951SJohn Birrell  *    and searching for the appropriate decimal to fill the one's place.)
3266ff6d951SJohn Birrell  *    The value x is the next digit in the square root.
3276ff6d951SJohn Birrell  * Repeat steps 3 and 4 until the desired precision is reached.  (We're
3286ff6d951SJohn Birrell  * dealing with integers, so the above is sufficient.)
3296ff6d951SJohn Birrell  *
3306ff6d951SJohn Birrell  * In decimal, the square root of 582,734 would be calculated as so:
3316ff6d951SJohn Birrell  *
3326ff6d951SJohn Birrell  *     __7__6__3
3336ff6d951SJohn Birrell  *    | 58 27 34
3346ff6d951SJohn Birrell  *     -49       (7^2 == 49 => 7 is the first digit in the square root)
3356ff6d951SJohn Birrell  *      --
3366ff6d951SJohn Birrell  *       9 27    (Subtract and bring down the next group.)
3376ff6d951SJohn Birrell  * 146   8 76    (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in
3386ff6d951SJohn Birrell  *      -----     the square root)
3396ff6d951SJohn Birrell  *         51 34 (Subtract and bring down the next group.)
3406ff6d951SJohn Birrell  * 1523    45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in
3416ff6d951SJohn Birrell  *         -----  the square root)
3426ff6d951SJohn Birrell  *          5 65 (remainder)
3436ff6d951SJohn Birrell  *
3446ff6d951SJohn Birrell  * The above algorithm applies similarly in binary, but note that the
3456ff6d951SJohn Birrell  * only possible non-zero value for x in step 4 is 1, so step 4 becomes a
3466ff6d951SJohn Birrell  * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the
3476ff6d951SJohn Birrell  * preceding difference?
3486ff6d951SJohn Birrell  *
3496ff6d951SJohn Birrell  * In binary, the square root of 11011011 would be calculated as so:
3506ff6d951SJohn Birrell  *
3516ff6d951SJohn Birrell  *     __1__1__1__0
3526ff6d951SJohn Birrell  *    | 11 01 10 11
3536ff6d951SJohn Birrell  *      01          (0 << 2 + 1 == 1 < 11 => this bit is 1)
3546ff6d951SJohn Birrell  *      --
3556ff6d951SJohn Birrell  *      10 01 10 11
3566ff6d951SJohn Birrell  * 101   1 01       (1 << 2 + 1 == 101 < 1001 => next bit is 1)
3576ff6d951SJohn Birrell  *      -----
3586ff6d951SJohn Birrell  *       1 00 10 11
3596ff6d951SJohn Birrell  * 1101    11 01    (11 << 2 + 1 == 1101 < 10010 => next bit is 1)
3606ff6d951SJohn Birrell  *       -------
3616ff6d951SJohn Birrell  *          1 01 11
3626ff6d951SJohn Birrell  * 11101    1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0)
3636ff6d951SJohn Birrell  *
3646ff6d951SJohn Birrell  */
3656ff6d951SJohn Birrell static uint64_t
dt_sqrt_128(uint64_t * square)3666ff6d951SJohn Birrell dt_sqrt_128(uint64_t *square)
3676ff6d951SJohn Birrell {
3686ff6d951SJohn Birrell 	uint64_t result[2] = { 0, 0 };
3696ff6d951SJohn Birrell 	uint64_t diff[2] = { 0, 0 };
3706ff6d951SJohn Birrell 	uint64_t one[2] = { 1, 0 };
3716ff6d951SJohn Birrell 	uint64_t next_pair[2];
3726ff6d951SJohn Birrell 	uint64_t next_try[2];
3736ff6d951SJohn Birrell 	uint64_t bit_pairs, pair_shift;
3746ff6d951SJohn Birrell 	int i;
3756ff6d951SJohn Birrell 
3766ff6d951SJohn Birrell 	bit_pairs = dt_nbits_128(square) / 2;
3776ff6d951SJohn Birrell 	pair_shift = bit_pairs * 2;
3786ff6d951SJohn Birrell 
3796ff6d951SJohn Birrell 	for (i = 0; i <= bit_pairs; i++) {
3806ff6d951SJohn Birrell 		/*
3816ff6d951SJohn Birrell 		 * Bring down the next pair of bits.
3826ff6d951SJohn Birrell 		 */
3836ff6d951SJohn Birrell 		next_pair[0] = square[0];
3846ff6d951SJohn Birrell 		next_pair[1] = square[1];
3856ff6d951SJohn Birrell 		dt_shift_128(next_pair, -pair_shift);
3866ff6d951SJohn Birrell 		next_pair[0] &= 0x3;
3876ff6d951SJohn Birrell 		next_pair[1] = 0;
3886ff6d951SJohn Birrell 
3896ff6d951SJohn Birrell 		dt_shift_128(diff, 2);
3906ff6d951SJohn Birrell 		dt_add_128(diff, next_pair, diff);
3916ff6d951SJohn Birrell 
3926ff6d951SJohn Birrell 		/*
3936ff6d951SJohn Birrell 		 * next_try = R << 2 + 1
3946ff6d951SJohn Birrell 		 */
3956ff6d951SJohn Birrell 		next_try[0] = result[0];
3966ff6d951SJohn Birrell 		next_try[1] = result[1];
3976ff6d951SJohn Birrell 		dt_shift_128(next_try, 2);
3986ff6d951SJohn Birrell 		dt_add_128(next_try, one, next_try);
3996ff6d951SJohn Birrell 
4006ff6d951SJohn Birrell 		if (dt_le_128(next_try, diff)) {
4016ff6d951SJohn Birrell 			dt_subtract_128(diff, next_try, diff);
4026ff6d951SJohn Birrell 			dt_shift_128(result, 1);
4036ff6d951SJohn Birrell 			dt_add_128(result, one, result);
4046ff6d951SJohn Birrell 		} else {
4056ff6d951SJohn Birrell 			dt_shift_128(result, 1);
4066ff6d951SJohn Birrell 		}
4076ff6d951SJohn Birrell 
4086ff6d951SJohn Birrell 		pair_shift -= 2;
4096ff6d951SJohn Birrell 	}
4106ff6d951SJohn Birrell 
4116ff6d951SJohn Birrell 	assert(result[1] == 0);
4126ff6d951SJohn Birrell 
4136ff6d951SJohn Birrell 	return (result[0]);
4146ff6d951SJohn Birrell }
4156ff6d951SJohn Birrell 
4166ff6d951SJohn Birrell uint64_t
dt_stddev(uint64_t * data,uint64_t normal)4176ff6d951SJohn Birrell dt_stddev(uint64_t *data, uint64_t normal)
4186ff6d951SJohn Birrell {
4196ff6d951SJohn Birrell 	uint64_t avg_of_squares[2];
4206ff6d951SJohn Birrell 	uint64_t square_of_avg[2];
4216ff6d951SJohn Birrell 	int64_t norm_avg;
4226ff6d951SJohn Birrell 	uint64_t diff[2];
4236ff6d951SJohn Birrell 
4246ac0e485SMark Johnston 	if (data[0] == 0)
4256ac0e485SMark Johnston 		return (0);
4266ac0e485SMark Johnston 
4276ff6d951SJohn Birrell 	/*
4286ff6d951SJohn Birrell 	 * The standard approximation for standard deviation is
4296ff6d951SJohn Birrell 	 * sqrt(average(x**2) - average(x)**2), i.e. the square root
4306ff6d951SJohn Birrell 	 * of the average of the squares minus the square of the average.
4315ad79d9bSAndriy Gapon 	 * When normalizing, we should divide the sum of x**2 by normal**2.
4326ff6d951SJohn Birrell 	 */
4336ff6d951SJohn Birrell 	dt_divide_128(data + 2, normal, avg_of_squares);
4345ad79d9bSAndriy Gapon 	dt_divide_128(avg_of_squares, normal, avg_of_squares);
4356ff6d951SJohn Birrell 	dt_divide_128(avg_of_squares, data[0], avg_of_squares);
4366ff6d951SJohn Birrell 
4376ff6d951SJohn Birrell 	norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0];
4386ff6d951SJohn Birrell 
4396ff6d951SJohn Birrell 	if (norm_avg < 0)
4406ff6d951SJohn Birrell 		norm_avg = -norm_avg;
4416ff6d951SJohn Birrell 
4426ff6d951SJohn Birrell 	dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg);
4436ff6d951SJohn Birrell 
4446ff6d951SJohn Birrell 	dt_subtract_128(avg_of_squares, square_of_avg, diff);
4456ff6d951SJohn Birrell 
4466ff6d951SJohn Birrell 	return (dt_sqrt_128(diff));
4476ff6d951SJohn Birrell }
4486ff6d951SJohn Birrell 
4496ff6d951SJohn Birrell static int
dt_flowindent(dtrace_hdl_t * dtp,dtrace_probedata_t * data,dtrace_epid_t last,dtrace_bufdesc_t * buf,size_t offs)4506ff6d951SJohn Birrell dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
4516ff6d951SJohn Birrell     dtrace_bufdesc_t *buf, size_t offs)
4526ff6d951SJohn Birrell {
4536ff6d951SJohn Birrell 	dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd;
4546ff6d951SJohn Birrell 	dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd;
4556ff6d951SJohn Birrell 	char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub;
4566ff6d951SJohn Birrell 	dtrace_flowkind_t flow = DTRACEFLOW_NONE;
4576ff6d951SJohn Birrell 	const char *str = NULL;
4586ff6d951SJohn Birrell 	static const char *e_str[2] = { " -> ", " => " };
4596ff6d951SJohn Birrell 	static const char *r_str[2] = { " <- ", " <= " };
4606ff6d951SJohn Birrell 	static const char *ent = "entry", *ret = "return";
4616ff6d951SJohn Birrell 	static int entlen = 0, retlen = 0;
4626ff6d951SJohn Birrell 	dtrace_epid_t next, id = epd->dtepd_epid;
4636ff6d951SJohn Birrell 	int rval;
4646ff6d951SJohn Birrell 
4656ff6d951SJohn Birrell 	if (entlen == 0) {
4666ff6d951SJohn Birrell 		assert(retlen == 0);
4676ff6d951SJohn Birrell 		entlen = strlen(ent);
4686ff6d951SJohn Birrell 		retlen = strlen(ret);
4696ff6d951SJohn Birrell 	}
4706ff6d951SJohn Birrell 
4716ff6d951SJohn Birrell 	/*
4726ff6d951SJohn Birrell 	 * If the name of the probe is "entry" or ends with "-entry", we
4736ff6d951SJohn Birrell 	 * treat it as an entry; if it is "return" or ends with "-return",
4746ff6d951SJohn Birrell 	 * we treat it as a return.  (This allows application-provided probes
4756ff6d951SJohn Birrell 	 * like "method-entry" or "function-entry" to participate in flow
4766ff6d951SJohn Birrell 	 * indentation -- without accidentally misinterpreting popular probe
4776ff6d951SJohn Birrell 	 * names like "carpentry", "gentry" or "Coventry".)
4786ff6d951SJohn Birrell 	 */
4796ff6d951SJohn Birrell 	if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' &&
4806ff6d951SJohn Birrell 	    (sub == n || sub[-1] == '-')) {
4816ff6d951SJohn Birrell 		flow = DTRACEFLOW_ENTRY;
4826ff6d951SJohn Birrell 		str = e_str[strcmp(p, "syscall") == 0];
4836ff6d951SJohn Birrell 	} else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' &&
4846ff6d951SJohn Birrell 	    (sub == n || sub[-1] == '-')) {
4856ff6d951SJohn Birrell 		flow = DTRACEFLOW_RETURN;
4866ff6d951SJohn Birrell 		str = r_str[strcmp(p, "syscall") == 0];
4876ff6d951SJohn Birrell 	}
4886ff6d951SJohn Birrell 
4896ff6d951SJohn Birrell 	/*
4906ff6d951SJohn Birrell 	 * If we're going to indent this, we need to check the ID of our last
4916ff6d951SJohn Birrell 	 * call.  If we're looking at the same probe ID but a different EPID,
4926ff6d951SJohn Birrell 	 * we _don't_ want to indent.  (Yes, there are some minor holes in
4936ff6d951SJohn Birrell 	 * this scheme -- it's a heuristic.)
4946ff6d951SJohn Birrell 	 */
4956ff6d951SJohn Birrell 	if (flow == DTRACEFLOW_ENTRY) {
4966ff6d951SJohn Birrell 		if ((last != DTRACE_EPIDNONE && id != last &&
4976ff6d951SJohn Birrell 		    pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id))
4986ff6d951SJohn Birrell 			flow = DTRACEFLOW_NONE;
4996ff6d951SJohn Birrell 	}
5006ff6d951SJohn Birrell 
5016ff6d951SJohn Birrell 	/*
5026ff6d951SJohn Birrell 	 * If we're going to unindent this, it's more difficult to see if
5036ff6d951SJohn Birrell 	 * we don't actually want to unindent it -- we need to look at the
5046ff6d951SJohn Birrell 	 * _next_ EPID.
5056ff6d951SJohn Birrell 	 */
5066ff6d951SJohn Birrell 	if (flow == DTRACEFLOW_RETURN) {
5076ff6d951SJohn Birrell 		offs += epd->dtepd_size;
5086ff6d951SJohn Birrell 
5096ff6d951SJohn Birrell 		do {
51009e6105fSMark Johnston 			if (offs >= buf->dtbd_size)
5116ff6d951SJohn Birrell 				goto out;
5126ff6d951SJohn Birrell 
5136ff6d951SJohn Birrell 			next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
5146ff6d951SJohn Birrell 
5156ff6d951SJohn Birrell 			if (next == DTRACE_EPIDNONE)
5166ff6d951SJohn Birrell 				offs += sizeof (id);
5176ff6d951SJohn Birrell 		} while (next == DTRACE_EPIDNONE);
5186ff6d951SJohn Birrell 
5196ff6d951SJohn Birrell 		if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0)
5206ff6d951SJohn Birrell 			return (rval);
5216ff6d951SJohn Birrell 
5226ff6d951SJohn Birrell 		if (next != id && npd->dtpd_id == pd->dtpd_id)
5236ff6d951SJohn Birrell 			flow = DTRACEFLOW_NONE;
5246ff6d951SJohn Birrell 	}
5256ff6d951SJohn Birrell 
5266ff6d951SJohn Birrell out:
5276ff6d951SJohn Birrell 	if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) {
5286ff6d951SJohn Birrell 		data->dtpda_prefix = str;
5296ff6d951SJohn Birrell 	} else {
5306ff6d951SJohn Birrell 		data->dtpda_prefix = "| ";
5316ff6d951SJohn Birrell 	}
5326ff6d951SJohn Birrell 
5336ff6d951SJohn Birrell 	if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0)
5346ff6d951SJohn Birrell 		data->dtpda_indent -= 2;
5356ff6d951SJohn Birrell 
5366ff6d951SJohn Birrell 	data->dtpda_flow = flow;
5376ff6d951SJohn Birrell 
5386ff6d951SJohn Birrell 	return (0);
5396ff6d951SJohn Birrell }
5406ff6d951SJohn Birrell 
5416ff6d951SJohn Birrell static int
dt_nullprobe()5426ff6d951SJohn Birrell dt_nullprobe()
5436ff6d951SJohn Birrell {
5446ff6d951SJohn Birrell 	return (DTRACE_CONSUME_THIS);
5456ff6d951SJohn Birrell }
5466ff6d951SJohn Birrell 
5476ff6d951SJohn Birrell static int
dt_nullrec()5486ff6d951SJohn Birrell dt_nullrec()
5496ff6d951SJohn Birrell {
5506ff6d951SJohn Birrell 	return (DTRACE_CONSUME_NEXT);
5516ff6d951SJohn Birrell }
5526ff6d951SJohn Birrell 
553a43f0be9SRui Paulo static void
dt_quantize_total(dtrace_hdl_t * dtp,int64_t datum,long double * total)554a43f0be9SRui Paulo dt_quantize_total(dtrace_hdl_t *dtp, int64_t datum, long double *total)
555a43f0be9SRui Paulo {
556a43f0be9SRui Paulo 	long double val = dt_fabsl((long double)datum);
557a43f0be9SRui Paulo 
558a43f0be9SRui Paulo 	if (dtp->dt_options[DTRACEOPT_AGGZOOM] == DTRACEOPT_UNSET) {
559a43f0be9SRui Paulo 		*total += val;
560a43f0be9SRui Paulo 		return;
561a43f0be9SRui Paulo 	}
562a43f0be9SRui Paulo 
563a43f0be9SRui Paulo 	/*
564a43f0be9SRui Paulo 	 * If we're zooming in on an aggregation, we want the height of the
565a43f0be9SRui Paulo 	 * highest value to be approximately 95% of total bar height -- so we
566a43f0be9SRui Paulo 	 * adjust up by the reciprocal of DTRACE_AGGZOOM_MAX when comparing to
567a43f0be9SRui Paulo 	 * our highest value.
568a43f0be9SRui Paulo 	 */
569a43f0be9SRui Paulo 	val *= 1 / DTRACE_AGGZOOM_MAX;
570a43f0be9SRui Paulo 
571a43f0be9SRui Paulo 	if (*total < val)
572a43f0be9SRui Paulo 		*total = val;
573a43f0be9SRui Paulo }
574a43f0be9SRui Paulo 
575a43f0be9SRui Paulo static int
dt_print_quanthdr(dtrace_hdl_t * dtp,FILE * fp,int width)576a43f0be9SRui Paulo dt_print_quanthdr(dtrace_hdl_t *dtp, FILE *fp, int width)
577a43f0be9SRui Paulo {
578a43f0be9SRui Paulo 	return (dt_printf(dtp, fp, "\n%*s %41s %-9s\n",
579a43f0be9SRui Paulo 	    width ? width : 16, width ? "key" : "value",
580a43f0be9SRui Paulo 	    "------------- Distribution -------------", "count"));
581a43f0be9SRui Paulo }
582a43f0be9SRui Paulo 
583a43f0be9SRui Paulo static int
dt_print_quanthdr_packed(dtrace_hdl_t * dtp,FILE * fp,int width,const dtrace_aggdata_t * aggdata,dtrace_actkind_t action)584a43f0be9SRui Paulo dt_print_quanthdr_packed(dtrace_hdl_t *dtp, FILE *fp, int width,
585a43f0be9SRui Paulo     const dtrace_aggdata_t *aggdata, dtrace_actkind_t action)
586a43f0be9SRui Paulo {
587a43f0be9SRui Paulo 	int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin;
588a43f0be9SRui Paulo 	int minwidth, maxwidth, i;
589a43f0be9SRui Paulo 
590a43f0be9SRui Paulo 	assert(action == DTRACEAGG_QUANTIZE || action == DTRACEAGG_LQUANTIZE);
591a43f0be9SRui Paulo 
592a43f0be9SRui Paulo 	if (action == DTRACEAGG_QUANTIZE) {
593a43f0be9SRui Paulo 		if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET)
594a43f0be9SRui Paulo 			min--;
595a43f0be9SRui Paulo 
596a43f0be9SRui Paulo 		if (max < DTRACE_QUANTIZE_NBUCKETS - 1)
597a43f0be9SRui Paulo 			max++;
598a43f0be9SRui Paulo 
599a43f0be9SRui Paulo 		minwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(min));
600a43f0be9SRui Paulo 		maxwidth = dt_ndigits(DTRACE_QUANTIZE_BUCKETVAL(max));
601a43f0be9SRui Paulo 	} else {
602a43f0be9SRui Paulo 		maxwidth = 8;
603a43f0be9SRui Paulo 		minwidth = maxwidth - 1;
604a43f0be9SRui Paulo 		max++;
605a43f0be9SRui Paulo 	}
606a43f0be9SRui Paulo 
607a43f0be9SRui Paulo 	if (dt_printf(dtp, fp, "\n%*s %*s .",
608a43f0be9SRui Paulo 	    width, width > 0 ? "key" : "", minwidth, "min") < 0)
609a43f0be9SRui Paulo 		return (-1);
610a43f0be9SRui Paulo 
611a43f0be9SRui Paulo 	for (i = min; i <= max; i++) {
612a43f0be9SRui Paulo 		if (dt_printf(dtp, fp, "-") < 0)
613a43f0be9SRui Paulo 			return (-1);
614a43f0be9SRui Paulo 	}
615a43f0be9SRui Paulo 
616a43f0be9SRui Paulo 	return (dt_printf(dtp, fp, ". %*s | count\n", -maxwidth, "max"));
617a43f0be9SRui Paulo }
618a43f0be9SRui Paulo 
619a43f0be9SRui Paulo /*
620a43f0be9SRui Paulo  * We use a subset of the Unicode Block Elements (U+2588 through U+258F,
621a43f0be9SRui Paulo  * inclusive) to represent aggregations via UTF-8 -- which are expressed via
622a43f0be9SRui Paulo  * 3-byte UTF-8 sequences.
623a43f0be9SRui Paulo  */
624a43f0be9SRui Paulo #define	DTRACE_AGGUTF8_FULL	0x2588
625a43f0be9SRui Paulo #define	DTRACE_AGGUTF8_BASE	0x258f
626a43f0be9SRui Paulo #define	DTRACE_AGGUTF8_LEVELS	8
627a43f0be9SRui Paulo 
628a43f0be9SRui Paulo #define	DTRACE_AGGUTF8_BYTE0(val)	(0xe0 | ((val) >> 12))
629a43f0be9SRui Paulo #define	DTRACE_AGGUTF8_BYTE1(val)	(0x80 | (((val) >> 6) & 0x3f))
630a43f0be9SRui Paulo #define	DTRACE_AGGUTF8_BYTE2(val)	(0x80 | ((val) & 0x3f))
631a43f0be9SRui Paulo 
632a43f0be9SRui Paulo static int
dt_print_quantline_utf8(dtrace_hdl_t * dtp,FILE * fp,int64_t val,uint64_t normal,long double total)633a43f0be9SRui Paulo dt_print_quantline_utf8(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
634a43f0be9SRui Paulo     uint64_t normal, long double total)
635a43f0be9SRui Paulo {
636a43f0be9SRui Paulo 	uint_t len = 40, i, whole, partial;
637a43f0be9SRui Paulo 	long double f = (dt_fabsl((long double)val) * len) / total;
638a43f0be9SRui Paulo 	const char *spaces = "                                        ";
639a43f0be9SRui Paulo 
640a43f0be9SRui Paulo 	whole = (uint_t)f;
641a43f0be9SRui Paulo 	partial = (uint_t)((f - (long double)(uint_t)f) *
642a43f0be9SRui Paulo 	    (long double)DTRACE_AGGUTF8_LEVELS);
643a43f0be9SRui Paulo 
644a43f0be9SRui Paulo 	if (dt_printf(dtp, fp, "|") < 0)
645a43f0be9SRui Paulo 		return (-1);
646a43f0be9SRui Paulo 
647a43f0be9SRui Paulo 	for (i = 0; i < whole; i++) {
648a43f0be9SRui Paulo 		if (dt_printf(dtp, fp, "%c%c%c",
649a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE0(DTRACE_AGGUTF8_FULL),
650a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE1(DTRACE_AGGUTF8_FULL),
651a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE2(DTRACE_AGGUTF8_FULL)) < 0)
652a43f0be9SRui Paulo 			return (-1);
653a43f0be9SRui Paulo 	}
654a43f0be9SRui Paulo 
655a43f0be9SRui Paulo 	if (partial != 0) {
656a43f0be9SRui Paulo 		partial = DTRACE_AGGUTF8_BASE - (partial - 1);
657a43f0be9SRui Paulo 
658a43f0be9SRui Paulo 		if (dt_printf(dtp, fp, "%c%c%c",
659a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE0(partial),
660a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE1(partial),
661a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE2(partial)) < 0)
662a43f0be9SRui Paulo 			return (-1);
663a43f0be9SRui Paulo 
664a43f0be9SRui Paulo 		i++;
665a43f0be9SRui Paulo 	}
666a43f0be9SRui Paulo 
667a43f0be9SRui Paulo 	return (dt_printf(dtp, fp, "%s %-9lld\n", spaces + i,
668a43f0be9SRui Paulo 	    (long long)val / normal));
669a43f0be9SRui Paulo }
670a43f0be9SRui Paulo 
671a43f0be9SRui Paulo static int
dt_print_quantline(dtrace_hdl_t * dtp,FILE * fp,int64_t val,uint64_t normal,long double total,char positives,char negatives)6726ff6d951SJohn Birrell dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
6736ff6d951SJohn Birrell     uint64_t normal, long double total, char positives, char negatives)
6746ff6d951SJohn Birrell {
6756ff6d951SJohn Birrell 	long double f;
6766ff6d951SJohn Birrell 	uint_t depth, len = 40;
6776ff6d951SJohn Birrell 
6786ff6d951SJohn Birrell 	const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
6796ff6d951SJohn Birrell 	const char *spaces = "                                        ";
6806ff6d951SJohn Birrell 
6816ff6d951SJohn Birrell 	assert(strlen(ats) == len && strlen(spaces) == len);
6826ff6d951SJohn Birrell 	assert(!(total == 0 && (positives || negatives)));
6836ff6d951SJohn Birrell 	assert(!(val < 0 && !negatives));
6846ff6d951SJohn Birrell 	assert(!(val > 0 && !positives));
6856ff6d951SJohn Birrell 	assert(!(val != 0 && total == 0));
6866ff6d951SJohn Birrell 
6876ff6d951SJohn Birrell 	if (!negatives) {
6886ff6d951SJohn Birrell 		if (positives) {
689a43f0be9SRui Paulo 			if (dtp->dt_encoding == DT_ENCODING_UTF8) {
690a43f0be9SRui Paulo 				return (dt_print_quantline_utf8(dtp, fp, val,
691a43f0be9SRui Paulo 				    normal, total));
692a43f0be9SRui Paulo 			}
693a43f0be9SRui Paulo 
6946ff6d951SJohn Birrell 			f = (dt_fabsl((long double)val) * len) / total;
6956ff6d951SJohn Birrell 			depth = (uint_t)(f + 0.5);
6966ff6d951SJohn Birrell 		} else {
6976ff6d951SJohn Birrell 			depth = 0;
6986ff6d951SJohn Birrell 		}
6996ff6d951SJohn Birrell 
7006ff6d951SJohn Birrell 		return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth,
7016ff6d951SJohn Birrell 		    spaces + depth, (long long)val / normal));
7026ff6d951SJohn Birrell 	}
7036ff6d951SJohn Birrell 
7046ff6d951SJohn Birrell 	if (!positives) {
7056ff6d951SJohn Birrell 		f = (dt_fabsl((long double)val) * len) / total;
7066ff6d951SJohn Birrell 		depth = (uint_t)(f + 0.5);
7076ff6d951SJohn Birrell 
7086ff6d951SJohn Birrell 		return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth,
7096ff6d951SJohn Birrell 		    ats + len - depth, (long long)val / normal));
7106ff6d951SJohn Birrell 	}
7116ff6d951SJohn Birrell 
7126ff6d951SJohn Birrell 	/*
7136ff6d951SJohn Birrell 	 * If we're here, we have both positive and negative bucket values.
7146ff6d951SJohn Birrell 	 * To express this graphically, we're going to generate both positive
7156ff6d951SJohn Birrell 	 * and negative bars separated by a centerline.  These bars are half
7166ff6d951SJohn Birrell 	 * the size of normal quantize()/lquantize() bars, so we divide the
7176ff6d951SJohn Birrell 	 * length in half before calculating the bar length.
7186ff6d951SJohn Birrell 	 */
7196ff6d951SJohn Birrell 	len /= 2;
7206ff6d951SJohn Birrell 	ats = &ats[len];
7216ff6d951SJohn Birrell 	spaces = &spaces[len];
7226ff6d951SJohn Birrell 
7236ff6d951SJohn Birrell 	f = (dt_fabsl((long double)val) * len) / total;
7246ff6d951SJohn Birrell 	depth = (uint_t)(f + 0.5);
7256ff6d951SJohn Birrell 
7266ff6d951SJohn Birrell 	if (val <= 0) {
7276ff6d951SJohn Birrell 		return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth,
7286ff6d951SJohn Birrell 		    ats + len - depth, len, "", (long long)val / normal));
7296ff6d951SJohn Birrell 	} else {
7306ff6d951SJohn Birrell 		return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "",
7316ff6d951SJohn Birrell 		    ats + len - depth, spaces + depth,
7326ff6d951SJohn Birrell 		    (long long)val / normal));
7336ff6d951SJohn Birrell 	}
7346ff6d951SJohn Birrell }
7356ff6d951SJohn Birrell 
736a43f0be9SRui Paulo /*
737a43f0be9SRui Paulo  * As with UTF-8 printing of aggregations, we use a subset of the Unicode
738a43f0be9SRui Paulo  * Block Elements (U+2581 through U+2588, inclusive) to represent our packed
739a43f0be9SRui Paulo  * aggregation.
740a43f0be9SRui Paulo  */
741a43f0be9SRui Paulo #define	DTRACE_AGGPACK_BASE	0x2581
742a43f0be9SRui Paulo #define	DTRACE_AGGPACK_LEVELS	8
743a43f0be9SRui Paulo 
744a43f0be9SRui Paulo static int
dt_print_packed(dtrace_hdl_t * dtp,FILE * fp,long double datum,long double total)745a43f0be9SRui Paulo dt_print_packed(dtrace_hdl_t *dtp, FILE *fp,
746a43f0be9SRui Paulo     long double datum, long double total)
747a43f0be9SRui Paulo {
748a43f0be9SRui Paulo 	static boolean_t utf8_checked = B_FALSE;
749a43f0be9SRui Paulo 	static boolean_t utf8;
750a43f0be9SRui Paulo 	char *ascii = "__xxxxXX";
751a43f0be9SRui Paulo 	char *neg = "vvvvVV";
752a43f0be9SRui Paulo 	unsigned int len;
753a43f0be9SRui Paulo 	long double val;
754a43f0be9SRui Paulo 
755a43f0be9SRui Paulo 	if (!utf8_checked) {
756a43f0be9SRui Paulo 		char *term;
757a43f0be9SRui Paulo 
758a43f0be9SRui Paulo 		/*
759a43f0be9SRui Paulo 		 * We want to determine if we can reasonably emit UTF-8 for our
760a43f0be9SRui Paulo 		 * packed aggregation.  To do this, we will check for terminals
761a43f0be9SRui Paulo 		 * that are known to be primitive to emit UTF-8 on these.
762a43f0be9SRui Paulo 		 */
763a43f0be9SRui Paulo 		utf8_checked = B_TRUE;
764a43f0be9SRui Paulo 
765a43f0be9SRui Paulo 		if (dtp->dt_encoding == DT_ENCODING_ASCII) {
766a43f0be9SRui Paulo 			utf8 = B_FALSE;
767a43f0be9SRui Paulo 		} else if (dtp->dt_encoding == DT_ENCODING_UTF8) {
768a43f0be9SRui Paulo 			utf8 = B_TRUE;
769a43f0be9SRui Paulo 		} else if ((term = getenv("TERM")) != NULL &&
770a43f0be9SRui Paulo 		    (strcmp(term, "sun") == 0 ||
77128cb2a5fSMark Johnston 		    strcmp(term, "sun-color") == 0 ||
77228cb2a5fSMark Johnston 		    strcmp(term, "dumb") == 0)) {
773a43f0be9SRui Paulo 			utf8 = B_FALSE;
774a43f0be9SRui Paulo 		} else {
775a43f0be9SRui Paulo 			utf8 = B_TRUE;
776a43f0be9SRui Paulo 		}
777a43f0be9SRui Paulo 	}
778a43f0be9SRui Paulo 
779a43f0be9SRui Paulo 	if (datum == 0)
780a43f0be9SRui Paulo 		return (dt_printf(dtp, fp, " "));
781a43f0be9SRui Paulo 
782a43f0be9SRui Paulo 	if (datum < 0) {
783a43f0be9SRui Paulo 		len = strlen(neg);
784a43f0be9SRui Paulo 		val = dt_fabsl(datum * (len - 1)) / total;
785a43f0be9SRui Paulo 		return (dt_printf(dtp, fp, "%c", neg[(uint_t)(val + 0.5)]));
786a43f0be9SRui Paulo 	}
787a43f0be9SRui Paulo 
788a43f0be9SRui Paulo 	if (utf8) {
789a43f0be9SRui Paulo 		int block = DTRACE_AGGPACK_BASE + (unsigned int)(((datum *
790a43f0be9SRui Paulo 		    (DTRACE_AGGPACK_LEVELS - 1)) / total) + 0.5);
791a43f0be9SRui Paulo 
792a43f0be9SRui Paulo 		return (dt_printf(dtp, fp, "%c%c%c",
793a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE0(block),
794a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE1(block),
795a43f0be9SRui Paulo 		    DTRACE_AGGUTF8_BYTE2(block)));
796a43f0be9SRui Paulo 	}
797a43f0be9SRui Paulo 
798a43f0be9SRui Paulo 	len = strlen(ascii);
799a43f0be9SRui Paulo 	val = (datum * (len - 1)) / total;
800a43f0be9SRui Paulo 	return (dt_printf(dtp, fp, "%c", ascii[(uint_t)(val + 0.5)]));
801a43f0be9SRui Paulo }
802a43f0be9SRui Paulo 
80393f27766SDomagoj Stolfa static const int64_t *
dt_format_quantize_prepare(dtrace_hdl_t * dtp,const void * addr,size_t size,dt_prepare_args_t * args)80493f27766SDomagoj Stolfa dt_format_quantize_prepare(dtrace_hdl_t *dtp, const void *addr, size_t size,
80593f27766SDomagoj Stolfa     dt_prepare_args_t *args)
8066ff6d951SJohn Birrell {
8076ff6d951SJohn Birrell 	const int64_t *data = addr;
80893f27766SDomagoj Stolfa 	int first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
8096ff6d951SJohn Birrell 
81093f27766SDomagoj Stolfa 	if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t)) {
81193f27766SDomagoj Stolfa 		(void) dt_set_errno(dtp, EDT_DMISMATCH);
81293f27766SDomagoj Stolfa 		return (NULL);
81393f27766SDomagoj Stolfa 	}
8146ff6d951SJohn Birrell 
8156ff6d951SJohn Birrell 	while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
8166ff6d951SJohn Birrell 		first_bin++;
8176ff6d951SJohn Birrell 
8186ff6d951SJohn Birrell 	if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) {
8196ff6d951SJohn Birrell 		/*
820a43f0be9SRui Paulo 		 * There isn't any data.  This is possible if the aggregation
821a43f0be9SRui Paulo 		 * has been clear()'d or if negative increment values have been
822a43f0be9SRui Paulo 		 * used.  Regardless, we'll print the buckets around 0.
8236ff6d951SJohn Birrell 		 */
8246ff6d951SJohn Birrell 		first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1;
8256ff6d951SJohn Birrell 		last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1;
8266ff6d951SJohn Birrell 	} else {
8276ff6d951SJohn Birrell 		if (first_bin > 0)
8286ff6d951SJohn Birrell 			first_bin--;
8296ff6d951SJohn Birrell 
8306ff6d951SJohn Birrell 		while (last_bin > 0 && data[last_bin] == 0)
8316ff6d951SJohn Birrell 			last_bin--;
8326ff6d951SJohn Birrell 
8336ff6d951SJohn Birrell 		if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
8346ff6d951SJohn Birrell 			last_bin++;
8356ff6d951SJohn Birrell 	}
8366ff6d951SJohn Birrell 
83793f27766SDomagoj Stolfa 	args->first_bin = first_bin;
83893f27766SDomagoj Stolfa 	args->last_bin = last_bin;
83993f27766SDomagoj Stolfa 	return (data);
84093f27766SDomagoj Stolfa }
84193f27766SDomagoj Stolfa 
84293f27766SDomagoj Stolfa int
dt_format_quantize(dtrace_hdl_t * dtp,const void * addr,size_t size,uint64_t normal)84393f27766SDomagoj Stolfa dt_format_quantize(dtrace_hdl_t *dtp, const void *addr, size_t size,
84493f27766SDomagoj Stolfa     uint64_t normal)
84593f27766SDomagoj Stolfa {
84693f27766SDomagoj Stolfa 	const int64_t *data;
84793f27766SDomagoj Stolfa 	dt_prepare_args_t args = { 0 };
84893f27766SDomagoj Stolfa 	int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
84993f27766SDomagoj Stolfa 
85093f27766SDomagoj Stolfa 	data = dt_format_quantize_prepare(dtp, addr, size, &args);
85193f27766SDomagoj Stolfa 	/* dt_errno is set for us */
85293f27766SDomagoj Stolfa 	if (data == NULL)
85393f27766SDomagoj Stolfa 		return (-1);
85493f27766SDomagoj Stolfa 
85593f27766SDomagoj Stolfa 	first_bin = args.first_bin;
85693f27766SDomagoj Stolfa 	last_bin = args.last_bin;
85793f27766SDomagoj Stolfa 
85893f27766SDomagoj Stolfa 	xo_open_list("buckets");
85993f27766SDomagoj Stolfa 	for (i = first_bin; i <= last_bin; i++) {
86093f27766SDomagoj Stolfa 		long long value = (long long)DTRACE_QUANTIZE_BUCKETVAL(i);
86193f27766SDomagoj Stolfa 		xo_open_instance("buckets");
86293f27766SDomagoj Stolfa 		xo_emit("{:value/%lld} {:count/%lld}", value,
86393f27766SDomagoj Stolfa 		    (long long)data[i] / normal);
86493f27766SDomagoj Stolfa 		xo_close_instance("buckets");
86593f27766SDomagoj Stolfa 	}
86693f27766SDomagoj Stolfa 	xo_close_list("buckets");
86793f27766SDomagoj Stolfa 
86893f27766SDomagoj Stolfa 	return (0);
86993f27766SDomagoj Stolfa }
87093f27766SDomagoj Stolfa 
87193f27766SDomagoj Stolfa int
dt_print_quantize(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,uint64_t normal)87293f27766SDomagoj Stolfa dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
87393f27766SDomagoj Stolfa     size_t size, uint64_t normal)
87493f27766SDomagoj Stolfa {
87593f27766SDomagoj Stolfa 	const int64_t *data;
87693f27766SDomagoj Stolfa 	dt_prepare_args_t args = { 0 };
87793f27766SDomagoj Stolfa 	int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
87893f27766SDomagoj Stolfa 	long double total = 0;
87993f27766SDomagoj Stolfa 	char positives = 0, negatives = 0;
88093f27766SDomagoj Stolfa 
88193f27766SDomagoj Stolfa 	data = dt_format_quantize_prepare(dtp, addr, size, &args);
88293f27766SDomagoj Stolfa 	/* dt_errno is set for us */
88393f27766SDomagoj Stolfa 	if (data == NULL)
88493f27766SDomagoj Stolfa 		return (-1);
88593f27766SDomagoj Stolfa 
88693f27766SDomagoj Stolfa 	first_bin = args.first_bin;
88793f27766SDomagoj Stolfa 	last_bin = args.last_bin;
88893f27766SDomagoj Stolfa 
8896ff6d951SJohn Birrell 	for (i = first_bin; i <= last_bin; i++) {
8906ff6d951SJohn Birrell 		positives |= (data[i] > 0);
8916ff6d951SJohn Birrell 		negatives |= (data[i] < 0);
892a43f0be9SRui Paulo 		dt_quantize_total(dtp, data[i], &total);
8936ff6d951SJohn Birrell 	}
8946ff6d951SJohn Birrell 
895a43f0be9SRui Paulo 	if (dt_print_quanthdr(dtp, fp, 0) < 0)
8966ff6d951SJohn Birrell 		return (-1);
8976ff6d951SJohn Birrell 
8986ff6d951SJohn Birrell 	for (i = first_bin; i <= last_bin; i++) {
8996ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "%16lld ",
9006ff6d951SJohn Birrell 		    (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0)
9016ff6d951SJohn Birrell 			return (-1);
9026ff6d951SJohn Birrell 
9036ff6d951SJohn Birrell 		if (dt_print_quantline(dtp, fp, data[i], normal, total,
9046ff6d951SJohn Birrell 		    positives, negatives) < 0)
9056ff6d951SJohn Birrell 			return (-1);
9066ff6d951SJohn Birrell 	}
9076ff6d951SJohn Birrell 
9086ff6d951SJohn Birrell 	return (0);
9096ff6d951SJohn Birrell }
9106ff6d951SJohn Birrell 
9116ff6d951SJohn Birrell int
dt_print_quantize_packed(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,const dtrace_aggdata_t * aggdata)912a43f0be9SRui Paulo dt_print_quantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
913a43f0be9SRui Paulo     size_t size, const dtrace_aggdata_t *aggdata)
914a43f0be9SRui Paulo {
915a43f0be9SRui Paulo 	const int64_t *data = addr;
916a43f0be9SRui Paulo 	long double total = 0, count = 0;
917a43f0be9SRui Paulo 	int min = aggdata->dtada_minbin, max = aggdata->dtada_maxbin, i;
918a43f0be9SRui Paulo 	int64_t minval, maxval;
919a43f0be9SRui Paulo 
920a43f0be9SRui Paulo 	if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
921a43f0be9SRui Paulo 		return (dt_set_errno(dtp, EDT_DMISMATCH));
922a43f0be9SRui Paulo 
923a43f0be9SRui Paulo 	if (min != 0 && min != DTRACE_QUANTIZE_ZEROBUCKET)
924a43f0be9SRui Paulo 		min--;
925a43f0be9SRui Paulo 
926a43f0be9SRui Paulo 	if (max < DTRACE_QUANTIZE_NBUCKETS - 1)
927a43f0be9SRui Paulo 		max++;
928a43f0be9SRui Paulo 
929a43f0be9SRui Paulo 	minval = DTRACE_QUANTIZE_BUCKETVAL(min);
930a43f0be9SRui Paulo 	maxval = DTRACE_QUANTIZE_BUCKETVAL(max);
931a43f0be9SRui Paulo 
932a43f0be9SRui Paulo 	if (dt_printf(dtp, fp, " %*lld :", dt_ndigits(minval),
933a43f0be9SRui Paulo 	    (long long)minval) < 0)
934a43f0be9SRui Paulo 		return (-1);
935a43f0be9SRui Paulo 
936a43f0be9SRui Paulo 	for (i = min; i <= max; i++) {
937a43f0be9SRui Paulo 		dt_quantize_total(dtp, data[i], &total);
938a43f0be9SRui Paulo 		count += data[i];
939a43f0be9SRui Paulo 	}
940a43f0be9SRui Paulo 
941a43f0be9SRui Paulo 	for (i = min; i <= max; i++) {
942a43f0be9SRui Paulo 		if (dt_print_packed(dtp, fp, data[i], total) < 0)
943a43f0be9SRui Paulo 			return (-1);
944a43f0be9SRui Paulo 	}
945a43f0be9SRui Paulo 
946a43f0be9SRui Paulo 	if (dt_printf(dtp, fp, ": %*lld | %lld\n",
947a43f0be9SRui Paulo 	    -dt_ndigits(maxval), (long long)maxval, (long long)count) < 0)
948a43f0be9SRui Paulo 		return (-1);
949a43f0be9SRui Paulo 
950a43f0be9SRui Paulo 	return (0);
951a43f0be9SRui Paulo }
952a43f0be9SRui Paulo 
95393f27766SDomagoj Stolfa static const int64_t *
dt_format_lquantize_prepare(dtrace_hdl_t * dtp,const void * addr,size_t size,dt_prepare_args_t * args)95493f27766SDomagoj Stolfa dt_format_lquantize_prepare(dtrace_hdl_t *dtp, const void *addr, size_t size,
95593f27766SDomagoj Stolfa     dt_prepare_args_t *args)
9566ff6d951SJohn Birrell {
9576ff6d951SJohn Birrell 	const int64_t *data = addr;
95893f27766SDomagoj Stolfa 	int first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1, base;
9596ff6d951SJohn Birrell 	uint64_t arg;
9606ff6d951SJohn Birrell 	uint16_t step, levels;
9616ff6d951SJohn Birrell 
96293f27766SDomagoj Stolfa 	if (size < sizeof (uint64_t)) {
96393f27766SDomagoj Stolfa 		(void) dt_set_errno(dtp, EDT_DMISMATCH);
96493f27766SDomagoj Stolfa 		return (NULL);
96593f27766SDomagoj Stolfa 	}
9666ff6d951SJohn Birrell 
9676ff6d951SJohn Birrell 	arg = *data++;
9686ff6d951SJohn Birrell 	size -= sizeof (uint64_t);
9696ff6d951SJohn Birrell 
9706ff6d951SJohn Birrell 	base = DTRACE_LQUANTIZE_BASE(arg);
9716ff6d951SJohn Birrell 	step = DTRACE_LQUANTIZE_STEP(arg);
9726ff6d951SJohn Birrell 	levels = DTRACE_LQUANTIZE_LEVELS(arg);
9736ff6d951SJohn Birrell 
9746ff6d951SJohn Birrell 	first_bin = 0;
9756ff6d951SJohn Birrell 	last_bin = levels + 1;
9766ff6d951SJohn Birrell 
97793f27766SDomagoj Stolfa 	if (size != sizeof (uint64_t) * (levels + 2)) {
97893f27766SDomagoj Stolfa 		(void) dt_set_errno(dtp, EDT_DMISMATCH);
97993f27766SDomagoj Stolfa 		return (NULL);
98093f27766SDomagoj Stolfa 	}
9816ff6d951SJohn Birrell 
9826ff6d951SJohn Birrell 	while (first_bin <= levels + 1 && data[first_bin] == 0)
9836ff6d951SJohn Birrell 		first_bin++;
9846ff6d951SJohn Birrell 
9856ff6d951SJohn Birrell 	if (first_bin > levels + 1) {
9866ff6d951SJohn Birrell 		first_bin = 0;
9876ff6d951SJohn Birrell 		last_bin = 2;
9886ff6d951SJohn Birrell 	} else {
9896ff6d951SJohn Birrell 		if (first_bin > 0)
9906ff6d951SJohn Birrell 			first_bin--;
9916ff6d951SJohn Birrell 
9926ff6d951SJohn Birrell 		while (last_bin > 0 && data[last_bin] == 0)
9936ff6d951SJohn Birrell 			last_bin--;
9946ff6d951SJohn Birrell 
9956ff6d951SJohn Birrell 		if (last_bin < levels + 1)
9966ff6d951SJohn Birrell 			last_bin++;
9976ff6d951SJohn Birrell 	}
9986ff6d951SJohn Birrell 
99993f27766SDomagoj Stolfa 	args->first_bin = first_bin;
100093f27766SDomagoj Stolfa 	args->last_bin = last_bin;
100193f27766SDomagoj Stolfa 	args->lquantize_base = base;
100293f27766SDomagoj Stolfa 	args->lquantize_step = step;
100393f27766SDomagoj Stolfa 	args->lquantize_levels = levels;
100493f27766SDomagoj Stolfa 	return (data);
100593f27766SDomagoj Stolfa }
100693f27766SDomagoj Stolfa 
100793f27766SDomagoj Stolfa int
dt_format_lquantize(dtrace_hdl_t * dtp,const void * addr,size_t size,uint64_t normal)100893f27766SDomagoj Stolfa dt_format_lquantize(dtrace_hdl_t *dtp, const void *addr, size_t size,
100993f27766SDomagoj Stolfa     uint64_t normal)
101093f27766SDomagoj Stolfa {
101193f27766SDomagoj Stolfa 	const int64_t *data;
101293f27766SDomagoj Stolfa 	dt_prepare_args_t args = { 0 };
101393f27766SDomagoj Stolfa 	int i, first_bin, last_bin, base;
101493f27766SDomagoj Stolfa 	uint16_t step, levels;
101593f27766SDomagoj Stolfa 
101693f27766SDomagoj Stolfa 	data = dt_format_lquantize_prepare(dtp, addr, size, &args);
101793f27766SDomagoj Stolfa 	/* dt_errno is set for us */
101893f27766SDomagoj Stolfa 	if (data == NULL)
101993f27766SDomagoj Stolfa 		return (-1);
102093f27766SDomagoj Stolfa 
102193f27766SDomagoj Stolfa 	first_bin = args.first_bin;
102293f27766SDomagoj Stolfa 	last_bin = args.last_bin;
102393f27766SDomagoj Stolfa 	step = args.lquantize_step;
102493f27766SDomagoj Stolfa 	levels = args.lquantize_levels;
102593f27766SDomagoj Stolfa 	base = args.lquantize_base;
102693f27766SDomagoj Stolfa 
102793f27766SDomagoj Stolfa 	xo_open_list("buckets");
102893f27766SDomagoj Stolfa 	for (i = first_bin; i <= last_bin; i++) {
102993f27766SDomagoj Stolfa 		char c[32];
103093f27766SDomagoj Stolfa 		int err;
103193f27766SDomagoj Stolfa 
103293f27766SDomagoj Stolfa 		xo_open_instance("buckets");
103393f27766SDomagoj Stolfa 		if (i == 0) {
103493f27766SDomagoj Stolfa 			xo_emit("{:value/%d} {:operator/%s}", base, "<");
103593f27766SDomagoj Stolfa 		} else if (i == levels + 1) {
103693f27766SDomagoj Stolfa 			xo_emit("{:value/%d} {:operator/%s}",
103793f27766SDomagoj Stolfa 			    base + (levels * step), ">=");
103893f27766SDomagoj Stolfa 		} else {
103993f27766SDomagoj Stolfa 			xo_emit("{:value/%d}", base + (i - 1) * step);
104093f27766SDomagoj Stolfa 		}
104193f27766SDomagoj Stolfa 
104293f27766SDomagoj Stolfa 		xo_emit("{:count/%lld}", (long long)data[i] / normal);
104393f27766SDomagoj Stolfa 		xo_close_instance("buckets");
104493f27766SDomagoj Stolfa 	}
104593f27766SDomagoj Stolfa 	xo_close_list("buckets");
104693f27766SDomagoj Stolfa 
104793f27766SDomagoj Stolfa 	return (0);
104893f27766SDomagoj Stolfa }
104993f27766SDomagoj Stolfa 
105093f27766SDomagoj Stolfa int
dt_print_lquantize(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,uint64_t normal)105193f27766SDomagoj Stolfa dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
105293f27766SDomagoj Stolfa     size_t size, uint64_t normal)
105393f27766SDomagoj Stolfa {
105493f27766SDomagoj Stolfa 	const int64_t *data;
105593f27766SDomagoj Stolfa 	dt_prepare_args_t args = { 0 };
105693f27766SDomagoj Stolfa 	int i, first_bin, last_bin, base;
105793f27766SDomagoj Stolfa 	uint64_t arg;
105893f27766SDomagoj Stolfa 	long double total = 0;
105993f27766SDomagoj Stolfa 	uint16_t step, levels;
106093f27766SDomagoj Stolfa 	char positives = 0, negatives = 0;
106193f27766SDomagoj Stolfa 
106293f27766SDomagoj Stolfa 	data = dt_format_lquantize_prepare(dtp, addr, size, &args);
106393f27766SDomagoj Stolfa 	/* dt_errno is set for us */
106493f27766SDomagoj Stolfa 	if (data == NULL)
106593f27766SDomagoj Stolfa 		return (-1);
106693f27766SDomagoj Stolfa 
106793f27766SDomagoj Stolfa 	first_bin = args.first_bin;
106893f27766SDomagoj Stolfa 	last_bin = args.last_bin;
106993f27766SDomagoj Stolfa 	step = args.lquantize_step;
107093f27766SDomagoj Stolfa 	levels = args.lquantize_levels;
107193f27766SDomagoj Stolfa 	base = args.lquantize_base;
107293f27766SDomagoj Stolfa 
10736ff6d951SJohn Birrell 	for (i = first_bin; i <= last_bin; i++) {
10746ff6d951SJohn Birrell 		positives |= (data[i] > 0);
10756ff6d951SJohn Birrell 		negatives |= (data[i] < 0);
1076a43f0be9SRui Paulo 		dt_quantize_total(dtp, data[i], &total);
10776ff6d951SJohn Birrell 	}
10786ff6d951SJohn Birrell 
10796ff6d951SJohn Birrell 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
10806ff6d951SJohn Birrell 	    "------------- Distribution -------------", "count") < 0)
10816ff6d951SJohn Birrell 		return (-1);
10826ff6d951SJohn Birrell 
10836ff6d951SJohn Birrell 	for (i = first_bin; i <= last_bin; i++) {
10846ff6d951SJohn Birrell 		char c[32];
10856ff6d951SJohn Birrell 		int err;
10866ff6d951SJohn Birrell 
10876ff6d951SJohn Birrell 		if (i == 0) {
1088a43f0be9SRui Paulo 			(void) snprintf(c, sizeof (c), "< %d", base);
10896ff6d951SJohn Birrell 			err = dt_printf(dtp, fp, "%16s ", c);
10906ff6d951SJohn Birrell 		} else if (i == levels + 1) {
10916ff6d951SJohn Birrell 			(void) snprintf(c, sizeof (c), ">= %d",
10926ff6d951SJohn Birrell 			    base + (levels * step));
10936ff6d951SJohn Birrell 			err = dt_printf(dtp, fp, "%16s ", c);
10946ff6d951SJohn Birrell 		} else {
10956ff6d951SJohn Birrell 			err = dt_printf(dtp, fp, "%16d ",
10966ff6d951SJohn Birrell 			    base + (i - 1) * step);
10976ff6d951SJohn Birrell 		}
10986ff6d951SJohn Birrell 
10996ff6d951SJohn Birrell 		if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal,
11006ff6d951SJohn Birrell 		    total, positives, negatives) < 0)
11016ff6d951SJohn Birrell 			return (-1);
11026ff6d951SJohn Birrell 	}
11036ff6d951SJohn Birrell 
11046ff6d951SJohn Birrell 	return (0);
11056ff6d951SJohn Birrell }
11066ff6d951SJohn Birrell 
1107a43f0be9SRui Paulo /*ARGSUSED*/
1108a43f0be9SRui Paulo int
dt_print_lquantize_packed(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,const dtrace_aggdata_t * aggdata)1109a43f0be9SRui Paulo dt_print_lquantize_packed(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
1110a43f0be9SRui Paulo     size_t size, const dtrace_aggdata_t *aggdata)
1111a43f0be9SRui Paulo {
1112a43f0be9SRui Paulo 	const int64_t *data = addr;
1113a43f0be9SRui Paulo 	long double total = 0, count = 0;
1114a43f0be9SRui Paulo 	int min, max, base, err;
1115a43f0be9SRui Paulo 	uint64_t arg;
1116a43f0be9SRui Paulo 	uint16_t step, levels;
1117a43f0be9SRui Paulo 	char c[32];
1118a43f0be9SRui Paulo 	unsigned int i;
1119a43f0be9SRui Paulo 
1120a43f0be9SRui Paulo 	if (size < sizeof (uint64_t))
1121a43f0be9SRui Paulo 		return (dt_set_errno(dtp, EDT_DMISMATCH));
1122a43f0be9SRui Paulo 
1123a43f0be9SRui Paulo 	arg = *data++;
1124a43f0be9SRui Paulo 	size -= sizeof (uint64_t);
1125a43f0be9SRui Paulo 
1126a43f0be9SRui Paulo 	base = DTRACE_LQUANTIZE_BASE(arg);
1127a43f0be9SRui Paulo 	step = DTRACE_LQUANTIZE_STEP(arg);
1128a43f0be9SRui Paulo 	levels = DTRACE_LQUANTIZE_LEVELS(arg);
1129a43f0be9SRui Paulo 
1130a43f0be9SRui Paulo 	if (size != sizeof (uint64_t) * (levels + 2))
1131a43f0be9SRui Paulo 		return (dt_set_errno(dtp, EDT_DMISMATCH));
1132a43f0be9SRui Paulo 
1133a43f0be9SRui Paulo 	min = 0;
1134a43f0be9SRui Paulo 	max = levels + 1;
1135a43f0be9SRui Paulo 
1136a43f0be9SRui Paulo 	if (min == 0) {
1137a43f0be9SRui Paulo 		(void) snprintf(c, sizeof (c), "< %d", base);
1138a43f0be9SRui Paulo 		err = dt_printf(dtp, fp, "%8s :", c);
1139a43f0be9SRui Paulo 	} else {
1140a43f0be9SRui Paulo 		err = dt_printf(dtp, fp, "%8d :", base + (min - 1) * step);
1141a43f0be9SRui Paulo 	}
1142a43f0be9SRui Paulo 
1143a43f0be9SRui Paulo 	if (err < 0)
1144a43f0be9SRui Paulo 		return (-1);
1145a43f0be9SRui Paulo 
1146a43f0be9SRui Paulo 	for (i = min; i <= max; i++) {
1147a43f0be9SRui Paulo 		dt_quantize_total(dtp, data[i], &total);
1148a43f0be9SRui Paulo 		count += data[i];
1149a43f0be9SRui Paulo 	}
1150a43f0be9SRui Paulo 
1151a43f0be9SRui Paulo 	for (i = min; i <= max; i++) {
1152a43f0be9SRui Paulo 		if (dt_print_packed(dtp, fp, data[i], total) < 0)
1153a43f0be9SRui Paulo 			return (-1);
1154a43f0be9SRui Paulo 	}
1155a43f0be9SRui Paulo 
1156a43f0be9SRui Paulo 	(void) snprintf(c, sizeof (c), ">= %d", base + (levels * step));
1157a43f0be9SRui Paulo 	return (dt_printf(dtp, fp, ": %-8s | %lld\n", c, (long long)count));
1158a43f0be9SRui Paulo }
1159a43f0be9SRui Paulo 
116093f27766SDomagoj Stolfa static const int64_t *
dt_format_llquantize_prepare(dtrace_hdl_t * dtp,const void * addr,size_t size,dt_prepare_args_t * args)116193f27766SDomagoj Stolfa dt_format_llquantize_prepare(dtrace_hdl_t *dtp, const void *addr, size_t size,
116293f27766SDomagoj Stolfa     dt_prepare_args_t *args)
1163675cf915SPedro F. Giffuni {
1164675cf915SPedro F. Giffuni 	int i, first_bin, last_bin, bin = 1, order, levels;
1165675cf915SPedro F. Giffuni 	uint16_t factor, low, high, nsteps;
1166675cf915SPedro F. Giffuni 	const int64_t *data = addr;
1167675cf915SPedro F. Giffuni 	int64_t value = 1, next, step;
1168675cf915SPedro F. Giffuni 	uint64_t arg;
1169675cf915SPedro F. Giffuni 
117093f27766SDomagoj Stolfa 	if (size < sizeof(uint64_t)) {
117193f27766SDomagoj Stolfa 		(void) dt_set_errno(dtp, EDT_DMISMATCH);
117293f27766SDomagoj Stolfa 		return (NULL);
117393f27766SDomagoj Stolfa 	}
1174675cf915SPedro F. Giffuni 
1175675cf915SPedro F. Giffuni 	arg = *data++;
1176675cf915SPedro F. Giffuni 	size -= sizeof (uint64_t);
1177675cf915SPedro F. Giffuni 
1178675cf915SPedro F. Giffuni 	factor = DTRACE_LLQUANTIZE_FACTOR(arg);
1179675cf915SPedro F. Giffuni 	low = DTRACE_LLQUANTIZE_LOW(arg);
1180675cf915SPedro F. Giffuni 	high = DTRACE_LLQUANTIZE_HIGH(arg);
1181675cf915SPedro F. Giffuni 	nsteps = DTRACE_LLQUANTIZE_NSTEP(arg);
1182675cf915SPedro F. Giffuni 
1183675cf915SPedro F. Giffuni 	/*
1184675cf915SPedro F. Giffuni 	 * We don't expect to be handed invalid llquantize() parameters here,
1185675cf915SPedro F. Giffuni 	 * but sanity check them (to a degree) nonetheless.
1186675cf915SPedro F. Giffuni 	 */
1187675cf915SPedro F. Giffuni 	if (size > INT32_MAX || factor < 2 || low >= high ||
118893f27766SDomagoj Stolfa 	    nsteps == 0 || factor > nsteps) {
118993f27766SDomagoj Stolfa 		(void) dt_set_errno(dtp, EDT_DMISMATCH);
119093f27766SDomagoj Stolfa 		return (NULL);
119193f27766SDomagoj Stolfa 	}
1192675cf915SPedro F. Giffuni 
1193675cf915SPedro F. Giffuni 	levels = (int)size / sizeof (uint64_t);
1194675cf915SPedro F. Giffuni 
1195675cf915SPedro F. Giffuni 	first_bin = 0;
1196675cf915SPedro F. Giffuni 	last_bin = levels - 1;
1197675cf915SPedro F. Giffuni 
1198675cf915SPedro F. Giffuni 	while (first_bin < levels && data[first_bin] == 0)
1199675cf915SPedro F. Giffuni 		first_bin++;
1200675cf915SPedro F. Giffuni 
1201675cf915SPedro F. Giffuni 	if (first_bin == levels) {
1202675cf915SPedro F. Giffuni 		first_bin = 0;
1203675cf915SPedro F. Giffuni 		last_bin = 1;
1204675cf915SPedro F. Giffuni 	} else {
1205675cf915SPedro F. Giffuni 		if (first_bin > 0)
1206675cf915SPedro F. Giffuni 			first_bin--;
1207675cf915SPedro F. Giffuni 
1208675cf915SPedro F. Giffuni 		while (last_bin > 0 && data[last_bin] == 0)
1209675cf915SPedro F. Giffuni 			last_bin--;
1210675cf915SPedro F. Giffuni 
1211675cf915SPedro F. Giffuni 		if (last_bin < levels - 1)
1212675cf915SPedro F. Giffuni 			last_bin++;
1213675cf915SPedro F. Giffuni 	}
1214675cf915SPedro F. Giffuni 
121593f27766SDomagoj Stolfa 	for (order = 0; order < low; order++)
121693f27766SDomagoj Stolfa 		value *= factor;
121793f27766SDomagoj Stolfa 
121893f27766SDomagoj Stolfa 	next = value * factor;
121993f27766SDomagoj Stolfa 	step = next > nsteps ? next / nsteps : 1;
122093f27766SDomagoj Stolfa 
122193f27766SDomagoj Stolfa 	args->first_bin = first_bin;
122293f27766SDomagoj Stolfa 	args->last_bin = last_bin;
122393f27766SDomagoj Stolfa 	args->llquantize_factor = factor;
122493f27766SDomagoj Stolfa 	args->llquantize_low = low;
122593f27766SDomagoj Stolfa 	args->llquantize_high = high;
122693f27766SDomagoj Stolfa 	args->llquantize_nsteps = nsteps;
122793f27766SDomagoj Stolfa 	args->llquantize_levels = levels;
122893f27766SDomagoj Stolfa 	args->llquantize_order = order;
122993f27766SDomagoj Stolfa 	args->llquantize_next = next;
123093f27766SDomagoj Stolfa 	args->llquantize_step = step;
123193f27766SDomagoj Stolfa 	args->llquantize_value = value;
123293f27766SDomagoj Stolfa 
123393f27766SDomagoj Stolfa 	return (data);
123493f27766SDomagoj Stolfa }
123593f27766SDomagoj Stolfa 
123693f27766SDomagoj Stolfa int
dt_format_llquantize(dtrace_hdl_t * dtp,const void * addr,size_t size,uint64_t normal)123793f27766SDomagoj Stolfa dt_format_llquantize(dtrace_hdl_t *dtp, const void *addr, size_t size,
123893f27766SDomagoj Stolfa     uint64_t normal)
123993f27766SDomagoj Stolfa {
124093f27766SDomagoj Stolfa 	int first_bin, last_bin, bin = 1, order, levels;
124193f27766SDomagoj Stolfa 	uint16_t factor, low, high, nsteps;
124293f27766SDomagoj Stolfa 	const int64_t *data;
124393f27766SDomagoj Stolfa 	dt_prepare_args_t args = { 0 };
124493f27766SDomagoj Stolfa 	int64_t value = 1, next, step;
124593f27766SDomagoj Stolfa 	uint64_t arg;
124693f27766SDomagoj Stolfa 	char c[32];
124793f27766SDomagoj Stolfa 
124893f27766SDomagoj Stolfa 	data = dt_format_llquantize_prepare(dtp, addr, size, &args);
124993f27766SDomagoj Stolfa 	/* dt_errno is set for us */
125093f27766SDomagoj Stolfa 	if (data == NULL)
125193f27766SDomagoj Stolfa 		return (-1);
125293f27766SDomagoj Stolfa 
125393f27766SDomagoj Stolfa 	first_bin = args.first_bin;
125493f27766SDomagoj Stolfa 	last_bin = args.last_bin;
125593f27766SDomagoj Stolfa 	factor = args.llquantize_factor;
125693f27766SDomagoj Stolfa 	low = args.llquantize_low;
125793f27766SDomagoj Stolfa 	high = args.llquantize_high;
125893f27766SDomagoj Stolfa 	nsteps = args.llquantize_nsteps;
125993f27766SDomagoj Stolfa 	levels = args.llquantize_levels;
126093f27766SDomagoj Stolfa 	order = args.llquantize_order;
126193f27766SDomagoj Stolfa 	next = args.llquantize_next;
126293f27766SDomagoj Stolfa 	step = args.llquantize_step;
126393f27766SDomagoj Stolfa 	value = args.llquantize_value;
126493f27766SDomagoj Stolfa 
126593f27766SDomagoj Stolfa 	xo_open_list("buckets");
126693f27766SDomagoj Stolfa 	if (first_bin == 0) {
126793f27766SDomagoj Stolfa 		/*
126893f27766SDomagoj Stolfa 		 * We have to represent < value somehow in JSON, so we bundle an
126993f27766SDomagoj Stolfa 		 * optional "operator" in llquantize buckets.
127093f27766SDomagoj Stolfa 		 */
127193f27766SDomagoj Stolfa 		xo_open_instance("buckets");
127293f27766SDomagoj Stolfa 		xo_emit("{:value/%lld} {:count/%lld} {:operator/%s}",
127393f27766SDomagoj Stolfa 		    (long long)value, (long long)data[0] / normal, "<");
127493f27766SDomagoj Stolfa 		xo_close_instance("buckets");
127593f27766SDomagoj Stolfa 	}
127693f27766SDomagoj Stolfa 
127793f27766SDomagoj Stolfa 	while (order <= high) {
127893f27766SDomagoj Stolfa 		if (bin >= first_bin && bin <= last_bin) {
127993f27766SDomagoj Stolfa 			xo_open_instance("buckets");
128093f27766SDomagoj Stolfa 			xo_emit("{:value/%lld} {:count/%lld}", (long long)value,
128193f27766SDomagoj Stolfa 			    (long long)data[bin] / normal);
128293f27766SDomagoj Stolfa 			xo_close_instance("buckets");
128393f27766SDomagoj Stolfa 		}
128493f27766SDomagoj Stolfa 
128593f27766SDomagoj Stolfa 		assert(value < next);
128693f27766SDomagoj Stolfa 		bin++;
128793f27766SDomagoj Stolfa 
128893f27766SDomagoj Stolfa 		if ((value += step) != next)
128993f27766SDomagoj Stolfa 			continue;
129093f27766SDomagoj Stolfa 
129193f27766SDomagoj Stolfa 		next = value * factor;
129293f27766SDomagoj Stolfa 		step = next > nsteps ? next / nsteps : 1;
129393f27766SDomagoj Stolfa 		order++;
129493f27766SDomagoj Stolfa 	}
129593f27766SDomagoj Stolfa 
129693f27766SDomagoj Stolfa 	if (last_bin < bin) {
129793f27766SDomagoj Stolfa 		xo_close_list("buckets");
129893f27766SDomagoj Stolfa 		return (0);
129993f27766SDomagoj Stolfa 	}
130093f27766SDomagoj Stolfa 
130193f27766SDomagoj Stolfa 	assert(last_bin == bin);
130293f27766SDomagoj Stolfa 	xo_open_instance("buckets");
130393f27766SDomagoj Stolfa 	xo_emit("{:value/%lld} {:count/%lld} {:operator/%s}", (long long)value,
130493f27766SDomagoj Stolfa 	    (long long)data[bin] / normal, ">=");
130593f27766SDomagoj Stolfa 	xo_close_instance("buckets");
130693f27766SDomagoj Stolfa 
130793f27766SDomagoj Stolfa 	xo_close_list("buckets");
130893f27766SDomagoj Stolfa 	return (0);
130993f27766SDomagoj Stolfa }
131093f27766SDomagoj Stolfa 
131193f27766SDomagoj Stolfa int
dt_print_llquantize(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,uint64_t normal)131293f27766SDomagoj Stolfa dt_print_llquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
131393f27766SDomagoj Stolfa     size_t size, uint64_t normal)
131493f27766SDomagoj Stolfa {
131593f27766SDomagoj Stolfa 	int i, first_bin, last_bin, bin = 1, order, levels;
131693f27766SDomagoj Stolfa 	uint16_t factor, low, high, nsteps;
131793f27766SDomagoj Stolfa 	const int64_t *data;
131893f27766SDomagoj Stolfa 	dt_prepare_args_t args = { 0 };
131993f27766SDomagoj Stolfa 	int64_t value = 1, next, step;
132093f27766SDomagoj Stolfa 	char positives = 0, negatives = 0;
132193f27766SDomagoj Stolfa 	long double total = 0;
132293f27766SDomagoj Stolfa 	uint64_t arg;
132393f27766SDomagoj Stolfa 	char c[32];
132493f27766SDomagoj Stolfa 
132593f27766SDomagoj Stolfa 	data = dt_format_llquantize_prepare(dtp, addr, size, &args);
132693f27766SDomagoj Stolfa 	/* dt_errno is set for us */
132793f27766SDomagoj Stolfa 	if (data == NULL)
132893f27766SDomagoj Stolfa 		return (-1);
132993f27766SDomagoj Stolfa 
133093f27766SDomagoj Stolfa 	first_bin = args.first_bin;
133193f27766SDomagoj Stolfa 	last_bin = args.last_bin;
133293f27766SDomagoj Stolfa 	factor = args.llquantize_factor;
133393f27766SDomagoj Stolfa 	low = args.llquantize_low;
133493f27766SDomagoj Stolfa 	high = args.llquantize_high;
133593f27766SDomagoj Stolfa 	nsteps = args.llquantize_nsteps;
133693f27766SDomagoj Stolfa 	levels = args.llquantize_levels;
133793f27766SDomagoj Stolfa 	order = args.llquantize_order;
133893f27766SDomagoj Stolfa 	next = args.llquantize_next;
133993f27766SDomagoj Stolfa 	step = args.llquantize_step;
134093f27766SDomagoj Stolfa 	value = args.llquantize_value;
134193f27766SDomagoj Stolfa 
1342675cf915SPedro F. Giffuni 	for (i = first_bin; i <= last_bin; i++) {
1343675cf915SPedro F. Giffuni 		positives |= (data[i] > 0);
1344675cf915SPedro F. Giffuni 		negatives |= (data[i] < 0);
1345a43f0be9SRui Paulo 		dt_quantize_total(dtp, data[i], &total);
1346675cf915SPedro F. Giffuni 	}
1347675cf915SPedro F. Giffuni 
1348675cf915SPedro F. Giffuni 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
1349675cf915SPedro F. Giffuni 	    "------------- Distribution -------------", "count") < 0)
1350675cf915SPedro F. Giffuni 		return (-1);
1351675cf915SPedro F. Giffuni 
1352675cf915SPedro F. Giffuni 	if (first_bin == 0) {
1353fed980b2SPedro F. Giffuni 		(void) snprintf(c, sizeof (c), "< %lld", (long long)value);
1354675cf915SPedro F. Giffuni 
1355675cf915SPedro F. Giffuni 		if (dt_printf(dtp, fp, "%16s ", c) < 0)
1356675cf915SPedro F. Giffuni 			return (-1);
1357675cf915SPedro F. Giffuni 
1358675cf915SPedro F. Giffuni 		if (dt_print_quantline(dtp, fp, data[0], normal,
1359675cf915SPedro F. Giffuni 		    total, positives, negatives) < 0)
1360675cf915SPedro F. Giffuni 			return (-1);
1361675cf915SPedro F. Giffuni 	}
1362675cf915SPedro F. Giffuni 
1363675cf915SPedro F. Giffuni 	while (order <= high) {
1364675cf915SPedro F. Giffuni 		if (bin >= first_bin && bin <= last_bin) {
1365675cf915SPedro F. Giffuni 			if (dt_printf(dtp, fp, "%16lld ", (long long)value) < 0)
1366675cf915SPedro F. Giffuni 				return (-1);
1367675cf915SPedro F. Giffuni 
1368675cf915SPedro F. Giffuni 			if (dt_print_quantline(dtp, fp, data[bin],
1369675cf915SPedro F. Giffuni 			    normal, total, positives, negatives) < 0)
1370675cf915SPedro F. Giffuni 				return (-1);
1371675cf915SPedro F. Giffuni 		}
1372675cf915SPedro F. Giffuni 
1373675cf915SPedro F. Giffuni 		assert(value < next);
1374675cf915SPedro F. Giffuni 		bin++;
1375675cf915SPedro F. Giffuni 
1376675cf915SPedro F. Giffuni 		if ((value += step) != next)
1377675cf915SPedro F. Giffuni 			continue;
1378675cf915SPedro F. Giffuni 
1379675cf915SPedro F. Giffuni 		next = value * factor;
1380675cf915SPedro F. Giffuni 		step = next > nsteps ? next / nsteps : 1;
1381675cf915SPedro F. Giffuni 		order++;
1382675cf915SPedro F. Giffuni 	}
1383675cf915SPedro F. Giffuni 
1384675cf915SPedro F. Giffuni 	if (last_bin < bin)
1385675cf915SPedro F. Giffuni 		return (0);
1386675cf915SPedro F. Giffuni 
1387675cf915SPedro F. Giffuni 	assert(last_bin == bin);
1388ae88a6d9SDimitry Andric 	(void) snprintf(c, sizeof (c), ">= %lld", (long long)value);
1389675cf915SPedro F. Giffuni 
1390675cf915SPedro F. Giffuni 	if (dt_printf(dtp, fp, "%16s ", c) < 0)
1391675cf915SPedro F. Giffuni 		return (-1);
1392675cf915SPedro F. Giffuni 
1393675cf915SPedro F. Giffuni 	return (dt_print_quantline(dtp, fp, data[bin], normal,
1394675cf915SPedro F. Giffuni 	    total, positives, negatives));
1395675cf915SPedro F. Giffuni }
1396675cf915SPedro F. Giffuni 
139793f27766SDomagoj Stolfa static int
dt_format_average(dtrace_hdl_t * dtp,caddr_t addr,size_t size,uint64_t normal)139893f27766SDomagoj Stolfa dt_format_average(dtrace_hdl_t *dtp, caddr_t addr, size_t size, uint64_t normal)
139993f27766SDomagoj Stolfa {
140093f27766SDomagoj Stolfa 	int64_t *data = (int64_t *)addr;
140193f27766SDomagoj Stolfa 
140293f27766SDomagoj Stolfa 	xo_emit("{:average/%lld}",
140393f27766SDomagoj Stolfa 	    data[0] ? (long long)(data[1] / (int64_t)normal / data[0]) : 0);
140493f27766SDomagoj Stolfa 	return (0);
140593f27766SDomagoj Stolfa }
140693f27766SDomagoj Stolfa 
14076ff6d951SJohn Birrell /*ARGSUSED*/
14086ff6d951SJohn Birrell static int
dt_print_average(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,size_t size,uint64_t normal)14096ff6d951SJohn Birrell dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
14106ff6d951SJohn Birrell     size_t size, uint64_t normal)
14116ff6d951SJohn Birrell {
14126ff6d951SJohn Birrell 	/* LINTED - alignment */
14136ff6d951SJohn Birrell 	int64_t *data = (int64_t *)addr;
14146ff6d951SJohn Birrell 
14156ff6d951SJohn Birrell 	return (dt_printf(dtp, fp, " %16lld", data[0] ?
14166ff6d951SJohn Birrell 	    (long long)(data[1] / (int64_t)normal / data[0]) : 0));
14176ff6d951SJohn Birrell }
14186ff6d951SJohn Birrell 
141993f27766SDomagoj Stolfa static int
dt_format_stddev(dtrace_hdl_t * dtp,caddr_t addr,size_t size,uint64_t normal)142093f27766SDomagoj Stolfa dt_format_stddev(dtrace_hdl_t *dtp, caddr_t addr, size_t size, uint64_t normal)
142193f27766SDomagoj Stolfa {
142293f27766SDomagoj Stolfa 	uint64_t *data = (uint64_t *)addr;
142393f27766SDomagoj Stolfa 
142493f27766SDomagoj Stolfa 	xo_emit("{:stddev/%llu}",
142593f27766SDomagoj Stolfa 	    data[0] ? (unsigned long long)dt_stddev(data, normal) : 0);
142693f27766SDomagoj Stolfa 	return (0);
142793f27766SDomagoj Stolfa }
142893f27766SDomagoj Stolfa 
14296ff6d951SJohn Birrell /*ARGSUSED*/
14306ff6d951SJohn Birrell static int
dt_print_stddev(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,size_t size,uint64_t normal)14316ff6d951SJohn Birrell dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
14326ff6d951SJohn Birrell     size_t size, uint64_t normal)
14336ff6d951SJohn Birrell {
14346ff6d951SJohn Birrell 	/* LINTED - alignment */
14356ff6d951SJohn Birrell 	uint64_t *data = (uint64_t *)addr;
14366ff6d951SJohn Birrell 
14376ff6d951SJohn Birrell 	return (dt_printf(dtp, fp, " %16llu", data[0] ?
14386ff6d951SJohn Birrell 	    (unsigned long long) dt_stddev(data, normal) : 0));
14396ff6d951SJohn Birrell }
14406ff6d951SJohn Birrell 
14416ff6d951SJohn Birrell /*ARGSUSED*/
1442a43f0be9SRui Paulo static int
dt_print_bytes(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,size_t nbytes,int width,int quiet,int forceraw)14436ff6d951SJohn Birrell dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
1444f2e66d30SPedro F. Giffuni     size_t nbytes, int width, int quiet, int forceraw)
14456ff6d951SJohn Birrell {
14466ff6d951SJohn Birrell 	/*
14476ff6d951SJohn Birrell 	 * If the byte stream is a series of printable characters, followed by
14486ff6d951SJohn Birrell 	 * a terminating byte, we print it out as a string.  Otherwise, we
14496ff6d951SJohn Birrell 	 * assume that it's something else and just print the bytes.
14506ff6d951SJohn Birrell 	 */
14516ff6d951SJohn Birrell 	int i, j, margin = 5;
14526ff6d951SJohn Birrell 	char *c = (char *)addr;
14536ff6d951SJohn Birrell 
14546ff6d951SJohn Birrell 	if (nbytes == 0)
14556ff6d951SJohn Birrell 		return (0);
14566ff6d951SJohn Birrell 
1457f2e66d30SPedro F. Giffuni 	if (forceraw)
1458f2e66d30SPedro F. Giffuni 		goto raw;
1459f2e66d30SPedro F. Giffuni 
1460f2e66d30SPedro F. Giffuni 	if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
14616ff6d951SJohn Birrell 		goto raw;
14626ff6d951SJohn Birrell 
14636ff6d951SJohn Birrell 	for (i = 0; i < nbytes; i++) {
14646ff6d951SJohn Birrell 		/*
14656ff6d951SJohn Birrell 		 * We define a "printable character" to be one for which
14666ff6d951SJohn Birrell 		 * isprint(3C) returns non-zero, isspace(3C) returns non-zero,
14676ff6d951SJohn Birrell 		 * or a character which is either backspace or the bell.
14686ff6d951SJohn Birrell 		 * Backspace and the bell are regrettably special because
14696ff6d951SJohn Birrell 		 * they fail the first two tests -- and yet they are entirely
14706ff6d951SJohn Birrell 		 * printable.  These are the only two control characters that
14716ff6d951SJohn Birrell 		 * have meaning for the terminal and for which isprint(3C) and
14726ff6d951SJohn Birrell 		 * isspace(3C) return 0.
14736ff6d951SJohn Birrell 		 */
14746ff6d951SJohn Birrell 		if (isprint(c[i]) || isspace(c[i]) ||
14756ff6d951SJohn Birrell 		    c[i] == '\b' || c[i] == '\a')
14766ff6d951SJohn Birrell 			continue;
14776ff6d951SJohn Birrell 
14786ff6d951SJohn Birrell 		if (c[i] == '\0' && i > 0) {
14796ff6d951SJohn Birrell 			/*
14806ff6d951SJohn Birrell 			 * This looks like it might be a string.  Before we
14816ff6d951SJohn Birrell 			 * assume that it is indeed a string, check the
14826ff6d951SJohn Birrell 			 * remainder of the byte range; if it contains
14836ff6d951SJohn Birrell 			 * additional non-nul characters, we'll assume that
14846ff6d951SJohn Birrell 			 * it's a binary stream that just happens to look like
14856ff6d951SJohn Birrell 			 * a string, and we'll print out the individual bytes.
14866ff6d951SJohn Birrell 			 */
14876ff6d951SJohn Birrell 			for (j = i + 1; j < nbytes; j++) {
14886ff6d951SJohn Birrell 				if (c[j] != '\0')
14896ff6d951SJohn Birrell 					break;
14906ff6d951SJohn Birrell 			}
14916ff6d951SJohn Birrell 
14926ff6d951SJohn Birrell 			if (j != nbytes)
14936ff6d951SJohn Birrell 				break;
14946ff6d951SJohn Birrell 
1495a43f0be9SRui Paulo 			if (quiet) {
14966ff6d951SJohn Birrell 				return (dt_printf(dtp, fp, "%s", c));
1497a43f0be9SRui Paulo 			} else {
1498a43f0be9SRui Paulo 				return (dt_printf(dtp, fp, " %s%*s",
1499a43f0be9SRui Paulo 				    width < 0 ? " " : "", width, c));
1500a43f0be9SRui Paulo 			}
15016ff6d951SJohn Birrell 		}
15026ff6d951SJohn Birrell 
15036ff6d951SJohn Birrell 		break;
15046ff6d951SJohn Birrell 	}
15056ff6d951SJohn Birrell 
15066ff6d951SJohn Birrell 	if (i == nbytes) {
15076ff6d951SJohn Birrell 		/*
15086ff6d951SJohn Birrell 		 * The byte range is all printable characters, but there is
15096ff6d951SJohn Birrell 		 * no trailing nul byte.  We'll assume that it's a string and
15106ff6d951SJohn Birrell 		 * print it as such.
15116ff6d951SJohn Birrell 		 */
15126ff6d951SJohn Birrell 		char *s = alloca(nbytes + 1);
15136ff6d951SJohn Birrell 		bcopy(c, s, nbytes);
15146ff6d951SJohn Birrell 		s[nbytes] = '\0';
15156ff6d951SJohn Birrell 		return (dt_printf(dtp, fp, "  %-*s", width, s));
15166ff6d951SJohn Birrell 	}
15176ff6d951SJohn Birrell 
15186ff6d951SJohn Birrell raw:
15196ff6d951SJohn Birrell 	if (dt_printf(dtp, fp, "\n%*s      ", margin, "") < 0)
15206ff6d951SJohn Birrell 		return (-1);
15216ff6d951SJohn Birrell 
15226ff6d951SJohn Birrell 	for (i = 0; i < 16; i++)
15236ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "  %c", "0123456789abcdef"[i]) < 0)
15246ff6d951SJohn Birrell 			return (-1);
15256ff6d951SJohn Birrell 
15266ff6d951SJohn Birrell 	if (dt_printf(dtp, fp, "  0123456789abcdef\n") < 0)
15276ff6d951SJohn Birrell 		return (-1);
15286ff6d951SJohn Birrell 
15296ff6d951SJohn Birrell 
15306ff6d951SJohn Birrell 	for (i = 0; i < nbytes; i += 16) {
15316ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0)
15326ff6d951SJohn Birrell 			return (-1);
15336ff6d951SJohn Birrell 
15346ff6d951SJohn Birrell 		for (j = i; j < i + 16 && j < nbytes; j++) {
15356ff6d951SJohn Birrell 			if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0)
15366ff6d951SJohn Birrell 				return (-1);
15376ff6d951SJohn Birrell 		}
15386ff6d951SJohn Birrell 
15396ff6d951SJohn Birrell 		while (j++ % 16) {
15406ff6d951SJohn Birrell 			if (dt_printf(dtp, fp, "   ") < 0)
15416ff6d951SJohn Birrell 				return (-1);
15426ff6d951SJohn Birrell 		}
15436ff6d951SJohn Birrell 
15446ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "  ") < 0)
15456ff6d951SJohn Birrell 			return (-1);
15466ff6d951SJohn Birrell 
15476ff6d951SJohn Birrell 		for (j = i; j < i + 16 && j < nbytes; j++) {
15486ff6d951SJohn Birrell 			if (dt_printf(dtp, fp, "%c",
15496ff6d951SJohn Birrell 			    c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0)
15506ff6d951SJohn Birrell 				return (-1);
15516ff6d951SJohn Birrell 		}
15526ff6d951SJohn Birrell 
15536ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "\n") < 0)
15546ff6d951SJohn Birrell 			return (-1);
15556ff6d951SJohn Birrell 	}
15566ff6d951SJohn Birrell 
15576ff6d951SJohn Birrell 	return (0);
15586ff6d951SJohn Birrell }
15596ff6d951SJohn Birrell 
15606ff6d951SJohn Birrell int
dt_format_stack(dtrace_hdl_t * dtp,caddr_t addr,int depth,int size)156193f27766SDomagoj Stolfa dt_format_stack(dtrace_hdl_t *dtp, caddr_t addr, int depth, int size)
156293f27766SDomagoj Stolfa {
156393f27766SDomagoj Stolfa 	dtrace_syminfo_t dts;
156493f27766SDomagoj Stolfa 	GElf_Sym sym;
156593f27766SDomagoj Stolfa 	int i;
156693f27766SDomagoj Stolfa 	uint64_t pc;
156793f27766SDomagoj Stolfa 
156893f27766SDomagoj Stolfa 	xo_open_list("stack-frames");
156993f27766SDomagoj Stolfa 	for (i = 0; i < depth; i++) {
157093f27766SDomagoj Stolfa 		switch (size) {
157193f27766SDomagoj Stolfa 		case sizeof (uint32_t):
157293f27766SDomagoj Stolfa 			pc = *((uint32_t *)addr);
157393f27766SDomagoj Stolfa 			break;
157493f27766SDomagoj Stolfa 
157593f27766SDomagoj Stolfa 		case sizeof (uint64_t):
157693f27766SDomagoj Stolfa 			pc = *((uint64_t *)addr);
157793f27766SDomagoj Stolfa 			break;
157893f27766SDomagoj Stolfa 
157993f27766SDomagoj Stolfa 		default:
158093f27766SDomagoj Stolfa 			return (dt_set_errno(dtp, EDT_BADSTACKPC));
158193f27766SDomagoj Stolfa 		}
158293f27766SDomagoj Stolfa 
158393f27766SDomagoj Stolfa 		if (pc == 0)
158493f27766SDomagoj Stolfa 			break;
158593f27766SDomagoj Stolfa 
158693f27766SDomagoj Stolfa 		addr += size;
158793f27766SDomagoj Stolfa 
158893f27766SDomagoj Stolfa 		xo_open_instance("stack-frames");
158993f27766SDomagoj Stolfa 		if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
159093f27766SDomagoj Stolfa 			if (pc > sym.st_value) {
159193f27766SDomagoj Stolfa 				xo_emit("{:symbol/%s`%s+0x%llx} {:module/%s} "
159293f27766SDomagoj Stolfa 					"{:name/%s} {:offset/0x%llx}",
159393f27766SDomagoj Stolfa 				    dts.dts_object, dts.dts_name,
159493f27766SDomagoj Stolfa 				    (u_longlong_t)(pc - sym.st_value),
159593f27766SDomagoj Stolfa 				    dts.dts_object, dts.dts_name,
159693f27766SDomagoj Stolfa 				    (u_longlong_t)(pc - sym.st_value));
159793f27766SDomagoj Stolfa 			} else {
159893f27766SDomagoj Stolfa 				xo_emit("{:symbol/%s`%s} {:module/%s} "
159993f27766SDomagoj Stolfa 					"{:name/%s}",
160093f27766SDomagoj Stolfa 				    dts.dts_object, dts.dts_name,
160193f27766SDomagoj Stolfa 				    dts.dts_object, dts.dts_name);
160293f27766SDomagoj Stolfa 			}
160393f27766SDomagoj Stolfa 		} else {
160493f27766SDomagoj Stolfa 			/*
160593f27766SDomagoj Stolfa 			 * We'll repeat the lookup, but this time we'll specify
160693f27766SDomagoj Stolfa 			 * a NULL GElf_Sym -- indicating that we're only
160793f27766SDomagoj Stolfa 			 * interested in the containing module.
160893f27766SDomagoj Stolfa 			 */
160993f27766SDomagoj Stolfa 			if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
161093f27766SDomagoj Stolfa 				xo_emit("{:symbol/%s`0x%llx} {:module/%s} "
161193f27766SDomagoj Stolfa 					"{:offset/0x%llx}",
161293f27766SDomagoj Stolfa 				    dts.dts_object, (u_longlong_t)pc,
161393f27766SDomagoj Stolfa 				    dts.dts_object, (u_longlong_t)pc);
161493f27766SDomagoj Stolfa 			} else {
161593f27766SDomagoj Stolfa 				xo_emit("{:symbol/0x%llx} {:offset/0x%llx}",
161693f27766SDomagoj Stolfa 				    (u_longlong_t)pc, (u_longlong_t)pc);
161793f27766SDomagoj Stolfa 			}
161893f27766SDomagoj Stolfa 		}
161993f27766SDomagoj Stolfa 		xo_close_instance("stack-frames");
162093f27766SDomagoj Stolfa 	}
162193f27766SDomagoj Stolfa 	xo_close_list("stack-frames");
162293f27766SDomagoj Stolfa 
162393f27766SDomagoj Stolfa 	return (0);
162493f27766SDomagoj Stolfa }
162593f27766SDomagoj Stolfa 
162693f27766SDomagoj Stolfa int
dt_format_ustack(dtrace_hdl_t * dtp,caddr_t addr,uint64_t arg)162793f27766SDomagoj Stolfa dt_format_ustack(dtrace_hdl_t *dtp, caddr_t addr, uint64_t arg)
162893f27766SDomagoj Stolfa {
162993f27766SDomagoj Stolfa 	uint64_t *pc = (uint64_t *)addr;
163093f27766SDomagoj Stolfa 	uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
163193f27766SDomagoj Stolfa 	uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
163293f27766SDomagoj Stolfa 	const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
163393f27766SDomagoj Stolfa 	const char *str = strsize ? strbase : NULL;
163493f27766SDomagoj Stolfa 	int err = 0;
163593f27766SDomagoj Stolfa 
163693f27766SDomagoj Stolfa 	char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
163793f27766SDomagoj Stolfa 	struct ps_prochandle *P;
163893f27766SDomagoj Stolfa 	GElf_Sym sym;
163993f27766SDomagoj Stolfa 	int i, indent;
164093f27766SDomagoj Stolfa 	pid_t pid;
164193f27766SDomagoj Stolfa 
164293f27766SDomagoj Stolfa 	if (depth == 0)
164393f27766SDomagoj Stolfa 		return (0);
164493f27766SDomagoj Stolfa 
164593f27766SDomagoj Stolfa 	pid = (pid_t)*pc++;
164693f27766SDomagoj Stolfa 
164793f27766SDomagoj Stolfa 	/*
164893f27766SDomagoj Stolfa 	 * Ultimately, we need to add an entry point in the library vector for
164993f27766SDomagoj Stolfa 	 * determining <symbol, offset> from <pid, address>.  For now, if
165093f27766SDomagoj Stolfa 	 * this is a vector open, we just print the raw address or string.
165193f27766SDomagoj Stolfa 	 */
165293f27766SDomagoj Stolfa 	if (dtp->dt_vector == NULL)
165393f27766SDomagoj Stolfa 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
165493f27766SDomagoj Stolfa 	else
165593f27766SDomagoj Stolfa 		P = NULL;
165693f27766SDomagoj Stolfa 
165793f27766SDomagoj Stolfa 	if (P != NULL)
165893f27766SDomagoj Stolfa 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
165993f27766SDomagoj Stolfa 
166093f27766SDomagoj Stolfa 	xo_open_list("ustack-frames");
166193f27766SDomagoj Stolfa 	for (i = 0; i < depth && pc[i] != 0; i++) {
166293f27766SDomagoj Stolfa 		const prmap_t *map;
166393f27766SDomagoj Stolfa 
166493f27766SDomagoj Stolfa 		xo_open_instance("ustack-frames");
166593f27766SDomagoj Stolfa 		if (P != NULL && Plookup_by_addr(P, pc[i],
166693f27766SDomagoj Stolfa 		    name, sizeof (name), &sym) == 0) {
166793f27766SDomagoj Stolfa 			(void) Pobjname(P, pc[i], objname, sizeof (objname));
166893f27766SDomagoj Stolfa 
166993f27766SDomagoj Stolfa 			if (pc[i] > sym.st_value) {
167093f27766SDomagoj Stolfa 				xo_emit("{:symbol/%s`%s+0x%llx} {:module/%s} "
167193f27766SDomagoj Stolfa 					"{:name/%s} {:offset/0x%llx}",
167293f27766SDomagoj Stolfa 				    dt_basename(objname), name,
167393f27766SDomagoj Stolfa 				    (u_longlong_t)(pc[i] - sym.st_value),
167493f27766SDomagoj Stolfa 				    dt_basename(objname), name,
167593f27766SDomagoj Stolfa 				    (u_longlong_t)(pc[i] - sym.st_value));
167693f27766SDomagoj Stolfa 			} else {
167793f27766SDomagoj Stolfa 				xo_emit("{:symbol/%s`%s} {:module/%s} "
167893f27766SDomagoj Stolfa 					"{:name/%s}",
167993f27766SDomagoj Stolfa 				    dt_basename(objname), name,
168093f27766SDomagoj Stolfa 				    dt_basename(objname), name);
168193f27766SDomagoj Stolfa 			}
168293f27766SDomagoj Stolfa 		} else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
168393f27766SDomagoj Stolfa 		    (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
168493f27766SDomagoj Stolfa 		    (map->pr_mflags & MA_WRITE)))) {
168593f27766SDomagoj Stolfa 			/*
168693f27766SDomagoj Stolfa 			 * If the current string pointer in the string table
168793f27766SDomagoj Stolfa 			 * does not point to an empty string _and_ the program
168893f27766SDomagoj Stolfa 			 * counter falls in a writable region, we'll use the
168993f27766SDomagoj Stolfa 			 * string from the string table instead of the raw
169093f27766SDomagoj Stolfa 			 * address.  This last condition is necessary because
169193f27766SDomagoj Stolfa 			 * some (broken) ustack helpers will return a string
169293f27766SDomagoj Stolfa 			 * even for a program counter that they can't
169393f27766SDomagoj Stolfa 			 * identify.  If we have a string for a program
169493f27766SDomagoj Stolfa 			 * counter that falls in a segment that isn't
169593f27766SDomagoj Stolfa 			 * writable, we assume that we have fallen into this
169693f27766SDomagoj Stolfa 			 * case and we refuse to use the string.
169793f27766SDomagoj Stolfa 			 */
169893f27766SDomagoj Stolfa 			xo_emit("{:symbol/%s}", str);
169993f27766SDomagoj Stolfa 		} else {
170093f27766SDomagoj Stolfa 			if (P != NULL && Pobjname(P, pc[i], objname,
170193f27766SDomagoj Stolfa 			    sizeof (objname)) != 0) {
170293f27766SDomagoj Stolfa 				xo_emit("{:symbol/%s`0x%llx} {:module/%s} "
170393f27766SDomagoj Stolfa 					"{:offset/0x%llx}",
170493f27766SDomagoj Stolfa 				    dt_basename(objname), (u_longlong_t)pc[i],
170593f27766SDomagoj Stolfa 				    dt_basename(objname), (u_longlong_t)pc[i]);
170693f27766SDomagoj Stolfa 			} else {
170793f27766SDomagoj Stolfa 				xo_emit("{:symbol/0x%llx} {:offset/0x%llx}",
170893f27766SDomagoj Stolfa 				    (u_longlong_t)pc[i], (u_longlong_t)pc[i]);
170993f27766SDomagoj Stolfa 			}
171093f27766SDomagoj Stolfa 		}
171193f27766SDomagoj Stolfa 
171293f27766SDomagoj Stolfa 		if (str != NULL && str[0] == '@') {
171393f27766SDomagoj Stolfa 			/*
171493f27766SDomagoj Stolfa 			 * If the first character of the string is an "at" sign,
171593f27766SDomagoj Stolfa 			 * then the string is inferred to be an annotation --
171693f27766SDomagoj Stolfa 			 * and it is printed out beneath the frame and offset
171793f27766SDomagoj Stolfa 			 * with brackets.
171893f27766SDomagoj Stolfa 			 */
171993f27766SDomagoj Stolfa 			xo_emit("{:annotation/%s}", &str[1]);
172093f27766SDomagoj Stolfa 		}
172193f27766SDomagoj Stolfa 
172293f27766SDomagoj Stolfa 		if (str != NULL) {
172393f27766SDomagoj Stolfa 			str += strlen(str) + 1;
172493f27766SDomagoj Stolfa 			if (str - strbase >= strsize)
172593f27766SDomagoj Stolfa 				str = NULL;
172693f27766SDomagoj Stolfa 		}
172793f27766SDomagoj Stolfa 		xo_close_instance("ustack-frames");
172893f27766SDomagoj Stolfa 	}
172993f27766SDomagoj Stolfa 	xo_close_list("ustack-frames");
173093f27766SDomagoj Stolfa 
173193f27766SDomagoj Stolfa 	if (P != NULL) {
173293f27766SDomagoj Stolfa 		dt_proc_unlock(dtp, P);
173393f27766SDomagoj Stolfa 		dt_proc_release(dtp, P);
173493f27766SDomagoj Stolfa 	}
173593f27766SDomagoj Stolfa 
173693f27766SDomagoj Stolfa 	return (err);
173793f27766SDomagoj Stolfa }
173893f27766SDomagoj Stolfa 
173993f27766SDomagoj Stolfa int
dt_print_stack(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr,int depth,int size)17406ff6d951SJohn Birrell dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
17416ff6d951SJohn Birrell     caddr_t addr, int depth, int size)
17426ff6d951SJohn Birrell {
17436ff6d951SJohn Birrell 	dtrace_syminfo_t dts;
17446ff6d951SJohn Birrell 	GElf_Sym sym;
17456ff6d951SJohn Birrell 	int i, indent;
17466ff6d951SJohn Birrell 	char c[PATH_MAX * 2];
17476ff6d951SJohn Birrell 	uint64_t pc;
17486ff6d951SJohn Birrell 
17496ff6d951SJohn Birrell 	if (dt_printf(dtp, fp, "\n") < 0)
17506ff6d951SJohn Birrell 		return (-1);
17516ff6d951SJohn Birrell 
17526ff6d951SJohn Birrell 	if (format == NULL)
17536ff6d951SJohn Birrell 		format = "%s";
17546ff6d951SJohn Birrell 
17556ff6d951SJohn Birrell 	if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
17566ff6d951SJohn Birrell 		indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
17576ff6d951SJohn Birrell 	else
17586ff6d951SJohn Birrell 		indent = _dtrace_stkindent;
17596ff6d951SJohn Birrell 
17606ff6d951SJohn Birrell 	for (i = 0; i < depth; i++) {
17616ff6d951SJohn Birrell 		switch (size) {
17626ff6d951SJohn Birrell 		case sizeof (uint32_t):
17636ff6d951SJohn Birrell 			/* LINTED - alignment */
17646ff6d951SJohn Birrell 			pc = *((uint32_t *)addr);
17656ff6d951SJohn Birrell 			break;
17666ff6d951SJohn Birrell 
17676ff6d951SJohn Birrell 		case sizeof (uint64_t):
17686ff6d951SJohn Birrell 			/* LINTED - alignment */
17696ff6d951SJohn Birrell 			pc = *((uint64_t *)addr);
17706ff6d951SJohn Birrell 			break;
17716ff6d951SJohn Birrell 
17726ff6d951SJohn Birrell 		default:
17736ff6d951SJohn Birrell 			return (dt_set_errno(dtp, EDT_BADSTACKPC));
17746ff6d951SJohn Birrell 		}
17756ff6d951SJohn Birrell 
177618737969SJohn Birrell 		if (pc == 0)
17776ff6d951SJohn Birrell 			break;
17786ff6d951SJohn Birrell 
17796ff6d951SJohn Birrell 		addr += size;
17806ff6d951SJohn Birrell 
17816ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
17826ff6d951SJohn Birrell 			return (-1);
17836ff6d951SJohn Birrell 
17846ff6d951SJohn Birrell 		if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
17856ff6d951SJohn Birrell 			if (pc > sym.st_value) {
17866ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
17876ff6d951SJohn Birrell 				    dts.dts_object, dts.dts_name,
17888ac4e8ebSDimitry Andric 				    (u_longlong_t)(pc - sym.st_value));
17896ff6d951SJohn Birrell 			} else {
17906ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "%s`%s",
17916ff6d951SJohn Birrell 				    dts.dts_object, dts.dts_name);
17926ff6d951SJohn Birrell 			}
17936ff6d951SJohn Birrell 		} else {
17946ff6d951SJohn Birrell 			/*
17956ff6d951SJohn Birrell 			 * We'll repeat the lookup, but this time we'll specify
17966ff6d951SJohn Birrell 			 * a NULL GElf_Sym -- indicating that we're only
17976ff6d951SJohn Birrell 			 * interested in the containing module.
17986ff6d951SJohn Birrell 			 */
17996ff6d951SJohn Birrell 			if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
18006ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
18018ac4e8ebSDimitry Andric 				    dts.dts_object, (u_longlong_t)pc);
18026ff6d951SJohn Birrell 			} else {
18038ac4e8ebSDimitry Andric 				(void) snprintf(c, sizeof (c), "0x%llx",
18048ac4e8ebSDimitry Andric 				    (u_longlong_t)pc);
18056ff6d951SJohn Birrell 			}
18066ff6d951SJohn Birrell 		}
18076ff6d951SJohn Birrell 
18086ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, format, c) < 0)
18096ff6d951SJohn Birrell 			return (-1);
18106ff6d951SJohn Birrell 
18116ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "\n") < 0)
18126ff6d951SJohn Birrell 			return (-1);
18136ff6d951SJohn Birrell 	}
18146ff6d951SJohn Birrell 
18156ff6d951SJohn Birrell 	return (0);
18166ff6d951SJohn Birrell }
18176ff6d951SJohn Birrell 
18186ff6d951SJohn Birrell int
dt_print_ustack(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr,uint64_t arg)18196ff6d951SJohn Birrell dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
18206ff6d951SJohn Birrell     caddr_t addr, uint64_t arg)
18216ff6d951SJohn Birrell {
18226ff6d951SJohn Birrell 	/* LINTED - alignment */
18236ff6d951SJohn Birrell 	uint64_t *pc = (uint64_t *)addr;
18246ff6d951SJohn Birrell 	uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
18256ff6d951SJohn Birrell 	uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
18266ff6d951SJohn Birrell 	const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
18276ff6d951SJohn Birrell 	const char *str = strsize ? strbase : NULL;
18286ff6d951SJohn Birrell 	int err = 0;
18296ff6d951SJohn Birrell 
18306ff6d951SJohn Birrell 	char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
18316ff6d951SJohn Birrell 	struct ps_prochandle *P;
18326ff6d951SJohn Birrell 	GElf_Sym sym;
18336ff6d951SJohn Birrell 	int i, indent;
18346ff6d951SJohn Birrell 	pid_t pid;
18356ff6d951SJohn Birrell 
18366ff6d951SJohn Birrell 	if (depth == 0)
18376ff6d951SJohn Birrell 		return (0);
18386ff6d951SJohn Birrell 
18396ff6d951SJohn Birrell 	pid = (pid_t)*pc++;
18406ff6d951SJohn Birrell 
18416ff6d951SJohn Birrell 	if (dt_printf(dtp, fp, "\n") < 0)
18426ff6d951SJohn Birrell 		return (-1);
18436ff6d951SJohn Birrell 
18446ff6d951SJohn Birrell 	if (format == NULL)
18456ff6d951SJohn Birrell 		format = "%s";
18466ff6d951SJohn Birrell 
18476ff6d951SJohn Birrell 	if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
18486ff6d951SJohn Birrell 		indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
18496ff6d951SJohn Birrell 	else
18506ff6d951SJohn Birrell 		indent = _dtrace_stkindent;
18516ff6d951SJohn Birrell 
18526ff6d951SJohn Birrell 	/*
18536ff6d951SJohn Birrell 	 * Ultimately, we need to add an entry point in the library vector for
18546ff6d951SJohn Birrell 	 * determining <symbol, offset> from <pid, address>.  For now, if
18556ff6d951SJohn Birrell 	 * this is a vector open, we just print the raw address or string.
18566ff6d951SJohn Birrell 	 */
18576ff6d951SJohn Birrell 	if (dtp->dt_vector == NULL)
18586ff6d951SJohn Birrell 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
18596ff6d951SJohn Birrell 	else
18606ff6d951SJohn Birrell 		P = NULL;
18616ff6d951SJohn Birrell 
18626ff6d951SJohn Birrell 	if (P != NULL)
18636ff6d951SJohn Birrell 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
18646ff6d951SJohn Birrell 
186518737969SJohn Birrell 	for (i = 0; i < depth && pc[i] != 0; i++) {
18666ff6d951SJohn Birrell 		const prmap_t *map;
18676ff6d951SJohn Birrell 
18686ff6d951SJohn Birrell 		if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
18696ff6d951SJohn Birrell 			break;
18706ff6d951SJohn Birrell 
18716ff6d951SJohn Birrell 		if (P != NULL && Plookup_by_addr(P, pc[i],
18726ff6d951SJohn Birrell 		    name, sizeof (name), &sym) == 0) {
18736ff6d951SJohn Birrell 			(void) Pobjname(P, pc[i], objname, sizeof (objname));
18746ff6d951SJohn Birrell 
18756ff6d951SJohn Birrell 			if (pc[i] > sym.st_value) {
18766ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c),
18776ff6d951SJohn Birrell 				    "%s`%s+0x%llx", dt_basename(objname), name,
18786ff6d951SJohn Birrell 				    (u_longlong_t)(pc[i] - sym.st_value));
18796ff6d951SJohn Birrell 			} else {
18806ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c),
18816ff6d951SJohn Birrell 				    "%s`%s", dt_basename(objname), name);
18826ff6d951SJohn Birrell 			}
18836ff6d951SJohn Birrell 		} else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
18846ff6d951SJohn Birrell 		    (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
18856ff6d951SJohn Birrell 		    (map->pr_mflags & MA_WRITE)))) {
18866ff6d951SJohn Birrell 			/*
18876ff6d951SJohn Birrell 			 * If the current string pointer in the string table
18886ff6d951SJohn Birrell 			 * does not point to an empty string _and_ the program
18896ff6d951SJohn Birrell 			 * counter falls in a writable region, we'll use the
18906ff6d951SJohn Birrell 			 * string from the string table instead of the raw
18916ff6d951SJohn Birrell 			 * address.  This last condition is necessary because
18926ff6d951SJohn Birrell 			 * some (broken) ustack helpers will return a string
18936ff6d951SJohn Birrell 			 * even for a program counter that they can't
18946ff6d951SJohn Birrell 			 * identify.  If we have a string for a program
18956ff6d951SJohn Birrell 			 * counter that falls in a segment that isn't
18966ff6d951SJohn Birrell 			 * writable, we assume that we have fallen into this
18976ff6d951SJohn Birrell 			 * case and we refuse to use the string.
18986ff6d951SJohn Birrell 			 */
18996ff6d951SJohn Birrell 			(void) snprintf(c, sizeof (c), "%s", str);
19006ff6d951SJohn Birrell 		} else {
19016ff6d951SJohn Birrell 			if (P != NULL && Pobjname(P, pc[i], objname,
190218737969SJohn Birrell 			    sizeof (objname)) != 0) {
19036ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
19046ff6d951SJohn Birrell 				    dt_basename(objname), (u_longlong_t)pc[i]);
19056ff6d951SJohn Birrell 			} else {
19066ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "0x%llx",
19076ff6d951SJohn Birrell 				    (u_longlong_t)pc[i]);
19086ff6d951SJohn Birrell 			}
19096ff6d951SJohn Birrell 		}
19106ff6d951SJohn Birrell 
19116ff6d951SJohn Birrell 		if ((err = dt_printf(dtp, fp, format, c)) < 0)
19126ff6d951SJohn Birrell 			break;
19136ff6d951SJohn Birrell 
19146ff6d951SJohn Birrell 		if ((err = dt_printf(dtp, fp, "\n")) < 0)
19156ff6d951SJohn Birrell 			break;
19166ff6d951SJohn Birrell 
19176ff6d951SJohn Birrell 		if (str != NULL && str[0] == '@') {
19186ff6d951SJohn Birrell 			/*
19196ff6d951SJohn Birrell 			 * If the first character of the string is an "at" sign,
19206ff6d951SJohn Birrell 			 * then the string is inferred to be an annotation --
19216ff6d951SJohn Birrell 			 * and it is printed out beneath the frame and offset
19226ff6d951SJohn Birrell 			 * with brackets.
19236ff6d951SJohn Birrell 			 */
19246ff6d951SJohn Birrell 			if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
19256ff6d951SJohn Birrell 				break;
19266ff6d951SJohn Birrell 
19276ff6d951SJohn Birrell 			(void) snprintf(c, sizeof (c), "  [ %s ]", &str[1]);
19286ff6d951SJohn Birrell 
19296ff6d951SJohn Birrell 			if ((err = dt_printf(dtp, fp, format, c)) < 0)
19306ff6d951SJohn Birrell 				break;
19316ff6d951SJohn Birrell 
19326ff6d951SJohn Birrell 			if ((err = dt_printf(dtp, fp, "\n")) < 0)
19336ff6d951SJohn Birrell 				break;
19346ff6d951SJohn Birrell 		}
19356ff6d951SJohn Birrell 
19366ff6d951SJohn Birrell 		if (str != NULL) {
19376ff6d951SJohn Birrell 			str += strlen(str) + 1;
19386ff6d951SJohn Birrell 			if (str - strbase >= strsize)
19396ff6d951SJohn Birrell 				str = NULL;
19406ff6d951SJohn Birrell 		}
19416ff6d951SJohn Birrell 	}
19426ff6d951SJohn Birrell 
19436ff6d951SJohn Birrell 	if (P != NULL) {
19446ff6d951SJohn Birrell 		dt_proc_unlock(dtp, P);
19456ff6d951SJohn Birrell 		dt_proc_release(dtp, P);
19466ff6d951SJohn Birrell 	}
19476ff6d951SJohn Birrell 
19486ff6d951SJohn Birrell 	return (err);
19496ff6d951SJohn Birrell }
19506ff6d951SJohn Birrell 
19516ff6d951SJohn Birrell static int
dt_format_usym(dtrace_hdl_t * dtp,caddr_t addr,dtrace_actkind_t act)195293f27766SDomagoj Stolfa dt_format_usym(dtrace_hdl_t *dtp, caddr_t addr, dtrace_actkind_t act)
195393f27766SDomagoj Stolfa {
195493f27766SDomagoj Stolfa 	uint64_t pid = ((uint64_t *)addr)[0];
195593f27766SDomagoj Stolfa 	uint64_t pc = ((uint64_t *)addr)[1];
195693f27766SDomagoj Stolfa 	char *s;
195793f27766SDomagoj Stolfa 	int n, len = 256;
195893f27766SDomagoj Stolfa 
195993f27766SDomagoj Stolfa 	if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
196093f27766SDomagoj Stolfa 		struct ps_prochandle *P;
196193f27766SDomagoj Stolfa 
196293f27766SDomagoj Stolfa 		if ((P = dt_proc_grab(dtp, pid,
196393f27766SDomagoj Stolfa 		    PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
196493f27766SDomagoj Stolfa 			GElf_Sym sym;
196593f27766SDomagoj Stolfa 
196693f27766SDomagoj Stolfa 			dt_proc_lock(dtp, P);
196793f27766SDomagoj Stolfa 
196893f27766SDomagoj Stolfa 			if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
196993f27766SDomagoj Stolfa 				pc = sym.st_value;
197093f27766SDomagoj Stolfa 
197193f27766SDomagoj Stolfa 			dt_proc_unlock(dtp, P);
197293f27766SDomagoj Stolfa 			dt_proc_release(dtp, P);
197393f27766SDomagoj Stolfa 		}
197493f27766SDomagoj Stolfa 	}
197593f27766SDomagoj Stolfa 
197693f27766SDomagoj Stolfa 	do {
197793f27766SDomagoj Stolfa 		n = len;
197893f27766SDomagoj Stolfa 		s = alloca(n);
197993f27766SDomagoj Stolfa 	} while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n);
198093f27766SDomagoj Stolfa 
198193f27766SDomagoj Stolfa 	xo_emit("{:usym/%s}", s);
198293f27766SDomagoj Stolfa 	return (0);
198393f27766SDomagoj Stolfa }
198493f27766SDomagoj Stolfa 
198593f27766SDomagoj Stolfa 
198693f27766SDomagoj Stolfa static int
dt_print_usym(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,dtrace_actkind_t act)19876ff6d951SJohn Birrell dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
19886ff6d951SJohn Birrell {
19896ff6d951SJohn Birrell 	/* LINTED - alignment */
19906ff6d951SJohn Birrell 	uint64_t pid = ((uint64_t *)addr)[0];
19916ff6d951SJohn Birrell 	/* LINTED - alignment */
19926ff6d951SJohn Birrell 	uint64_t pc = ((uint64_t *)addr)[1];
19936ff6d951SJohn Birrell 	const char *format = "  %-50s";
19946ff6d951SJohn Birrell 	char *s;
19956ff6d951SJohn Birrell 	int n, len = 256;
19966ff6d951SJohn Birrell 
19976ff6d951SJohn Birrell 	if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
19986ff6d951SJohn Birrell 		struct ps_prochandle *P;
19996ff6d951SJohn Birrell 
20006ff6d951SJohn Birrell 		if ((P = dt_proc_grab(dtp, pid,
20016ff6d951SJohn Birrell 		    PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
20026ff6d951SJohn Birrell 			GElf_Sym sym;
20036ff6d951SJohn Birrell 
20046ff6d951SJohn Birrell 			dt_proc_lock(dtp, P);
20056ff6d951SJohn Birrell 
20066ff6d951SJohn Birrell 			if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
20076ff6d951SJohn Birrell 				pc = sym.st_value;
20086ff6d951SJohn Birrell 
20096ff6d951SJohn Birrell 			dt_proc_unlock(dtp, P);
20106ff6d951SJohn Birrell 			dt_proc_release(dtp, P);
20116ff6d951SJohn Birrell 		}
20126ff6d951SJohn Birrell 	}
20136ff6d951SJohn Birrell 
20146ff6d951SJohn Birrell 	do {
20156ff6d951SJohn Birrell 		n = len;
20166ff6d951SJohn Birrell 		s = alloca(n);
20171670a1c2SRui Paulo 	} while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n);
20186ff6d951SJohn Birrell 
20196ff6d951SJohn Birrell 	return (dt_printf(dtp, fp, format, s));
20206ff6d951SJohn Birrell }
20216ff6d951SJohn Birrell 
20226ff6d951SJohn Birrell int
dt_format_umod(dtrace_hdl_t * dtp,caddr_t addr)202393f27766SDomagoj Stolfa dt_format_umod(dtrace_hdl_t *dtp, caddr_t addr)
202493f27766SDomagoj Stolfa {
202593f27766SDomagoj Stolfa 	uint64_t pid = ((uint64_t *)addr)[0];
202693f27766SDomagoj Stolfa 	uint64_t pc = ((uint64_t *)addr)[1];
202793f27766SDomagoj Stolfa 	int err = 0;
202893f27766SDomagoj Stolfa 
202993f27766SDomagoj Stolfa 	char objname[PATH_MAX];
203093f27766SDomagoj Stolfa 	struct ps_prochandle *P;
203193f27766SDomagoj Stolfa 
203293f27766SDomagoj Stolfa 	/*
203393f27766SDomagoj Stolfa 	 * See the comment in dt_print_ustack() for the rationale for
203493f27766SDomagoj Stolfa 	 * printing raw addresses in the vectored case.
203593f27766SDomagoj Stolfa 	 */
203693f27766SDomagoj Stolfa 	if (dtp->dt_vector == NULL)
203793f27766SDomagoj Stolfa 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
203893f27766SDomagoj Stolfa 	else
203993f27766SDomagoj Stolfa 		P = NULL;
204093f27766SDomagoj Stolfa 
204193f27766SDomagoj Stolfa 	if (P != NULL)
204293f27766SDomagoj Stolfa 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
204393f27766SDomagoj Stolfa 
204493f27766SDomagoj Stolfa 	if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) {
204593f27766SDomagoj Stolfa 		xo_emit("{:umod/%s}", dt_basename(objname));
204693f27766SDomagoj Stolfa 	} else {
204793f27766SDomagoj Stolfa 		xo_emit("{:umod/0x%llx}", (u_longlong_t)pc);
204893f27766SDomagoj Stolfa 	}
204993f27766SDomagoj Stolfa 
205093f27766SDomagoj Stolfa 	if (P != NULL) {
205193f27766SDomagoj Stolfa 		dt_proc_unlock(dtp, P);
205293f27766SDomagoj Stolfa 		dt_proc_release(dtp, P);
205393f27766SDomagoj Stolfa 	}
205493f27766SDomagoj Stolfa 
205593f27766SDomagoj Stolfa 	return (0);
205693f27766SDomagoj Stolfa }
205793f27766SDomagoj Stolfa 
205893f27766SDomagoj Stolfa int
dt_print_umod(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr)20596ff6d951SJohn Birrell dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
20606ff6d951SJohn Birrell {
20616ff6d951SJohn Birrell 	/* LINTED - alignment */
20626ff6d951SJohn Birrell 	uint64_t pid = ((uint64_t *)addr)[0];
20636ff6d951SJohn Birrell 	/* LINTED - alignment */
20646ff6d951SJohn Birrell 	uint64_t pc = ((uint64_t *)addr)[1];
20656ff6d951SJohn Birrell 	int err = 0;
20666ff6d951SJohn Birrell 
20676ff6d951SJohn Birrell 	char objname[PATH_MAX], c[PATH_MAX * 2];
20686ff6d951SJohn Birrell 	struct ps_prochandle *P;
20696ff6d951SJohn Birrell 
20706ff6d951SJohn Birrell 	if (format == NULL)
20716ff6d951SJohn Birrell 		format = "  %-50s";
20726ff6d951SJohn Birrell 
20736ff6d951SJohn Birrell 	/*
20746ff6d951SJohn Birrell 	 * See the comment in dt_print_ustack() for the rationale for
20756ff6d951SJohn Birrell 	 * printing raw addresses in the vectored case.
20766ff6d951SJohn Birrell 	 */
20776ff6d951SJohn Birrell 	if (dtp->dt_vector == NULL)
20786ff6d951SJohn Birrell 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
20796ff6d951SJohn Birrell 	else
20806ff6d951SJohn Birrell 		P = NULL;
20816ff6d951SJohn Birrell 
20826ff6d951SJohn Birrell 	if (P != NULL)
20836ff6d951SJohn Birrell 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
20846ff6d951SJohn Birrell 
208518737969SJohn Birrell 	if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) {
20866ff6d951SJohn Birrell 		(void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
20876ff6d951SJohn Birrell 	} else {
20886ff6d951SJohn Birrell 		(void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
20896ff6d951SJohn Birrell 	}
20906ff6d951SJohn Birrell 
20916ff6d951SJohn Birrell 	err = dt_printf(dtp, fp, format, c);
20926ff6d951SJohn Birrell 
20936ff6d951SJohn Birrell 	if (P != NULL) {
20946ff6d951SJohn Birrell 		dt_proc_unlock(dtp, P);
20956ff6d951SJohn Birrell 		dt_proc_release(dtp, P);
20966ff6d951SJohn Birrell 	}
20976ff6d951SJohn Birrell 
20986ff6d951SJohn Birrell 	return (err);
20996ff6d951SJohn Birrell }
21006ff6d951SJohn Birrell 
21016ff6d951SJohn Birrell static int
dt_print_sym(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr)21026ff6d951SJohn Birrell dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
21036ff6d951SJohn Birrell {
21046ff6d951SJohn Birrell 	/* LINTED - alignment */
21056ff6d951SJohn Birrell 	uint64_t pc = *((uint64_t *)addr);
21066ff6d951SJohn Birrell 	dtrace_syminfo_t dts;
21076ff6d951SJohn Birrell 	GElf_Sym sym;
21086ff6d951SJohn Birrell 	char c[PATH_MAX * 2];
21096ff6d951SJohn Birrell 
21106ff6d951SJohn Birrell 	if (format == NULL)
21116ff6d951SJohn Birrell 		format = "  %-50s";
21126ff6d951SJohn Birrell 
21136ff6d951SJohn Birrell 	if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
211493f27766SDomagoj Stolfa 		if (dtp->dt_oformat)
211593f27766SDomagoj Stolfa 			xo_emit("{:sym/%s`%s} {:object/%s} {:name/%s}",
211693f27766SDomagoj Stolfa 			    dts.dts_object, dts.dts_name, dts.dts_object,
211793f27766SDomagoj Stolfa 			    dts.dts_name);
211893f27766SDomagoj Stolfa 		else
21196ff6d951SJohn Birrell 			(void) snprintf(c, sizeof (c), "%s`%s",
21206ff6d951SJohn Birrell 			    dts.dts_object, dts.dts_name);
21216ff6d951SJohn Birrell 	} else {
21226ff6d951SJohn Birrell 		/*
21236ff6d951SJohn Birrell 		 * We'll repeat the lookup, but this time we'll specify a
21246ff6d951SJohn Birrell 		 * NULL GElf_Sym -- indicating that we're only interested in
21256ff6d951SJohn Birrell 		 * the containing module.
21266ff6d951SJohn Birrell 		 */
21276ff6d951SJohn Birrell 		if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
212893f27766SDomagoj Stolfa 			if (dtp->dt_oformat)
212993f27766SDomagoj Stolfa 				xo_emit("{:sym/%s`0x%llx} {:object/%s} "
213093f27766SDomagoj Stolfa 					"{:offset/0x%llx}",
213193f27766SDomagoj Stolfa 				    dts.dts_object, (u_longlong_t)pc,
213293f27766SDomagoj Stolfa 				    dts.dts_object, (u_longlong_t)pc);
213393f27766SDomagoj Stolfa 			else
21346ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
21356ff6d951SJohn Birrell 				    dts.dts_object, (u_longlong_t)pc);
21366ff6d951SJohn Birrell 		} else {
213793f27766SDomagoj Stolfa 			if (dtp->dt_oformat)
213893f27766SDomagoj Stolfa 				xo_emit("{:sym/0x%llx} {:offset/0x%llx}",
213993f27766SDomagoj Stolfa 				    (u_longlong_t)pc, (u_longlong_t)pc);
214093f27766SDomagoj Stolfa 			else
21416ff6d951SJohn Birrell 				(void) snprintf(c, sizeof (c), "0x%llx",
21426ff6d951SJohn Birrell 				    (u_longlong_t)pc);
21436ff6d951SJohn Birrell 		}
21446ff6d951SJohn Birrell 	}
21456ff6d951SJohn Birrell 
214693f27766SDomagoj Stolfa 	if (dtp->dt_oformat != 0 && dt_printf(dtp, fp, format, c) < 0)
21476ff6d951SJohn Birrell 		return (-1);
21486ff6d951SJohn Birrell 
21496ff6d951SJohn Birrell 	return (0);
21506ff6d951SJohn Birrell }
21516ff6d951SJohn Birrell 
21526ff6d951SJohn Birrell int
dt_format_mod(dtrace_hdl_t * dtp,caddr_t addr)215393f27766SDomagoj Stolfa dt_format_mod(dtrace_hdl_t *dtp, caddr_t addr)
215493f27766SDomagoj Stolfa {
215593f27766SDomagoj Stolfa 	/* LINTED - alignment */
215693f27766SDomagoj Stolfa 	uint64_t pc = *((uint64_t *)addr);
215793f27766SDomagoj Stolfa 	dtrace_syminfo_t dts;
215893f27766SDomagoj Stolfa 
215993f27766SDomagoj Stolfa 	if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
216093f27766SDomagoj Stolfa 		xo_emit("{:mod/%s}", dts.dts_object);
216193f27766SDomagoj Stolfa 	} else {
216293f27766SDomagoj Stolfa 		xo_emit("{:mod/0x%llx}", (u_longlong_t)pc);
216393f27766SDomagoj Stolfa 	}
216493f27766SDomagoj Stolfa 
216593f27766SDomagoj Stolfa 	return (0);
216693f27766SDomagoj Stolfa }
216793f27766SDomagoj Stolfa 
216893f27766SDomagoj Stolfa int
dt_print_mod(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr)21696ff6d951SJohn Birrell dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
21706ff6d951SJohn Birrell {
21716ff6d951SJohn Birrell 	/* LINTED - alignment */
21726ff6d951SJohn Birrell 	uint64_t pc = *((uint64_t *)addr);
21736ff6d951SJohn Birrell 	dtrace_syminfo_t dts;
21746ff6d951SJohn Birrell 	char c[PATH_MAX * 2];
21756ff6d951SJohn Birrell 
21766ff6d951SJohn Birrell 	if (format == NULL)
21776ff6d951SJohn Birrell 		format = "  %-50s";
21786ff6d951SJohn Birrell 
21796ff6d951SJohn Birrell 	if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
21806ff6d951SJohn Birrell 		(void) snprintf(c, sizeof (c), "%s", dts.dts_object);
21816ff6d951SJohn Birrell 	} else {
21826ff6d951SJohn Birrell 		(void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
21836ff6d951SJohn Birrell 	}
21846ff6d951SJohn Birrell 
21856ff6d951SJohn Birrell 	if (dt_printf(dtp, fp, format, c) < 0)
21866ff6d951SJohn Birrell 		return (-1);
21876ff6d951SJohn Birrell 
21886ff6d951SJohn Birrell 	return (0);
21896ff6d951SJohn Birrell }
21906ff6d951SJohn Birrell 
219193f27766SDomagoj Stolfa static char *
dt_format_bytes_get(dtrace_hdl_t * dtp,caddr_t addr,size_t nbytes)219293f27766SDomagoj Stolfa dt_format_bytes_get(dtrace_hdl_t *dtp, caddr_t addr, size_t nbytes)
219393f27766SDomagoj Stolfa {
219493f27766SDomagoj Stolfa 	char *s = dt_alloc(dtp, nbytes * 2 + 2 + 1); /* 2 bytes per byte + 0x + '\0' */
219593f27766SDomagoj Stolfa 	char t[6];
219693f27766SDomagoj Stolfa 	char *c = (char *)addr;
219793f27766SDomagoj Stolfa 	size_t i, j;
219893f27766SDomagoj Stolfa 
219993f27766SDomagoj Stolfa 	if (s == NULL)
220093f27766SDomagoj Stolfa 		return (NULL);
220193f27766SDomagoj Stolfa 
220293f27766SDomagoj Stolfa 	/*
220393f27766SDomagoj Stolfa 	 * XXX: Some duplication with dt_print_bytes().
220493f27766SDomagoj Stolfa 	 */
220593f27766SDomagoj Stolfa 	for (i = 0; i < nbytes; i++) {
220693f27766SDomagoj Stolfa 		if (isprint(c[i]) || isspace(c[i]) || c[i] == '\b' || c[i] == '\a')
220793f27766SDomagoj Stolfa 			continue;
220893f27766SDomagoj Stolfa 
220993f27766SDomagoj Stolfa 		if (c[i] == '\0' && i > 0) {
221093f27766SDomagoj Stolfa 			for (j = i + 1; j < nbytes; j++) {
221193f27766SDomagoj Stolfa 				if (c[j] != '\0')
221293f27766SDomagoj Stolfa 					break;
221393f27766SDomagoj Stolfa 			}
221493f27766SDomagoj Stolfa 
221593f27766SDomagoj Stolfa 			if (j != nbytes)
221693f27766SDomagoj Stolfa 				break;
221793f27766SDomagoj Stolfa 
221893f27766SDomagoj Stolfa 			memcpy(s, c, nbytes);
221993f27766SDomagoj Stolfa 			return (s);
222093f27766SDomagoj Stolfa 		}
222193f27766SDomagoj Stolfa 
222293f27766SDomagoj Stolfa 		break;
222393f27766SDomagoj Stolfa 	}
222493f27766SDomagoj Stolfa 
222593f27766SDomagoj Stolfa 	if (i == nbytes) {
222693f27766SDomagoj Stolfa 		memcpy(s, c, nbytes);
222793f27766SDomagoj Stolfa 		s[nbytes] = '\0';
222893f27766SDomagoj Stolfa 		return (s);
222993f27766SDomagoj Stolfa 	}
223093f27766SDomagoj Stolfa 
223193f27766SDomagoj Stolfa 	s[0] = '0';
223293f27766SDomagoj Stolfa 	s[1] = 'x';
223393f27766SDomagoj Stolfa 	for (i = 0; i < nbytes; i++) {
223493f27766SDomagoj Stolfa 		snprintf(t, sizeof(t), "%02x", (uchar_t)c[i]);
223593f27766SDomagoj Stolfa 		memcpy(s + (i * 2) + 2, t, 2);
223693f27766SDomagoj Stolfa 	}
223793f27766SDomagoj Stolfa 
223893f27766SDomagoj Stolfa 	s[nbytes * 2 + 2] = 0;
223993f27766SDomagoj Stolfa 	return (s);
224093f27766SDomagoj Stolfa }
224193f27766SDomagoj Stolfa 
224293f27766SDomagoj Stolfa static int
dt_format_memory(dtrace_hdl_t * dtp,caddr_t addr)224393f27766SDomagoj Stolfa dt_format_memory(dtrace_hdl_t *dtp, caddr_t addr)
224493f27766SDomagoj Stolfa {
2245*3877025fSMark Johnston 	size_t nbytes = *((size_t *) addr);
224693f27766SDomagoj Stolfa 	char *s;
224793f27766SDomagoj Stolfa 
2248*3877025fSMark Johnston 	s = dt_format_bytes_get(dtp, addr + sizeof(size_t), nbytes);
224993f27766SDomagoj Stolfa 	if (s == NULL)
225093f27766SDomagoj Stolfa 		return (-1);
225193f27766SDomagoj Stolfa 
225293f27766SDomagoj Stolfa 	xo_emit("{:printm/%s}", s);
225393f27766SDomagoj Stolfa 	dt_free(dtp, s);
225493f27766SDomagoj Stolfa 
225593f27766SDomagoj Stolfa 	return (0);
225693f27766SDomagoj Stolfa }
225793f27766SDomagoj Stolfa 
2258375c8b20SMark Johnston static int
dt_print_memory(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr)2259375c8b20SMark Johnston dt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
2260375c8b20SMark Johnston {
2261375c8b20SMark Johnston 	int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
2262*3877025fSMark Johnston 	size_t nbytes = *((size_t *) addr);
2263375c8b20SMark Johnston 
2264*3877025fSMark Johnston 	return (dt_print_bytes(dtp, fp, addr + sizeof(size_t),
2265375c8b20SMark Johnston 	    nbytes, 50, quiet, 1));
2266375c8b20SMark Johnston }
2267375c8b20SMark Johnston 
22686ff6d951SJohn Birrell typedef struct dt_normal {
22696ff6d951SJohn Birrell 	dtrace_aggvarid_t dtnd_id;
22706ff6d951SJohn Birrell 	uint64_t dtnd_normal;
22716ff6d951SJohn Birrell } dt_normal_t;
22726ff6d951SJohn Birrell 
22736ff6d951SJohn Birrell static int
dt_normalize_agg(const dtrace_aggdata_t * aggdata,void * arg)22746ff6d951SJohn Birrell dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
22756ff6d951SJohn Birrell {
22766ff6d951SJohn Birrell 	dt_normal_t *normal = arg;
22776ff6d951SJohn Birrell 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
22786ff6d951SJohn Birrell 	dtrace_aggvarid_t id = normal->dtnd_id;
22796ff6d951SJohn Birrell 
22806ff6d951SJohn Birrell 	if (agg->dtagd_nrecs == 0)
22816ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
22826ff6d951SJohn Birrell 
22836ff6d951SJohn Birrell 	if (agg->dtagd_varid != id)
22846ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
22856ff6d951SJohn Birrell 
22866ff6d951SJohn Birrell 	((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal;
22876ff6d951SJohn Birrell 	return (DTRACE_AGGWALK_NORMALIZE);
22886ff6d951SJohn Birrell }
22896ff6d951SJohn Birrell 
22906ff6d951SJohn Birrell static int
dt_normalize(dtrace_hdl_t * dtp,caddr_t base,dtrace_recdesc_t * rec)22916ff6d951SJohn Birrell dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
22926ff6d951SJohn Birrell {
22936ff6d951SJohn Birrell 	dt_normal_t normal;
22946ff6d951SJohn Birrell 	caddr_t addr;
22956ff6d951SJohn Birrell 
22966ff6d951SJohn Birrell 	/*
22976ff6d951SJohn Birrell 	 * We (should) have two records:  the aggregation ID followed by the
22986ff6d951SJohn Birrell 	 * normalization value.
22996ff6d951SJohn Birrell 	 */
23006ff6d951SJohn Birrell 	addr = base + rec->dtrd_offset;
23016ff6d951SJohn Birrell 
23026ff6d951SJohn Birrell 	if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
23036ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADNORMAL));
23046ff6d951SJohn Birrell 
23056ff6d951SJohn Birrell 	/* LINTED - alignment */
23066ff6d951SJohn Birrell 	normal.dtnd_id = *((dtrace_aggvarid_t *)addr);
23076ff6d951SJohn Birrell 	rec++;
23086ff6d951SJohn Birrell 
23096ff6d951SJohn Birrell 	if (rec->dtrd_action != DTRACEACT_LIBACT)
23106ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADNORMAL));
23116ff6d951SJohn Birrell 
23126ff6d951SJohn Birrell 	if (rec->dtrd_arg != DT_ACT_NORMALIZE)
23136ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADNORMAL));
23146ff6d951SJohn Birrell 
23156ff6d951SJohn Birrell 	addr = base + rec->dtrd_offset;
23166ff6d951SJohn Birrell 
23176ff6d951SJohn Birrell 	switch (rec->dtrd_size) {
23186ff6d951SJohn Birrell 	case sizeof (uint64_t):
23196ff6d951SJohn Birrell 		/* LINTED - alignment */
23206ff6d951SJohn Birrell 		normal.dtnd_normal = *((uint64_t *)addr);
23216ff6d951SJohn Birrell 		break;
23226ff6d951SJohn Birrell 	case sizeof (uint32_t):
23236ff6d951SJohn Birrell 		/* LINTED - alignment */
23246ff6d951SJohn Birrell 		normal.dtnd_normal = *((uint32_t *)addr);
23256ff6d951SJohn Birrell 		break;
23266ff6d951SJohn Birrell 	case sizeof (uint16_t):
23276ff6d951SJohn Birrell 		/* LINTED - alignment */
23286ff6d951SJohn Birrell 		normal.dtnd_normal = *((uint16_t *)addr);
23296ff6d951SJohn Birrell 		break;
23306ff6d951SJohn Birrell 	case sizeof (uint8_t):
23316ff6d951SJohn Birrell 		normal.dtnd_normal = *((uint8_t *)addr);
23326ff6d951SJohn Birrell 		break;
23336ff6d951SJohn Birrell 	default:
23346ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADNORMAL));
23356ff6d951SJohn Birrell 	}
23366ff6d951SJohn Birrell 
23376ff6d951SJohn Birrell 	(void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal);
23386ff6d951SJohn Birrell 
23396ff6d951SJohn Birrell 	return (0);
23406ff6d951SJohn Birrell }
23416ff6d951SJohn Birrell 
23426ff6d951SJohn Birrell static int
dt_denormalize_agg(const dtrace_aggdata_t * aggdata,void * arg)23436ff6d951SJohn Birrell dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
23446ff6d951SJohn Birrell {
23456ff6d951SJohn Birrell 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
23466ff6d951SJohn Birrell 	dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
23476ff6d951SJohn Birrell 
23486ff6d951SJohn Birrell 	if (agg->dtagd_nrecs == 0)
23496ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
23506ff6d951SJohn Birrell 
23516ff6d951SJohn Birrell 	if (agg->dtagd_varid != id)
23526ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
23536ff6d951SJohn Birrell 
23546ff6d951SJohn Birrell 	return (DTRACE_AGGWALK_DENORMALIZE);
23556ff6d951SJohn Birrell }
23566ff6d951SJohn Birrell 
23576ff6d951SJohn Birrell static int
dt_clear_agg(const dtrace_aggdata_t * aggdata,void * arg)23586ff6d951SJohn Birrell dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg)
23596ff6d951SJohn Birrell {
23606ff6d951SJohn Birrell 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
23616ff6d951SJohn Birrell 	dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
23626ff6d951SJohn Birrell 
23636ff6d951SJohn Birrell 	if (agg->dtagd_nrecs == 0)
23646ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
23656ff6d951SJohn Birrell 
23666ff6d951SJohn Birrell 	if (agg->dtagd_varid != id)
23676ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
23686ff6d951SJohn Birrell 
23696ff6d951SJohn Birrell 	return (DTRACE_AGGWALK_CLEAR);
23706ff6d951SJohn Birrell }
23716ff6d951SJohn Birrell 
23726ff6d951SJohn Birrell typedef struct dt_trunc {
23736ff6d951SJohn Birrell 	dtrace_aggvarid_t dttd_id;
23746ff6d951SJohn Birrell 	uint64_t dttd_remaining;
23756ff6d951SJohn Birrell } dt_trunc_t;
23766ff6d951SJohn Birrell 
23776ff6d951SJohn Birrell static int
dt_trunc_agg(const dtrace_aggdata_t * aggdata,void * arg)23786ff6d951SJohn Birrell dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg)
23796ff6d951SJohn Birrell {
23806ff6d951SJohn Birrell 	dt_trunc_t *trunc = arg;
23816ff6d951SJohn Birrell 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
23826ff6d951SJohn Birrell 	dtrace_aggvarid_t id = trunc->dttd_id;
23836ff6d951SJohn Birrell 
23846ff6d951SJohn Birrell 	if (agg->dtagd_nrecs == 0)
23856ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
23866ff6d951SJohn Birrell 
23876ff6d951SJohn Birrell 	if (agg->dtagd_varid != id)
23886ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_NEXT);
23896ff6d951SJohn Birrell 
23906ff6d951SJohn Birrell 	if (trunc->dttd_remaining == 0)
23916ff6d951SJohn Birrell 		return (DTRACE_AGGWALK_REMOVE);
23926ff6d951SJohn Birrell 
23936ff6d951SJohn Birrell 	trunc->dttd_remaining--;
23946ff6d951SJohn Birrell 	return (DTRACE_AGGWALK_NEXT);
23956ff6d951SJohn Birrell }
23966ff6d951SJohn Birrell 
23976ff6d951SJohn Birrell static int
dt_trunc(dtrace_hdl_t * dtp,caddr_t base,dtrace_recdesc_t * rec)23986ff6d951SJohn Birrell dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
23996ff6d951SJohn Birrell {
24006ff6d951SJohn Birrell 	dt_trunc_t trunc;
24016ff6d951SJohn Birrell 	caddr_t addr;
24026ff6d951SJohn Birrell 	int64_t remaining;
24036ff6d951SJohn Birrell 	int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
24046ff6d951SJohn Birrell 
24056ff6d951SJohn Birrell 	/*
24066ff6d951SJohn Birrell 	 * We (should) have two records:  the aggregation ID followed by the
24076ff6d951SJohn Birrell 	 * number of aggregation entries after which the aggregation is to be
24086ff6d951SJohn Birrell 	 * truncated.
24096ff6d951SJohn Birrell 	 */
24106ff6d951SJohn Birrell 	addr = base + rec->dtrd_offset;
24116ff6d951SJohn Birrell 
24126ff6d951SJohn Birrell 	if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
24136ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADTRUNC));
24146ff6d951SJohn Birrell 
24156ff6d951SJohn Birrell 	/* LINTED - alignment */
24166ff6d951SJohn Birrell 	trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
24176ff6d951SJohn Birrell 	rec++;
24186ff6d951SJohn Birrell 
24196ff6d951SJohn Birrell 	if (rec->dtrd_action != DTRACEACT_LIBACT)
24206ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADTRUNC));
24216ff6d951SJohn Birrell 
24226ff6d951SJohn Birrell 	if (rec->dtrd_arg != DT_ACT_TRUNC)
24236ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADTRUNC));
24246ff6d951SJohn Birrell 
24256ff6d951SJohn Birrell 	addr = base + rec->dtrd_offset;
24266ff6d951SJohn Birrell 
24276ff6d951SJohn Birrell 	switch (rec->dtrd_size) {
24286ff6d951SJohn Birrell 	case sizeof (uint64_t):
24296ff6d951SJohn Birrell 		/* LINTED - alignment */
24306ff6d951SJohn Birrell 		remaining = *((int64_t *)addr);
24316ff6d951SJohn Birrell 		break;
24326ff6d951SJohn Birrell 	case sizeof (uint32_t):
24336ff6d951SJohn Birrell 		/* LINTED - alignment */
24346ff6d951SJohn Birrell 		remaining = *((int32_t *)addr);
24356ff6d951SJohn Birrell 		break;
24366ff6d951SJohn Birrell 	case sizeof (uint16_t):
24376ff6d951SJohn Birrell 		/* LINTED - alignment */
24386ff6d951SJohn Birrell 		remaining = *((int16_t *)addr);
24396ff6d951SJohn Birrell 		break;
24406ff6d951SJohn Birrell 	case sizeof (uint8_t):
24416ff6d951SJohn Birrell 		remaining = *((int8_t *)addr);
24426ff6d951SJohn Birrell 		break;
24436ff6d951SJohn Birrell 	default:
24446ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_BADNORMAL));
24456ff6d951SJohn Birrell 	}
24466ff6d951SJohn Birrell 
24476ff6d951SJohn Birrell 	if (remaining < 0) {
24486ff6d951SJohn Birrell 		func = dtrace_aggregate_walk_valsorted;
24496ff6d951SJohn Birrell 		remaining = -remaining;
24506ff6d951SJohn Birrell 	} else {
24516ff6d951SJohn Birrell 		func = dtrace_aggregate_walk_valrevsorted;
24526ff6d951SJohn Birrell 	}
24536ff6d951SJohn Birrell 
24546ff6d951SJohn Birrell 	assert(remaining >= 0);
24556ff6d951SJohn Birrell 	trunc.dttd_remaining = remaining;
24566ff6d951SJohn Birrell 
24576ff6d951SJohn Birrell 	(void) func(dtp, dt_trunc_agg, &trunc);
24586ff6d951SJohn Birrell 
24596ff6d951SJohn Birrell 	return (0);
24606ff6d951SJohn Birrell }
24616ff6d951SJohn Birrell 
24626ff6d951SJohn Birrell static int
dt_format_datum(dtrace_hdl_t * dtp,dtrace_recdesc_t * rec,caddr_t addr,size_t size,const dtrace_aggdata_t * aggdata,uint64_t normal,dt_print_aggdata_t * pd)246393f27766SDomagoj Stolfa dt_format_datum(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, caddr_t addr,
246493f27766SDomagoj Stolfa     size_t size, const dtrace_aggdata_t *aggdata, uint64_t normal,
246593f27766SDomagoj Stolfa     dt_print_aggdata_t *pd)
246693f27766SDomagoj Stolfa {
246793f27766SDomagoj Stolfa 	dtrace_actkind_t act = rec->dtrd_action;
246893f27766SDomagoj Stolfa 	boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack;
246993f27766SDomagoj Stolfa 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
247093f27766SDomagoj Stolfa 	char fmt[512];
247193f27766SDomagoj Stolfa 	char *s;
247293f27766SDomagoj Stolfa 
247393f27766SDomagoj Stolfa 	if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid)
247493f27766SDomagoj Stolfa 		pd->dtpa_agghisthdr = agg->dtagd_varid;
247593f27766SDomagoj Stolfa 
247693f27766SDomagoj Stolfa 	switch (act) {
247793f27766SDomagoj Stolfa 	case DTRACEACT_STACK:
247893f27766SDomagoj Stolfa 		return (dt_format_stack(dtp, addr, rec->dtrd_arg,
247993f27766SDomagoj Stolfa 		    rec->dtrd_size / rec->dtrd_arg));
248093f27766SDomagoj Stolfa 
248193f27766SDomagoj Stolfa 	case DTRACEACT_USTACK:
248293f27766SDomagoj Stolfa 	case DTRACEACT_JSTACK:
248393f27766SDomagoj Stolfa 		return (dt_format_ustack(dtp, addr, rec->dtrd_arg));
248493f27766SDomagoj Stolfa 
248593f27766SDomagoj Stolfa 	case DTRACEACT_USYM:
248693f27766SDomagoj Stolfa 	case DTRACEACT_UADDR:
248793f27766SDomagoj Stolfa 		return (dt_format_usym(dtp, addr, act));
248893f27766SDomagoj Stolfa 
248993f27766SDomagoj Stolfa 	case DTRACEACT_UMOD:
249093f27766SDomagoj Stolfa 		return (dt_format_umod(dtp, addr));
249193f27766SDomagoj Stolfa 
249293f27766SDomagoj Stolfa 	case DTRACEACT_SYM:
249393f27766SDomagoj Stolfa 		return (dt_format_sym(dtp, addr));
249493f27766SDomagoj Stolfa 	case DTRACEACT_MOD:
249593f27766SDomagoj Stolfa 		return (dt_format_mod(dtp, addr));
249693f27766SDomagoj Stolfa 
249793f27766SDomagoj Stolfa 	case DTRACEAGG_QUANTIZE:
249893f27766SDomagoj Stolfa 		return (dt_format_quantize(dtp, addr, size, normal));
249993f27766SDomagoj Stolfa 
250093f27766SDomagoj Stolfa 	case DTRACEAGG_LQUANTIZE:
250193f27766SDomagoj Stolfa 		return (dt_format_lquantize(dtp, addr, size, normal));
250293f27766SDomagoj Stolfa 
250393f27766SDomagoj Stolfa 	case DTRACEAGG_LLQUANTIZE:
250493f27766SDomagoj Stolfa 		return (dt_format_llquantize(dtp, addr, size, normal));
250593f27766SDomagoj Stolfa 
250693f27766SDomagoj Stolfa 	case DTRACEAGG_AVG:
250793f27766SDomagoj Stolfa 		return (dt_format_average(dtp, addr, size, normal));
250893f27766SDomagoj Stolfa 
250993f27766SDomagoj Stolfa 	case DTRACEAGG_STDDEV:
251093f27766SDomagoj Stolfa 		return (dt_format_stddev(dtp, addr, size, normal));
251193f27766SDomagoj Stolfa 
251293f27766SDomagoj Stolfa 	default:
251393f27766SDomagoj Stolfa 		break;
251493f27766SDomagoj Stolfa 	}
251593f27766SDomagoj Stolfa 
251693f27766SDomagoj Stolfa 	switch (size) {
251793f27766SDomagoj Stolfa 	case sizeof (uint64_t):
251893f27766SDomagoj Stolfa 		snprintf(fmt, sizeof(fmt), "{:%s/%%lld}", pd->dtpa_keyname);
251993f27766SDomagoj Stolfa 		xo_emit(fmt, (long long)*((uint64_t *)addr) / normal);
252093f27766SDomagoj Stolfa 		break;
252193f27766SDomagoj Stolfa 	case sizeof (uint32_t):
252293f27766SDomagoj Stolfa 		snprintf(fmt, sizeof(fmt), "{:%s/%%d}", pd->dtpa_keyname);
252393f27766SDomagoj Stolfa 		xo_emit(fmt, *((uint32_t *)addr) / (uint32_t)normal);
252493f27766SDomagoj Stolfa 		break;
252593f27766SDomagoj Stolfa 	case sizeof (uint16_t):
252693f27766SDomagoj Stolfa 		snprintf(fmt, sizeof(fmt), "{:%s/%%d}", pd->dtpa_keyname);
252793f27766SDomagoj Stolfa 		xo_emit(fmt, *((uint16_t *)addr) / (uint32_t)normal);
252893f27766SDomagoj Stolfa 		break;
252993f27766SDomagoj Stolfa 	case sizeof (uint8_t):
253093f27766SDomagoj Stolfa 		snprintf(fmt, sizeof(fmt), "{:%s/%%d}", pd->dtpa_keyname);
253193f27766SDomagoj Stolfa 		xo_emit(fmt, *((uint8_t *)addr) / (uint32_t)normal);
253293f27766SDomagoj Stolfa 		break;
253393f27766SDomagoj Stolfa 	default:
253493f27766SDomagoj Stolfa 		s = dt_format_bytes_get(dtp, addr, size);
253593f27766SDomagoj Stolfa 		if (s == NULL)
253693f27766SDomagoj Stolfa 			return (-1);
253793f27766SDomagoj Stolfa 
253893f27766SDomagoj Stolfa 		xo_emit("{:value/%s}", s);
253993f27766SDomagoj Stolfa 		dt_free(dtp, s);
254093f27766SDomagoj Stolfa 		break;
254193f27766SDomagoj Stolfa 	}
254293f27766SDomagoj Stolfa 
254393f27766SDomagoj Stolfa 	return (0);
254493f27766SDomagoj Stolfa }
254593f27766SDomagoj Stolfa 
254693f27766SDomagoj Stolfa static int
dt_print_datum(dtrace_hdl_t * dtp,FILE * fp,dtrace_recdesc_t * rec,caddr_t addr,size_t size,const dtrace_aggdata_t * aggdata,uint64_t normal,dt_print_aggdata_t * pd)25476ff6d951SJohn Birrell dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
2548a43f0be9SRui Paulo     caddr_t addr, size_t size, const dtrace_aggdata_t *aggdata,
2549a43f0be9SRui Paulo     uint64_t normal, dt_print_aggdata_t *pd)
25506ff6d951SJohn Birrell {
2551a43f0be9SRui Paulo 	int err, width;
25526ff6d951SJohn Birrell 	dtrace_actkind_t act = rec->dtrd_action;
2553a43f0be9SRui Paulo 	boolean_t packed = pd->dtpa_agghist || pd->dtpa_aggpack;
2554a43f0be9SRui Paulo 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
2555a43f0be9SRui Paulo 
2556a43f0be9SRui Paulo 	static struct {
2557a43f0be9SRui Paulo 		size_t size;
2558a43f0be9SRui Paulo 		int width;
2559a43f0be9SRui Paulo 		int packedwidth;
2560a43f0be9SRui Paulo 	} *fmt, fmttab[] = {
2561a43f0be9SRui Paulo 		{ sizeof (uint8_t),	3,	3 },
2562a43f0be9SRui Paulo 		{ sizeof (uint16_t),	5,	5 },
2563a43f0be9SRui Paulo 		{ sizeof (uint32_t),	8,	8 },
2564a43f0be9SRui Paulo 		{ sizeof (uint64_t),	16,	16 },
2565a43f0be9SRui Paulo 		{ 0,			-50,	16 }
2566a43f0be9SRui Paulo 	};
2567a43f0be9SRui Paulo 
2568a43f0be9SRui Paulo 	if (packed && pd->dtpa_agghisthdr != agg->dtagd_varid) {
2569a43f0be9SRui Paulo 		dtrace_recdesc_t *r;
2570a43f0be9SRui Paulo 
2571a43f0be9SRui Paulo 		width = 0;
2572a43f0be9SRui Paulo 
2573a43f0be9SRui Paulo 		/*
2574a43f0be9SRui Paulo 		 * To print our quantization header for either an agghist or
2575a43f0be9SRui Paulo 		 * aggpack aggregation, we need to iterate through all of our
2576a43f0be9SRui Paulo 		 * of our records to determine their width.
2577a43f0be9SRui Paulo 		 */
2578a43f0be9SRui Paulo 		for (r = rec; !DTRACEACT_ISAGG(r->dtrd_action); r++) {
2579a43f0be9SRui Paulo 			for (fmt = fmttab; fmt->size &&
2580a43f0be9SRui Paulo 			    fmt->size != r->dtrd_size; fmt++)
2581a43f0be9SRui Paulo 				continue;
2582a43f0be9SRui Paulo 
2583a43f0be9SRui Paulo 			width += fmt->packedwidth + 1;
2584a43f0be9SRui Paulo 		}
2585a43f0be9SRui Paulo 
2586a43f0be9SRui Paulo 		if (pd->dtpa_agghist) {
2587a43f0be9SRui Paulo 			if (dt_print_quanthdr(dtp, fp, width) < 0)
2588a43f0be9SRui Paulo 				return (-1);
2589a43f0be9SRui Paulo 		} else {
2590a43f0be9SRui Paulo 			if (dt_print_quanthdr_packed(dtp, fp,
2591a43f0be9SRui Paulo 			    width, aggdata, r->dtrd_action) < 0)
2592a43f0be9SRui Paulo 				return (-1);
2593a43f0be9SRui Paulo 		}
2594a43f0be9SRui Paulo 
2595a43f0be9SRui Paulo 		pd->dtpa_agghisthdr = agg->dtagd_varid;
2596a43f0be9SRui Paulo 	}
2597a43f0be9SRui Paulo 
2598a43f0be9SRui Paulo 	if (pd->dtpa_agghist && DTRACEACT_ISAGG(act)) {
2599a43f0be9SRui Paulo 		char positives = aggdata->dtada_flags & DTRACE_A_HASPOSITIVES;
2600a43f0be9SRui Paulo 		char negatives = aggdata->dtada_flags & DTRACE_A_HASNEGATIVES;
2601a43f0be9SRui Paulo 		int64_t val;
2602a43f0be9SRui Paulo 
2603a43f0be9SRui Paulo 		assert(act == DTRACEAGG_SUM || act == DTRACEAGG_COUNT);
2604a43f0be9SRui Paulo 		val = (long long)*((uint64_t *)addr);
2605a43f0be9SRui Paulo 
2606a43f0be9SRui Paulo 		if (dt_printf(dtp, fp, " ") < 0)
2607a43f0be9SRui Paulo 			return (-1);
2608a43f0be9SRui Paulo 
2609a43f0be9SRui Paulo 		return (dt_print_quantline(dtp, fp, val, normal,
2610a43f0be9SRui Paulo 		    aggdata->dtada_total, positives, negatives));
2611a43f0be9SRui Paulo 	}
2612a43f0be9SRui Paulo 
2613a43f0be9SRui Paulo 	if (pd->dtpa_aggpack && DTRACEACT_ISAGG(act)) {
2614a43f0be9SRui Paulo 		switch (act) {
2615a43f0be9SRui Paulo 		case DTRACEAGG_QUANTIZE:
2616a43f0be9SRui Paulo 			return (dt_print_quantize_packed(dtp,
2617a43f0be9SRui Paulo 			    fp, addr, size, aggdata));
2618a43f0be9SRui Paulo 		case DTRACEAGG_LQUANTIZE:
2619a43f0be9SRui Paulo 			return (dt_print_lquantize_packed(dtp,
2620a43f0be9SRui Paulo 			    fp, addr, size, aggdata));
2621a43f0be9SRui Paulo 		default:
2622a43f0be9SRui Paulo 			break;
2623a43f0be9SRui Paulo 		}
2624a43f0be9SRui Paulo 	}
26256ff6d951SJohn Birrell 
26266ff6d951SJohn Birrell 	switch (act) {
26276ff6d951SJohn Birrell 	case DTRACEACT_STACK:
26286ff6d951SJohn Birrell 		return (dt_print_stack(dtp, fp, NULL, addr,
26296ff6d951SJohn Birrell 		    rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg));
26306ff6d951SJohn Birrell 
26316ff6d951SJohn Birrell 	case DTRACEACT_USTACK:
26326ff6d951SJohn Birrell 	case DTRACEACT_JSTACK:
26336ff6d951SJohn Birrell 		return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg));
26346ff6d951SJohn Birrell 
26356ff6d951SJohn Birrell 	case DTRACEACT_USYM:
26366ff6d951SJohn Birrell 	case DTRACEACT_UADDR:
26376ff6d951SJohn Birrell 		return (dt_print_usym(dtp, fp, addr, act));
26386ff6d951SJohn Birrell 
26396ff6d951SJohn Birrell 	case DTRACEACT_UMOD:
26406ff6d951SJohn Birrell 		return (dt_print_umod(dtp, fp, NULL, addr));
26416ff6d951SJohn Birrell 
26426ff6d951SJohn Birrell 	case DTRACEACT_SYM:
26436ff6d951SJohn Birrell 		return (dt_print_sym(dtp, fp, NULL, addr));
26446ff6d951SJohn Birrell 
26456ff6d951SJohn Birrell 	case DTRACEACT_MOD:
26466ff6d951SJohn Birrell 		return (dt_print_mod(dtp, fp, NULL, addr));
26476ff6d951SJohn Birrell 
26486ff6d951SJohn Birrell 	case DTRACEAGG_QUANTIZE:
26496ff6d951SJohn Birrell 		return (dt_print_quantize(dtp, fp, addr, size, normal));
26506ff6d951SJohn Birrell 
26516ff6d951SJohn Birrell 	case DTRACEAGG_LQUANTIZE:
26526ff6d951SJohn Birrell 		return (dt_print_lquantize(dtp, fp, addr, size, normal));
26536ff6d951SJohn Birrell 
2654675cf915SPedro F. Giffuni 	case DTRACEAGG_LLQUANTIZE:
2655675cf915SPedro F. Giffuni 		return (dt_print_llquantize(dtp, fp, addr, size, normal));
2656675cf915SPedro F. Giffuni 
26576ff6d951SJohn Birrell 	case DTRACEAGG_AVG:
26586ff6d951SJohn Birrell 		return (dt_print_average(dtp, fp, addr, size, normal));
26596ff6d951SJohn Birrell 
26606ff6d951SJohn Birrell 	case DTRACEAGG_STDDEV:
26616ff6d951SJohn Birrell 		return (dt_print_stddev(dtp, fp, addr, size, normal));
26626ff6d951SJohn Birrell 
26636ff6d951SJohn Birrell 	default:
26646ff6d951SJohn Birrell 		break;
26656ff6d951SJohn Birrell 	}
26666ff6d951SJohn Birrell 
2667a43f0be9SRui Paulo 	for (fmt = fmttab; fmt->size && fmt->size != size; fmt++)
2668a43f0be9SRui Paulo 		continue;
2669a43f0be9SRui Paulo 
2670a43f0be9SRui Paulo 	width = packed ? fmt->packedwidth : fmt->width;
2671a43f0be9SRui Paulo 
26726ff6d951SJohn Birrell 	switch (size) {
26736ff6d951SJohn Birrell 	case sizeof (uint64_t):
2674a43f0be9SRui Paulo 		err = dt_printf(dtp, fp, " %*lld", width,
26756ff6d951SJohn Birrell 		    /* LINTED - alignment */
26766ff6d951SJohn Birrell 		    (long long)*((uint64_t *)addr) / normal);
26776ff6d951SJohn Birrell 		break;
26786ff6d951SJohn Birrell 	case sizeof (uint32_t):
26796ff6d951SJohn Birrell 		/* LINTED - alignment */
2680a43f0be9SRui Paulo 		err = dt_printf(dtp, fp, " %*d", width, *((uint32_t *)addr) /
26816ff6d951SJohn Birrell 		    (uint32_t)normal);
26826ff6d951SJohn Birrell 		break;
26836ff6d951SJohn Birrell 	case sizeof (uint16_t):
26846ff6d951SJohn Birrell 		/* LINTED - alignment */
2685a43f0be9SRui Paulo 		err = dt_printf(dtp, fp, " %*d", width, *((uint16_t *)addr) /
26866ff6d951SJohn Birrell 		    (uint32_t)normal);
26876ff6d951SJohn Birrell 		break;
26886ff6d951SJohn Birrell 	case sizeof (uint8_t):
2689a43f0be9SRui Paulo 		err = dt_printf(dtp, fp, " %*d", width, *((uint8_t *)addr) /
26906ff6d951SJohn Birrell 		    (uint32_t)normal);
26916ff6d951SJohn Birrell 		break;
26926ff6d951SJohn Birrell 	default:
2693a43f0be9SRui Paulo 		err = dt_print_bytes(dtp, fp, addr, size, width, 0, 0);
26946ff6d951SJohn Birrell 		break;
26956ff6d951SJohn Birrell 	}
26966ff6d951SJohn Birrell 
26976ff6d951SJohn Birrell 	return (err);
26986ff6d951SJohn Birrell }
26996ff6d951SJohn Birrell 
27006ff6d951SJohn Birrell int
dt_format_aggs(const dtrace_aggdata_t ** aggsdata,int naggvars,void * arg)270193f27766SDomagoj Stolfa dt_format_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
270293f27766SDomagoj Stolfa {
270393f27766SDomagoj Stolfa 	int i, aggact = 0;
270493f27766SDomagoj Stolfa 	dt_print_aggdata_t *pd = arg;
270593f27766SDomagoj Stolfa 	const dtrace_aggdata_t *aggdata = aggsdata[0];
270693f27766SDomagoj Stolfa 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
270793f27766SDomagoj Stolfa 	dtrace_hdl_t *dtp = pd->dtpa_dtp;
270893f27766SDomagoj Stolfa 	dtrace_recdesc_t *rec;
270993f27766SDomagoj Stolfa 	dtrace_actkind_t act;
271093f27766SDomagoj Stolfa 	caddr_t addr;
271193f27766SDomagoj Stolfa 	size_t size;
271293f27766SDomagoj Stolfa 
271393f27766SDomagoj Stolfa 	if (pd->dtpa_aggname == NULL)
271493f27766SDomagoj Stolfa 		pd->dtpa_aggname = agg->dtagd_name;
271593f27766SDomagoj Stolfa 
271693f27766SDomagoj Stolfa 	xo_open_instance("aggregation-data");
271793f27766SDomagoj Stolfa 	strcpy(pd->dtpa_keyname, "value");
271893f27766SDomagoj Stolfa 	xo_open_list("keys");
271993f27766SDomagoj Stolfa 
272093f27766SDomagoj Stolfa 	/*
272193f27766SDomagoj Stolfa 	 * Iterate over each record description in the key, printing the traced
272293f27766SDomagoj Stolfa 	 * data, skipping the first datum (the tuple member created by the
272393f27766SDomagoj Stolfa 	 * compiler).
272493f27766SDomagoj Stolfa 	 */
272593f27766SDomagoj Stolfa 	for (i = 1; i < agg->dtagd_nrecs; i++) {
272693f27766SDomagoj Stolfa 		rec = &agg->dtagd_rec[i];
272793f27766SDomagoj Stolfa 		act = rec->dtrd_action;
272893f27766SDomagoj Stolfa 		addr = aggdata->dtada_data + rec->dtrd_offset;
272993f27766SDomagoj Stolfa 		size = rec->dtrd_size;
273093f27766SDomagoj Stolfa 
273193f27766SDomagoj Stolfa 		if (DTRACEACT_ISAGG(act)) {
273293f27766SDomagoj Stolfa 			aggact = i;
273393f27766SDomagoj Stolfa 			break;
273493f27766SDomagoj Stolfa 		}
273593f27766SDomagoj Stolfa 
273693f27766SDomagoj Stolfa 		xo_open_instance("keys");
273793f27766SDomagoj Stolfa 		if (dt_format_datum(dtp, rec, addr,
273893f27766SDomagoj Stolfa 		    size, aggdata, 1, pd) < 0) {
273993f27766SDomagoj Stolfa 			xo_close_instance("keys");
274093f27766SDomagoj Stolfa 			xo_close_instance("aggregation-data");
274193f27766SDomagoj Stolfa 			return (-1);
274293f27766SDomagoj Stolfa 		}
274393f27766SDomagoj Stolfa 		xo_close_instance("keys");
274493f27766SDomagoj Stolfa 
274593f27766SDomagoj Stolfa 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
274693f27766SDomagoj Stolfa 		    DTRACE_BUFDATA_AGGKEY) < 0) {
274793f27766SDomagoj Stolfa 			xo_close_instance("aggregation-data");
274893f27766SDomagoj Stolfa 			return (-1);
274993f27766SDomagoj Stolfa 		}
275093f27766SDomagoj Stolfa 	}
275193f27766SDomagoj Stolfa 	xo_close_list("keys");
275293f27766SDomagoj Stolfa 
275393f27766SDomagoj Stolfa 	assert(aggact != 0);
275493f27766SDomagoj Stolfa 
275593f27766SDomagoj Stolfa 	for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) {
275693f27766SDomagoj Stolfa 		uint64_t normal;
275793f27766SDomagoj Stolfa 
275893f27766SDomagoj Stolfa 		aggdata = aggsdata[i];
275993f27766SDomagoj Stolfa 		agg = aggdata->dtada_desc;
276093f27766SDomagoj Stolfa 		rec = &agg->dtagd_rec[aggact];
276193f27766SDomagoj Stolfa 		act = rec->dtrd_action;
276293f27766SDomagoj Stolfa 		addr = aggdata->dtada_data + rec->dtrd_offset;
276393f27766SDomagoj Stolfa 		size = rec->dtrd_size;
276493f27766SDomagoj Stolfa 
276593f27766SDomagoj Stolfa 		assert(DTRACEACT_ISAGG(act));
276693f27766SDomagoj Stolfa 
276793f27766SDomagoj Stolfa 		switch (act) {
276893f27766SDomagoj Stolfa 		case DTRACEAGG_MIN:
276993f27766SDomagoj Stolfa 			strcpy(pd->dtpa_keyname, "min");
277093f27766SDomagoj Stolfa 			break;
277193f27766SDomagoj Stolfa 		case DTRACEAGG_MAX:
277293f27766SDomagoj Stolfa 			strcpy(pd->dtpa_keyname, "max");
277393f27766SDomagoj Stolfa 			break;
277493f27766SDomagoj Stolfa 		case DTRACEAGG_COUNT:
277593f27766SDomagoj Stolfa 			strcpy(pd->dtpa_keyname, "count");
277693f27766SDomagoj Stolfa 			break;
277793f27766SDomagoj Stolfa 		case DTRACEAGG_SUM:
277893f27766SDomagoj Stolfa 			strcpy(pd->dtpa_keyname, "sum");
277993f27766SDomagoj Stolfa 			break;
278093f27766SDomagoj Stolfa 		default:
278193f27766SDomagoj Stolfa 			strcpy(pd->dtpa_keyname, "UNKNOWN");
278293f27766SDomagoj Stolfa 			break;
278393f27766SDomagoj Stolfa 		}
278493f27766SDomagoj Stolfa 
278593f27766SDomagoj Stolfa 		normal = aggdata->dtada_normal;
278693f27766SDomagoj Stolfa 
278793f27766SDomagoj Stolfa 		if (dt_format_datum(dtp, rec, addr, size,
278893f27766SDomagoj Stolfa 		    aggdata, normal, pd) < 0) {
278993f27766SDomagoj Stolfa 			xo_close_instance("aggregation-data");
279093f27766SDomagoj Stolfa 			return (-1);
279193f27766SDomagoj Stolfa 		}
279293f27766SDomagoj Stolfa 
279393f27766SDomagoj Stolfa 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
279493f27766SDomagoj Stolfa 		    DTRACE_BUFDATA_AGGVAL) < 0) {
279593f27766SDomagoj Stolfa 			xo_close_instance("aggregation-data");
279693f27766SDomagoj Stolfa 			return (-1);
279793f27766SDomagoj Stolfa 		}
279893f27766SDomagoj Stolfa 
279993f27766SDomagoj Stolfa 		if (!pd->dtpa_allunprint)
280093f27766SDomagoj Stolfa 			agg->dtagd_flags |= DTRACE_AGD_PRINTED;
280193f27766SDomagoj Stolfa 	}
280293f27766SDomagoj Stolfa 
280393f27766SDomagoj Stolfa 	if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
280493f27766SDomagoj Stolfa 	    DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0) {
280593f27766SDomagoj Stolfa 		xo_close_instance("aggregation-data");
280693f27766SDomagoj Stolfa 		return (-1);
280793f27766SDomagoj Stolfa 	}
280893f27766SDomagoj Stolfa 
280993f27766SDomagoj Stolfa 	xo_close_instance("aggregation-data");
281093f27766SDomagoj Stolfa 	return (0);
281193f27766SDomagoj Stolfa }
281293f27766SDomagoj Stolfa 
281393f27766SDomagoj Stolfa int
dt_print_aggs(const dtrace_aggdata_t ** aggsdata,int naggvars,void * arg)28146ff6d951SJohn Birrell dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
28156ff6d951SJohn Birrell {
28166ff6d951SJohn Birrell 	int i, aggact = 0;
28176ff6d951SJohn Birrell 	dt_print_aggdata_t *pd = arg;
28186ff6d951SJohn Birrell 	const dtrace_aggdata_t *aggdata = aggsdata[0];
28196ff6d951SJohn Birrell 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
28206ff6d951SJohn Birrell 	FILE *fp = pd->dtpa_fp;
28216ff6d951SJohn Birrell 	dtrace_hdl_t *dtp = pd->dtpa_dtp;
28226ff6d951SJohn Birrell 	dtrace_recdesc_t *rec;
28236ff6d951SJohn Birrell 	dtrace_actkind_t act;
28246ff6d951SJohn Birrell 	caddr_t addr;
28256ff6d951SJohn Birrell 	size_t size;
28266ff6d951SJohn Birrell 
2827a43f0be9SRui Paulo 	pd->dtpa_agghist = (aggdata->dtada_flags & DTRACE_A_TOTAL);
2828a43f0be9SRui Paulo 	pd->dtpa_aggpack = (aggdata->dtada_flags & DTRACE_A_MINMAXBIN);
2829a43f0be9SRui Paulo 
28306ff6d951SJohn Birrell 	/*
28316ff6d951SJohn Birrell 	 * Iterate over each record description in the key, printing the traced
28326ff6d951SJohn Birrell 	 * data, skipping the first datum (the tuple member created by the
28336ff6d951SJohn Birrell 	 * compiler).
28346ff6d951SJohn Birrell 	 */
28356ff6d951SJohn Birrell 	for (i = 1; i < agg->dtagd_nrecs; i++) {
28366ff6d951SJohn Birrell 		rec = &agg->dtagd_rec[i];
28376ff6d951SJohn Birrell 		act = rec->dtrd_action;
28386ff6d951SJohn Birrell 		addr = aggdata->dtada_data + rec->dtrd_offset;
28396ff6d951SJohn Birrell 		size = rec->dtrd_size;
28406ff6d951SJohn Birrell 
28416ff6d951SJohn Birrell 		if (DTRACEACT_ISAGG(act)) {
28426ff6d951SJohn Birrell 			aggact = i;
28436ff6d951SJohn Birrell 			break;
28446ff6d951SJohn Birrell 		}
28456ff6d951SJohn Birrell 
2846a43f0be9SRui Paulo 		if (dt_print_datum(dtp, fp, rec, addr,
2847a43f0be9SRui Paulo 		    size, aggdata, 1, pd) < 0)
28486ff6d951SJohn Birrell 			return (-1);
28496ff6d951SJohn Birrell 
28506ff6d951SJohn Birrell 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
28516ff6d951SJohn Birrell 		    DTRACE_BUFDATA_AGGKEY) < 0)
28526ff6d951SJohn Birrell 			return (-1);
28536ff6d951SJohn Birrell 	}
28546ff6d951SJohn Birrell 
28556ff6d951SJohn Birrell 	assert(aggact != 0);
28566ff6d951SJohn Birrell 
28576ff6d951SJohn Birrell 	for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) {
28586ff6d951SJohn Birrell 		uint64_t normal;
28596ff6d951SJohn Birrell 
28606ff6d951SJohn Birrell 		aggdata = aggsdata[i];
28616ff6d951SJohn Birrell 		agg = aggdata->dtada_desc;
28626ff6d951SJohn Birrell 		rec = &agg->dtagd_rec[aggact];
28636ff6d951SJohn Birrell 		act = rec->dtrd_action;
28646ff6d951SJohn Birrell 		addr = aggdata->dtada_data + rec->dtrd_offset;
28656ff6d951SJohn Birrell 		size = rec->dtrd_size;
28666ff6d951SJohn Birrell 
28676ff6d951SJohn Birrell 		assert(DTRACEACT_ISAGG(act));
28686ff6d951SJohn Birrell 		normal = aggdata->dtada_normal;
28696ff6d951SJohn Birrell 
2870a43f0be9SRui Paulo 		if (dt_print_datum(dtp, fp, rec, addr,
2871a43f0be9SRui Paulo 		    size, aggdata, normal, pd) < 0)
28726ff6d951SJohn Birrell 			return (-1);
28736ff6d951SJohn Birrell 
28746ff6d951SJohn Birrell 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
28756ff6d951SJohn Birrell 		    DTRACE_BUFDATA_AGGVAL) < 0)
28766ff6d951SJohn Birrell 			return (-1);
28776ff6d951SJohn Birrell 
28786ff6d951SJohn Birrell 		if (!pd->dtpa_allunprint)
28796ff6d951SJohn Birrell 			agg->dtagd_flags |= DTRACE_AGD_PRINTED;
28806ff6d951SJohn Birrell 	}
28816ff6d951SJohn Birrell 
2882a43f0be9SRui Paulo 	if (!pd->dtpa_agghist && !pd->dtpa_aggpack) {
28836ff6d951SJohn Birrell 		if (dt_printf(dtp, fp, "\n") < 0)
28846ff6d951SJohn Birrell 			return (-1);
2885a43f0be9SRui Paulo 	}
28866ff6d951SJohn Birrell 
28876ff6d951SJohn Birrell 	if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
28886ff6d951SJohn Birrell 	    DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0)
28896ff6d951SJohn Birrell 		return (-1);
28906ff6d951SJohn Birrell 
28916ff6d951SJohn Birrell 	return (0);
28926ff6d951SJohn Birrell }
28936ff6d951SJohn Birrell 
28946ff6d951SJohn Birrell int
dt_format_agg(const dtrace_aggdata_t * aggdata,void * arg)289593f27766SDomagoj Stolfa dt_format_agg(const dtrace_aggdata_t *aggdata, void *arg)
289693f27766SDomagoj Stolfa {
289793f27766SDomagoj Stolfa 	dt_print_aggdata_t *pd = arg;
289893f27766SDomagoj Stolfa 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
289993f27766SDomagoj Stolfa 	dtrace_aggvarid_t aggvarid = pd->dtpa_id;
290093f27766SDomagoj Stolfa 
290193f27766SDomagoj Stolfa 	if (pd->dtpa_allunprint) {
290293f27766SDomagoj Stolfa 		if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
290393f27766SDomagoj Stolfa 			return (0);
290493f27766SDomagoj Stolfa 	} else {
290593f27766SDomagoj Stolfa 		/*
290693f27766SDomagoj Stolfa 		 * If we're not printing all unprinted aggregations, then the
290793f27766SDomagoj Stolfa 		 * aggregation variable ID denotes a specific aggregation
290893f27766SDomagoj Stolfa 		 * variable that we should print -- skip any other aggregations
290993f27766SDomagoj Stolfa 		 * that we encounter.
291093f27766SDomagoj Stolfa 		 */
291193f27766SDomagoj Stolfa 		if (agg->dtagd_nrecs == 0)
291293f27766SDomagoj Stolfa 			return (0);
291393f27766SDomagoj Stolfa 
291493f27766SDomagoj Stolfa 		if (aggvarid != agg->dtagd_varid)
291593f27766SDomagoj Stolfa 			return (0);
291693f27766SDomagoj Stolfa 	}
291793f27766SDomagoj Stolfa 
291893f27766SDomagoj Stolfa 	return (dt_format_aggs(&aggdata, 1, arg));
291993f27766SDomagoj Stolfa }
292093f27766SDomagoj Stolfa 
292193f27766SDomagoj Stolfa int
dt_print_agg(const dtrace_aggdata_t * aggdata,void * arg)29226ff6d951SJohn Birrell dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg)
29236ff6d951SJohn Birrell {
29246ff6d951SJohn Birrell 	dt_print_aggdata_t *pd = arg;
29256ff6d951SJohn Birrell 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
29266ff6d951SJohn Birrell 	dtrace_aggvarid_t aggvarid = pd->dtpa_id;
29276ff6d951SJohn Birrell 
29286ff6d951SJohn Birrell 	if (pd->dtpa_allunprint) {
29296ff6d951SJohn Birrell 		if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
29306ff6d951SJohn Birrell 			return (0);
29316ff6d951SJohn Birrell 	} else {
29326ff6d951SJohn Birrell 		/*
29336ff6d951SJohn Birrell 		 * If we're not printing all unprinted aggregations, then the
29346ff6d951SJohn Birrell 		 * aggregation variable ID denotes a specific aggregation
29356ff6d951SJohn Birrell 		 * variable that we should print -- skip any other aggregations
29366ff6d951SJohn Birrell 		 * that we encounter.
29376ff6d951SJohn Birrell 		 */
29386ff6d951SJohn Birrell 		if (agg->dtagd_nrecs == 0)
29396ff6d951SJohn Birrell 			return (0);
29406ff6d951SJohn Birrell 
29416ff6d951SJohn Birrell 		if (aggvarid != agg->dtagd_varid)
29426ff6d951SJohn Birrell 			return (0);
29436ff6d951SJohn Birrell 	}
29446ff6d951SJohn Birrell 
29456ff6d951SJohn Birrell 	return (dt_print_aggs(&aggdata, 1, arg));
29466ff6d951SJohn Birrell }
29476ff6d951SJohn Birrell 
29486ff6d951SJohn Birrell int
dt_setopt(dtrace_hdl_t * dtp,const dtrace_probedata_t * data,const char * option,const char * value)29496ff6d951SJohn Birrell dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
29506ff6d951SJohn Birrell     const char *option, const char *value)
29516ff6d951SJohn Birrell {
29526ff6d951SJohn Birrell 	int len, rval;
29536ff6d951SJohn Birrell 	char *msg;
29546ff6d951SJohn Birrell 	const char *errstr;
29556ff6d951SJohn Birrell 	dtrace_setoptdata_t optdata;
29566ff6d951SJohn Birrell 
29576ff6d951SJohn Birrell 	bzero(&optdata, sizeof (optdata));
29586ff6d951SJohn Birrell 	(void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval);
29596ff6d951SJohn Birrell 
29606ff6d951SJohn Birrell 	if (dtrace_setopt(dtp, option, value) == 0) {
29616ff6d951SJohn Birrell 		(void) dtrace_getopt(dtp, option, &optdata.dtsda_newval);
29626ff6d951SJohn Birrell 		optdata.dtsda_probe = data;
29636ff6d951SJohn Birrell 		optdata.dtsda_option = option;
29646ff6d951SJohn Birrell 		optdata.dtsda_handle = dtp;
29656ff6d951SJohn Birrell 
29666ff6d951SJohn Birrell 		if ((rval = dt_handle_setopt(dtp, &optdata)) != 0)
29676ff6d951SJohn Birrell 			return (rval);
29686ff6d951SJohn Birrell 
29696ff6d951SJohn Birrell 		return (0);
29706ff6d951SJohn Birrell 	}
29716ff6d951SJohn Birrell 
29726ff6d951SJohn Birrell 	errstr = dtrace_errmsg(dtp, dtrace_errno(dtp));
29736ff6d951SJohn Birrell 	len = strlen(option) + strlen(value) + strlen(errstr) + 80;
29746ff6d951SJohn Birrell 	msg = alloca(len);
29756ff6d951SJohn Birrell 
29766ff6d951SJohn Birrell 	(void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n",
29776ff6d951SJohn Birrell 	    option, value, errstr);
29786ff6d951SJohn Birrell 
29796ff6d951SJohn Birrell 	if ((rval = dt_handle_liberr(dtp, data, msg)) == 0)
29806ff6d951SJohn Birrell 		return (0);
29816ff6d951SJohn Birrell 
29826ff6d951SJohn Birrell 	return (rval);
29836ff6d951SJohn Birrell }
29846ff6d951SJohn Birrell 
298593f27766SDomagoj Stolfa /*
298693f27766SDomagoj Stolfa  * Helper functions to help maintain style(9) in dt_consume_cpu().
298793f27766SDomagoj Stolfa  */
298893f27766SDomagoj Stolfa static int
dt_oformat_agg_sorted(dtrace_hdl_t * dtp,dtrace_aggregate_f * func,dt_print_aggdata_t * pd)298993f27766SDomagoj Stolfa dt_oformat_agg_sorted(dtrace_hdl_t *dtp, dtrace_aggregate_f *func,
299093f27766SDomagoj Stolfa     dt_print_aggdata_t *pd)
299193f27766SDomagoj Stolfa {
299293f27766SDomagoj Stolfa 	int r;
299393f27766SDomagoj Stolfa 
299493f27766SDomagoj Stolfa 	r = dtrace_aggregate_walk_sorted(dtp, dt_format_agg, pd);
299593f27766SDomagoj Stolfa 	if (r < 0) {
299693f27766SDomagoj Stolfa 		xo_close_list("aggregation-data");
299793f27766SDomagoj Stolfa 		xo_emit("{:aggregation-name/%s}", pd->dtpa_aggname);
299893f27766SDomagoj Stolfa 		xo_close_instance("output");
299993f27766SDomagoj Stolfa 	}
300093f27766SDomagoj Stolfa 
300193f27766SDomagoj Stolfa 	return (r);
300293f27766SDomagoj Stolfa }
300393f27766SDomagoj Stolfa 
300493f27766SDomagoj Stolfa static void
dt_oformat_agg_name(dt_print_aggdata_t * pd)300593f27766SDomagoj Stolfa dt_oformat_agg_name(dt_print_aggdata_t *pd)
300693f27766SDomagoj Stolfa {
300793f27766SDomagoj Stolfa 
300893f27766SDomagoj Stolfa 	xo_close_list("aggregation-data");
300993f27766SDomagoj Stolfa 	xo_emit("{:aggregation-name/%s}", pd->dtpa_aggname);
301093f27766SDomagoj Stolfa }
301193f27766SDomagoj Stolfa 
30126ff6d951SJohn Birrell static int
dt_consume_cpu(dtrace_hdl_t * dtp,FILE * fp,int cpu,dtrace_bufdesc_t * buf,boolean_t just_one,dtrace_consume_probe_f * efunc,dtrace_consume_rec_f * rfunc,void * arg)301309e6105fSMark Johnston dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu,
301409e6105fSMark Johnston     dtrace_bufdesc_t *buf, boolean_t just_one,
30156ff6d951SJohn Birrell     dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
30166ff6d951SJohn Birrell {
30176ff6d951SJohn Birrell 	dtrace_epid_t id;
301809e6105fSMark Johnston 	size_t offs;
30196ff6d951SJohn Birrell 	int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
30206ff6d951SJohn Birrell 	int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
30216ff6d951SJohn Birrell 	int rval, i, n;
3022f2e66d30SPedro F. Giffuni 	uint64_t tracememsize = 0;
30236ff6d951SJohn Birrell 	dtrace_probedata_t data;
30246ff6d951SJohn Birrell 	uint64_t drops;
302593f27766SDomagoj Stolfa 	size_t skip_format;
30266ff6d951SJohn Birrell 
30276ff6d951SJohn Birrell 	bzero(&data, sizeof (data));
30286ff6d951SJohn Birrell 	data.dtpda_handle = dtp;
30296ff6d951SJohn Birrell 	data.dtpda_cpu = cpu;
3030a98ff317SPedro F. Giffuni 	data.dtpda_flow = dtp->dt_flow;
3031a98ff317SPedro F. Giffuni 	data.dtpda_indent = dtp->dt_indent;
3032a98ff317SPedro F. Giffuni 	data.dtpda_prefix = dtp->dt_prefix;
30336ff6d951SJohn Birrell 
303409e6105fSMark Johnston 	for (offs = buf->dtbd_oldest; offs < buf->dtbd_size; ) {
30356ff6d951SJohn Birrell 		dtrace_eprobedesc_t *epd;
30366ff6d951SJohn Birrell 
30376ff6d951SJohn Birrell 		/*
30386ff6d951SJohn Birrell 		 * We're guaranteed to have an ID.
30396ff6d951SJohn Birrell 		 */
30406ff6d951SJohn Birrell 		id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
30416ff6d951SJohn Birrell 
30426ff6d951SJohn Birrell 		if (id == DTRACE_EPIDNONE) {
30436ff6d951SJohn Birrell 			/*
30446ff6d951SJohn Birrell 			 * This is filler to assure proper alignment of the
30456ff6d951SJohn Birrell 			 * next record; we simply ignore it.
30466ff6d951SJohn Birrell 			 */
30476ff6d951SJohn Birrell 			offs += sizeof (id);
30486ff6d951SJohn Birrell 			continue;
30496ff6d951SJohn Birrell 		}
30506ff6d951SJohn Birrell 
30516ff6d951SJohn Birrell 		if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc,
30526ff6d951SJohn Birrell 		    &data.dtpda_pdesc)) != 0)
30536ff6d951SJohn Birrell 			return (rval);
30546ff6d951SJohn Birrell 
30556ff6d951SJohn Birrell 		epd = data.dtpda_edesc;
30566ff6d951SJohn Birrell 		data.dtpda_data = buf->dtbd_data + offs;
305793f27766SDomagoj Stolfa 		data.dtpda_timestamp = DTRACE_RECORD_LOAD_TIMESTAMP(
305893f27766SDomagoj Stolfa 		    (struct dtrace_rechdr *)data.dtpda_data);
30596ff6d951SJohn Birrell 
30606ff6d951SJohn Birrell 		if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) {
30616ff6d951SJohn Birrell 			rval = dt_handle(dtp, &data);
30626ff6d951SJohn Birrell 
30636ff6d951SJohn Birrell 			if (rval == DTRACE_CONSUME_NEXT)
30646ff6d951SJohn Birrell 				goto nextepid;
30656ff6d951SJohn Birrell 
30666ff6d951SJohn Birrell 			if (rval == DTRACE_CONSUME_ERROR)
30676ff6d951SJohn Birrell 				return (-1);
30686ff6d951SJohn Birrell 		}
30696ff6d951SJohn Birrell 
30706ff6d951SJohn Birrell 		if (flow)
307109e6105fSMark Johnston 			(void) dt_flowindent(dtp, &data, dtp->dt_last_epid,
307209e6105fSMark Johnston 			    buf, offs);
30736ff6d951SJohn Birrell 
307493f27766SDomagoj Stolfa 		if (dtp->dt_oformat)
307593f27766SDomagoj Stolfa 			xo_open_instance("probes");
30766ff6d951SJohn Birrell 		rval = (*efunc)(&data, arg);
30776ff6d951SJohn Birrell 
30786ff6d951SJohn Birrell 		if (flow) {
30796ff6d951SJohn Birrell 			if (data.dtpda_flow == DTRACEFLOW_ENTRY)
30806ff6d951SJohn Birrell 				data.dtpda_indent += 2;
30816ff6d951SJohn Birrell 		}
30826ff6d951SJohn Birrell 
30836ff6d951SJohn Birrell 		if (rval == DTRACE_CONSUME_NEXT)
30846ff6d951SJohn Birrell 			goto nextepid;
30856ff6d951SJohn Birrell 
30866ff6d951SJohn Birrell 		if (rval == DTRACE_CONSUME_ABORT)
30876ff6d951SJohn Birrell 			return (dt_set_errno(dtp, EDT_DIRABORT));
30886ff6d951SJohn Birrell 
30896ff6d951SJohn Birrell 		if (rval != DTRACE_CONSUME_THIS)
30906ff6d951SJohn Birrell 			return (dt_set_errno(dtp, EDT_BADRVAL));
30916ff6d951SJohn Birrell 
309293f27766SDomagoj Stolfa 		skip_format = 0;
309393f27766SDomagoj Stolfa 		if (dtp->dt_oformat)
309493f27766SDomagoj Stolfa 			xo_open_list("output");
30956ff6d951SJohn Birrell 		for (i = 0; i < epd->dtepd_nrecs; i++) {
309609e6105fSMark Johnston 			caddr_t addr;
30976ff6d951SJohn Birrell 			dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
30986ff6d951SJohn Birrell 			dtrace_actkind_t act = rec->dtrd_action;
30996ff6d951SJohn Birrell 
310093f27766SDomagoj Stolfa 			if (skip_format > 0)
310193f27766SDomagoj Stolfa 				skip_format--;
310293f27766SDomagoj Stolfa 
31036ff6d951SJohn Birrell 			data.dtpda_data = buf->dtbd_data + offs +
31046ff6d951SJohn Birrell 			    rec->dtrd_offset;
31056ff6d951SJohn Birrell 			addr = data.dtpda_data;
31066ff6d951SJohn Birrell 
31076ff6d951SJohn Birrell 			if (act == DTRACEACT_LIBACT) {
31086ff6d951SJohn Birrell 				uint64_t arg = rec->dtrd_arg;
31096ff6d951SJohn Birrell 				dtrace_aggvarid_t id;
31106ff6d951SJohn Birrell 
31116ff6d951SJohn Birrell 				switch (arg) {
31126ff6d951SJohn Birrell 				case DT_ACT_CLEAR:
31136ff6d951SJohn Birrell 					/* LINTED - alignment */
31146ff6d951SJohn Birrell 					id = *((dtrace_aggvarid_t *)addr);
31156ff6d951SJohn Birrell 					(void) dtrace_aggregate_walk(dtp,
31166ff6d951SJohn Birrell 					    dt_clear_agg, &id);
31176ff6d951SJohn Birrell 					continue;
31186ff6d951SJohn Birrell 
31196ff6d951SJohn Birrell 				case DT_ACT_DENORMALIZE:
31206ff6d951SJohn Birrell 					/* LINTED - alignment */
31216ff6d951SJohn Birrell 					id = *((dtrace_aggvarid_t *)addr);
31226ff6d951SJohn Birrell 					(void) dtrace_aggregate_walk(dtp,
31236ff6d951SJohn Birrell 					    dt_denormalize_agg, &id);
31246ff6d951SJohn Birrell 					continue;
31256ff6d951SJohn Birrell 
31266ff6d951SJohn Birrell 				case DT_ACT_FTRUNCATE:
31276ff6d951SJohn Birrell 					if (fp == NULL)
31286ff6d951SJohn Birrell 						continue;
31296ff6d951SJohn Birrell 
31306ff6d951SJohn Birrell 					(void) fflush(fp);
31316ff6d951SJohn Birrell 					(void) ftruncate(fileno(fp), 0);
31326ff6d951SJohn Birrell 					(void) fseeko(fp, 0, SEEK_SET);
31336ff6d951SJohn Birrell 					continue;
31346ff6d951SJohn Birrell 
31356ff6d951SJohn Birrell 				case DT_ACT_NORMALIZE:
31366ff6d951SJohn Birrell 					if (i == epd->dtepd_nrecs - 1)
31376ff6d951SJohn Birrell 						return (dt_set_errno(dtp,
31386ff6d951SJohn Birrell 						    EDT_BADNORMAL));
31396ff6d951SJohn Birrell 
31406ff6d951SJohn Birrell 					if (dt_normalize(dtp,
31416ff6d951SJohn Birrell 					    buf->dtbd_data + offs, rec) != 0)
31426ff6d951SJohn Birrell 						return (-1);
31436ff6d951SJohn Birrell 
31446ff6d951SJohn Birrell 					i++;
31456ff6d951SJohn Birrell 					continue;
31466ff6d951SJohn Birrell 
31476ff6d951SJohn Birrell 				case DT_ACT_SETOPT: {
31486ff6d951SJohn Birrell 					uint64_t *opts = dtp->dt_options;
31496ff6d951SJohn Birrell 					dtrace_recdesc_t *valrec;
31506ff6d951SJohn Birrell 					uint32_t valsize;
31516ff6d951SJohn Birrell 					caddr_t val;
31526ff6d951SJohn Birrell 					int rv;
31536ff6d951SJohn Birrell 
31546ff6d951SJohn Birrell 					if (i == epd->dtepd_nrecs - 1) {
31556ff6d951SJohn Birrell 						return (dt_set_errno(dtp,
31566ff6d951SJohn Birrell 						    EDT_BADSETOPT));
31576ff6d951SJohn Birrell 					}
31586ff6d951SJohn Birrell 
31596ff6d951SJohn Birrell 					valrec = &epd->dtepd_rec[++i];
31606ff6d951SJohn Birrell 					valsize = valrec->dtrd_size;
31616ff6d951SJohn Birrell 
31626ff6d951SJohn Birrell 					if (valrec->dtrd_action != act ||
31636ff6d951SJohn Birrell 					    valrec->dtrd_arg != arg) {
31646ff6d951SJohn Birrell 						return (dt_set_errno(dtp,
31656ff6d951SJohn Birrell 						    EDT_BADSETOPT));
31666ff6d951SJohn Birrell 					}
31676ff6d951SJohn Birrell 
31686ff6d951SJohn Birrell 					if (valsize > sizeof (uint64_t)) {
31696ff6d951SJohn Birrell 						val = buf->dtbd_data + offs +
31706ff6d951SJohn Birrell 						    valrec->dtrd_offset;
31716ff6d951SJohn Birrell 					} else {
31726ff6d951SJohn Birrell 						val = "1";
31736ff6d951SJohn Birrell 					}
31746ff6d951SJohn Birrell 
31756ff6d951SJohn Birrell 					rv = dt_setopt(dtp, &data, addr, val);
31766ff6d951SJohn Birrell 
31776ff6d951SJohn Birrell 					if (rv != 0)
31786ff6d951SJohn Birrell 						return (-1);
31796ff6d951SJohn Birrell 
31806ff6d951SJohn Birrell 					flow = (opts[DTRACEOPT_FLOWINDENT] !=
31816ff6d951SJohn Birrell 					    DTRACEOPT_UNSET);
31826ff6d951SJohn Birrell 					quiet = (opts[DTRACEOPT_QUIET] !=
31836ff6d951SJohn Birrell 					    DTRACEOPT_UNSET);
31846ff6d951SJohn Birrell 
31856ff6d951SJohn Birrell 					continue;
31866ff6d951SJohn Birrell 				}
31876ff6d951SJohn Birrell 
31886ff6d951SJohn Birrell 				case DT_ACT_TRUNC:
31896ff6d951SJohn Birrell 					if (i == epd->dtepd_nrecs - 1)
31906ff6d951SJohn Birrell 						return (dt_set_errno(dtp,
31916ff6d951SJohn Birrell 						    EDT_BADTRUNC));
31926ff6d951SJohn Birrell 
31936ff6d951SJohn Birrell 					if (dt_trunc(dtp,
31946ff6d951SJohn Birrell 					    buf->dtbd_data + offs, rec) != 0)
31956ff6d951SJohn Birrell 						return (-1);
31966ff6d951SJohn Birrell 
31976ff6d951SJohn Birrell 					i++;
31986ff6d951SJohn Birrell 					continue;
31996ff6d951SJohn Birrell 
32006ff6d951SJohn Birrell 				default:
32016ff6d951SJohn Birrell 					continue;
32026ff6d951SJohn Birrell 				}
32036ff6d951SJohn Birrell 			}
32046ff6d951SJohn Birrell 
3205f2e66d30SPedro F. Giffuni 			if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
3206f2e66d30SPedro F. Giffuni 			    rec->dtrd_size == sizeof (uint64_t)) {
320754727873SPedro F. Giffuni 			    	/* LINTED - alignment */
3208f2e66d30SPedro F. Giffuni 				tracememsize = *((unsigned long long *)addr);
3209f2e66d30SPedro F. Giffuni 				continue;
3210f2e66d30SPedro F. Giffuni 			}
3211f2e66d30SPedro F. Giffuni 
32126ff6d951SJohn Birrell 			rval = (*rfunc)(&data, rec, arg);
32136ff6d951SJohn Birrell 
32146ff6d951SJohn Birrell 			if (rval == DTRACE_CONSUME_NEXT)
32156ff6d951SJohn Birrell 				continue;
32166ff6d951SJohn Birrell 
32176ff6d951SJohn Birrell 			if (rval == DTRACE_CONSUME_ABORT)
32186ff6d951SJohn Birrell 				return (dt_set_errno(dtp, EDT_DIRABORT));
32196ff6d951SJohn Birrell 
32206ff6d951SJohn Birrell 			if (rval != DTRACE_CONSUME_THIS)
32216ff6d951SJohn Birrell 				return (dt_set_errno(dtp, EDT_BADRVAL));
32226ff6d951SJohn Birrell 
322393f27766SDomagoj Stolfa 			if (dtp->dt_oformat && rec->dtrd_size > 0)
322493f27766SDomagoj Stolfa 				xo_open_instance("output");
32256ff6d951SJohn Birrell 			if (act == DTRACEACT_STACK) {
32266ff6d951SJohn Birrell 				int depth = rec->dtrd_arg;
32276ff6d951SJohn Birrell 
322893f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
322993f27766SDomagoj Stolfa 					if (dt_format_stack(dtp, addr, depth,
323093f27766SDomagoj Stolfa 					    rec->dtrd_size / depth) < 0) {
323193f27766SDomagoj Stolfa 						xo_close_instance("output");
323293f27766SDomagoj Stolfa 						return (-1);
323393f27766SDomagoj Stolfa 					}
323493f27766SDomagoj Stolfa 				} else {
323593f27766SDomagoj Stolfa 					if (dt_print_stack(dtp,
323693f27766SDomagoj Stolfa 					    fp, NULL, addr, depth,
32376ff6d951SJohn Birrell 					    rec->dtrd_size / depth) < 0)
32386ff6d951SJohn Birrell 					return (-1);
323993f27766SDomagoj Stolfa 				}
32406ff6d951SJohn Birrell 				goto nextrec;
32416ff6d951SJohn Birrell 			}
32426ff6d951SJohn Birrell 
32436ff6d951SJohn Birrell 			if (act == DTRACEACT_USTACK ||
32446ff6d951SJohn Birrell 			    act == DTRACEACT_JSTACK) {
324593f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
324693f27766SDomagoj Stolfa 					if (dt_format_ustack(dtp, addr,
324793f27766SDomagoj Stolfa 					    rec->dtrd_arg) < 0) {
324893f27766SDomagoj Stolfa 						xo_close_instance("output");
324993f27766SDomagoj Stolfa 						return (-1);
325093f27766SDomagoj Stolfa 					}
325193f27766SDomagoj Stolfa 				} else {
32526ff6d951SJohn Birrell 					if (dt_print_ustack(dtp, fp, NULL,
32536ff6d951SJohn Birrell 					    addr, rec->dtrd_arg) < 0)
32546ff6d951SJohn Birrell 						return (-1);
325593f27766SDomagoj Stolfa 				}
32566ff6d951SJohn Birrell 				goto nextrec;
32576ff6d951SJohn Birrell 			}
32586ff6d951SJohn Birrell 
32596ff6d951SJohn Birrell 			if (act == DTRACEACT_SYM) {
326093f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
326193f27766SDomagoj Stolfa 					if (dt_format_sym(dtp, addr) < 0) {
326293f27766SDomagoj Stolfa 						xo_close_instance("output");
326393f27766SDomagoj Stolfa 						return (-1);
326493f27766SDomagoj Stolfa 					}
326593f27766SDomagoj Stolfa 				} else {
32666ff6d951SJohn Birrell 					if (dt_print_sym(dtp, fp, NULL, addr) < 0)
32676ff6d951SJohn Birrell 						return (-1);
326893f27766SDomagoj Stolfa 				}
32696ff6d951SJohn Birrell 				goto nextrec;
32706ff6d951SJohn Birrell 			}
32716ff6d951SJohn Birrell 
32726ff6d951SJohn Birrell 			if (act == DTRACEACT_MOD) {
327393f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
327493f27766SDomagoj Stolfa 					if (dt_format_mod(dtp, addr) < 0) {
327593f27766SDomagoj Stolfa 						xo_close_instance("output");
327693f27766SDomagoj Stolfa 						return (-1);
327793f27766SDomagoj Stolfa 					}
327893f27766SDomagoj Stolfa 				} else {
32796ff6d951SJohn Birrell 					if (dt_print_mod(dtp, fp, NULL, addr) < 0)
32806ff6d951SJohn Birrell 						return (-1);
328193f27766SDomagoj Stolfa 				}
32826ff6d951SJohn Birrell 				goto nextrec;
32836ff6d951SJohn Birrell 			}
32846ff6d951SJohn Birrell 
32856ff6d951SJohn Birrell 			if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
328693f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
328793f27766SDomagoj Stolfa 					if (dt_format_usym(dtp, addr, act) < 0) {
328893f27766SDomagoj Stolfa 						xo_close_instance("output");
328993f27766SDomagoj Stolfa 						return (-1);
329093f27766SDomagoj Stolfa 					}
329193f27766SDomagoj Stolfa 				} else {
32926ff6d951SJohn Birrell 					if (dt_print_usym(dtp, fp, addr, act) < 0)
32936ff6d951SJohn Birrell 						return (-1);
329493f27766SDomagoj Stolfa 				}
32956ff6d951SJohn Birrell 				goto nextrec;
32966ff6d951SJohn Birrell 			}
32976ff6d951SJohn Birrell 
32986ff6d951SJohn Birrell 			if (act == DTRACEACT_UMOD) {
329993f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
330093f27766SDomagoj Stolfa 					if (dt_format_umod(dtp, addr) < 0) {
330193f27766SDomagoj Stolfa 						xo_close_instance("output");
330293f27766SDomagoj Stolfa 						return (-1);
330393f27766SDomagoj Stolfa 					}
330493f27766SDomagoj Stolfa 				} else {
33056ff6d951SJohn Birrell 					if (dt_print_umod(dtp, fp, NULL, addr) < 0)
33066ff6d951SJohn Birrell 						return (-1);
330793f27766SDomagoj Stolfa 				}
33086ff6d951SJohn Birrell 				goto nextrec;
33096ff6d951SJohn Birrell 			}
33106ff6d951SJohn Birrell 
331118737969SJohn Birrell 			if (act == DTRACEACT_PRINTM) {
331293f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
331393f27766SDomagoj Stolfa 					if (dt_format_memory(dtp, addr) < 0) {
331493f27766SDomagoj Stolfa 						xo_close_instance("output");
331593f27766SDomagoj Stolfa 						return (-1);
331693f27766SDomagoj Stolfa 					}
331793f27766SDomagoj Stolfa 				} else {
331818737969SJohn Birrell 					if (dt_print_memory(dtp, fp, addr) < 0)
331918737969SJohn Birrell 						return (-1);
332093f27766SDomagoj Stolfa 				}
332118737969SJohn Birrell 				goto nextrec;
332218737969SJohn Birrell 			}
332318737969SJohn Birrell 
332493f27766SDomagoj Stolfa 			if (dtp->dt_oformat == DTRACE_OFORMAT_TEXT &&
332593f27766SDomagoj Stolfa 			    DTRACEACT_ISPRINTFLIKE(act)) {
33266ff6d951SJohn Birrell 				void *fmtdata;
33276ff6d951SJohn Birrell 				int (*func)(dtrace_hdl_t *, FILE *, void *,
33286ff6d951SJohn Birrell 				    const dtrace_probedata_t *,
33296ff6d951SJohn Birrell 				    const dtrace_recdesc_t *, uint_t,
33306ff6d951SJohn Birrell 				    const void *buf, size_t);
33316ff6d951SJohn Birrell 
33326ff6d951SJohn Birrell 				if ((fmtdata = dt_format_lookup(dtp,
33336ff6d951SJohn Birrell 				    rec->dtrd_format)) == NULL)
33346ff6d951SJohn Birrell 					goto nofmt;
33356ff6d951SJohn Birrell 
33366ff6d951SJohn Birrell 				switch (act) {
33376ff6d951SJohn Birrell 				case DTRACEACT_PRINTF:
33386ff6d951SJohn Birrell 					func = dtrace_fprintf;
33396ff6d951SJohn Birrell 					break;
33406ff6d951SJohn Birrell 				case DTRACEACT_PRINTA:
33416ff6d951SJohn Birrell 					func = dtrace_fprinta;
33426ff6d951SJohn Birrell 					break;
33436ff6d951SJohn Birrell 				case DTRACEACT_SYSTEM:
33446ff6d951SJohn Birrell 					func = dtrace_system;
33456ff6d951SJohn Birrell 					break;
33466ff6d951SJohn Birrell 				case DTRACEACT_FREOPEN:
33476ff6d951SJohn Birrell 					func = dtrace_freopen;
33486ff6d951SJohn Birrell 					break;
33496ff6d951SJohn Birrell 				}
33506ff6d951SJohn Birrell 
33516ff6d951SJohn Birrell 				n = (*func)(dtp, fp, fmtdata, &data,
33526ff6d951SJohn Birrell 				    rec, epd->dtepd_nrecs - i,
33536ff6d951SJohn Birrell 				    (uchar_t *)buf->dtbd_data + offs,
33546ff6d951SJohn Birrell 				    buf->dtbd_size - offs);
33556ff6d951SJohn Birrell 
33566ff6d951SJohn Birrell 				if (n < 0)
33576ff6d951SJohn Birrell 					return (-1); /* errno is set for us */
33586ff6d951SJohn Birrell 
33596ff6d951SJohn Birrell 				if (n > 0)
33606ff6d951SJohn Birrell 					i += n - 1;
33616ff6d951SJohn Birrell 				goto nextrec;
33626ff6d951SJohn Birrell 			}
33636ff6d951SJohn Birrell 
336454727873SPedro F. Giffuni 			/*
336593f27766SDomagoj Stolfa 			 * We don't care about a formatted printa, system or
336693f27766SDomagoj Stolfa 			 * freopen for oformat.
336793f27766SDomagoj Stolfa 			 */
336893f27766SDomagoj Stolfa 			if (dtp->dt_oformat && act == DTRACEACT_PRINTF &&
336993f27766SDomagoj Stolfa 			    skip_format == 0) {
337093f27766SDomagoj Stolfa 				void *fmtdata;
337193f27766SDomagoj Stolfa 				if ((fmtdata = dt_format_lookup(dtp,
337293f27766SDomagoj Stolfa 				    rec->dtrd_format)) == NULL)
337393f27766SDomagoj Stolfa 					goto nofmt;
337493f27766SDomagoj Stolfa 
337593f27766SDomagoj Stolfa 				n = dtrace_sprintf(dtp, fp, fmtdata, rec,
337693f27766SDomagoj Stolfa 				    epd->dtepd_nrecs - i,
337793f27766SDomagoj Stolfa 				    (uchar_t *)buf->dtbd_data + offs,
337893f27766SDomagoj Stolfa 				    buf->dtbd_size - offs);
337993f27766SDomagoj Stolfa 
338093f27766SDomagoj Stolfa 				if (n < 0) {
338193f27766SDomagoj Stolfa 					xo_close_instance("output");
338293f27766SDomagoj Stolfa 					return (-1); /* errno is set for us */
338393f27766SDomagoj Stolfa 				}
338493f27766SDomagoj Stolfa 
338593f27766SDomagoj Stolfa 				xo_emit("{:message/%s}", dtp->dt_sprintf_buf);
338693f27766SDomagoj Stolfa 				skip_format += n;
338793f27766SDomagoj Stolfa 
338893f27766SDomagoj Stolfa 				/*
338993f27766SDomagoj Stolfa 				 * We want the "message" object to be its own
339093f27766SDomagoj Stolfa 				 * thing, but we still want to process the
339193f27766SDomagoj Stolfa 				 * current DIFEXPR in case there is a value
339293f27766SDomagoj Stolfa 				 * attached to it. If there is, we need to
339393f27766SDomagoj Stolfa 				 * re-open a new output instance, as otherwise
339493f27766SDomagoj Stolfa 				 * the message ends up bundled with the first
339593f27766SDomagoj Stolfa 				 * value.
339693f27766SDomagoj Stolfa 				 *
339793f27766SDomagoj Stolfa 				 * XXX: There is an edge case where a
339893f27766SDomagoj Stolfa 				 * printf("hello"); will produce a DIFO that
339993f27766SDomagoj Stolfa 				 * returns 0 attached to it and we have no good
340093f27766SDomagoj Stolfa 				 * way to determine if this 0 value is because
340193f27766SDomagoj Stolfa 				 * there's no real data attached to the printf
340293f27766SDomagoj Stolfa 				 * as an argument, or it's because the argument
340393f27766SDomagoj Stolfa 				 * actually returns 0.
340493f27766SDomagoj Stolfa 				 */
340593f27766SDomagoj Stolfa 				if (skip_format == 0)
340693f27766SDomagoj Stolfa 					goto nextrec;
340793f27766SDomagoj Stolfa 
340893f27766SDomagoj Stolfa 				xo_close_instance("output");
340993f27766SDomagoj Stolfa 				xo_open_instance("output");
341093f27766SDomagoj Stolfa 			}
341193f27766SDomagoj Stolfa 
341293f27766SDomagoj Stolfa 			/*
341354727873SPedro F. Giffuni 			 * If this is a DIF expression, and the record has a
341454727873SPedro F. Giffuni 			 * format set, this indicates we have a CTF type name
341554727873SPedro F. Giffuni 			 * associated with the data and we should try to print
341654727873SPedro F. Giffuni 			 * it out by type.
341754727873SPedro F. Giffuni 			 */
341854727873SPedro F. Giffuni 			if (act == DTRACEACT_DIFEXPR) {
341954727873SPedro F. Giffuni 				const char *strdata = dt_strdata_lookup(dtp,
342054727873SPedro F. Giffuni 				    rec->dtrd_format);
342154727873SPedro F. Giffuni 				if (strdata != NULL) {
342293f27766SDomagoj Stolfa 					if (dtp->dt_oformat)
342393f27766SDomagoj Stolfa 						n = dtrace_format_print(dtp, fp,
342493f27766SDomagoj Stolfa 						    strdata, addr,
342593f27766SDomagoj Stolfa 						    rec->dtrd_size);
342693f27766SDomagoj Stolfa 					else
342793f27766SDomagoj Stolfa 						n = dtrace_print(dtp, fp,
342893f27766SDomagoj Stolfa 						    strdata, addr,
342993f27766SDomagoj Stolfa 						    rec->dtrd_size);
343054727873SPedro F. Giffuni 
343154727873SPedro F. Giffuni 					/*
343254727873SPedro F. Giffuni 					 * dtrace_print() will return -1 on
343354727873SPedro F. Giffuni 					 * error, or return the number of bytes
343454727873SPedro F. Giffuni 					 * consumed.  It will return 0 if the
343554727873SPedro F. Giffuni 					 * type couldn't be determined, and we
343654727873SPedro F. Giffuni 					 * should fall through to the normal
343754727873SPedro F. Giffuni 					 * trace method.
343854727873SPedro F. Giffuni 					 */
343993f27766SDomagoj Stolfa 					if (n < 0) {
344093f27766SDomagoj Stolfa 						if (dtp->dt_oformat)
344193f27766SDomagoj Stolfa 							xo_close_instance(
344293f27766SDomagoj Stolfa 							    "output");
344354727873SPedro F. Giffuni 						return (-1);
344493f27766SDomagoj Stolfa 					}
344554727873SPedro F. Giffuni 
344654727873SPedro F. Giffuni 					if (n > 0)
344754727873SPedro F. Giffuni 						goto nextrec;
344854727873SPedro F. Giffuni 				}
344954727873SPedro F. Giffuni 			}
345054727873SPedro F. Giffuni 
34516ff6d951SJohn Birrell nofmt:
34526ff6d951SJohn Birrell 			if (act == DTRACEACT_PRINTA) {
34536ff6d951SJohn Birrell 				dt_print_aggdata_t pd;
34546ff6d951SJohn Birrell 				dtrace_aggvarid_t *aggvars;
34556ff6d951SJohn Birrell 				int j, naggvars = 0;
34566ff6d951SJohn Birrell 				size_t size = ((epd->dtepd_nrecs - i) *
34576ff6d951SJohn Birrell 				    sizeof (dtrace_aggvarid_t));
34586ff6d951SJohn Birrell 
345993f27766SDomagoj Stolfa 				if ((aggvars = dt_alloc(dtp, size)) == NULL) {
346093f27766SDomagoj Stolfa 					if (dtp->dt_oformat)
346193f27766SDomagoj Stolfa 						xo_close_instance("output");
34626ff6d951SJohn Birrell 					return (-1);
346393f27766SDomagoj Stolfa 				}
34646ff6d951SJohn Birrell 
34656ff6d951SJohn Birrell 				/*
34666ff6d951SJohn Birrell 				 * This might be a printa() with multiple
34676ff6d951SJohn Birrell 				 * aggregation variables.  We need to scan
34686ff6d951SJohn Birrell 				 * forward through the records until we find
34696ff6d951SJohn Birrell 				 * a record from a different statement.
34706ff6d951SJohn Birrell 				 */
34716ff6d951SJohn Birrell 				for (j = i; j < epd->dtepd_nrecs; j++) {
34726ff6d951SJohn Birrell 					dtrace_recdesc_t *nrec;
34736ff6d951SJohn Birrell 					caddr_t naddr;
34746ff6d951SJohn Birrell 
34756ff6d951SJohn Birrell 					nrec = &epd->dtepd_rec[j];
34766ff6d951SJohn Birrell 
34776ff6d951SJohn Birrell 					if (nrec->dtrd_uarg != rec->dtrd_uarg)
34786ff6d951SJohn Birrell 						break;
34796ff6d951SJohn Birrell 
34806ff6d951SJohn Birrell 					if (nrec->dtrd_action != act) {
348193f27766SDomagoj Stolfa 						if (dtp->dt_oformat)
348293f27766SDomagoj Stolfa 							xo_close_instance(
348393f27766SDomagoj Stolfa 							    "output");
34846ff6d951SJohn Birrell 						return (dt_set_errno(dtp,
34856ff6d951SJohn Birrell 						    EDT_BADAGG));
34866ff6d951SJohn Birrell 					}
34876ff6d951SJohn Birrell 
34886ff6d951SJohn Birrell 					naddr = buf->dtbd_data + offs +
34896ff6d951SJohn Birrell 					    nrec->dtrd_offset;
34906ff6d951SJohn Birrell 
34916ff6d951SJohn Birrell 					aggvars[naggvars++] =
34926ff6d951SJohn Birrell 					    /* LINTED - alignment */
34936ff6d951SJohn Birrell 					    *((dtrace_aggvarid_t *)naddr);
34946ff6d951SJohn Birrell 				}
34956ff6d951SJohn Birrell 
34966ff6d951SJohn Birrell 				i = j - 1;
34976ff6d951SJohn Birrell 				bzero(&pd, sizeof (pd));
34986ff6d951SJohn Birrell 				pd.dtpa_dtp = dtp;
34996ff6d951SJohn Birrell 				pd.dtpa_fp = fp;
35006ff6d951SJohn Birrell 
35016ff6d951SJohn Birrell 				assert(naggvars >= 1);
35026ff6d951SJohn Birrell 
350393f27766SDomagoj Stolfa 				if (dtp->dt_oformat)
350493f27766SDomagoj Stolfa 					xo_open_list("aggregation-data");
35056ff6d951SJohn Birrell 				if (naggvars == 1) {
35066ff6d951SJohn Birrell 					pd.dtpa_id = aggvars[0];
35076ff6d951SJohn Birrell 					dt_free(dtp, aggvars);
35086ff6d951SJohn Birrell 
350993f27766SDomagoj Stolfa 					if (dtp->dt_oformat) {
351093f27766SDomagoj Stolfa 						n = dt_oformat_agg_sorted(dtp,
351193f27766SDomagoj Stolfa 						    dt_format_agg, &pd);
351293f27766SDomagoj Stolfa 						if (n < 0)
351393f27766SDomagoj Stolfa 							return (-1);
351493f27766SDomagoj Stolfa 					} else {
35156ff6d951SJohn Birrell 						if (dt_printf(dtp, fp, "\n") < 0 ||
35166ff6d951SJohn Birrell 						    dtrace_aggregate_walk_sorted(dtp,
35176ff6d951SJohn Birrell 						    dt_print_agg, &pd) < 0)
35186ff6d951SJohn Birrell 							return (-1);
351993f27766SDomagoj Stolfa 					}
352093f27766SDomagoj Stolfa 
352193f27766SDomagoj Stolfa 					if (dtp->dt_oformat)
352293f27766SDomagoj Stolfa 						dt_oformat_agg_name(&pd);
35236ff6d951SJohn Birrell 					goto nextrec;
35246ff6d951SJohn Birrell 				}
35256ff6d951SJohn Birrell 
352693f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
352793f27766SDomagoj Stolfa 					if (dtrace_aggregate_walk_joined(dtp,
352893f27766SDomagoj Stolfa 					    aggvars, naggvars,
352993f27766SDomagoj Stolfa 					    dt_format_aggs, &pd) < 0) {
353093f27766SDomagoj Stolfa 						dt_oformat_agg_name(&pd);
353193f27766SDomagoj Stolfa 						xo_close_instance("output");
35326ff6d951SJohn Birrell 						dt_free(dtp, aggvars);
35336ff6d951SJohn Birrell 						return (-1);
35346ff6d951SJohn Birrell 					}
353593f27766SDomagoj Stolfa 				} else {
353693f27766SDomagoj Stolfa 					if (dt_printf(dtp, fp, "\n") < 0 ||
353793f27766SDomagoj Stolfa 					    dtrace_aggregate_walk_joined(dtp,
353893f27766SDomagoj Stolfa 					    aggvars, naggvars,
353993f27766SDomagoj Stolfa 					    dt_print_aggs, &pd) < 0) {
354093f27766SDomagoj Stolfa 						dt_free(dtp, aggvars);
354193f27766SDomagoj Stolfa 						return (-1);
354293f27766SDomagoj Stolfa 					}
354393f27766SDomagoj Stolfa 				}
35446ff6d951SJohn Birrell 
354593f27766SDomagoj Stolfa 				if (dtp->dt_oformat)
354693f27766SDomagoj Stolfa 					dt_oformat_agg_name(&pd);
35476ff6d951SJohn Birrell 				dt_free(dtp, aggvars);
35486ff6d951SJohn Birrell 				goto nextrec;
35496ff6d951SJohn Birrell 			}
35506ff6d951SJohn Birrell 
3551f2e66d30SPedro F. Giffuni 			if (act == DTRACEACT_TRACEMEM) {
3552f2e66d30SPedro F. Giffuni 				if (tracememsize == 0 ||
3553f2e66d30SPedro F. Giffuni 				    tracememsize > rec->dtrd_size) {
3554f2e66d30SPedro F. Giffuni 					tracememsize = rec->dtrd_size;
3555f2e66d30SPedro F. Giffuni 				}
3556f2e66d30SPedro F. Giffuni 
355793f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
355893f27766SDomagoj Stolfa 					char *s;
355993f27766SDomagoj Stolfa 
356093f27766SDomagoj Stolfa 					s = dt_format_bytes_get(dtp, addr,
356193f27766SDomagoj Stolfa 					    tracememsize);
356293f27766SDomagoj Stolfa 					n = xo_emit("{:tracemem/%s}", s);
356393f27766SDomagoj Stolfa 					dt_free(dtp, s);
356493f27766SDomagoj Stolfa 				} else {
3565f2e66d30SPedro F. Giffuni 					n = dt_print_bytes(dtp, fp, addr,
3566a43f0be9SRui Paulo 					    tracememsize, -33, quiet, 1);
356793f27766SDomagoj Stolfa 				}
3568f2e66d30SPedro F. Giffuni 
3569f2e66d30SPedro F. Giffuni 				tracememsize = 0;
3570f2e66d30SPedro F. Giffuni 
3571f2e66d30SPedro F. Giffuni 				if (n < 0)
3572f2e66d30SPedro F. Giffuni 					return (-1);
3573f2e66d30SPedro F. Giffuni 
3574f2e66d30SPedro F. Giffuni 				goto nextrec;
3575f2e66d30SPedro F. Giffuni 			}
3576f2e66d30SPedro F. Giffuni 
35776ff6d951SJohn Birrell 			switch (rec->dtrd_size) {
35786ff6d951SJohn Birrell 			case sizeof (uint64_t):
357993f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
358093f27766SDomagoj Stolfa 					xo_emit("{:value/%lld}",
358193f27766SDomagoj Stolfa 					    *((unsigned long long *)addr));
358293f27766SDomagoj Stolfa 					n = 0;
358393f27766SDomagoj Stolfa 				} else
35846ff6d951SJohn Birrell 					n = dt_printf(dtp, fp,
35856ff6d951SJohn Birrell 					    quiet ? "%lld" : " %16lld",
35866ff6d951SJohn Birrell 					    /* LINTED - alignment */
35876ff6d951SJohn Birrell 					    *((unsigned long long *)addr));
35886ff6d951SJohn Birrell 				break;
35896ff6d951SJohn Birrell 			case sizeof (uint32_t):
359093f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
359193f27766SDomagoj Stolfa 					xo_emit("{:value/%d}",
359293f27766SDomagoj Stolfa 					    *((uint32_t *)addr));
359393f27766SDomagoj Stolfa 					n = 0;
359493f27766SDomagoj Stolfa 				} else
359593f27766SDomagoj Stolfa 					n = dt_printf(dtp, fp,
359693f27766SDomagoj Stolfa 					    quiet ? "%d" : " %8d",
35976ff6d951SJohn Birrell 					    /* LINTED - alignment */
35986ff6d951SJohn Birrell 					    *((uint32_t *)addr));
35996ff6d951SJohn Birrell 				break;
36006ff6d951SJohn Birrell 			case sizeof (uint16_t):
360193f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
360293f27766SDomagoj Stolfa 					xo_emit("{:value/%d}",
360393f27766SDomagoj Stolfa 					    *((uint16_t *)addr));
360493f27766SDomagoj Stolfa 					n = 0;
360593f27766SDomagoj Stolfa 				} else
360693f27766SDomagoj Stolfa 					n = dt_printf(dtp, fp,
360793f27766SDomagoj Stolfa 					    quiet ? "%d" : " %5d",
36086ff6d951SJohn Birrell 					    /* LINTED - alignment */
36096ff6d951SJohn Birrell 					    *((uint16_t *)addr));
36106ff6d951SJohn Birrell 				break;
36116ff6d951SJohn Birrell 			case sizeof (uint8_t):
361293f27766SDomagoj Stolfa 				if (dtp->dt_oformat) {
361393f27766SDomagoj Stolfa 					xo_emit("{:value/%d}",
361493f27766SDomagoj Stolfa 					    *((uint8_t *)addr));
361593f27766SDomagoj Stolfa 					n = 0;
361693f27766SDomagoj Stolfa 				} else
361793f27766SDomagoj Stolfa 					n = dt_printf(dtp, fp,
361893f27766SDomagoj Stolfa 					    quiet ? "%d" : " %3d",
36196ff6d951SJohn Birrell 					    *((uint8_t *)addr));
36206ff6d951SJohn Birrell 				break;
36216ff6d951SJohn Birrell 			default:
362293f27766SDomagoj Stolfa 				if (dtp->dt_oformat && rec->dtrd_size > 0) {
362393f27766SDomagoj Stolfa 					char *s;
362493f27766SDomagoj Stolfa 
362593f27766SDomagoj Stolfa 					s = dt_format_bytes_get(dtp, addr,
362693f27766SDomagoj Stolfa 					    rec->dtrd_size);
362793f27766SDomagoj Stolfa 					xo_emit("{:value/%s}", s);
362893f27766SDomagoj Stolfa 					dt_free(dtp, s);
362993f27766SDomagoj Stolfa 					n = 0;
363093f27766SDomagoj Stolfa 				} else {
36316ff6d951SJohn Birrell 					n = dt_print_bytes(dtp, fp, addr,
3632a43f0be9SRui Paulo 					    rec->dtrd_size, -33, quiet, 0);
363393f27766SDomagoj Stolfa 				}
36346ff6d951SJohn Birrell 				break;
36356ff6d951SJohn Birrell 			}
36366ff6d951SJohn Birrell 
363793f27766SDomagoj Stolfa 			if (dtp->dt_oformat && rec->dtrd_size > 0)
363893f27766SDomagoj Stolfa 				xo_close_instance("output");
363993f27766SDomagoj Stolfa 
36406ff6d951SJohn Birrell 			if (n < 0)
36416ff6d951SJohn Birrell 				return (-1); /* errno is set for us */
36426ff6d951SJohn Birrell 
36436ff6d951SJohn Birrell nextrec:
36446ff6d951SJohn Birrell 			if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0)
36456ff6d951SJohn Birrell 				return (-1); /* errno is set for us */
36466ff6d951SJohn Birrell 		}
36476ff6d951SJohn Birrell 
36486ff6d951SJohn Birrell 		/*
36496ff6d951SJohn Birrell 		 * Call the record callback with a NULL record to indicate
36506ff6d951SJohn Birrell 		 * that we're done processing this EPID.
36516ff6d951SJohn Birrell 		 */
36526ff6d951SJohn Birrell 		rval = (*rfunc)(&data, NULL, arg);
36536ff6d951SJohn Birrell nextepid:
36546ff6d951SJohn Birrell 		offs += epd->dtepd_size;
365509e6105fSMark Johnston 		dtp->dt_last_epid = id;
365693f27766SDomagoj Stolfa 
365793f27766SDomagoj Stolfa 		if (dtp->dt_oformat) {
365893f27766SDomagoj Stolfa 			xo_close_list("output");
365993f27766SDomagoj Stolfa 			xo_close_instance("probes");
366093f27766SDomagoj Stolfa 			xo_flush();
366193f27766SDomagoj Stolfa 		}
366209e6105fSMark Johnston 		if (just_one) {
366309e6105fSMark Johnston 			buf->dtbd_oldest = offs;
366409e6105fSMark Johnston 			break;
366509e6105fSMark Johnston 		}
36666ff6d951SJohn Birrell 	}
36676ff6d951SJohn Birrell 
366809e6105fSMark Johnston 	dtp->dt_flow = data.dtpda_flow;
366909e6105fSMark Johnston 	dtp->dt_indent = data.dtpda_indent;
367009e6105fSMark Johnston 	dtp->dt_prefix = data.dtpda_prefix;
36716ff6d951SJohn Birrell 
36726ff6d951SJohn Birrell 	if ((drops = buf->dtbd_drops) == 0)
36736ff6d951SJohn Birrell 		return (0);
36746ff6d951SJohn Birrell 
36756ff6d951SJohn Birrell 	/*
36766ff6d951SJohn Birrell 	 * Explicitly zero the drops to prevent us from processing them again.
36776ff6d951SJohn Birrell 	 */
36786ff6d951SJohn Birrell 	buf->dtbd_drops = 0;
36796ff6d951SJohn Birrell 
36801bb8b1d7SMark Johnston 	if (dtp->dt_oformat) {
368193f27766SDomagoj Stolfa 		xo_open_instance("probes");
368293f27766SDomagoj Stolfa 		dt_oformat_drop(dtp, cpu);
36831bb8b1d7SMark Johnston 	}
368493f27766SDomagoj Stolfa 	rval = dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops);
36851bb8b1d7SMark Johnston 	if (dtp->dt_oformat)
368693f27766SDomagoj Stolfa 		xo_close_instance("probes");
368793f27766SDomagoj Stolfa 
368893f27766SDomagoj Stolfa 	return (rval);
36896ff6d951SJohn Birrell }
36906ff6d951SJohn Birrell 
369109e6105fSMark Johnston /*
369209e6105fSMark Johnston  * Reduce memory usage by shrinking the buffer if it's no more than half full.
369309e6105fSMark Johnston  * Note, we need to preserve the alignment of the data at dtbd_oldest, which is
369409e6105fSMark Johnston  * only 4-byte aligned.
369509e6105fSMark Johnston  */
369609e6105fSMark Johnston static void
dt_realloc_buf(dtrace_hdl_t * dtp,dtrace_bufdesc_t * buf,int cursize)369709e6105fSMark Johnston dt_realloc_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf, int cursize)
369809e6105fSMark Johnston {
369909e6105fSMark Johnston 	uint64_t used = buf->dtbd_size - buf->dtbd_oldest;
370009e6105fSMark Johnston 	if (used < cursize / 2) {
370109e6105fSMark Johnston 		int misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1);
370209e6105fSMark Johnston 		char *newdata = dt_alloc(dtp, used + misalign);
370309e6105fSMark Johnston 		if (newdata == NULL)
370409e6105fSMark Johnston 			return;
370509e6105fSMark Johnston 		bzero(newdata, misalign);
370609e6105fSMark Johnston 		bcopy(buf->dtbd_data + buf->dtbd_oldest,
370709e6105fSMark Johnston 		    newdata + misalign, used);
370809e6105fSMark Johnston 		dt_free(dtp, buf->dtbd_data);
370909e6105fSMark Johnston 		buf->dtbd_oldest = misalign;
371009e6105fSMark Johnston 		buf->dtbd_size = used + misalign;
371109e6105fSMark Johnston 		buf->dtbd_data = newdata;
371209e6105fSMark Johnston 	}
371309e6105fSMark Johnston }
371409e6105fSMark Johnston 
371509e6105fSMark Johnston /*
371609e6105fSMark Johnston  * If the ring buffer has wrapped, the data is not in order.  Rearrange it
371709e6105fSMark Johnston  * so that it is.  Note, we need to preserve the alignment of the data at
371809e6105fSMark Johnston  * dtbd_oldest, which is only 4-byte aligned.
371909e6105fSMark Johnston  */
372009e6105fSMark Johnston static int
dt_unring_buf(dtrace_hdl_t * dtp,dtrace_bufdesc_t * buf)372109e6105fSMark Johnston dt_unring_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf)
372209e6105fSMark Johnston {
372309e6105fSMark Johnston 	int misalign;
372409e6105fSMark Johnston 	char *newdata, *ndp;
372509e6105fSMark Johnston 
372609e6105fSMark Johnston 	if (buf->dtbd_oldest == 0)
372709e6105fSMark Johnston 		return (0);
372809e6105fSMark Johnston 
372909e6105fSMark Johnston 	misalign = buf->dtbd_oldest & (sizeof (uint64_t) - 1);
373009e6105fSMark Johnston 	newdata = ndp = dt_alloc(dtp, buf->dtbd_size + misalign);
373109e6105fSMark Johnston 
373209e6105fSMark Johnston 	if (newdata == NULL)
373309e6105fSMark Johnston 		return (-1);
373409e6105fSMark Johnston 
373509e6105fSMark Johnston 	assert(0 == (buf->dtbd_size & (sizeof (uint64_t) - 1)));
373609e6105fSMark Johnston 
373709e6105fSMark Johnston 	bzero(ndp, misalign);
373809e6105fSMark Johnston 	ndp += misalign;
373909e6105fSMark Johnston 
374009e6105fSMark Johnston 	bcopy(buf->dtbd_data + buf->dtbd_oldest, ndp,
374109e6105fSMark Johnston 	    buf->dtbd_size - buf->dtbd_oldest);
374209e6105fSMark Johnston 	ndp += buf->dtbd_size - buf->dtbd_oldest;
374309e6105fSMark Johnston 
374409e6105fSMark Johnston 	bcopy(buf->dtbd_data, ndp, buf->dtbd_oldest);
374509e6105fSMark Johnston 
374609e6105fSMark Johnston 	dt_free(dtp, buf->dtbd_data);
3747256c8c5dSAndriy Gapon 	buf->dtbd_oldest = misalign;
374809e6105fSMark Johnston 	buf->dtbd_data = newdata;
374909e6105fSMark Johnston 	buf->dtbd_size += misalign;
375009e6105fSMark Johnston 
375109e6105fSMark Johnston 	return (0);
375209e6105fSMark Johnston }
375309e6105fSMark Johnston 
375409e6105fSMark Johnston static void
dt_put_buf(dtrace_hdl_t * dtp,dtrace_bufdesc_t * buf)375509e6105fSMark Johnston dt_put_buf(dtrace_hdl_t *dtp, dtrace_bufdesc_t *buf)
375609e6105fSMark Johnston {
375709e6105fSMark Johnston 	dt_free(dtp, buf->dtbd_data);
375809e6105fSMark Johnston 	dt_free(dtp, buf);
375909e6105fSMark Johnston }
376009e6105fSMark Johnston 
376109e6105fSMark Johnston /*
376209e6105fSMark Johnston  * Returns 0 on success, in which case *cbp will be filled in if we retrieved
376309e6105fSMark Johnston  * data, or NULL if there is no data for this CPU.
376409e6105fSMark Johnston  * Returns -1 on failure and sets dt_errno.
376509e6105fSMark Johnston  */
376609e6105fSMark Johnston static int
dt_get_buf(dtrace_hdl_t * dtp,int cpu,dtrace_bufdesc_t ** bufp)376709e6105fSMark Johnston dt_get_buf(dtrace_hdl_t *dtp, int cpu, dtrace_bufdesc_t **bufp)
376809e6105fSMark Johnston {
376909e6105fSMark Johnston 	dtrace_optval_t size;
377009e6105fSMark Johnston 	dtrace_bufdesc_t *buf = dt_zalloc(dtp, sizeof (*buf));
377147890cb5SMark Johnston 	int error, rval;
377209e6105fSMark Johnston 
377309e6105fSMark Johnston 	if (buf == NULL)
377409e6105fSMark Johnston 		return (-1);
377509e6105fSMark Johnston 
377609e6105fSMark Johnston 	(void) dtrace_getopt(dtp, "bufsize", &size);
377709e6105fSMark Johnston 	buf->dtbd_data = dt_alloc(dtp, size);
377809e6105fSMark Johnston 	if (buf->dtbd_data == NULL) {
377909e6105fSMark Johnston 		dt_free(dtp, buf);
378009e6105fSMark Johnston 		return (-1);
378109e6105fSMark Johnston 	}
378209e6105fSMark Johnston 	buf->dtbd_size = size;
378309e6105fSMark Johnston 	buf->dtbd_cpu = cpu;
378409e6105fSMark Johnston 
3785bc96366cSSteven Hartland #ifdef illumos
378609e6105fSMark Johnston 	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
378709e6105fSMark Johnston #else
378809e6105fSMark Johnston 	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &buf) == -1) {
378909e6105fSMark Johnston #endif
379009e6105fSMark Johnston 		/*
379109e6105fSMark Johnston 		 * If we failed with ENOENT, it may be because the
379209e6105fSMark Johnston 		 * CPU was unconfigured -- this is okay.  Any other
379309e6105fSMark Johnston 		 * error, however, is unexpected.
379409e6105fSMark Johnston 		 */
379509e6105fSMark Johnston 		if (errno == ENOENT) {
379609e6105fSMark Johnston 			*bufp = NULL;
379747890cb5SMark Johnston 			rval = 0;
379847890cb5SMark Johnston 		} else
379947890cb5SMark Johnston 			rval = dt_set_errno(dtp, errno);
380009e6105fSMark Johnston 
380147890cb5SMark Johnston 		dt_put_buf(dtp, buf);
380247890cb5SMark Johnston 		return (rval);
380309e6105fSMark Johnston 	}
380409e6105fSMark Johnston 
380509e6105fSMark Johnston 	error = dt_unring_buf(dtp, buf);
380609e6105fSMark Johnston 	if (error != 0) {
380709e6105fSMark Johnston 		dt_put_buf(dtp, buf);
380809e6105fSMark Johnston 		return (error);
380909e6105fSMark Johnston 	}
381009e6105fSMark Johnston 	dt_realloc_buf(dtp, buf, size);
381109e6105fSMark Johnston 
381209e6105fSMark Johnston 	*bufp = buf;
381309e6105fSMark Johnston 	return (0);
381409e6105fSMark Johnston }
381509e6105fSMark Johnston 
38166ff6d951SJohn Birrell typedef struct dt_begin {
38176ff6d951SJohn Birrell 	dtrace_consume_probe_f *dtbgn_probefunc;
38186ff6d951SJohn Birrell 	dtrace_consume_rec_f *dtbgn_recfunc;
38196ff6d951SJohn Birrell 	void *dtbgn_arg;
38206ff6d951SJohn Birrell 	dtrace_handle_err_f *dtbgn_errhdlr;
38216ff6d951SJohn Birrell 	void *dtbgn_errarg;
38226ff6d951SJohn Birrell 	int dtbgn_beginonly;
38236ff6d951SJohn Birrell } dt_begin_t;
38246ff6d951SJohn Birrell 
38256ff6d951SJohn Birrell static int
38266ff6d951SJohn Birrell dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg)
38276ff6d951SJohn Birrell {
3828a98ff317SPedro F. Giffuni 	dt_begin_t *begin = arg;
38296ff6d951SJohn Birrell 	dtrace_probedesc_t *pd = data->dtpda_pdesc;
38306ff6d951SJohn Birrell 
38316ff6d951SJohn Birrell 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
38326ff6d951SJohn Birrell 	int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
38336ff6d951SJohn Birrell 
38346ff6d951SJohn Birrell 	if (begin->dtbgn_beginonly) {
38356ff6d951SJohn Birrell 		if (!(r1 && r2))
38366ff6d951SJohn Birrell 			return (DTRACE_CONSUME_NEXT);
38376ff6d951SJohn Birrell 	} else {
38386ff6d951SJohn Birrell 		if (r1 && r2)
38396ff6d951SJohn Birrell 			return (DTRACE_CONSUME_NEXT);
38406ff6d951SJohn Birrell 	}
38416ff6d951SJohn Birrell 
38426ff6d951SJohn Birrell 	/*
38436ff6d951SJohn Birrell 	 * We have a record that we're interested in.  Now call the underlying
38446ff6d951SJohn Birrell 	 * probe function...
38456ff6d951SJohn Birrell 	 */
38466ff6d951SJohn Birrell 	return (begin->dtbgn_probefunc(data, begin->dtbgn_arg));
38476ff6d951SJohn Birrell }
38486ff6d951SJohn Birrell 
38496ff6d951SJohn Birrell static int
38506ff6d951SJohn Birrell dt_consume_begin_record(const dtrace_probedata_t *data,
38516ff6d951SJohn Birrell     const dtrace_recdesc_t *rec, void *arg)
38526ff6d951SJohn Birrell {
3853a98ff317SPedro F. Giffuni 	dt_begin_t *begin = arg;
38546ff6d951SJohn Birrell 
38556ff6d951SJohn Birrell 	return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg));
38566ff6d951SJohn Birrell }
38576ff6d951SJohn Birrell 
38586ff6d951SJohn Birrell static int
38596ff6d951SJohn Birrell dt_consume_begin_error(const dtrace_errdata_t *data, void *arg)
38606ff6d951SJohn Birrell {
38616ff6d951SJohn Birrell 	dt_begin_t *begin = (dt_begin_t *)arg;
38626ff6d951SJohn Birrell 	dtrace_probedesc_t *pd = data->dteda_pdesc;
38636ff6d951SJohn Birrell 
38646ff6d951SJohn Birrell 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
38656ff6d951SJohn Birrell 	int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
38666ff6d951SJohn Birrell 
38676ff6d951SJohn Birrell 	if (begin->dtbgn_beginonly) {
38686ff6d951SJohn Birrell 		if (!(r1 && r2))
38696ff6d951SJohn Birrell 			return (DTRACE_HANDLE_OK);
38706ff6d951SJohn Birrell 	} else {
38716ff6d951SJohn Birrell 		if (r1 && r2)
38726ff6d951SJohn Birrell 			return (DTRACE_HANDLE_OK);
38736ff6d951SJohn Birrell 	}
38746ff6d951SJohn Birrell 
38756ff6d951SJohn Birrell 	return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg));
38766ff6d951SJohn Birrell }
38776ff6d951SJohn Birrell 
38786ff6d951SJohn Birrell static int
387909e6105fSMark Johnston dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp,
38806ff6d951SJohn Birrell     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
38816ff6d951SJohn Birrell {
38826ff6d951SJohn Birrell 	/*
38836ff6d951SJohn Birrell 	 * There's this idea that the BEGIN probe should be processed before
38846ff6d951SJohn Birrell 	 * everything else, and that the END probe should be processed after
38856ff6d951SJohn Birrell 	 * anything else.  In the common case, this is pretty easy to deal
38866ff6d951SJohn Birrell 	 * with.  However, a situation may arise where the BEGIN enabling and
38876ff6d951SJohn Birrell 	 * END enabling are on the same CPU, and some enabling in the middle
38886ff6d951SJohn Birrell 	 * occurred on a different CPU.  To deal with this (blech!) we need to
38896ff6d951SJohn Birrell 	 * consume the BEGIN buffer up until the end of the BEGIN probe, and
38906ff6d951SJohn Birrell 	 * then set it aside.  We will then process every other CPU, and then
38916ff6d951SJohn Birrell 	 * we'll return to the BEGIN CPU and process the rest of the data
38926ff6d951SJohn Birrell 	 * (which will inevitably include the END probe, if any).  Making this
38936ff6d951SJohn Birrell 	 * even more complicated (!) is the library's ERROR enabling.  Because
38946ff6d951SJohn Birrell 	 * this enabling is processed before we even get into the consume call
38956ff6d951SJohn Birrell 	 * back, any ERROR firing would result in the library's ERROR enabling
38966ff6d951SJohn Birrell 	 * being processed twice -- once in our first pass (for BEGIN probes),
38976ff6d951SJohn Birrell 	 * and again in our second pass (for everything but BEGIN probes).  To
38986ff6d951SJohn Birrell 	 * deal with this, we interpose on the ERROR handler to assure that we
38996ff6d951SJohn Birrell 	 * only process ERROR enablings induced by BEGIN enablings in the
39006ff6d951SJohn Birrell 	 * first pass, and that we only process ERROR enablings _not_ induced
39016ff6d951SJohn Birrell 	 * by BEGIN enablings in the second pass.
39026ff6d951SJohn Birrell 	 */
390309e6105fSMark Johnston 
39046ff6d951SJohn Birrell 	dt_begin_t begin;
39056ff6d951SJohn Birrell 	processorid_t cpu = dtp->dt_beganon;
39066ff6d951SJohn Birrell 	int rval, i;
39076ff6d951SJohn Birrell 	static int max_ncpus;
390809e6105fSMark Johnston 	dtrace_bufdesc_t *buf;
39096ff6d951SJohn Birrell 
39106ff6d951SJohn Birrell 	dtp->dt_beganon = -1;
39116ff6d951SJohn Birrell 
391209e6105fSMark Johnston 	if (dt_get_buf(dtp, cpu, &buf) != 0)
391309e6105fSMark Johnston 		return (-1);
391409e6105fSMark Johnston 	if (buf == NULL)
39156ff6d951SJohn Birrell 		return (0);
39166ff6d951SJohn Birrell 
39176ff6d951SJohn Birrell 	if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) {
39186ff6d951SJohn Birrell 		/*
39196ff6d951SJohn Birrell 		 * This is the simple case.  We're either not stopped, or if
39206ff6d951SJohn Birrell 		 * we are, we actually processed any END probes on another
39216ff6d951SJohn Birrell 		 * CPU.  We can simply consume this buffer and return.
39226ff6d951SJohn Birrell 		 */
392309e6105fSMark Johnston 		rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
392409e6105fSMark Johnston 		    pf, rf, arg);
392509e6105fSMark Johnston 		dt_put_buf(dtp, buf);
392609e6105fSMark Johnston 		return (rval);
39276ff6d951SJohn Birrell 	}
39286ff6d951SJohn Birrell 
39296ff6d951SJohn Birrell 	begin.dtbgn_probefunc = pf;
39306ff6d951SJohn Birrell 	begin.dtbgn_recfunc = rf;
39316ff6d951SJohn Birrell 	begin.dtbgn_arg = arg;
39326ff6d951SJohn Birrell 	begin.dtbgn_beginonly = 1;
39336ff6d951SJohn Birrell 
39346ff6d951SJohn Birrell 	/*
39356ff6d951SJohn Birrell 	 * We need to interpose on the ERROR handler to be sure that we
39366ff6d951SJohn Birrell 	 * only process ERRORs induced by BEGIN.
39376ff6d951SJohn Birrell 	 */
39386ff6d951SJohn Birrell 	begin.dtbgn_errhdlr = dtp->dt_errhdlr;
39396ff6d951SJohn Birrell 	begin.dtbgn_errarg = dtp->dt_errarg;
39406ff6d951SJohn Birrell 	dtp->dt_errhdlr = dt_consume_begin_error;
39416ff6d951SJohn Birrell 	dtp->dt_errarg = &begin;
39426ff6d951SJohn Birrell 
394309e6105fSMark Johnston 	rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
394409e6105fSMark Johnston 	    dt_consume_begin_probe, dt_consume_begin_record, &begin);
39456ff6d951SJohn Birrell 
39466ff6d951SJohn Birrell 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
39476ff6d951SJohn Birrell 	dtp->dt_errarg = begin.dtbgn_errarg;
39486ff6d951SJohn Birrell 
394909e6105fSMark Johnston 	if (rval != 0) {
395009e6105fSMark Johnston 		dt_put_buf(dtp, buf);
39516ff6d951SJohn Birrell 		return (rval);
395209e6105fSMark Johnston 	}
39536ff6d951SJohn Birrell 
39549a30c8d3SMark Johnston 	if (max_ncpus == 0 && (max_ncpus = dt_cpu_maxid(dtp) + 1) <= 0)
39559a30c8d3SMark Johnston 		return (-1);
39566ff6d951SJohn Birrell 
39576ff6d951SJohn Birrell 	for (i = 0; i < max_ncpus; i++) {
395809e6105fSMark Johnston 		dtrace_bufdesc_t *nbuf;
39596ff6d951SJohn Birrell 		if (i == cpu)
39606ff6d951SJohn Birrell 			continue;
39616ff6d951SJohn Birrell 
396209e6105fSMark Johnston 		if (dt_get_buf(dtp, i, &nbuf) != 0) {
396309e6105fSMark Johnston 			dt_put_buf(dtp, buf);
396409e6105fSMark Johnston 			return (-1);
396509e6105fSMark Johnston 		}
396609e6105fSMark Johnston 		if (nbuf == NULL)
39676ff6d951SJohn Birrell 			continue;
39686ff6d951SJohn Birrell 
396909e6105fSMark Johnston 		rval = dt_consume_cpu(dtp, fp, i, nbuf, B_FALSE,
397009e6105fSMark Johnston 		    pf, rf, arg);
397109e6105fSMark Johnston 		dt_put_buf(dtp, nbuf);
397209e6105fSMark Johnston 		if (rval != 0) {
397309e6105fSMark Johnston 			dt_put_buf(dtp, buf);
39746ff6d951SJohn Birrell 			return (rval);
39756ff6d951SJohn Birrell 		}
39766ff6d951SJohn Birrell 	}
39776ff6d951SJohn Birrell 
39786ff6d951SJohn Birrell 	/*
39796ff6d951SJohn Birrell 	 * Okay -- we're done with the other buffers.  Now we want to
39806ff6d951SJohn Birrell 	 * reconsume the first buffer -- but this time we're looking for
39816ff6d951SJohn Birrell 	 * everything _but_ BEGIN.  And of course, in order to only consume
39826ff6d951SJohn Birrell 	 * those ERRORs _not_ associated with BEGIN, we need to reinstall our
39836ff6d951SJohn Birrell 	 * ERROR interposition function...
39846ff6d951SJohn Birrell 	 */
39856ff6d951SJohn Birrell 	begin.dtbgn_beginonly = 0;
39866ff6d951SJohn Birrell 
39876ff6d951SJohn Birrell 	assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr);
39886ff6d951SJohn Birrell 	assert(begin.dtbgn_errarg == dtp->dt_errarg);
39896ff6d951SJohn Birrell 	dtp->dt_errhdlr = dt_consume_begin_error;
39906ff6d951SJohn Birrell 	dtp->dt_errarg = &begin;
39916ff6d951SJohn Birrell 
399209e6105fSMark Johnston 	rval = dt_consume_cpu(dtp, fp, cpu, buf, B_FALSE,
399309e6105fSMark Johnston 	    dt_consume_begin_probe, dt_consume_begin_record, &begin);
39946ff6d951SJohn Birrell 
39956ff6d951SJohn Birrell 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
39966ff6d951SJohn Birrell 	dtp->dt_errarg = begin.dtbgn_errarg;
39976ff6d951SJohn Birrell 
39986ff6d951SJohn Birrell 	return (rval);
39996ff6d951SJohn Birrell }
40006ff6d951SJohn Birrell 
400109e6105fSMark Johnston /* ARGSUSED */
400209e6105fSMark Johnston static uint64_t
400309e6105fSMark Johnston dt_buf_oldest(void *elem, void *arg)
400409e6105fSMark Johnston {
400509e6105fSMark Johnston 	dtrace_bufdesc_t *buf = elem;
400609e6105fSMark Johnston 	size_t offs = buf->dtbd_oldest;
400709e6105fSMark Johnston 
400809e6105fSMark Johnston 	while (offs < buf->dtbd_size) {
400909e6105fSMark Johnston 		dtrace_rechdr_t *dtrh =
401009e6105fSMark Johnston 		    /* LINTED - alignment */
401109e6105fSMark Johnston 		    (dtrace_rechdr_t *)(buf->dtbd_data + offs);
401209e6105fSMark Johnston 		if (dtrh->dtrh_epid == DTRACE_EPIDNONE) {
401309e6105fSMark Johnston 			offs += sizeof (dtrace_epid_t);
401409e6105fSMark Johnston 		} else {
401509e6105fSMark Johnston 			return (DTRACE_RECORD_LOAD_TIMESTAMP(dtrh));
401609e6105fSMark Johnston 		}
401709e6105fSMark Johnston 	}
401809e6105fSMark Johnston 
401909e6105fSMark Johnston 	/* There are no records left; use the time the buffer was retrieved. */
402009e6105fSMark Johnston 	return (buf->dtbd_timestamp);
402109e6105fSMark Johnston }
402209e6105fSMark Johnston 
40236ff6d951SJohn Birrell int
40246ff6d951SJohn Birrell dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
40256ff6d951SJohn Birrell     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
40266ff6d951SJohn Birrell {
40276ff6d951SJohn Birrell 	dtrace_optval_t size;
40286ff6d951SJohn Birrell 	static int max_ncpus;
40296ff6d951SJohn Birrell 	int i, rval;
40306ff6d951SJohn Birrell 	dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE];
40316ff6d951SJohn Birrell 	hrtime_t now = gethrtime();
40326ff6d951SJohn Birrell 
40336ff6d951SJohn Birrell 	if (dtp->dt_lastswitch != 0) {
40346ff6d951SJohn Birrell 		if (now - dtp->dt_lastswitch < interval)
40356ff6d951SJohn Birrell 			return (0);
40366ff6d951SJohn Birrell 
40376ff6d951SJohn Birrell 		dtp->dt_lastswitch += interval;
40386ff6d951SJohn Birrell 	} else {
40396ff6d951SJohn Birrell 		dtp->dt_lastswitch = now;
40406ff6d951SJohn Birrell 	}
40416ff6d951SJohn Birrell 
40426ff6d951SJohn Birrell 	if (!dtp->dt_active)
40436ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EINVAL));
40446ff6d951SJohn Birrell 
40459a30c8d3SMark Johnston 	if (max_ncpus == 0 && (max_ncpus = dt_cpu_maxid(dtp) + 1) <= 0)
40469a30c8d3SMark Johnston 		return (-1);
40476ff6d951SJohn Birrell 
40486ff6d951SJohn Birrell 	if (pf == NULL)
40496ff6d951SJohn Birrell 		pf = (dtrace_consume_probe_f *)dt_nullprobe;
40506ff6d951SJohn Birrell 
40516ff6d951SJohn Birrell 	if (rf == NULL)
40526ff6d951SJohn Birrell 		rf = (dtrace_consume_rec_f *)dt_nullrec;
40536ff6d951SJohn Birrell 
405409e6105fSMark Johnston 	if (dtp->dt_options[DTRACEOPT_TEMPORAL] == DTRACEOPT_UNSET) {
40556ff6d951SJohn Birrell 		/*
405609e6105fSMark Johnston 		 * The output will not be in the order it was traced.  Rather,
405709e6105fSMark Johnston 		 * we will consume all of the data from each CPU's buffer in
405809e6105fSMark Johnston 		 * turn.  We apply special handling for the records from BEGIN
405909e6105fSMark Johnston 		 * and END probes so that they are consumed first and last,
406009e6105fSMark Johnston 		 * respectively.
406109e6105fSMark Johnston 		 *
40626ff6d951SJohn Birrell 		 * If we have just begun, we want to first process the CPU that
40636ff6d951SJohn Birrell 		 * executed the BEGIN probe (if any).
40646ff6d951SJohn Birrell 		 */
406509e6105fSMark Johnston 		if (dtp->dt_active && dtp->dt_beganon != -1 &&
406609e6105fSMark Johnston 		    (rval = dt_consume_begin(dtp, fp, pf, rf, arg)) != 0)
40676ff6d951SJohn Birrell 			return (rval);
40686ff6d951SJohn Birrell 
40696ff6d951SJohn Birrell 		for (i = 0; i < max_ncpus; i++) {
407009e6105fSMark Johnston 			dtrace_bufdesc_t *buf;
40716ff6d951SJohn Birrell 
40726ff6d951SJohn Birrell 			/*
407309e6105fSMark Johnston 			 * If we have stopped, we want to process the CPU on
407409e6105fSMark Johnston 			 * which the END probe was processed only _after_ we
407509e6105fSMark Johnston 			 * have processed everything else.
40766ff6d951SJohn Birrell 			 */
40776ff6d951SJohn Birrell 			if (dtp->dt_stopped && (i == dtp->dt_endedon))
40786ff6d951SJohn Birrell 				continue;
40796ff6d951SJohn Birrell 
408009e6105fSMark Johnston 			if (dt_get_buf(dtp, i, &buf) != 0)
408109e6105fSMark Johnston 				return (-1);
408209e6105fSMark Johnston 			if (buf == NULL)
40836ff6d951SJohn Birrell 				continue;
40846ff6d951SJohn Birrell 
408509e6105fSMark Johnston 			dtp->dt_flow = 0;
408609e6105fSMark Johnston 			dtp->dt_indent = 0;
408709e6105fSMark Johnston 			dtp->dt_prefix = NULL;
408809e6105fSMark Johnston 			rval = dt_consume_cpu(dtp, fp, i,
408909e6105fSMark Johnston 			    buf, B_FALSE, pf, rf, arg);
409009e6105fSMark Johnston 			dt_put_buf(dtp, buf);
409109e6105fSMark Johnston 			if (rval != 0)
40926ff6d951SJohn Birrell 				return (rval);
40936ff6d951SJohn Birrell 		}
409409e6105fSMark Johnston 		if (dtp->dt_stopped) {
409509e6105fSMark Johnston 			dtrace_bufdesc_t *buf;
40966ff6d951SJohn Birrell 
409709e6105fSMark Johnston 			if (dt_get_buf(dtp, dtp->dt_endedon, &buf) != 0)
409809e6105fSMark Johnston 				return (-1);
409909e6105fSMark Johnston 			if (buf == NULL)
41006ff6d951SJohn Birrell 				return (0);
41016ff6d951SJohn Birrell 
410209e6105fSMark Johnston 			rval = dt_consume_cpu(dtp, fp, dtp->dt_endedon,
410309e6105fSMark Johnston 			    buf, B_FALSE, pf, rf, arg);
410409e6105fSMark Johnston 			dt_put_buf(dtp, buf);
410509e6105fSMark Johnston 			return (rval);
410609e6105fSMark Johnston 		}
410709e6105fSMark Johnston 	} else {
41086ff6d951SJohn Birrell 		/*
410909e6105fSMark Johnston 		 * The output will be in the order it was traced (or for
411009e6105fSMark Johnston 		 * speculations, when it was committed).  We retrieve a buffer
411109e6105fSMark Johnston 		 * from each CPU and put it into a priority queue, which sorts
411209e6105fSMark Johnston 		 * based on the first entry in the buffer.  This is sufficient
411309e6105fSMark Johnston 		 * because entries within a buffer are already sorted.
411409e6105fSMark Johnston 		 *
411509e6105fSMark Johnston 		 * We then consume records one at a time, always consuming the
411609e6105fSMark Johnston 		 * oldest record, as determined by the priority queue.  When
411709e6105fSMark Johnston 		 * we reach the end of the time covered by these buffers,
411809e6105fSMark Johnston 		 * we need to stop and retrieve more records on the next pass.
411909e6105fSMark Johnston 		 * The kernel tells us the time covered by each buffer, in
412009e6105fSMark Johnston 		 * dtbd_timestamp.  The first buffer's timestamp tells us the
412109e6105fSMark Johnston 		 * time covered by all buffers, as subsequently retrieved
412209e6105fSMark Johnston 		 * buffers will cover to a more recent time.
41236ff6d951SJohn Birrell 		 */
412403836978SPedro F. Giffuni 
412509e6105fSMark Johnston 		uint64_t *drops = alloca(max_ncpus * sizeof (uint64_t));
412609e6105fSMark Johnston 		uint64_t first_timestamp = 0;
412709e6105fSMark Johnston 		uint_t cookie = 0;
412809e6105fSMark Johnston 		dtrace_bufdesc_t *buf;
412909e6105fSMark Johnston 
413009e6105fSMark Johnston 		bzero(drops, max_ncpus * sizeof (uint64_t));
413109e6105fSMark Johnston 
413209e6105fSMark Johnston 		if (dtp->dt_bufq == NULL) {
413309e6105fSMark Johnston 			dtp->dt_bufq = dt_pq_init(dtp, max_ncpus * 2,
413409e6105fSMark Johnston 			    dt_buf_oldest, NULL);
413509e6105fSMark Johnston 			if (dtp->dt_bufq == NULL) /* ENOMEM */
413609e6105fSMark Johnston 				return (-1);
413703836978SPedro F. Giffuni 		}
413803836978SPedro F. Giffuni 
413909e6105fSMark Johnston 		/* Retrieve data from each CPU. */
414009e6105fSMark Johnston 		(void) dtrace_getopt(dtp, "bufsize", &size);
414109e6105fSMark Johnston 		for (i = 0; i < max_ncpus; i++) {
414209e6105fSMark Johnston 			dtrace_bufdesc_t *buf;
414309e6105fSMark Johnston 
414409e6105fSMark Johnston 			if (dt_get_buf(dtp, i, &buf) != 0)
414509e6105fSMark Johnston 				return (-1);
414609e6105fSMark Johnston 			if (buf != NULL) {
414709e6105fSMark Johnston 				if (first_timestamp == 0)
414809e6105fSMark Johnston 					first_timestamp = buf->dtbd_timestamp;
414909e6105fSMark Johnston 				assert(buf->dtbd_timestamp >= first_timestamp);
415009e6105fSMark Johnston 
415109e6105fSMark Johnston 				dt_pq_insert(dtp->dt_bufq, buf);
415209e6105fSMark Johnston 				drops[i] = buf->dtbd_drops;
415309e6105fSMark Johnston 				buf->dtbd_drops = 0;
415409e6105fSMark Johnston 			}
415509e6105fSMark Johnston 		}
415609e6105fSMark Johnston 
415709e6105fSMark Johnston 		/* Consume records. */
415809e6105fSMark Johnston 		for (;;) {
415909e6105fSMark Johnston 			dtrace_bufdesc_t *buf = dt_pq_pop(dtp->dt_bufq);
416009e6105fSMark Johnston 			uint64_t timestamp;
416109e6105fSMark Johnston 
416209e6105fSMark Johnston 			if (buf == NULL)
416309e6105fSMark Johnston 				break;
416409e6105fSMark Johnston 
416509e6105fSMark Johnston 			timestamp = dt_buf_oldest(buf, dtp);
416609e6105fSMark Johnston 			if (timestamp == buf->dtbd_timestamp) {
416709e6105fSMark Johnston 				/*
416809e6105fSMark Johnston 				 * We've reached the end of the time covered
416909e6105fSMark Johnston 				 * by this buffer.  If this is the oldest
417009e6105fSMark Johnston 				 * buffer, we must do another pass
417109e6105fSMark Johnston 				 * to retrieve more data.
417209e6105fSMark Johnston 				 */
417309e6105fSMark Johnston 				dt_put_buf(dtp, buf);
417409e6105fSMark Johnston 				if (timestamp == first_timestamp &&
417509e6105fSMark Johnston 				    !dtp->dt_stopped)
417609e6105fSMark Johnston 					break;
417709e6105fSMark Johnston 				continue;
417809e6105fSMark Johnston 			}
41799747bd8eSMark Johnston 			assert(timestamp >= dtp->dt_last_timestamp);
41809747bd8eSMark Johnston 			dtp->dt_last_timestamp = timestamp;
418109e6105fSMark Johnston 
418209e6105fSMark Johnston 			if ((rval = dt_consume_cpu(dtp, fp,
418309e6105fSMark Johnston 			    buf->dtbd_cpu, buf, B_TRUE, pf, rf, arg)) != 0)
418409e6105fSMark Johnston 				return (rval);
418509e6105fSMark Johnston 			dt_pq_insert(dtp->dt_bufq, buf);
418609e6105fSMark Johnston 		}
418709e6105fSMark Johnston 
418809e6105fSMark Johnston 		/* Consume drops. */
418909e6105fSMark Johnston 		for (i = 0; i < max_ncpus; i++) {
419009e6105fSMark Johnston 			if (drops[i] != 0) {
419193f27766SDomagoj Stolfa 				int error;
41921bb8b1d7SMark Johnston 
41931bb8b1d7SMark Johnston 				if (dtp->dt_oformat) {
419493f27766SDomagoj Stolfa 					xo_open_instance("probes");
419593f27766SDomagoj Stolfa 					dt_oformat_drop(dtp, i);
41961bb8b1d7SMark Johnston 				}
419793f27766SDomagoj Stolfa 				error = dt_handle_cpudrop(dtp, i,
419809e6105fSMark Johnston 				    DTRACEDROP_PRINCIPAL, drops[i]);
41991bb8b1d7SMark Johnston 				if (dtp->dt_oformat)
420093f27766SDomagoj Stolfa 					xo_close_instance("probes");
420109e6105fSMark Johnston 				if (error != 0)
420209e6105fSMark Johnston 					return (error);
420309e6105fSMark Johnston 			}
420409e6105fSMark Johnston 		}
420509e6105fSMark Johnston 
420609e6105fSMark Johnston 		/*
420709e6105fSMark Johnston 		 * Reduce memory usage by re-allocating smaller buffers
420809e6105fSMark Johnston 		 * for the "remnants".
420909e6105fSMark Johnston 		 */
421009e6105fSMark Johnston 		while (buf = dt_pq_walk(dtp->dt_bufq, &cookie))
421109e6105fSMark Johnston 			dt_realloc_buf(dtp, buf, buf->dtbd_size);
421209e6105fSMark Johnston 	}
421309e6105fSMark Johnston 
421409e6105fSMark Johnston 	return (0);
42156ff6d951SJohn Birrell }
421693f27766SDomagoj Stolfa 
421793f27766SDomagoj Stolfa void
421893f27766SDomagoj Stolfa dtrace_oformat_probe(dtrace_hdl_t *dtp __unused, const dtrace_probedata_t *data,
421993f27766SDomagoj Stolfa     processorid_t cpu, dtrace_probedesc_t *pd)
422093f27766SDomagoj Stolfa {
422193f27766SDomagoj Stolfa 
422293f27766SDomagoj Stolfa 	xo_emit("{:timestamp/%llu} {:cpu/%d} {:id/%d} {:provider/%s} "
422393f27766SDomagoj Stolfa 		"{:module/%s} {:function/%s} {:name/%s}",
422493f27766SDomagoj Stolfa 	    (unsigned long long)data->dtpda_timestamp, cpu, pd->dtpd_id,
422593f27766SDomagoj Stolfa 	    pd->dtpd_provider, pd->dtpd_mod, pd->dtpd_func, pd->dtpd_name);
422693f27766SDomagoj Stolfa }
422793f27766SDomagoj Stolfa 
422893f27766SDomagoj Stolfa void
422993f27766SDomagoj Stolfa dt_oformat_drop(dtrace_hdl_t *dtp, processorid_t cpu)
423093f27766SDomagoj Stolfa {
423193f27766SDomagoj Stolfa 	xo_emit("{:cpu/%d} {:id/%d} {:provider/%s} "
423293f27766SDomagoj Stolfa 		"{:module/%s} {:function/%s} {:name/%s}",
423393f27766SDomagoj Stolfa 	    cpu, -1, "dtrace", "INTERNAL", "INTERNAL", "DROP");
423493f27766SDomagoj Stolfa }
4235