1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21178479Sjb
22178479Sjb/*
23178479Sjb * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24178479Sjb * Use is subject to license terms.
25178479Sjb */
26268578Srpaulo/*
27268578Srpaulo * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
28268578Srpaulo */
29178479Sjb
30178479Sjb#include <sys/types.h>
31178557Sjb#if defined(sun)
32178479Sjb#include <sys/sysmacros.h>
33178557Sjb#endif
34178479Sjb
35178479Sjb#include <assert.h>
36178479Sjb#include <limits.h>
37178479Sjb#include <strings.h>
38178479Sjb#include <stdlib.h>
39178557Sjb#if defined(sun)
40178479Sjb#include <alloca.h>
41178557Sjb#endif
42178479Sjb#include <unistd.h>
43178479Sjb#include <errno.h>
44178479Sjb
45178479Sjb#include <dt_provider.h>
46178479Sjb#include <dt_module.h>
47178479Sjb#include <dt_string.h>
48178479Sjb#include <dt_list.h>
49268578Srpaulo#include <dt_pid.h>
50268578Srpaulo#include <dtrace.h>
51178479Sjb
52178479Sjbstatic dt_provider_t *
53178479Sjbdt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h)
54178479Sjb{
55178479Sjb	dt_list_append(&dtp->dt_provlist, pvp);
56178479Sjb
57178479Sjb	pvp->pv_next = dtp->dt_provs[h];
58178479Sjb	dtp->dt_provs[h] = pvp;
59178479Sjb	dtp->dt_nprovs++;
60178479Sjb
61178479Sjb	return (pvp);
62178479Sjb}
63178479Sjb
64178479Sjbdt_provider_t *
65178479Sjbdt_provider_lookup(dtrace_hdl_t *dtp, const char *name)
66178479Sjb{
67178479Sjb	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets;
68178479Sjb	dtrace_providerdesc_t desc;
69178479Sjb	dt_provider_t *pvp;
70178479Sjb
71178479Sjb	for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) {
72178479Sjb		if (strcmp(pvp->pv_desc.dtvd_name, name) == 0)
73178479Sjb			return (pvp);
74178479Sjb	}
75178479Sjb
76178479Sjb	if (strisglob(name) || name[0] == '\0') {
77178479Sjb		(void) dt_set_errno(dtp, EDT_NOPROV);
78178479Sjb		return (NULL);
79178479Sjb	}
80178479Sjb
81178479Sjb	bzero(&desc, sizeof (desc));
82178479Sjb	(void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN);
83178479Sjb
84178479Sjb	if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) {
85178479Sjb		(void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno);
86178479Sjb		return (NULL);
87178479Sjb	}
88178479Sjb
89178479Sjb	if ((pvp = dt_provider_create(dtp, name)) == NULL)
90178479Sjb		return (NULL); /* dt_errno is set for us */
91178479Sjb
92178479Sjb	bcopy(&desc, &pvp->pv_desc, sizeof (desc));
93178479Sjb	pvp->pv_flags |= DT_PROVIDER_IMPL;
94178479Sjb	return (pvp);
95178479Sjb}
96178479Sjb
97178479Sjbdt_provider_t *
98178479Sjbdt_provider_create(dtrace_hdl_t *dtp, const char *name)
99178479Sjb{
100178479Sjb	dt_provider_t *pvp;
101178479Sjb
102178479Sjb	if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL)
103178479Sjb		return (NULL);
104178479Sjb
105178479Sjb	(void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN);
106178479Sjb	pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0);
107178479Sjb	pvp->pv_gen = dtp->dt_gen;
108178479Sjb	pvp->pv_hdl = dtp;
109178479Sjb
110178479Sjb	if (pvp->pv_probes == NULL) {
111178479Sjb		dt_free(dtp, pvp);
112178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
113178479Sjb		return (NULL);
114178479Sjb	}
115178479Sjb
116178479Sjb	pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr;
117178479Sjb	pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr;
118178479Sjb	pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr;
119178479Sjb	pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr;
120178479Sjb	pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr;
121178479Sjb
122178479Sjb	return (dt_provider_insert(dtp, pvp,
123178479Sjb	    dt_strtab_hash(name, NULL) % dtp->dt_provbuckets));
124178479Sjb}
125178479Sjb
126178479Sjbvoid
127178479Sjbdt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp)
128178479Sjb{
129178479Sjb	dt_provider_t **pp;
130178479Sjb	uint_t h;
131178479Sjb
132178479Sjb	assert(pvp->pv_hdl == dtp);
133178479Sjb
134178479Sjb	h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets;
135178479Sjb	pp = &dtp->dt_provs[h];
136178479Sjb
137178479Sjb	while (*pp != NULL && *pp != pvp)
138178479Sjb		pp = &(*pp)->pv_next;
139178479Sjb
140178479Sjb	assert(*pp != NULL && *pp == pvp);
141178479Sjb	*pp = pvp->pv_next;
142178479Sjb
143178479Sjb	dt_list_delete(&dtp->dt_provlist, pvp);
144178479Sjb	dtp->dt_nprovs--;
145178479Sjb
146178479Sjb	if (pvp->pv_probes != NULL)
147178479Sjb		dt_idhash_destroy(pvp->pv_probes);
148178479Sjb
149178479Sjb	dt_node_link_free(&pvp->pv_nodes);
150178479Sjb	dt_free(dtp, pvp->pv_xrefs);
151178479Sjb	dt_free(dtp, pvp);
152178479Sjb}
153178479Sjb
154178479Sjbint
155178479Sjbdt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id)
156178479Sjb{
157178479Sjb	size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax);
158178479Sjb	size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid);
159178479Sjb
160178479Sjb	assert(id >= 0 && id < dtp->dt_xlatorid);
161178479Sjb
162178479Sjb	if (newsize > oldsize) {
163178479Sjb		ulong_t *xrefs = dt_zalloc(dtp, newsize);
164178479Sjb
165178479Sjb		if (xrefs == NULL)
166178479Sjb			return (-1);
167178479Sjb
168178479Sjb		bcopy(pvp->pv_xrefs, xrefs, oldsize);
169178479Sjb		dt_free(dtp, pvp->pv_xrefs);
170178479Sjb
171178479Sjb		pvp->pv_xrefs = xrefs;
172178479Sjb		pvp->pv_xrmax = dtp->dt_xlatorid;
173178479Sjb	}
174178479Sjb
175178479Sjb	BT_SET(pvp->pv_xrefs, id);
176178479Sjb	return (0);
177178479Sjb}
178178479Sjb
179178479Sjbstatic uint8_t
180178479Sjbdt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp)
181178479Sjb{
182178479Sjb	uint8_t i;
183178479Sjb
184178479Sjb	for (i = 0; nnp != NULL; i++) {
185178479Sjb		if (nnp->dn_string != NULL &&
186178479Sjb		    strcmp(nnp->dn_string, xnp->dn_string) == 0)
187178479Sjb			break;
188178479Sjb		else
189178479Sjb			nnp = nnp->dn_list;
190178479Sjb	}
191178479Sjb
192178479Sjb	return (i);
193178479Sjb}
194178479Sjb
195178479Sjbstatic dt_node_t *
196178479Sjbdt_probe_alloc_args(dt_provider_t *pvp, int argc)
197178479Sjb{
198178479Sjb	dt_node_t *args = NULL, *pnp = NULL, *dnp;
199178479Sjb	int i;
200178479Sjb
201178479Sjb	for (i = 0; i < argc; i++, pnp = dnp) {
202178479Sjb		if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL)
203178479Sjb			return (NULL);
204178479Sjb
205178479Sjb		dnp->dn_link = pvp->pv_nodes;
206178479Sjb		pvp->pv_nodes = dnp;
207178479Sjb
208178479Sjb		if (args == NULL)
209178479Sjb			args = dnp;
210178479Sjb		else
211178479Sjb			pnp->dn_list = dnp;
212178479Sjb	}
213178479Sjb
214178479Sjb	return (args);
215178479Sjb}
216178479Sjb
217178479Sjbstatic size_t
218178479Sjbdt_probe_keylen(const dtrace_probedesc_t *pdp)
219178479Sjb{
220178479Sjb	return (strlen(pdp->dtpd_mod) + 1 +
221178479Sjb	    strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1);
222178479Sjb}
223178479Sjb
224178479Sjbstatic char *
225178479Sjbdt_probe_key(const dtrace_probedesc_t *pdp, char *s)
226178479Sjb{
227178479Sjb	(void) snprintf(s, INT_MAX, "%s:%s:%s",
228178479Sjb	    pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
229178479Sjb	return (s);
230178479Sjb}
231178479Sjb
232178479Sjb/*
233178479Sjb * If a probe was discovered from the kernel, ask dtrace(7D) for a description
234178479Sjb * of each of its arguments, including native and translated types.
235178479Sjb */
236178479Sjbstatic dt_probe_t *
237178479Sjbdt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
238178479Sjb{
239178479Sjb	dtrace_hdl_t *dtp = pvp->pv_hdl;
240178479Sjb	char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp)));
241178479Sjb
242178479Sjb	dt_node_t *xargs, *nargs;
243178479Sjb	dt_ident_t *idp;
244178479Sjb	dt_probe_t *prp;
245178479Sjb
246178479Sjb	dtrace_typeinfo_t dtt;
247178479Sjb	int i, nc, xc;
248178479Sjb
249178479Sjb	int adc = _dtrace_argmax;
250178479Sjb	dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc);
251178479Sjb	dtrace_argdesc_t *adp = adv;
252178479Sjb
253178479Sjb	assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0);
254178479Sjb	assert(pdp->dtpd_id != DTRACE_IDNONE);
255178479Sjb
256178479Sjb	dt_dprintf("discovering probe %s:%s id=%d\n",
257178479Sjb	    pvp->pv_desc.dtvd_name, name, pdp->dtpd_id);
258178479Sjb
259178479Sjb	for (nc = -1, i = 0; i < adc; i++, adp++) {
260178479Sjb		bzero(adp, sizeof (dtrace_argdesc_t));
261178479Sjb		adp->dtargd_ndx = i;
262178479Sjb		adp->dtargd_id = pdp->dtpd_id;
263178479Sjb
264178479Sjb		if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) {
265178479Sjb			(void) dt_set_errno(dtp, errno);
266178479Sjb			return (NULL);
267178479Sjb		}
268178479Sjb
269178479Sjb		if (adp->dtargd_ndx == DTRACE_ARGNONE)
270178479Sjb			break; /* all argument descs have been retrieved */
271178479Sjb
272178479Sjb		nc = MAX(nc, adp->dtargd_mapping);
273178479Sjb	}
274178479Sjb
275178479Sjb	xc = i;
276178479Sjb	nc++;
277178479Sjb
278178479Sjb	/*
279268578Srpaulo	 * The pid provider believes in giving the kernel a break. No reason to
280268578Srpaulo	 * give the kernel all the ctf containers that we're keeping ourselves
281268578Srpaulo	 * just to get it back from it. So if we're coming from a pid provider
282268578Srpaulo	 * probe and the kernel gave us no argument information we'll get some
283268578Srpaulo	 * here. If for some crazy reason the kernel knows about our userland
284268578Srpaulo	 * types then we just ignore this.
285268578Srpaulo	 */
286268578Srpaulo	if (xc == 0 && nc == 0 &&
287268578Srpaulo	    strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) {
288268578Srpaulo		nc = adc;
289268578Srpaulo		dt_pid_get_types(dtp, pdp, adv, &nc);
290268578Srpaulo		xc = nc;
291268578Srpaulo	}
292268578Srpaulo
293268578Srpaulo	/*
294178479Sjb	 * Now that we have discovered the number of native and translated
295178479Sjb	 * arguments from the argument descriptions, allocate a new probe ident
296178479Sjb	 * and corresponding dt_probe_t and hash it into the provider.
297178479Sjb	 */
298178479Sjb	xargs = dt_probe_alloc_args(pvp, xc);
299178479Sjb	nargs = dt_probe_alloc_args(pvp, nc);
300178479Sjb
301178479Sjb	if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL))
302178479Sjb		return (NULL); /* dt_errno is set for us */
303178479Sjb
304178479Sjb	idp = dt_ident_create(name, DT_IDENT_PROBE,
305178479Sjb	    DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0,
306178479Sjb	    &dt_idops_probe, NULL, dtp->dt_gen);
307178479Sjb
308178479Sjb	if (idp == NULL) {
309178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
310178479Sjb		return (NULL);
311178479Sjb	}
312178479Sjb
313178479Sjb	if ((prp = dt_probe_create(dtp, idp, 2,
314178479Sjb	    nargs, nc, xargs, xc)) == NULL) {
315178479Sjb		dt_ident_destroy(idp);
316178479Sjb		return (NULL);
317178479Sjb	}
318178479Sjb
319178479Sjb	dt_probe_declare(pvp, prp);
320178479Sjb
321178479Sjb	/*
322178479Sjb	 * Once our new dt_probe_t is fully constructed, iterate over the
323178479Sjb	 * cached argument descriptions and assign types to prp->pr_nargv[]
324178479Sjb	 * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[].
325178479Sjb	 */
326178479Sjb	for (adp = adv, i = 0; i < xc; i++, adp++) {
327178479Sjb		if (dtrace_type_strcompile(dtp,
328178479Sjb		    adp->dtargd_native, &dtt) != 0) {
329178479Sjb			dt_dprintf("failed to resolve input type %s "
330178479Sjb			    "for %s:%s arg #%d: %s\n", adp->dtargd_native,
331178479Sjb			    pvp->pv_desc.dtvd_name, name, i + 1,
332178479Sjb			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
333178479Sjb
334178479Sjb			dtt.dtt_object = NULL;
335178479Sjb			dtt.dtt_ctfp = NULL;
336178479Sjb			dtt.dtt_type = CTF_ERR;
337178479Sjb		} else {
338178479Sjb			dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
339268578Srpaulo			    dtt.dtt_ctfp, dtt.dtt_type,
340268578Srpaulo			    dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE);
341178479Sjb		}
342178479Sjb
343178479Sjb		if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
344178479Sjb		    strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) {
345178479Sjb			dt_node_type_propagate(prp->pr_nargv[
346178479Sjb			    adp->dtargd_mapping], prp->pr_xargv[i]);
347178479Sjb		} else if (dtrace_type_strcompile(dtp,
348178479Sjb		    adp->dtargd_xlate, &dtt) != 0) {
349178479Sjb			dt_dprintf("failed to resolve output type %s "
350178479Sjb			    "for %s:%s arg #%d: %s\n", adp->dtargd_xlate,
351178479Sjb			    pvp->pv_desc.dtvd_name, name, i + 1,
352178479Sjb			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
353178479Sjb
354178479Sjb			dtt.dtt_object = NULL;
355178479Sjb			dtt.dtt_ctfp = NULL;
356178479Sjb			dtt.dtt_type = CTF_ERR;
357178479Sjb		} else {
358178479Sjb			dt_node_type_assign(prp->pr_xargv[i],
359268578Srpaulo			    dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
360178479Sjb		}
361178479Sjb
362178479Sjb		prp->pr_mapping[i] = adp->dtargd_mapping;
363178479Sjb		prp->pr_argv[i] = dtt;
364178479Sjb	}
365178479Sjb
366178479Sjb	return (prp);
367178479Sjb}
368178479Sjb
369178479Sjb/*
370178479Sjb * Lookup a probe declaration based on a known provider and full or partially
371178479Sjb * specified module, function, and name.  If the probe is not known to us yet,
372178479Sjb * ask dtrace(7D) to match the description and then cache any useful results.
373178479Sjb */
374178479Sjbdt_probe_t *
375178479Sjbdt_probe_lookup(dt_provider_t *pvp, const char *s)
376178479Sjb{
377178479Sjb	dtrace_hdl_t *dtp = pvp->pv_hdl;
378178479Sjb	dtrace_probedesc_t pd;
379178479Sjb	dt_ident_t *idp;
380178479Sjb	size_t keylen;
381178479Sjb	char *key;
382178479Sjb
383178479Sjb	if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0)
384178479Sjb		return (NULL); /* dt_errno is set for us */
385178479Sjb
386178479Sjb	keylen = dt_probe_keylen(&pd);
387178479Sjb	key = dt_probe_key(&pd, alloca(keylen));
388178479Sjb
389178479Sjb	/*
390178479Sjb	 * If the probe is already declared, then return the dt_probe_t from
391178479Sjb	 * the existing identifier.  This could come from a static declaration
392178479Sjb	 * or it could have been cached from an earlier call to this function.
393178479Sjb	 */
394178479Sjb	if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
395178479Sjb		return (idp->di_data);
396178479Sjb
397178479Sjb	/*
398178479Sjb	 * If the probe isn't known, use the probe description computed above
399178479Sjb	 * to ask dtrace(7D) to find the first matching probe.
400178479Sjb	 */
401178479Sjb	if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0)
402178479Sjb		return (dt_probe_discover(pvp, &pd));
403178479Sjb
404178479Sjb	if (errno == ESRCH || errno == EBADF)
405178479Sjb		(void) dt_set_errno(dtp, EDT_NOPROBE);
406178479Sjb	else
407178479Sjb		(void) dt_set_errno(dtp, errno);
408178479Sjb
409178479Sjb	return (NULL);
410178479Sjb}
411178479Sjb
412178479Sjbdt_probe_t *
413178479Sjbdt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp, int protoc,
414178479Sjb    dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc)
415178479Sjb{
416178479Sjb	dt_module_t *dmp;
417178479Sjb	dt_probe_t *prp;
418178479Sjb	const char *p;
419178479Sjb	uint_t i;
420178479Sjb
421178479Sjb	assert(idp->di_kind == DT_IDENT_PROBE);
422178479Sjb	assert(idp->di_data == NULL);
423178479Sjb
424178479Sjb	/*
425178479Sjb	 * If only a single prototype is given, set xargc/s to nargc/s to
426178479Sjb	 * simplify subsequent use.  Note that we can have one or both of nargs
427178479Sjb	 * and xargs be specified but set to NULL, indicating a void prototype.
428178479Sjb	 */
429178479Sjb	if (protoc < 2) {
430178479Sjb		assert(xargs == NULL);
431178479Sjb		assert(xargc == 0);
432178479Sjb		xargs = nargs;
433178479Sjb		xargc = nargc;
434178479Sjb	}
435178479Sjb
436178479Sjb	if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL)
437178479Sjb		return (NULL);
438178479Sjb
439178479Sjb	prp->pr_pvp = NULL;
440178479Sjb	prp->pr_ident = idp;
441178479Sjb
442178479Sjb	p = strrchr(idp->di_name, ':');
443178479Sjb	assert(p != NULL);
444178479Sjb	prp->pr_name = p + 1;
445178479Sjb
446178479Sjb	prp->pr_nargs = nargs;
447178479Sjb	prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc);
448178479Sjb	prp->pr_nargc = nargc;
449178479Sjb	prp->pr_xargs = xargs;
450178479Sjb	prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc);
451178479Sjb	prp->pr_xargc = xargc;
452178479Sjb	prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc);
453178479Sjb	prp->pr_inst = NULL;
454178479Sjb	prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc);
455178479Sjb	prp->pr_argc = xargc;
456178479Sjb
457178479Sjb	if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) ||
458178479Sjb	    (prp->pr_xargc != 0 && prp->pr_xargv == NULL) ||
459178479Sjb	    (prp->pr_xargc != 0 && prp->pr_mapping == NULL) ||
460178479Sjb	    (prp->pr_argc != 0 && prp->pr_argv == NULL)) {
461178479Sjb		dt_probe_destroy(prp);
462178479Sjb		return (NULL);
463178479Sjb	}
464178479Sjb
465178479Sjb	for (i = 0; i < xargc; i++, xargs = xargs->dn_list) {
466178479Sjb		if (xargs->dn_string != NULL)
467178479Sjb			prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs);
468178479Sjb		else
469178479Sjb			prp->pr_mapping[i] = i;
470178479Sjb
471178479Sjb		prp->pr_xargv[i] = xargs;
472178479Sjb
473178479Sjb		if ((dmp = dt_module_lookup_by_ctf(dtp,
474178479Sjb		    xargs->dn_ctfp)) != NULL)
475178479Sjb			prp->pr_argv[i].dtt_object = dmp->dm_name;
476178479Sjb		else
477178479Sjb			prp->pr_argv[i].dtt_object = NULL;
478178479Sjb
479178479Sjb		prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp;
480178479Sjb		prp->pr_argv[i].dtt_type = xargs->dn_type;
481178479Sjb	}
482178479Sjb
483178479Sjb	for (i = 0; i < nargc; i++, nargs = nargs->dn_list)
484178479Sjb		prp->pr_nargv[i] = nargs;
485178479Sjb
486178479Sjb	idp->di_data = prp;
487178479Sjb	return (prp);
488178479Sjb}
489178479Sjb
490178479Sjbvoid
491178479Sjbdt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp)
492178479Sjb{
493178479Sjb	assert(prp->pr_ident->di_kind == DT_IDENT_PROBE);
494178479Sjb	assert(prp->pr_ident->di_data == prp);
495178479Sjb	assert(prp->pr_pvp == NULL);
496178479Sjb
497178479Sjb	if (prp->pr_xargs != prp->pr_nargs)
498178479Sjb		pvp->pv_flags &= ~DT_PROVIDER_INTF;
499178479Sjb
500178479Sjb	prp->pr_pvp = pvp;
501178479Sjb	dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident);
502178479Sjb}
503178479Sjb
504178479Sjbvoid
505178479Sjbdt_probe_destroy(dt_probe_t *prp)
506178479Sjb{
507178479Sjb	dt_probe_instance_t *pip, *pip_next;
508178479Sjb	dtrace_hdl_t *dtp;
509178479Sjb
510178479Sjb	if (prp->pr_pvp != NULL)
511178479Sjb		dtp = prp->pr_pvp->pv_hdl;
512178479Sjb	else
513178479Sjb		dtp = yypcb->pcb_hdl;
514178479Sjb
515178479Sjb	dt_node_list_free(&prp->pr_nargs);
516178479Sjb	dt_node_list_free(&prp->pr_xargs);
517178479Sjb
518178479Sjb	dt_free(dtp, prp->pr_nargv);
519178479Sjb	dt_free(dtp, prp->pr_xargv);
520178479Sjb
521178479Sjb	for (pip = prp->pr_inst; pip != NULL; pip = pip_next) {
522178479Sjb		pip_next = pip->pi_next;
523178479Sjb		dt_free(dtp, pip->pi_offs);
524178479Sjb		dt_free(dtp, pip->pi_enoffs);
525178479Sjb		dt_free(dtp, pip);
526178479Sjb	}
527178479Sjb
528178479Sjb	dt_free(dtp, prp->pr_mapping);
529178479Sjb	dt_free(dtp, prp->pr_argv);
530178479Sjb	dt_free(dtp, prp);
531178479Sjb}
532178479Sjb
533178479Sjbint
534178479Sjbdt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
535178479Sjb    const char *fname, const char *rname, uint32_t offset, int isenabled)
536178479Sjb{
537178479Sjb	dtrace_hdl_t *dtp = pvp->pv_hdl;
538178479Sjb	dt_probe_instance_t *pip;
539178479Sjb	uint32_t **offs;
540178479Sjb	uint_t *noffs, *maxoffs;
541178479Sjb
542178479Sjb	assert(fname != NULL);
543178479Sjb
544178479Sjb	for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
545178479Sjb		if (strcmp(pip->pi_fname, fname) == 0 &&
546178479Sjb		    ((rname == NULL && pip->pi_rname[0] == '\0') ||
547178479Sjb		    (rname != NULL && strcmp(pip->pi_rname, rname)) == 0))
548178479Sjb			break;
549178479Sjb	}
550178479Sjb
551178479Sjb	if (pip == NULL) {
552178479Sjb		if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL)
553178479Sjb			return (-1);
554178479Sjb
555178479Sjb		if ((pip->pi_offs = dt_zalloc(dtp,
556178479Sjb		    sizeof (uint32_t))) == NULL) {
557178479Sjb			dt_free(dtp, pip);
558178479Sjb			return (-1);
559178479Sjb		}
560178479Sjb
561178479Sjb		if ((pip->pi_enoffs = dt_zalloc(dtp,
562178479Sjb		    sizeof (uint32_t))) == NULL) {
563178479Sjb			dt_free(dtp, pip->pi_offs);
564178479Sjb			dt_free(dtp, pip);
565178479Sjb			return (-1);
566178479Sjb		}
567178479Sjb
568178479Sjb		(void) strlcpy(pip->pi_fname, fname, sizeof (pip->pi_fname));
569178479Sjb		if (rname != NULL) {
570178479Sjb			if (strlen(rname) + 1 > sizeof (pip->pi_rname)) {
571178479Sjb				dt_free(dtp, pip->pi_offs);
572178479Sjb				dt_free(dtp, pip);
573178479Sjb				return (dt_set_errno(dtp, EDT_COMPILER));
574178479Sjb			}
575178479Sjb			(void) strcpy(pip->pi_rname, rname);
576178479Sjb		}
577178479Sjb
578178479Sjb		pip->pi_noffs = 0;
579178479Sjb		pip->pi_maxoffs = 1;
580178479Sjb		pip->pi_nenoffs = 0;
581178479Sjb		pip->pi_maxenoffs = 1;
582178479Sjb
583178479Sjb		pip->pi_next = prp->pr_inst;
584178479Sjb
585178479Sjb		prp->pr_inst = pip;
586178479Sjb	}
587178479Sjb
588178479Sjb	if (isenabled) {
589178479Sjb		offs = &pip->pi_enoffs;
590178479Sjb		noffs = &pip->pi_nenoffs;
591178479Sjb		maxoffs = &pip->pi_maxenoffs;
592178479Sjb	} else {
593178479Sjb		offs = &pip->pi_offs;
594178479Sjb		noffs = &pip->pi_noffs;
595178479Sjb		maxoffs = &pip->pi_maxoffs;
596178479Sjb	}
597178479Sjb
598178479Sjb	if (*noffs == *maxoffs) {
599178479Sjb		uint_t new_max = *maxoffs * 2;
600178479Sjb		uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max);
601178479Sjb
602178479Sjb		if (new_offs == NULL)
603178479Sjb			return (-1);
604178479Sjb
605178479Sjb		bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs);
606178479Sjb
607178479Sjb		dt_free(dtp, *offs);
608178479Sjb		*maxoffs = new_max;
609178479Sjb		*offs = new_offs;
610178479Sjb	}
611178479Sjb
612178479Sjb	dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n",
613178479Sjb	    isenabled ? "(is-enabled)" : "",
614178479Sjb	    pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset,
615178479Sjb	    rname != NULL ? rname : fname);
616178479Sjb
617178479Sjb	assert(*noffs < *maxoffs);
618178479Sjb	(*offs)[(*noffs)++] = offset;
619178479Sjb
620178479Sjb	return (0);
621178479Sjb}
622178479Sjb
623178479Sjb/*
624178479Sjb * Lookup the dynamic translator type tag for the specified probe argument and
625178479Sjb * assign the type to the specified node.  If the type is not yet defined, add
626178479Sjb * it to the "D" module's type container as a typedef for an unknown type.
627178479Sjb */
628178479Sjbdt_node_t *
629178479Sjbdt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
630178479Sjb{
631178479Sjb	dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl;
632178479Sjb	dtrace_typeinfo_t dtt;
633178479Sjb	size_t len;
634178479Sjb	char *tag;
635178479Sjb
636178479Sjb	len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u",
637178479Sjb	    prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);
638178479Sjb
639178479Sjb	tag = alloca(len + 1);
640178479Sjb
641178479Sjb	(void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u",
642178479Sjb	    prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);
643178479Sjb
644178479Sjb	if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) {
645178479Sjb		dtt.dtt_object = DTRACE_OBJ_DDEFS;
646178479Sjb		dtt.dtt_ctfp = DT_DYN_CTFP(dtp);
647178479Sjb		dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp),
648178479Sjb		    CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp));
649178479Sjb
650178479Sjb		if (dtt.dtt_type == CTF_ERR ||
651178479Sjb		    ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
652178479Sjb			xyerror(D_UNKNOWN, "cannot define type %s: %s\n",
653178479Sjb			    tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
654178479Sjb		}
655178479Sjb	}
656178479Sjb
657178479Sjb	bzero(dnp, sizeof (dt_node_t));
658178479Sjb	dnp->dn_kind = DT_NODE_TYPE;
659178479Sjb
660268578Srpaulo	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
661178479Sjb	dt_node_attr_assign(dnp, _dtrace_defattr);
662178479Sjb
663178479Sjb	return (dnp);
664178479Sjb}
665178479Sjb
666178479Sjb/*ARGSUSED*/
667178479Sjbstatic int
668178479Sjbdt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
669178479Sjb{
670178479Sjb	if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) {
671178479Sjb		bcopy(pdp, arg, sizeof (dtrace_probedesc_t));
672178479Sjb		return (0);
673178479Sjb	}
674178479Sjb
675178479Sjb	return (1);
676178479Sjb}
677178479Sjb
678178479Sjbdt_probe_t *
679178479Sjbdt_probe_info(dtrace_hdl_t *dtp,
680178479Sjb    const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
681178479Sjb{
682178479Sjb	int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod);
683178479Sjb	int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func);
684178479Sjb	int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name);
685178479Sjb
686178479Sjb	dt_probe_t *prp = NULL;
687178479Sjb	const dtrace_pattr_t *pap;
688178479Sjb	dt_provider_t *pvp;
689178479Sjb	dt_ident_t *idp;
690178479Sjb
691178479Sjb	/*
692178479Sjb	 * Attempt to lookup the probe in our existing cache for this provider.
693178479Sjb	 * If none is found and an explicit probe ID was specified, discover
694178479Sjb	 * that specific probe and cache its description and arguments.
695178479Sjb	 */
696178479Sjb	if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) {
697178479Sjb		size_t keylen = dt_probe_keylen(pdp);
698178479Sjb		char *key = dt_probe_key(pdp, alloca(keylen));
699178479Sjb
700178479Sjb		if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
701178479Sjb			prp = idp->di_data;
702178479Sjb		else if (pdp->dtpd_id != DTRACE_IDNONE)
703178479Sjb			prp = dt_probe_discover(pvp, pdp);
704178479Sjb	}
705178479Sjb
706178479Sjb	/*
707178479Sjb	 * If no probe was found in our cache, convert the caller's partial
708178479Sjb	 * probe description into a fully-formed matching probe description by
709178479Sjb	 * iterating over up to at most two probes that match 'pdp'.  We then
710178479Sjb	 * call dt_probe_discover() on the resulting probe identifier.
711178479Sjb	 */
712178479Sjb	if (prp == NULL) {
713178479Sjb		dtrace_probedesc_t pd;
714178479Sjb		int m;
715178479Sjb
716178479Sjb		bzero(&pd, sizeof (pd));
717178479Sjb		pd.dtpd_id = DTRACE_IDNONE;
718178479Sjb
719178479Sjb		/*
720178479Sjb		 * Call dtrace_probe_iter() to find matching probes.  Our
721178479Sjb		 * dt_probe_desc() callback will produce the following results:
722178479Sjb		 *
723178479Sjb		 * m < 0 dtrace_probe_iter() found zero matches (or failed).
724178479Sjb		 * m > 0 dtrace_probe_iter() found more than one match.
725178479Sjb		 * m = 0 dtrace_probe_iter() found exactly one match.
726178479Sjb		 */
727178479Sjb		if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0)
728178479Sjb			return (NULL); /* dt_errno is set for us */
729178479Sjb
730178479Sjb		if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL)
731178479Sjb			return (NULL); /* dt_errno is set for us */
732178479Sjb
733178479Sjb		/*
734178479Sjb		 * If more than one probe was matched, then do not report probe
735178479Sjb		 * information if either of the following conditions is true:
736178479Sjb		 *
737178479Sjb		 * (a) The Arguments Data stability of the matched provider is
738178479Sjb		 *	less than Evolving.
739178479Sjb		 *
740178479Sjb		 * (b) Any description component that is at least Evolving is
741178479Sjb		 *	empty or is specified using a globbing expression.
742178479Sjb		 *
743178479Sjb		 * These conditions imply that providers that provide Evolving
744178479Sjb		 * or better Arguments Data stability must guarantee that all
745178479Sjb		 * probes with identical field names in a field of Evolving or
746178479Sjb		 * better Name stability have identical argument signatures.
747178479Sjb		 */
748178479Sjb		if (m > 0) {
749178479Sjb			if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data <
750178479Sjb			    DTRACE_STABILITY_EVOLVING) {
751178479Sjb				(void) dt_set_errno(dtp, EDT_UNSTABLE);
752178479Sjb				return (NULL);
753178479Sjb			}
754178479Sjb
755178479Sjb
756178479Sjb			if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >=
757178479Sjb			    DTRACE_STABILITY_EVOLVING && m_is_glob) {
758178479Sjb				(void) dt_set_errno(dtp, EDT_UNSTABLE);
759178479Sjb				return (NULL);
760178479Sjb			}
761178479Sjb
762178479Sjb			if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >=
763178479Sjb			    DTRACE_STABILITY_EVOLVING && f_is_glob) {
764178479Sjb				(void) dt_set_errno(dtp, EDT_UNSTABLE);
765178479Sjb				return (NULL);
766178479Sjb			}
767178479Sjb
768178479Sjb			if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >=
769178479Sjb			    DTRACE_STABILITY_EVOLVING && n_is_glob) {
770178479Sjb				(void) dt_set_errno(dtp, EDT_UNSTABLE);
771178479Sjb				return (NULL);
772178479Sjb			}
773178479Sjb		}
774178479Sjb
775178479Sjb		/*
776178479Sjb		 * If we matched a probe exported by dtrace(7D), then discover
777178479Sjb		 * the real attributes.  Otherwise grab the static declaration.
778178479Sjb		 */
779178479Sjb		if (pd.dtpd_id != DTRACE_IDNONE)
780178479Sjb			prp = dt_probe_discover(pvp, &pd);
781178479Sjb		else
782178479Sjb			prp = dt_probe_lookup(pvp, pd.dtpd_name);
783178479Sjb
784178479Sjb		if (prp == NULL)
785178479Sjb			return (NULL); /* dt_errno is set for us */
786178479Sjb	}
787178479Sjb
788178479Sjb	assert(pvp != NULL && prp != NULL);
789178479Sjb
790178479Sjb	/*
791178479Sjb	 * Compute the probe description attributes by taking the minimum of
792178479Sjb	 * the attributes of the specified fields.  If no provider is specified
793178479Sjb	 * or a glob pattern is used for the provider, use Unstable attributes.
794178479Sjb	 */
795178479Sjb	if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider))
796178479Sjb		pap = &_dtrace_prvdesc;
797178479Sjb	else
798178479Sjb		pap = &pvp->pv_desc.dtvd_attr;
799178479Sjb
800178479Sjb	pip->dtp_attr = pap->dtpa_provider;
801178479Sjb
802178479Sjb	if (!m_is_glob)
803178479Sjb		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod);
804178479Sjb	if (!f_is_glob)
805178479Sjb		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func);
806178479Sjb	if (!n_is_glob)
807178479Sjb		pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name);
808178479Sjb
809178479Sjb	pip->dtp_arga = pap->dtpa_args;
810178479Sjb	pip->dtp_argv = prp->pr_argv;
811178479Sjb	pip->dtp_argc = prp->pr_argc;
812178479Sjb
813178479Sjb	return (prp);
814178479Sjb}
815178479Sjb
816178479Sjbint
817178479Sjbdtrace_probe_info(dtrace_hdl_t *dtp,
818178479Sjb    const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
819178479Sjb{
820178479Sjb	return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1);
821178479Sjb}
822178479Sjb
823178479Sjb/*ARGSUSED*/
824178479Sjbstatic int
825178479Sjbdt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit)
826178479Sjb{
827178479Sjb	const dt_probe_t *prp = idp->di_data;
828178479Sjb
829178479Sjb	if (!dt_gmatch(prp->pr_name, pit->pit_pat))
830178479Sjb		return (0); /* continue on and examine next probe in hash */
831178479Sjb
832178479Sjb	(void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN);
833178479Sjb	pit->pit_desc.dtpd_id = idp->di_id;
834178479Sjb	pit->pit_matches++;
835178479Sjb
836178479Sjb	return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg));
837178479Sjb}
838178479Sjb
839178479Sjbint
840178479Sjbdtrace_probe_iter(dtrace_hdl_t *dtp,
841178479Sjb    const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg)
842178479Sjb{
843178479Sjb	const char *provider = pdp ? pdp->dtpd_provider : NULL;
844178479Sjb	dtrace_id_t id = DTRACE_IDNONE;
845178479Sjb
846178479Sjb	dtrace_probedesc_t pd;
847178479Sjb	dt_probe_iter_t pit;
848178479Sjb	int cmd, rv;
849178479Sjb
850178479Sjb	bzero(&pit, sizeof (pit));
851178479Sjb	pit.pit_hdl = dtp;
852178479Sjb	pit.pit_func = func;
853178479Sjb	pit.pit_arg = arg;
854178479Sjb	pit.pit_pat = pdp ? pdp->dtpd_name : NULL;
855178479Sjb
856178479Sjb	for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist);
857178479Sjb	    pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) {
858178479Sjb
859178479Sjb		if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL)
860178479Sjb			continue; /* we'll get these later using dt_ioctl() */
861178479Sjb
862178479Sjb		if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider))
863178479Sjb			continue;
864178479Sjb
865178479Sjb		(void) strlcpy(pit.pit_desc.dtpd_provider,
866178479Sjb		    pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN);
867178479Sjb
868178479Sjb		if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes,
869178479Sjb		    (dt_idhash_f *)dt_probe_iter, &pit)) != 0)
870178479Sjb			return (rv);
871178479Sjb	}
872178479Sjb
873178479Sjb	if (pdp != NULL)
874178479Sjb		cmd = DTRACEIOC_PROBEMATCH;
875178479Sjb	else
876178479Sjb		cmd = DTRACEIOC_PROBES;
877178479Sjb
878178479Sjb	for (;;) {
879178479Sjb		if (pdp != NULL)
880178479Sjb			bcopy(pdp, &pd, sizeof (pd));
881178479Sjb
882178479Sjb		pd.dtpd_id = id;
883178479Sjb
884178479Sjb		if (dt_ioctl(dtp, cmd, &pd) != 0)
885178479Sjb			break;
886178479Sjb		else if ((rv = func(dtp, &pd, arg)) != 0)
887178479Sjb			return (rv);
888178479Sjb
889178479Sjb		pit.pit_matches++;
890178479Sjb		id = pd.dtpd_id + 1;
891178479Sjb	}
892178479Sjb
893178479Sjb	switch (errno) {
894178479Sjb	case ESRCH:
895178479Sjb	case EBADF:
896178479Sjb		return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE));
897178479Sjb	case EINVAL:
898178479Sjb		return (dt_set_errno(dtp, EDT_BADPGLOB));
899178479Sjb	default:
900178479Sjb		return (dt_set_errno(dtp, errno));
901178479Sjb	}
902178479Sjb}
903