xref: /onnv-gate/usr/src/lib/libdtrace/common/dt_consume.c (revision 5984:a183e54573d2)
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
5*5984Sjhaslam  * Common Development and Distribution License (the "License").
6*5984Sjhaslam  * 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*5984Sjhaslam  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <limits.h>
330Sstevel@tonic-gate #include <assert.h>
340Sstevel@tonic-gate #include <ctype.h>
350Sstevel@tonic-gate #include <alloca.h>
36457Sbmc #include <dt_impl.h>
370Sstevel@tonic-gate 
38*5984Sjhaslam #define	DT_MASK_LO 0x00000000FFFFFFFFULL
39*5984Sjhaslam 
40457Sbmc /*
41457Sbmc  * We declare this here because (1) we need it and (2) we want to avoid a
42457Sbmc  * dependency on libm in libdtrace.
43457Sbmc  */
44457Sbmc static long double
45457Sbmc dt_fabsl(long double x)
46457Sbmc {
47457Sbmc 	if (x < 0)
48457Sbmc 		return (-x);
49457Sbmc 
50457Sbmc 	return (x);
51457Sbmc }
520Sstevel@tonic-gate 
53*5984Sjhaslam /*
54*5984Sjhaslam  * 128-bit arithmetic functions needed to support the stddev() aggregating
55*5984Sjhaslam  * action.
56*5984Sjhaslam  */
57*5984Sjhaslam static int
58*5984Sjhaslam dt_gt_128(uint64_t *a, uint64_t *b)
59*5984Sjhaslam {
60*5984Sjhaslam 	return (a[1] > b[1] || (a[1] == b[1] && a[0] > b[0]));
61*5984Sjhaslam }
62*5984Sjhaslam 
63*5984Sjhaslam static int
64*5984Sjhaslam dt_ge_128(uint64_t *a, uint64_t *b)
65*5984Sjhaslam {
66*5984Sjhaslam 	return (a[1] > b[1] || (a[1] == b[1] && a[0] >= b[0]));
67*5984Sjhaslam }
68*5984Sjhaslam 
69*5984Sjhaslam static int
70*5984Sjhaslam dt_le_128(uint64_t *a, uint64_t *b)
71*5984Sjhaslam {
72*5984Sjhaslam 	return (a[1] < b[1] || (a[1] == b[1] && a[0] <= b[0]));
73*5984Sjhaslam }
74*5984Sjhaslam 
75*5984Sjhaslam /*
76*5984Sjhaslam  * Shift the 128-bit value in a by b. If b is positive, shift left.
77*5984Sjhaslam  * If b is negative, shift right.
78*5984Sjhaslam  */
79*5984Sjhaslam static void
80*5984Sjhaslam dt_shift_128(uint64_t *a, int b)
81*5984Sjhaslam {
82*5984Sjhaslam 	uint64_t mask;
83*5984Sjhaslam 
84*5984Sjhaslam 	if (b == 0)
85*5984Sjhaslam 		return;
86*5984Sjhaslam 
87*5984Sjhaslam 	if (b < 0) {
88*5984Sjhaslam 		b = -b;
89*5984Sjhaslam 		if (b >= 64) {
90*5984Sjhaslam 			a[0] = a[1] >> (b - 64);
91*5984Sjhaslam 			a[1] = 0;
92*5984Sjhaslam 		} else {
93*5984Sjhaslam 			a[0] >>= b;
94*5984Sjhaslam 			mask = 1LL << (64 - b);
95*5984Sjhaslam 			mask -= 1;
96*5984Sjhaslam 			a[0] |= ((a[1] & mask) << (64 - b));
97*5984Sjhaslam 			a[1] >>= b;
98*5984Sjhaslam 		}
99*5984Sjhaslam 	} else {
100*5984Sjhaslam 		if (b >= 64) {
101*5984Sjhaslam 			a[1] = a[0] << (b - 64);
102*5984Sjhaslam 			a[0] = 0;
103*5984Sjhaslam 		} else {
104*5984Sjhaslam 			a[1] <<= b;
105*5984Sjhaslam 			mask = a[0] >> (64 - b);
106*5984Sjhaslam 			a[1] |= mask;
107*5984Sjhaslam 			a[0] <<= b;
108*5984Sjhaslam 		}
109*5984Sjhaslam 	}
110*5984Sjhaslam }
111*5984Sjhaslam 
112*5984Sjhaslam static int
113*5984Sjhaslam dt_nbits_128(uint64_t *a)
114*5984Sjhaslam {
115*5984Sjhaslam 	int nbits = 0;
116*5984Sjhaslam 	uint64_t tmp[2];
117*5984Sjhaslam 	uint64_t zero[2] = { 0, 0 };
118*5984Sjhaslam 
119*5984Sjhaslam 	tmp[0] = a[0];
120*5984Sjhaslam 	tmp[1] = a[1];
121*5984Sjhaslam 
122*5984Sjhaslam 	dt_shift_128(tmp, -1);
123*5984Sjhaslam 	while (dt_gt_128(tmp, zero)) {
124*5984Sjhaslam 		dt_shift_128(tmp, -1);
125*5984Sjhaslam 		nbits++;
126*5984Sjhaslam 	}
127*5984Sjhaslam 
128*5984Sjhaslam 	return (nbits);
129*5984Sjhaslam }
130*5984Sjhaslam 
131*5984Sjhaslam static void
132*5984Sjhaslam dt_subtract_128(uint64_t *minuend, uint64_t *subtrahend, uint64_t *difference)
133*5984Sjhaslam {
134*5984Sjhaslam 	uint64_t result[2];
135*5984Sjhaslam 
136*5984Sjhaslam 	result[0] = minuend[0] - subtrahend[0];
137*5984Sjhaslam 	result[1] = minuend[1] - subtrahend[1] -
138*5984Sjhaslam 	    (minuend[0] < subtrahend[0] ? 1 : 0);
139*5984Sjhaslam 
140*5984Sjhaslam 	difference[0] = result[0];
141*5984Sjhaslam 	difference[1] = result[1];
142*5984Sjhaslam }
143*5984Sjhaslam 
144*5984Sjhaslam static void
145*5984Sjhaslam dt_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum)
146*5984Sjhaslam {
147*5984Sjhaslam 	uint64_t result[2];
148*5984Sjhaslam 
149*5984Sjhaslam 	result[0] = addend1[0] + addend2[0];
150*5984Sjhaslam 	result[1] = addend1[1] + addend2[1] +
151*5984Sjhaslam 	    (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0);
152*5984Sjhaslam 
153*5984Sjhaslam 	sum[0] = result[0];
154*5984Sjhaslam 	sum[1] = result[1];
155*5984Sjhaslam }
156*5984Sjhaslam 
157*5984Sjhaslam /*
158*5984Sjhaslam  * The basic idea is to break the 2 64-bit values into 4 32-bit values,
159*5984Sjhaslam  * use native multiplication on those, and then re-combine into the
160*5984Sjhaslam  * resulting 128-bit value.
161*5984Sjhaslam  *
162*5984Sjhaslam  * (hi1 << 32 + lo1) * (hi2 << 32 + lo2) =
163*5984Sjhaslam  *     hi1 * hi2 << 64 +
164*5984Sjhaslam  *     hi1 * lo2 << 32 +
165*5984Sjhaslam  *     hi2 * lo1 << 32 +
166*5984Sjhaslam  *     lo1 * lo2
167*5984Sjhaslam  */
168*5984Sjhaslam static void
169*5984Sjhaslam dt_multiply_128(uint64_t factor1, uint64_t factor2, uint64_t *product)
170*5984Sjhaslam {
171*5984Sjhaslam 	uint64_t hi1, hi2, lo1, lo2;
172*5984Sjhaslam 	uint64_t tmp[2];
173*5984Sjhaslam 
174*5984Sjhaslam 	hi1 = factor1 >> 32;
175*5984Sjhaslam 	hi2 = factor2 >> 32;
176*5984Sjhaslam 
177*5984Sjhaslam 	lo1 = factor1 & DT_MASK_LO;
178*5984Sjhaslam 	lo2 = factor2 & DT_MASK_LO;
179*5984Sjhaslam 
180*5984Sjhaslam 	product[0] = lo1 * lo2;
181*5984Sjhaslam 	product[1] = hi1 * hi2;
182*5984Sjhaslam 
183*5984Sjhaslam 	tmp[0] = hi1 * lo2;
184*5984Sjhaslam 	tmp[1] = 0;
185*5984Sjhaslam 	dt_shift_128(tmp, 32);
186*5984Sjhaslam 	dt_add_128(product, tmp, product);
187*5984Sjhaslam 
188*5984Sjhaslam 	tmp[0] = hi2 * lo1;
189*5984Sjhaslam 	tmp[1] = 0;
190*5984Sjhaslam 	dt_shift_128(tmp, 32);
191*5984Sjhaslam 	dt_add_128(product, tmp, product);
192*5984Sjhaslam }
193*5984Sjhaslam 
194*5984Sjhaslam /*
195*5984Sjhaslam  * This is long-hand division.
196*5984Sjhaslam  *
197*5984Sjhaslam  * We initialize subtrahend by shifting divisor left as far as possible. We
198*5984Sjhaslam  * loop, comparing subtrahend to dividend:  if subtrahend is smaller, we
199*5984Sjhaslam  * subtract and set the appropriate bit in the result.  We then shift
200*5984Sjhaslam  * subtrahend right by one bit for the next comparison.
201*5984Sjhaslam  */
202*5984Sjhaslam static void
203*5984Sjhaslam dt_divide_128(uint64_t *dividend, uint64_t divisor, uint64_t *quotient)
204*5984Sjhaslam {
205*5984Sjhaslam 	uint64_t result[2] = { 0, 0 };
206*5984Sjhaslam 	uint64_t remainder[2];
207*5984Sjhaslam 	uint64_t subtrahend[2];
208*5984Sjhaslam 	uint64_t divisor_128[2];
209*5984Sjhaslam 	uint64_t mask[2] = { 1, 0 };
210*5984Sjhaslam 	int log = 0;
211*5984Sjhaslam 
212*5984Sjhaslam 	assert(divisor != 0);
213*5984Sjhaslam 
214*5984Sjhaslam 	divisor_128[0] = divisor;
215*5984Sjhaslam 	divisor_128[1] = 0;
216*5984Sjhaslam 
217*5984Sjhaslam 	remainder[0] = dividend[0];
218*5984Sjhaslam 	remainder[1] = dividend[1];
219*5984Sjhaslam 
220*5984Sjhaslam 	subtrahend[0] = divisor;
221*5984Sjhaslam 	subtrahend[1] = 0;
222*5984Sjhaslam 
223*5984Sjhaslam 	while (divisor > 0) {
224*5984Sjhaslam 		log++;
225*5984Sjhaslam 		divisor >>= 1;
226*5984Sjhaslam 	}
227*5984Sjhaslam 
228*5984Sjhaslam 	dt_shift_128(subtrahend, 128 - log);
229*5984Sjhaslam 	dt_shift_128(mask, 128 - log);
230*5984Sjhaslam 
231*5984Sjhaslam 	while (dt_ge_128(remainder, divisor_128)) {
232*5984Sjhaslam 		if (dt_ge_128(remainder, subtrahend)) {
233*5984Sjhaslam 			dt_subtract_128(remainder, subtrahend, remainder);
234*5984Sjhaslam 			result[0] |= mask[0];
235*5984Sjhaslam 			result[1] |= mask[1];
236*5984Sjhaslam 		}
237*5984Sjhaslam 
238*5984Sjhaslam 		dt_shift_128(subtrahend, -1);
239*5984Sjhaslam 		dt_shift_128(mask, -1);
240*5984Sjhaslam 	}
241*5984Sjhaslam 
242*5984Sjhaslam 	quotient[0] = result[0];
243*5984Sjhaslam 	quotient[1] = result[1];
244*5984Sjhaslam }
245*5984Sjhaslam 
246*5984Sjhaslam /*
247*5984Sjhaslam  * This is the long-hand method of calculating a square root.
248*5984Sjhaslam  * The algorithm is as follows:
249*5984Sjhaslam  *
250*5984Sjhaslam  * 1. Group the digits by 2 from the right.
251*5984Sjhaslam  * 2. Over the leftmost group, find the largest single-digit number
252*5984Sjhaslam  *    whose square is less than that group.
253*5984Sjhaslam  * 3. Subtract the result of the previous step (2 or 4, depending) and
254*5984Sjhaslam  *    bring down the next two-digit group.
255*5984Sjhaslam  * 4. For the result R we have so far, find the largest single-digit number
256*5984Sjhaslam  *    x such that 2 * R * 10 * x + x^2 is less than the result from step 3.
257*5984Sjhaslam  *    (Note that this is doubling R and performing a decimal left-shift by 1
258*5984Sjhaslam  *    and searching for the appropriate decimal to fill the one's place.)
259*5984Sjhaslam  *    The value x is the next digit in the square root.
260*5984Sjhaslam  * Repeat steps 3 and 4 until the desired precision is reached.  (We're
261*5984Sjhaslam  * dealing with integers, so the above is sufficient.)
262*5984Sjhaslam  *
263*5984Sjhaslam  * In decimal, the square root of 582,734 would be calculated as so:
264*5984Sjhaslam  *
265*5984Sjhaslam  *     __7__6__3
266*5984Sjhaslam  *    | 58 27 34
267*5984Sjhaslam  *     -49       (7^2 == 49 => 7 is the first digit in the square root)
268*5984Sjhaslam  *      --
269*5984Sjhaslam  *       9 27    (Subtract and bring down the next group.)
270*5984Sjhaslam  * 146   8 76    (2 * 7 * 10 * 6 + 6^2 == 876 => 6 is the next digit in
271*5984Sjhaslam  *      -----     the square root)
272*5984Sjhaslam  *         51 34 (Subtract and bring down the next group.)
273*5984Sjhaslam  * 1523    45 69 (2 * 76 * 10 * 3 + 3^2 == 4569 => 3 is the next digit in
274*5984Sjhaslam  *         -----  the square root)
275*5984Sjhaslam  *          5 65 (remainder)
276*5984Sjhaslam  *
277*5984Sjhaslam  * The above algorithm applies similarly in binary, but note that the
278*5984Sjhaslam  * only possible non-zero value for x in step 4 is 1, so step 4 becomes a
279*5984Sjhaslam  * simple decision: is 2 * R * 2 * 1 + 1^2 (aka R << 2 + 1) less than the
280*5984Sjhaslam  * preceding difference?
281*5984Sjhaslam  *
282*5984Sjhaslam  * In binary, the square root of 11011011 would be calculated as so:
283*5984Sjhaslam  *
284*5984Sjhaslam  *     __1__1__1__0
285*5984Sjhaslam  *    | 11 01 10 11
286*5984Sjhaslam  *      01          (0 << 2 + 1 == 1 < 11 => this bit is 1)
287*5984Sjhaslam  *      --
288*5984Sjhaslam  *      10 01 10 11
289*5984Sjhaslam  * 101   1 01       (1 << 2 + 1 == 101 < 1001 => next bit is 1)
290*5984Sjhaslam  *      -----
291*5984Sjhaslam  *       1 00 10 11
292*5984Sjhaslam  * 1101    11 01    (11 << 2 + 1 == 1101 < 10010 => next bit is 1)
293*5984Sjhaslam  *       -------
294*5984Sjhaslam  *          1 01 11
295*5984Sjhaslam  * 11101    1 11 01 (111 << 2 + 1 == 11101 > 10111 => last bit is 0)
296*5984Sjhaslam  *
297*5984Sjhaslam  */
298*5984Sjhaslam static uint64_t
299*5984Sjhaslam dt_sqrt_128(uint64_t *square)
300*5984Sjhaslam {
301*5984Sjhaslam 	uint64_t result[2] = { 0, 0 };
302*5984Sjhaslam 	uint64_t diff[2] = { 0, 0 };
303*5984Sjhaslam 	uint64_t one[2] = { 1, 0 };
304*5984Sjhaslam 	uint64_t next_pair[2];
305*5984Sjhaslam 	uint64_t next_try[2];
306*5984Sjhaslam 	uint64_t bit_pairs, pair_shift;
307*5984Sjhaslam 	int i;
308*5984Sjhaslam 
309*5984Sjhaslam 	bit_pairs = dt_nbits_128(square) / 2;
310*5984Sjhaslam 	pair_shift = bit_pairs * 2;
311*5984Sjhaslam 
312*5984Sjhaslam 	for (i = 0; i <= bit_pairs; i++) {
313*5984Sjhaslam 		/*
314*5984Sjhaslam 		 * Bring down the next pair of bits.
315*5984Sjhaslam 		 */
316*5984Sjhaslam 		next_pair[0] = square[0];
317*5984Sjhaslam 		next_pair[1] = square[1];
318*5984Sjhaslam 		dt_shift_128(next_pair, -pair_shift);
319*5984Sjhaslam 		next_pair[0] &= 0x3;
320*5984Sjhaslam 		next_pair[1] = 0;
321*5984Sjhaslam 
322*5984Sjhaslam 		dt_shift_128(diff, 2);
323*5984Sjhaslam 		dt_add_128(diff, next_pair, diff);
324*5984Sjhaslam 
325*5984Sjhaslam 		/*
326*5984Sjhaslam 		 * next_try = R << 2 + 1
327*5984Sjhaslam 		 */
328*5984Sjhaslam 		next_try[0] = result[0];
329*5984Sjhaslam 		next_try[1] = result[1];
330*5984Sjhaslam 		dt_shift_128(next_try, 2);
331*5984Sjhaslam 		dt_add_128(next_try, one, next_try);
332*5984Sjhaslam 
333*5984Sjhaslam 		if (dt_le_128(next_try, diff)) {
334*5984Sjhaslam 			dt_subtract_128(diff, next_try, diff);
335*5984Sjhaslam 			dt_shift_128(result, 1);
336*5984Sjhaslam 			dt_add_128(result, one, result);
337*5984Sjhaslam 		} else {
338*5984Sjhaslam 			dt_shift_128(result, 1);
339*5984Sjhaslam 		}
340*5984Sjhaslam 
341*5984Sjhaslam 		pair_shift -= 2;
342*5984Sjhaslam 	}
343*5984Sjhaslam 
344*5984Sjhaslam 	assert(result[1] == 0);
345*5984Sjhaslam 
346*5984Sjhaslam 	return (result[0]);
347*5984Sjhaslam }
348*5984Sjhaslam 
349*5984Sjhaslam uint64_t
350*5984Sjhaslam dt_stddev(uint64_t *data, uint64_t normal)
351*5984Sjhaslam {
352*5984Sjhaslam 	uint64_t avg_of_squares[2];
353*5984Sjhaslam 	uint64_t square_of_avg[2];
354*5984Sjhaslam 	int64_t norm_avg;
355*5984Sjhaslam 	uint64_t diff[2];
356*5984Sjhaslam 
357*5984Sjhaslam 	/*
358*5984Sjhaslam 	 * The standard approximation for standard deviation is
359*5984Sjhaslam 	 * sqrt(average(x**2) - average(x)**2), i.e. the square root
360*5984Sjhaslam 	 * of the average of the squares minus the square of the average.
361*5984Sjhaslam 	 */
362*5984Sjhaslam 	dt_divide_128(data + 2, normal, avg_of_squares);
363*5984Sjhaslam 	dt_divide_128(avg_of_squares, data[0], avg_of_squares);
364*5984Sjhaslam 
365*5984Sjhaslam 	norm_avg = (int64_t)data[1] / (int64_t)normal / (int64_t)data[0];
366*5984Sjhaslam 
367*5984Sjhaslam 	if (norm_avg < 0)
368*5984Sjhaslam 		norm_avg = -norm_avg;
369*5984Sjhaslam 
370*5984Sjhaslam 	dt_multiply_128((uint64_t)norm_avg, (uint64_t)norm_avg, square_of_avg);
371*5984Sjhaslam 
372*5984Sjhaslam 	dt_subtract_128(avg_of_squares, square_of_avg, diff);
373*5984Sjhaslam 
374*5984Sjhaslam 	return (dt_sqrt_128(diff));
375*5984Sjhaslam }
376*5984Sjhaslam 
3770Sstevel@tonic-gate static int
3780Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
3790Sstevel@tonic-gate     dtrace_bufdesc_t *buf, size_t offs)
3800Sstevel@tonic-gate {
3810Sstevel@tonic-gate 	dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd;
3820Sstevel@tonic-gate 	dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd;
383457Sbmc 	char *p = pd->dtpd_provider, *n = pd->dtpd_name, *sub;
3840Sstevel@tonic-gate 	dtrace_flowkind_t flow = DTRACEFLOW_NONE;
3850Sstevel@tonic-gate 	const char *str = NULL;
3860Sstevel@tonic-gate 	static const char *e_str[2] = { " -> ", " => " };
3870Sstevel@tonic-gate 	static const char *r_str[2] = { " <- ", " <= " };
388457Sbmc 	static const char *ent = "entry", *ret = "return";
389457Sbmc 	static int entlen = 0, retlen = 0;
3900Sstevel@tonic-gate 	dtrace_epid_t next, id = epd->dtepd_epid;
3910Sstevel@tonic-gate 	int rval;
3920Sstevel@tonic-gate 
393457Sbmc 	if (entlen == 0) {
394457Sbmc 		assert(retlen == 0);
395457Sbmc 		entlen = strlen(ent);
396457Sbmc 		retlen = strlen(ret);
397457Sbmc 	}
398457Sbmc 
399457Sbmc 	/*
400457Sbmc 	 * If the name of the probe is "entry" or ends with "-entry", we
401457Sbmc 	 * treat it as an entry; if it is "return" or ends with "-return",
402457Sbmc 	 * we treat it as a return.  (This allows application-provided probes
403457Sbmc 	 * like "method-entry" or "function-entry" to participate in flow
404457Sbmc 	 * indentation -- without accidentally misinterpreting popular probe
405457Sbmc 	 * names like "carpentry", "gentry" or "Coventry".)
406457Sbmc 	 */
407457Sbmc 	if ((sub = strstr(n, ent)) != NULL && sub[entlen] == '\0' &&
408457Sbmc 	    (sub == n || sub[-1] == '-')) {
4090Sstevel@tonic-gate 		flow = DTRACEFLOW_ENTRY;
4100Sstevel@tonic-gate 		str = e_str[strcmp(p, "syscall") == 0];
411457Sbmc 	} else if ((sub = strstr(n, ret)) != NULL && sub[retlen] == '\0' &&
412457Sbmc 	    (sub == n || sub[-1] == '-')) {
4130Sstevel@tonic-gate 		flow = DTRACEFLOW_RETURN;
4140Sstevel@tonic-gate 		str = r_str[strcmp(p, "syscall") == 0];
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	/*
4180Sstevel@tonic-gate 	 * If we're going to indent this, we need to check the ID of our last
4190Sstevel@tonic-gate 	 * call.  If we're looking at the same probe ID but a different EPID,
4200Sstevel@tonic-gate 	 * we _don't_ want to indent.  (Yes, there are some minor holes in
4210Sstevel@tonic-gate 	 * this scheme -- it's a heuristic.)
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	if (flow == DTRACEFLOW_ENTRY) {
4240Sstevel@tonic-gate 		if ((last != DTRACE_EPIDNONE && id != last &&
4250Sstevel@tonic-gate 		    pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id))
4260Sstevel@tonic-gate 			flow = DTRACEFLOW_NONE;
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	/*
4300Sstevel@tonic-gate 	 * If we're going to unindent this, it's more difficult to see if
4310Sstevel@tonic-gate 	 * we don't actually want to unindent it -- we need to look at the
4320Sstevel@tonic-gate 	 * _next_ EPID.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	if (flow == DTRACEFLOW_RETURN) {
4350Sstevel@tonic-gate 		offs += epd->dtepd_size;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 		do {
4380Sstevel@tonic-gate 			if (offs >= buf->dtbd_size) {
4390Sstevel@tonic-gate 				/*
4400Sstevel@tonic-gate 				 * We're at the end -- maybe.  If the oldest
4410Sstevel@tonic-gate 				 * record is non-zero, we need to wrap.
4420Sstevel@tonic-gate 				 */
4430Sstevel@tonic-gate 				if (buf->dtbd_oldest != 0) {
4440Sstevel@tonic-gate 					offs = 0;
4450Sstevel@tonic-gate 				} else {
4460Sstevel@tonic-gate 					goto out;
4470Sstevel@tonic-gate 				}
4480Sstevel@tonic-gate 			}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 			next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 			if (next == DTRACE_EPIDNONE)
4530Sstevel@tonic-gate 				offs += sizeof (id);
4540Sstevel@tonic-gate 		} while (next == DTRACE_EPIDNONE);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 		if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0)
4570Sstevel@tonic-gate 			return (rval);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 		if (next != id && npd->dtpd_id == pd->dtpd_id)
4600Sstevel@tonic-gate 			flow = DTRACEFLOW_NONE;
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate out:
4640Sstevel@tonic-gate 	if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) {
4650Sstevel@tonic-gate 		data->dtpda_prefix = str;
4660Sstevel@tonic-gate 	} else {
4670Sstevel@tonic-gate 		data->dtpda_prefix = "| ";
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0)
4710Sstevel@tonic-gate 		data->dtpda_indent -= 2;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	data->dtpda_flow = flow;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	return (0);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate static int
4790Sstevel@tonic-gate dt_nullprobe()
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	return (DTRACE_CONSUME_THIS);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate static int
4850Sstevel@tonic-gate dt_nullrec()
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	return (DTRACE_CONSUME_NEXT);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate int
491457Sbmc dt_print_quantline(dtrace_hdl_t *dtp, FILE *fp, int64_t val,
492457Sbmc     uint64_t normal, long double total, char positives, char negatives)
493457Sbmc {
494457Sbmc 	long double f;
495457Sbmc 	uint_t depth, len = 40;
496457Sbmc 
497457Sbmc 	const char *ats = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
498457Sbmc 	const char *spaces = "                                        ";
499457Sbmc 
500457Sbmc 	assert(strlen(ats) == len && strlen(spaces) == len);
501457Sbmc 	assert(!(total == 0 && (positives || negatives)));
502457Sbmc 	assert(!(val < 0 && !negatives));
503457Sbmc 	assert(!(val > 0 && !positives));
504457Sbmc 	assert(!(val != 0 && total == 0));
505457Sbmc 
506457Sbmc 	if (!negatives) {
507457Sbmc 		if (positives) {
508457Sbmc 			f = (dt_fabsl((long double)val) * len) / total;
509457Sbmc 			depth = (uint_t)(f + 0.5);
510457Sbmc 		} else {
511457Sbmc 			depth = 0;
512457Sbmc 		}
513457Sbmc 
514457Sbmc 		return (dt_printf(dtp, fp, "|%s%s %-9lld\n", ats + len - depth,
515457Sbmc 		    spaces + depth, (long long)val / normal));
516457Sbmc 	}
517457Sbmc 
518457Sbmc 	if (!positives) {
519457Sbmc 		f = (dt_fabsl((long double)val) * len) / total;
520457Sbmc 		depth = (uint_t)(f + 0.5);
521457Sbmc 
522457Sbmc 		return (dt_printf(dtp, fp, "%s%s| %-9lld\n", spaces + depth,
523457Sbmc 		    ats + len - depth, (long long)val / normal));
524457Sbmc 	}
525457Sbmc 
526457Sbmc 	/*
527457Sbmc 	 * If we're here, we have both positive and negative bucket values.
528457Sbmc 	 * To express this graphically, we're going to generate both positive
529457Sbmc 	 * and negative bars separated by a centerline.  These bars are half
530457Sbmc 	 * the size of normal quantize()/lquantize() bars, so we divide the
531457Sbmc 	 * length in half before calculating the bar length.
532457Sbmc 	 */
533457Sbmc 	len /= 2;
534457Sbmc 	ats = &ats[len];
535457Sbmc 	spaces = &spaces[len];
536457Sbmc 
537457Sbmc 	f = (dt_fabsl((long double)val) * len) / total;
538457Sbmc 	depth = (uint_t)(f + 0.5);
539457Sbmc 
540457Sbmc 	if (val <= 0) {
541457Sbmc 		return (dt_printf(dtp, fp, "%s%s|%*s %-9lld\n", spaces + depth,
542457Sbmc 		    ats + len - depth, len, "", (long long)val / normal));
543457Sbmc 	} else {
544457Sbmc 		return (dt_printf(dtp, fp, "%20s|%s%s %-9lld\n", "",
545457Sbmc 		    ats + len - depth, spaces + depth,
546457Sbmc 		    (long long)val / normal));
547457Sbmc 	}
548457Sbmc }
549457Sbmc 
550457Sbmc int
5510Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
5520Sstevel@tonic-gate     size_t size, uint64_t normal)
5530Sstevel@tonic-gate {
554457Sbmc 	const int64_t *data = addr;
5550Sstevel@tonic-gate 	int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
556457Sbmc 	long double total = 0;
557457Sbmc 	char positives = 0, negatives = 0;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
5600Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DMISMATCH));
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
5630Sstevel@tonic-gate 		first_bin++;
5640Sstevel@tonic-gate 
565457Sbmc 	if (first_bin == DTRACE_QUANTIZE_NBUCKETS - 1) {
566457Sbmc 		/*
567457Sbmc 		 * There isn't any data.  This is possible if (and only if)
568457Sbmc 		 * negative increment values have been used.  In this case,
569457Sbmc 		 * we'll print the buckets around 0.
570457Sbmc 		 */
571457Sbmc 		first_bin = DTRACE_QUANTIZE_ZEROBUCKET - 1;
572457Sbmc 		last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 1;
573457Sbmc 	} else {
574457Sbmc 		if (first_bin > 0)
575457Sbmc 			first_bin--;
5760Sstevel@tonic-gate 
577457Sbmc 		while (last_bin > 0 && data[last_bin] == 0)
578457Sbmc 			last_bin--;
5790Sstevel@tonic-gate 
580457Sbmc 		if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
581457Sbmc 			last_bin++;
582457Sbmc 	}
583457Sbmc 
584457Sbmc 	for (i = first_bin; i <= last_bin; i++) {
585457Sbmc 		positives |= (data[i] > 0);
586457Sbmc 		negatives |= (data[i] < 0);
587457Sbmc 		total += dt_fabsl((long double)data[i]);
588457Sbmc 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
5910Sstevel@tonic-gate 	    "------------- Distribution -------------", "count") < 0)
5920Sstevel@tonic-gate 		return (-1);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	for (i = first_bin; i <= last_bin; i++) {
595457Sbmc 		if (dt_printf(dtp, fp, "%16lld ",
596457Sbmc 		    (long long)DTRACE_QUANTIZE_BUCKETVAL(i)) < 0)
597457Sbmc 			return (-1);
5980Sstevel@tonic-gate 
599457Sbmc 		if (dt_print_quantline(dtp, fp, data[i], normal, total,
600457Sbmc 		    positives, negatives) < 0)
6010Sstevel@tonic-gate 			return (-1);
6020Sstevel@tonic-gate 	}
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	return (0);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate int
6080Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
6090Sstevel@tonic-gate     size_t size, uint64_t normal)
6100Sstevel@tonic-gate {
611457Sbmc 	const int64_t *data = addr;
6120Sstevel@tonic-gate 	int i, first_bin, last_bin, base;
613457Sbmc 	uint64_t arg;
614457Sbmc 	long double total = 0;
6150Sstevel@tonic-gate 	uint16_t step, levels;
616457Sbmc 	char positives = 0, negatives = 0;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	if (size < sizeof (uint64_t))
6190Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DMISMATCH));
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	arg = *data++;
6220Sstevel@tonic-gate 	size -= sizeof (uint64_t);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	base = DTRACE_LQUANTIZE_BASE(arg);
6250Sstevel@tonic-gate 	step = DTRACE_LQUANTIZE_STEP(arg);
6260Sstevel@tonic-gate 	levels = DTRACE_LQUANTIZE_LEVELS(arg);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	first_bin = 0;
6290Sstevel@tonic-gate 	last_bin = levels + 1;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (size != sizeof (uint64_t) * (levels + 2))
6320Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DMISMATCH));
6330Sstevel@tonic-gate 
634491Sbmc 	while (first_bin <= levels + 1 && data[first_bin] == 0)
6350Sstevel@tonic-gate 		first_bin++;
6360Sstevel@tonic-gate 
637491Sbmc 	if (first_bin > levels + 1) {
638457Sbmc 		first_bin = 0;
639457Sbmc 		last_bin = 2;
640457Sbmc 	} else {
641457Sbmc 		if (first_bin > 0)
642457Sbmc 			first_bin--;
6430Sstevel@tonic-gate 
644457Sbmc 		while (last_bin > 0 && data[last_bin] == 0)
645457Sbmc 			last_bin--;
6460Sstevel@tonic-gate 
647457Sbmc 		if (last_bin < levels + 1)
648457Sbmc 			last_bin++;
649457Sbmc 	}
6500Sstevel@tonic-gate 
651457Sbmc 	for (i = first_bin; i <= last_bin; i++) {
652457Sbmc 		positives |= (data[i] > 0);
653457Sbmc 		negatives |= (data[i] < 0);
654457Sbmc 		total += dt_fabsl((long double)data[i]);
655457Sbmc 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
6580Sstevel@tonic-gate 	    "------------- Distribution -------------", "count") < 0)
6590Sstevel@tonic-gate 		return (-1);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	for (i = first_bin; i <= last_bin; i++) {
6620Sstevel@tonic-gate 		char c[32];
6630Sstevel@tonic-gate 		int err;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 		if (i == 0) {
6660Sstevel@tonic-gate 			(void) snprintf(c, sizeof (c), "< %d",
6670Sstevel@tonic-gate 			    base / (uint32_t)normal);
6680Sstevel@tonic-gate 			err = dt_printf(dtp, fp, "%16s ", c);
6690Sstevel@tonic-gate 		} else if (i == levels + 1) {
6700Sstevel@tonic-gate 			(void) snprintf(c, sizeof (c), ">= %d",
6710Sstevel@tonic-gate 			    base + (levels * step));
6720Sstevel@tonic-gate 			err = dt_printf(dtp, fp, "%16s ", c);
6730Sstevel@tonic-gate 		} else {
6740Sstevel@tonic-gate 			err = dt_printf(dtp, fp, "%16d ",
6750Sstevel@tonic-gate 			    base + (i - 1) * step);
6760Sstevel@tonic-gate 		}
6770Sstevel@tonic-gate 
678457Sbmc 		if (err < 0 || dt_print_quantline(dtp, fp, data[i], normal,
679457Sbmc 		    total, positives, negatives) < 0)
6800Sstevel@tonic-gate 			return (-1);
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	return (0);
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate /*ARGSUSED*/
6870Sstevel@tonic-gate static int
6880Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
6890Sstevel@tonic-gate     size_t size, uint64_t normal)
6900Sstevel@tonic-gate {
6910Sstevel@tonic-gate 	/* LINTED - alignment */
692*5984Sjhaslam 	int64_t *data = (int64_t *)addr;
693*5984Sjhaslam 
694*5984Sjhaslam 	return (dt_printf(dtp, fp, " %16lld", data[0] ?
695*5984Sjhaslam 	    (long long)(data[1] / (int64_t)normal / data[0]) : 0));
696*5984Sjhaslam }
697*5984Sjhaslam 
698*5984Sjhaslam /*ARGSUSED*/
699*5984Sjhaslam static int
700*5984Sjhaslam dt_print_stddev(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
701*5984Sjhaslam     size_t size, uint64_t normal)
702*5984Sjhaslam {
703*5984Sjhaslam 	/* LINTED - alignment */
7040Sstevel@tonic-gate 	uint64_t *data = (uint64_t *)addr;
7050Sstevel@tonic-gate 
706*5984Sjhaslam 	return (dt_printf(dtp, fp, " %16llu", data[0] ?
707*5984Sjhaslam 	    (unsigned long long) dt_stddev(data, normal) : 0));
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate /*ARGSUSED*/
7110Sstevel@tonic-gate int
7120Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
7130Sstevel@tonic-gate     size_t nbytes, int width, int quiet)
7140Sstevel@tonic-gate {
7150Sstevel@tonic-gate 	/*
7160Sstevel@tonic-gate 	 * If the byte stream is a series of printable characters, followed by
7170Sstevel@tonic-gate 	 * a terminating byte, we print it out as a string.  Otherwise, we
7180Sstevel@tonic-gate 	 * assume that it's something else and just print the bytes.
7190Sstevel@tonic-gate 	 */
7200Sstevel@tonic-gate 	int i, j, margin = 5;
7210Sstevel@tonic-gate 	char *c = (char *)addr;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (nbytes == 0)
7240Sstevel@tonic-gate 		return (0);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
7270Sstevel@tonic-gate 		goto raw;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	for (i = 0; i < nbytes; i++) {
7300Sstevel@tonic-gate 		/*
7310Sstevel@tonic-gate 		 * We define a "printable character" to be one for which
7320Sstevel@tonic-gate 		 * isprint(3C) returns non-zero, isspace(3C) returns non-zero,
7330Sstevel@tonic-gate 		 * or a character which is either backspace or the bell.
7340Sstevel@tonic-gate 		 * Backspace and the bell are regrettably special because
7350Sstevel@tonic-gate 		 * they fail the first two tests -- and yet they are entirely
7360Sstevel@tonic-gate 		 * printable.  These are the only two control characters that
7370Sstevel@tonic-gate 		 * have meaning for the terminal and for which isprint(3C) and
7380Sstevel@tonic-gate 		 * isspace(3C) return 0.
7390Sstevel@tonic-gate 		 */
7400Sstevel@tonic-gate 		if (isprint(c[i]) || isspace(c[i]) ||
7410Sstevel@tonic-gate 		    c[i] == '\b' || c[i] == '\a')
7420Sstevel@tonic-gate 			continue;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		if (c[i] == '\0' && i > 0) {
7450Sstevel@tonic-gate 			/*
7460Sstevel@tonic-gate 			 * This looks like it might be a string.  Before we
7470Sstevel@tonic-gate 			 * assume that it is indeed a string, check the
7480Sstevel@tonic-gate 			 * remainder of the byte range; if it contains
7490Sstevel@tonic-gate 			 * additional non-nul characters, we'll assume that
7500Sstevel@tonic-gate 			 * it's a binary stream that just happens to look like
7510Sstevel@tonic-gate 			 * a string, and we'll print out the individual bytes.
7520Sstevel@tonic-gate 			 */
7530Sstevel@tonic-gate 			for (j = i + 1; j < nbytes; j++) {
7540Sstevel@tonic-gate 				if (c[j] != '\0')
7550Sstevel@tonic-gate 					break;
7560Sstevel@tonic-gate 			}
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 			if (j != nbytes)
7590Sstevel@tonic-gate 				break;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 			if (quiet)
7620Sstevel@tonic-gate 				return (dt_printf(dtp, fp, "%s", c));
7630Sstevel@tonic-gate 			else
7640Sstevel@tonic-gate 				return (dt_printf(dtp, fp, "  %-*s", width, c));
7650Sstevel@tonic-gate 		}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 		break;
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	if (i == nbytes) {
7710Sstevel@tonic-gate 		/*
7720Sstevel@tonic-gate 		 * The byte range is all printable characters, but there is
7730Sstevel@tonic-gate 		 * no trailing nul byte.  We'll assume that it's a string and
7740Sstevel@tonic-gate 		 * print it as such.
7750Sstevel@tonic-gate 		 */
7760Sstevel@tonic-gate 		char *s = alloca(nbytes + 1);
7770Sstevel@tonic-gate 		bcopy(c, s, nbytes);
7780Sstevel@tonic-gate 		s[nbytes] = '\0';
7790Sstevel@tonic-gate 		return (dt_printf(dtp, fp, "  %-*s", width, s));
7800Sstevel@tonic-gate 	}
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate raw:
7830Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n%*s      ", margin, "") < 0)
7840Sstevel@tonic-gate 		return (-1);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
7870Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "  %c", "0123456789abcdef"[i]) < 0)
7880Sstevel@tonic-gate 			return (-1);
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "  0123456789abcdef\n") < 0)
7910Sstevel@tonic-gate 		return (-1);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	for (i = 0; i < nbytes; i += 16) {
7950Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0)
7960Sstevel@tonic-gate 			return (-1);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 		for (j = i; j < i + 16 && j < nbytes; j++) {
7990Sstevel@tonic-gate 			if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0)
8000Sstevel@tonic-gate 				return (-1);
8010Sstevel@tonic-gate 		}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 		while (j++ % 16) {
8040Sstevel@tonic-gate 			if (dt_printf(dtp, fp, "   ") < 0)
8050Sstevel@tonic-gate 				return (-1);
8060Sstevel@tonic-gate 		}
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "  ") < 0)
8090Sstevel@tonic-gate 			return (-1);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 		for (j = i; j < i + 16 && j < nbytes; j++) {
8120Sstevel@tonic-gate 			if (dt_printf(dtp, fp, "%c",
8130Sstevel@tonic-gate 			    c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0)
8140Sstevel@tonic-gate 				return (-1);
8150Sstevel@tonic-gate 		}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "\n") < 0)
8180Sstevel@tonic-gate 			return (-1);
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	return (0);
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate int
8250Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
826457Sbmc     caddr_t addr, int depth, int size)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate 	dtrace_syminfo_t dts;
8290Sstevel@tonic-gate 	GElf_Sym sym;
8300Sstevel@tonic-gate 	int i, indent;
8310Sstevel@tonic-gate 	char c[PATH_MAX * 2];
832457Sbmc 	uint64_t pc;
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n") < 0)
8350Sstevel@tonic-gate 		return (-1);
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	if (format == NULL)
8380Sstevel@tonic-gate 		format = "%s";
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
8410Sstevel@tonic-gate 		indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
8420Sstevel@tonic-gate 	else
8430Sstevel@tonic-gate 		indent = _dtrace_stkindent;
8440Sstevel@tonic-gate 
845457Sbmc 	for (i = 0; i < depth; i++) {
846457Sbmc 		switch (size) {
847457Sbmc 		case sizeof (uint32_t):
848457Sbmc 			/* LINTED - alignment */
849457Sbmc 			pc = *((uint32_t *)addr);
850457Sbmc 			break;
851457Sbmc 
852457Sbmc 		case sizeof (uint64_t):
853457Sbmc 			/* LINTED - alignment */
854457Sbmc 			pc = *((uint64_t *)addr);
855457Sbmc 			break;
856457Sbmc 
857457Sbmc 		default:
858457Sbmc 			return (dt_set_errno(dtp, EDT_BADSTACKPC));
859457Sbmc 		}
860457Sbmc 
861457Sbmc 		if (pc == NULL)
862457Sbmc 			break;
863457Sbmc 
864457Sbmc 		addr += size;
865457Sbmc 
8660Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
8670Sstevel@tonic-gate 			return (-1);
8680Sstevel@tonic-gate 
869457Sbmc 		if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
870457Sbmc 			if (pc > sym.st_value) {
8710Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
8720Sstevel@tonic-gate 				    dts.dts_object, dts.dts_name,
873457Sbmc 				    pc - sym.st_value);
8740Sstevel@tonic-gate 			} else {
8750Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`%s",
8760Sstevel@tonic-gate 				    dts.dts_object, dts.dts_name);
8770Sstevel@tonic-gate 			}
8780Sstevel@tonic-gate 		} else {
8790Sstevel@tonic-gate 			/*
8800Sstevel@tonic-gate 			 * We'll repeat the lookup, but this time we'll specify
8810Sstevel@tonic-gate 			 * a NULL GElf_Sym -- indicating that we're only
8820Sstevel@tonic-gate 			 * interested in the containing module.
8830Sstevel@tonic-gate 			 */
884457Sbmc 			if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
8850Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
886457Sbmc 				    dts.dts_object, pc);
8870Sstevel@tonic-gate 			} else {
888457Sbmc 				(void) snprintf(c, sizeof (c), "0x%llx", pc);
8890Sstevel@tonic-gate 			}
8900Sstevel@tonic-gate 		}
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 		if (dt_printf(dtp, fp, format, c) < 0)
8930Sstevel@tonic-gate 			return (-1);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "\n") < 0)
8960Sstevel@tonic-gate 			return (-1);
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	return (0);
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate int
9030Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
9040Sstevel@tonic-gate     caddr_t addr, uint64_t arg)
9050Sstevel@tonic-gate {
906457Sbmc 	/* LINTED - alignment */
907457Sbmc 	uint64_t *pc = (uint64_t *)addr;
9080Sstevel@tonic-gate 	uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
9090Sstevel@tonic-gate 	uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
9100Sstevel@tonic-gate 	const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
9110Sstevel@tonic-gate 	const char *str = strsize ? strbase : NULL;
9120Sstevel@tonic-gate 	int err = 0;
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
9150Sstevel@tonic-gate 	struct ps_prochandle *P;
9160Sstevel@tonic-gate 	GElf_Sym sym;
9170Sstevel@tonic-gate 	int i, indent;
9180Sstevel@tonic-gate 	pid_t pid;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	if (depth == 0)
9210Sstevel@tonic-gate 		return (0);
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	pid = (pid_t)*pc++;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n") < 0)
9260Sstevel@tonic-gate 		return (-1);
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	if (format == NULL)
9290Sstevel@tonic-gate 		format = "%s";
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
9320Sstevel@tonic-gate 		indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
9330Sstevel@tonic-gate 	else
9340Sstevel@tonic-gate 		indent = _dtrace_stkindent;
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * Ultimately, we need to add an entry point in the library vector for
9380Sstevel@tonic-gate 	 * determining <symbol, offset> from <pid, address>.  For now, if
9390Sstevel@tonic-gate 	 * this is a vector open, we just print the raw address or string.
9400Sstevel@tonic-gate 	 */
9410Sstevel@tonic-gate 	if (dtp->dt_vector == NULL)
9420Sstevel@tonic-gate 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
9430Sstevel@tonic-gate 	else
9440Sstevel@tonic-gate 		P = NULL;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	if (P != NULL)
9470Sstevel@tonic-gate 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	for (i = 0; i < depth && pc[i] != NULL; i++) {
950457Sbmc 		const prmap_t *map;
951457Sbmc 
9520Sstevel@tonic-gate 		if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
9530Sstevel@tonic-gate 			break;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		if (P != NULL && Plookup_by_addr(P, pc[i],
9560Sstevel@tonic-gate 		    name, sizeof (name), &sym) == 0) {
9570Sstevel@tonic-gate 			(void) Pobjname(P, pc[i], objname, sizeof (objname));
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 			if (pc[i] > sym.st_value) {
9600Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c),
9610Sstevel@tonic-gate 				    "%s`%s+0x%llx", dt_basename(objname), name,
9620Sstevel@tonic-gate 				    (u_longlong_t)(pc[i] - sym.st_value));
9630Sstevel@tonic-gate 			} else {
9640Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c),
9650Sstevel@tonic-gate 				    "%s`%s", dt_basename(objname), name);
9660Sstevel@tonic-gate 			}
967491Sbmc 		} else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
968457Sbmc 		    (P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
969457Sbmc 		    (map->pr_mflags & MA_WRITE)))) {
970457Sbmc 			/*
971457Sbmc 			 * If the current string pointer in the string table
972457Sbmc 			 * does not point to an empty string _and_ the program
973457Sbmc 			 * counter falls in a writable region, we'll use the
974457Sbmc 			 * string from the string table instead of the raw
975457Sbmc 			 * address.  This last condition is necessary because
976457Sbmc 			 * some (broken) ustack helpers will return a string
977457Sbmc 			 * even for a program counter that they can't
978457Sbmc 			 * identify.  If we have a string for a program
979457Sbmc 			 * counter that falls in a segment that isn't
980457Sbmc 			 * writable, we assume that we have fallen into this
981457Sbmc 			 * case and we refuse to use the string.
982457Sbmc 			 */
9830Sstevel@tonic-gate 			(void) snprintf(c, sizeof (c), "%s", str);
9840Sstevel@tonic-gate 		} else {
9850Sstevel@tonic-gate 			if (P != NULL && Pobjname(P, pc[i], objname,
9860Sstevel@tonic-gate 			    sizeof (objname)) != NULL) {
9870Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
9880Sstevel@tonic-gate 				    dt_basename(objname), (u_longlong_t)pc[i]);
9890Sstevel@tonic-gate 			} else {
9900Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "0x%llx",
9910Sstevel@tonic-gate 				    (u_longlong_t)pc[i]);
9920Sstevel@tonic-gate 			}
9930Sstevel@tonic-gate 		}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 		if ((err = dt_printf(dtp, fp, format, c)) < 0)
9960Sstevel@tonic-gate 			break;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 		if ((err = dt_printf(dtp, fp, "\n")) < 0)
9990Sstevel@tonic-gate 			break;
10000Sstevel@tonic-gate 
1001491Sbmc 		if (str != NULL && str[0] == '@') {
1002491Sbmc 			/*
1003491Sbmc 			 * If the first character of the string is an "at" sign,
1004491Sbmc 			 * then the string is inferred to be an annotation --
1005491Sbmc 			 * and it is printed out beneath the frame and offset
1006491Sbmc 			 * with brackets.
1007491Sbmc 			 */
1008491Sbmc 			if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
1009491Sbmc 				break;
1010491Sbmc 
1011491Sbmc 			(void) snprintf(c, sizeof (c), "  [ %s ]", &str[1]);
1012491Sbmc 
1013491Sbmc 			if ((err = dt_printf(dtp, fp, format, c)) < 0)
1014491Sbmc 				break;
1015491Sbmc 
1016491Sbmc 			if ((err = dt_printf(dtp, fp, "\n")) < 0)
1017491Sbmc 				break;
1018491Sbmc 		}
1019491Sbmc 
10200Sstevel@tonic-gate 		if (str != NULL) {
10210Sstevel@tonic-gate 			str += strlen(str) + 1;
10220Sstevel@tonic-gate 			if (str - strbase >= strsize)
10230Sstevel@tonic-gate 				str = NULL;
10240Sstevel@tonic-gate 		}
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	if (P != NULL) {
10280Sstevel@tonic-gate 		dt_proc_unlock(dtp, P);
10290Sstevel@tonic-gate 		dt_proc_release(dtp, P);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	return (err);
10330Sstevel@tonic-gate }
10340Sstevel@tonic-gate 
1035457Sbmc static int
1036457Sbmc dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
1037457Sbmc {
1038457Sbmc 	/* LINTED - alignment */
1039457Sbmc 	uint64_t pid = ((uint64_t *)addr)[0];
1040457Sbmc 	/* LINTED - alignment */
1041457Sbmc 	uint64_t pc = ((uint64_t *)addr)[1];
1042457Sbmc 	const char *format = "  %-50s";
1043457Sbmc 	char *s;
1044457Sbmc 	int n, len = 256;
1045457Sbmc 
1046457Sbmc 	if (act == DTRACEACT_USYM && dtp->dt_vector == NULL) {
1047457Sbmc 		struct ps_prochandle *P;
1048457Sbmc 
1049457Sbmc 		if ((P = dt_proc_grab(dtp, pid,
1050457Sbmc 		    PGRAB_RDONLY | PGRAB_FORCE, 0)) != NULL) {
1051457Sbmc 			GElf_Sym sym;
1052457Sbmc 
1053457Sbmc 			dt_proc_lock(dtp, P);
1054457Sbmc 
1055457Sbmc 			if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
1056457Sbmc 				pc = sym.st_value;
1057457Sbmc 
1058457Sbmc 			dt_proc_unlock(dtp, P);
1059457Sbmc 			dt_proc_release(dtp, P);
1060457Sbmc 		}
1061457Sbmc 	}
1062457Sbmc 
1063457Sbmc 	do {
1064457Sbmc 		n = len;
1065457Sbmc 		s = alloca(n);
1066457Sbmc 	} while ((len = dtrace_uaddr2str(dtp, pid, pc, s, n)) >= n);
1067457Sbmc 
1068457Sbmc 	return (dt_printf(dtp, fp, format, s));
1069457Sbmc }
1070457Sbmc 
1071457Sbmc int
1072457Sbmc dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
1073457Sbmc {
1074457Sbmc 	/* LINTED - alignment */
1075457Sbmc 	uint64_t pid = ((uint64_t *)addr)[0];
1076457Sbmc 	/* LINTED - alignment */
1077457Sbmc 	uint64_t pc = ((uint64_t *)addr)[1];
1078457Sbmc 	int err = 0;
1079457Sbmc 
1080457Sbmc 	char objname[PATH_MAX], c[PATH_MAX * 2];
1081457Sbmc 	struct ps_prochandle *P;
1082457Sbmc 
1083457Sbmc 	if (format == NULL)
1084457Sbmc 		format = "  %-50s";
1085457Sbmc 
1086457Sbmc 	/*
1087457Sbmc 	 * See the comment in dt_print_ustack() for the rationale for
1088457Sbmc 	 * printing raw addresses in the vectored case.
1089457Sbmc 	 */
1090457Sbmc 	if (dtp->dt_vector == NULL)
1091457Sbmc 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
1092457Sbmc 	else
1093457Sbmc 		P = NULL;
1094457Sbmc 
1095457Sbmc 	if (P != NULL)
1096457Sbmc 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
1097457Sbmc 
1098457Sbmc 	if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != NULL) {
1099457Sbmc 		(void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
1100457Sbmc 	} else {
1101457Sbmc 		(void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
1102457Sbmc 	}
1103457Sbmc 
1104457Sbmc 	err = dt_printf(dtp, fp, format, c);
1105457Sbmc 
1106457Sbmc 	if (P != NULL) {
1107457Sbmc 		dt_proc_unlock(dtp, P);
1108457Sbmc 		dt_proc_release(dtp, P);
1109457Sbmc 	}
1110457Sbmc 
1111457Sbmc 	return (err);
1112457Sbmc }
1113457Sbmc 
1114457Sbmc static int
1115457Sbmc dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
1116457Sbmc {
1117457Sbmc 	/* LINTED - alignment */
1118457Sbmc 	uint64_t pc = *((uint64_t *)addr);
1119457Sbmc 	dtrace_syminfo_t dts;
1120457Sbmc 	GElf_Sym sym;
1121457Sbmc 	char c[PATH_MAX * 2];
1122457Sbmc 
1123457Sbmc 	if (format == NULL)
1124457Sbmc 		format = "  %-50s";
1125457Sbmc 
1126457Sbmc 	if (dtrace_lookup_by_addr(dtp, pc, &sym, &dts) == 0) {
1127457Sbmc 		(void) snprintf(c, sizeof (c), "%s`%s",
1128457Sbmc 		    dts.dts_object, dts.dts_name);
1129457Sbmc 	} else {
1130457Sbmc 		/*
1131457Sbmc 		 * We'll repeat the lookup, but this time we'll specify a
1132457Sbmc 		 * NULL GElf_Sym -- indicating that we're only interested in
1133457Sbmc 		 * the containing module.
1134457Sbmc 		 */
1135457Sbmc 		if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
1136457Sbmc 			(void) snprintf(c, sizeof (c), "%s`0x%llx",
1137457Sbmc 			    dts.dts_object, (u_longlong_t)pc);
1138457Sbmc 		} else {
1139457Sbmc 			(void) snprintf(c, sizeof (c), "0x%llx",
1140457Sbmc 			    (u_longlong_t)pc);
1141457Sbmc 		}
1142457Sbmc 	}
1143457Sbmc 
1144457Sbmc 	if (dt_printf(dtp, fp, format, c) < 0)
1145457Sbmc 		return (-1);
1146457Sbmc 
1147457Sbmc 	return (0);
1148457Sbmc }
1149457Sbmc 
1150457Sbmc int
1151457Sbmc dt_print_mod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
1152457Sbmc {
1153457Sbmc 	/* LINTED - alignment */
1154457Sbmc 	uint64_t pc = *((uint64_t *)addr);
1155457Sbmc 	dtrace_syminfo_t dts;
1156457Sbmc 	char c[PATH_MAX * 2];
1157457Sbmc 
1158457Sbmc 	if (format == NULL)
1159457Sbmc 		format = "  %-50s";
1160457Sbmc 
1161457Sbmc 	if (dtrace_lookup_by_addr(dtp, pc, NULL, &dts) == 0) {
1162457Sbmc 		(void) snprintf(c, sizeof (c), "%s", dts.dts_object);
1163457Sbmc 	} else {
1164457Sbmc 		(void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);
1165457Sbmc 	}
1166457Sbmc 
1167457Sbmc 	if (dt_printf(dtp, fp, format, c) < 0)
1168457Sbmc 		return (-1);
1169457Sbmc 
1170457Sbmc 	return (0);
1171457Sbmc }
1172457Sbmc 
11730Sstevel@tonic-gate typedef struct dt_normal {
11740Sstevel@tonic-gate 	dtrace_aggvarid_t dtnd_id;
11750Sstevel@tonic-gate 	uint64_t dtnd_normal;
11760Sstevel@tonic-gate } dt_normal_t;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate static int
1179457Sbmc dt_normalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
11800Sstevel@tonic-gate {
11810Sstevel@tonic-gate 	dt_normal_t *normal = arg;
11820Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
11830Sstevel@tonic-gate 	dtrace_aggvarid_t id = normal->dtnd_id;
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
11860Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
11870Sstevel@tonic-gate 
11881017Sbmc 	if (agg->dtagd_varid != id)
11890Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
11900Sstevel@tonic-gate 
1191457Sbmc 	((dtrace_aggdata_t *)aggdata)->dtada_normal = normal->dtnd_normal;
11920Sstevel@tonic-gate 	return (DTRACE_AGGWALK_NORMALIZE);
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate static int
11960Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
11970Sstevel@tonic-gate {
11980Sstevel@tonic-gate 	dt_normal_t normal;
11990Sstevel@tonic-gate 	caddr_t addr;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 	/*
12020Sstevel@tonic-gate 	 * We (should) have two records:  the aggregation ID followed by the
12030Sstevel@tonic-gate 	 * normalization value.
12040Sstevel@tonic-gate 	 */
12050Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
12080Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	/* LINTED - alignment */
12110Sstevel@tonic-gate 	normal.dtnd_id = *((dtrace_aggvarid_t *)addr);
12120Sstevel@tonic-gate 	rec++;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 	if (rec->dtrd_action != DTRACEACT_LIBACT)
12150Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	if (rec->dtrd_arg != DT_ACT_NORMALIZE)
12180Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	switch (rec->dtrd_size) {
12230Sstevel@tonic-gate 	case sizeof (uint64_t):
12240Sstevel@tonic-gate 		/* LINTED - alignment */
12250Sstevel@tonic-gate 		normal.dtnd_normal = *((uint64_t *)addr);
12260Sstevel@tonic-gate 		break;
12270Sstevel@tonic-gate 	case sizeof (uint32_t):
12280Sstevel@tonic-gate 		/* LINTED - alignment */
12290Sstevel@tonic-gate 		normal.dtnd_normal = *((uint32_t *)addr);
12300Sstevel@tonic-gate 		break;
12310Sstevel@tonic-gate 	case sizeof (uint16_t):
12320Sstevel@tonic-gate 		/* LINTED - alignment */
12330Sstevel@tonic-gate 		normal.dtnd_normal = *((uint16_t *)addr);
12340Sstevel@tonic-gate 		break;
12350Sstevel@tonic-gate 	case sizeof (uint8_t):
12360Sstevel@tonic-gate 		normal.dtnd_normal = *((uint8_t *)addr);
12370Sstevel@tonic-gate 		break;
12380Sstevel@tonic-gate 	default:
12390Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	(void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal);
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	return (0);
12450Sstevel@tonic-gate }
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate static int
1248457Sbmc dt_denormalize_agg(const dtrace_aggdata_t *aggdata, void *arg)
12490Sstevel@tonic-gate {
12500Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
12510Sstevel@tonic-gate 	dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
12540Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
12550Sstevel@tonic-gate 
12561017Sbmc 	if (agg->dtagd_varid != id)
12570Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	return (DTRACE_AGGWALK_DENORMALIZE);
12600Sstevel@tonic-gate }
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate static int
1263457Sbmc dt_clear_agg(const dtrace_aggdata_t *aggdata, void *arg)
12640Sstevel@tonic-gate {
12650Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
12660Sstevel@tonic-gate 	dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
12690Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
12700Sstevel@tonic-gate 
12711017Sbmc 	if (agg->dtagd_varid != id)
12720Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	return (DTRACE_AGGWALK_CLEAR);
12750Sstevel@tonic-gate }
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate typedef struct dt_trunc {
12780Sstevel@tonic-gate 	dtrace_aggvarid_t dttd_id;
12790Sstevel@tonic-gate 	uint64_t dttd_remaining;
12800Sstevel@tonic-gate } dt_trunc_t;
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate static int
1283457Sbmc dt_trunc_agg(const dtrace_aggdata_t *aggdata, void *arg)
12840Sstevel@tonic-gate {
12850Sstevel@tonic-gate 	dt_trunc_t *trunc = arg;
12860Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
12870Sstevel@tonic-gate 	dtrace_aggvarid_t id = trunc->dttd_id;
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
12900Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
12910Sstevel@tonic-gate 
12921017Sbmc 	if (agg->dtagd_varid != id)
12930Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 	if (trunc->dttd_remaining == 0)
12960Sstevel@tonic-gate 		return (DTRACE_AGGWALK_REMOVE);
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	trunc->dttd_remaining--;
12990Sstevel@tonic-gate 	return (DTRACE_AGGWALK_NEXT);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate static int
13030Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
13040Sstevel@tonic-gate {
13050Sstevel@tonic-gate 	dt_trunc_t trunc;
13060Sstevel@tonic-gate 	caddr_t addr;
13070Sstevel@tonic-gate 	int64_t remaining;
13080Sstevel@tonic-gate 	int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	/*
13110Sstevel@tonic-gate 	 * We (should) have two records:  the aggregation ID followed by the
13120Sstevel@tonic-gate 	 * number of aggregation entries after which the aggregation is to be
13130Sstevel@tonic-gate 	 * truncated.
13140Sstevel@tonic-gate 	 */
13150Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
13180Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADTRUNC));
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 	/* LINTED - alignment */
13210Sstevel@tonic-gate 	trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
13220Sstevel@tonic-gate 	rec++;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	if (rec->dtrd_action != DTRACEACT_LIBACT)
13250Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADTRUNC));
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	if (rec->dtrd_arg != DT_ACT_TRUNC)
13280Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADTRUNC));
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	switch (rec->dtrd_size) {
13330Sstevel@tonic-gate 	case sizeof (uint64_t):
13340Sstevel@tonic-gate 		/* LINTED - alignment */
13350Sstevel@tonic-gate 		remaining = *((int64_t *)addr);
13360Sstevel@tonic-gate 		break;
13370Sstevel@tonic-gate 	case sizeof (uint32_t):
13380Sstevel@tonic-gate 		/* LINTED - alignment */
13390Sstevel@tonic-gate 		remaining = *((int32_t *)addr);
13400Sstevel@tonic-gate 		break;
13410Sstevel@tonic-gate 	case sizeof (uint16_t):
13420Sstevel@tonic-gate 		/* LINTED - alignment */
13430Sstevel@tonic-gate 		remaining = *((int16_t *)addr);
13440Sstevel@tonic-gate 		break;
13450Sstevel@tonic-gate 	case sizeof (uint8_t):
13460Sstevel@tonic-gate 		remaining = *((int8_t *)addr);
13470Sstevel@tonic-gate 		break;
13480Sstevel@tonic-gate 	default:
13490Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
13500Sstevel@tonic-gate 	}
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	if (remaining < 0) {
13530Sstevel@tonic-gate 		func = dtrace_aggregate_walk_valsorted;
13540Sstevel@tonic-gate 		remaining = -remaining;
13550Sstevel@tonic-gate 	} else {
13560Sstevel@tonic-gate 		func = dtrace_aggregate_walk_valrevsorted;
13570Sstevel@tonic-gate 	}
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	assert(remaining >= 0);
13600Sstevel@tonic-gate 	trunc.dttd_remaining = remaining;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	(void) func(dtp, dt_trunc_agg, &trunc);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	return (0);
13650Sstevel@tonic-gate }
13660Sstevel@tonic-gate 
13671017Sbmc static int
13681017Sbmc dt_print_datum(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
13691017Sbmc     caddr_t addr, size_t size, uint64_t normal)
13701017Sbmc {
13711017Sbmc 	int err;
13721017Sbmc 	dtrace_actkind_t act = rec->dtrd_action;
13731017Sbmc 
13741017Sbmc 	switch (act) {
13751017Sbmc 	case DTRACEACT_STACK:
13761017Sbmc 		return (dt_print_stack(dtp, fp, NULL, addr,
13771017Sbmc 		    rec->dtrd_arg, rec->dtrd_size / rec->dtrd_arg));
13781017Sbmc 
13791017Sbmc 	case DTRACEACT_USTACK:
13801017Sbmc 	case DTRACEACT_JSTACK:
13811017Sbmc 		return (dt_print_ustack(dtp, fp, NULL, addr, rec->dtrd_arg));
13821017Sbmc 
13831017Sbmc 	case DTRACEACT_USYM:
13841017Sbmc 	case DTRACEACT_UADDR:
13851017Sbmc 		return (dt_print_usym(dtp, fp, addr, act));
13861017Sbmc 
13871017Sbmc 	case DTRACEACT_UMOD:
13881017Sbmc 		return (dt_print_umod(dtp, fp, NULL, addr));
13891017Sbmc 
13901017Sbmc 	case DTRACEACT_SYM:
13911017Sbmc 		return (dt_print_sym(dtp, fp, NULL, addr));
13921017Sbmc 
13931017Sbmc 	case DTRACEACT_MOD:
13941017Sbmc 		return (dt_print_mod(dtp, fp, NULL, addr));
13951017Sbmc 
13961017Sbmc 	case DTRACEAGG_QUANTIZE:
13971017Sbmc 		return (dt_print_quantize(dtp, fp, addr, size, normal));
13981017Sbmc 
13991017Sbmc 	case DTRACEAGG_LQUANTIZE:
14001017Sbmc 		return (dt_print_lquantize(dtp, fp, addr, size, normal));
14011017Sbmc 
14021017Sbmc 	case DTRACEAGG_AVG:
14031017Sbmc 		return (dt_print_average(dtp, fp, addr, size, normal));
14041017Sbmc 
1405*5984Sjhaslam 	case DTRACEAGG_STDDEV:
1406*5984Sjhaslam 		return (dt_print_stddev(dtp, fp, addr, size, normal));
1407*5984Sjhaslam 
14081017Sbmc 	default:
14091017Sbmc 		break;
14101017Sbmc 	}
14111017Sbmc 
14121017Sbmc 	switch (size) {
14131017Sbmc 	case sizeof (uint64_t):
14141017Sbmc 		err = dt_printf(dtp, fp, " %16lld",
14151017Sbmc 		    /* LINTED - alignment */
14161017Sbmc 		    (long long)*((uint64_t *)addr) / normal);
14171017Sbmc 		break;
14181017Sbmc 	case sizeof (uint32_t):
14191017Sbmc 		/* LINTED - alignment */
14201017Sbmc 		err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) /
14211017Sbmc 		    (uint32_t)normal);
14221017Sbmc 		break;
14231017Sbmc 	case sizeof (uint16_t):
14241017Sbmc 		/* LINTED - alignment */
14251017Sbmc 		err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) /
14261017Sbmc 		    (uint32_t)normal);
14271017Sbmc 		break;
14281017Sbmc 	case sizeof (uint8_t):
14291017Sbmc 		err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) /
14301017Sbmc 		    (uint32_t)normal);
14311017Sbmc 		break;
14321017Sbmc 	default:
14331017Sbmc 		err = dt_print_bytes(dtp, fp, addr, size, 50, 0);
14341017Sbmc 		break;
14351017Sbmc 	}
14361017Sbmc 
14371017Sbmc 	return (err);
14381017Sbmc }
14391017Sbmc 
14401017Sbmc int
14411017Sbmc dt_print_aggs(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
14421017Sbmc {
14431017Sbmc 	int i, aggact = 0;
14441017Sbmc 	dt_print_aggdata_t *pd = arg;
14451017Sbmc 	const dtrace_aggdata_t *aggdata = aggsdata[0];
14461017Sbmc 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
14471017Sbmc 	FILE *fp = pd->dtpa_fp;
14481017Sbmc 	dtrace_hdl_t *dtp = pd->dtpa_dtp;
14491017Sbmc 	dtrace_recdesc_t *rec;
14501017Sbmc 	dtrace_actkind_t act;
14511017Sbmc 	caddr_t addr;
14521017Sbmc 	size_t size;
14531017Sbmc 
14541017Sbmc 	/*
14551017Sbmc 	 * Iterate over each record description in the key, printing the traced
14561017Sbmc 	 * data, skipping the first datum (the tuple member created by the
14571017Sbmc 	 * compiler).
14581017Sbmc 	 */
14591017Sbmc 	for (i = 1; i < agg->dtagd_nrecs; i++) {
14601017Sbmc 		rec = &agg->dtagd_rec[i];
14611017Sbmc 		act = rec->dtrd_action;
14621017Sbmc 		addr = aggdata->dtada_data + rec->dtrd_offset;
14631017Sbmc 		size = rec->dtrd_size;
14641017Sbmc 
14651017Sbmc 		if (DTRACEACT_ISAGG(act)) {
14661017Sbmc 			aggact = i;
14671017Sbmc 			break;
14681017Sbmc 		}
14691017Sbmc 
14701017Sbmc 		if (dt_print_datum(dtp, fp, rec, addr, size, 1) < 0)
14711017Sbmc 			return (-1);
14721017Sbmc 
14731017Sbmc 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
14741017Sbmc 		    DTRACE_BUFDATA_AGGKEY) < 0)
14751017Sbmc 			return (-1);
14761017Sbmc 	}
14771017Sbmc 
14781017Sbmc 	assert(aggact != 0);
14791017Sbmc 
14801017Sbmc 	for (i = (naggvars == 1 ? 0 : 1); i < naggvars; i++) {
14811017Sbmc 		uint64_t normal;
14821017Sbmc 
14831017Sbmc 		aggdata = aggsdata[i];
14841017Sbmc 		agg = aggdata->dtada_desc;
14851017Sbmc 		rec = &agg->dtagd_rec[aggact];
14861017Sbmc 		act = rec->dtrd_action;
14871017Sbmc 		addr = aggdata->dtada_data + rec->dtrd_offset;
14881017Sbmc 		size = rec->dtrd_size;
14891017Sbmc 
14901017Sbmc 		assert(DTRACEACT_ISAGG(act));
14911017Sbmc 		normal = aggdata->dtada_normal;
14921017Sbmc 
14931017Sbmc 		if (dt_print_datum(dtp, fp, rec, addr, size, normal) < 0)
14941017Sbmc 			return (-1);
14951017Sbmc 
14961017Sbmc 		if (dt_buffered_flush(dtp, NULL, rec, aggdata,
14971017Sbmc 		    DTRACE_BUFDATA_AGGVAL) < 0)
14981017Sbmc 			return (-1);
14991017Sbmc 
15001017Sbmc 		if (!pd->dtpa_allunprint)
15011017Sbmc 			agg->dtagd_flags |= DTRACE_AGD_PRINTED;
15021017Sbmc 	}
15031017Sbmc 
15041017Sbmc 	if (dt_printf(dtp, fp, "\n") < 0)
15051017Sbmc 		return (-1);
15061017Sbmc 
15071017Sbmc 	if (dt_buffered_flush(dtp, NULL, NULL, aggdata,
15081017Sbmc 	    DTRACE_BUFDATA_AGGFORMAT | DTRACE_BUFDATA_AGGLAST) < 0)
15091017Sbmc 		return (-1);
15101017Sbmc 
15111017Sbmc 	return (0);
15121017Sbmc }
15131017Sbmc 
15140Sstevel@tonic-gate int
1515457Sbmc dt_print_agg(const dtrace_aggdata_t *aggdata, void *arg)
15160Sstevel@tonic-gate {
15170Sstevel@tonic-gate 	dt_print_aggdata_t *pd = arg;
15180Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
15190Sstevel@tonic-gate 	dtrace_aggvarid_t aggvarid = pd->dtpa_id;
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	if (pd->dtpa_allunprint) {
15220Sstevel@tonic-gate 		if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
15230Sstevel@tonic-gate 			return (0);
15240Sstevel@tonic-gate 	} else {
15250Sstevel@tonic-gate 		/*
15260Sstevel@tonic-gate 		 * If we're not printing all unprinted aggregations, then the
15270Sstevel@tonic-gate 		 * aggregation variable ID denotes a specific aggregation
15280Sstevel@tonic-gate 		 * variable that we should print -- skip any other aggregations
15290Sstevel@tonic-gate 		 * that we encounter.
15300Sstevel@tonic-gate 		 */
15310Sstevel@tonic-gate 		if (agg->dtagd_nrecs == 0)
15320Sstevel@tonic-gate 			return (0);
15330Sstevel@tonic-gate 
15341017Sbmc 		if (aggvarid != agg->dtagd_varid)
15350Sstevel@tonic-gate 			return (0);
15360Sstevel@tonic-gate 	}
15370Sstevel@tonic-gate 
15381017Sbmc 	return (dt_print_aggs(&aggdata, 1, arg));
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate 
1541457Sbmc int
1542457Sbmc dt_setopt(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
1543457Sbmc     const char *option, const char *value)
1544457Sbmc {
1545457Sbmc 	int len, rval;
1546457Sbmc 	char *msg;
1547457Sbmc 	const char *errstr;
1548457Sbmc 	dtrace_setoptdata_t optdata;
1549457Sbmc 
1550457Sbmc 	bzero(&optdata, sizeof (optdata));
1551457Sbmc 	(void) dtrace_getopt(dtp, option, &optdata.dtsda_oldval);
1552457Sbmc 
1553457Sbmc 	if (dtrace_setopt(dtp, option, value) == 0) {
1554457Sbmc 		(void) dtrace_getopt(dtp, option, &optdata.dtsda_newval);
1555457Sbmc 		optdata.dtsda_probe = data;
1556457Sbmc 		optdata.dtsda_option = option;
1557457Sbmc 		optdata.dtsda_handle = dtp;
1558457Sbmc 
1559457Sbmc 		if ((rval = dt_handle_setopt(dtp, &optdata)) != 0)
1560457Sbmc 			return (rval);
1561457Sbmc 
1562457Sbmc 		return (0);
1563457Sbmc 	}
1564457Sbmc 
1565457Sbmc 	errstr = dtrace_errmsg(dtp, dtrace_errno(dtp));
1566457Sbmc 	len = strlen(option) + strlen(value) + strlen(errstr) + 80;
1567457Sbmc 	msg = alloca(len);
1568457Sbmc 
1569457Sbmc 	(void) snprintf(msg, len, "couldn't set option \"%s\" to \"%s\": %s\n",
1570457Sbmc 	    option, value, errstr);
1571457Sbmc 
1572457Sbmc 	if ((rval = dt_handle_liberr(dtp, data, msg)) == 0)
1573457Sbmc 		return (0);
1574457Sbmc 
1575457Sbmc 	return (rval);
1576457Sbmc }
1577457Sbmc 
15780Sstevel@tonic-gate static int
15790Sstevel@tonic-gate dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
15800Sstevel@tonic-gate     dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
15810Sstevel@tonic-gate {
15820Sstevel@tonic-gate 	dtrace_epid_t id;
15830Sstevel@tonic-gate 	size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size;
15840Sstevel@tonic-gate 	int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
15850Sstevel@tonic-gate 	int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
15860Sstevel@tonic-gate 	int rval, i, n;
15870Sstevel@tonic-gate 	dtrace_epid_t last = DTRACE_EPIDNONE;
15880Sstevel@tonic-gate 	dtrace_probedata_t data;
15890Sstevel@tonic-gate 	uint64_t drops;
15900Sstevel@tonic-gate 	caddr_t addr;
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	bzero(&data, sizeof (data));
15930Sstevel@tonic-gate 	data.dtpda_handle = dtp;
15940Sstevel@tonic-gate 	data.dtpda_cpu = cpu;
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate again:
15970Sstevel@tonic-gate 	for (offs = start; offs < end; ) {
15980Sstevel@tonic-gate 		dtrace_eprobedesc_t *epd;
15990Sstevel@tonic-gate 
16000Sstevel@tonic-gate 		/*
16010Sstevel@tonic-gate 		 * We're guaranteed to have an ID.
16020Sstevel@tonic-gate 		 */
16030Sstevel@tonic-gate 		id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 		if (id == DTRACE_EPIDNONE) {
16060Sstevel@tonic-gate 			/*
16070Sstevel@tonic-gate 			 * This is filler to assure proper alignment of the
16080Sstevel@tonic-gate 			 * next record; we simply ignore it.
16090Sstevel@tonic-gate 			 */
16100Sstevel@tonic-gate 			offs += sizeof (id);
16110Sstevel@tonic-gate 			continue;
16120Sstevel@tonic-gate 		}
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 		if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc,
16150Sstevel@tonic-gate 		    &data.dtpda_pdesc)) != 0)
16160Sstevel@tonic-gate 			return (rval);
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		epd = data.dtpda_edesc;
16190Sstevel@tonic-gate 		data.dtpda_data = buf->dtbd_data + offs;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 		if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) {
16220Sstevel@tonic-gate 			rval = dt_handle(dtp, &data);
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_NEXT)
16250Sstevel@tonic-gate 				goto nextepid;
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_ERROR)
16280Sstevel@tonic-gate 				return (-1);
16290Sstevel@tonic-gate 		}
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 		if (flow)
16320Sstevel@tonic-gate 			(void) dt_flowindent(dtp, &data, last, buf, offs);
16330Sstevel@tonic-gate 
16340Sstevel@tonic-gate 		rval = (*efunc)(&data, arg);
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 		if (flow) {
16370Sstevel@tonic-gate 			if (data.dtpda_flow == DTRACEFLOW_ENTRY)
16380Sstevel@tonic-gate 				data.dtpda_indent += 2;
16390Sstevel@tonic-gate 		}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 		if (rval == DTRACE_CONSUME_NEXT)
16420Sstevel@tonic-gate 			goto nextepid;
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 		if (rval == DTRACE_CONSUME_ABORT)
16450Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_DIRABORT));
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 		if (rval != DTRACE_CONSUME_THIS)
16480Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_BADRVAL));
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 		for (i = 0; i < epd->dtepd_nrecs; i++) {
16510Sstevel@tonic-gate 			dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
16520Sstevel@tonic-gate 			dtrace_actkind_t act = rec->dtrd_action;
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 			data.dtpda_data = buf->dtbd_data + offs +
16550Sstevel@tonic-gate 			    rec->dtrd_offset;
16560Sstevel@tonic-gate 			addr = data.dtpda_data;
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 			if (act == DTRACEACT_LIBACT) {
1659457Sbmc 				uint64_t arg = rec->dtrd_arg;
1660457Sbmc 				dtrace_aggvarid_t id;
16610Sstevel@tonic-gate 
1662457Sbmc 				switch (arg) {
1663457Sbmc 				case DT_ACT_CLEAR:
16640Sstevel@tonic-gate 					/* LINTED - alignment */
16650Sstevel@tonic-gate 					id = *((dtrace_aggvarid_t *)addr);
16660Sstevel@tonic-gate 					(void) dtrace_aggregate_walk(dtp,
16670Sstevel@tonic-gate 					    dt_clear_agg, &id);
16680Sstevel@tonic-gate 					continue;
16690Sstevel@tonic-gate 
1670457Sbmc 				case DT_ACT_DENORMALIZE:
16710Sstevel@tonic-gate 					/* LINTED - alignment */
16720Sstevel@tonic-gate 					id = *((dtrace_aggvarid_t *)addr);
16730Sstevel@tonic-gate 					(void) dtrace_aggregate_walk(dtp,
16740Sstevel@tonic-gate 					    dt_denormalize_agg, &id);
16750Sstevel@tonic-gate 					continue;
1676457Sbmc 
1677457Sbmc 				case DT_ACT_FTRUNCATE:
1678457Sbmc 					if (fp == NULL)
1679457Sbmc 						continue;
16800Sstevel@tonic-gate 
1681457Sbmc 					(void) fflush(fp);
1682457Sbmc 					(void) ftruncate(fileno(fp), 0);
1683457Sbmc 					(void) fseeko(fp, 0, SEEK_SET);
1684457Sbmc 					continue;
1685457Sbmc 
1686457Sbmc 				case DT_ACT_NORMALIZE:
16870Sstevel@tonic-gate 					if (i == epd->dtepd_nrecs - 1)
16880Sstevel@tonic-gate 						return (dt_set_errno(dtp,
16890Sstevel@tonic-gate 						    EDT_BADNORMAL));
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 					if (dt_normalize(dtp,
16920Sstevel@tonic-gate 					    buf->dtbd_data + offs, rec) != 0)
16930Sstevel@tonic-gate 						return (-1);
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 					i++;
16960Sstevel@tonic-gate 					continue;
1697457Sbmc 
1698457Sbmc 				case DT_ACT_SETOPT: {
1699457Sbmc 					uint64_t *opts = dtp->dt_options;
1700457Sbmc 					dtrace_recdesc_t *valrec;
1701457Sbmc 					uint32_t valsize;
1702457Sbmc 					caddr_t val;
1703457Sbmc 					int rv;
1704457Sbmc 
1705457Sbmc 					if (i == epd->dtepd_nrecs - 1) {
1706457Sbmc 						return (dt_set_errno(dtp,
1707457Sbmc 						    EDT_BADSETOPT));
1708457Sbmc 					}
1709457Sbmc 
1710457Sbmc 					valrec = &epd->dtepd_rec[++i];
1711457Sbmc 					valsize = valrec->dtrd_size;
1712457Sbmc 
1713457Sbmc 					if (valrec->dtrd_action != act ||
1714457Sbmc 					    valrec->dtrd_arg != arg) {
1715457Sbmc 						return (dt_set_errno(dtp,
1716457Sbmc 						    EDT_BADSETOPT));
1717457Sbmc 					}
1718457Sbmc 
1719457Sbmc 					if (valsize > sizeof (uint64_t)) {
1720457Sbmc 						val = buf->dtbd_data + offs +
1721457Sbmc 						    valrec->dtrd_offset;
1722457Sbmc 					} else {
1723457Sbmc 						val = "1";
1724457Sbmc 					}
1725457Sbmc 
1726457Sbmc 					rv = dt_setopt(dtp, &data, addr, val);
1727457Sbmc 
1728457Sbmc 					if (rv != 0)
1729457Sbmc 						return (-1);
1730457Sbmc 
1731457Sbmc 					flow = (opts[DTRACEOPT_FLOWINDENT] !=
1732457Sbmc 					    DTRACEOPT_UNSET);
1733457Sbmc 					quiet = (opts[DTRACEOPT_QUIET] !=
1734457Sbmc 					    DTRACEOPT_UNSET);
1735457Sbmc 
1736457Sbmc 					continue;
17370Sstevel@tonic-gate 				}
17380Sstevel@tonic-gate 
1739457Sbmc 				case DT_ACT_TRUNC:
17400Sstevel@tonic-gate 					if (i == epd->dtepd_nrecs - 1)
17410Sstevel@tonic-gate 						return (dt_set_errno(dtp,
17420Sstevel@tonic-gate 						    EDT_BADTRUNC));
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 					if (dt_trunc(dtp,
17450Sstevel@tonic-gate 					    buf->dtbd_data + offs, rec) != 0)
17460Sstevel@tonic-gate 						return (-1);
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 					i++;
17490Sstevel@tonic-gate 					continue;
17500Sstevel@tonic-gate 
1751457Sbmc 				default:
17520Sstevel@tonic-gate 					continue;
17530Sstevel@tonic-gate 				}
17540Sstevel@tonic-gate 			}
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 			rval = (*rfunc)(&data, rec, arg);
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_NEXT)
17590Sstevel@tonic-gate 				continue;
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_ABORT)
17620Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_DIRABORT));
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 			if (rval != DTRACE_CONSUME_THIS)
17650Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_BADRVAL));
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 			if (act == DTRACEACT_STACK) {
1768457Sbmc 				int depth = rec->dtrd_arg;
1769457Sbmc 
1770457Sbmc 				if (dt_print_stack(dtp, fp, NULL, addr, depth,
1771457Sbmc 				    rec->dtrd_size / depth) < 0)
17720Sstevel@tonic-gate 					return (-1);
17730Sstevel@tonic-gate 				goto nextrec;
17740Sstevel@tonic-gate 			}
17750Sstevel@tonic-gate 
17760Sstevel@tonic-gate 			if (act == DTRACEACT_USTACK ||
17770Sstevel@tonic-gate 			    act == DTRACEACT_JSTACK) {
17780Sstevel@tonic-gate 				if (dt_print_ustack(dtp, fp, NULL,
17790Sstevel@tonic-gate 				    addr, rec->dtrd_arg) < 0)
17800Sstevel@tonic-gate 					return (-1);
17810Sstevel@tonic-gate 				goto nextrec;
17820Sstevel@tonic-gate 			}
17830Sstevel@tonic-gate 
1784457Sbmc 			if (act == DTRACEACT_SYM) {
1785457Sbmc 				if (dt_print_sym(dtp, fp, NULL, addr) < 0)
1786457Sbmc 					return (-1);
1787457Sbmc 				goto nextrec;
1788457Sbmc 			}
1789457Sbmc 
1790457Sbmc 			if (act == DTRACEACT_MOD) {
1791457Sbmc 				if (dt_print_mod(dtp, fp, NULL, addr) < 0)
1792457Sbmc 					return (-1);
1793457Sbmc 				goto nextrec;
1794457Sbmc 			}
1795457Sbmc 
1796457Sbmc 			if (act == DTRACEACT_USYM || act == DTRACEACT_UADDR) {
1797457Sbmc 				if (dt_print_usym(dtp, fp, addr, act) < 0)
1798457Sbmc 					return (-1);
1799457Sbmc 				goto nextrec;
1800457Sbmc 			}
1801457Sbmc 
1802457Sbmc 			if (act == DTRACEACT_UMOD) {
1803457Sbmc 				if (dt_print_umod(dtp, fp, NULL, addr) < 0)
1804457Sbmc 					return (-1);
1805457Sbmc 				goto nextrec;
1806457Sbmc 			}
1807457Sbmc 
18080Sstevel@tonic-gate 			if (DTRACEACT_ISPRINTFLIKE(act)) {
18090Sstevel@tonic-gate 				void *fmtdata;
18100Sstevel@tonic-gate 				int (*func)(dtrace_hdl_t *, FILE *, void *,
18110Sstevel@tonic-gate 				    const dtrace_probedata_t *,
18120Sstevel@tonic-gate 				    const dtrace_recdesc_t *, uint_t,
18130Sstevel@tonic-gate 				    const void *buf, size_t);
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 				if ((fmtdata = dt_format_lookup(dtp,
18160Sstevel@tonic-gate 				    rec->dtrd_format)) == NULL)
18170Sstevel@tonic-gate 					goto nofmt;
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 				switch (act) {
18200Sstevel@tonic-gate 				case DTRACEACT_PRINTF:
18210Sstevel@tonic-gate 					func = dtrace_fprintf;
18220Sstevel@tonic-gate 					break;
18230Sstevel@tonic-gate 				case DTRACEACT_PRINTA:
18240Sstevel@tonic-gate 					func = dtrace_fprinta;
18250Sstevel@tonic-gate 					break;
18260Sstevel@tonic-gate 				case DTRACEACT_SYSTEM:
18270Sstevel@tonic-gate 					func = dtrace_system;
18280Sstevel@tonic-gate 					break;
18290Sstevel@tonic-gate 				case DTRACEACT_FREOPEN:
18300Sstevel@tonic-gate 					func = dtrace_freopen;
18310Sstevel@tonic-gate 					break;
18320Sstevel@tonic-gate 				}
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 				n = (*func)(dtp, fp, fmtdata, &data,
18350Sstevel@tonic-gate 				    rec, epd->dtepd_nrecs - i,
18360Sstevel@tonic-gate 				    (uchar_t *)buf->dtbd_data + offs,
18370Sstevel@tonic-gate 				    buf->dtbd_size - offs);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 				if (n < 0)
18400Sstevel@tonic-gate 					return (-1); /* errno is set for us */
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 				if (n > 0)
18430Sstevel@tonic-gate 					i += n - 1;
18440Sstevel@tonic-gate 				goto nextrec;
18450Sstevel@tonic-gate 			}
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate nofmt:
18480Sstevel@tonic-gate 			if (act == DTRACEACT_PRINTA) {
18490Sstevel@tonic-gate 				dt_print_aggdata_t pd;
18501017Sbmc 				dtrace_aggvarid_t *aggvars;
18511017Sbmc 				int j, naggvars = 0;
18521017Sbmc 				size_t size = ((epd->dtepd_nrecs - i) *
18531017Sbmc 				    sizeof (dtrace_aggvarid_t));
18540Sstevel@tonic-gate 
18551017Sbmc 				if ((aggvars = dt_alloc(dtp, size)) == NULL)
18561017Sbmc 					return (-1);
18571017Sbmc 
18581017Sbmc 				/*
18591017Sbmc 				 * This might be a printa() with multiple
18601017Sbmc 				 * aggregation variables.  We need to scan
18611017Sbmc 				 * forward through the records until we find
18621017Sbmc 				 * a record from a different statement.
18631017Sbmc 				 */
18641017Sbmc 				for (j = i; j < epd->dtepd_nrecs; j++) {
18651017Sbmc 					dtrace_recdesc_t *nrec;
18661017Sbmc 					caddr_t naddr;
18671017Sbmc 
18681017Sbmc 					nrec = &epd->dtepd_rec[j];
18691017Sbmc 
18701017Sbmc 					if (nrec->dtrd_uarg != rec->dtrd_uarg)
18711017Sbmc 						break;
18721017Sbmc 
18731017Sbmc 					if (nrec->dtrd_action != act) {
18741017Sbmc 						return (dt_set_errno(dtp,
18751017Sbmc 						    EDT_BADAGG));
18761017Sbmc 					}
18771017Sbmc 
18781017Sbmc 					naddr = buf->dtbd_data + offs +
18791017Sbmc 					    nrec->dtrd_offset;
18801017Sbmc 
18811017Sbmc 					aggvars[naggvars++] =
18821017Sbmc 					    /* LINTED - alignment */
18831017Sbmc 					    *((dtrace_aggvarid_t *)naddr);
18841017Sbmc 				}
18851017Sbmc 
18861017Sbmc 				i = j - 1;
18870Sstevel@tonic-gate 				bzero(&pd, sizeof (pd));
18880Sstevel@tonic-gate 				pd.dtpa_dtp = dtp;
18890Sstevel@tonic-gate 				pd.dtpa_fp = fp;
18901017Sbmc 
18911017Sbmc 				assert(naggvars >= 1);
18921017Sbmc 
18931017Sbmc 				if (naggvars == 1) {
18941017Sbmc 					pd.dtpa_id = aggvars[0];
18951017Sbmc 					dt_free(dtp, aggvars);
18961017Sbmc 
18971017Sbmc 					if (dt_printf(dtp, fp, "\n") < 0 ||
18981017Sbmc 					    dtrace_aggregate_walk_sorted(dtp,
18991017Sbmc 					    dt_print_agg, &pd) < 0)
19001017Sbmc 						return (-1);
19011017Sbmc 					goto nextrec;
19021017Sbmc 				}
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 				if (dt_printf(dtp, fp, "\n") < 0 ||
19051017Sbmc 				    dtrace_aggregate_walk_joined(dtp, aggvars,
19061017Sbmc 				    naggvars, dt_print_aggs, &pd) < 0) {
19071017Sbmc 					dt_free(dtp, aggvars);
19080Sstevel@tonic-gate 					return (-1);
19091017Sbmc 				}
19100Sstevel@tonic-gate 
19111017Sbmc 				dt_free(dtp, aggvars);
19120Sstevel@tonic-gate 				goto nextrec;
19130Sstevel@tonic-gate 			}
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 			switch (rec->dtrd_size) {
19160Sstevel@tonic-gate 			case sizeof (uint64_t):
19170Sstevel@tonic-gate 				n = dt_printf(dtp, fp,
19180Sstevel@tonic-gate 				    quiet ? "%lld" : " %16lld",
19190Sstevel@tonic-gate 				    /* LINTED - alignment */
19200Sstevel@tonic-gate 				    *((unsigned long long *)addr));
19210Sstevel@tonic-gate 				break;
19220Sstevel@tonic-gate 			case sizeof (uint32_t):
19230Sstevel@tonic-gate 				n = dt_printf(dtp, fp, quiet ? "%d" : " %8d",
19240Sstevel@tonic-gate 				    /* LINTED - alignment */
19250Sstevel@tonic-gate 				    *((uint32_t *)addr));
19260Sstevel@tonic-gate 				break;
19270Sstevel@tonic-gate 			case sizeof (uint16_t):
19280Sstevel@tonic-gate 				n = dt_printf(dtp, fp, quiet ? "%d" : " %5d",
19290Sstevel@tonic-gate 				    /* LINTED - alignment */
19300Sstevel@tonic-gate 				    *((uint16_t *)addr));
19310Sstevel@tonic-gate 				break;
19320Sstevel@tonic-gate 			case sizeof (uint8_t):
19330Sstevel@tonic-gate 				n = dt_printf(dtp, fp, quiet ? "%d" : " %3d",
19340Sstevel@tonic-gate 				    *((uint8_t *)addr));
19350Sstevel@tonic-gate 				break;
19360Sstevel@tonic-gate 			default:
19370Sstevel@tonic-gate 				n = dt_print_bytes(dtp, fp, addr,
19380Sstevel@tonic-gate 				    rec->dtrd_size, 33, quiet);
19390Sstevel@tonic-gate 				break;
19400Sstevel@tonic-gate 			}
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 			if (n < 0)
19430Sstevel@tonic-gate 				return (-1); /* errno is set for us */
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate nextrec:
19461017Sbmc 			if (dt_buffered_flush(dtp, &data, rec, NULL, 0) < 0)
19470Sstevel@tonic-gate 				return (-1); /* errno is set for us */
19480Sstevel@tonic-gate 		}
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 		/*
19510Sstevel@tonic-gate 		 * Call the record callback with a NULL record to indicate
19520Sstevel@tonic-gate 		 * that we're done processing this EPID.
19530Sstevel@tonic-gate 		 */
19540Sstevel@tonic-gate 		rval = (*rfunc)(&data, NULL, arg);
19550Sstevel@tonic-gate nextepid:
19560Sstevel@tonic-gate 		offs += epd->dtepd_size;
19570Sstevel@tonic-gate 		last = id;
19580Sstevel@tonic-gate 	}
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) {
19610Sstevel@tonic-gate 		end = buf->dtbd_oldest;
19620Sstevel@tonic-gate 		start = 0;
19630Sstevel@tonic-gate 		goto again;
19640Sstevel@tonic-gate 	}
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate 	if ((drops = buf->dtbd_drops) == 0)
19670Sstevel@tonic-gate 		return (0);
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	/*
19700Sstevel@tonic-gate 	 * Explicitly zero the drops to prevent us from processing them again.
19710Sstevel@tonic-gate 	 */
19720Sstevel@tonic-gate 	buf->dtbd_drops = 0;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate typedef struct dt_begin {
19780Sstevel@tonic-gate 	dtrace_consume_probe_f *dtbgn_probefunc;
19790Sstevel@tonic-gate 	dtrace_consume_rec_f *dtbgn_recfunc;
19800Sstevel@tonic-gate 	void *dtbgn_arg;
19810Sstevel@tonic-gate 	dtrace_handle_err_f *dtbgn_errhdlr;
19820Sstevel@tonic-gate 	void *dtbgn_errarg;
19830Sstevel@tonic-gate 	int dtbgn_beginonly;
19840Sstevel@tonic-gate } dt_begin_t;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate static int
19870Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg)
19880Sstevel@tonic-gate {
19890Sstevel@tonic-gate 	dt_begin_t *begin = (dt_begin_t *)arg;
19900Sstevel@tonic-gate 	dtrace_probedesc_t *pd = data->dtpda_pdesc;
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
19930Sstevel@tonic-gate 	int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 	if (begin->dtbgn_beginonly) {
19960Sstevel@tonic-gate 		if (!(r1 && r2))
19970Sstevel@tonic-gate 			return (DTRACE_CONSUME_NEXT);
19980Sstevel@tonic-gate 	} else {
19990Sstevel@tonic-gate 		if (r1 && r2)
20000Sstevel@tonic-gate 			return (DTRACE_CONSUME_NEXT);
20010Sstevel@tonic-gate 	}
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	/*
20040Sstevel@tonic-gate 	 * We have a record that we're interested in.  Now call the underlying
20050Sstevel@tonic-gate 	 * probe function...
20060Sstevel@tonic-gate 	 */
20070Sstevel@tonic-gate 	return (begin->dtbgn_probefunc(data, begin->dtbgn_arg));
20080Sstevel@tonic-gate }
20090Sstevel@tonic-gate 
20100Sstevel@tonic-gate static int
20110Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data,
20120Sstevel@tonic-gate     const dtrace_recdesc_t *rec, void *arg)
20130Sstevel@tonic-gate {
20140Sstevel@tonic-gate 	dt_begin_t *begin = (dt_begin_t *)arg;
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 	return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg));
20170Sstevel@tonic-gate }
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate static int
2020457Sbmc dt_consume_begin_error(const dtrace_errdata_t *data, void *arg)
20210Sstevel@tonic-gate {
20220Sstevel@tonic-gate 	dt_begin_t *begin = (dt_begin_t *)arg;
20230Sstevel@tonic-gate 	dtrace_probedesc_t *pd = data->dteda_pdesc;
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
20260Sstevel@tonic-gate 	int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	if (begin->dtbgn_beginonly) {
20290Sstevel@tonic-gate 		if (!(r1 && r2))
20300Sstevel@tonic-gate 			return (DTRACE_HANDLE_OK);
20310Sstevel@tonic-gate 	} else {
20320Sstevel@tonic-gate 		if (r1 && r2)
20330Sstevel@tonic-gate 			return (DTRACE_HANDLE_OK);
20340Sstevel@tonic-gate 	}
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate 	return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg));
20370Sstevel@tonic-gate }
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate static int
20400Sstevel@tonic-gate dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf,
20410Sstevel@tonic-gate     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
20420Sstevel@tonic-gate {
20430Sstevel@tonic-gate 	/*
20440Sstevel@tonic-gate 	 * There's this idea that the BEGIN probe should be processed before
20450Sstevel@tonic-gate 	 * everything else, and that the END probe should be processed after
20460Sstevel@tonic-gate 	 * anything else.  In the common case, this is pretty easy to deal
20470Sstevel@tonic-gate 	 * with.  However, a situation may arise where the BEGIN enabling and
20480Sstevel@tonic-gate 	 * END enabling are on the same CPU, and some enabling in the middle
20490Sstevel@tonic-gate 	 * occurred on a different CPU.  To deal with this (blech!) we need to
20500Sstevel@tonic-gate 	 * consume the BEGIN buffer up until the end of the BEGIN probe, and
20510Sstevel@tonic-gate 	 * then set it aside.  We will then process every other CPU, and then
20520Sstevel@tonic-gate 	 * we'll return to the BEGIN CPU and process the rest of the data
20530Sstevel@tonic-gate 	 * (which will inevitably include the END probe, if any).  Making this
20540Sstevel@tonic-gate 	 * even more complicated (!) is the library's ERROR enabling.  Because
20550Sstevel@tonic-gate 	 * this enabling is processed before we even get into the consume call
20560Sstevel@tonic-gate 	 * back, any ERROR firing would result in the library's ERROR enabling
20570Sstevel@tonic-gate 	 * being processed twice -- once in our first pass (for BEGIN probes),
20580Sstevel@tonic-gate 	 * and again in our second pass (for everything but BEGIN probes).  To
20590Sstevel@tonic-gate 	 * deal with this, we interpose on the ERROR handler to assure that we
20600Sstevel@tonic-gate 	 * only process ERROR enablings induced by BEGIN enablings in the
20610Sstevel@tonic-gate 	 * first pass, and that we only process ERROR enablings _not_ induced
20620Sstevel@tonic-gate 	 * by BEGIN enablings in the second pass.
20630Sstevel@tonic-gate 	 */
20640Sstevel@tonic-gate 	dt_begin_t begin;
20650Sstevel@tonic-gate 	processorid_t cpu = dtp->dt_beganon;
20660Sstevel@tonic-gate 	dtrace_bufdesc_t nbuf;
20670Sstevel@tonic-gate 	int rval, i;
20680Sstevel@tonic-gate 	static int max_ncpus;
20690Sstevel@tonic-gate 	dtrace_optval_t size;
20700Sstevel@tonic-gate 
20710Sstevel@tonic-gate 	dtp->dt_beganon = -1;
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
20740Sstevel@tonic-gate 		/*
20750Sstevel@tonic-gate 		 * We really don't expect this to fail, but it is at least
20760Sstevel@tonic-gate 		 * technically possible for this to fail with ENOENT.  In this
20770Sstevel@tonic-gate 		 * case, we just drive on...
20780Sstevel@tonic-gate 		 */
20790Sstevel@tonic-gate 		if (errno == ENOENT)
20800Sstevel@tonic-gate 			return (0);
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
20830Sstevel@tonic-gate 	}
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) {
20860Sstevel@tonic-gate 		/*
20870Sstevel@tonic-gate 		 * This is the simple case.  We're either not stopped, or if
20880Sstevel@tonic-gate 		 * we are, we actually processed any END probes on another
20890Sstevel@tonic-gate 		 * CPU.  We can simply consume this buffer and return.
20900Sstevel@tonic-gate 		 */
20910Sstevel@tonic-gate 		return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg));
20920Sstevel@tonic-gate 	}
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	begin.dtbgn_probefunc = pf;
20950Sstevel@tonic-gate 	begin.dtbgn_recfunc = rf;
20960Sstevel@tonic-gate 	begin.dtbgn_arg = arg;
20970Sstevel@tonic-gate 	begin.dtbgn_beginonly = 1;
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	/*
21000Sstevel@tonic-gate 	 * We need to interpose on the ERROR handler to be sure that we
21010Sstevel@tonic-gate 	 * only process ERRORs induced by BEGIN.
21020Sstevel@tonic-gate 	 */
21030Sstevel@tonic-gate 	begin.dtbgn_errhdlr = dtp->dt_errhdlr;
21040Sstevel@tonic-gate 	begin.dtbgn_errarg = dtp->dt_errarg;
21050Sstevel@tonic-gate 	dtp->dt_errhdlr = dt_consume_begin_error;
21060Sstevel@tonic-gate 	dtp->dt_errarg = &begin;
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
21090Sstevel@tonic-gate 	    dt_consume_begin_record, &begin);
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
21120Sstevel@tonic-gate 	dtp->dt_errarg = begin.dtbgn_errarg;
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate 	if (rval != 0)
21150Sstevel@tonic-gate 		return (rval);
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 	/*
21180Sstevel@tonic-gate 	 * Now allocate a new buffer.  We'll use this to deal with every other
21190Sstevel@tonic-gate 	 * CPU.
21200Sstevel@tonic-gate 	 */
21210Sstevel@tonic-gate 	bzero(&nbuf, sizeof (dtrace_bufdesc_t));
21220Sstevel@tonic-gate 	(void) dtrace_getopt(dtp, "bufsize", &size);
21230Sstevel@tonic-gate 	if ((nbuf.dtbd_data = malloc(size)) == NULL)
21240Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_NOMEM));
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	if (max_ncpus == 0)
21270Sstevel@tonic-gate 		max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 	for (i = 0; i < max_ncpus; i++) {
21300Sstevel@tonic-gate 		nbuf.dtbd_cpu = i;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 		if (i == cpu)
21330Sstevel@tonic-gate 			continue;
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) {
21360Sstevel@tonic-gate 			/*
21370Sstevel@tonic-gate 			 * If we failed with ENOENT, it may be because the
21380Sstevel@tonic-gate 			 * CPU was unconfigured -- this is okay.  Any other
21390Sstevel@tonic-gate 			 * error, however, is unexpected.
21400Sstevel@tonic-gate 			 */
21410Sstevel@tonic-gate 			if (errno == ENOENT)
21420Sstevel@tonic-gate 				continue;
21430Sstevel@tonic-gate 
21440Sstevel@tonic-gate 			free(nbuf.dtbd_data);
21450Sstevel@tonic-gate 
21460Sstevel@tonic-gate 			return (dt_set_errno(dtp, errno));
21470Sstevel@tonic-gate 		}
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 		if ((rval = dt_consume_cpu(dtp, fp,
21500Sstevel@tonic-gate 		    i, &nbuf, pf, rf, arg)) != 0) {
21510Sstevel@tonic-gate 			free(nbuf.dtbd_data);
21520Sstevel@tonic-gate 			return (rval);
21530Sstevel@tonic-gate 		}
21540Sstevel@tonic-gate 	}
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 	free(nbuf.dtbd_data);
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	/*
21590Sstevel@tonic-gate 	 * Okay -- we're done with the other buffers.  Now we want to
21600Sstevel@tonic-gate 	 * reconsume the first buffer -- but this time we're looking for
21610Sstevel@tonic-gate 	 * everything _but_ BEGIN.  And of course, in order to only consume
21620Sstevel@tonic-gate 	 * those ERRORs _not_ associated with BEGIN, we need to reinstall our
21630Sstevel@tonic-gate 	 * ERROR interposition function...
21640Sstevel@tonic-gate 	 */
21650Sstevel@tonic-gate 	begin.dtbgn_beginonly = 0;
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr);
21680Sstevel@tonic-gate 	assert(begin.dtbgn_errarg == dtp->dt_errarg);
21690Sstevel@tonic-gate 	dtp->dt_errhdlr = dt_consume_begin_error;
21700Sstevel@tonic-gate 	dtp->dt_errarg = &begin;
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate 	rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
21730Sstevel@tonic-gate 	    dt_consume_begin_record, &begin);
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
21760Sstevel@tonic-gate 	dtp->dt_errarg = begin.dtbgn_errarg;
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	return (rval);
21790Sstevel@tonic-gate }
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate int
21820Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
21830Sstevel@tonic-gate     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
21840Sstevel@tonic-gate {
21850Sstevel@tonic-gate 	dtrace_bufdesc_t *buf = &dtp->dt_buf;
21860Sstevel@tonic-gate 	dtrace_optval_t size;
21870Sstevel@tonic-gate 	static int max_ncpus;
21880Sstevel@tonic-gate 	int i, rval;
21890Sstevel@tonic-gate 	dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE];
21900Sstevel@tonic-gate 	hrtime_t now = gethrtime();
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 	if (dtp->dt_lastswitch != 0) {
21930Sstevel@tonic-gate 		if (now - dtp->dt_lastswitch < interval)
21940Sstevel@tonic-gate 			return (0);
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate 		dtp->dt_lastswitch += interval;
21970Sstevel@tonic-gate 	} else {
21980Sstevel@tonic-gate 		dtp->dt_lastswitch = now;
21990Sstevel@tonic-gate 	}
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	if (!dtp->dt_active)
22020Sstevel@tonic-gate 		return (dt_set_errno(dtp, EINVAL));
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	if (max_ncpus == 0)
22050Sstevel@tonic-gate 		max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	if (pf == NULL)
22080Sstevel@tonic-gate 		pf = (dtrace_consume_probe_f *)dt_nullprobe;
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	if (rf == NULL)
22110Sstevel@tonic-gate 		rf = (dtrace_consume_rec_f *)dt_nullrec;
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	if (buf->dtbd_data == NULL) {
22140Sstevel@tonic-gate 		(void) dtrace_getopt(dtp, "bufsize", &size);
22150Sstevel@tonic-gate 		if ((buf->dtbd_data = malloc(size)) == NULL)
22160Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_NOMEM));
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 		buf->dtbd_size = size;
22190Sstevel@tonic-gate 	}
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 	/*
22220Sstevel@tonic-gate 	 * If we have just begun, we want to first process the CPU that
22230Sstevel@tonic-gate 	 * executed the BEGIN probe (if any).
22240Sstevel@tonic-gate 	 */
22250Sstevel@tonic-gate 	if (dtp->dt_active && dtp->dt_beganon != -1) {
22260Sstevel@tonic-gate 		buf->dtbd_cpu = dtp->dt_beganon;
22270Sstevel@tonic-gate 		if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0)
22280Sstevel@tonic-gate 			return (rval);
22290Sstevel@tonic-gate 	}
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate 	for (i = 0; i < max_ncpus; i++) {
22320Sstevel@tonic-gate 		buf->dtbd_cpu = i;
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 		/*
22350Sstevel@tonic-gate 		 * If we have stopped, we want to process the CPU on which the
22360Sstevel@tonic-gate 		 * END probe was processed only _after_ we have processed
22370Sstevel@tonic-gate 		 * everything else.
22380Sstevel@tonic-gate 		 */
22390Sstevel@tonic-gate 		if (dtp->dt_stopped && (i == dtp->dt_endedon))
22400Sstevel@tonic-gate 			continue;
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
22430Sstevel@tonic-gate 			/*
22440Sstevel@tonic-gate 			 * If we failed with ENOENT, it may be because the
22450Sstevel@tonic-gate 			 * CPU was unconfigured -- this is okay.  Any other
22460Sstevel@tonic-gate 			 * error, however, is unexpected.
22470Sstevel@tonic-gate 			 */
22480Sstevel@tonic-gate 			if (errno == ENOENT)
22490Sstevel@tonic-gate 				continue;
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate 			return (dt_set_errno(dtp, errno));
22520Sstevel@tonic-gate 		}
22530Sstevel@tonic-gate 
22540Sstevel@tonic-gate 		if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0)
22550Sstevel@tonic-gate 			return (rval);
22560Sstevel@tonic-gate 	}
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 	if (!dtp->dt_stopped)
22590Sstevel@tonic-gate 		return (0);
22600Sstevel@tonic-gate 
22610Sstevel@tonic-gate 	buf->dtbd_cpu = dtp->dt_endedon;
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
22640Sstevel@tonic-gate 		/*
22650Sstevel@tonic-gate 		 * This _really_ shouldn't fail, but it is strictly speaking
22660Sstevel@tonic-gate 		 * possible for this to return ENOENT if the CPU that called
22670Sstevel@tonic-gate 		 * the END enabling somehow managed to become unconfigured.
22680Sstevel@tonic-gate 		 * It's unclear how the user can possibly expect anything
22690Sstevel@tonic-gate 		 * rational to happen in this case -- the state has been thrown
22700Sstevel@tonic-gate 		 * out along with the unconfigured CPU -- so we'll just drive
22710Sstevel@tonic-gate 		 * on...
22720Sstevel@tonic-gate 		 */
22730Sstevel@tonic-gate 		if (errno == ENOENT)
22740Sstevel@tonic-gate 			return (0);
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
22770Sstevel@tonic-gate 	}
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 	return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg));
22800Sstevel@tonic-gate }
2281