10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
55984Sjhaslam * Common Development and Distribution License (the "License").
65984Sjhaslam * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*10791SJonathan.Haslam@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <strings.h>
280Sstevel@tonic-gate #include <errno.h>
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <limits.h>
310Sstevel@tonic-gate #include <assert.h>
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <alloca.h>
34457Sbmc #include <dt_impl.h>
350Sstevel@tonic-gate
365984Sjhaslam #define DT_MASK_LO 0x00000000FFFFFFFFULL
375984Sjhaslam
38457Sbmc /*
39457Sbmc * We declare this here because (1) we need it and (2) we want to avoid a
40457Sbmc * dependency on libm in libdtrace.
41457Sbmc */
42457Sbmc static long double
dt_fabsl(long double x)43457Sbmc dt_fabsl(long double x)
44457Sbmc {
45457Sbmc if (x < 0)
46457Sbmc return (-x);
47457Sbmc
48457Sbmc return (x);
49457Sbmc }
500Sstevel@tonic-gate
515984Sjhaslam /*
525984Sjhaslam * 128-bit arithmetic functions needed to support the stddev() aggregating
535984Sjhaslam * action.
545984Sjhaslam */
555984Sjhaslam static int
dt_gt_128(uint64_t * a,uint64_t * b)565984Sjhaslam dt_gt_128(uint64_t *a, uint64_t *b)
575984Sjhaslam {
585984Sjhaslam return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0]));
595984Sjhaslam }
605984Sjhaslam
615984Sjhaslam static int
dt_ge_128(uint64_t * a,uint64_t * b)625984Sjhaslam dt_ge_128(uint64_t *a, uint64_t *b)
635984Sjhaslam {
645984Sjhaslam return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0]));
655984Sjhaslam }
665984Sjhaslam
675984Sjhaslam static int
dt_le_128(uint64_t * a,uint64_t * b)685984Sjhaslam dt_le_128(uint64_t *a, uint64_t *b)
695984Sjhaslam {
705984Sjhaslam return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0]));
715984Sjhaslam }
725984Sjhaslam
735984Sjhaslam /*
745984Sjhaslam * Shift the 128-bit value in a by b. If b is positive, shift left.
755984Sjhaslam * If b is negative, shift right.
765984Sjhaslam */
775984Sjhaslam static void
dt_shift_128(uint64_t * a,int b)785984Sjhaslam dt_shift_128(uint64_t *a, int b)
795984Sjhaslam {
805984Sjhaslam uint64_t mask;
815984Sjhaslam
825984Sjhaslam if (b == 0)
835984Sjhaslam return;
845984Sjhaslam
855984Sjhaslam if (b < 0) {
865984Sjhaslam b = -b;
875984Sjhaslam if (b >= 64) {
885984Sjhaslam a[0] = a[1] >> (b - 64);
895984Sjhaslam a[1] = 0;
905984Sjhaslam } else {
915984Sjhaslam a[0] >>= b;
925984Sjhaslam mask = 1LL << (64 - b);
935984Sjhaslam mask -= 1;
945984Sjhaslam a[0] |= ((a[1] & mask) << (64 - b));
955984Sjhaslam a[1] >>= b;
965984Sjhaslam }
975984Sjhaslam } else {
985984Sjhaslam if (b >= 64) {
995984Sjhaslam a[1] = a[0] << (b - 64);
1005984Sjhaslam a[0] = 0;
1015984Sjhaslam } else {
1025984Sjhaslam a[1] <<= b;
1035984Sjhaslam mask = a[0] >> (64 - b);
1045984Sjhaslam a[1] |= mask;
1055984Sjhaslam a[0] <<= b;
1065984Sjhaslam }
1075984Sjhaslam }
1085984Sjhaslam }
1095984Sjhaslam
1105984Sjhaslam static int
dt_nbits_128(uint64_t * a)1115984Sjhaslam dt_nbits_128(uint64_t *a)
1125984Sjhaslam {
1135984Sjhaslam int nbits = 0;
1145984Sjhaslam uint64_t tmp[2];
1155984Sjhaslam uint64_t zero[2] = { 0, 0 };
1165984Sjhaslam
1175984Sjhaslam tmp[0] = a[0];
1185984Sjhaslam tmp[1] = a[1];
1195984Sjhaslam
1205984Sjhaslam dt_shift_128(tmp, -1);
1215984Sjhaslam while (dt_gt_128(tmp, zero)) {
1225984Sjhaslam dt_shift_128(tmp, -1);
1235984Sjhaslam nbits++;
1245984Sjhaslam }
1255984Sjhaslam
1265984Sjhaslam return (nbits);
1275984Sjhaslam }
1285984Sjhaslam
1295984Sjhaslam static void
dt_subtract_128(uint64_t * minuend,uint64_t * subtrahend,uint64_t * difference)1305984Sjhaslam dt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference)
1315984Sjhaslam {
1325984Sjhaslam uint64_t result[2];
1335984Sjhaslam
1345984Sjhaslam result[0] = minuend[0] - subtrahend[0];
1355984Sjhaslam result[1] = minuend[1] - subtrahend[1] -
1365984Sjhaslam (minuend[0] < subtrahend[0] ? 1 : 0);
1375984Sjhaslam
1385984Sjhaslam difference[0] = result[0];
1395984Sjhaslam difference[1] = result[1];
1405984Sjhaslam }
1415984Sjhaslam
1425984Sjhaslam static void
dt_add_128(uint64_t * addend1,uint64_t * addend2,uint64_t * sum)1435984Sjhaslam dt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum)
1445984Sjhaslam {
1455984Sjhaslam uint64_t result[2];
1465984Sjhaslam
1475984Sjhaslam result[0] = addend1[0] + addend2[0];
1485984Sjhaslam result[1] = addend1[1] + addend2[1] +
1495984Sjhaslam (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0);
1505984Sjhaslam
1515984Sjhaslam sum[0] = result[0];
1525984Sjhaslam sum[1] = result[1];
1535984Sjhaslam }
1545984Sjhaslam
1555984Sjhaslam /*
1565984Sjhaslam * The basic idea is to break the 2 64-bit values into 4 32-bit values,
1575984Sjhaslam * use native multiplication on those, and then re-combine into the
1585984Sjhaslam * resulting 128-bit value.
1595984Sjhaslam *
1605984Sjhaslam * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) =
1615984Sjhaslam * hi1 * hi2 << 64 +
1625984Sjhaslam * hi1 * lo2 << 32 +
1635984Sjhaslam * hi2 * lo1 << 32 +
1645984Sjhaslam * lo1 * lo2
1655984Sjhaslam */
1665984Sjhaslam static void
dt_multiply_128(uint64_t factor1,uint64_t factor2,uint64_t * product)1675984Sjhaslam dt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product)
1685984Sjhaslam {
1695984Sjhaslam uint64_t hi1, hi2, lo1, lo2;
1705984Sjhaslam uint64_t tmp[2];
1715984Sjhaslam
1725984Sjhaslam hi1 = factor1 >> 32;
1735984Sjhaslam hi2 = factor2 >> 32;
1745984Sjhaslam
1755984Sjhaslam lo1 = factor1 & DT_MASK_LO;
1765984Sjhaslam lo2 = factor2 & DT_MASK_LO;
1775984Sjhaslam
1785984Sjhaslam product[0] = lo1 * lo2;
1795984Sjhaslam product[1] = hi1 * hi2;
1805984Sjhaslam
1815984Sjhaslam tmp[0] = hi1 * lo2;
1825984Sjhaslam tmp[1] = 0;
1835984Sjhaslam dt_shift_128(tmp, 32);
1845984Sjhaslam dt_add_128(product, tmp, product);
1855984Sjhaslam
1865984Sjhaslam tmp[0] = hi2 * lo1;
1875984Sjhaslam tmp[1] = 0;
1885984Sjhaslam dt_shift_128(tmp, 32);
1895984Sjhaslam dt_add_128(product, tmp, product);
1905984Sjhaslam }
1915984Sjhaslam
1925984Sjhaslam /*
1935984Sjhaslam * This is long-hand division.
1945984Sjhaslam *
1955984Sjhaslam * We initialize subtrahend by shifting divisor left as far as possible. We
1965984Sjhaslam * loop, comparing subtrahend to dividend: if subtrahend is smaller, we
1975984Sjhaslam * subtract and set the appropriate bit in the result. We then shift
1985984Sjhaslam * subtrahend right by one bit for the next comparison.
1995984Sjhaslam */
2005984Sjhaslam static void
dt_divide_128(uint64_t * dividend,uint64_t divisor,uint64_t * quotient)2015984Sjhaslam dt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient)
2025984Sjhaslam {
2035984Sjhaslam uint64_t result[2] = { 0, 0 };
2045984Sjhaslam uint64_t remainder[2];
2055984Sjhaslam uint64_t subtrahend[2];
2065984Sjhaslam uint64_t divisor_128[2];
2075984Sjhaslam uint64_t mask[2] = { 1, 0 };
2085984Sjhaslam int log = 0;
2095984Sjhaslam
2105984Sjhaslam assert(divisor != 0);
2115984Sjhaslam
2125984Sjhaslam divisor_128[0] = divisor;
2135984Sjhaslam divisor_128[1] = 0;
2145984Sjhaslam
2155984Sjhaslam remainder[0] = dividend[0];
2165984Sjhaslam remainder[1] = dividend[1];
2175984Sjhaslam
2185984Sjhaslam subtrahend[0] = divisor;
2195984Sjhaslam subtrahend[1] = 0;
2205984Sjhaslam
2215984Sjhaslam while (divisor > 0) {
2225984Sjhaslam log++;
2235984Sjhaslam divisor >>= 1;
2245984Sjhaslam }
2255984Sjhaslam
2265984Sjhaslam dt_shift_128(subtrahend, 128 - log);
2275984Sjhaslam dt_shift_128(mask, 128 - log);
2285984Sjhaslam
2295984Sjhaslam while (dt_ge_128(remainder, divisor_128)) {
2305984Sjhaslam if (dt_ge_128(remainder, subtrahend)) {
2315984Sjhaslam dt_subtract_128(remainder, subtrahend, remainder);
2325984Sjhaslam result[0] |= mask[0];
2335984Sjhaslam result[1] |= mask[1];
2345984Sjhaslam }
2355984Sjhaslam
2365984Sjhaslam dt_shift_128(subtrahend, -1);
2375984Sjhaslam dt_shift_128(mask, -1);
2385984Sjhaslam }
2395984Sjhaslam
2405984Sjhaslam quotient[0] = result[0];
2415984Sjhaslam quotient[1] = result[1];
2425984Sjhaslam }
2435984Sjhaslam
2445984Sjhaslam /*
2455984Sjhaslam * This is the long-hand method of calculating a square root.
2465984Sjhaslam * The algorithm is as follows:
2475984Sjhaslam *
2485984Sjhaslam * 1. Group the digits by 2 from the right.
2495984Sjhaslam * 2. Over the leftmost group, find the largest single-digit number
2505984Sjhaslam * whose square is less than that group.
2515984Sjhaslam * 3. Subtract the result of the previous step (2 or 4, depending) and
2525984Sjhaslam * bring down the next two-digit group.
2535984Sjhaslam * 4. For the result R we have so far, find the largest single-digit number
2545984Sjhaslam * x such that 2 * R * 10 * x + x^2 is less than the result from step 3.
2555984Sjhaslam * (Note that this is doubling R and performing a decimal left-shift by 1
2565984Sjhaslam * and searching for the appropriate decimal to fill the one's place.)
2575984Sjhaslam * The value x is the next digit in the square root.
2585984Sjhaslam * Repeat steps 3 and 4 until the desired precision is reached. (We're
2595984Sjhaslam * dealing with integers, so the above is sufficient.)
2605984Sjhaslam *
2615984Sjhaslam * In decimal, the square root of 582,734 would be calculated as so:
2625984Sjhaslam *
2635984Sjhaslam * __7__6__3
2645984Sjhaslam * | 58 27 34
2655984Sjhaslam * -49 (7^2 == 49 => 7 is the first digit in the square root)
2665984Sjhaslam * --
2675984Sjhaslam * 9 27 (Subtract and bring down the next group.)
2685984Sjhaslam * 146 8 76 (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in
2695984Sjhaslam * ----- the square root)
2705984Sjhaslam * 51 34 (Subtract and bring down the next group.)
2715984Sjhaslam * 1523 45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in
2725984Sjhaslam * ----- the square root)
2735984Sjhaslam * 5 65 (remainder)
2745984Sjhaslam *
2755984Sjhaslam * The above algorithm applies similarly in binary, but note that the
2765984Sjhaslam * only possible non-zero value for x in step 4 is 1, so step 4 becomes a
2775984Sjhaslam * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the
2785984Sjhaslam * preceding difference?
2795984Sjhaslam *
2805984Sjhaslam * In binary, the square root of 11011011 would be calculated as so:
2815984Sjhaslam *
2825984Sjhaslam * __1__1__1__0
2835984Sjhaslam * | 11 01 10 11
2845984Sjhaslam * 01 (0 << 2 + 1 == 1 < 11 => this bit is 1)
2855984Sjhaslam * --
2865984Sjhaslam * 10 01 10 11
2875984Sjhaslam * 101 1 01 (1 << 2 + 1 == 101 < 1001 => next bit is 1)
2885984Sjhaslam * -----
2895984Sjhaslam * 1 00 10 11
2905984Sjhaslam * 1101 11 01 (11 << 2 + 1 == 1101 < 10010 => next bit is 1)
2915984Sjhaslam * -------
2925984Sjhaslam * 1 01 11
2935984Sjhaslam * 11101 1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0)
2945984Sjhaslam *
2955984Sjhaslam */
2965984Sjhaslam static uint64_t
dt_sqrt_128(uint64_t * square)2975984Sjhaslam dt_sqrt_128(uint64_t *square)
2985984Sjhaslam {
2995984Sjhaslam uint64_t result[2] = { 0, 0 };
3005984Sjhaslam uint64_t diff[2] = { 0, 0 };
3015984Sjhaslam uint64_t one[2] = { 1, 0 };
3025984Sjhaslam uint64_t next_pair[2];
3035984Sjhaslam uint64_t next_try[2];
3045984Sjhaslam uint64_t bit_pairs, pair_shift;
3055984Sjhaslam int i;
3065984Sjhaslam
3075984Sjhaslam bit_pairs = dt_nbits_128(square) / 2;
3085984Sjhaslam pair_shift = bit_pairs * 2;
3095984Sjhaslam
3105984Sjhaslam for (i = 0; i <= bit_pairs; i++) {
3115984Sjhaslam /*
3125984Sjhaslam * Bring down the next pair of bits.
3135984Sjhaslam */
3145984Sjhaslam next_pair[0] = square[0];
3155984Sjhaslam next_pair[1] = square[1];
3165984Sjhaslam dt_shift_128(next_pair, -pair_shift);
3175984Sjhaslam next_pair[0] &= 0x3;
3185984Sjhaslam next_pair[1] = 0;
3195984Sjhaslam
3205984Sjhaslam dt_shift_128(diff, 2);
3215984Sjhaslam dt_add_128(diff, next_pair, diff);
3225984Sjhaslam
3235984Sjhaslam /*
3245984Sjhaslam * next_try = R << 2 + 1
3255984Sjhaslam */
3265984Sjhaslam next_try[0] = result[0];
3275984Sjhaslam next_try[1] = result[1];
3285984Sjhaslam dt_shift_128(next_try, 2);
3295984Sjhaslam dt_add_128(next_try, one, next_try);
3305984Sjhaslam
3315984Sjhaslam if (dt_le_128(next_try, diff)) {
3325984Sjhaslam dt_subtract_128(diff, next_try, diff);
3335984Sjhaslam dt_shift_128(result, 1);
3345984Sjhaslam dt_add_128(result, one, result);
3355984Sjhaslam } else {
3365984Sjhaslam dt_shift_128(result, 1);
3375984Sjhaslam }
3385984Sjhaslam
3395984Sjhaslam pair_shift -= 2;
3405984Sjhaslam }
3415984Sjhaslam
3425984Sjhaslam assert(result[1] == 0);
3435984Sjhaslam
3445984Sjhaslam return (result[0]);
3455984Sjhaslam }
3465984Sjhaslam
3475984Sjhaslam uint64_t
dt_stddev(uint64_t * data,uint64_t normal)3485984Sjhaslam dt_stddev(uint64_t *data, uint64_t normal)
3495984Sjhaslam {
3505984Sjhaslam uint64_t avg_of_squares[2];
3515984Sjhaslam uint64_t square_of_avg[2];
3525984Sjhaslam int64_t norm_avg;
3535984Sjhaslam uint64_t diff[2];
3545984Sjhaslam
3555984Sjhaslam /*
3565984Sjhaslam * The standard approximation for standard deviation is
3575984Sjhaslam * sqrt(average(x**2) - average(x)**2), i.e. the square root
3585984Sjhaslam * of the average of the squares minus the square of the average.
3595984Sjhaslam */
3605984Sjhaslam dt_divide_128(data + 2, normal, avg_of_squares);
3615984Sjhaslam dt_divide_128(avg_of_squares, data[0], avg_of_squares);
3625984Sjhaslam
3635984Sjhaslam norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0];
3645984Sjhaslam
3655984Sjhaslam if (norm_avg < 0)
3665984Sjhaslam norm_avg = -norm_avg;
3675984Sjhaslam
3685984Sjhaslam dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg);
3695984Sjhaslam
3705984Sjhaslam dt_subtract_128(avg_of_squares, square_of_avg, diff);
3715984Sjhaslam
3725984Sjhaslam return (dt_sqrt_128(diff));
3735984Sjhaslam }
3745984Sjhaslam
3750Sstevel@tonic-gate static int
dt_flowindent(dtrace_hdl_t * dtp,dtrace_probedata_t * data,dtrace_epid_t last,dtrace_bufdesc_t * buf,size_t offs)3760Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
3770Sstevel@tonic-gate dtrace_bufdesc_t *buf, size_t offs)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd;
3800Sstevel@tonic-gate dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd;
381457Sbmc char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub;
3820Sstevel@tonic-gate dtrace_flowkind_t flow = DTRACEFLOW_NONE;
3830Sstevel@tonic-gate const char *str = NULL;
3840Sstevel@tonic-gate static const char *e_str[2] = { " -> ", " => " };
3850Sstevel@tonic-gate static const char *r_str[2] = { " <- ", " <= " };
386457Sbmc static const char *ent = "entry", *ret = "return";
387457Sbmc static int entlen = 0, retlen = 0;
3880Sstevel@tonic-gate dtrace_epid_t next, id = epd->dtepd_epid;
3890Sstevel@tonic-gate int rval;
3900Sstevel@tonic-gate
391457Sbmc if (entlen == 0) {
392457Sbmc assert(retlen == 0);
393457Sbmc entlen = strlen(ent);
394457Sbmc retlen = strlen(ret);
395457Sbmc }
396457Sbmc
397457Sbmc /*
398457Sbmc * If the name of the probe is "entry" or ends with "-entry", we
399457Sbmc * treat it as an entry; if it is "return" or ends with "-return",
400457Sbmc * we treat it as a return. (This allows application-provided probes
401457Sbmc * like "method-entry" or "function-entry" to participate in flow
402457Sbmc * indentation -- without accidentally misinterpreting popular probe
403457Sbmc * names like "carpentry", "gentry" or "Coventry".)
404457Sbmc */
405457Sbmc if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' &&
406457Sbmc (sub == n || sub[-1] == '-')) {
4070Sstevel@tonic-gate flow = DTRACEFLOW_ENTRY;
4080Sstevel@tonic-gate str = e_str[strcmp(p, "syscall") == 0];
409457Sbmc } else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' &&
410457Sbmc (sub == n || sub[-1] == '-')) {
4110Sstevel@tonic-gate flow = DTRACEFLOW_RETURN;
4120Sstevel@tonic-gate str = r_str[strcmp(p, "syscall") == 0];
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate /*
4160Sstevel@tonic-gate * If we're going to indent this, we need to check the ID of our last
4170Sstevel@tonic-gate * call. If we're looking at the same probe ID but a different EPID,
4180Sstevel@tonic-gate * we _don't_ want to indent. (Yes, there are some minor holes in
4190Sstevel@tonic-gate * this scheme -- it's a heuristic.)
4200Sstevel@tonic-gate */
4210Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY) {
4220Sstevel@tonic-gate if ((last != DTRACE_EPIDNONE && id != last &&
4230Sstevel@tonic-gate pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id))
4240Sstevel@tonic-gate flow = DTRACEFLOW_NONE;
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate * If we're going to unindent this, it's more difficult to see if
4290Sstevel@tonic-gate * we don't actually want to unindent it -- we need to look at the
4300Sstevel@tonic-gate * _next_ EPID.
4310Sstevel@tonic-gate */
4320Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN) {
4330Sstevel@tonic-gate offs += epd->dtepd_size;
4340Sstevel@tonic-gate
4350Sstevel@tonic-gate do {
4360Sstevel@tonic-gate if (offs >= buf->dtbd_size) {
4370Sstevel@tonic-gate /*
4380Sstevel@tonic-gate * We're at the end -- maybe. If the oldest
4390Sstevel@tonic-gate * record is non-zero, we need to wrap.
4400Sstevel@tonic-gate */
4410Sstevel@tonic-gate if (buf->dtbd_oldest != 0) {
4420Sstevel@tonic-gate offs = 0;
4430Sstevel@tonic-gate } else {
4440Sstevel@tonic-gate goto out;
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate if (next == DTRACE_EPIDNONE)
4510Sstevel@tonic-gate offs += sizeof (id);
4520Sstevel@tonic-gate } while (next == DTRACE_EPIDNONE);
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0)
4550Sstevel@tonic-gate return (rval);
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate if (next != id && npd->dtpd_id == pd->dtpd_id)
4580Sstevel@tonic-gate flow = DTRACEFLOW_NONE;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate out:
4620Sstevel@tonic-gate if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) {
4630Sstevel@tonic-gate data->dtpda_prefix = str;
4640Sstevel@tonic-gate } else {
4650Sstevel@tonic-gate data->dtpda_prefix = "| ";
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0)
4690Sstevel@tonic-gate data->dtpda_indent -= 2;
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate data->dtpda_flow = flow;
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate return (0);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate static int
dt_nullprobe()4770Sstevel@tonic-gate dt_nullprobe()
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate return (DTRACE_CONSUME_THIS);
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate static int
dt_nullrec()4830Sstevel@tonic-gate dt_nullrec()
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate int
dt_print_quantline(dtrace_hdl_t * dtp,FILE * fp,int64_t val,uint64_t normal,long double total,char positives,char negatives)489457Sbmc dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
490457Sbmc uint64_t normal, long double total, char positives, char negatives)
491457Sbmc {
492457Sbmc long double f;
493457Sbmc uint_t depth, len = 40;
494457Sbmc
495457Sbmc const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
496457Sbmc const char *spaces = " ";
497457Sbmc
498457Sbmc assert(strlen(ats) == len && strlen(spaces) == len);
499457Sbmc assert(!(total == 0 && (positives || negatives)));
500457Sbmc assert(!(val < 0 && !negatives));
501457Sbmc assert(!(val > 0 && !positives));
502457Sbmc assert(!(val != 0 && total == 0));
503457Sbmc
504457Sbmc if (!negatives) {
505457Sbmc if (positives) {
506457Sbmc f = (dt_fabsl((long double)val) * len) / total;
507457Sbmc depth = (uint_t)(f + 0.5);
508457Sbmc } else {
509457Sbmc depth = 0;
510457Sbmc }
511457Sbmc
512457Sbmc return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth,
513457Sbmc spaces + depth, (long long)val / normal));
514457Sbmc }
515457Sbmc
516457Sbmc if (!positives) {
517457Sbmc f = (dt_fabsl((long double)val) * len) / total;
518457Sbmc depth = (uint_t)(f + 0.5);
519457Sbmc
520457Sbmc return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth,
521457Sbmc ats + len - depth, (long long)val / normal));
522457Sbmc }
523457Sbmc
524457Sbmc /*
525457Sbmc * If we're here, we have both positive and negative bucket values.
526457Sbmc * To express this graphically, we're going to generate both positive
527457Sbmc * and negative bars separated by a centerline. These bars are half
528457Sbmc * the size of normal quantize()/lquantize() bars, so we divide the
529457Sbmc * length in half before calculating the bar length.
530457Sbmc */
531457Sbmc len /= 2;
532457Sbmc ats = &ats[len];
533457Sbmc spaces = &spaces[len];
534457Sbmc
535457Sbmc f = (dt_fabsl((long double)val) * len) / total;
536457Sbmc depth = (uint_t)(f + 0.5);
537457Sbmc
538457Sbmc if (val <= 0) {
539457Sbmc return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth,
540457Sbmc ats + len - depth, len, "", (long long)val / normal));
541457Sbmc } else {
542457Sbmc return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "",
543457Sbmc ats + len - depth, spaces + depth,
544457Sbmc (long long)val / normal));
545457Sbmc }
546457Sbmc }
547457Sbmc
548457Sbmc int
dt_print_quantize(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,uint64_t normal)5490Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
5500Sstevel@tonic-gate size_t size, uint64_t normal)
5510Sstevel@tonic-gate {
552457Sbmc const int64_t *data = addr;
5530Sstevel@tonic-gate int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
554457Sbmc long double total = 0;
555457Sbmc char positives = 0, negatives = 0;
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
5580Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH));
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
5610Sstevel@tonic-gate first_bin++;
5620Sstevel@tonic-gate
563457Sbmc if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) {
564457Sbmc /*
565457Sbmc * There isn't any data. This is possible if (and only if)
566457Sbmc * negative increment values have been used. In this case,
567457Sbmc * we'll print the buckets around 0.
568457Sbmc */
569457Sbmc first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1;
570457Sbmc last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1;
571457Sbmc } else {
572457Sbmc if (first_bin > 0)
573457Sbmc first_bin--;
5740Sstevel@tonic-gate
575457Sbmc while (last_bin > 0 && data[last_bin] == 0)
576457Sbmc last_bin--;
5770Sstevel@tonic-gate
578457Sbmc if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
579457Sbmc last_bin++;
580457Sbmc }
581457Sbmc
582457Sbmc for (i = first_bin; i <= last_bin; i++) {
583457Sbmc positives |= (data[i] > 0);
584457Sbmc negatives |= (data[i] < 0);
585457Sbmc total += dt_fabsl((long double)data[i]);
586457Sbmc }
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
5890Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0)
5900Sstevel@tonic-gate return (-1);
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) {
593457Sbmc if (dt_printf(dtp, fp, "%16lld ",
594457Sbmc (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0)
595457Sbmc return (-1);
5960Sstevel@tonic-gate
597457Sbmc if (dt_print_quantline(dtp, fp, data[i], normal, total,
598457Sbmc positives, negatives) < 0)
5990Sstevel@tonic-gate return (-1);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate
6020Sstevel@tonic-gate return (0);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate int
dt_print_lquantize(dtrace_hdl_t * dtp,FILE * fp,const void * addr,size_t size,uint64_t normal)6060Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
6070Sstevel@tonic-gate size_t size, uint64_t normal)
6080Sstevel@tonic-gate {
609457Sbmc const int64_t *data = addr;
6100Sstevel@tonic-gate int i, first_bin, last_bin, base;
611457Sbmc uint64_t arg;
612457Sbmc long double total = 0;
6130Sstevel@tonic-gate uint16_t step, levels;
614457Sbmc char positives = 0, negatives = 0;
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate if (size < sizeof (uint64_t))
6170Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH));
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate arg = *data++;
6200Sstevel@tonic-gate size -= sizeof (uint64_t);
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate base = DTRACE_LQUANTIZE_BASE(arg);
6230Sstevel@tonic-gate step = DTRACE_LQUANTIZE_STEP(arg);
6240Sstevel@tonic-gate levels = DTRACE_LQUANTIZE_LEVELS(arg);
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate first_bin = 0;
6270Sstevel@tonic-gate last_bin = levels + 1;
6280Sstevel@tonic-gate
6290Sstevel@tonic-gate if (size != sizeof (uint64_t) * (levels + 2))
6300Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DMISMATCH));
6310Sstevel@tonic-gate
632491Sbmc while (first_bin <= levels + 1 && data[first_bin] == 0)
6330Sstevel@tonic-gate first_bin++;
6340Sstevel@tonic-gate
635491Sbmc if (first_bin > levels + 1) {
636457Sbmc first_bin = 0;
637457Sbmc last_bin = 2;
638457Sbmc } else {
639457Sbmc if (first_bin > 0)
640457Sbmc first_bin--;
6410Sstevel@tonic-gate
642457Sbmc while (last_bin > 0 && data[last_bin] == 0)
643457Sbmc last_bin--;
6440Sstevel@tonic-gate
645457Sbmc if (last_bin < levels + 1)
646457Sbmc last_bin++;
647457Sbmc }
6480Sstevel@tonic-gate
649457Sbmc for (i = first_bin; i <= last_bin; i++) {
650457Sbmc positives |= (data[i] > 0);
651457Sbmc negatives |= (data[i] < 0);
652457Sbmc total += dt_fabsl((long double)data[i]);
653457Sbmc }
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
6560Sstevel@tonic-gate "------------- Distribution -------------", "count") < 0)
6570Sstevel@tonic-gate return (-1);
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate for (i = first_bin; i <= last_bin; i++) {
6600Sstevel@tonic-gate char c[32];
6610Sstevel@tonic-gate int err;
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate if (i == 0) {
6640Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "< %d",
6650Sstevel@tonic-gate base / (uint32_t)normal);
6660Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c);
6670Sstevel@tonic-gate } else if (i == levels + 1) {
6680Sstevel@tonic-gate (void) snprintf(c, sizeof (c), ">= %d",
6690Sstevel@tonic-gate base + (levels * step));
6700Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16s ", c);
6710Sstevel@tonic-gate } else {
6720Sstevel@tonic-gate err = dt_printf(dtp, fp, "%16d ",
6730Sstevel@tonic-gate base + (i - 1) * step);
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate
676457Sbmc if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal,
677457Sbmc total, positives, negatives) < 0)
6780Sstevel@tonic-gate return (-1);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate return (0);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate /*ARGSUSED*/
6850Sstevel@tonic-gate static int
dt_print_average(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,size_t size,uint64_t normal)6860Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
6870Sstevel@tonic-gate size_t size, uint64_t normal)
6880Sstevel@tonic-gate {
6890Sstevel@tonic-gate /* LINTED - alignment */
6905984Sjhaslam int64_t *data = (int64_t *)addr;
6915984Sjhaslam
6925984Sjhaslam return (dt_printf(dtp, fp, " %16lld", data[0] ?
6935984Sjhaslam (long long)(data[1] / (int64_t)normal / data[0]) : 0));
6945984Sjhaslam }
6955984Sjhaslam
6965984Sjhaslam /*ARGSUSED*/
6975984Sjhaslam static int
dt_print_stddev(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,size_t size,uint64_t normal)6985984Sjhaslam dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
6995984Sjhaslam size_t size, uint64_t normal)
7005984Sjhaslam {
7015984Sjhaslam /* LINTED - alignment */
7020Sstevel@tonic-gate uint64_t *data = (uint64_t *)addr;
7030Sstevel@tonic-gate
7045984Sjhaslam return (dt_printf(dtp, fp, " %16llu", data[0] ?
7055984Sjhaslam (unsigned long long) dt_stddev(data, normal) : 0));
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate /*ARGSUSED*/
7090Sstevel@tonic-gate int
dt_print_bytes(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,size_t nbytes,int width,int quiet)7100Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
7110Sstevel@tonic-gate size_t nbytes, int width, int quiet)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate /*
7140Sstevel@tonic-gate * If the byte stream is a series of printable characters, followed by
7150Sstevel@tonic-gate * a terminating byte, we print it out as a string. Otherwise, we
7160Sstevel@tonic-gate * assume that it's something else and just print the bytes.
7170Sstevel@tonic-gate */
7180Sstevel@tonic-gate int i, j, margin = 5;
7190Sstevel@tonic-gate char *c = (char *)addr;
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate if (nbytes == 0)
7220Sstevel@tonic-gate return (0);
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
7250Sstevel@tonic-gate goto raw;
7260Sstevel@tonic-gate
7270Sstevel@tonic-gate for (i = 0; i < nbytes; i++) {
7280Sstevel@tonic-gate /*
7290Sstevel@tonic-gate * We define a "printable character" to be one for which
7300Sstevel@tonic-gate * isprint(3C) returns non-zero, isspace(3C) returns non-zero,
7310Sstevel@tonic-gate * or a character which is either backspace or the bell.
7320Sstevel@tonic-gate * Backspace and the bell are regrettably special because
7330Sstevel@tonic-gate * they fail the first two tests -- and yet they are entirely
7340Sstevel@tonic-gate * printable. These are the only two control characters that
7350Sstevel@tonic-gate * have meaning for the terminal and for which isprint(3C) and
7360Sstevel@tonic-gate * isspace(3C) return 0.
7370Sstevel@tonic-gate */
7380Sstevel@tonic-gate if (isprint(c[i]) || isspace(c[i]) ||
7390Sstevel@tonic-gate c[i] == '\b' || c[i] == '\a')
7400Sstevel@tonic-gate continue;
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate if (c[i] == '\0' && i > 0) {
7430Sstevel@tonic-gate /*
7440Sstevel@tonic-gate * This looks like it might be a string. Before we
7450Sstevel@tonic-gate * assume that it is indeed a string, check the
7460Sstevel@tonic-gate * remainder of the byte range; if it contains
7470Sstevel@tonic-gate * additional non-nul characters, we'll assume that
7480Sstevel@tonic-gate * it's a binary stream that just happens to look like
7490Sstevel@tonic-gate * a string, and we'll print out the individual bytes.
7500Sstevel@tonic-gate */
7510Sstevel@tonic-gate for (j = i + 1; j < nbytes; j++) {
7520Sstevel@tonic-gate if (c[j] != '\0')
7530Sstevel@tonic-gate break;
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate if (j != nbytes)
7570Sstevel@tonic-gate break;
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate if (quiet)
7600Sstevel@tonic-gate return (dt_printf(dtp, fp, "%s", c));
7610Sstevel@tonic-gate else
7620Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, c));
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate break;
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate
7680Sstevel@tonic-gate if (i == nbytes) {
7690Sstevel@tonic-gate /*
7700Sstevel@tonic-gate * The byte range is all printable characters, but there is
7710Sstevel@tonic-gate * no trailing nul byte. We'll assume that it's a string and
7720Sstevel@tonic-gate * print it as such.
7730Sstevel@tonic-gate */
7740Sstevel@tonic-gate char *s = alloca(nbytes + 1);
7750Sstevel@tonic-gate bcopy(c, s, nbytes);
7760Sstevel@tonic-gate s[nbytes] = '\0';
7770Sstevel@tonic-gate return (dt_printf(dtp, fp, " %-*s", width, s));
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate raw:
7810Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n%*s ", margin, "") < 0)
7820Sstevel@tonic-gate return (-1);
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate for (i = 0; i < 16; i++)
7850Sstevel@tonic-gate if (dt_printf(dtp, fp, " %c", "0123456789abcdef"[i]) < 0)
7860Sstevel@tonic-gate return (-1);
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate if (dt_printf(dtp, fp, " 0123456789abcdef\n") < 0)
7890Sstevel@tonic-gate return (-1);
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate for (i = 0; i < nbytes; i += 16) {
7930Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0)
7940Sstevel@tonic-gate return (-1);
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) {
7970Sstevel@tonic-gate if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0)
7980Sstevel@tonic-gate return (-1);
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate
8010Sstevel@tonic-gate while (j++ % 16) {
8020Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0)
8030Sstevel@tonic-gate return (-1);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate if (dt_printf(dtp, fp, " ") < 0)
8070Sstevel@tonic-gate return (-1);
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate for (j = i; j < i + 16 && j < nbytes; j++) {
8100Sstevel@tonic-gate if (dt_printf(dtp, fp, "%c",
8110Sstevel@tonic-gate c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0)
8120Sstevel@tonic-gate return (-1);
8130Sstevel@tonic-gate }
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0)
8160Sstevel@tonic-gate return (-1);
8170Sstevel@tonic-gate }
8180Sstevel@tonic-gate
8190Sstevel@tonic-gate return (0);
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate int
dt_print_stack(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr,int depth,int size)8230Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
824457Sbmc caddr_t addr, int depth, int size)
8250Sstevel@tonic-gate {
8260Sstevel@tonic-gate dtrace_syminfo_t dts;
8270Sstevel@tonic-gate GElf_Sym sym;
8280Sstevel@tonic-gate int i, indent;
8290Sstevel@tonic-gate char c[PATH_MAX * 2];
830457Sbmc uint64_t pc;
8310Sstevel@tonic-gate
8320Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0)
8330Sstevel@tonic-gate return (-1);
8340Sstevel@tonic-gate
8350Sstevel@tonic-gate if (format == NULL)
8360Sstevel@tonic-gate format = "%s";
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
8390Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
8400Sstevel@tonic-gate else
8410Sstevel@tonic-gate indent = _dtrace_stkindent;
8420Sstevel@tonic-gate
843457Sbmc for (i = 0; i < depth; i++) {
844457Sbmc switch (size) {
845457Sbmc case sizeof (uint32_t):
846457Sbmc /* LINTED - alignment */
847457Sbmc pc = *((uint32_t *)addr);
848457Sbmc break;
849457Sbmc
850457Sbmc case sizeof (uint64_t):
851457Sbmc /* LINTED - alignment */
852457Sbmc pc = *((uint64_t *)addr);
853457Sbmc break;
854457Sbmc
855457Sbmc default:
856457Sbmc return (dt_set_errno(dtp, EDT_BADSTACKPC));
857457Sbmc }
858457Sbmc
859457Sbmc if (pc == NULL)
860457Sbmc break;
861457Sbmc
862457Sbmc addr += size;
863457Sbmc
8640Sstevel@tonic-gate if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
8650Sstevel@tonic-gate return (-1);
8660Sstevel@tonic-gate
867457Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
868457Sbmc if (pc > sym.st_value) {
8690Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
8700Sstevel@tonic-gate dts.dts_object, dts.dts_name,
871457Sbmc pc - sym.st_value);
8720Sstevel@tonic-gate } else {
8730Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`%s",
8740Sstevel@tonic-gate dts.dts_object, dts.dts_name);
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate } else {
8770Sstevel@tonic-gate /*
8780Sstevel@tonic-gate * We'll repeat the lookup, but this time we'll specify
8790Sstevel@tonic-gate * a NULL GElf_Sym -- indicating that we're only
8800Sstevel@tonic-gate * interested in the containing module.
8810Sstevel@tonic-gate */
882457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
8830Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx",
884457Sbmc dts.dts_object, pc);
8850Sstevel@tonic-gate } else {
886457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", pc);
8870Sstevel@tonic-gate }
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate if (dt_printf(dtp, fp, format, c) < 0)
8910Sstevel@tonic-gate return (-1);
8920Sstevel@tonic-gate
8930Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0)
8940Sstevel@tonic-gate return (-1);
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate
8970Sstevel@tonic-gate return (0);
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate int
dt_print_ustack(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr,uint64_t arg)9010Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
9020Sstevel@tonic-gate caddr_t addr, uint64_t arg)
9030Sstevel@tonic-gate {
904457Sbmc /* LINTED - alignment */
905457Sbmc uint64_t *pc = (uint64_t *)addr;
9060Sstevel@tonic-gate uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
9070Sstevel@tonic-gate uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
9080Sstevel@tonic-gate const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
9090Sstevel@tonic-gate const char *str = strsize ? strbase : NULL;
9100Sstevel@tonic-gate int err = 0;
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
9130Sstevel@tonic-gate struct ps_prochandle *P;
9140Sstevel@tonic-gate GElf_Sym sym;
9150Sstevel@tonic-gate int i, indent;
9160Sstevel@tonic-gate pid_t pid;
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate if (depth == 0)
9190Sstevel@tonic-gate return (0);
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate pid = (pid_t)*pc++;
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0)
9240Sstevel@tonic-gate return (-1);
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate if (format == NULL)
9270Sstevel@tonic-gate format = "%s";
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
9300Sstevel@tonic-gate indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
9310Sstevel@tonic-gate else
9320Sstevel@tonic-gate indent = _dtrace_stkindent;
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate /*
9350Sstevel@tonic-gate * Ultimately, we need to add an entry point in the library vector for
9360Sstevel@tonic-gate * determining <symbol, offset> from <pid, address>. For now, if
9370Sstevel@tonic-gate * this is a vector open, we just print the raw address or string.
9380Sstevel@tonic-gate */
9390Sstevel@tonic-gate if (dtp->dt_vector == NULL)
9400Sstevel@tonic-gate P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
9410Sstevel@tonic-gate else
9420Sstevel@tonic-gate P = NULL;
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate if (P != NULL)
9450Sstevel@tonic-gate dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate for (i = 0; i < depth && pc[i] != NULL; i++) {
948457Sbmc const prmap_t *map;
949457Sbmc
9500Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
9510Sstevel@tonic-gate break;
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate if (P != NULL && Plookup_by_addr(P, pc[i],
9540Sstevel@tonic-gate name, sizeof (name), &sym) == 0) {
9550Sstevel@tonic-gate (void) Pobjname(P, pc[i], objname, sizeof (objname));
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate if (pc[i] > sym.st_value) {
9580Sstevel@tonic-gate (void) snprintf(c, sizeof (c),
9590Sstevel@tonic-gate "%s`%s+0x%llx", dt_basename(objname), name,
9600Sstevel@tonic-gate (u_longlong_t)(pc[i] - sym.st_value));
9610Sstevel@tonic-gate } else {
9620Sstevel@tonic-gate (void) snprintf(c, sizeof (c),
9630Sstevel@tonic-gate "%s`%s", dt_basename(objname), name);
9640Sstevel@tonic-gate }
965491Sbmc } else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
966457Sbmc (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
967457Sbmc (map->pr_mflags & MA_WRITE)))) {
968457Sbmc /*
969457Sbmc * If the current string pointer in the string table
970457Sbmc * does not point to an empty string _and_ the program
971457Sbmc * counter falls in a writable region, we'll use the
972457Sbmc * string from the string table instead of the raw
973457Sbmc * address. This last condition is necessary because
974457Sbmc * some (broken) ustack helpers will return a string
975457Sbmc * even for a program counter that they can't
976457Sbmc * identify. If we have a string for a program
977457Sbmc * counter that falls in a segment that isn't
978457Sbmc * writable, we assume that we have fallen into this
979457Sbmc * case and we refuse to use the string.
980457Sbmc */
9810Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s", str);
9820Sstevel@tonic-gate } else {
9830Sstevel@tonic-gate if (P != NULL && Pobjname(P, pc[i], objname,
9840Sstevel@tonic-gate sizeof (objname)) != NULL) {
9850Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "%s`0x%llx",
9860Sstevel@tonic-gate dt_basename(objname), (u_longlong_t)pc[i]);
9870Sstevel@tonic-gate } else {
9880Sstevel@tonic-gate (void) snprintf(c, sizeof (c), "0x%llx",
9890Sstevel@tonic-gate (u_longlong_t)pc[i]);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate }
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, format, c)) < 0)
9940Sstevel@tonic-gate break;
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate if ((err = dt_printf(dtp, fp, "\n")) < 0)
9970Sstevel@tonic-gate break;
9980Sstevel@tonic-gate
999491Sbmc if (str != NULL && str[0] == '@') {
1000491Sbmc /*
1001491Sbmc * If the first character of the string is an "at" sign,
1002491Sbmc * then the string is inferred to be an annotation --
1003491Sbmc * and it is printed out beneath the frame and offset
1004491Sbmc * with brackets.
1005491Sbmc */
1006491Sbmc if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
1007491Sbmc break;
1008491Sbmc
1009491Sbmc (void) snprintf(c, sizeof (c), " [ %s ]", &str[1]);
1010491Sbmc
1011491Sbmc if ((err = dt_printf(dtp, fp, format, c)) < 0)
1012491Sbmc break;
1013491Sbmc
1014491Sbmc if ((err = dt_printf(dtp, fp, "\n")) < 0)
1015491Sbmc break;
1016491Sbmc }
1017491Sbmc
10180Sstevel@tonic-gate if (str != NULL) {
10190Sstevel@tonic-gate str += strlen(str) + 1;
10200Sstevel@tonic-gate if (str - strbase >= strsize)
10210Sstevel@tonic-gate str = NULL;
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate if (P != NULL) {
10260Sstevel@tonic-gate dt_proc_unlock(dtp, P);
10270Sstevel@tonic-gate dt_proc_release(dtp, P);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate return (err);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate
1033457Sbmc static int
dt_print_usym(dtrace_hdl_t * dtp,FILE * fp,caddr_t addr,dtrace_actkind_t act)1034457Sbmc dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
1035457Sbmc {
1036457Sbmc /* LINTED - alignment */
1037457Sbmc uint64_t pid = ((uint64_t *)addr)[0];
1038457Sbmc /* LINTED - alignment */
1039457Sbmc uint64_t pc = ((uint64_t *)addr)[1];
1040457Sbmc const char *format = " %-50s";
1041457Sbmc char *s;
1042457Sbmc int n, len = 256;
1043457Sbmc
1044457Sbmc if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
1045457Sbmc struct ps_prochandle *P;
1046457Sbmc
1047457Sbmc if ((P = dt_proc_grab(dtp, pid,
1048457Sbmc PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
1049457Sbmc GElf_Sym sym;
1050457Sbmc
1051457Sbmc dt_proc_lock(dtp, P);
1052457Sbmc
1053457Sbmc if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
1054457Sbmc pc = sym.st_value;
1055457Sbmc
1056457Sbmc dt_proc_unlock(dtp, P);
1057457Sbmc dt_proc_release(dtp, P);
1058457Sbmc }
1059457Sbmc }
1060457Sbmc
1061457Sbmc do {
1062457Sbmc n = len;
1063457Sbmc s = alloca(n);
1064*10791SJonathan.Haslam@Sun.COM } while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) > n);
1065457Sbmc
1066457Sbmc return (dt_printf(dtp, fp, format, s));
1067457Sbmc }
1068457Sbmc
1069457Sbmc int
dt_print_umod(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr)1070457Sbmc dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
1071457Sbmc {
1072457Sbmc /* LINTED - alignment */
1073457Sbmc uint64_t pid = ((uint64_t *)addr)[0];
1074457Sbmc /* LINTED - alignment */
1075457Sbmc uint64_t pc = ((uint64_t *)addr)[1];
1076457Sbmc int err = 0;
1077457Sbmc
1078457Sbmc char objname[PATH_MAX], c[PATH_MAX * 2];
1079457Sbmc struct ps_prochandle *P;
1080457Sbmc
1081457Sbmc if (format == NULL)
1082457Sbmc format = " %-50s";
1083457Sbmc
1084457Sbmc /*
1085457Sbmc * See the comment in dt_print_ustack() for the rationale for
1086457Sbmc * printing raw addresses in the vectored case.
1087457Sbmc */
1088457Sbmc if (dtp->dt_vector == NULL)
1089457Sbmc P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
1090457Sbmc else
1091457Sbmc P = NULL;
1092457Sbmc
1093457Sbmc if (P != NULL)
1094457Sbmc dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
1095457Sbmc
1096457Sbmc if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != NULL) {
1097457Sbmc (void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
1098457Sbmc } else {
1099457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
1100457Sbmc }
1101457Sbmc
1102457Sbmc err = dt_printf(dtp, fp, format, c);
1103457Sbmc
1104457Sbmc if (P != NULL) {
1105457Sbmc dt_proc_unlock(dtp, P);
1106457Sbmc dt_proc_release(dtp, P);
1107457Sbmc }
1108457Sbmc
1109457Sbmc return (err);
1110457Sbmc }
1111457Sbmc
1112457Sbmc static int
dt_print_sym(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr)1113457Sbmc dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
1114457Sbmc {
1115457Sbmc /* LINTED - alignment */
1116457Sbmc uint64_t pc = *((uint64_t *)addr);
1117457Sbmc dtrace_syminfo_t dts;
1118457Sbmc GElf_Sym sym;
1119457Sbmc char c[PATH_MAX * 2];
1120457Sbmc
1121457Sbmc if (format == NULL)
1122457Sbmc format = " %-50s";
1123457Sbmc
1124457Sbmc if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
1125457Sbmc (void) snprintf(c, sizeof (c), "%s`%s",
1126457Sbmc dts.dts_object, dts.dts_name);
1127457Sbmc } else {
1128457Sbmc /*
1129457Sbmc * We'll repeat the lookup, but this time we'll specify a
1130457Sbmc * NULL GElf_Sym -- indicating that we're only interested in
1131457Sbmc * the containing module.
1132457Sbmc */
1133457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
1134457Sbmc (void) snprintf(c, sizeof (c), "%s`0x%llx",
1135457Sbmc dts.dts_object, (u_longlong_t)pc);
1136457Sbmc } else {
1137457Sbmc (void) snprintf(c, sizeof (c), "0x%llx",
1138457Sbmc (u_longlong_t)pc);
1139457Sbmc }
1140457Sbmc }
1141457Sbmc
1142457Sbmc if (dt_printf(dtp, fp, format, c) < 0)
1143457Sbmc return (-1);
1144457Sbmc
1145457Sbmc return (0);
1146457Sbmc }
1147457Sbmc
1148457Sbmc int
dt_print_mod(dtrace_hdl_t * dtp,FILE * fp,const char * format,caddr_t addr)1149457Sbmc dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
1150457Sbmc {
1151457Sbmc /* LINTED - alignment */
1152457Sbmc uint64_t pc = *((uint64_t *)addr);
1153457Sbmc dtrace_syminfo_t dts;
1154457Sbmc char c[PATH_MAX * 2];
1155457Sbmc
1156457Sbmc if (format == NULL)
1157457Sbmc format = " %-50s";
1158457Sbmc
1159457Sbmc if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
1160457Sbmc (void) snprintf(c, sizeof (c), "%s", dts.dts_object);
1161457Sbmc } else {
1162457Sbmc (void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
1163457Sbmc }
1164457Sbmc
1165457Sbmc if (dt_printf(dtp, fp, format, c) < 0)
1166457Sbmc return (-1);
1167457Sbmc
1168457Sbmc return (0);
1169457Sbmc }
1170457Sbmc
11710Sstevel@tonic-gate typedef struct dt_normal {
11720Sstevel@tonic-gate dtrace_aggvarid_t dtnd_id;
11730Sstevel@tonic-gate uint64_t dtnd_normal;
11740Sstevel@tonic-gate } dt_normal_t;
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate static int
dt_normalize_agg(const dtrace_aggdata_t * aggdata,void * arg)1177457Sbmc dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
11780Sstevel@tonic-gate {
11790Sstevel@tonic-gate dt_normal_t *normal = arg;
11800Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc;
11810Sstevel@tonic-gate dtrace_aggvarid_t id = normal->dtnd_id;
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate if (agg->dtagd_nrecs == 0)
11840Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
11850Sstevel@tonic-gate
11861017Sbmc if (agg->dtagd_varid != id)
11870Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
11880Sstevel@tonic-gate
1189457Sbmc ((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal;
11900Sstevel@tonic-gate return (DTRACE_AGGWALK_NORMALIZE);
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate static int
dt_normalize(dtrace_hdl_t * dtp,caddr_t base,dtrace_recdesc_t * rec)11940Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
11950Sstevel@tonic-gate {
11960Sstevel@tonic-gate dt_normal_t normal;
11970Sstevel@tonic-gate caddr_t addr;
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate /*
12000Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the
12010Sstevel@tonic-gate * normalization value.
12020Sstevel@tonic-gate */
12030Sstevel@tonic-gate addr = base + rec->dtrd_offset;
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
12060Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL));
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate /* LINTED - alignment */
12090Sstevel@tonic-gate normal.dtnd_id = *((dtrace_aggvarid_t *)addr);
12100Sstevel@tonic-gate rec++;
12110Sstevel@tonic-gate
12120Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT)
12130Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL));
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_NORMALIZE)
12160Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL));
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate addr = base + rec->dtrd_offset;
12190Sstevel@tonic-gate
12200Sstevel@tonic-gate switch (rec->dtrd_size) {
12210Sstevel@tonic-gate case sizeof (uint64_t):
12220Sstevel@tonic-gate /* LINTED - alignment */
12230Sstevel@tonic-gate normal.dtnd_normal = *((uint64_t *)addr);
12240Sstevel@tonic-gate break;
12250Sstevel@tonic-gate case sizeof (uint32_t):
12260Sstevel@tonic-gate /* LINTED - alignment */
12270Sstevel@tonic-gate normal.dtnd_normal = *((uint32_t *)addr);
12280Sstevel@tonic-gate break;
12290Sstevel@tonic-gate case sizeof (uint16_t):
12300Sstevel@tonic-gate /* LINTED - alignment */
12310Sstevel@tonic-gate normal.dtnd_normal = *((uint16_t *)addr);
12320Sstevel@tonic-gate break;
12330Sstevel@tonic-gate case sizeof (uint8_t):
12340Sstevel@tonic-gate normal.dtnd_normal = *((uint8_t *)addr);
12350Sstevel@tonic-gate break;
12360Sstevel@tonic-gate default:
12370Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL));
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal);
12410Sstevel@tonic-gate
12420Sstevel@tonic-gate return (0);
12430Sstevel@tonic-gate }
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate static int
dt_denormalize_agg(const dtrace_aggdata_t * aggdata,void * arg)1246457Sbmc dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
12470Sstevel@tonic-gate {
12480Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc;
12490Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate if (agg->dtagd_nrecs == 0)
12520Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12530Sstevel@tonic-gate
12541017Sbmc if (agg->dtagd_varid != id)
12550Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12560Sstevel@tonic-gate
12570Sstevel@tonic-gate return (DTRACE_AGGWALK_DENORMALIZE);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate static int
dt_clear_agg(const dtrace_aggdata_t * aggdata,void * arg)1261457Sbmc dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg)
12620Sstevel@tonic-gate {
12630Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc;
12640Sstevel@tonic-gate dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate if (agg->dtagd_nrecs == 0)
12670Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12680Sstevel@tonic-gate
12691017Sbmc if (agg->dtagd_varid != id)
12700Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate return (DTRACE_AGGWALK_CLEAR);
12730Sstevel@tonic-gate }
12740Sstevel@tonic-gate
12750Sstevel@tonic-gate typedef struct dt_trunc {
12760Sstevel@tonic-gate dtrace_aggvarid_t dttd_id;
12770Sstevel@tonic-gate uint64_t dttd_remaining;
12780Sstevel@tonic-gate } dt_trunc_t;
12790Sstevel@tonic-gate
12800Sstevel@tonic-gate static int
dt_trunc_agg(const dtrace_aggdata_t * aggdata,void * arg)1281457Sbmc dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg)
12820Sstevel@tonic-gate {
12830Sstevel@tonic-gate dt_trunc_t *trunc = arg;
12840Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc;
12850Sstevel@tonic-gate dtrace_aggvarid_t id = trunc->dttd_id;
12860Sstevel@tonic-gate
12870Sstevel@tonic-gate if (agg->dtagd_nrecs == 0)
12880Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12890Sstevel@tonic-gate
12901017Sbmc if (agg->dtagd_varid != id)
12910Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate if (trunc->dttd_remaining == 0)
12940Sstevel@tonic-gate return (DTRACE_AGGWALK_REMOVE);
12950Sstevel@tonic-gate
12960Sstevel@tonic-gate trunc->dttd_remaining--;
12970Sstevel@tonic-gate return (DTRACE_AGGWALK_NEXT);
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate
13000Sstevel@tonic-gate static int
dt_trunc(dtrace_hdl_t * dtp,caddr_t base,dtrace_recdesc_t * rec)13010Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
13020Sstevel@tonic-gate {
13030Sstevel@tonic-gate dt_trunc_t trunc;
13040Sstevel@tonic-gate caddr_t addr;
13050Sstevel@tonic-gate int64_t remaining;
13060Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate /*
13090Sstevel@tonic-gate * We (should) have two records: the aggregation ID followed by the
13100Sstevel@tonic-gate * number of aggregation entries after which the aggregation is to be
13110Sstevel@tonic-gate * truncated.
13120Sstevel@tonic-gate */
13130Sstevel@tonic-gate addr = base + rec->dtrd_offset;
13140Sstevel@tonic-gate
13150Sstevel@tonic-gate if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
13160Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC));
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate /* LINTED - alignment */
13190Sstevel@tonic-gate trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
13200Sstevel@tonic-gate rec++;
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate if (rec->dtrd_action != DTRACEACT_LIBACT)
13230Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC));
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate if (rec->dtrd_arg != DT_ACT_TRUNC)
13260Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADTRUNC));
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate addr = base + rec->dtrd_offset;
13290Sstevel@tonic-gate
13300Sstevel@tonic-gate switch (rec->dtrd_size) {
13310Sstevel@tonic-gate case sizeof (uint64_t):
13320Sstevel@tonic-gate /* LINTED - alignment */
13330Sstevel@tonic-gate remaining = *((int64_t *)addr);
13340Sstevel@tonic-gate break;
13350Sstevel@tonic-gate case sizeof (uint32_t):
13360Sstevel@tonic-gate /* LINTED - alignment */
13370Sstevel@tonic-gate remaining = *((int32_t *)addr);
13380Sstevel@tonic-gate break;
13390Sstevel@tonic-gate case sizeof (uint16_t):
13400Sstevel@tonic-gate /* LINTED - alignment */
13410Sstevel@tonic-gate remaining = *((int16_t *)addr);
13420Sstevel@tonic-gate break;
13430Sstevel@tonic-gate case sizeof (uint8_t):
13440Sstevel@tonic-gate remaining = *((int8_t *)addr);
13450Sstevel@tonic-gate break;
13460Sstevel@tonic-gate default:
13470Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADNORMAL));
13480Sstevel@tonic-gate }
13490Sstevel@tonic-gate
13500Sstevel@tonic-gate if (remaining < 0) {
13510Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted;
13520Sstevel@tonic-gate remaining = -remaining;
13530Sstevel@tonic-gate } else {
13540Sstevel@tonic-gate func = dtrace_aggregate_walk_valrevsorted;
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate assert(remaining >= 0);
13580Sstevel@tonic-gate trunc.dttd_remaining = remaining;
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate (void) func(dtp, dt_trunc_agg, &trunc);
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate return (0);
13630Sstevel@tonic-gate }
13640Sstevel@tonic-gate
13651017Sbmc static int
dt_print_datum(dtrace_hdl_t * dtp,FILE * fp,dtrace_recdesc_t * rec,caddr_t addr,size_t size,uint64_t normal)13661017Sbmc dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
13671017Sbmc caddr_t addr, size_t size, uint64_t normal)
13681017Sbmc {
13691017Sbmc int err;
13701017Sbmc dtrace_actkind_t act = rec->dtrd_action;
13711017Sbmc
13721017Sbmc switch (act) {
13731017Sbmc case DTRACEACT_STACK:
13741017Sbmc return (dt_print_stack(dtp, fp, NULL, addr,
13751017Sbmc rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg));
13761017Sbmc
13771017Sbmc case DTRACEACT_USTACK:
13781017Sbmc case DTRACEACT_JSTACK:
13791017Sbmc return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg));
13801017Sbmc
13811017Sbmc case DTRACEACT_USYM:
13821017Sbmc case DTRACEACT_UADDR:
13831017Sbmc return (dt_print_usym(dtp, fp, addr, act));
13841017Sbmc
13851017Sbmc case DTRACEACT_UMOD:
13861017Sbmc return (dt_print_umod(dtp, fp, NULL, addr));
13871017Sbmc
13881017Sbmc case DTRACEACT_SYM:
13891017Sbmc return (dt_print_sym(dtp, fp, NULL, addr));
13901017Sbmc
13911017Sbmc case DTRACEACT_MOD:
13921017Sbmc return (dt_print_mod(dtp, fp, NULL, addr));
13931017Sbmc
13941017Sbmc case DTRACEAGG_QUANTIZE:
13951017Sbmc return (dt_print_quantize(dtp, fp, addr, size, normal));
13961017Sbmc
13971017Sbmc case DTRACEAGG_LQUANTIZE:
13981017Sbmc return (dt_print_lquantize(dtp, fp, addr, size, normal));
13991017Sbmc
14001017Sbmc case DTRACEAGG_AVG:
14011017Sbmc return (dt_print_average(dtp, fp, addr, size, normal));
14021017Sbmc
14035984Sjhaslam case DTRACEAGG_STDDEV:
14045984Sjhaslam return (dt_print_stddev(dtp, fp, addr, size, normal));
14055984Sjhaslam
14061017Sbmc default:
14071017Sbmc break;
14081017Sbmc }
14091017Sbmc
14101017Sbmc switch (size) {
14111017Sbmc case sizeof (uint64_t):
14121017Sbmc err = dt_printf(dtp, fp, " %16lld",
14131017Sbmc /* LINTED - alignment */
14141017Sbmc (long long)*((uint64_t *)addr) / normal);
14151017Sbmc break;
14161017Sbmc case sizeof (uint32_t):
14171017Sbmc /* LINTED - alignment */
14181017Sbmc err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) /
14191017Sbmc (uint32_t)normal);
14201017Sbmc break;
14211017Sbmc case sizeof (uint16_t):
14221017Sbmc /* LINTED - alignment */
14231017Sbmc err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) /
14241017Sbmc (uint32_t)normal);
14251017Sbmc break;
14261017Sbmc case sizeof (uint8_t):
14271017Sbmc err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) /
14281017Sbmc (uint32_t)normal);
14291017Sbmc break;
14301017Sbmc default:
14311017Sbmc err = dt_print_bytes(dtp, fp, addr, size, 50, 0);
14321017Sbmc break;
14331017Sbmc }
14341017Sbmc
14351017Sbmc return (err);
14361017Sbmc }
14371017Sbmc
14381017Sbmc int
dt_print_aggs(const dtrace_aggdata_t ** aggsdata,int naggvars,void * arg)14391017Sbmc dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
14401017Sbmc {
14411017Sbmc int i, aggact = 0;
14421017Sbmc dt_print_aggdata_t *pd = arg;
14431017Sbmc const dtrace_aggdata_t *aggdata = aggsdata[0];
14441017Sbmc dtrace_aggdesc_t *agg = aggdata->dtada_desc;
14451017Sbmc FILE *fp = pd->dtpa_fp;
14461017Sbmc dtrace_hdl_t *dtp = pd->dtpa_dtp;
14471017Sbmc dtrace_recdesc_t *rec;
14481017Sbmc dtrace_actkind_t act;
14491017Sbmc caddr_t addr;
14501017Sbmc size_t size;
14511017Sbmc
14521017Sbmc /*
14531017Sbmc * Iterate over each record description in the key, printing the traced
14541017Sbmc * data, skipping the first datum (the tuple member created by the
14551017Sbmc * compiler).
14561017Sbmc */
14571017Sbmc for (i = 1; i < agg->dtagd_nrecs; i++) {
14581017Sbmc rec = &agg->dtagd_rec[i];
14591017Sbmc act = rec->dtrd_action;
14601017Sbmc addr = aggdata->dtada_data + rec->dtrd_offset;
14611017Sbmc size = rec->dtrd_size;
14621017Sbmc
14631017Sbmc if (DTRACEACT_ISAGG(act)) {
14641017Sbmc aggact = i;
14651017Sbmc break;
14661017Sbmc }
14671017Sbmc
14681017Sbmc if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0)
14691017Sbmc return (-1);
14701017Sbmc
14711017Sbmc if (dt_buffered_flush(dtp, NULL, rec, aggdata,
14721017Sbmc DTRACE_BUFDATA_AGGKEY) < 0)
14731017Sbmc return (-1);
14741017Sbmc }
14751017Sbmc
14761017Sbmc assert(aggact != 0);
14771017Sbmc
14781017Sbmc for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) {
14791017Sbmc uint64_t normal;
14801017Sbmc
14811017Sbmc aggdata = aggsdata[i];
14821017Sbmc agg = aggdata->dtada_desc;
14831017Sbmc rec = &agg->dtagd_rec[aggact];
14841017Sbmc act = rec->dtrd_action;
14851017Sbmc addr = aggdata->dtada_data + rec->dtrd_offset;
14861017Sbmc size = rec->dtrd_size;
14871017Sbmc
14881017Sbmc assert(DTRACEACT_ISAGG(act));
14891017Sbmc normal = aggdata->dtada_normal;
14901017Sbmc
14911017Sbmc if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0)
14921017Sbmc return (-1);
14931017Sbmc
14941017Sbmc if (dt_buffered_flush(dtp, NULL, rec, aggdata,
14951017Sbmc DTRACE_BUFDATA_AGGVAL) < 0)
14961017Sbmc return (-1);
14971017Sbmc
14981017Sbmc if (!pd->dtpa_allunprint)
14991017Sbmc agg->dtagd_flags |= DTRACE_AGD_PRINTED;
15001017Sbmc }
15011017Sbmc
15021017Sbmc if (dt_printf(dtp, fp, "\n") < 0)
15031017Sbmc return (-1);
15041017Sbmc
15051017Sbmc if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
15061017Sbmc DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0)
15071017Sbmc return (-1);
15081017Sbmc
15091017Sbmc return (0);
15101017Sbmc }
15111017Sbmc
15120Sstevel@tonic-gate int
dt_print_agg(const dtrace_aggdata_t * aggdata,void * arg)1513457Sbmc dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg)
15140Sstevel@tonic-gate {
15150Sstevel@tonic-gate dt_print_aggdata_t *pd = arg;
15160Sstevel@tonic-gate dtrace_aggdesc_t *agg = aggdata->dtada_desc;
15170Sstevel@tonic-gate dtrace_aggvarid_t aggvarid = pd->dtpa_id;
15180Sstevel@tonic-gate
15190Sstevel@tonic-gate if (pd->dtpa_allunprint) {
15200Sstevel@tonic-gate if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
15210Sstevel@tonic-gate return (0);
15220Sstevel@tonic-gate } else {
15230Sstevel@tonic-gate /*
15240Sstevel@tonic-gate * If we're not printing all unprinted aggregations, then the
15250Sstevel@tonic-gate * aggregation variable ID denotes a specific aggregation
15260Sstevel@tonic-gate * variable that we should print -- skip any other aggregations
15270Sstevel@tonic-gate * that we encounter.
15280Sstevel@tonic-gate */
15290Sstevel@tonic-gate if (agg->dtagd_nrecs == 0)
15300Sstevel@tonic-gate return (0);
15310Sstevel@tonic-gate
15321017Sbmc if (aggvarid != agg->dtagd_varid)
15330Sstevel@tonic-gate return (0);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate
15361017Sbmc return (dt_print_aggs(&aggdata, 1, arg));
15370Sstevel@tonic-gate }
15380Sstevel@tonic-gate
1539457Sbmc int
dt_setopt(dtrace_hdl_t * dtp,const dtrace_probedata_t * data,const char * option,const char * value)1540457Sbmc dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
1541457Sbmc const char *option, const char *value)
1542457Sbmc {
1543457Sbmc int len, rval;
1544457Sbmc char *msg;
1545457Sbmc const char *errstr;
1546457Sbmc dtrace_setoptdata_t optdata;
1547457Sbmc
1548457Sbmc bzero(&optdata, sizeof (optdata));
1549457Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval);
1550457Sbmc
1551457Sbmc if (dtrace_setopt(dtp, option, value) == 0) {
1552457Sbmc (void) dtrace_getopt(dtp, option, &optdata.dtsda_newval);
1553457Sbmc optdata.dtsda_probe = data;
1554457Sbmc optdata.dtsda_option = option;
1555457Sbmc optdata.dtsda_handle = dtp;
1556457Sbmc
1557457Sbmc if ((rval = dt_handle_setopt(dtp, &optdata)) != 0)
1558457Sbmc return (rval);
1559457Sbmc
1560457Sbmc return (0);
1561457Sbmc }
1562457Sbmc
1563457Sbmc errstr = dtrace_errmsg(dtp, dtrace_errno(dtp));
1564457Sbmc len = strlen(option) + strlen(value) + strlen(errstr) + 80;
1565457Sbmc msg = alloca(len);
1566457Sbmc
1567457Sbmc (void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n",
1568457Sbmc option, value, errstr);
1569457Sbmc
1570457Sbmc if ((rval = dt_handle_liberr(dtp, data, msg)) == 0)
1571457Sbmc return (0);
1572457Sbmc
1573457Sbmc return (rval);
1574457Sbmc }
1575457Sbmc
15760Sstevel@tonic-gate static int
dt_consume_cpu(dtrace_hdl_t * dtp,FILE * fp,int cpu,dtrace_bufdesc_t * buf,dtrace_consume_probe_f * efunc,dtrace_consume_rec_f * rfunc,void * arg)15770Sstevel@tonic-gate dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
15780Sstevel@tonic-gate dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
15790Sstevel@tonic-gate {
15800Sstevel@tonic-gate dtrace_epid_t id;
15810Sstevel@tonic-gate size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size;
15820Sstevel@tonic-gate int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
15830Sstevel@tonic-gate int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
15840Sstevel@tonic-gate int rval, i, n;
15850Sstevel@tonic-gate dtrace_epid_t last = DTRACE_EPIDNONE;
15860Sstevel@tonic-gate dtrace_probedata_t data;
15870Sstevel@tonic-gate uint64_t drops;
15880Sstevel@tonic-gate caddr_t addr;
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate bzero(&data, sizeof (data));
15910Sstevel@tonic-gate data.dtpda_handle = dtp;
15920Sstevel@tonic-gate data.dtpda_cpu = cpu;
15930Sstevel@tonic-gate
15940Sstevel@tonic-gate again:
15950Sstevel@tonic-gate for (offs = start; offs < end; ) {
15960Sstevel@tonic-gate dtrace_eprobedesc_t *epd;
15970Sstevel@tonic-gate
15980Sstevel@tonic-gate /*
15990Sstevel@tonic-gate * We're guaranteed to have an ID.
16000Sstevel@tonic-gate */
16010Sstevel@tonic-gate id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate if (id == DTRACE_EPIDNONE) {
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate * This is filler to assure proper alignment of the
16060Sstevel@tonic-gate * next record; we simply ignore it.
16070Sstevel@tonic-gate */
16080Sstevel@tonic-gate offs += sizeof (id);
16090Sstevel@tonic-gate continue;
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc,
16130Sstevel@tonic-gate &data.dtpda_pdesc)) != 0)
16140Sstevel@tonic-gate return (rval);
16150Sstevel@tonic-gate
16160Sstevel@tonic-gate epd = data.dtpda_edesc;
16170Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs;
16180Sstevel@tonic-gate
16190Sstevel@tonic-gate if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) {
16200Sstevel@tonic-gate rval = dt_handle(dtp, &data);
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT)
16230Sstevel@tonic-gate goto nextepid;
16240Sstevel@tonic-gate
16250Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ERROR)
16260Sstevel@tonic-gate return (-1);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate if (flow)
16300Sstevel@tonic-gate (void) dt_flowindent(dtp, &data, last, buf, offs);
16310Sstevel@tonic-gate
16320Sstevel@tonic-gate rval = (*efunc)(&data, arg);
16330Sstevel@tonic-gate
16340Sstevel@tonic-gate if (flow) {
16350Sstevel@tonic-gate if (data.dtpda_flow == DTRACEFLOW_ENTRY)
16360Sstevel@tonic-gate data.dtpda_indent += 2;
16370Sstevel@tonic-gate }
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT)
16400Sstevel@tonic-gate goto nextepid;
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT)
16430Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT));
16440Sstevel@tonic-gate
16450Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS)
16460Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL));
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate for (i = 0; i < epd->dtepd_nrecs; i++) {
16490Sstevel@tonic-gate dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
16500Sstevel@tonic-gate dtrace_actkind_t act = rec->dtrd_action;
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate data.dtpda_data = buf->dtbd_data + offs +
16530Sstevel@tonic-gate rec->dtrd_offset;
16540Sstevel@tonic-gate addr = data.dtpda_data;
16550Sstevel@tonic-gate
16560Sstevel@tonic-gate if (act == DTRACEACT_LIBACT) {
1657457Sbmc uint64_t arg = rec->dtrd_arg;
1658457Sbmc dtrace_aggvarid_t id;
16590Sstevel@tonic-gate
1660457Sbmc switch (arg) {
1661457Sbmc case DT_ACT_CLEAR:
16620Sstevel@tonic-gate /* LINTED - alignment */
16630Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr);
16640Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp,
16650Sstevel@tonic-gate dt_clear_agg, &id);
16660Sstevel@tonic-gate continue;
16670Sstevel@tonic-gate
1668457Sbmc case DT_ACT_DENORMALIZE:
16690Sstevel@tonic-gate /* LINTED - alignment */
16700Sstevel@tonic-gate id = *((dtrace_aggvarid_t *)addr);
16710Sstevel@tonic-gate (void) dtrace_aggregate_walk(dtp,
16720Sstevel@tonic-gate dt_denormalize_agg, &id);
16730Sstevel@tonic-gate continue;
1674457Sbmc
1675457Sbmc case DT_ACT_FTRUNCATE:
1676457Sbmc if (fp == NULL)
1677457Sbmc continue;
16780Sstevel@tonic-gate
1679457Sbmc (void) fflush(fp);
1680457Sbmc (void) ftruncate(fileno(fp), 0);
1681457Sbmc (void) fseeko(fp, 0, SEEK_SET);
1682457Sbmc continue;
1683457Sbmc
1684457Sbmc case DT_ACT_NORMALIZE:
16850Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1)
16860Sstevel@tonic-gate return (dt_set_errno(dtp,
16870Sstevel@tonic-gate EDT_BADNORMAL));
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate if (dt_normalize(dtp,
16900Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0)
16910Sstevel@tonic-gate return (-1);
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate i++;
16940Sstevel@tonic-gate continue;
1695457Sbmc
1696457Sbmc case DT_ACT_SETOPT: {
1697457Sbmc uint64_t *opts = dtp->dt_options;
1698457Sbmc dtrace_recdesc_t *valrec;
1699457Sbmc uint32_t valsize;
1700457Sbmc caddr_t val;
1701457Sbmc int rv;
1702457Sbmc
1703457Sbmc if (i == epd->dtepd_nrecs - 1) {
1704457Sbmc return (dt_set_errno(dtp,
1705457Sbmc EDT_BADSETOPT));
1706457Sbmc }
1707457Sbmc
1708457Sbmc valrec = &epd->dtepd_rec[++i];
1709457Sbmc valsize = valrec->dtrd_size;
1710457Sbmc
1711457Sbmc if (valrec->dtrd_action != act ||
1712457Sbmc valrec->dtrd_arg != arg) {
1713457Sbmc return (dt_set_errno(dtp,
1714457Sbmc EDT_BADSETOPT));
1715457Sbmc }
1716457Sbmc
1717457Sbmc if (valsize > sizeof (uint64_t)) {
1718457Sbmc val = buf->dtbd_data + offs +
1719457Sbmc valrec->dtrd_offset;
1720457Sbmc } else {
1721457Sbmc val = "1";
1722457Sbmc }
1723457Sbmc
1724457Sbmc rv = dt_setopt(dtp, &data, addr, val);
1725457Sbmc
1726457Sbmc if (rv != 0)
1727457Sbmc return (-1);
1728457Sbmc
1729457Sbmc flow = (opts[DTRACEOPT_FLOWINDENT] !=
1730457Sbmc DTRACEOPT_UNSET);
1731457Sbmc quiet = (opts[DTRACEOPT_QUIET] !=
1732457Sbmc DTRACEOPT_UNSET);
1733457Sbmc
1734457Sbmc continue;
17350Sstevel@tonic-gate }
17360Sstevel@tonic-gate
1737457Sbmc case DT_ACT_TRUNC:
17380Sstevel@tonic-gate if (i == epd->dtepd_nrecs - 1)
17390Sstevel@tonic-gate return (dt_set_errno(dtp,
17400Sstevel@tonic-gate EDT_BADTRUNC));
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate if (dt_trunc(dtp,
17430Sstevel@tonic-gate buf->dtbd_data + offs, rec) != 0)
17440Sstevel@tonic-gate return (-1);
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate i++;
17470Sstevel@tonic-gate continue;
17480Sstevel@tonic-gate
1749457Sbmc default:
17500Sstevel@tonic-gate continue;
17510Sstevel@tonic-gate }
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate rval = (*rfunc)(&data, rec, arg);
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate if (rval == DTRACE_CONSUME_NEXT)
17570Sstevel@tonic-gate continue;
17580Sstevel@tonic-gate
17590Sstevel@tonic-gate if (rval == DTRACE_CONSUME_ABORT)
17600Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT));
17610Sstevel@tonic-gate
17620Sstevel@tonic-gate if (rval != DTRACE_CONSUME_THIS)
17630Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL));
17640Sstevel@tonic-gate
17650Sstevel@tonic-gate if (act == DTRACEACT_STACK) {
1766457Sbmc int depth = rec->dtrd_arg;
1767457Sbmc
1768457Sbmc if (dt_print_stack(dtp, fp, NULL, addr, depth,
1769457Sbmc rec->dtrd_size / depth) < 0)
17700Sstevel@tonic-gate return (-1);
17710Sstevel@tonic-gate goto nextrec;
17720Sstevel@tonic-gate }
17730Sstevel@tonic-gate
17740Sstevel@tonic-gate if (act == DTRACEACT_USTACK ||
17750Sstevel@tonic-gate act == DTRACEACT_JSTACK) {
17760Sstevel@tonic-gate if (dt_print_ustack(dtp, fp, NULL,
17770Sstevel@tonic-gate addr, rec->dtrd_arg) < 0)
17780Sstevel@tonic-gate return (-1);
17790Sstevel@tonic-gate goto nextrec;
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate
1782457Sbmc if (act == DTRACEACT_SYM) {
1783457Sbmc if (dt_print_sym(dtp, fp, NULL, addr) < 0)
1784457Sbmc return (-1);
1785457Sbmc goto nextrec;
1786457Sbmc }
1787457Sbmc
1788457Sbmc if (act == DTRACEACT_MOD) {
1789457Sbmc if (dt_print_mod(dtp, fp, NULL, addr) < 0)
1790457Sbmc return (-1);
1791457Sbmc goto nextrec;
1792457Sbmc }
1793457Sbmc
1794457Sbmc if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
1795457Sbmc if (dt_print_usym(dtp, fp, addr, act) < 0)
1796457Sbmc return (-1);
1797457Sbmc goto nextrec;
1798457Sbmc }
1799457Sbmc
1800457Sbmc if (act == DTRACEACT_UMOD) {
1801457Sbmc if (dt_print_umod(dtp, fp, NULL, addr) < 0)
1802457Sbmc return (-1);
1803457Sbmc goto nextrec;
1804457Sbmc }
1805457Sbmc
18060Sstevel@tonic-gate if (DTRACEACT_ISPRINTFLIKE(act)) {
18070Sstevel@tonic-gate void *fmtdata;
18080Sstevel@tonic-gate int (*func)(dtrace_hdl_t *, FILE *, void *,
18090Sstevel@tonic-gate const dtrace_probedata_t *,
18100Sstevel@tonic-gate const dtrace_recdesc_t *, uint_t,
18110Sstevel@tonic-gate const void *buf, size_t);
18120Sstevel@tonic-gate
18130Sstevel@tonic-gate if ((fmtdata = dt_format_lookup(dtp,
18140Sstevel@tonic-gate rec->dtrd_format)) == NULL)
18150Sstevel@tonic-gate goto nofmt;
18160Sstevel@tonic-gate
18170Sstevel@tonic-gate switch (act) {
18180Sstevel@tonic-gate case DTRACEACT_PRINTF:
18190Sstevel@tonic-gate func = dtrace_fprintf;
18200Sstevel@tonic-gate break;
18210Sstevel@tonic-gate case DTRACEACT_PRINTA:
18220Sstevel@tonic-gate func = dtrace_fprinta;
18230Sstevel@tonic-gate break;
18240Sstevel@tonic-gate case DTRACEACT_SYSTEM:
18250Sstevel@tonic-gate func = dtrace_system;
18260Sstevel@tonic-gate break;
18270Sstevel@tonic-gate case DTRACEACT_FREOPEN:
18280Sstevel@tonic-gate func = dtrace_freopen;
18290Sstevel@tonic-gate break;
18300Sstevel@tonic-gate }
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate n = (*func)(dtp, fp, fmtdata, &data,
18330Sstevel@tonic-gate rec, epd->dtepd_nrecs - i,
18340Sstevel@tonic-gate (uchar_t *)buf->dtbd_data + offs,
18350Sstevel@tonic-gate buf->dtbd_size - offs);
18360Sstevel@tonic-gate
18370Sstevel@tonic-gate if (n < 0)
18380Sstevel@tonic-gate return (-1); /* errno is set for us */
18390Sstevel@tonic-gate
18400Sstevel@tonic-gate if (n > 0)
18410Sstevel@tonic-gate i += n - 1;
18420Sstevel@tonic-gate goto nextrec;
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate
18450Sstevel@tonic-gate nofmt:
18460Sstevel@tonic-gate if (act == DTRACEACT_PRINTA) {
18470Sstevel@tonic-gate dt_print_aggdata_t pd;
18481017Sbmc dtrace_aggvarid_t *aggvars;
18491017Sbmc int j, naggvars = 0;
18501017Sbmc size_t size = ((epd->dtepd_nrecs - i) *
18511017Sbmc sizeof (dtrace_aggvarid_t));
18520Sstevel@tonic-gate
18531017Sbmc if ((aggvars = dt_alloc(dtp, size)) == NULL)
18541017Sbmc return (-1);
18551017Sbmc
18561017Sbmc /*
18571017Sbmc * This might be a printa() with multiple
18581017Sbmc * aggregation variables. We need to scan
18591017Sbmc * forward through the records until we find
18601017Sbmc * a record from a different statement.
18611017Sbmc */
18621017Sbmc for (j = i; j < epd->dtepd_nrecs; j++) {
18631017Sbmc dtrace_recdesc_t *nrec;
18641017Sbmc caddr_t naddr;
18651017Sbmc
18661017Sbmc nrec = &epd->dtepd_rec[j];
18671017Sbmc
18681017Sbmc if (nrec->dtrd_uarg != rec->dtrd_uarg)
18691017Sbmc break;
18701017Sbmc
18711017Sbmc if (nrec->dtrd_action != act) {
18721017Sbmc return (dt_set_errno(dtp,
18731017Sbmc EDT_BADAGG));
18741017Sbmc }
18751017Sbmc
18761017Sbmc naddr = buf->dtbd_data + offs +
18771017Sbmc nrec->dtrd_offset;
18781017Sbmc
18791017Sbmc aggvars[naggvars++] =
18801017Sbmc /* LINTED - alignment */
18811017Sbmc *((dtrace_aggvarid_t *)naddr);
18821017Sbmc }
18831017Sbmc
18841017Sbmc i = j - 1;
18850Sstevel@tonic-gate bzero(&pd, sizeof (pd));
18860Sstevel@tonic-gate pd.dtpa_dtp = dtp;
18870Sstevel@tonic-gate pd.dtpa_fp = fp;
18881017Sbmc
18891017Sbmc assert(naggvars >= 1);
18901017Sbmc
18911017Sbmc if (naggvars == 1) {
18921017Sbmc pd.dtpa_id = aggvars[0];
18931017Sbmc dt_free(dtp, aggvars);
18941017Sbmc
18951017Sbmc if (dt_printf(dtp, fp, "\n") < 0 ||
18961017Sbmc dtrace_aggregate_walk_sorted(dtp,
18971017Sbmc dt_print_agg, &pd) < 0)
18981017Sbmc return (-1);
18991017Sbmc goto nextrec;
19001017Sbmc }
19010Sstevel@tonic-gate
19020Sstevel@tonic-gate if (dt_printf(dtp, fp, "\n") < 0 ||
19031017Sbmc dtrace_aggregate_walk_joined(dtp, aggvars,
19041017Sbmc naggvars, dt_print_aggs, &pd) < 0) {
19051017Sbmc dt_free(dtp, aggvars);
19060Sstevel@tonic-gate return (-1);
19071017Sbmc }
19080Sstevel@tonic-gate
19091017Sbmc dt_free(dtp, aggvars);
19100Sstevel@tonic-gate goto nextrec;
19110Sstevel@tonic-gate }
19120Sstevel@tonic-gate
19130Sstevel@tonic-gate switch (rec->dtrd_size) {
19140Sstevel@tonic-gate case sizeof (uint64_t):
19150Sstevel@tonic-gate n = dt_printf(dtp, fp,
19160Sstevel@tonic-gate quiet ? "%lld" : " %16lld",
19170Sstevel@tonic-gate /* LINTED - alignment */
19180Sstevel@tonic-gate *((unsigned long long *)addr));
19190Sstevel@tonic-gate break;
19200Sstevel@tonic-gate case sizeof (uint32_t):
19210Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %8d",
19220Sstevel@tonic-gate /* LINTED - alignment */
19230Sstevel@tonic-gate *((uint32_t *)addr));
19240Sstevel@tonic-gate break;
19250Sstevel@tonic-gate case sizeof (uint16_t):
19260Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %5d",
19270Sstevel@tonic-gate /* LINTED - alignment */
19280Sstevel@tonic-gate *((uint16_t *)addr));
19290Sstevel@tonic-gate break;
19300Sstevel@tonic-gate case sizeof (uint8_t):
19310Sstevel@tonic-gate n = dt_printf(dtp, fp, quiet ? "%d" : " %3d",
19320Sstevel@tonic-gate *((uint8_t *)addr));
19330Sstevel@tonic-gate break;
19340Sstevel@tonic-gate default:
19350Sstevel@tonic-gate n = dt_print_bytes(dtp, fp, addr,
19360Sstevel@tonic-gate rec->dtrd_size, 33, quiet);
19370Sstevel@tonic-gate break;
19380Sstevel@tonic-gate }
19390Sstevel@tonic-gate
19400Sstevel@tonic-gate if (n < 0)
19410Sstevel@tonic-gate return (-1); /* errno is set for us */
19420Sstevel@tonic-gate
19430Sstevel@tonic-gate nextrec:
19441017Sbmc if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0)
19450Sstevel@tonic-gate return (-1); /* errno is set for us */
19460Sstevel@tonic-gate }
19470Sstevel@tonic-gate
19480Sstevel@tonic-gate /*
19490Sstevel@tonic-gate * Call the record callback with a NULL record to indicate
19500Sstevel@tonic-gate * that we're done processing this EPID.
19510Sstevel@tonic-gate */
19520Sstevel@tonic-gate rval = (*rfunc)(&data, NULL, arg);
19530Sstevel@tonic-gate nextepid:
19540Sstevel@tonic-gate offs += epd->dtepd_size;
19550Sstevel@tonic-gate last = id;
19560Sstevel@tonic-gate }
19570Sstevel@tonic-gate
19580Sstevel@tonic-gate if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) {
19590Sstevel@tonic-gate end = buf->dtbd_oldest;
19600Sstevel@tonic-gate start = 0;
19610Sstevel@tonic-gate goto again;
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate
19640Sstevel@tonic-gate if ((drops = buf->dtbd_drops) == 0)
19650Sstevel@tonic-gate return (0);
19660Sstevel@tonic-gate
19670Sstevel@tonic-gate /*
19680Sstevel@tonic-gate * Explicitly zero the drops to prevent us from processing them again.
19690Sstevel@tonic-gate */
19700Sstevel@tonic-gate buf->dtbd_drops = 0;
19710Sstevel@tonic-gate
19720Sstevel@tonic-gate return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
19730Sstevel@tonic-gate }
19740Sstevel@tonic-gate
19750Sstevel@tonic-gate typedef struct dt_begin {
19760Sstevel@tonic-gate dtrace_consume_probe_f *dtbgn_probefunc;
19770Sstevel@tonic-gate dtrace_consume_rec_f *dtbgn_recfunc;
19780Sstevel@tonic-gate void *dtbgn_arg;
19790Sstevel@tonic-gate dtrace_handle_err_f *dtbgn_errhdlr;
19800Sstevel@tonic-gate void *dtbgn_errarg;
19810Sstevel@tonic-gate int dtbgn_beginonly;
19820Sstevel@tonic-gate } dt_begin_t;
19830Sstevel@tonic-gate
19840Sstevel@tonic-gate static int
dt_consume_begin_probe(const dtrace_probedata_t * data,void * arg)19850Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg)
19860Sstevel@tonic-gate {
19870Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg;
19880Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dtpda_pdesc;
19890Sstevel@tonic-gate
19900Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
19910Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
19920Sstevel@tonic-gate
19930Sstevel@tonic-gate if (begin->dtbgn_beginonly) {
19940Sstevel@tonic-gate if (!(r1 && r2))
19950Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT);
19960Sstevel@tonic-gate } else {
19970Sstevel@tonic-gate if (r1 && r2)
19980Sstevel@tonic-gate return (DTRACE_CONSUME_NEXT);
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate /*
20020Sstevel@tonic-gate * We have a record that we're interested in. Now call the underlying
20030Sstevel@tonic-gate * probe function...
20040Sstevel@tonic-gate */
20050Sstevel@tonic-gate return (begin->dtbgn_probefunc(data, begin->dtbgn_arg));
20060Sstevel@tonic-gate }
20070Sstevel@tonic-gate
20080Sstevel@tonic-gate static int
dt_consume_begin_record(const dtrace_probedata_t * data,const dtrace_recdesc_t * rec,void * arg)20090Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data,
20100Sstevel@tonic-gate const dtrace_recdesc_t *rec, void *arg)
20110Sstevel@tonic-gate {
20120Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg;
20130Sstevel@tonic-gate
20140Sstevel@tonic-gate return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg));
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate static int
dt_consume_begin_error(const dtrace_errdata_t * data,void * arg)2018457Sbmc dt_consume_begin_error(const dtrace_errdata_t *data, void *arg)
20190Sstevel@tonic-gate {
20200Sstevel@tonic-gate dt_begin_t *begin = (dt_begin_t *)arg;
20210Sstevel@tonic-gate dtrace_probedesc_t *pd = data->dteda_pdesc;
20220Sstevel@tonic-gate
20230Sstevel@tonic-gate int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
20240Sstevel@tonic-gate int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
20250Sstevel@tonic-gate
20260Sstevel@tonic-gate if (begin->dtbgn_beginonly) {
20270Sstevel@tonic-gate if (!(r1 && r2))
20280Sstevel@tonic-gate return (DTRACE_HANDLE_OK);
20290Sstevel@tonic-gate } else {
20300Sstevel@tonic-gate if (r1 && r2)
20310Sstevel@tonic-gate return (DTRACE_HANDLE_OK);
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate
20340Sstevel@tonic-gate return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg));
20350Sstevel@tonic-gate }
20360Sstevel@tonic-gate
20370Sstevel@tonic-gate static int
dt_consume_begin(dtrace_hdl_t * dtp,FILE * fp,dtrace_bufdesc_t * buf,dtrace_consume_probe_f * pf,dtrace_consume_rec_f * rf,void * arg)20380Sstevel@tonic-gate dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf,
20390Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
20400Sstevel@tonic-gate {
20410Sstevel@tonic-gate /*
20420Sstevel@tonic-gate * There's this idea that the BEGIN probe should be processed before
20430Sstevel@tonic-gate * everything else, and that the END probe should be processed after
20440Sstevel@tonic-gate * anything else. In the common case, this is pretty easy to deal
20450Sstevel@tonic-gate * with. However, a situation may arise where the BEGIN enabling and
20460Sstevel@tonic-gate * END enabling are on the same CPU, and some enabling in the middle
20470Sstevel@tonic-gate * occurred on a different CPU. To deal with this (blech!) we need to
20480Sstevel@tonic-gate * consume the BEGIN buffer up until the end of the BEGIN probe, and
20490Sstevel@tonic-gate * then set it aside. We will then process every other CPU, and then
20500Sstevel@tonic-gate * we'll return to the BEGIN CPU and process the rest of the data
20510Sstevel@tonic-gate * (which will inevitably include the END probe, if any). Making this
20520Sstevel@tonic-gate * even more complicated (!) is the library's ERROR enabling. Because
20530Sstevel@tonic-gate * this enabling is processed before we even get into the consume call
20540Sstevel@tonic-gate * back, any ERROR firing would result in the library's ERROR enabling
20550Sstevel@tonic-gate * being processed twice -- once in our first pass (for BEGIN probes),
20560Sstevel@tonic-gate * and again in our second pass (for everything but BEGIN probes). To
20570Sstevel@tonic-gate * deal with this, we interpose on the ERROR handler to assure that we
20580Sstevel@tonic-gate * only process ERROR enablings induced by BEGIN enablings in the
20590Sstevel@tonic-gate * first pass, and that we only process ERROR enablings _not_ induced
20600Sstevel@tonic-gate * by BEGIN enablings in the second pass.
20610Sstevel@tonic-gate */
20620Sstevel@tonic-gate dt_begin_t begin;
20630Sstevel@tonic-gate processorid_t cpu = dtp->dt_beganon;
20640Sstevel@tonic-gate dtrace_bufdesc_t nbuf;
20650Sstevel@tonic-gate int rval, i;
20660Sstevel@tonic-gate static int max_ncpus;
20670Sstevel@tonic-gate dtrace_optval_t size;
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate dtp->dt_beganon = -1;
20700Sstevel@tonic-gate
20710Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
20720Sstevel@tonic-gate /*
20730Sstevel@tonic-gate * We really don't expect this to fail, but it is at least
20740Sstevel@tonic-gate * technically possible for this to fail with ENOENT. In this
20750Sstevel@tonic-gate * case, we just drive on...
20760Sstevel@tonic-gate */
20770Sstevel@tonic-gate if (errno == ENOENT)
20780Sstevel@tonic-gate return (0);
20790Sstevel@tonic-gate
20800Sstevel@tonic-gate return (dt_set_errno(dtp, errno));
20810Sstevel@tonic-gate }
20820Sstevel@tonic-gate
20830Sstevel@tonic-gate if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) {
20840Sstevel@tonic-gate /*
20850Sstevel@tonic-gate * This is the simple case. We're either not stopped, or if
20860Sstevel@tonic-gate * we are, we actually processed any END probes on another
20870Sstevel@tonic-gate * CPU. We can simply consume this buffer and return.
20880Sstevel@tonic-gate */
20890Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg));
20900Sstevel@tonic-gate }
20910Sstevel@tonic-gate
20920Sstevel@tonic-gate begin.dtbgn_probefunc = pf;
20930Sstevel@tonic-gate begin.dtbgn_recfunc = rf;
20940Sstevel@tonic-gate begin.dtbgn_arg = arg;
20950Sstevel@tonic-gate begin.dtbgn_beginonly = 1;
20960Sstevel@tonic-gate
20970Sstevel@tonic-gate /*
20980Sstevel@tonic-gate * We need to interpose on the ERROR handler to be sure that we
20990Sstevel@tonic-gate * only process ERRORs induced by BEGIN.
21000Sstevel@tonic-gate */
21010Sstevel@tonic-gate begin.dtbgn_errhdlr = dtp->dt_errhdlr;
21020Sstevel@tonic-gate begin.dtbgn_errarg = dtp->dt_errarg;
21030Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error;
21040Sstevel@tonic-gate dtp->dt_errarg = &begin;
21050Sstevel@tonic-gate
21060Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
21070Sstevel@tonic-gate dt_consume_begin_record, &begin);
21080Sstevel@tonic-gate
21090Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr;
21100Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg;
21110Sstevel@tonic-gate
21120Sstevel@tonic-gate if (rval != 0)
21130Sstevel@tonic-gate return (rval);
21140Sstevel@tonic-gate
21150Sstevel@tonic-gate /*
21160Sstevel@tonic-gate * Now allocate a new buffer. We'll use this to deal with every other
21170Sstevel@tonic-gate * CPU.
21180Sstevel@tonic-gate */
21190Sstevel@tonic-gate bzero(&nbuf, sizeof (dtrace_bufdesc_t));
21200Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size);
21210Sstevel@tonic-gate if ((nbuf.dtbd_data = malloc(size)) == NULL)
21220Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM));
21230Sstevel@tonic-gate
21240Sstevel@tonic-gate if (max_ncpus == 0)
21250Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
21260Sstevel@tonic-gate
21270Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) {
21280Sstevel@tonic-gate nbuf.dtbd_cpu = i;
21290Sstevel@tonic-gate
21300Sstevel@tonic-gate if (i == cpu)
21310Sstevel@tonic-gate continue;
21320Sstevel@tonic-gate
21330Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) {
21340Sstevel@tonic-gate /*
21350Sstevel@tonic-gate * If we failed with ENOENT, it may be because the
21360Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other
21370Sstevel@tonic-gate * error, however, is unexpected.
21380Sstevel@tonic-gate */
21390Sstevel@tonic-gate if (errno == ENOENT)
21400Sstevel@tonic-gate continue;
21410Sstevel@tonic-gate
21420Sstevel@tonic-gate free(nbuf.dtbd_data);
21430Sstevel@tonic-gate
21440Sstevel@tonic-gate return (dt_set_errno(dtp, errno));
21450Sstevel@tonic-gate }
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp,
21480Sstevel@tonic-gate i, &nbuf, pf, rf, arg)) != 0) {
21490Sstevel@tonic-gate free(nbuf.dtbd_data);
21500Sstevel@tonic-gate return (rval);
21510Sstevel@tonic-gate }
21520Sstevel@tonic-gate }
21530Sstevel@tonic-gate
21540Sstevel@tonic-gate free(nbuf.dtbd_data);
21550Sstevel@tonic-gate
21560Sstevel@tonic-gate /*
21570Sstevel@tonic-gate * Okay -- we're done with the other buffers. Now we want to
21580Sstevel@tonic-gate * reconsume the first buffer -- but this time we're looking for
21590Sstevel@tonic-gate * everything _but_ BEGIN. And of course, in order to only consume
21600Sstevel@tonic-gate * those ERRORs _not_ associated with BEGIN, we need to reinstall our
21610Sstevel@tonic-gate * ERROR interposition function...
21620Sstevel@tonic-gate */
21630Sstevel@tonic-gate begin.dtbgn_beginonly = 0;
21640Sstevel@tonic-gate
21650Sstevel@tonic-gate assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr);
21660Sstevel@tonic-gate assert(begin.dtbgn_errarg == dtp->dt_errarg);
21670Sstevel@tonic-gate dtp->dt_errhdlr = dt_consume_begin_error;
21680Sstevel@tonic-gate dtp->dt_errarg = &begin;
21690Sstevel@tonic-gate
21700Sstevel@tonic-gate rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
21710Sstevel@tonic-gate dt_consume_begin_record, &begin);
21720Sstevel@tonic-gate
21730Sstevel@tonic-gate dtp->dt_errhdlr = begin.dtbgn_errhdlr;
21740Sstevel@tonic-gate dtp->dt_errarg = begin.dtbgn_errarg;
21750Sstevel@tonic-gate
21760Sstevel@tonic-gate return (rval);
21770Sstevel@tonic-gate }
21780Sstevel@tonic-gate
21790Sstevel@tonic-gate int
dtrace_consume(dtrace_hdl_t * dtp,FILE * fp,dtrace_consume_probe_f * pf,dtrace_consume_rec_f * rf,void * arg)21800Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
21810Sstevel@tonic-gate dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
21820Sstevel@tonic-gate {
21830Sstevel@tonic-gate dtrace_bufdesc_t *buf = &dtp->dt_buf;
21840Sstevel@tonic-gate dtrace_optval_t size;
21850Sstevel@tonic-gate static int max_ncpus;
21860Sstevel@tonic-gate int i, rval;
21870Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE];
21880Sstevel@tonic-gate hrtime_t now = gethrtime();
21890Sstevel@tonic-gate
21900Sstevel@tonic-gate if (dtp->dt_lastswitch != 0) {
21910Sstevel@tonic-gate if (now - dtp->dt_lastswitch < interval)
21920Sstevel@tonic-gate return (0);
21930Sstevel@tonic-gate
21940Sstevel@tonic-gate dtp->dt_lastswitch += interval;
21950Sstevel@tonic-gate } else {
21960Sstevel@tonic-gate dtp->dt_lastswitch = now;
21970Sstevel@tonic-gate }
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate if (!dtp->dt_active)
22000Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL));
22010Sstevel@tonic-gate
22020Sstevel@tonic-gate if (max_ncpus == 0)
22030Sstevel@tonic-gate max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
22040Sstevel@tonic-gate
22050Sstevel@tonic-gate if (pf == NULL)
22060Sstevel@tonic-gate pf = (dtrace_consume_probe_f *)dt_nullprobe;
22070Sstevel@tonic-gate
22080Sstevel@tonic-gate if (rf == NULL)
22090Sstevel@tonic-gate rf = (dtrace_consume_rec_f *)dt_nullrec;
22100Sstevel@tonic-gate
22110Sstevel@tonic-gate if (buf->dtbd_data == NULL) {
22120Sstevel@tonic-gate (void) dtrace_getopt(dtp, "bufsize", &size);
22130Sstevel@tonic-gate if ((buf->dtbd_data = malloc(size)) == NULL)
22140Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM));
22150Sstevel@tonic-gate
22160Sstevel@tonic-gate buf->dtbd_size = size;
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate /*
22200Sstevel@tonic-gate * If we have just begun, we want to first process the CPU that
22210Sstevel@tonic-gate * executed the BEGIN probe (if any).
22220Sstevel@tonic-gate */
22230Sstevel@tonic-gate if (dtp->dt_active && dtp->dt_beganon != -1) {
22240Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_beganon;
22250Sstevel@tonic-gate if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0)
22260Sstevel@tonic-gate return (rval);
22270Sstevel@tonic-gate }
22280Sstevel@tonic-gate
22290Sstevel@tonic-gate for (i = 0; i < max_ncpus; i++) {
22300Sstevel@tonic-gate buf->dtbd_cpu = i;
22310Sstevel@tonic-gate
22320Sstevel@tonic-gate /*
22330Sstevel@tonic-gate * If we have stopped, we want to process the CPU on which the
22340Sstevel@tonic-gate * END probe was processed only _after_ we have processed
22350Sstevel@tonic-gate * everything else.
22360Sstevel@tonic-gate */
22370Sstevel@tonic-gate if (dtp->dt_stopped && (i == dtp->dt_endedon))
22380Sstevel@tonic-gate continue;
22390Sstevel@tonic-gate
22400Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
22410Sstevel@tonic-gate /*
22420Sstevel@tonic-gate * If we failed with ENOENT, it may be because the
22430Sstevel@tonic-gate * CPU was unconfigured -- this is okay. Any other
22440Sstevel@tonic-gate * error, however, is unexpected.
22450Sstevel@tonic-gate */
22460Sstevel@tonic-gate if (errno == ENOENT)
22470Sstevel@tonic-gate continue;
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate return (dt_set_errno(dtp, errno));
22500Sstevel@tonic-gate }
22510Sstevel@tonic-gate
22520Sstevel@tonic-gate if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0)
22530Sstevel@tonic-gate return (rval);
22540Sstevel@tonic-gate }
22550Sstevel@tonic-gate
22560Sstevel@tonic-gate if (!dtp->dt_stopped)
22570Sstevel@tonic-gate return (0);
22580Sstevel@tonic-gate
22590Sstevel@tonic-gate buf->dtbd_cpu = dtp->dt_endedon;
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
22620Sstevel@tonic-gate /*
22630Sstevel@tonic-gate * This _really_ shouldn't fail, but it is strictly speaking
22640Sstevel@tonic-gate * possible for this to return ENOENT if the CPU that called
22650Sstevel@tonic-gate * the END enabling somehow managed to become unconfigured.
22660Sstevel@tonic-gate * It's unclear how the user can possibly expect anything
22670Sstevel@tonic-gate * rational to happen in this case -- the state has been thrown
22680Sstevel@tonic-gate * out along with the unconfigured CPU -- so we'll just drive
22690Sstevel@tonic-gate * on...
22700Sstevel@tonic-gate */
22710Sstevel@tonic-gate if (errno == ENOENT)
22720Sstevel@tonic-gate return (0);
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate return (dt_set_errno(dtp, errno));
22750Sstevel@tonic-gate }
22760Sstevel@tonic-gate
22770Sstevel@tonic-gate return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg));
22780Sstevel@tonic-gate }
2279