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