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 <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/sysmacros.h>
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include <assert.h>
33*0Sstevel@tonic-gate #include <limits.h>
34*0Sstevel@tonic-gate #include <strings.h>
35*0Sstevel@tonic-gate #include <stdlib.h>
36*0Sstevel@tonic-gate #include <alloca.h>
37*0Sstevel@tonic-gate #include <unistd.h>
38*0Sstevel@tonic-gate #include <errno.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <dt_provider.h>
41*0Sstevel@tonic-gate #include <dt_module.h>
42*0Sstevel@tonic-gate #include <dt_string.h>
43*0Sstevel@tonic-gate #include <dt_list.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate static dt_provider_t *
46*0Sstevel@tonic-gate dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h)
47*0Sstevel@tonic-gate {
48*0Sstevel@tonic-gate 	dt_list_append(&dtp->dt_provlist, pvp);
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate 	pvp->pv_next = dtp->dt_provs[h];
51*0Sstevel@tonic-gate 	dtp->dt_provs[h] = pvp;
52*0Sstevel@tonic-gate 	dtp->dt_nprovs++;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate 	return (pvp);
55*0Sstevel@tonic-gate }
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate dt_provider_t *
58*0Sstevel@tonic-gate dt_provider_lookup(dtrace_hdl_t *dtp, const char *name)
59*0Sstevel@tonic-gate {
60*0Sstevel@tonic-gate 	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets;
61*0Sstevel@tonic-gate 	dt_provider_t *pvp;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 	for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) {
64*0Sstevel@tonic-gate 		if (strcmp(pvp->pv_desc.dtvd_name, name) == 0)
65*0Sstevel@tonic-gate 			return (pvp);
66*0Sstevel@tonic-gate 	}
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 	if (strisglob(name) || name[0] == '\0') {
69*0Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOPROV);
70*0Sstevel@tonic-gate 		return (NULL);
71*0Sstevel@tonic-gate 	}
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	if ((pvp = dt_provider_create(dtp, name)) == NULL)
74*0Sstevel@tonic-gate 		return (NULL); /* dt_errno is set for us */
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &pvp->pv_desc) == -1) {
77*0Sstevel@tonic-gate 		(void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno);
78*0Sstevel@tonic-gate 		dt_provider_destroy(dtp, pvp);
79*0Sstevel@tonic-gate 		return (NULL);
80*0Sstevel@tonic-gate 	}
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	pvp->pv_flags |= DT_PROVIDER_IMPL;
83*0Sstevel@tonic-gate 	return (pvp);
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate dt_provider_t *
87*0Sstevel@tonic-gate dt_provider_create(dtrace_hdl_t *dtp, const char *name)
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate 	dt_provider_t *pvp;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL)
92*0Sstevel@tonic-gate 		return (NULL);
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	(void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN);
95*0Sstevel@tonic-gate 	pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0);
96*0Sstevel@tonic-gate 	pvp->pv_gen = dtp->dt_gen;
97*0Sstevel@tonic-gate 	pvp->pv_hdl = dtp;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	if (pvp->pv_probes == NULL) {
100*0Sstevel@tonic-gate 		dt_free(dtp, pvp);
101*0Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
102*0Sstevel@tonic-gate 		return (NULL);
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr;
106*0Sstevel@tonic-gate 	pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr;
107*0Sstevel@tonic-gate 	pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr;
108*0Sstevel@tonic-gate 	pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr;
109*0Sstevel@tonic-gate 	pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	return (dt_provider_insert(dtp, pvp,
112*0Sstevel@tonic-gate 	    dt_strtab_hash(name, NULL) % dtp->dt_provbuckets));
113*0Sstevel@tonic-gate }
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate void
116*0Sstevel@tonic-gate dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp)
117*0Sstevel@tonic-gate {
118*0Sstevel@tonic-gate 	dt_provider_t **pp;
119*0Sstevel@tonic-gate 	uint_t h;
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	assert(pvp->pv_hdl == dtp);
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets;
124*0Sstevel@tonic-gate 	pp = &dtp->dt_provs[h];
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	while (*pp != NULL && *pp != pvp)
127*0Sstevel@tonic-gate 		pp = &(*pp)->pv_next;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	assert(*pp != NULL && *pp == pvp);
130*0Sstevel@tonic-gate 	*pp = pvp->pv_next;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	dt_list_delete(&dtp->dt_provlist, pvp);
133*0Sstevel@tonic-gate 	dtp->dt_nprovs--;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	if (pvp->pv_probes != NULL)
136*0Sstevel@tonic-gate 		dt_idhash_destroy(pvp->pv_probes);
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	dt_node_link_free(&pvp->pv_nodes);
139*0Sstevel@tonic-gate 	dt_free(dtp, pvp);
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate static uint8_t
143*0Sstevel@tonic-gate dt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp)
144*0Sstevel@tonic-gate {
145*0Sstevel@tonic-gate 	uint8_t i;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	for (i = 0; nnp != NULL; i++) {
148*0Sstevel@tonic-gate 		if (nnp->dn_string != NULL &&
149*0Sstevel@tonic-gate 		    strcmp(nnp->dn_string, xnp->dn_string) == 0)
150*0Sstevel@tonic-gate 			break;
151*0Sstevel@tonic-gate 		else
152*0Sstevel@tonic-gate 			nnp = nnp->dn_list;
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	return (i);
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate static dt_node_t *
159*0Sstevel@tonic-gate dt_probe_alloc_args(dt_provider_t *pvp, int argc)
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	dt_node_t *args = NULL, *pnp = NULL, *dnp;
162*0Sstevel@tonic-gate 	int i;
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	for (i = 0; i < argc; i++, pnp = dnp) {
165*0Sstevel@tonic-gate 		if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL)
166*0Sstevel@tonic-gate 			return (NULL);
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 		dnp->dn_link = pvp->pv_nodes;
169*0Sstevel@tonic-gate 		pvp->pv_nodes = dnp;
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 		if (args == NULL)
172*0Sstevel@tonic-gate 			args = dnp;
173*0Sstevel@tonic-gate 		else
174*0Sstevel@tonic-gate 			pnp->dn_list = dnp;
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	return (args);
178*0Sstevel@tonic-gate }
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate static size_t
181*0Sstevel@tonic-gate dt_probe_keylen(const dtrace_probedesc_t *pdp)
182*0Sstevel@tonic-gate {
183*0Sstevel@tonic-gate 	return (strlen(pdp->dtpd_mod) + 1 +
184*0Sstevel@tonic-gate 	    strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1);
185*0Sstevel@tonic-gate }
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate static char *
188*0Sstevel@tonic-gate dt_probe_key(const dtrace_probedesc_t *pdp, char *s)
189*0Sstevel@tonic-gate {
190*0Sstevel@tonic-gate 	(void) snprintf(s, INT_MAX, "%s:%s:%s",
191*0Sstevel@tonic-gate 	    pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
192*0Sstevel@tonic-gate 	return (s);
193*0Sstevel@tonic-gate }
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate /*
196*0Sstevel@tonic-gate  * If a probe was discovered from the kernel, ask dtrace(7D) for a description
197*0Sstevel@tonic-gate  * of each of its arguments, including native and translated types.
198*0Sstevel@tonic-gate  */
199*0Sstevel@tonic-gate static dt_probe_t *
200*0Sstevel@tonic-gate dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
201*0Sstevel@tonic-gate {
202*0Sstevel@tonic-gate 	dtrace_hdl_t *dtp = pvp->pv_hdl;
203*0Sstevel@tonic-gate 	char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp)));
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	dt_node_t *xargs, *nargs;
206*0Sstevel@tonic-gate 	dt_ident_t *idp;
207*0Sstevel@tonic-gate 	dt_probe_t *prp;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	dtrace_typeinfo_t dtt;
210*0Sstevel@tonic-gate 	int i, nc, xc;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	int adc = _dtrace_argmax;
213*0Sstevel@tonic-gate 	dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc);
214*0Sstevel@tonic-gate 	dtrace_argdesc_t *adp = adv;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0);
217*0Sstevel@tonic-gate 	assert(pdp->dtpd_id != DTRACE_IDNONE);
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	dt_dprintf("discovering probe %s:%s id=%d\n",
220*0Sstevel@tonic-gate 	    pvp->pv_desc.dtvd_name, name, pdp->dtpd_id);
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	for (nc = -1, i = 0; i < adc; i++, adp++) {
223*0Sstevel@tonic-gate 		bzero(adp, sizeof (dtrace_argdesc_t));
224*0Sstevel@tonic-gate 		adp->dtargd_ndx = i;
225*0Sstevel@tonic-gate 		adp->dtargd_id = pdp->dtpd_id;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 		if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) {
228*0Sstevel@tonic-gate 			(void) dt_set_errno(dtp, errno);
229*0Sstevel@tonic-gate 			return (NULL);
230*0Sstevel@tonic-gate 		}
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 		if (adp->dtargd_ndx == DTRACE_ARGNONE)
233*0Sstevel@tonic-gate 			break; /* all argument descs have been retrieved */
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 		nc = MAX(nc, adp->dtargd_mapping);
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	xc = i;
239*0Sstevel@tonic-gate 	nc++;
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	/*
242*0Sstevel@tonic-gate 	 * Now that we have discovered the number of native and translated
243*0Sstevel@tonic-gate 	 * arguments from the argument descriptions, allocate a new probe ident
244*0Sstevel@tonic-gate 	 * and corresponding dt_probe_t and hash it into the provider.
245*0Sstevel@tonic-gate 	 */
246*0Sstevel@tonic-gate 	xargs = dt_probe_alloc_args(pvp, xc);
247*0Sstevel@tonic-gate 	nargs = dt_probe_alloc_args(pvp, nc);
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL))
250*0Sstevel@tonic-gate 		return (NULL); /* dt_errno is set for us */
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	idp = dt_ident_create(name, DT_IDENT_PROBE,
253*0Sstevel@tonic-gate 	    DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0,
254*0Sstevel@tonic-gate 	    &dt_idops_probe, NULL, dtp->dt_gen);
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	if (idp == NULL) {
257*0Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOMEM);
258*0Sstevel@tonic-gate 		return (NULL);
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	if ((prp = dt_probe_create(dtp, idp, nargs, nc, xargs, xc)) == NULL) {
262*0Sstevel@tonic-gate 		dt_ident_destroy(idp);
263*0Sstevel@tonic-gate 		return (NULL);
264*0Sstevel@tonic-gate 	}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	dt_probe_declare(pvp, prp);
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	/*
269*0Sstevel@tonic-gate 	 * Once our new dt_probe_t is fully constructed, iterate over the
270*0Sstevel@tonic-gate 	 * cached argument descriptions and assign types to prp->pr_nargv[]
271*0Sstevel@tonic-gate 	 * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[].
272*0Sstevel@tonic-gate 	 */
273*0Sstevel@tonic-gate 	for (adp = adv, i = 0; i < xc; i++, adp++) {
274*0Sstevel@tonic-gate 		if (dtrace_type_strcompile(dtp,
275*0Sstevel@tonic-gate 		    adp->dtargd_native, &dtt) != 0) {
276*0Sstevel@tonic-gate 			dt_dprintf("failed to resolve input type %s "
277*0Sstevel@tonic-gate 			    "for %s:%s arg #%d: %s\n", adp->dtargd_native,
278*0Sstevel@tonic-gate 			    pvp->pv_desc.dtvd_name, name, i + 1,
279*0Sstevel@tonic-gate 			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 			dtt.dtt_object = NULL;
282*0Sstevel@tonic-gate 			dtt.dtt_ctfp = NULL;
283*0Sstevel@tonic-gate 			dtt.dtt_type = CTF_ERR;
284*0Sstevel@tonic-gate 		} else {
285*0Sstevel@tonic-gate 			dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
286*0Sstevel@tonic-gate 			    dtt.dtt_ctfp, dtt.dtt_type);
287*0Sstevel@tonic-gate 		}
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 		if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
290*0Sstevel@tonic-gate 		    strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) {
291*0Sstevel@tonic-gate 			dt_node_type_propagate(prp->pr_nargv[
292*0Sstevel@tonic-gate 			    adp->dtargd_mapping], prp->pr_xargv[i]);
293*0Sstevel@tonic-gate 		} else if (dtrace_type_strcompile(dtp,
294*0Sstevel@tonic-gate 		    adp->dtargd_xlate, &dtt) != 0) {
295*0Sstevel@tonic-gate 			dt_dprintf("failed to resolve output type %s "
296*0Sstevel@tonic-gate 			    "for %s:%s arg #%d: %s\n", adp->dtargd_xlate,
297*0Sstevel@tonic-gate 			    pvp->pv_desc.dtvd_name, name, i + 1,
298*0Sstevel@tonic-gate 			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 			dtt.dtt_object = NULL;
301*0Sstevel@tonic-gate 			dtt.dtt_ctfp = NULL;
302*0Sstevel@tonic-gate 			dtt.dtt_type = CTF_ERR;
303*0Sstevel@tonic-gate 		} else {
304*0Sstevel@tonic-gate 			dt_node_type_assign(prp->pr_xargv[i],
305*0Sstevel@tonic-gate 			    dtt.dtt_ctfp, dtt.dtt_type);
306*0Sstevel@tonic-gate 		}
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 		prp->pr_mapping[i] = adp->dtargd_mapping;
309*0Sstevel@tonic-gate 		prp->pr_argv[i] = dtt;
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	return (prp);
313*0Sstevel@tonic-gate }
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate /*
316*0Sstevel@tonic-gate  * Lookup a probe declaration based on a known provider and full or partially
317*0Sstevel@tonic-gate  * specified module, function, and name.  If the probe is not known to us yet,
318*0Sstevel@tonic-gate  * ask dtrace(7D) to match the description and then cache any useful results.
319*0Sstevel@tonic-gate  */
320*0Sstevel@tonic-gate dt_probe_t *
321*0Sstevel@tonic-gate dt_probe_lookup(dt_provider_t *pvp, const char *s)
322*0Sstevel@tonic-gate {
323*0Sstevel@tonic-gate 	dtrace_hdl_t *dtp = pvp->pv_hdl;
324*0Sstevel@tonic-gate 	dtrace_probedesc_t pd;
325*0Sstevel@tonic-gate 	dt_ident_t *idp;
326*0Sstevel@tonic-gate 	size_t keylen;
327*0Sstevel@tonic-gate 	char *key;
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0)
330*0Sstevel@tonic-gate 		return (NULL); /* dt_errno is set for us */
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	keylen = dt_probe_keylen(&pd);
333*0Sstevel@tonic-gate 	key = dt_probe_key(&pd, alloca(keylen));
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	/*
336*0Sstevel@tonic-gate 	 * If the probe is already declared, then return the dt_probe_t from
337*0Sstevel@tonic-gate 	 * the existing identifier.  This could come from a static declaration
338*0Sstevel@tonic-gate 	 * or it could have been cached from an earlier call to this function.
339*0Sstevel@tonic-gate 	 */
340*0Sstevel@tonic-gate 	if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
341*0Sstevel@tonic-gate 		return (idp->di_data);
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	/*
344*0Sstevel@tonic-gate 	 * If the probe isn't known, use the probe description computed above
345*0Sstevel@tonic-gate 	 * to ask dtrace(7D) to find the first matching probe.
346*0Sstevel@tonic-gate 	 */
347*0Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0)
348*0Sstevel@tonic-gate 		return (dt_probe_discover(pvp, &pd));
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	if (errno == ESRCH || errno == EBADF)
351*0Sstevel@tonic-gate 		(void) dt_set_errno(dtp, EDT_NOPROBE);
352*0Sstevel@tonic-gate 	else
353*0Sstevel@tonic-gate 		(void) dt_set_errno(dtp, errno);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	return (NULL);
356*0Sstevel@tonic-gate }
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate dt_probe_t *
359*0Sstevel@tonic-gate dt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp,
360*0Sstevel@tonic-gate     dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc)
361*0Sstevel@tonic-gate {
362*0Sstevel@tonic-gate 	dt_module_t *dmp;
363*0Sstevel@tonic-gate 	dt_probe_t *prp;
364*0Sstevel@tonic-gate 	const char *p;
365*0Sstevel@tonic-gate 	uint_t i;
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	assert(idp->di_kind == DT_IDENT_PROBE);
368*0Sstevel@tonic-gate 	assert(idp->di_data == NULL);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	if (xargs == NULL) {
371*0Sstevel@tonic-gate 		xargs = nargs;
372*0Sstevel@tonic-gate 		xargc = nargc;
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL)
376*0Sstevel@tonic-gate 		return (NULL);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	prp->pr_pvp = NULL;
379*0Sstevel@tonic-gate 	prp->pr_ident = idp;
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	p = strrchr(idp->di_name, ':');
382*0Sstevel@tonic-gate 	assert(p != NULL);
383*0Sstevel@tonic-gate 	prp->pr_name = p + 1;
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	prp->pr_nargs = nargs;
386*0Sstevel@tonic-gate 	prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc);
387*0Sstevel@tonic-gate 	prp->pr_nargc = nargc;
388*0Sstevel@tonic-gate 	prp->pr_xargs = xargs;
389*0Sstevel@tonic-gate 	prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc);
390*0Sstevel@tonic-gate 	prp->pr_xargc = xargc;
391*0Sstevel@tonic-gate 	prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc);
392*0Sstevel@tonic-gate 	prp->pr_inst = NULL;
393*0Sstevel@tonic-gate 	prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc);
394*0Sstevel@tonic-gate 	prp->pr_argc = xargc;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) ||
397*0Sstevel@tonic-gate 	    (prp->pr_xargc != 0 && prp->pr_xargv == NULL) ||
398*0Sstevel@tonic-gate 	    (prp->pr_xargc != 0 && prp->pr_mapping == NULL) ||
399*0Sstevel@tonic-gate 	    (prp->pr_argc != 0 && prp->pr_argv == NULL)) {
400*0Sstevel@tonic-gate 		dt_probe_destroy(prp);
401*0Sstevel@tonic-gate 		return (NULL);
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	for (i = 0; i < xargc; i++, xargs = xargs->dn_list) {
405*0Sstevel@tonic-gate 		if (xargs->dn_string != NULL)
406*0Sstevel@tonic-gate 			prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs);
407*0Sstevel@tonic-gate 		else
408*0Sstevel@tonic-gate 			prp->pr_mapping[i] = i;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		prp->pr_xargv[i] = xargs;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 		if ((dmp = dt_module_lookup_by_ctf(dtp,
413*0Sstevel@tonic-gate 		    xargs->dn_ctfp)) != NULL)
414*0Sstevel@tonic-gate 			prp->pr_argv[i].dtt_object = dmp->dm_name;
415*0Sstevel@tonic-gate 		else
416*0Sstevel@tonic-gate 			prp->pr_argv[i].dtt_object = NULL;
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp;
419*0Sstevel@tonic-gate 		prp->pr_argv[i].dtt_type = xargs->dn_type;
420*0Sstevel@tonic-gate 	}
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	for (i = 0; i < nargc; i++, nargs = nargs->dn_list)
423*0Sstevel@tonic-gate 		prp->pr_nargv[i] = nargs;
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	idp->di_data = prp;
426*0Sstevel@tonic-gate 	return (prp);
427*0Sstevel@tonic-gate }
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate void
430*0Sstevel@tonic-gate dt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp)
431*0Sstevel@tonic-gate {
432*0Sstevel@tonic-gate 	assert(prp->pr_ident->di_kind == DT_IDENT_PROBE);
433*0Sstevel@tonic-gate 	assert(prp->pr_ident->di_data == prp);
434*0Sstevel@tonic-gate 	assert(prp->pr_pvp == NULL);
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	if (prp->pr_xargs != prp->pr_nargs)
437*0Sstevel@tonic-gate 		pvp->pv_flags &= ~DT_PROVIDER_INTF;
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	prp->pr_pvp = pvp;
440*0Sstevel@tonic-gate 	dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident);
441*0Sstevel@tonic-gate }
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate void
444*0Sstevel@tonic-gate dt_probe_destroy(dt_probe_t *prp)
445*0Sstevel@tonic-gate {
446*0Sstevel@tonic-gate 	dt_probe_instance_t *pip, *pip_next;
447*0Sstevel@tonic-gate 	dtrace_hdl_t *dtp;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	if (prp->pr_pvp != NULL)
450*0Sstevel@tonic-gate 		dtp = prp->pr_pvp->pv_hdl;
451*0Sstevel@tonic-gate 	else
452*0Sstevel@tonic-gate 		dtp = yypcb->pcb_hdl;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	dt_node_list_free(&prp->pr_nargs);
455*0Sstevel@tonic-gate 	dt_node_list_free(&prp->pr_xargs);
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	dt_free(dtp, prp->pr_nargv);
458*0Sstevel@tonic-gate 	dt_free(dtp, prp->pr_xargv);
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	for (pip = prp->pr_inst; pip != NULL; pip = pip_next) {
461*0Sstevel@tonic-gate 		pip_next = pip->pi_next;
462*0Sstevel@tonic-gate 		dt_free(dtp, pip->pi_offs);
463*0Sstevel@tonic-gate 		dt_free(dtp, pip);
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	dt_free(dtp, prp->pr_mapping);
467*0Sstevel@tonic-gate 	dt_free(dtp, prp->pr_argv);
468*0Sstevel@tonic-gate 	dt_free(dtp, prp);
469*0Sstevel@tonic-gate }
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate int
472*0Sstevel@tonic-gate dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
473*0Sstevel@tonic-gate     const char *fname, uint32_t offset)
474*0Sstevel@tonic-gate {
475*0Sstevel@tonic-gate 	dtrace_hdl_t *dtp = pvp->pv_hdl;
476*0Sstevel@tonic-gate 	dt_probe_instance_t *pip;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
479*0Sstevel@tonic-gate 		if (strcmp(pip->pi_fname, fname) == 0)
480*0Sstevel@tonic-gate 			break;
481*0Sstevel@tonic-gate 	}
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	if (pip == NULL) {
484*0Sstevel@tonic-gate 		if ((pip = dt_alloc(dtp, sizeof (*pip))) == NULL ||
485*0Sstevel@tonic-gate 		    (pip->pi_offs = dt_alloc(dtp, sizeof (uint32_t))) == NULL) {
486*0Sstevel@tonic-gate 			dt_free(dtp, pip);
487*0Sstevel@tonic-gate 			return (-1);
488*0Sstevel@tonic-gate 		}
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		(void) strlcpy(pip->pi_fname, fname, sizeof (pip->pi_fname));
491*0Sstevel@tonic-gate 		pip->pi_noffs = 0;
492*0Sstevel@tonic-gate 		pip->pi_maxoffs = 1;
493*0Sstevel@tonic-gate 		pip->pi_next = prp->pr_inst;
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		prp->pr_inst = pip;
496*0Sstevel@tonic-gate 	}
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 	if (pip->pi_noffs == pip->pi_maxoffs) {
499*0Sstevel@tonic-gate 		uint_t new_max = pip->pi_maxoffs * 2;
500*0Sstevel@tonic-gate 		uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max);
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 		if (new_offs == NULL)
503*0Sstevel@tonic-gate 			return (-1);
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 		bcopy(pip->pi_offs, new_offs,
506*0Sstevel@tonic-gate 		    sizeof (uint32_t) * pip->pi_maxoffs);
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 		dt_free(dtp, pip->pi_offs);
509*0Sstevel@tonic-gate 		pip->pi_maxoffs = new_max;
510*0Sstevel@tonic-gate 		pip->pi_offs = new_offs;
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 	dt_dprintf("defined probe %s:%s %s() +0x%x\n",
514*0Sstevel@tonic-gate 	    pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset);
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	assert(pip->pi_noffs < pip->pi_maxoffs);
517*0Sstevel@tonic-gate 	pip->pi_offs[pip->pi_noffs++] = offset;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	return (0);
520*0Sstevel@tonic-gate }
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate /*ARGSUSED*/
523*0Sstevel@tonic-gate static int
524*0Sstevel@tonic-gate dt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
525*0Sstevel@tonic-gate {
526*0Sstevel@tonic-gate 	if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) {
527*0Sstevel@tonic-gate 		bcopy(pdp, arg, sizeof (dtrace_probedesc_t));
528*0Sstevel@tonic-gate 		return (0);
529*0Sstevel@tonic-gate 	}
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	return (1);
532*0Sstevel@tonic-gate }
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate dt_probe_t *
535*0Sstevel@tonic-gate dt_probe_info(dtrace_hdl_t *dtp,
536*0Sstevel@tonic-gate     const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
537*0Sstevel@tonic-gate {
538*0Sstevel@tonic-gate 	int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod);
539*0Sstevel@tonic-gate 	int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func);
540*0Sstevel@tonic-gate 	int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name);
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	dt_probe_t *prp = NULL;
543*0Sstevel@tonic-gate 	const dtrace_pattr_t *pap;
544*0Sstevel@tonic-gate 	dt_provider_t *pvp;
545*0Sstevel@tonic-gate 	dt_ident_t *idp;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	/*
548*0Sstevel@tonic-gate 	 * Attempt to lookup the probe in our existing cache for this provider.
549*0Sstevel@tonic-gate 	 * If none is found and an explicit probe ID was specified, discover
550*0Sstevel@tonic-gate 	 * that specific probe and cache its description and arguments.
551*0Sstevel@tonic-gate 	 */
552*0Sstevel@tonic-gate 	if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) {
553*0Sstevel@tonic-gate 		size_t keylen = dt_probe_keylen(pdp);
554*0Sstevel@tonic-gate 		char *key = dt_probe_key(pdp, alloca(keylen));
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 		if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
557*0Sstevel@tonic-gate 			prp = idp->di_data;
558*0Sstevel@tonic-gate 		else if (pdp->dtpd_id != DTRACE_IDNONE)
559*0Sstevel@tonic-gate 			prp = dt_probe_discover(pvp, pdp);
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	/*
563*0Sstevel@tonic-gate 	 * If no probe was found in our cache, convert the caller's partial
564*0Sstevel@tonic-gate 	 * probe description into a fully-formed matching probe description by
565*0Sstevel@tonic-gate 	 * iterating over up to at most two probes that match 'pdp'.  We then
566*0Sstevel@tonic-gate 	 * call dt_probe_discover() on the resulting probe identifier.
567*0Sstevel@tonic-gate 	 */
568*0Sstevel@tonic-gate 	if (prp == NULL) {
569*0Sstevel@tonic-gate 		dtrace_probedesc_t pd;
570*0Sstevel@tonic-gate 		int m;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 		bzero(&pd, sizeof (pd));
573*0Sstevel@tonic-gate 		pd.dtpd_id = DTRACE_IDNONE;
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 		/*
576*0Sstevel@tonic-gate 		 * Call dtrace_probe_iter() to find matching probes.  Our
577*0Sstevel@tonic-gate 		 * dt_probe_desc() callback will produce the following results:
578*0Sstevel@tonic-gate 		 *
579*0Sstevel@tonic-gate 		 * m < 0 dtrace_probe_iter() found zero matches (or failed).
580*0Sstevel@tonic-gate 		 * m > 0 dtrace_probe_iter() found more than one match.
581*0Sstevel@tonic-gate 		 * m = 0 dtrace_probe_iter() found exactly one match.
582*0Sstevel@tonic-gate 		 */
583*0Sstevel@tonic-gate 		if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0)
584*0Sstevel@tonic-gate 			return (NULL); /* dt_errno is set for us */
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 		if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL)
587*0Sstevel@tonic-gate 			return (NULL); /* dt_errno is set for us */
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		/*
590*0Sstevel@tonic-gate 		 * If more than one probe was matched, then do not report probe
591*0Sstevel@tonic-gate 		 * information if either of the following conditions is true:
592*0Sstevel@tonic-gate 		 *
593*0Sstevel@tonic-gate 		 * (a) The Arguments Data stability of the matched provider is
594*0Sstevel@tonic-gate 		 *	less than Evolving.
595*0Sstevel@tonic-gate 		 *
596*0Sstevel@tonic-gate 		 * (b) Any description component that is at least Evolving is
597*0Sstevel@tonic-gate 		 *	empty or is specified using a globbing expression.
598*0Sstevel@tonic-gate 		 *
599*0Sstevel@tonic-gate 		 * These conditions imply that providers that provide Evolving
600*0Sstevel@tonic-gate 		 * or better Arguments Data stability must guarantee that all
601*0Sstevel@tonic-gate 		 * probes with identical field names in a field of Evolving or
602*0Sstevel@tonic-gate 		 * better Name stability have identical argument signatures.
603*0Sstevel@tonic-gate 		 */
604*0Sstevel@tonic-gate 		if (m > 0) {
605*0Sstevel@tonic-gate 			if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data <
606*0Sstevel@tonic-gate 			    DTRACE_STABILITY_EVOLVING) {
607*0Sstevel@tonic-gate 				(void) dt_set_errno(dtp, EDT_UNSTABLE);
608*0Sstevel@tonic-gate 				return (NULL);
609*0Sstevel@tonic-gate 			}
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 			if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >=
613*0Sstevel@tonic-gate 			    DTRACE_STABILITY_EVOLVING && m_is_glob) {
614*0Sstevel@tonic-gate 				(void) dt_set_errno(dtp, EDT_UNSTABLE);
615*0Sstevel@tonic-gate 				return (NULL);
616*0Sstevel@tonic-gate 			}
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 			if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >=
619*0Sstevel@tonic-gate 			    DTRACE_STABILITY_EVOLVING && f_is_glob) {
620*0Sstevel@tonic-gate 				(void) dt_set_errno(dtp, EDT_UNSTABLE);
621*0Sstevel@tonic-gate 				return (NULL);
622*0Sstevel@tonic-gate 			}
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 			if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >=
625*0Sstevel@tonic-gate 			    DTRACE_STABILITY_EVOLVING && n_is_glob) {
626*0Sstevel@tonic-gate 				(void) dt_set_errno(dtp, EDT_UNSTABLE);
627*0Sstevel@tonic-gate 				return (NULL);
628*0Sstevel@tonic-gate 			}
629*0Sstevel@tonic-gate 		}
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 		if ((prp = dt_probe_discover(pvp, &pd)) == NULL)
632*0Sstevel@tonic-gate 			return (NULL); /* dt_errno is set for us */
633*0Sstevel@tonic-gate 	}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 	assert(pvp != NULL && prp != NULL);
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	/*
638*0Sstevel@tonic-gate 	 * Compute the probe description attributes by taking the minimum of
639*0Sstevel@tonic-gate 	 * the attributes of the specified fields.  If no provider is specified
640*0Sstevel@tonic-gate 	 * or a glob pattern is used for the provider, use Unstable attributes.
641*0Sstevel@tonic-gate 	 */
642*0Sstevel@tonic-gate 	if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider))
643*0Sstevel@tonic-gate 		pap = &_dtrace_prvdesc;
644*0Sstevel@tonic-gate 	else
645*0Sstevel@tonic-gate 		pap = &pvp->pv_desc.dtvd_attr;
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	pip->dtp_attr = pap->dtpa_provider;
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	if (!m_is_glob)
650*0Sstevel@tonic-gate 		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod);
651*0Sstevel@tonic-gate 	if (!f_is_glob)
652*0Sstevel@tonic-gate 		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func);
653*0Sstevel@tonic-gate 	if (!n_is_glob)
654*0Sstevel@tonic-gate 		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name);
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 	pip->dtp_arga = pap->dtpa_args;
657*0Sstevel@tonic-gate 	pip->dtp_argv = prp->pr_argv;
658*0Sstevel@tonic-gate 	pip->dtp_argc = prp->pr_argc;
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	return (prp);
661*0Sstevel@tonic-gate }
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate int
664*0Sstevel@tonic-gate dtrace_probe_info(dtrace_hdl_t *dtp,
665*0Sstevel@tonic-gate     const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
666*0Sstevel@tonic-gate {
667*0Sstevel@tonic-gate 	return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1);
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate /*ARGSUSED*/
671*0Sstevel@tonic-gate static int
672*0Sstevel@tonic-gate dt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit)
673*0Sstevel@tonic-gate {
674*0Sstevel@tonic-gate 	const dt_probe_t *prp = idp->di_data;
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	if (!dt_gmatch(prp->pr_name, pit->pit_pat))
677*0Sstevel@tonic-gate 		return (0); /* continue on and examine next probe in hash */
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	(void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN);
680*0Sstevel@tonic-gate 	pit->pit_desc.dtpd_id = idp->di_id;
681*0Sstevel@tonic-gate 	pit->pit_matches++;
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg));
684*0Sstevel@tonic-gate }
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate int
687*0Sstevel@tonic-gate dtrace_probe_iter(dtrace_hdl_t *dtp,
688*0Sstevel@tonic-gate     const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg)
689*0Sstevel@tonic-gate {
690*0Sstevel@tonic-gate 	const char *provider = pdp ? pdp->dtpd_provider : NULL;
691*0Sstevel@tonic-gate 	dtrace_id_t id = DTRACE_IDNONE;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	dtrace_probedesc_t pd;
694*0Sstevel@tonic-gate 	dt_probe_iter_t pit;
695*0Sstevel@tonic-gate 	int cmd, rv;
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	bzero(&pit, sizeof (pit));
698*0Sstevel@tonic-gate 	pit.pit_hdl = dtp;
699*0Sstevel@tonic-gate 	pit.pit_func = func;
700*0Sstevel@tonic-gate 	pit.pit_arg = arg;
701*0Sstevel@tonic-gate 	pit.pit_pat = pdp ? pdp->dtpd_name : NULL;
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist);
704*0Sstevel@tonic-gate 	    pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) {
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 		if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL)
707*0Sstevel@tonic-gate 			continue; /* we'll get these later using dt_ioctl() */
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider))
710*0Sstevel@tonic-gate 			continue;
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 		(void) strlcpy(pit.pit_desc.dtpd_provider,
713*0Sstevel@tonic-gate 		    pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN);
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate 		if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes,
716*0Sstevel@tonic-gate 		    (dt_idhash_f *)dt_probe_iter, &pit)) != 0)
717*0Sstevel@tonic-gate 			return (rv);
718*0Sstevel@tonic-gate 	}
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	if (pdp != NULL)
721*0Sstevel@tonic-gate 		cmd = DTRACEIOC_PROBEMATCH;
722*0Sstevel@tonic-gate 	else
723*0Sstevel@tonic-gate 		cmd = DTRACEIOC_PROBES;
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 	for (;;) {
726*0Sstevel@tonic-gate 		if (pdp != NULL)
727*0Sstevel@tonic-gate 			bcopy(pdp, &pd, sizeof (pd));
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 		pd.dtpd_id = id;
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 		if (dt_ioctl(dtp, cmd, &pd) != 0)
732*0Sstevel@tonic-gate 			break;
733*0Sstevel@tonic-gate 		else if ((rv = func(dtp, &pd, arg)) != 0)
734*0Sstevel@tonic-gate 			return (rv);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 		pit.pit_matches++;
737*0Sstevel@tonic-gate 		id = pd.dtpd_id + 1;
738*0Sstevel@tonic-gate 	}
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	switch (errno) {
741*0Sstevel@tonic-gate 	case ESRCH:
742*0Sstevel@tonic-gate 	case EBADF:
743*0Sstevel@tonic-gate 		return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE));
744*0Sstevel@tonic-gate 	case EINVAL:
745*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADPGLOB));
746*0Sstevel@tonic-gate 	default:
747*0Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
748*0Sstevel@tonic-gate 	}
749*0Sstevel@tonic-gate }
750