1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <strings.h>
32*7c478bd9Sstevel@tonic-gate #include <unistd.h>
33*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
34*7c478bd9Sstevel@tonic-gate #include <stddef.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <stdio.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <ctype.h>
39*7c478bd9Sstevel@tonic-gate #include <alloca.h>
40*7c478bd9Sstevel@tonic-gate #include <assert.h>
41*7c478bd9Sstevel@tonic-gate #include <libgen.h>
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <dt_impl.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate static const struct {
46*7c478bd9Sstevel@tonic-gate 	size_t dtps_offset;
47*7c478bd9Sstevel@tonic-gate 	size_t dtps_len;
48*7c478bd9Sstevel@tonic-gate } dtrace_probespecs[] = {
49*7c478bd9Sstevel@tonic-gate 	{ offsetof(dtrace_probedesc_t, dtpd_provider),	DTRACE_PROVNAMELEN },
50*7c478bd9Sstevel@tonic-gate 	{ offsetof(dtrace_probedesc_t, dtpd_mod),	DTRACE_MODNAMELEN },
51*7c478bd9Sstevel@tonic-gate 	{ offsetof(dtrace_probedesc_t, dtpd_func),	DTRACE_FUNCNAMELEN },
52*7c478bd9Sstevel@tonic-gate 	{ offsetof(dtrace_probedesc_t, dtpd_name),	DTRACE_NAMELEN }
53*7c478bd9Sstevel@tonic-gate };
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate int
56*7c478bd9Sstevel@tonic-gate dtrace_xstr2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec,
57*7c478bd9Sstevel@tonic-gate     const char *s, int argc, char *const argv[], dtrace_probedesc_t *pdp)
58*7c478bd9Sstevel@tonic-gate {
59*7c478bd9Sstevel@tonic-gate 	size_t off, len, vlen;
60*7c478bd9Sstevel@tonic-gate 	const char *p, *q, *v;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	char buf[32]; /* for id_t as %d (see below) */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	if (spec < DTRACE_PROBESPEC_NONE || spec > DTRACE_PROBESPEC_NAME)
65*7c478bd9Sstevel@tonic-gate 		return (dt_set_errno(dtp, EINVAL));
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	bzero(pdp, sizeof (dtrace_probedesc_t));
68*7c478bd9Sstevel@tonic-gate 	p = s + strlen(s) - 1;
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	do {
71*7c478bd9Sstevel@tonic-gate 		for (len = 0; p >= s && *p != ':'; len++)
72*7c478bd9Sstevel@tonic-gate 			p--; /* move backward until we find a delimiter */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate 		q = p + 1;
75*7c478bd9Sstevel@tonic-gate 		vlen = 0;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 		if ((v = strchr(q, '$')) != NULL && v < q + len) {
78*7c478bd9Sstevel@tonic-gate 			/*
79*7c478bd9Sstevel@tonic-gate 			 * Set vlen to the length of the variable name and then
80*7c478bd9Sstevel@tonic-gate 			 * reset len to the length of the text prior to '$'. If
81*7c478bd9Sstevel@tonic-gate 			 * the name begins with a digit, interpret it using the
82*7c478bd9Sstevel@tonic-gate 			 * the argv[] array.  Otherwise we look in dt_macros.
83*7c478bd9Sstevel@tonic-gate 			 * For the moment, all dt_macros variables are of type
84*7c478bd9Sstevel@tonic-gate 			 * id_t (see dtrace_update() for more details on that).
85*7c478bd9Sstevel@tonic-gate 			 */
86*7c478bd9Sstevel@tonic-gate 			vlen = (size_t)(q + len - v);
87*7c478bd9Sstevel@tonic-gate 			len = (size_t)(v - q);
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 			/*
90*7c478bd9Sstevel@tonic-gate 			 * If the variable string begins with $$, skip past the
91*7c478bd9Sstevel@tonic-gate 			 * leading dollar sign since $ and $$ are equivalent
92*7c478bd9Sstevel@tonic-gate 			 * macro reference operators in a probe description.
93*7c478bd9Sstevel@tonic-gate 			 */
94*7c478bd9Sstevel@tonic-gate 			if (vlen > 2 && v[1] == '$') {
95*7c478bd9Sstevel@tonic-gate 				vlen--;
96*7c478bd9Sstevel@tonic-gate 				v++;
97*7c478bd9Sstevel@tonic-gate 			}
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 			if (isdigit(v[1])) {
100*7c478bd9Sstevel@tonic-gate 				char *end;
101*7c478bd9Sstevel@tonic-gate 				long i;
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 				errno = 0;
104*7c478bd9Sstevel@tonic-gate 				i = strtol(v + 1, &end, 10);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 				if (i < 0 || i >= argc ||
107*7c478bd9Sstevel@tonic-gate 				    errno != 0 || end != v + vlen)
108*7c478bd9Sstevel@tonic-gate 					return (dt_set_errno(dtp, EDT_BADSPCV));
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 				v = argv[i];
111*7c478bd9Sstevel@tonic-gate 				vlen = strlen(v);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 				if (yypcb != NULL && yypcb->pcb_sargv == argv)
114*7c478bd9Sstevel@tonic-gate 					yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 			} else if (vlen > 1) {
117*7c478bd9Sstevel@tonic-gate 				char *vstr = alloca(vlen);
118*7c478bd9Sstevel@tonic-gate 				dt_ident_t *idp;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 				(void) strncpy(vstr, v + 1, vlen - 1);
121*7c478bd9Sstevel@tonic-gate 				vstr[vlen - 1] = '\0';
122*7c478bd9Sstevel@tonic-gate 				idp = dt_idhash_lookup(dtp->dt_macros, vstr);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 				if (idp == NULL)
125*7c478bd9Sstevel@tonic-gate 					return (dt_set_errno(dtp, EDT_BADSPCV));
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 				v = buf;
128*7c478bd9Sstevel@tonic-gate 				vlen = snprintf(buf, 32, "%d", idp->di_id);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 			} else
131*7c478bd9Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_BADSPCV));
132*7c478bd9Sstevel@tonic-gate 		}
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 		if (spec == DTRACE_PROBESPEC_NONE)
135*7c478bd9Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_BADSPEC));
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 		if (len + vlen >= dtrace_probespecs[spec].dtps_len)
138*7c478bd9Sstevel@tonic-gate 			return (dt_set_errno(dtp, ENAMETOOLONG));
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		off = dtrace_probespecs[spec--].dtps_offset;
141*7c478bd9Sstevel@tonic-gate 		bcopy(q, (char *)pdp + off, len);
142*7c478bd9Sstevel@tonic-gate 		bcopy(v, (char *)pdp + off + len, vlen);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	} while (--p >= s);
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	pdp->dtpd_id = DTRACE_IDNONE;
147*7c478bd9Sstevel@tonic-gate 	return (0);
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate int
151*7c478bd9Sstevel@tonic-gate dtrace_str2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec,
152*7c478bd9Sstevel@tonic-gate     const char *s, dtrace_probedesc_t *pdp)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	return (dtrace_xstr2desc(dtp, spec, s, 0, NULL, pdp));
155*7c478bd9Sstevel@tonic-gate }
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate int
158*7c478bd9Sstevel@tonic-gate dtrace_id2desc(dtrace_hdl_t *dtp, dtrace_id_t id, dtrace_probedesc_t *pdp)
159*7c478bd9Sstevel@tonic-gate {
160*7c478bd9Sstevel@tonic-gate 	bzero(pdp, sizeof (dtrace_probedesc_t));
161*7c478bd9Sstevel@tonic-gate 	pdp->dtpd_id = id;
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_PROBES, pdp) == -1 ||
164*7c478bd9Sstevel@tonic-gate 	    pdp->dtpd_id != id)
165*7c478bd9Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADID));
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	return (0);
168*7c478bd9Sstevel@tonic-gate }
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate char *
171*7c478bd9Sstevel@tonic-gate dtrace_desc2str(const dtrace_probedesc_t *pdp, char *buf, size_t len)
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate 	if (pdp->dtpd_id == 0) {
174*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "%s:%s:%s:%s", pdp->dtpd_provider,
175*7c478bd9Sstevel@tonic-gate 		    pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
176*7c478bd9Sstevel@tonic-gate 	} else
177*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "%u", pdp->dtpd_id);
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	return (buf);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate char *
183*7c478bd9Sstevel@tonic-gate dtrace_attr2str(dtrace_attribute_t attr, char *buf, size_t len)
184*7c478bd9Sstevel@tonic-gate {
185*7c478bd9Sstevel@tonic-gate 	const char *name = dtrace_stability_name(attr.dtat_name);
186*7c478bd9Sstevel@tonic-gate 	const char *data = dtrace_stability_name(attr.dtat_data);
187*7c478bd9Sstevel@tonic-gate 	const char *class = dtrace_class_name(attr.dtat_class);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if (name == NULL || data == NULL || class == NULL)
190*7c478bd9Sstevel@tonic-gate 		return (NULL); /* one or more invalid attributes */
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, len, "%s/%s/%s", name, data, class);
193*7c478bd9Sstevel@tonic-gate 	return (buf);
194*7c478bd9Sstevel@tonic-gate }
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate static char *
197*7c478bd9Sstevel@tonic-gate dt_getstrattr(char *p, char **qp)
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate 	char *q;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	if (*p == '\0')
202*7c478bd9Sstevel@tonic-gate 		return (NULL);
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if ((q = strchr(p, '/')) == NULL)
205*7c478bd9Sstevel@tonic-gate 		q = p + strlen(p);
206*7c478bd9Sstevel@tonic-gate 	else
207*7c478bd9Sstevel@tonic-gate 		*q++ = '\0';
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	*qp = q;
210*7c478bd9Sstevel@tonic-gate 	return (p);
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate int
214*7c478bd9Sstevel@tonic-gate dtrace_str2attr(const char *str, dtrace_attribute_t *attr)
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	dtrace_stability_t s;
217*7c478bd9Sstevel@tonic-gate 	dtrace_class_t c;
218*7c478bd9Sstevel@tonic-gate 	char *p, *q;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	if (str == NULL || attr == NULL)
221*7c478bd9Sstevel@tonic-gate 		return (-1); /* invalid function arguments */
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	*attr = _dtrace_maxattr;
224*7c478bd9Sstevel@tonic-gate 	p = alloca(strlen(str) + 1);
225*7c478bd9Sstevel@tonic-gate 	(void) strcpy(p, str);
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	if ((p = dt_getstrattr(p, &q)) == NULL)
228*7c478bd9Sstevel@tonic-gate 		return (0);
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	for (s = 0; s <= DTRACE_STABILITY_MAX; s++) {
231*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(p, dtrace_stability_name(s)) == 0) {
232*7c478bd9Sstevel@tonic-gate 			attr->dtat_name = s;
233*7c478bd9Sstevel@tonic-gate 			break;
234*7c478bd9Sstevel@tonic-gate 		}
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	if (s > DTRACE_STABILITY_MAX)
238*7c478bd9Sstevel@tonic-gate 		return (-1);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	if ((p = dt_getstrattr(q, &q)) == NULL)
241*7c478bd9Sstevel@tonic-gate 		return (0);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 	for (s = 0; s <= DTRACE_STABILITY_MAX; s++) {
244*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(p, dtrace_stability_name(s)) == 0) {
245*7c478bd9Sstevel@tonic-gate 			attr->dtat_data = s;
246*7c478bd9Sstevel@tonic-gate 			break;
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 	}
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	if (s > DTRACE_STABILITY_MAX)
251*7c478bd9Sstevel@tonic-gate 		return (-1);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if ((p = dt_getstrattr(q, &q)) == NULL)
254*7c478bd9Sstevel@tonic-gate 		return (0);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	for (c = 0; c <= DTRACE_CLASS_MAX; c++) {
257*7c478bd9Sstevel@tonic-gate 		if (strcasecmp(p, dtrace_class_name(c)) == 0) {
258*7c478bd9Sstevel@tonic-gate 			attr->dtat_class = c;
259*7c478bd9Sstevel@tonic-gate 			break;
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (c > DTRACE_CLASS_MAX || (p = dt_getstrattr(q, &q)) != NULL)
264*7c478bd9Sstevel@tonic-gate 		return (-1);
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	return (0);
267*7c478bd9Sstevel@tonic-gate }
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate const char *
270*7c478bd9Sstevel@tonic-gate dtrace_stability_name(dtrace_stability_t s)
271*7c478bd9Sstevel@tonic-gate {
272*7c478bd9Sstevel@tonic-gate 	switch (s) {
273*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_INTERNAL:	return ("Internal");
274*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_PRIVATE:	return ("Private");
275*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_OBSOLETE:	return ("Obsolete");
276*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_EXTERNAL:	return ("External");
277*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_UNSTABLE:	return ("Unstable");
278*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_EVOLVING:	return ("Evolving");
279*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_STABLE:	return ("Stable");
280*7c478bd9Sstevel@tonic-gate 	case DTRACE_STABILITY_STANDARD:	return ("Standard");
281*7c478bd9Sstevel@tonic-gate 	default:			return (NULL);
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate }
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate const char *
286*7c478bd9Sstevel@tonic-gate dtrace_class_name(dtrace_class_t c)
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate 	switch (c) {
289*7c478bd9Sstevel@tonic-gate 	case DTRACE_CLASS_UNKNOWN:	return ("Unknown");
290*7c478bd9Sstevel@tonic-gate 	case DTRACE_CLASS_CPU:		return ("CPU");
291*7c478bd9Sstevel@tonic-gate 	case DTRACE_CLASS_PLATFORM:	return ("Platform");
292*7c478bd9Sstevel@tonic-gate 	case DTRACE_CLASS_GROUP:	return ("Group");
293*7c478bd9Sstevel@tonic-gate 	case DTRACE_CLASS_ISA:		return ("ISA");
294*7c478bd9Sstevel@tonic-gate 	case DTRACE_CLASS_COMMON:	return ("Common");
295*7c478bd9Sstevel@tonic-gate 	default:			return (NULL);
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate }
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate dtrace_attribute_t
300*7c478bd9Sstevel@tonic-gate dt_attr_min(dtrace_attribute_t a1, dtrace_attribute_t a2)
301*7c478bd9Sstevel@tonic-gate {
302*7c478bd9Sstevel@tonic-gate 	dtrace_attribute_t am;
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	am.dtat_name = MIN(a1.dtat_name, a2.dtat_name);
305*7c478bd9Sstevel@tonic-gate 	am.dtat_data = MIN(a1.dtat_data, a2.dtat_data);
306*7c478bd9Sstevel@tonic-gate 	am.dtat_class = MIN(a1.dtat_class, a2.dtat_class);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	return (am);
309*7c478bd9Sstevel@tonic-gate }
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate dtrace_attribute_t
312*7c478bd9Sstevel@tonic-gate dt_attr_max(dtrace_attribute_t a1, dtrace_attribute_t a2)
313*7c478bd9Sstevel@tonic-gate {
314*7c478bd9Sstevel@tonic-gate 	dtrace_attribute_t am;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	am.dtat_name = MAX(a1.dtat_name, a2.dtat_name);
317*7c478bd9Sstevel@tonic-gate 	am.dtat_data = MAX(a1.dtat_data, a2.dtat_data);
318*7c478bd9Sstevel@tonic-gate 	am.dtat_class = MAX(a1.dtat_class, a2.dtat_class);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	return (am);
321*7c478bd9Sstevel@tonic-gate }
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate /*
324*7c478bd9Sstevel@tonic-gate  * Compare two attributes and return an integer value in the following ranges:
325*7c478bd9Sstevel@tonic-gate  *
326*7c478bd9Sstevel@tonic-gate  * <0 if any of a1's attributes are less than a2's attributes
327*7c478bd9Sstevel@tonic-gate  * =0 if all of a1's attributes are equal to a2's attributes
328*7c478bd9Sstevel@tonic-gate  * >0 if all of a1's attributes are greater than or equal to a2's attributes
329*7c478bd9Sstevel@tonic-gate  *
330*7c478bd9Sstevel@tonic-gate  * To implement this function efficiently, we subtract a2's attributes from
331*7c478bd9Sstevel@tonic-gate  * a1's to obtain a negative result if an a1 attribute is less than its a2
332*7c478bd9Sstevel@tonic-gate  * counterpart.  We then OR the intermediate results together, relying on the
333*7c478bd9Sstevel@tonic-gate  * twos-complement property that if any result is negative, the bitwise union
334*7c478bd9Sstevel@tonic-gate  * will also be negative since the highest bit will be set in the result.
335*7c478bd9Sstevel@tonic-gate  */
336*7c478bd9Sstevel@tonic-gate int
337*7c478bd9Sstevel@tonic-gate dt_attr_cmp(dtrace_attribute_t a1, dtrace_attribute_t a2)
338*7c478bd9Sstevel@tonic-gate {
339*7c478bd9Sstevel@tonic-gate 	return (((int)a1.dtat_name - a2.dtat_name) |
340*7c478bd9Sstevel@tonic-gate 	    ((int)a1.dtat_data - a2.dtat_data) |
341*7c478bd9Sstevel@tonic-gate 	    ((int)a1.dtat_class - a2.dtat_class));
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate char *
345*7c478bd9Sstevel@tonic-gate dt_attr_str(dtrace_attribute_t a, char *buf, size_t len)
346*7c478bd9Sstevel@tonic-gate {
347*7c478bd9Sstevel@tonic-gate 	static const char stability[] = "ipoxuesS";
348*7c478bd9Sstevel@tonic-gate 	static const char class[] = "uCpgIc";
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	if (a.dtat_name < sizeof (stability) &&
351*7c478bd9Sstevel@tonic-gate 	    a.dtat_data < sizeof (stability) && a.dtat_class < sizeof (class)) {
352*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "[%c/%c/%c]", stability[a.dtat_name],
353*7c478bd9Sstevel@tonic-gate 		    stability[a.dtat_data], class[a.dtat_class]);
354*7c478bd9Sstevel@tonic-gate 	} else {
355*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "[%u/%u/%u]",
356*7c478bd9Sstevel@tonic-gate 		    a.dtat_name, a.dtat_data, a.dtat_class);
357*7c478bd9Sstevel@tonic-gate 	}
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	return (buf);
360*7c478bd9Sstevel@tonic-gate }
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate char *
363*7c478bd9Sstevel@tonic-gate dt_version_num2str(dt_version_t v, char *buf, size_t len)
364*7c478bd9Sstevel@tonic-gate {
365*7c478bd9Sstevel@tonic-gate 	uint_t M = DT_VERSION_MAJOR(v);
366*7c478bd9Sstevel@tonic-gate 	uint_t m = DT_VERSION_MINOR(v);
367*7c478bd9Sstevel@tonic-gate 	uint_t u = DT_VERSION_MICRO(v);
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	if (u == 0)
370*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "%u.%u", M, m);
371*7c478bd9Sstevel@tonic-gate 	else
372*7c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "%u.%u.%u", M, m, u);
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 	return (buf);
375*7c478bd9Sstevel@tonic-gate }
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate int
378*7c478bd9Sstevel@tonic-gate dt_version_str2num(const char *s, dt_version_t *vp)
379*7c478bd9Sstevel@tonic-gate {
380*7c478bd9Sstevel@tonic-gate 	int i = 0, n[3] = { 0, 0, 0 };
381*7c478bd9Sstevel@tonic-gate 	char c;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	while ((c = *s++) != '\0') {
384*7c478bd9Sstevel@tonic-gate 		if (isdigit(c))
385*7c478bd9Sstevel@tonic-gate 			n[i] = n[i] * 10 + c - '0';
386*7c478bd9Sstevel@tonic-gate 		else if (c != '.' || i++ >= sizeof (n) / sizeof (n[0]) - 1)
387*7c478bd9Sstevel@tonic-gate 			return (-1);
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	if (n[0] > DT_VERSION_MAJMAX ||
391*7c478bd9Sstevel@tonic-gate 	    n[1] > DT_VERSION_MINMAX ||
392*7c478bd9Sstevel@tonic-gate 	    n[2] > DT_VERSION_MICMAX)
393*7c478bd9Sstevel@tonic-gate 		return (-1);
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	if (vp != NULL)
396*7c478bd9Sstevel@tonic-gate 		*vp = DT_VERSION_NUMBER(n[0], n[1], n[2]);
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	return (0);
399*7c478bd9Sstevel@tonic-gate }
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate int
402*7c478bd9Sstevel@tonic-gate dt_version_defined(dt_version_t v)
403*7c478bd9Sstevel@tonic-gate {
404*7c478bd9Sstevel@tonic-gate 	int i;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	for (i = 0; _dtrace_versions[i] != 0; i++) {
407*7c478bd9Sstevel@tonic-gate 		if (_dtrace_versions[i] == v)
408*7c478bd9Sstevel@tonic-gate 			return (1);
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	return (0);
412*7c478bd9Sstevel@tonic-gate }
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate char *
415*7c478bd9Sstevel@tonic-gate dt_cpp_add_arg(dtrace_hdl_t *dtp, const char *str)
416*7c478bd9Sstevel@tonic-gate {
417*7c478bd9Sstevel@tonic-gate 	char *arg;
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	if (dtp->dt_cpp_argc == dtp->dt_cpp_args) {
420*7c478bd9Sstevel@tonic-gate 		int olds = dtp->dt_cpp_args;
421*7c478bd9Sstevel@tonic-gate 		int news = olds * 2;
422*7c478bd9Sstevel@tonic-gate 		char **argv = realloc(dtp->dt_cpp_argv, sizeof (char *) * news);
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 		if (argv == NULL)
425*7c478bd9Sstevel@tonic-gate 			return (NULL);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 		bzero(&argv[olds], sizeof (char *) * olds);
428*7c478bd9Sstevel@tonic-gate 		dtp->dt_cpp_argv = argv;
429*7c478bd9Sstevel@tonic-gate 		dtp->dt_cpp_args = news;
430*7c478bd9Sstevel@tonic-gate 	}
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	if ((arg = strdup(str)) == NULL)
433*7c478bd9Sstevel@tonic-gate 		return (NULL);
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	assert(dtp->dt_cpp_argc < dtp->dt_cpp_args);
436*7c478bd9Sstevel@tonic-gate 	dtp->dt_cpp_argv[dtp->dt_cpp_argc++] = arg;
437*7c478bd9Sstevel@tonic-gate 	return (arg);
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate char *
441*7c478bd9Sstevel@tonic-gate dt_cpp_pop_arg(dtrace_hdl_t *dtp)
442*7c478bd9Sstevel@tonic-gate {
443*7c478bd9Sstevel@tonic-gate 	char *arg;
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	if (dtp->dt_cpp_argc <= 1)
446*7c478bd9Sstevel@tonic-gate 		return (NULL); /* dt_cpp_argv[0] cannot be popped */
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	arg = dtp->dt_cpp_argv[--dtp->dt_cpp_argc];
449*7c478bd9Sstevel@tonic-gate 	dtp->dt_cpp_argv[dtp->dt_cpp_argc] = NULL;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	return (arg);
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
455*7c478bd9Sstevel@tonic-gate void
456*7c478bd9Sstevel@tonic-gate dt_dprintf(const char *format, ...)
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	if (_dtrace_debug) {
459*7c478bd9Sstevel@tonic-gate 		va_list alist;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 		va_start(alist, format);
462*7c478bd9Sstevel@tonic-gate 		(void) fputs("libdtrace DEBUG: ", stderr);
463*7c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, format, alist);
464*7c478bd9Sstevel@tonic-gate 		va_end(alist);
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate int
469*7c478bd9Sstevel@tonic-gate dt_ioctl(dtrace_hdl_t *dtp, int val, void *arg)
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	const dtrace_vector_t *v = dtp->dt_vector;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	if (v != NULL)
474*7c478bd9Sstevel@tonic-gate 		return (v->dtv_ioctl(dtp->dt_varg, val, arg));
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	if (dtp->dt_fd >= 0)
477*7c478bd9Sstevel@tonic-gate 		return (ioctl(dtp->dt_fd, val, arg));
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	errno = EBADF;
480*7c478bd9Sstevel@tonic-gate 	return (-1);
481*7c478bd9Sstevel@tonic-gate }
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate int
484*7c478bd9Sstevel@tonic-gate dt_status(dtrace_hdl_t *dtp, processorid_t cpu)
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate 	const dtrace_vector_t *v = dtp->dt_vector;
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	if (v == NULL)
489*7c478bd9Sstevel@tonic-gate 		return (p_online(cpu, P_STATUS));
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	return (v->dtv_status(dtp->dt_varg, cpu));
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate long
495*7c478bd9Sstevel@tonic-gate dt_sysconf(dtrace_hdl_t *dtp, int name)
496*7c478bd9Sstevel@tonic-gate {
497*7c478bd9Sstevel@tonic-gate 	const dtrace_vector_t *v = dtp->dt_vector;
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	if (v == NULL)
500*7c478bd9Sstevel@tonic-gate 		return (sysconf(name));
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	return (v->dtv_sysconf(dtp->dt_varg, name));
503*7c478bd9Sstevel@tonic-gate }
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate /*
506*7c478bd9Sstevel@tonic-gate  * Wrapper around write(2) to handle partial writes.  For maximum safety of
507*7c478bd9Sstevel@tonic-gate  * output files and proper error reporting, we continuing writing in the
508*7c478bd9Sstevel@tonic-gate  * face of partial writes until write(2) fails or 'buf' is completely written.
509*7c478bd9Sstevel@tonic-gate  * We also record any errno in the specified dtrace_hdl_t as well as 'errno'.
510*7c478bd9Sstevel@tonic-gate  */
511*7c478bd9Sstevel@tonic-gate ssize_t
512*7c478bd9Sstevel@tonic-gate dt_write(dtrace_hdl_t *dtp, int fd, const void *buf, size_t n)
513*7c478bd9Sstevel@tonic-gate {
514*7c478bd9Sstevel@tonic-gate 	ssize_t resid = n;
515*7c478bd9Sstevel@tonic-gate 	ssize_t len;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	while (resid != 0) {
518*7c478bd9Sstevel@tonic-gate 		if ((len = write(fd, buf, resid)) <= 0)
519*7c478bd9Sstevel@tonic-gate 			break;
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 		resid -= len;
522*7c478bd9Sstevel@tonic-gate 		buf = (char *)buf + len;
523*7c478bd9Sstevel@tonic-gate 	}
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	if (resid == n && n != 0)
526*7c478bd9Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	return (n - resid);
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate /*
532*7c478bd9Sstevel@tonic-gate  * This function handles all output from libdtrace, as well as the
533*7c478bd9Sstevel@tonic-gate  * dtrace_sprintf() case.  If we're here due to dtrace_sprintf(), then
534*7c478bd9Sstevel@tonic-gate  * dt_sprintf_buflen will be non-zero; in this case, we sprintf into the
535*7c478bd9Sstevel@tonic-gate  * specified buffer and return.  Otherwise, if output is buffered (denoted by
536*7c478bd9Sstevel@tonic-gate  * a NULL fp), we sprintf the desired output into the buffered buffer
537*7c478bd9Sstevel@tonic-gate  * (expanding the buffer if required).  If we don't satisfy either of these
538*7c478bd9Sstevel@tonic-gate  * conditions (that is, if we are to actually generate output), then we call
539*7c478bd9Sstevel@tonic-gate  * fprintf with the specified fp.  In this case, we need to deal with one of
540*7c478bd9Sstevel@tonic-gate  * the more annoying peculiarities of libc's printf routines:  any failed
541*7c478bd9Sstevel@tonic-gate  * write persistently sets an error flag inside the FILE causing every
542*7c478bd9Sstevel@tonic-gate  * subsequent write to fail, but only the caller that initiated the error gets
543*7c478bd9Sstevel@tonic-gate  * the errno.  Since libdtrace clients often intercept SIGINT, this case is
544*7c478bd9Sstevel@tonic-gate  * particularly frustrating since we don't want the EINTR on one attempt to
545*7c478bd9Sstevel@tonic-gate  * write to the output file to preclude later attempts to write.  This
546*7c478bd9Sstevel@tonic-gate  * function therefore does a clearerr() if any error occurred, and saves the
547*7c478bd9Sstevel@tonic-gate  * errno for the caller inside the specified dtrace_hdl_t.
548*7c478bd9Sstevel@tonic-gate  */
549*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
550*7c478bd9Sstevel@tonic-gate int
551*7c478bd9Sstevel@tonic-gate dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
552*7c478bd9Sstevel@tonic-gate {
553*7c478bd9Sstevel@tonic-gate 	va_list ap;
554*7c478bd9Sstevel@tonic-gate 	int n;
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	va_start(ap, format);
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	if (dtp->dt_sprintf_buflen != 0) {
559*7c478bd9Sstevel@tonic-gate 		int len;
560*7c478bd9Sstevel@tonic-gate 		char *buf;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 		assert(dtp->dt_sprintf_buf != NULL);
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 		buf = &dtp->dt_sprintf_buf[len = strlen(dtp->dt_sprintf_buf)];
565*7c478bd9Sstevel@tonic-gate 		len = dtp->dt_sprintf_buflen - len;
566*7c478bd9Sstevel@tonic-gate 		assert(len >= 0);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 		if ((n = vsnprintf(buf, len, format, ap)) < 0)
569*7c478bd9Sstevel@tonic-gate 			n = dt_set_errno(dtp, errno);
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 		va_end(ap);
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		return (n);
574*7c478bd9Sstevel@tonic-gate 	}
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
577*7c478bd9Sstevel@tonic-gate 		int needed, rval;
578*7c478bd9Sstevel@tonic-gate 		size_t avail;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 		/*
581*7c478bd9Sstevel@tonic-gate 		 * It's not legal to use buffered ouput if there is not a
582*7c478bd9Sstevel@tonic-gate 		 * handler for buffered output.
583*7c478bd9Sstevel@tonic-gate 		 */
584*7c478bd9Sstevel@tonic-gate 		if (dtp->dt_bufhdlr == NULL) {
585*7c478bd9Sstevel@tonic-gate 			va_end(ap);
586*7c478bd9Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_NOBUFFERED));
587*7c478bd9Sstevel@tonic-gate 		}
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		if (dtp->dt_buffered_buf == NULL) {
590*7c478bd9Sstevel@tonic-gate 			assert(dtp->dt_buffered_size == 0);
591*7c478bd9Sstevel@tonic-gate 			dtp->dt_buffered_size = 1;
592*7c478bd9Sstevel@tonic-gate 			dtp->dt_buffered_buf = malloc(dtp->dt_buffered_size);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 			if (dtp->dt_buffered_buf == NULL) {
595*7c478bd9Sstevel@tonic-gate 				va_end(ap);
596*7c478bd9Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_NOMEM));
597*7c478bd9Sstevel@tonic-gate 			}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 			dtp->dt_buffered_offs = 0;
600*7c478bd9Sstevel@tonic-gate 			dtp->dt_buffered_buf[0] = '\0';
601*7c478bd9Sstevel@tonic-gate 		}
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 		if ((needed = vsnprintf(NULL, 0, format, ap)) < 0) {
604*7c478bd9Sstevel@tonic-gate 			rval = dt_set_errno(dtp, errno);
605*7c478bd9Sstevel@tonic-gate 			va_end(ap);
606*7c478bd9Sstevel@tonic-gate 			return (rval);
607*7c478bd9Sstevel@tonic-gate 		}
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 		if (needed == 0) {
610*7c478bd9Sstevel@tonic-gate 			va_end(ap);
611*7c478bd9Sstevel@tonic-gate 			return (0);
612*7c478bd9Sstevel@tonic-gate 		}
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 		for (;;) {
615*7c478bd9Sstevel@tonic-gate 			char *newbuf;
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 			assert(dtp->dt_buffered_offs < dtp->dt_buffered_size);
618*7c478bd9Sstevel@tonic-gate 			avail = dtp->dt_buffered_size - dtp->dt_buffered_offs;
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 			if (needed + 1 < avail)
621*7c478bd9Sstevel@tonic-gate 				break;
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 			if ((newbuf = realloc(dtp->dt_buffered_buf,
624*7c478bd9Sstevel@tonic-gate 			    dtp->dt_buffered_size << 1)) == NULL) {
625*7c478bd9Sstevel@tonic-gate 				va_end(ap);
626*7c478bd9Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_NOMEM));
627*7c478bd9Sstevel@tonic-gate 			}
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 			dtp->dt_buffered_buf = newbuf;
630*7c478bd9Sstevel@tonic-gate 			dtp->dt_buffered_size <<= 1;
631*7c478bd9Sstevel@tonic-gate 		}
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 		if (vsnprintf(&dtp->dt_buffered_buf[dtp->dt_buffered_offs],
634*7c478bd9Sstevel@tonic-gate 		    avail, format, ap) < 0) {
635*7c478bd9Sstevel@tonic-gate 			rval = dt_set_errno(dtp, errno);
636*7c478bd9Sstevel@tonic-gate 			va_end(ap);
637*7c478bd9Sstevel@tonic-gate 			return (rval);
638*7c478bd9Sstevel@tonic-gate 		}
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 		dtp->dt_buffered_offs += needed;
641*7c478bd9Sstevel@tonic-gate 		assert(dtp->dt_buffered_buf[dtp->dt_buffered_offs] == '\0');
642*7c478bd9Sstevel@tonic-gate 		return (0);
643*7c478bd9Sstevel@tonic-gate 	}
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	n = vfprintf(fp, format, ap);
646*7c478bd9Sstevel@tonic-gate 	va_end(ap);
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	if (n < 0) {
649*7c478bd9Sstevel@tonic-gate 		clearerr(fp);
650*7c478bd9Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	return (n);
654*7c478bd9Sstevel@tonic-gate }
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate int
657*7c478bd9Sstevel@tonic-gate dt_buffered_flush(dtrace_hdl_t *dtp, dtrace_probedata_t *pdata,
658*7c478bd9Sstevel@tonic-gate     dtrace_recdesc_t *rec, dtrace_aggdata_t *agg)
659*7c478bd9Sstevel@tonic-gate {
660*7c478bd9Sstevel@tonic-gate 	dtrace_bufdata_t data;
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	if (dtp->dt_buffered_offs == 0)
663*7c478bd9Sstevel@tonic-gate 		return (0);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	data.dtbda_handle = dtp;
666*7c478bd9Sstevel@tonic-gate 	data.dtbda_buffered = dtp->dt_buffered_buf;
667*7c478bd9Sstevel@tonic-gate 	data.dtbda_probe = pdata;
668*7c478bd9Sstevel@tonic-gate 	data.dtbda_recdesc = rec;
669*7c478bd9Sstevel@tonic-gate 	data.dtbda_aggdata = agg;
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	if ((*dtp->dt_bufhdlr)(&data, dtp->dt_bufarg) == DTRACE_HANDLE_ABORT)
672*7c478bd9Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DIRABORT));
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	dtp->dt_buffered_offs = 0;
675*7c478bd9Sstevel@tonic-gate 	dtp->dt_buffered_buf[0] = '\0';
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	return (0);
678*7c478bd9Sstevel@tonic-gate }
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate void
681*7c478bd9Sstevel@tonic-gate dt_buffered_destroy(dtrace_hdl_t *dtp)
682*7c478bd9Sstevel@tonic-gate {
683*7c478bd9Sstevel@tonic-gate 	free(dtp->dt_buffered_buf);
684*7c478bd9Sstevel@tonic-gate 	dtp->dt_buffered_buf = NULL;
685*7c478bd9Sstevel@tonic-gate 	dtp->dt_buffered_offs = 0;
686*7c478bd9Sstevel@tonic-gate 	dtp->dt_buffered_size = 0;
687*7c478bd9Sstevel@tonic-gate }
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate void *
690*7c478bd9Sstevel@tonic-gate dt_zalloc(dtrace_hdl_t *dtp, size_t size)
691*7c478bd9Sstevel@tonic-gate {
692*7c478bd9Sstevel@tonic-gate 	void *data;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	if ((data = malloc(size)) == NULL)
695*7c478bd9Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
696*7c478bd9Sstevel@tonic-gate 	else
697*7c478bd9Sstevel@tonic-gate 		bzero(data, size);
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	return (data);
700*7c478bd9Sstevel@tonic-gate }
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate void *
703*7c478bd9Sstevel@tonic-gate dt_alloc(dtrace_hdl_t *dtp, size_t size)
704*7c478bd9Sstevel@tonic-gate {
705*7c478bd9Sstevel@tonic-gate 	void *data;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	if ((data = malloc(size)) == NULL)
708*7c478bd9Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	return (data);
711*7c478bd9Sstevel@tonic-gate }
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate void
714*7c478bd9Sstevel@tonic-gate dt_free(dtrace_hdl_t *dtp, void *data)
715*7c478bd9Sstevel@tonic-gate {
716*7c478bd9Sstevel@tonic-gate 	assert(dtp != NULL); /* ensure sane use of this interface */
717*7c478bd9Sstevel@tonic-gate 	free(data);
718*7c478bd9Sstevel@tonic-gate }
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate /*
721*7c478bd9Sstevel@tonic-gate  * dt_gmatch() is similar to gmatch(3GEN) and dtrace(7D) globbing, but also
722*7c478bd9Sstevel@tonic-gate  * implements the behavior that an empty pattern matches any string.
723*7c478bd9Sstevel@tonic-gate  */
724*7c478bd9Sstevel@tonic-gate int
725*7c478bd9Sstevel@tonic-gate dt_gmatch(const char *s, const char *p)
726*7c478bd9Sstevel@tonic-gate {
727*7c478bd9Sstevel@tonic-gate 	return (p == NULL || *p == '\0' || gmatch(s, p));
728*7c478bd9Sstevel@tonic-gate }
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate char *
731*7c478bd9Sstevel@tonic-gate dt_basename(char *str)
732*7c478bd9Sstevel@tonic-gate {
733*7c478bd9Sstevel@tonic-gate 	char *last = strrchr(str, '/');
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	if (last == NULL)
736*7c478bd9Sstevel@tonic-gate 		return (str);
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	return (last + 1);
739*7c478bd9Sstevel@tonic-gate }
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate struct _rwlock;
742*7c478bd9Sstevel@tonic-gate struct _lwp_mutex;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate int
745*7c478bd9Sstevel@tonic-gate dt_rw_read_held(pthread_rwlock_t *lock)
746*7c478bd9Sstevel@tonic-gate {
747*7c478bd9Sstevel@tonic-gate 	extern int _rw_read_held(struct _rwlock *);
748*7c478bd9Sstevel@tonic-gate 	return (_rw_read_held((struct _rwlock *)lock));
749*7c478bd9Sstevel@tonic-gate }
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate int
752*7c478bd9Sstevel@tonic-gate dt_rw_write_held(pthread_rwlock_t *lock)
753*7c478bd9Sstevel@tonic-gate {
754*7c478bd9Sstevel@tonic-gate 	extern int _rw_write_held(struct _rwlock *);
755*7c478bd9Sstevel@tonic-gate 	return (_rw_write_held((struct _rwlock *)lock));
756*7c478bd9Sstevel@tonic-gate }
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate int
759*7c478bd9Sstevel@tonic-gate dt_mutex_held(pthread_mutex_t *lock)
760*7c478bd9Sstevel@tonic-gate {
761*7c478bd9Sstevel@tonic-gate 	extern int _mutex_held(struct _lwp_mutex *);
762*7c478bd9Sstevel@tonic-gate 	return (_mutex_held((struct _lwp_mutex *)lock));
763*7c478bd9Sstevel@tonic-gate }
764