1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <strings.h>
31*0Sstevel@tonic-gate #include <errno.h>
32*0Sstevel@tonic-gate #include <unistd.h>
33*0Sstevel@tonic-gate #include <limits.h>
34*0Sstevel@tonic-gate #include <assert.h>
35*0Sstevel@tonic-gate #include <ctype.h>
36*0Sstevel@tonic-gate #include <alloca.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <dt_impl.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate static int
41*0Sstevel@tonic-gate dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
42*0Sstevel@tonic-gate     dtrace_bufdesc_t *buf, size_t offs)
43*0Sstevel@tonic-gate {
44*0Sstevel@tonic-gate 	dtrace_probedesc_t *pd = data->dtpda_pdesc, *npd;
45*0Sstevel@tonic-gate 	dtrace_eprobedesc_t *epd = data->dtpda_edesc, *nepd;
46*0Sstevel@tonic-gate 	char *p = pd->dtpd_provider, *n = pd->dtpd_name;
47*0Sstevel@tonic-gate 	dtrace_flowkind_t flow = DTRACEFLOW_NONE;
48*0Sstevel@tonic-gate 	const char *str = NULL;
49*0Sstevel@tonic-gate 	static const char *e_str[2] = { " -> ", " => " };
50*0Sstevel@tonic-gate 	static const char *r_str[2] = { " <- ", " <= " };
51*0Sstevel@tonic-gate 	dtrace_epid_t next, id = epd->dtepd_epid;
52*0Sstevel@tonic-gate 	int rval;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate 	if (strcmp(n, "entry") == 0) {
55*0Sstevel@tonic-gate 		flow = DTRACEFLOW_ENTRY;
56*0Sstevel@tonic-gate 		str = e_str[strcmp(p, "syscall") == 0];
57*0Sstevel@tonic-gate 	} else if (strcmp(n, "return") == 0 ||
58*0Sstevel@tonic-gate 	    strcmp(n, "exit") == 0) {
59*0Sstevel@tonic-gate 		flow = DTRACEFLOW_RETURN;
60*0Sstevel@tonic-gate 		str = r_str[strcmp(p, "syscall") == 0];
61*0Sstevel@tonic-gate 	}
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 	/*
64*0Sstevel@tonic-gate 	 * If we're going to indent this, we need to check the ID of our last
65*0Sstevel@tonic-gate 	 * call.  If we're looking at the same probe ID but a different EPID,
66*0Sstevel@tonic-gate 	 * we _don't_ want to indent.  (Yes, there are some minor holes in
67*0Sstevel@tonic-gate 	 * this scheme -- it's a heuristic.)
68*0Sstevel@tonic-gate 	 */
69*0Sstevel@tonic-gate 	if (flow == DTRACEFLOW_ENTRY) {
70*0Sstevel@tonic-gate 		if ((last != DTRACE_EPIDNONE && id != last &&
71*0Sstevel@tonic-gate 		    pd->dtpd_id == dtp->dt_pdesc[last]->dtpd_id))
72*0Sstevel@tonic-gate 			flow = DTRACEFLOW_NONE;
73*0Sstevel@tonic-gate 	}
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	/*
76*0Sstevel@tonic-gate 	 * If we're going to unindent this, it's more difficult to see if
77*0Sstevel@tonic-gate 	 * we don't actually want to unindent it -- we need to look at the
78*0Sstevel@tonic-gate 	 * _next_ EPID.
79*0Sstevel@tonic-gate 	 */
80*0Sstevel@tonic-gate 	if (flow == DTRACEFLOW_RETURN) {
81*0Sstevel@tonic-gate 		offs += epd->dtepd_size;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 		do {
84*0Sstevel@tonic-gate 			if (offs >= buf->dtbd_size) {
85*0Sstevel@tonic-gate 				/*
86*0Sstevel@tonic-gate 				 * We're at the end -- maybe.  If the oldest
87*0Sstevel@tonic-gate 				 * record is non-zero, we need to wrap.
88*0Sstevel@tonic-gate 				 */
89*0Sstevel@tonic-gate 				if (buf->dtbd_oldest != 0) {
90*0Sstevel@tonic-gate 					offs = 0;
91*0Sstevel@tonic-gate 				} else {
92*0Sstevel@tonic-gate 					goto out;
93*0Sstevel@tonic-gate 				}
94*0Sstevel@tonic-gate 			}
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 			next = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 			if (next == DTRACE_EPIDNONE)
99*0Sstevel@tonic-gate 				offs += sizeof (id);
100*0Sstevel@tonic-gate 		} while (next == DTRACE_EPIDNONE);
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 		if ((rval = dt_epid_lookup(dtp, next, &nepd, &npd)) != 0)
103*0Sstevel@tonic-gate 			return (rval);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 		if (next != id && npd->dtpd_id == pd->dtpd_id)
106*0Sstevel@tonic-gate 			flow = DTRACEFLOW_NONE;
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate out:
110*0Sstevel@tonic-gate 	if (flow == DTRACEFLOW_ENTRY || flow == DTRACEFLOW_RETURN) {
111*0Sstevel@tonic-gate 		data->dtpda_prefix = str;
112*0Sstevel@tonic-gate 	} else {
113*0Sstevel@tonic-gate 		data->dtpda_prefix = "| ";
114*0Sstevel@tonic-gate 	}
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	if (flow == DTRACEFLOW_RETURN && data->dtpda_indent > 0)
117*0Sstevel@tonic-gate 		data->dtpda_indent -= 2;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	data->dtpda_flow = flow;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	return (0);
122*0Sstevel@tonic-gate }
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate static int
125*0Sstevel@tonic-gate dt_nullprobe()
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	return (DTRACE_CONSUME_THIS);
128*0Sstevel@tonic-gate }
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate static int
131*0Sstevel@tonic-gate dt_nullrec()
132*0Sstevel@tonic-gate {
133*0Sstevel@tonic-gate 	return (DTRACE_CONSUME_NEXT);
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate int
137*0Sstevel@tonic-gate dt_print_quantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
138*0Sstevel@tonic-gate     size_t size, uint64_t normal)
139*0Sstevel@tonic-gate {
140*0Sstevel@tonic-gate 	const uint64_t *data = addr;
141*0Sstevel@tonic-gate 	int i, first_bin = 0, last_bin = DTRACE_QUANTIZE_NBUCKETS - 1;
142*0Sstevel@tonic-gate 	uint64_t total_bin_count = 0;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	if (size != DTRACE_QUANTIZE_NBUCKETS * sizeof (uint64_t))
145*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DMISMATCH));
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	while (first_bin < DTRACE_QUANTIZE_NBUCKETS - 1 && data[first_bin] == 0)
148*0Sstevel@tonic-gate 		first_bin++;
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	if (first_bin > 0)
151*0Sstevel@tonic-gate 		first_bin--;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	while (last_bin > 0 && data[last_bin] == 0)
154*0Sstevel@tonic-gate 		last_bin--;
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	if (last_bin < DTRACE_QUANTIZE_NBUCKETS - 1)
157*0Sstevel@tonic-gate 		last_bin++;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	for (i = first_bin; i <= last_bin; i++)
160*0Sstevel@tonic-gate 		total_bin_count += data[i];
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
163*0Sstevel@tonic-gate 	    "------------- Distribution -------------", "count") < 0)
164*0Sstevel@tonic-gate 		return (-1);
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	for (i = first_bin; i <= last_bin; i++) {
167*0Sstevel@tonic-gate 		float f = ((float)data[i] * 40.0) / (float)total_bin_count;
168*0Sstevel@tonic-gate 		uint_t depth = (uint_t)(f + 0.5);
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "%16lld |%s%s %-9llu\n",
171*0Sstevel@tonic-gate 		    (long long)DTRACE_QUANTIZE_BUCKETVAL(i),
172*0Sstevel@tonic-gate 		    "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth,
173*0Sstevel@tonic-gate 		    "                                        " + depth,
174*0Sstevel@tonic-gate 		    (u_longlong_t)data[i] / normal) < 0)
175*0Sstevel@tonic-gate 			return (-1);
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	return (0);
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate int
182*0Sstevel@tonic-gate dt_print_lquantize(dtrace_hdl_t *dtp, FILE *fp, const void *addr,
183*0Sstevel@tonic-gate     size_t size, uint64_t normal)
184*0Sstevel@tonic-gate {
185*0Sstevel@tonic-gate 	const uint64_t *data = addr;
186*0Sstevel@tonic-gate 	int i, first_bin, last_bin, base;
187*0Sstevel@tonic-gate 	uint64_t arg, total_bin_count = 0;
188*0Sstevel@tonic-gate 	uint16_t step, levels;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	if (size < sizeof (uint64_t))
191*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DMISMATCH));
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	arg = *data++;
194*0Sstevel@tonic-gate 	size -= sizeof (uint64_t);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	base = DTRACE_LQUANTIZE_BASE(arg);
197*0Sstevel@tonic-gate 	step = DTRACE_LQUANTIZE_STEP(arg);
198*0Sstevel@tonic-gate 	levels = DTRACE_LQUANTIZE_LEVELS(arg);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	first_bin = 0;
201*0Sstevel@tonic-gate 	last_bin = levels + 1;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	if (size != sizeof (uint64_t) * (levels + 2))
204*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DMISMATCH));
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate 	while (first_bin < levels + 1 && data[first_bin] == 0)
207*0Sstevel@tonic-gate 		first_bin++;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (first_bin > 0)
210*0Sstevel@tonic-gate 		first_bin--;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	while (last_bin > 0 && data[last_bin] == 0)
213*0Sstevel@tonic-gate 		last_bin--;
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	if (last_bin < levels + 1)
216*0Sstevel@tonic-gate 		last_bin++;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	for (i = first_bin; i <= last_bin; i++)
219*0Sstevel@tonic-gate 		total_bin_count += data[i];
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n%16s %41s %-9s\n", "value",
222*0Sstevel@tonic-gate 	    "------------- Distribution -------------", "count") < 0)
223*0Sstevel@tonic-gate 		return (-1);
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	for (i = first_bin; i <= last_bin; i++) {
226*0Sstevel@tonic-gate 		float f = ((float)data[i] * 40.0) / (float)total_bin_count;
227*0Sstevel@tonic-gate 		uint_t depth = (uint_t)(f + 0.5);
228*0Sstevel@tonic-gate 		char c[32];
229*0Sstevel@tonic-gate 		int err;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		if (i == 0) {
232*0Sstevel@tonic-gate 			(void) snprintf(c, sizeof (c), "< %d",
233*0Sstevel@tonic-gate 			    base / (uint32_t)normal);
234*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, "%16s ", c);
235*0Sstevel@tonic-gate 		} else if (i == levels + 1) {
236*0Sstevel@tonic-gate 			(void) snprintf(c, sizeof (c), ">= %d",
237*0Sstevel@tonic-gate 			    base + (levels * step));
238*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, "%16s ", c);
239*0Sstevel@tonic-gate 		} else {
240*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, "%16d ",
241*0Sstevel@tonic-gate 			    base + (i - 1) * step);
242*0Sstevel@tonic-gate 		}
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 		if (err < 0 || dt_printf(dtp, fp, "|%s%s %-9llu\n",
245*0Sstevel@tonic-gate 		    "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 40 - depth,
246*0Sstevel@tonic-gate 		    "                                        " + depth,
247*0Sstevel@tonic-gate 		    (u_longlong_t)data[i] / normal) < 0)
248*0Sstevel@tonic-gate 			return (-1);
249*0Sstevel@tonic-gate 	}
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	return (0);
252*0Sstevel@tonic-gate }
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate /*ARGSUSED*/
255*0Sstevel@tonic-gate static int
256*0Sstevel@tonic-gate dt_print_average(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
257*0Sstevel@tonic-gate     size_t size, uint64_t normal)
258*0Sstevel@tonic-gate {
259*0Sstevel@tonic-gate 	/* LINTED - alignment */
260*0Sstevel@tonic-gate 	uint64_t *data = (uint64_t *)addr;
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	return (dt_printf(dtp, fp, " %16lld", data[0] ?
263*0Sstevel@tonic-gate 	    (long long)(data[1] / normal / data[0]) : 0));
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate /*ARGSUSED*/
267*0Sstevel@tonic-gate int
268*0Sstevel@tonic-gate dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
269*0Sstevel@tonic-gate     size_t nbytes, int width, int quiet)
270*0Sstevel@tonic-gate {
271*0Sstevel@tonic-gate 	/*
272*0Sstevel@tonic-gate 	 * If the byte stream is a series of printable characters, followed by
273*0Sstevel@tonic-gate 	 * a terminating byte, we print it out as a string.  Otherwise, we
274*0Sstevel@tonic-gate 	 * assume that it's something else and just print the bytes.
275*0Sstevel@tonic-gate 	 */
276*0Sstevel@tonic-gate 	int i, j, margin = 5;
277*0Sstevel@tonic-gate 	char *c = (char *)addr;
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate 	if (nbytes == 0)
280*0Sstevel@tonic-gate 		return (0);
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
283*0Sstevel@tonic-gate 		goto raw;
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	for (i = 0; i < nbytes; i++) {
286*0Sstevel@tonic-gate 		/*
287*0Sstevel@tonic-gate 		 * We define a "printable character" to be one for which
288*0Sstevel@tonic-gate 		 * isprint(3C) returns non-zero, isspace(3C) returns non-zero,
289*0Sstevel@tonic-gate 		 * or a character which is either backspace or the bell.
290*0Sstevel@tonic-gate 		 * Backspace and the bell are regrettably special because
291*0Sstevel@tonic-gate 		 * they fail the first two tests -- and yet they are entirely
292*0Sstevel@tonic-gate 		 * printable.  These are the only two control characters that
293*0Sstevel@tonic-gate 		 * have meaning for the terminal and for which isprint(3C) and
294*0Sstevel@tonic-gate 		 * isspace(3C) return 0.
295*0Sstevel@tonic-gate 		 */
296*0Sstevel@tonic-gate 		if (isprint(c[i]) || isspace(c[i]) ||
297*0Sstevel@tonic-gate 		    c[i] == '\b' || c[i] == '\a')
298*0Sstevel@tonic-gate 			continue;
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 		if (c[i] == '\0' && i > 0) {
301*0Sstevel@tonic-gate 			/*
302*0Sstevel@tonic-gate 			 * This looks like it might be a string.  Before we
303*0Sstevel@tonic-gate 			 * assume that it is indeed a string, check the
304*0Sstevel@tonic-gate 			 * remainder of the byte range; if it contains
305*0Sstevel@tonic-gate 			 * additional non-nul characters, we'll assume that
306*0Sstevel@tonic-gate 			 * it's a binary stream that just happens to look like
307*0Sstevel@tonic-gate 			 * a string, and we'll print out the individual bytes.
308*0Sstevel@tonic-gate 			 */
309*0Sstevel@tonic-gate 			for (j = i + 1; j < nbytes; j++) {
310*0Sstevel@tonic-gate 				if (c[j] != '\0')
311*0Sstevel@tonic-gate 					break;
312*0Sstevel@tonic-gate 			}
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 			if (j != nbytes)
315*0Sstevel@tonic-gate 				break;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 			if (quiet)
318*0Sstevel@tonic-gate 				return (dt_printf(dtp, fp, "%s", c));
319*0Sstevel@tonic-gate 			else
320*0Sstevel@tonic-gate 				return (dt_printf(dtp, fp, "  %-*s", width, c));
321*0Sstevel@tonic-gate 		}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 		break;
324*0Sstevel@tonic-gate 	}
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if (i == nbytes) {
327*0Sstevel@tonic-gate 		/*
328*0Sstevel@tonic-gate 		 * The byte range is all printable characters, but there is
329*0Sstevel@tonic-gate 		 * no trailing nul byte.  We'll assume that it's a string and
330*0Sstevel@tonic-gate 		 * print it as such.
331*0Sstevel@tonic-gate 		 */
332*0Sstevel@tonic-gate 		char *s = alloca(nbytes + 1);
333*0Sstevel@tonic-gate 		bcopy(c, s, nbytes);
334*0Sstevel@tonic-gate 		s[nbytes] = '\0';
335*0Sstevel@tonic-gate 		return (dt_printf(dtp, fp, "  %-*s", width, s));
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate raw:
339*0Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n%*s      ", margin, "") < 0)
340*0Sstevel@tonic-gate 		return (-1);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	for (i = 0; i < 16; i++)
343*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "  %c", "0123456789abcdef"[i]) < 0)
344*0Sstevel@tonic-gate 			return (-1);
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "  0123456789abcdef\n") < 0)
347*0Sstevel@tonic-gate 		return (-1);
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	for (i = 0; i < nbytes; i += 16) {
351*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "%*s%5x:", margin, "", i) < 0)
352*0Sstevel@tonic-gate 			return (-1);
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		for (j = i; j < i + 16 && j < nbytes; j++) {
355*0Sstevel@tonic-gate 			if (dt_printf(dtp, fp, " %02x", (uchar_t)c[j]) < 0)
356*0Sstevel@tonic-gate 				return (-1);
357*0Sstevel@tonic-gate 		}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 		while (j++ % 16) {
360*0Sstevel@tonic-gate 			if (dt_printf(dtp, fp, "   ") < 0)
361*0Sstevel@tonic-gate 				return (-1);
362*0Sstevel@tonic-gate 		}
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "  ") < 0)
365*0Sstevel@tonic-gate 			return (-1);
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 		for (j = i; j < i + 16 && j < nbytes; j++) {
368*0Sstevel@tonic-gate 			if (dt_printf(dtp, fp, "%c",
369*0Sstevel@tonic-gate 			    c[j] < ' ' || c[j] > '~' ? '.' : c[j]) < 0)
370*0Sstevel@tonic-gate 				return (-1);
371*0Sstevel@tonic-gate 		}
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "\n") < 0)
374*0Sstevel@tonic-gate 			return (-1);
375*0Sstevel@tonic-gate 	}
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	return (0);
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate int
381*0Sstevel@tonic-gate dt_print_stack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
382*0Sstevel@tonic-gate     caddr_t addr, int depth)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	pc_t *pc = (pc_t *)(uintptr_t)addr;
385*0Sstevel@tonic-gate 	dtrace_syminfo_t dts;
386*0Sstevel@tonic-gate 	GElf_Sym sym;
387*0Sstevel@tonic-gate 	int i, indent;
388*0Sstevel@tonic-gate 	char c[PATH_MAX * 2];
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n") < 0)
391*0Sstevel@tonic-gate 		return (-1);
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	if (format == NULL)
394*0Sstevel@tonic-gate 		format = "%s";
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
397*0Sstevel@tonic-gate 		indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
398*0Sstevel@tonic-gate 	else
399*0Sstevel@tonic-gate 		indent = _dtrace_stkindent;
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	for (i = 0; i < depth && pc[i] != NULL; i++) {
402*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "%*s", indent, "") < 0)
403*0Sstevel@tonic-gate 			return (-1);
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 		if (dtrace_lookup_by_addr(dtp, pc[i], &sym, &dts) == 0) {
406*0Sstevel@tonic-gate 			if (pc[i] > sym.st_value) {
407*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
408*0Sstevel@tonic-gate 				    dts.dts_object, dts.dts_name,
409*0Sstevel@tonic-gate 				    (u_longlong_t)pc[i] - sym.st_value);
410*0Sstevel@tonic-gate 			} else {
411*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`%s",
412*0Sstevel@tonic-gate 				    dts.dts_object, dts.dts_name);
413*0Sstevel@tonic-gate 			}
414*0Sstevel@tonic-gate 		} else {
415*0Sstevel@tonic-gate 			/*
416*0Sstevel@tonic-gate 			 * We'll repeat the lookup, but this time we'll specify
417*0Sstevel@tonic-gate 			 * a NULL GElf_Sym -- indicating that we're only
418*0Sstevel@tonic-gate 			 * interested in the containing module.
419*0Sstevel@tonic-gate 			 */
420*0Sstevel@tonic-gate 			if (dtrace_lookup_by_addr(dtp, pc[i],
421*0Sstevel@tonic-gate 			    NULL, &dts) == 0) {
422*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
423*0Sstevel@tonic-gate 				    dts.dts_object, (u_longlong_t)pc[i]);
424*0Sstevel@tonic-gate 			} else {
425*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "0x%llx",
426*0Sstevel@tonic-gate 				    (u_longlong_t)pc[i]);
427*0Sstevel@tonic-gate 			}
428*0Sstevel@tonic-gate 		}
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, format, c) < 0)
431*0Sstevel@tonic-gate 			return (-1);
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 		if (dt_printf(dtp, fp, "\n") < 0)
434*0Sstevel@tonic-gate 			return (-1);
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	return (0);
438*0Sstevel@tonic-gate }
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate int
441*0Sstevel@tonic-gate dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
442*0Sstevel@tonic-gate     caddr_t addr, uint64_t arg)
443*0Sstevel@tonic-gate {
444*0Sstevel@tonic-gate 	uint64_t *pc = (uint64_t *)(uintptr_t)addr;
445*0Sstevel@tonic-gate 	uint32_t depth = DTRACE_USTACK_NFRAMES(arg);
446*0Sstevel@tonic-gate 	uint32_t strsize = DTRACE_USTACK_STRSIZE(arg);
447*0Sstevel@tonic-gate 	const char *strbase = addr + (depth + 1) * sizeof (uint64_t);
448*0Sstevel@tonic-gate 	const char *str = strsize ? strbase : NULL;
449*0Sstevel@tonic-gate 	int err = 0;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
452*0Sstevel@tonic-gate 	struct ps_prochandle *P;
453*0Sstevel@tonic-gate 	GElf_Sym sym;
454*0Sstevel@tonic-gate 	int i, indent;
455*0Sstevel@tonic-gate 	pid_t pid;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	if (depth == 0)
458*0Sstevel@tonic-gate 		return (0);
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	pid = (pid_t)*pc++;
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	if (dt_printf(dtp, fp, "\n") < 0)
463*0Sstevel@tonic-gate 		return (-1);
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 	if (format == NULL)
466*0Sstevel@tonic-gate 		format = "%s";
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 	if (dtp->dt_options[DTRACEOPT_STACKINDENT] != DTRACEOPT_UNSET)
469*0Sstevel@tonic-gate 		indent = (int)dtp->dt_options[DTRACEOPT_STACKINDENT];
470*0Sstevel@tonic-gate 	else
471*0Sstevel@tonic-gate 		indent = _dtrace_stkindent;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 	/*
474*0Sstevel@tonic-gate 	 * Ultimately, we need to add an entry point in the library vector for
475*0Sstevel@tonic-gate 	 * determining <symbol, offset> from <pid, address>.  For now, if
476*0Sstevel@tonic-gate 	 * this is a vector open, we just print the raw address or string.
477*0Sstevel@tonic-gate 	 */
478*0Sstevel@tonic-gate 	if (dtp->dt_vector == NULL)
479*0Sstevel@tonic-gate 		P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
480*0Sstevel@tonic-gate 	else
481*0Sstevel@tonic-gate 		P = NULL;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	if (P != NULL)
484*0Sstevel@tonic-gate 		dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	for (i = 0; i < depth && pc[i] != NULL; i++) {
487*0Sstevel@tonic-gate 		if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
488*0Sstevel@tonic-gate 			break;
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		if (P != NULL && Plookup_by_addr(P, pc[i],
491*0Sstevel@tonic-gate 		    name, sizeof (name), &sym) == 0) {
492*0Sstevel@tonic-gate 			(void) Pobjname(P, pc[i], objname, sizeof (objname));
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 			if (pc[i] > sym.st_value) {
495*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c),
496*0Sstevel@tonic-gate 				    "%s`%s+0x%llx", dt_basename(objname), name,
497*0Sstevel@tonic-gate 				    (u_longlong_t)(pc[i] - sym.st_value));
498*0Sstevel@tonic-gate 			} else {
499*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c),
500*0Sstevel@tonic-gate 				    "%s`%s", dt_basename(objname), name);
501*0Sstevel@tonic-gate 			}
502*0Sstevel@tonic-gate 		} else if (str != NULL && str[0] != '\0') {
503*0Sstevel@tonic-gate 			(void) snprintf(c, sizeof (c), "%s", str);
504*0Sstevel@tonic-gate 		} else {
505*0Sstevel@tonic-gate 			if (P != NULL && Pobjname(P, pc[i], objname,
506*0Sstevel@tonic-gate 			    sizeof (objname)) != NULL) {
507*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "%s`0x%llx",
508*0Sstevel@tonic-gate 				    dt_basename(objname), (u_longlong_t)pc[i]);
509*0Sstevel@tonic-gate 			} else {
510*0Sstevel@tonic-gate 				(void) snprintf(c, sizeof (c), "0x%llx",
511*0Sstevel@tonic-gate 				    (u_longlong_t)pc[i]);
512*0Sstevel@tonic-gate 			}
513*0Sstevel@tonic-gate 		}
514*0Sstevel@tonic-gate 
515*0Sstevel@tonic-gate 		if ((err = dt_printf(dtp, fp, format, c)) < 0)
516*0Sstevel@tonic-gate 			break;
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 		if ((err = dt_printf(dtp, fp, "\n")) < 0)
519*0Sstevel@tonic-gate 			break;
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate 		if (str != NULL) {
522*0Sstevel@tonic-gate 			str += strlen(str) + 1;
523*0Sstevel@tonic-gate 			if (str - strbase >= strsize)
524*0Sstevel@tonic-gate 				str = NULL;
525*0Sstevel@tonic-gate 		}
526*0Sstevel@tonic-gate 	}
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if (P != NULL) {
529*0Sstevel@tonic-gate 		dt_proc_unlock(dtp, P);
530*0Sstevel@tonic-gate 		dt_proc_release(dtp, P);
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	return (err);
534*0Sstevel@tonic-gate }
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate typedef struct dt_normal {
537*0Sstevel@tonic-gate 	dtrace_aggvarid_t dtnd_id;
538*0Sstevel@tonic-gate 	uint64_t dtnd_normal;
539*0Sstevel@tonic-gate } dt_normal_t;
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate static int
542*0Sstevel@tonic-gate dt_normalize_agg(dtrace_aggdata_t *aggdata, void *arg)
543*0Sstevel@tonic-gate {
544*0Sstevel@tonic-gate 	dt_normal_t *normal = arg;
545*0Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
546*0Sstevel@tonic-gate 	dtrace_aggvarid_t id = normal->dtnd_id;
547*0Sstevel@tonic-gate 	uintptr_t data = (uintptr_t)aggdata->dtada_data;
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
550*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset))
553*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	aggdata->dtada_normal = normal->dtnd_normal;
556*0Sstevel@tonic-gate 	return (DTRACE_AGGWALK_NORMALIZE);
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate static int
560*0Sstevel@tonic-gate dt_normalize(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
561*0Sstevel@tonic-gate {
562*0Sstevel@tonic-gate 	dt_normal_t normal;
563*0Sstevel@tonic-gate 	caddr_t addr;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/*
566*0Sstevel@tonic-gate 	 * We (should) have two records:  the aggregation ID followed by the
567*0Sstevel@tonic-gate 	 * normalization value.
568*0Sstevel@tonic-gate 	 */
569*0Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
572*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	/* LINTED - alignment */
575*0Sstevel@tonic-gate 	normal.dtnd_id = *((dtrace_aggvarid_t *)addr);
576*0Sstevel@tonic-gate 	rec++;
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	if (rec->dtrd_action != DTRACEACT_LIBACT)
579*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	if (rec->dtrd_arg != DT_ACT_NORMALIZE)
582*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	switch (rec->dtrd_size) {
587*0Sstevel@tonic-gate 	case sizeof (uint64_t):
588*0Sstevel@tonic-gate 		/* LINTED - alignment */
589*0Sstevel@tonic-gate 		normal.dtnd_normal = *((uint64_t *)addr);
590*0Sstevel@tonic-gate 		break;
591*0Sstevel@tonic-gate 	case sizeof (uint32_t):
592*0Sstevel@tonic-gate 		/* LINTED - alignment */
593*0Sstevel@tonic-gate 		normal.dtnd_normal = *((uint32_t *)addr);
594*0Sstevel@tonic-gate 		break;
595*0Sstevel@tonic-gate 	case sizeof (uint16_t):
596*0Sstevel@tonic-gate 		/* LINTED - alignment */
597*0Sstevel@tonic-gate 		normal.dtnd_normal = *((uint16_t *)addr);
598*0Sstevel@tonic-gate 		break;
599*0Sstevel@tonic-gate 	case sizeof (uint8_t):
600*0Sstevel@tonic-gate 		normal.dtnd_normal = *((uint8_t *)addr);
601*0Sstevel@tonic-gate 		break;
602*0Sstevel@tonic-gate 	default:
603*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
604*0Sstevel@tonic-gate 	}
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	(void) dtrace_aggregate_walk(dtp, dt_normalize_agg, &normal);
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	return (0);
609*0Sstevel@tonic-gate }
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate static int
612*0Sstevel@tonic-gate dt_denormalize_agg(dtrace_aggdata_t *aggdata, void *arg)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
615*0Sstevel@tonic-gate 	dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
616*0Sstevel@tonic-gate 	uintptr_t data = (uintptr_t)aggdata->dtada_data;
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
619*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset))
622*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	return (DTRACE_AGGWALK_DENORMALIZE);
625*0Sstevel@tonic-gate }
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate static int
628*0Sstevel@tonic-gate dt_clear_agg(dtrace_aggdata_t *aggdata, void *arg)
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
631*0Sstevel@tonic-gate 	dtrace_aggvarid_t id = *((dtrace_aggvarid_t *)arg);
632*0Sstevel@tonic-gate 	uintptr_t data = (uintptr_t)aggdata->dtada_data;
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
635*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset))
638*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	return (DTRACE_AGGWALK_CLEAR);
641*0Sstevel@tonic-gate }
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate typedef struct dt_trunc {
644*0Sstevel@tonic-gate 	dtrace_aggvarid_t dttd_id;
645*0Sstevel@tonic-gate 	uint64_t dttd_remaining;
646*0Sstevel@tonic-gate } dt_trunc_t;
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate static int
649*0Sstevel@tonic-gate dt_trunc_agg(dtrace_aggdata_t *aggdata, void *arg)
650*0Sstevel@tonic-gate {
651*0Sstevel@tonic-gate 	dt_trunc_t *trunc = arg;
652*0Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
653*0Sstevel@tonic-gate 	dtrace_aggvarid_t id = trunc->dttd_id;
654*0Sstevel@tonic-gate 	uintptr_t data = (uintptr_t)aggdata->dtada_data;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	if (agg->dtagd_nrecs == 0)
657*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	if (id != *(dtrace_aggvarid_t *)(data + agg->dtagd_rec[0].dtrd_offset))
660*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_NEXT);
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	if (trunc->dttd_remaining == 0)
663*0Sstevel@tonic-gate 		return (DTRACE_AGGWALK_REMOVE);
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	trunc->dttd_remaining--;
666*0Sstevel@tonic-gate 	return (DTRACE_AGGWALK_NEXT);
667*0Sstevel@tonic-gate }
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate static int
670*0Sstevel@tonic-gate dt_trunc(dtrace_hdl_t *dtp, caddr_t base, dtrace_recdesc_t *rec)
671*0Sstevel@tonic-gate {
672*0Sstevel@tonic-gate 	dt_trunc_t trunc;
673*0Sstevel@tonic-gate 	caddr_t addr;
674*0Sstevel@tonic-gate 	int64_t remaining;
675*0Sstevel@tonic-gate 	int (*func)(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	/*
678*0Sstevel@tonic-gate 	 * We (should) have two records:  the aggregation ID followed by the
679*0Sstevel@tonic-gate 	 * number of aggregation entries after which the aggregation is to be
680*0Sstevel@tonic-gate 	 * truncated.
681*0Sstevel@tonic-gate 	 */
682*0Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	if (rec->dtrd_size != sizeof (dtrace_aggvarid_t))
685*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADTRUNC));
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 	/* LINTED - alignment */
688*0Sstevel@tonic-gate 	trunc.dttd_id = *((dtrace_aggvarid_t *)addr);
689*0Sstevel@tonic-gate 	rec++;
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	if (rec->dtrd_action != DTRACEACT_LIBACT)
692*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADTRUNC));
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	if (rec->dtrd_arg != DT_ACT_TRUNC)
695*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADTRUNC));
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	addr = base + rec->dtrd_offset;
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	switch (rec->dtrd_size) {
700*0Sstevel@tonic-gate 	case sizeof (uint64_t):
701*0Sstevel@tonic-gate 		/* LINTED - alignment */
702*0Sstevel@tonic-gate 		remaining = *((int64_t *)addr);
703*0Sstevel@tonic-gate 		break;
704*0Sstevel@tonic-gate 	case sizeof (uint32_t):
705*0Sstevel@tonic-gate 		/* LINTED - alignment */
706*0Sstevel@tonic-gate 		remaining = *((int32_t *)addr);
707*0Sstevel@tonic-gate 		break;
708*0Sstevel@tonic-gate 	case sizeof (uint16_t):
709*0Sstevel@tonic-gate 		/* LINTED - alignment */
710*0Sstevel@tonic-gate 		remaining = *((int16_t *)addr);
711*0Sstevel@tonic-gate 		break;
712*0Sstevel@tonic-gate 	case sizeof (uint8_t):
713*0Sstevel@tonic-gate 		remaining = *((int8_t *)addr);
714*0Sstevel@tonic-gate 		break;
715*0Sstevel@tonic-gate 	default:
716*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADNORMAL));
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	if (remaining < 0) {
720*0Sstevel@tonic-gate 		func = dtrace_aggregate_walk_valsorted;
721*0Sstevel@tonic-gate 		remaining = -remaining;
722*0Sstevel@tonic-gate 	} else {
723*0Sstevel@tonic-gate 		func = dtrace_aggregate_walk_valrevsorted;
724*0Sstevel@tonic-gate 	}
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	assert(remaining >= 0);
727*0Sstevel@tonic-gate 	trunc.dttd_remaining = remaining;
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	(void) func(dtp, dt_trunc_agg, &trunc);
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	return (0);
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate int
735*0Sstevel@tonic-gate dt_print_agg(dtrace_aggdata_t *aggdata, void *arg)
736*0Sstevel@tonic-gate {
737*0Sstevel@tonic-gate 	int i, err = 0;
738*0Sstevel@tonic-gate 	dt_print_aggdata_t *pd = arg;
739*0Sstevel@tonic-gate 	dtrace_aggdesc_t *agg = aggdata->dtada_desc;
740*0Sstevel@tonic-gate 	FILE *fp = pd->dtpa_fp;
741*0Sstevel@tonic-gate 	dtrace_hdl_t *dtp = pd->dtpa_dtp;
742*0Sstevel@tonic-gate 	dtrace_aggvarid_t aggvarid = pd->dtpa_id;
743*0Sstevel@tonic-gate 	uintptr_t data = (uintptr_t)aggdata->dtada_data;
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	if (pd->dtpa_allunprint) {
746*0Sstevel@tonic-gate 		if (agg->dtagd_flags & DTRACE_AGD_PRINTED)
747*0Sstevel@tonic-gate 			return (0);
748*0Sstevel@tonic-gate 	} else {
749*0Sstevel@tonic-gate 		/*
750*0Sstevel@tonic-gate 		 * If we're not printing all unprinted aggregations, then the
751*0Sstevel@tonic-gate 		 * aggregation variable ID denotes a specific aggregation
752*0Sstevel@tonic-gate 		 * variable that we should print -- skip any other aggregations
753*0Sstevel@tonic-gate 		 * that we encounter.
754*0Sstevel@tonic-gate 		 */
755*0Sstevel@tonic-gate 		if (agg->dtagd_nrecs == 0)
756*0Sstevel@tonic-gate 			return (0);
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 		if (aggvarid != *(dtrace_aggvarid_t *)(data +
759*0Sstevel@tonic-gate 		    agg->dtagd_rec[0].dtrd_offset))
760*0Sstevel@tonic-gate 			return (0);
761*0Sstevel@tonic-gate 	}
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	/*
764*0Sstevel@tonic-gate 	 * Iterate over each record description, printing the traced data,
765*0Sstevel@tonic-gate 	 * skipping the first datum (the tuple member created by the compiler).
766*0Sstevel@tonic-gate 	 */
767*0Sstevel@tonic-gate 	for (i = 1; err >= 0 && i < agg->dtagd_nrecs; i++) {
768*0Sstevel@tonic-gate 		dtrace_recdesc_t *rec = &agg->dtagd_rec[i];
769*0Sstevel@tonic-gate 		dtrace_actkind_t act = rec->dtrd_action;
770*0Sstevel@tonic-gate 		caddr_t addr = aggdata->dtada_data + rec->dtrd_offset;
771*0Sstevel@tonic-gate 		size_t size = rec->dtrd_size;
772*0Sstevel@tonic-gate 		uint64_t normal;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 		normal = DTRACEACT_ISAGG(act) ? aggdata->dtada_normal : 1;
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 		if (act == DTRACEACT_STACK) {
777*0Sstevel@tonic-gate 			int depth = rec->dtrd_size / sizeof (pc_t);
778*0Sstevel@tonic-gate 			err = dt_print_stack(dtp, fp, NULL, addr, depth);
779*0Sstevel@tonic-gate 			goto nextrec;
780*0Sstevel@tonic-gate 		}
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 		if (act == DTRACEACT_USTACK || act == DTRACEACT_JSTACK) {
783*0Sstevel@tonic-gate 			err = dt_print_ustack(dtp, fp, NULL, addr,
784*0Sstevel@tonic-gate 			    rec->dtrd_arg);
785*0Sstevel@tonic-gate 			goto nextrec;
786*0Sstevel@tonic-gate 		}
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 		if (act == DTRACEAGG_QUANTIZE) {
789*0Sstevel@tonic-gate 			err = dt_print_quantize(dtp, fp, addr, size, normal);
790*0Sstevel@tonic-gate 			goto nextrec;
791*0Sstevel@tonic-gate 		}
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 		if (act == DTRACEAGG_LQUANTIZE) {
794*0Sstevel@tonic-gate 			err = dt_print_lquantize(dtp, fp, addr, size, normal);
795*0Sstevel@tonic-gate 			goto nextrec;
796*0Sstevel@tonic-gate 		}
797*0Sstevel@tonic-gate 
798*0Sstevel@tonic-gate 		if (act == DTRACEAGG_AVG) {
799*0Sstevel@tonic-gate 			err = dt_print_average(dtp, fp, addr, size, normal);
800*0Sstevel@tonic-gate 			goto nextrec;
801*0Sstevel@tonic-gate 		}
802*0Sstevel@tonic-gate 
803*0Sstevel@tonic-gate 		switch (size) {
804*0Sstevel@tonic-gate 		case sizeof (uint64_t):
805*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, " %16lld",
806*0Sstevel@tonic-gate 			    /* LINTED - alignment */
807*0Sstevel@tonic-gate 			    (long long)*((uint64_t *)addr) / normal);
808*0Sstevel@tonic-gate 			break;
809*0Sstevel@tonic-gate 		case sizeof (uint32_t):
810*0Sstevel@tonic-gate 			/* LINTED - alignment */
811*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, " %8d", *((uint32_t *)addr) /
812*0Sstevel@tonic-gate 			    (uint32_t)normal);
813*0Sstevel@tonic-gate 			break;
814*0Sstevel@tonic-gate 		case sizeof (uint16_t):
815*0Sstevel@tonic-gate 			/* LINTED - alignment */
816*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, " %5d", *((uint16_t *)addr) /
817*0Sstevel@tonic-gate 			    (uint32_t)normal);
818*0Sstevel@tonic-gate 			break;
819*0Sstevel@tonic-gate 		case sizeof (uint8_t):
820*0Sstevel@tonic-gate 			err = dt_printf(dtp, fp, " %3d", *((uint8_t *)addr) /
821*0Sstevel@tonic-gate 			    (uint32_t)normal);
822*0Sstevel@tonic-gate 			break;
823*0Sstevel@tonic-gate 		default:
824*0Sstevel@tonic-gate 			err = dt_print_bytes(dtp, fp, addr, size, 50, 0);
825*0Sstevel@tonic-gate 			break;
826*0Sstevel@tonic-gate 		}
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate nextrec:
829*0Sstevel@tonic-gate 		if (dt_buffered_flush(dtp, NULL, rec, aggdata) < 0)
830*0Sstevel@tonic-gate 			return (-1);
831*0Sstevel@tonic-gate 	}
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	if (err >= 0)
834*0Sstevel@tonic-gate 		err = dt_printf(dtp, fp, "\n");
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	if (dt_buffered_flush(dtp, NULL, NULL, aggdata) < 0)
837*0Sstevel@tonic-gate 		return (-1);
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	if (!pd->dtpa_allunprint)
840*0Sstevel@tonic-gate 		agg->dtagd_flags |= DTRACE_AGD_PRINTED;
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	return (err < 0 ? -1 : 0);
843*0Sstevel@tonic-gate }
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate static int
846*0Sstevel@tonic-gate dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, int cpu, dtrace_bufdesc_t *buf,
847*0Sstevel@tonic-gate     dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc, void *arg)
848*0Sstevel@tonic-gate {
849*0Sstevel@tonic-gate 	dtrace_epid_t id;
850*0Sstevel@tonic-gate 	size_t offs, start = buf->dtbd_oldest, end = buf->dtbd_size;
851*0Sstevel@tonic-gate 	int flow = (dtp->dt_options[DTRACEOPT_FLOWINDENT] != DTRACEOPT_UNSET);
852*0Sstevel@tonic-gate 	int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
853*0Sstevel@tonic-gate 	int rval, i, n;
854*0Sstevel@tonic-gate 	dtrace_epid_t last = DTRACE_EPIDNONE;
855*0Sstevel@tonic-gate 	dtrace_probedata_t data;
856*0Sstevel@tonic-gate 	uint64_t drops;
857*0Sstevel@tonic-gate 	caddr_t addr;
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	bzero(&data, sizeof (data));
860*0Sstevel@tonic-gate 	data.dtpda_handle = dtp;
861*0Sstevel@tonic-gate 	data.dtpda_cpu = cpu;
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate again:
864*0Sstevel@tonic-gate 	for (offs = start; offs < end; ) {
865*0Sstevel@tonic-gate 		dtrace_eprobedesc_t *epd;
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 		/*
868*0Sstevel@tonic-gate 		 * We're guaranteed to have an ID.
869*0Sstevel@tonic-gate 		 */
870*0Sstevel@tonic-gate 		id = *(uint32_t *)((uintptr_t)buf->dtbd_data + offs);
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 		if (id == DTRACE_EPIDNONE) {
873*0Sstevel@tonic-gate 			/*
874*0Sstevel@tonic-gate 			 * This is filler to assure proper alignment of the
875*0Sstevel@tonic-gate 			 * next record; we simply ignore it.
876*0Sstevel@tonic-gate 			 */
877*0Sstevel@tonic-gate 			offs += sizeof (id);
878*0Sstevel@tonic-gate 			continue;
879*0Sstevel@tonic-gate 		}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 		if ((rval = dt_epid_lookup(dtp, id, &data.dtpda_edesc,
882*0Sstevel@tonic-gate 		    &data.dtpda_pdesc)) != 0)
883*0Sstevel@tonic-gate 			return (rval);
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 		epd = data.dtpda_edesc;
886*0Sstevel@tonic-gate 		data.dtpda_data = buf->dtbd_data + offs;
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 		if (data.dtpda_edesc->dtepd_uarg != DT_ECB_DEFAULT) {
889*0Sstevel@tonic-gate 			rval = dt_handle(dtp, &data);
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_NEXT)
892*0Sstevel@tonic-gate 				goto nextepid;
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_ERROR)
895*0Sstevel@tonic-gate 				return (-1);
896*0Sstevel@tonic-gate 		}
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 		if (flow)
899*0Sstevel@tonic-gate 			(void) dt_flowindent(dtp, &data, last, buf, offs);
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 		rval = (*efunc)(&data, arg);
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 		if (flow) {
904*0Sstevel@tonic-gate 			if (data.dtpda_flow == DTRACEFLOW_ENTRY)
905*0Sstevel@tonic-gate 				data.dtpda_indent += 2;
906*0Sstevel@tonic-gate 		}
907*0Sstevel@tonic-gate 
908*0Sstevel@tonic-gate 		if (rval == DTRACE_CONSUME_NEXT)
909*0Sstevel@tonic-gate 			goto nextepid;
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 		if (rval == DTRACE_CONSUME_ABORT)
912*0Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_DIRABORT));
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 		if (rval != DTRACE_CONSUME_THIS)
915*0Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_BADRVAL));
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 		for (i = 0; i < epd->dtepd_nrecs; i++) {
918*0Sstevel@tonic-gate 			dtrace_recdesc_t *rec = &epd->dtepd_rec[i];
919*0Sstevel@tonic-gate 			dtrace_actkind_t act = rec->dtrd_action;
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 			data.dtpda_data = buf->dtbd_data + offs +
922*0Sstevel@tonic-gate 			    rec->dtrd_offset;
923*0Sstevel@tonic-gate 			addr = data.dtpda_data;
924*0Sstevel@tonic-gate 
925*0Sstevel@tonic-gate 			if (act == DTRACEACT_LIBACT) {
926*0Sstevel@tonic-gate 				if (rec->dtrd_arg == DT_ACT_CLEAR) {
927*0Sstevel@tonic-gate 					dtrace_aggvarid_t id;
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 					/* LINTED - alignment */
930*0Sstevel@tonic-gate 					id = *((dtrace_aggvarid_t *)addr);
931*0Sstevel@tonic-gate 					(void) dtrace_aggregate_walk(dtp,
932*0Sstevel@tonic-gate 					    dt_clear_agg, &id);
933*0Sstevel@tonic-gate 					continue;
934*0Sstevel@tonic-gate 				}
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 				if (rec->dtrd_arg == DT_ACT_DENORMALIZE) {
937*0Sstevel@tonic-gate 					dtrace_aggvarid_t id;
938*0Sstevel@tonic-gate 
939*0Sstevel@tonic-gate 					/* LINTED - alignment */
940*0Sstevel@tonic-gate 					id = *((dtrace_aggvarid_t *)addr);
941*0Sstevel@tonic-gate 					(void) dtrace_aggregate_walk(dtp,
942*0Sstevel@tonic-gate 					    dt_denormalize_agg, &id);
943*0Sstevel@tonic-gate 					continue;
944*0Sstevel@tonic-gate 				}
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 				if (rec->dtrd_arg == DT_ACT_NORMALIZE) {
947*0Sstevel@tonic-gate 					if (i == epd->dtepd_nrecs - 1)
948*0Sstevel@tonic-gate 						return (dt_set_errno(dtp,
949*0Sstevel@tonic-gate 						    EDT_BADNORMAL));
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 					if (dt_normalize(dtp,
952*0Sstevel@tonic-gate 					    buf->dtbd_data + offs, rec) != 0)
953*0Sstevel@tonic-gate 						return (-1);
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate 					i++;
956*0Sstevel@tonic-gate 					continue;
957*0Sstevel@tonic-gate 				}
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 				if (rec->dtrd_arg == DT_ACT_TRUNC) {
960*0Sstevel@tonic-gate 					if (i == epd->dtepd_nrecs - 1)
961*0Sstevel@tonic-gate 						return (dt_set_errno(dtp,
962*0Sstevel@tonic-gate 						    EDT_BADTRUNC));
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 					if (dt_trunc(dtp,
965*0Sstevel@tonic-gate 					    buf->dtbd_data + offs, rec) != 0)
966*0Sstevel@tonic-gate 						return (-1);
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 					i++;
969*0Sstevel@tonic-gate 					continue;
970*0Sstevel@tonic-gate 				}
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 				if (rec->dtrd_arg == DT_ACT_FTRUNCATE) {
973*0Sstevel@tonic-gate 					if (fp == NULL)
974*0Sstevel@tonic-gate 						continue;
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 					(void) fflush(fp);
977*0Sstevel@tonic-gate 					(void) ftruncate(fileno(fp), 0);
978*0Sstevel@tonic-gate 					(void) fseeko(fp, 0, SEEK_SET);
979*0Sstevel@tonic-gate 					continue;
980*0Sstevel@tonic-gate 				}
981*0Sstevel@tonic-gate 			}
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 			rval = (*rfunc)(&data, rec, arg);
984*0Sstevel@tonic-gate 
985*0Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_NEXT)
986*0Sstevel@tonic-gate 				continue;
987*0Sstevel@tonic-gate 
988*0Sstevel@tonic-gate 			if (rval == DTRACE_CONSUME_ABORT)
989*0Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_DIRABORT));
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 			if (rval != DTRACE_CONSUME_THIS)
992*0Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_BADRVAL));
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 			if (act == DTRACEACT_STACK) {
995*0Sstevel@tonic-gate 				int depth = rec->dtrd_size / sizeof (pc_t);
996*0Sstevel@tonic-gate 				if (dt_print_stack(dtp, fp, NULL,
997*0Sstevel@tonic-gate 				    addr, depth) < 0)
998*0Sstevel@tonic-gate 					return (-1);
999*0Sstevel@tonic-gate 				goto nextrec;
1000*0Sstevel@tonic-gate 			}
1001*0Sstevel@tonic-gate 
1002*0Sstevel@tonic-gate 			if (act == DTRACEACT_USTACK ||
1003*0Sstevel@tonic-gate 			    act == DTRACEACT_JSTACK) {
1004*0Sstevel@tonic-gate 				if (dt_print_ustack(dtp, fp, NULL,
1005*0Sstevel@tonic-gate 				    addr, rec->dtrd_arg) < 0)
1006*0Sstevel@tonic-gate 					return (-1);
1007*0Sstevel@tonic-gate 				goto nextrec;
1008*0Sstevel@tonic-gate 			}
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate 			if (DTRACEACT_ISPRINTFLIKE(act)) {
1011*0Sstevel@tonic-gate 				void *fmtdata;
1012*0Sstevel@tonic-gate 				int (*func)(dtrace_hdl_t *, FILE *, void *,
1013*0Sstevel@tonic-gate 				    const dtrace_probedata_t *,
1014*0Sstevel@tonic-gate 				    const dtrace_recdesc_t *, uint_t,
1015*0Sstevel@tonic-gate 				    const void *buf, size_t);
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 				if ((fmtdata = dt_format_lookup(dtp,
1018*0Sstevel@tonic-gate 				    rec->dtrd_format)) == NULL)
1019*0Sstevel@tonic-gate 					goto nofmt;
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 				switch (act) {
1022*0Sstevel@tonic-gate 				case DTRACEACT_PRINTF:
1023*0Sstevel@tonic-gate 					func = dtrace_fprintf;
1024*0Sstevel@tonic-gate 					break;
1025*0Sstevel@tonic-gate 				case DTRACEACT_PRINTA:
1026*0Sstevel@tonic-gate 					func = dtrace_fprinta;
1027*0Sstevel@tonic-gate 					break;
1028*0Sstevel@tonic-gate 				case DTRACEACT_SYSTEM:
1029*0Sstevel@tonic-gate 					func = dtrace_system;
1030*0Sstevel@tonic-gate 					break;
1031*0Sstevel@tonic-gate 				case DTRACEACT_FREOPEN:
1032*0Sstevel@tonic-gate 					func = dtrace_freopen;
1033*0Sstevel@tonic-gate 					break;
1034*0Sstevel@tonic-gate 				}
1035*0Sstevel@tonic-gate 
1036*0Sstevel@tonic-gate 				n = (*func)(dtp, fp, fmtdata, &data,
1037*0Sstevel@tonic-gate 				    rec, epd->dtepd_nrecs - i,
1038*0Sstevel@tonic-gate 				    (uchar_t *)buf->dtbd_data + offs,
1039*0Sstevel@tonic-gate 				    buf->dtbd_size - offs);
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate 				if (n < 0)
1042*0Sstevel@tonic-gate 					return (-1); /* errno is set for us */
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate 				if (n > 0)
1045*0Sstevel@tonic-gate 					i += n - 1;
1046*0Sstevel@tonic-gate 				goto nextrec;
1047*0Sstevel@tonic-gate 			}
1048*0Sstevel@tonic-gate 
1049*0Sstevel@tonic-gate nofmt:
1050*0Sstevel@tonic-gate 			if (act == DTRACEACT_PRINTA) {
1051*0Sstevel@tonic-gate 				dt_print_aggdata_t pd;
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 				bzero(&pd, sizeof (pd));
1054*0Sstevel@tonic-gate 				pd.dtpa_dtp = dtp;
1055*0Sstevel@tonic-gate 				pd.dtpa_fp = fp;
1056*0Sstevel@tonic-gate 				/* LINTED - alignment */
1057*0Sstevel@tonic-gate 				pd.dtpa_id = *((dtrace_aggvarid_t *)addr);
1058*0Sstevel@tonic-gate 
1059*0Sstevel@tonic-gate 				if (dt_printf(dtp, fp, "\n") < 0 ||
1060*0Sstevel@tonic-gate 				    dtrace_aggregate_walk_valsorted(dtp,
1061*0Sstevel@tonic-gate 				    dt_print_agg, &pd) < 0)
1062*0Sstevel@tonic-gate 					return (-1);
1063*0Sstevel@tonic-gate 
1064*0Sstevel@tonic-gate 				goto nextrec;
1065*0Sstevel@tonic-gate 			}
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 			switch (rec->dtrd_size) {
1068*0Sstevel@tonic-gate 			case sizeof (uint64_t):
1069*0Sstevel@tonic-gate 				n = dt_printf(dtp, fp,
1070*0Sstevel@tonic-gate 				    quiet ? "%lld" : " %16lld",
1071*0Sstevel@tonic-gate 				    /* LINTED - alignment */
1072*0Sstevel@tonic-gate 				    *((unsigned long long *)addr));
1073*0Sstevel@tonic-gate 				break;
1074*0Sstevel@tonic-gate 			case sizeof (uint32_t):
1075*0Sstevel@tonic-gate 				n = dt_printf(dtp, fp, quiet ? "%d" : " %8d",
1076*0Sstevel@tonic-gate 				    /* LINTED - alignment */
1077*0Sstevel@tonic-gate 				    *((uint32_t *)addr));
1078*0Sstevel@tonic-gate 				break;
1079*0Sstevel@tonic-gate 			case sizeof (uint16_t):
1080*0Sstevel@tonic-gate 				n = dt_printf(dtp, fp, quiet ? "%d" : " %5d",
1081*0Sstevel@tonic-gate 				    /* LINTED - alignment */
1082*0Sstevel@tonic-gate 				    *((uint16_t *)addr));
1083*0Sstevel@tonic-gate 				break;
1084*0Sstevel@tonic-gate 			case sizeof (uint8_t):
1085*0Sstevel@tonic-gate 				n = dt_printf(dtp, fp, quiet ? "%d" : " %3d",
1086*0Sstevel@tonic-gate 				    *((uint8_t *)addr));
1087*0Sstevel@tonic-gate 				break;
1088*0Sstevel@tonic-gate 			default:
1089*0Sstevel@tonic-gate 				n = dt_print_bytes(dtp, fp, addr,
1090*0Sstevel@tonic-gate 				    rec->dtrd_size, 33, quiet);
1091*0Sstevel@tonic-gate 				break;
1092*0Sstevel@tonic-gate 			}
1093*0Sstevel@tonic-gate 
1094*0Sstevel@tonic-gate 			if (n < 0)
1095*0Sstevel@tonic-gate 				return (-1); /* errno is set for us */
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate nextrec:
1098*0Sstevel@tonic-gate 			if (dt_buffered_flush(dtp, &data, rec, NULL) < 0)
1099*0Sstevel@tonic-gate 				return (-1); /* errno is set for us */
1100*0Sstevel@tonic-gate 		}
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 		/*
1103*0Sstevel@tonic-gate 		 * Call the record callback with a NULL record to indicate
1104*0Sstevel@tonic-gate 		 * that we're done processing this EPID.
1105*0Sstevel@tonic-gate 		 */
1106*0Sstevel@tonic-gate 		rval = (*rfunc)(&data, NULL, arg);
1107*0Sstevel@tonic-gate nextepid:
1108*0Sstevel@tonic-gate 		offs += epd->dtepd_size;
1109*0Sstevel@tonic-gate 		last = id;
1110*0Sstevel@tonic-gate 	}
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	if (buf->dtbd_oldest != 0 && start == buf->dtbd_oldest) {
1113*0Sstevel@tonic-gate 		end = buf->dtbd_oldest;
1114*0Sstevel@tonic-gate 		start = 0;
1115*0Sstevel@tonic-gate 		goto again;
1116*0Sstevel@tonic-gate 	}
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 	if ((drops = buf->dtbd_drops) == 0)
1119*0Sstevel@tonic-gate 		return (0);
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 	/*
1122*0Sstevel@tonic-gate 	 * Explicitly zero the drops to prevent us from processing them again.
1123*0Sstevel@tonic-gate 	 */
1124*0Sstevel@tonic-gate 	buf->dtbd_drops = 0;
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	return (dt_handle_cpudrop(dtp, cpu, DTRACEDROP_PRINCIPAL, drops));
1127*0Sstevel@tonic-gate }
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate typedef struct dt_begin {
1130*0Sstevel@tonic-gate 	dtrace_consume_probe_f *dtbgn_probefunc;
1131*0Sstevel@tonic-gate 	dtrace_consume_rec_f *dtbgn_recfunc;
1132*0Sstevel@tonic-gate 	void *dtbgn_arg;
1133*0Sstevel@tonic-gate 	dtrace_handle_err_f *dtbgn_errhdlr;
1134*0Sstevel@tonic-gate 	void *dtbgn_errarg;
1135*0Sstevel@tonic-gate 	int dtbgn_beginonly;
1136*0Sstevel@tonic-gate } dt_begin_t;
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate static int
1139*0Sstevel@tonic-gate dt_consume_begin_probe(const dtrace_probedata_t *data, void *arg)
1140*0Sstevel@tonic-gate {
1141*0Sstevel@tonic-gate 	dt_begin_t *begin = (dt_begin_t *)arg;
1142*0Sstevel@tonic-gate 	dtrace_probedesc_t *pd = data->dtpda_pdesc;
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
1145*0Sstevel@tonic-gate 	int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate 	if (begin->dtbgn_beginonly) {
1148*0Sstevel@tonic-gate 		if (!(r1 && r2))
1149*0Sstevel@tonic-gate 			return (DTRACE_CONSUME_NEXT);
1150*0Sstevel@tonic-gate 	} else {
1151*0Sstevel@tonic-gate 		if (r1 && r2)
1152*0Sstevel@tonic-gate 			return (DTRACE_CONSUME_NEXT);
1153*0Sstevel@tonic-gate 	}
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 	/*
1156*0Sstevel@tonic-gate 	 * We have a record that we're interested in.  Now call the underlying
1157*0Sstevel@tonic-gate 	 * probe function...
1158*0Sstevel@tonic-gate 	 */
1159*0Sstevel@tonic-gate 	return (begin->dtbgn_probefunc(data, begin->dtbgn_arg));
1160*0Sstevel@tonic-gate }
1161*0Sstevel@tonic-gate 
1162*0Sstevel@tonic-gate static int
1163*0Sstevel@tonic-gate dt_consume_begin_record(const dtrace_probedata_t *data,
1164*0Sstevel@tonic-gate     const dtrace_recdesc_t *rec, void *arg)
1165*0Sstevel@tonic-gate {
1166*0Sstevel@tonic-gate 	dt_begin_t *begin = (dt_begin_t *)arg;
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 	return (begin->dtbgn_recfunc(data, rec, begin->dtbgn_arg));
1169*0Sstevel@tonic-gate }
1170*0Sstevel@tonic-gate 
1171*0Sstevel@tonic-gate static int
1172*0Sstevel@tonic-gate dt_consume_begin_error(dtrace_errdata_t *data, void *arg)
1173*0Sstevel@tonic-gate {
1174*0Sstevel@tonic-gate 	dt_begin_t *begin = (dt_begin_t *)arg;
1175*0Sstevel@tonic-gate 	dtrace_probedesc_t *pd = data->dteda_pdesc;
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	int r1 = (strcmp(pd->dtpd_provider, "dtrace") == 0);
1178*0Sstevel@tonic-gate 	int r2 = (strcmp(pd->dtpd_name, "BEGIN") == 0);
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate 	if (begin->dtbgn_beginonly) {
1181*0Sstevel@tonic-gate 		if (!(r1 && r2))
1182*0Sstevel@tonic-gate 			return (DTRACE_HANDLE_OK);
1183*0Sstevel@tonic-gate 	} else {
1184*0Sstevel@tonic-gate 		if (r1 && r2)
1185*0Sstevel@tonic-gate 			return (DTRACE_HANDLE_OK);
1186*0Sstevel@tonic-gate 	}
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	return (begin->dtbgn_errhdlr(data, begin->dtbgn_errarg));
1189*0Sstevel@tonic-gate }
1190*0Sstevel@tonic-gate 
1191*0Sstevel@tonic-gate static int
1192*0Sstevel@tonic-gate dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, dtrace_bufdesc_t *buf,
1193*0Sstevel@tonic-gate     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
1194*0Sstevel@tonic-gate {
1195*0Sstevel@tonic-gate 	/*
1196*0Sstevel@tonic-gate 	 * There's this idea that the BEGIN probe should be processed before
1197*0Sstevel@tonic-gate 	 * everything else, and that the END probe should be processed after
1198*0Sstevel@tonic-gate 	 * anything else.  In the common case, this is pretty easy to deal
1199*0Sstevel@tonic-gate 	 * with.  However, a situation may arise where the BEGIN enabling and
1200*0Sstevel@tonic-gate 	 * END enabling are on the same CPU, and some enabling in the middle
1201*0Sstevel@tonic-gate 	 * occurred on a different CPU.  To deal with this (blech!) we need to
1202*0Sstevel@tonic-gate 	 * consume the BEGIN buffer up until the end of the BEGIN probe, and
1203*0Sstevel@tonic-gate 	 * then set it aside.  We will then process every other CPU, and then
1204*0Sstevel@tonic-gate 	 * we'll return to the BEGIN CPU and process the rest of the data
1205*0Sstevel@tonic-gate 	 * (which will inevitably include the END probe, if any).  Making this
1206*0Sstevel@tonic-gate 	 * even more complicated (!) is the library's ERROR enabling.  Because
1207*0Sstevel@tonic-gate 	 * this enabling is processed before we even get into the consume call
1208*0Sstevel@tonic-gate 	 * back, any ERROR firing would result in the library's ERROR enabling
1209*0Sstevel@tonic-gate 	 * being processed twice -- once in our first pass (for BEGIN probes),
1210*0Sstevel@tonic-gate 	 * and again in our second pass (for everything but BEGIN probes).  To
1211*0Sstevel@tonic-gate 	 * deal with this, we interpose on the ERROR handler to assure that we
1212*0Sstevel@tonic-gate 	 * only process ERROR enablings induced by BEGIN enablings in the
1213*0Sstevel@tonic-gate 	 * first pass, and that we only process ERROR enablings _not_ induced
1214*0Sstevel@tonic-gate 	 * by BEGIN enablings in the second pass.
1215*0Sstevel@tonic-gate 	 */
1216*0Sstevel@tonic-gate 	dt_begin_t begin;
1217*0Sstevel@tonic-gate 	processorid_t cpu = dtp->dt_beganon;
1218*0Sstevel@tonic-gate 	dtrace_bufdesc_t nbuf;
1219*0Sstevel@tonic-gate 	int rval, i;
1220*0Sstevel@tonic-gate 	static int max_ncpus;
1221*0Sstevel@tonic-gate 	dtrace_optval_t size;
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate 	dtp->dt_beganon = -1;
1224*0Sstevel@tonic-gate 
1225*0Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
1226*0Sstevel@tonic-gate 		/*
1227*0Sstevel@tonic-gate 		 * We really don't expect this to fail, but it is at least
1228*0Sstevel@tonic-gate 		 * technically possible for this to fail with ENOENT.  In this
1229*0Sstevel@tonic-gate 		 * case, we just drive on...
1230*0Sstevel@tonic-gate 		 */
1231*0Sstevel@tonic-gate 		if (errno == ENOENT)
1232*0Sstevel@tonic-gate 			return (0);
1233*0Sstevel@tonic-gate 
1234*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
1235*0Sstevel@tonic-gate 	}
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate 	if (!dtp->dt_stopped || buf->dtbd_cpu != dtp->dt_endedon) {
1238*0Sstevel@tonic-gate 		/*
1239*0Sstevel@tonic-gate 		 * This is the simple case.  We're either not stopped, or if
1240*0Sstevel@tonic-gate 		 * we are, we actually processed any END probes on another
1241*0Sstevel@tonic-gate 		 * CPU.  We can simply consume this buffer and return.
1242*0Sstevel@tonic-gate 		 */
1243*0Sstevel@tonic-gate 		return (dt_consume_cpu(dtp, fp, cpu, buf, pf, rf, arg));
1244*0Sstevel@tonic-gate 	}
1245*0Sstevel@tonic-gate 
1246*0Sstevel@tonic-gate 	begin.dtbgn_probefunc = pf;
1247*0Sstevel@tonic-gate 	begin.dtbgn_recfunc = rf;
1248*0Sstevel@tonic-gate 	begin.dtbgn_arg = arg;
1249*0Sstevel@tonic-gate 	begin.dtbgn_beginonly = 1;
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate 	/*
1252*0Sstevel@tonic-gate 	 * We need to interpose on the ERROR handler to be sure that we
1253*0Sstevel@tonic-gate 	 * only process ERRORs induced by BEGIN.
1254*0Sstevel@tonic-gate 	 */
1255*0Sstevel@tonic-gate 	begin.dtbgn_errhdlr = dtp->dt_errhdlr;
1256*0Sstevel@tonic-gate 	begin.dtbgn_errarg = dtp->dt_errarg;
1257*0Sstevel@tonic-gate 	dtp->dt_errhdlr = dt_consume_begin_error;
1258*0Sstevel@tonic-gate 	dtp->dt_errarg = &begin;
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate 	rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
1261*0Sstevel@tonic-gate 	    dt_consume_begin_record, &begin);
1262*0Sstevel@tonic-gate 
1263*0Sstevel@tonic-gate 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
1264*0Sstevel@tonic-gate 	dtp->dt_errarg = begin.dtbgn_errarg;
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 	if (rval != 0)
1267*0Sstevel@tonic-gate 		return (rval);
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 	/*
1270*0Sstevel@tonic-gate 	 * Now allocate a new buffer.  We'll use this to deal with every other
1271*0Sstevel@tonic-gate 	 * CPU.
1272*0Sstevel@tonic-gate 	 */
1273*0Sstevel@tonic-gate 	bzero(&nbuf, sizeof (dtrace_bufdesc_t));
1274*0Sstevel@tonic-gate 	(void) dtrace_getopt(dtp, "bufsize", &size);
1275*0Sstevel@tonic-gate 	if ((nbuf.dtbd_data = malloc(size)) == NULL)
1276*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_NOMEM));
1277*0Sstevel@tonic-gate 
1278*0Sstevel@tonic-gate 	if (max_ncpus == 0)
1279*0Sstevel@tonic-gate 		max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
1280*0Sstevel@tonic-gate 
1281*0Sstevel@tonic-gate 	for (i = 0; i < max_ncpus; i++) {
1282*0Sstevel@tonic-gate 		nbuf.dtbd_cpu = i;
1283*0Sstevel@tonic-gate 
1284*0Sstevel@tonic-gate 		if (i == cpu)
1285*0Sstevel@tonic-gate 			continue;
1286*0Sstevel@tonic-gate 
1287*0Sstevel@tonic-gate 		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, &nbuf) == -1) {
1288*0Sstevel@tonic-gate 			/*
1289*0Sstevel@tonic-gate 			 * If we failed with ENOENT, it may be because the
1290*0Sstevel@tonic-gate 			 * CPU was unconfigured -- this is okay.  Any other
1291*0Sstevel@tonic-gate 			 * error, however, is unexpected.
1292*0Sstevel@tonic-gate 			 */
1293*0Sstevel@tonic-gate 			if (errno == ENOENT)
1294*0Sstevel@tonic-gate 				continue;
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 			free(nbuf.dtbd_data);
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate 			return (dt_set_errno(dtp, errno));
1299*0Sstevel@tonic-gate 		}
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 		if ((rval = dt_consume_cpu(dtp, fp,
1302*0Sstevel@tonic-gate 		    i, &nbuf, pf, rf, arg)) != 0) {
1303*0Sstevel@tonic-gate 			free(nbuf.dtbd_data);
1304*0Sstevel@tonic-gate 			return (rval);
1305*0Sstevel@tonic-gate 		}
1306*0Sstevel@tonic-gate 	}
1307*0Sstevel@tonic-gate 
1308*0Sstevel@tonic-gate 	free(nbuf.dtbd_data);
1309*0Sstevel@tonic-gate 
1310*0Sstevel@tonic-gate 	/*
1311*0Sstevel@tonic-gate 	 * Okay -- we're done with the other buffers.  Now we want to
1312*0Sstevel@tonic-gate 	 * reconsume the first buffer -- but this time we're looking for
1313*0Sstevel@tonic-gate 	 * everything _but_ BEGIN.  And of course, in order to only consume
1314*0Sstevel@tonic-gate 	 * those ERRORs _not_ associated with BEGIN, we need to reinstall our
1315*0Sstevel@tonic-gate 	 * ERROR interposition function...
1316*0Sstevel@tonic-gate 	 */
1317*0Sstevel@tonic-gate 	begin.dtbgn_beginonly = 0;
1318*0Sstevel@tonic-gate 
1319*0Sstevel@tonic-gate 	assert(begin.dtbgn_errhdlr == dtp->dt_errhdlr);
1320*0Sstevel@tonic-gate 	assert(begin.dtbgn_errarg == dtp->dt_errarg);
1321*0Sstevel@tonic-gate 	dtp->dt_errhdlr = dt_consume_begin_error;
1322*0Sstevel@tonic-gate 	dtp->dt_errarg = &begin;
1323*0Sstevel@tonic-gate 
1324*0Sstevel@tonic-gate 	rval = dt_consume_cpu(dtp, fp, cpu, buf, dt_consume_begin_probe,
1325*0Sstevel@tonic-gate 	    dt_consume_begin_record, &begin);
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	dtp->dt_errhdlr = begin.dtbgn_errhdlr;
1328*0Sstevel@tonic-gate 	dtp->dt_errarg = begin.dtbgn_errarg;
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 	return (rval);
1331*0Sstevel@tonic-gate }
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate int
1334*0Sstevel@tonic-gate dtrace_consume(dtrace_hdl_t *dtp, FILE *fp,
1335*0Sstevel@tonic-gate     dtrace_consume_probe_f *pf, dtrace_consume_rec_f *rf, void *arg)
1336*0Sstevel@tonic-gate {
1337*0Sstevel@tonic-gate 	dtrace_bufdesc_t *buf = &dtp->dt_buf;
1338*0Sstevel@tonic-gate 	dtrace_optval_t size;
1339*0Sstevel@tonic-gate 	static int max_ncpus;
1340*0Sstevel@tonic-gate 	int i, rval;
1341*0Sstevel@tonic-gate 	dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_SWITCHRATE];
1342*0Sstevel@tonic-gate 	hrtime_t now = gethrtime();
1343*0Sstevel@tonic-gate 
1344*0Sstevel@tonic-gate 	if (dtp->dt_lastswitch != 0) {
1345*0Sstevel@tonic-gate 		if (now - dtp->dt_lastswitch < interval)
1346*0Sstevel@tonic-gate 			return (0);
1347*0Sstevel@tonic-gate 
1348*0Sstevel@tonic-gate 		dtp->dt_lastswitch += interval;
1349*0Sstevel@tonic-gate 	} else {
1350*0Sstevel@tonic-gate 		dtp->dt_lastswitch = now;
1351*0Sstevel@tonic-gate 	}
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 	if (!dtp->dt_active)
1354*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EINVAL));
1355*0Sstevel@tonic-gate 
1356*0Sstevel@tonic-gate 	if (max_ncpus == 0)
1357*0Sstevel@tonic-gate 		max_ncpus = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
1358*0Sstevel@tonic-gate 
1359*0Sstevel@tonic-gate 	if (pf == NULL)
1360*0Sstevel@tonic-gate 		pf = (dtrace_consume_probe_f *)dt_nullprobe;
1361*0Sstevel@tonic-gate 
1362*0Sstevel@tonic-gate 	if (rf == NULL)
1363*0Sstevel@tonic-gate 		rf = (dtrace_consume_rec_f *)dt_nullrec;
1364*0Sstevel@tonic-gate 
1365*0Sstevel@tonic-gate 	if (buf->dtbd_data == NULL) {
1366*0Sstevel@tonic-gate 		(void) dtrace_getopt(dtp, "bufsize", &size);
1367*0Sstevel@tonic-gate 		if ((buf->dtbd_data = malloc(size)) == NULL)
1368*0Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_NOMEM));
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate 		buf->dtbd_size = size;
1371*0Sstevel@tonic-gate 	}
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 	/*
1374*0Sstevel@tonic-gate 	 * If we have just begun, we want to first process the CPU that
1375*0Sstevel@tonic-gate 	 * executed the BEGIN probe (if any).
1376*0Sstevel@tonic-gate 	 */
1377*0Sstevel@tonic-gate 	if (dtp->dt_active && dtp->dt_beganon != -1) {
1378*0Sstevel@tonic-gate 		buf->dtbd_cpu = dtp->dt_beganon;
1379*0Sstevel@tonic-gate 		if ((rval = dt_consume_begin(dtp, fp, buf, pf, rf, arg)) != 0)
1380*0Sstevel@tonic-gate 			return (rval);
1381*0Sstevel@tonic-gate 	}
1382*0Sstevel@tonic-gate 
1383*0Sstevel@tonic-gate 	for (i = 0; i < max_ncpus; i++) {
1384*0Sstevel@tonic-gate 		buf->dtbd_cpu = i;
1385*0Sstevel@tonic-gate 
1386*0Sstevel@tonic-gate 		/*
1387*0Sstevel@tonic-gate 		 * If we have stopped, we want to process the CPU on which the
1388*0Sstevel@tonic-gate 		 * END probe was processed only _after_ we have processed
1389*0Sstevel@tonic-gate 		 * everything else.
1390*0Sstevel@tonic-gate 		 */
1391*0Sstevel@tonic-gate 		if (dtp->dt_stopped && (i == dtp->dt_endedon))
1392*0Sstevel@tonic-gate 			continue;
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate 		if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
1395*0Sstevel@tonic-gate 			/*
1396*0Sstevel@tonic-gate 			 * If we failed with ENOENT, it may be because the
1397*0Sstevel@tonic-gate 			 * CPU was unconfigured -- this is okay.  Any other
1398*0Sstevel@tonic-gate 			 * error, however, is unexpected.
1399*0Sstevel@tonic-gate 			 */
1400*0Sstevel@tonic-gate 			if (errno == ENOENT)
1401*0Sstevel@tonic-gate 				continue;
1402*0Sstevel@tonic-gate 
1403*0Sstevel@tonic-gate 			return (dt_set_errno(dtp, errno));
1404*0Sstevel@tonic-gate 		}
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 		if ((rval = dt_consume_cpu(dtp, fp, i, buf, pf, rf, arg)) != 0)
1407*0Sstevel@tonic-gate 			return (rval);
1408*0Sstevel@tonic-gate 	}
1409*0Sstevel@tonic-gate 
1410*0Sstevel@tonic-gate 	if (!dtp->dt_stopped)
1411*0Sstevel@tonic-gate 		return (0);
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate 	buf->dtbd_cpu = dtp->dt_endedon;
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_BUFSNAP, buf) == -1) {
1416*0Sstevel@tonic-gate 		/*
1417*0Sstevel@tonic-gate 		 * This _really_ shouldn't fail, but it is strictly speaking
1418*0Sstevel@tonic-gate 		 * possible for this to return ENOENT if the CPU that called
1419*0Sstevel@tonic-gate 		 * the END enabling somehow managed to become unconfigured.
1420*0Sstevel@tonic-gate 		 * It's unclear how the user can possibly expect anything
1421*0Sstevel@tonic-gate 		 * rational to happen in this case -- the state has been thrown
1422*0Sstevel@tonic-gate 		 * out along with the unconfigured CPU -- so we'll just drive
1423*0Sstevel@tonic-gate 		 * on...
1424*0Sstevel@tonic-gate 		 */
1425*0Sstevel@tonic-gate 		if (errno == ENOENT)
1426*0Sstevel@tonic-gate 			return (0);
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
1429*0Sstevel@tonic-gate 	}
1430*0Sstevel@tonic-gate 
1431*0Sstevel@tonic-gate 	return (dt_consume_cpu(dtp, fp, dtp->dt_endedon, buf, pf, rf, arg));
1432*0Sstevel@tonic-gate }
1433