fbt.c revision 275576
1139826Simp/*
253541Sshin * CDDL HEADER START
353541Sshin *
453541Sshin * The contents of this file are subject to the terms of the
553541Sshin * Common Development and Distribution License (the "License").
653541Sshin * You may not use this file except in compliance with the License.
753541Sshin *
853541Sshin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
953541Sshin * or http://www.opensolaris.org/os/licensing.
1053541Sshin * See the License for the specific language governing permissions
1153541Sshin * and limitations under the License.
1253541Sshin *
1353541Sshin * When distributing Covered Code, include this CDDL HEADER in each
1453541Sshin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1553541Sshin * If applicable, add the following below this CDDL HEADER, with the
1653541Sshin * fields enclosed by brackets "[]" replaced with your own identifying
1753541Sshin * information: Portions Copyright [yyyy] [name of copyright owner]
1853541Sshin *
1953541Sshin * CDDL HEADER END
2053541Sshin *
2153541Sshin * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
2253541Sshin *
2353541Sshin * $FreeBSD: head/sys/cddl/dev/fbt/fbt.c 275576 2014-12-07 11:21:41Z avg $
2453541Sshin *
2553541Sshin */
2653541Sshin
2753541Sshin/*
2853541Sshin * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2953541Sshin * Use is subject to license terms.
30139826Simp */
3153541Sshin
32180305Srwatson#include <sys/cdefs.h>
33180305Srwatson#include <sys/param.h>
3453541Sshin#include <sys/systm.h>
3553541Sshin#include <sys/conf.h>
3653541Sshin#include <sys/cpuvar.h>
3753541Sshin#include <sys/fcntl.h>
3853541Sshin#include <sys/filio.h>
3953541Sshin#include <sys/kdb.h>
4053541Sshin#include <sys/kernel.h>
4153541Sshin#include <sys/kmem.h>
4253541Sshin#include <sys/kthread.h>
4353541Sshin#include <sys/limits.h>
4453541Sshin#include <sys/linker.h>
4553541Sshin#include <sys/lock.h>
4653541Sshin#include <sys/malloc.h>
4753541Sshin#include <sys/module.h>
4853541Sshin#include <sys/mutex.h>
4953541Sshin#include <sys/pcpu.h>
5053541Sshin#include <sys/poll.h>
5153541Sshin#include <sys/proc.h>
5253541Sshin#include <sys/selinfo.h>
5353541Sshin#include <sys/smp.h>
5453541Sshin#include <sys/syscall.h>
5553541Sshin#include <sys/sysent.h>
5653541Sshin#include <sys/sysproto.h>
5753541Sshin#include <sys/uio.h>
5853541Sshin#include <sys/unistd.h>
5953541Sshin#include <machine/stdarg.h>
6053541Sshin
6153541Sshin#include <sys/dtrace.h>
62174510Sobrien#include <sys/dtrace_bsd.h>
63174510Sobrien
64174510Sobrien#include "fbt.h"
6555009Sshin
6678064SumeMALLOC_DEFINE(M_FBT, "fbt", "Function Boundary Tracing");
6755009Sshin
6853541Sshindtrace_provider_id_t	fbt_id;
6995759Stanimurafbt_probe_t		**fbt_probetab;
70185435Sbzint			fbt_probetab_mask;
71253085Sae
7295759Stanimurastatic d_open_t	fbt_open;
7353541Sshinstatic int	fbt_unload(void);
7495759Stanimurastatic void	fbt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
75170689Srwatsonstatic void	fbt_provide_module(void *, modctl_t *);
7653541Sshinstatic void	fbt_destroy(void *, dtrace_id_t, void *);
7795759Stanimurastatic void	fbt_enable(void *, dtrace_id_t, void *);
7895759Stanimurastatic void	fbt_disable(void *, dtrace_id_t, void *);
7953541Sshinstatic void	fbt_load(void *);
8053541Sshinstatic void	fbt_suspend(void *, dtrace_id_t, void *);
8195759Stanimurastatic void	fbt_resume(void *, dtrace_id_t, void *);
82148385Sume
8353541Sshinstatic struct cdevsw fbt_cdevsw = {
8453541Sshin	.d_version	= D_VERSION,
8595759Stanimura	.d_open		= fbt_open,
8653541Sshin	.d_name		= "fbt",
87185571Sbz};
8853541Sshin
8953541Sshinstatic dtrace_pattr_t fbt_attr = {
9053541Sshin{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
9153541Sshin{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
92185571Sbz{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
93185571Sbz{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
9495759Stanimura{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
9562587Sitojun};
96211501Sanchie
9795759Stanimurastatic dtrace_pops_t fbt_pops = {
9856723Sshin	NULL,
9953541Sshin	fbt_provide_module,
10095759Stanimura	fbt_enable,
10153541Sshin	fbt_disable,
10295759Stanimura	fbt_suspend,
10362587Sitojun	fbt_resume,
104211501Sanchie	fbt_getargdesc,
10553541Sshin	NULL,
106171167Sgnn	NULL,
107105199Ssam	fbt_destroy
108105199Ssam};
109171167Sgnn
110105199Ssamstatic struct cdev		*fbt_cdev;
11153541Sshinstatic int			fbt_probetab_size;
11253541Sshinstatic int			fbt_verbose = 0;
11353541Sshin
11453541Sshinstatic void
11553541Sshinfbt_doubletrap(void)
11653541Sshin{
11753541Sshin	fbt_probe_t *fbt;
11853541Sshin	int i;
11953541Sshin
120195699Srwatson	for (i = 0; i < fbt_probetab_size; i++) {
121195699Srwatson		fbt = fbt_probetab[i];
122195727Srwatson
123195727Srwatson		for (; fbt != NULL; fbt = fbt->fbtp_next)
124185348Szec			fbt_patch_tracepoint(fbt, fbt->fbtp_savedval);
12553541Sshin	}
12653541Sshin}
12753541Sshin
128253085Saestatic void
129253085Saefbt_provide_module(void *arg, modctl_t *lf)
130207369Sbz{
131253085Sae	char modname[MAXPATHLEN];
132253085Sae	int i;
133253085Sae	size_t len;
134253085Sae
13553541Sshin	strlcpy(modname, lf->filename, sizeof(modname));
136191672Sbms	len = strlen(modname);
137191672Sbms	if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
138166938Sbms		modname[len - 3] = '\0';
139191672Sbms
140191672Sbms	/*
141191672Sbms	 * Employees of dtrace and their families are ineligible.  Void
142191672Sbms	 * where prohibited.
143195699Srwatson	 */
144191672Sbms	if (strcmp(modname, "dtrace") == 0)
145191672Sbms		return;
146191672Sbms
147191672Sbms	/*
148166938Sbms	 * To register with DTrace, a module must list 'dtrace' as a
149166938Sbms	 * dependency in order for the kernel linker to resolve
150166938Sbms	 * symbols like dtrace_register(). All modules with such a
151166938Sbms	 * dependency are ineligible for FBT tracing.
152194581Srdivacky	 */
153166938Sbms	for (i = 0; i < lf->ndeps; i++)
154166938Sbms		if (strncmp(lf->deps[i]->filename, "dtrace", 6) == 0)
155180305Srwatson			return;
156180305Srwatson
15753541Sshin	if (lf->fbt_nentries) {
15853541Sshin		/*
159171259Sdelphij		 * This module has some FBT entries allocated; we're afraid
16053541Sshin		 * to screw with it.
161191672Sbms		 */
16253541Sshin		return;
16353541Sshin	}
16453541Sshin
16553541Sshin	/*
16678064Sume	 * List the functions in the module and the symbol values.
167121901Sume	 */
16853541Sshin	(void) linker_file_function_listall(lf, fbt_provide_module_function, modname);
169252007Sae}
17078064Sume
17183934Sbrooksstatic void
172180305Srwatsonfbt_destroy(void *arg, dtrace_id_t id, void *parg)
17378064Sume{
174180305Srwatson	fbt_probe_t *fbt = parg, *next, *hash, *last;
17553541Sshin	modctl_t *ctl;
17678064Sume	int ndx;
177121901Sume
17853541Sshin	do {
179191672Sbms		ctl = fbt->fbtp_ctl;
180191672Sbms
181181803Sbz		ctl->fbt_nentries--;
182181803Sbz
183185435Sbz		/*
184186141Sbz		 * Now we need to remove this probe from the fbt_probetab.
18553541Sshin		 */
186186141Sbz		ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
187186141Sbz		last = NULL;
188180850Smav		hash = fbt_probetab[ndx];
18953541Sshin
19053541Sshin		while (hash != fbt) {
191180850Smav			ASSERT(hash != NULL);
19253541Sshin			last = hash;
19353541Sshin			hash = hash->fbtp_hashnext;
194180850Smav		}
195200473Sbz
196191672Sbms		if (last != NULL) {
197191672Sbms			last->fbtp_hashnext = fbt->fbtp_hashnext;
198191672Sbms		} else {
199191672Sbms			fbt_probetab[ndx] = fbt->fbtp_hashnext;
200191672Sbms		}
201191672Sbms
202191672Sbms		next = fbt->fbtp_next;
203191672Sbms		free(fbt, M_FBT);
204191672Sbms
205191672Sbms		fbt = next;
206248180Sae	} while (fbt != NULL);
20778064Sume}
208252007Sae
209151459Ssuzstatic void
21078064Sumefbt_enable(void *arg, dtrace_id_t id, void *parg)
211180932Smav{
212252007Sae	fbt_probe_t *fbt = parg;
213180850Smav	modctl_t *ctl = fbt->fbtp_ctl;
21478064Sume
21553541Sshin	ctl->nenabled++;
216191672Sbms
217191672Sbms	/*
218191672Sbms	 * Now check that our modctl has the expected load count.  If it
219191672Sbms	 * doesn't, this module must have been unloaded and reloaded -- and
220191672Sbms	 * we're not going to touch it.
221191672Sbms	 */
222191672Sbms	if (ctl->loadcnt != fbt->fbtp_loadcnt) {
223191672Sbms		if (fbt_verbose) {
224199518Sbms			printf("fbt is failing for probe %s "
225199518Sbms			    "(module %s reloaded)",
226199518Sbms			    fbt->fbtp_name, ctl->filename);
227199518Sbms		}
228199518Sbms
229199518Sbms		return;
230199518Sbms	}
231199518Sbms
232199518Sbms	for (; fbt != NULL; fbt = fbt->fbtp_next)
233199518Sbms		fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
234199518Sbms}
235199518Sbms
236199518Sbmsstatic void
237199518Sbmsfbt_disable(void *arg, dtrace_id_t id, void *parg)
238199518Sbms{
239199518Sbms	fbt_probe_t *fbt = parg;
240199518Sbms	modctl_t *ctl = fbt->fbtp_ctl;
241191672Sbms
242191672Sbms	ASSERT(ctl->nenabled > 0);
243199518Sbms	ctl->nenabled--;
244199518Sbms
245199518Sbms	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
246191672Sbms		return;
247199518Sbms
248199518Sbms	for (; fbt != NULL; fbt = fbt->fbtp_next)
249199518Sbms		fbt_patch_tracepoint(fbt, fbt->fbtp_savedval);
250199518Sbms}
251199518Sbms
252199518Sbmsstatic void
253199518Sbmsfbt_suspend(void *arg, dtrace_id_t id, void *parg)
254199518Sbms{
255199518Sbms	fbt_probe_t *fbt = parg;
256199518Sbms	modctl_t *ctl = fbt->fbtp_ctl;
257191672Sbms
258191672Sbms	ASSERT(ctl->nenabled > 0);
259211301Sbz
260191672Sbms	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
261191672Sbms		return;
262191672Sbms
263186163Skmacy	for (; fbt != NULL; fbt = fbt->fbtp_next)
26453541Sshin		fbt_patch_tracepoint(fbt, fbt->fbtp_savedval);
26578064Sume}
266171167Sgnn
26778064Sumestatic void
26878064Sumefbt_resume(void *arg, dtrace_id_t id, void *parg)
26978064Sume{
270125396Sume	fbt_probe_t *fbt = parg;
27178064Sume	modctl_t *ctl = fbt->fbtp_ctl;
272253571Sae
273180305Srwatson	ASSERT(ctl->nenabled > 0);
274105199Ssam
275171167Sgnn	if ((ctl->loadcnt != fbt->fbtp_loadcnt))
27653541Sshin		return;
277186223Sbz
278186141Sbz	for (; fbt != NULL; fbt = fbt->fbtp_next)
279121674Sume		fbt_patch_tracepoint(fbt, fbt->fbtp_patchval);
28053541Sshin}
28153541Sshin
282186141Sbzstatic int
283121901Sumefbt_ctfoff_init(modctl_t *lf, linker_ctf_t *lc)
28453541Sshin{
28553541Sshin	const Elf_Sym *symp = lc->symtab;;
28653541Sshin	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
28753541Sshin	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
288252007Sae	int i;
28997658Stanimura	uint32_t *ctfoff;
290186141Sbz	uint32_t objtoff = hp->cth_objtoff;
29153541Sshin	uint32_t funcoff = hp->cth_funcoff;
29253541Sshin	ushort_t info;
293178377Srwatson	ushort_t vlen;
29453541Sshin
29553541Sshin	/* Sanity check. */
29653541Sshin	if (hp->cth_magic != CTF_MAGIC) {
297181803Sbz		printf("Bad magic value in CTF data of '%s'\n",lf->pathname);
298171167Sgnn		return (EINVAL);
29978064Sume	}
30078064Sume
30178064Sume	if (lc->symtab == NULL) {
302186170Skmacy		printf("No symbol table in '%s'\n",lf->pathname);
30378064Sume		return (EINVAL);
304253571Sae	}
305249294Sae
306180305Srwatson	if ((ctfoff = malloc(sizeof(uint32_t) * lc->nsym, M_LINKER, M_WAITOK)) == NULL)
307178377Srwatson		return (ENOMEM);
308105199Ssam
309171167Sgnn	*lc->ctfoffp = ctfoff;
310186163Skmacy
311186223Sbz	for (i = 0; i < lc->nsym; i++, ctfoff++, symp++) {
312186141Sbz		if (symp->st_name == 0 || symp->st_shndx == SHN_UNDEF) {
313121674Sume			*ctfoff = 0xffffffff;
314180305Srwatson			continue;
31553541Sshin		}
316186141Sbz
317180305Srwatson		switch (ELF_ST_TYPE(symp->st_info)) {
31853541Sshin		case STT_OBJECT:
31953541Sshin			if (objtoff >= hp->cth_funcoff ||
32053541Sshin                            (symp->st_shndx == SHN_ABS && symp->st_value == 0)) {
321252007Sae				*ctfoff = 0xffffffff;
32297658Stanimura                                break;
323186141Sbz                        }
324178377Srwatson
32553541Sshin                        *ctfoff = objtoff;
326252007Sae                        objtoff += sizeof (ushort_t);
32778064Sume			break;
328252007Sae
32953541Sshin		case STT_FUNC:
33053541Sshin			if (funcoff >= hp->cth_typeoff) {
331329158Sae				*ctfoff = 0xffffffff;
33253541Sshin				break;
333180305Srwatson			}
334329158Sae
335249294Sae			*ctfoff = funcoff;
33653541Sshin
337180305Srwatson			info = *((const ushort_t *)(ctfdata + funcoff));
33853541Sshin			vlen = CTF_INFO_VLEN(info);
33953541Sshin
34062587Sitojun			/*
341171259Sdelphij			 * If we encounter a zero pad at the end, just skip it.
34262587Sitojun			 * Otherwise skip over the function and its return type
34362587Sitojun			 * (+2) and the argument list (vlen).
34462587Sitojun			 */
34562587Sitojun			if (CTF_INFO_KIND(info) == CTF_K_UNKNOWN && vlen == 0)
34678064Sume				funcoff += sizeof (ushort_t); /* skip pad */
34778064Sume			else
348125776Sume				funcoff += sizeof (ushort_t) * (vlen + 2);
349175162Sobrien			break;
35062587Sitojun
35162587Sitojun		default:
35262587Sitojun			*ctfoff = 0xffffffff;
35362587Sitojun			break;
35462587Sitojun		}
35562587Sitojun	}
35662587Sitojun
35762587Sitojun	return (0);
35862587Sitojun}
35962587Sitojun
36062587Sitojunstatic ssize_t
36162587Sitojunfbt_get_ctt_size(uint8_t version, const ctf_type_t *tp, ssize_t *sizep,
36262587Sitojun    ssize_t *incrementp)
36362587Sitojun{
364180305Srwatson	ssize_t size, increment;
365180305Srwatson
366180305Srwatson	if (version > CTF_VERSION_1 &&
36762587Sitojun	    tp->ctt_size == CTF_LSIZE_SENT) {
36878064Sume		size = CTF_TYPE_LSIZE(tp);
36962587Sitojun		increment = sizeof (ctf_type_t);
37062587Sitojun	} else {
37162587Sitojun		size = tp->ctt_size;
372125776Sume		increment = sizeof (ctf_stype_t);
37378064Sume	}
37462587Sitojun
37562587Sitojun	if (sizep)
37662587Sitojun		*sizep = size;
377125776Sume	if (incrementp)
37878064Sume		*incrementp = increment;
37962587Sitojun
38062587Sitojun	return (size);
381181803Sbz}
382180305Srwatson
38362587Sitojunstatic int
38462587Sitojunfbt_typoff_init(linker_ctf_t *lc)
38553541Sshin{
386180305Srwatson	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
387180305Srwatson	const ctf_type_t *tbuf;
38853541Sshin	const ctf_type_t *tend;
38953541Sshin	const ctf_type_t *tp;
39053541Sshin	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
39153541Sshin	int ctf_typemax = 0;
39253541Sshin	uint32_t *xp;
39353541Sshin	ulong_t pop[CTF_K_MAX + 1] = { 0 };
39453541Sshin
39553541Sshin
39653541Sshin	/* Sanity check. */
39753541Sshin	if (hp->cth_magic != CTF_MAGIC)
398120941Sume		return (EINVAL);
399211501Sanchie
40053541Sshin	tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff);
40153541Sshin	tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff);
40253541Sshin
40353541Sshin	int child = hp->cth_parname != 0;
40453541Sshin
40553541Sshin	/*
40653541Sshin	 * We make two passes through the entire type section.  In this first
407148247Sume	 * pass, we count the number of each type and the total number of types.
40853541Sshin	 */
40953541Sshin	for (tp = tbuf; tp < tend; ctf_typemax++) {
410148385Sume		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
411211435Sume		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
412194777Sbz		ssize_t size, increment;
41353541Sshin
41453541Sshin		size_t vbytes;
41553541Sshin		uint_t n;
41653541Sshin
41753541Sshin		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
41853541Sshin
41953541Sshin		switch (kind) {
42053541Sshin		case CTF_K_INTEGER:
421186141Sbz		case CTF_K_FLOAT:
422178285Srwatson			vbytes = sizeof (uint_t);
42353541Sshin			break;
42453541Sshin		case CTF_K_ARRAY:
425186170Skmacy			vbytes = sizeof (ctf_array_t);
426148242Sume			break;
427175630Sbz		case CTF_K_FUNCTION:
428175630Sbz			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
42953541Sshin			break;
430121472Sume		case CTF_K_STRUCT:
431148247Sume		case CTF_K_UNION:
432148247Sume			if (size < CTF_LSTRUCT_THRESH) {
433148247Sume				ctf_member_t *mp = (ctf_member_t *)
43453541Sshin				    ((uintptr_t)tp + increment);
43553541Sshin
436148385Sume				vbytes = sizeof (ctf_member_t) * vlen;
437180305Srwatson				for (n = vlen; n != 0; n--, mp++)
438148385Sume					child |= CTF_TYPE_ISCHILD(mp->ctm_type);
439148385Sume			} else {
440148385Sume				ctf_lmember_t *lmp = (ctf_lmember_t *)
441211530Sume				    ((uintptr_t)tp + increment);
442211530Sume
443211435Sume				vbytes = sizeof (ctf_lmember_t) * vlen;
444211435Sume				for (n = vlen; n != 0; n--, lmp++)
445148385Sume					child |=
446211435Sume					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
447148385Sume			}
448148385Sume			break;
449148385Sume		case CTF_K_ENUM:
450148385Sume			vbytes = sizeof (ctf_enum_t) * vlen;
451180305Srwatson			break;
452180305Srwatson		case CTF_K_FORWARD:
45353541Sshin			/*
45453541Sshin			 * For forward declarations, ctt_type is the CTF_K_*
45553541Sshin			 * kind for the tag, so bump that population count too.
45653541Sshin			 * If ctt_type is unknown, treat the tag as a struct.
45753541Sshin			 */
45853541Sshin			if (tp->ctt_type == CTF_K_UNKNOWN ||
45953541Sshin			    tp->ctt_type >= CTF_K_MAX)
46053541Sshin				pop[CTF_K_STRUCT]++;
46153541Sshin			else
46253541Sshin				pop[tp->ctt_type]++;
46353541Sshin			/*FALLTHRU*/
46453541Sshin		case CTF_K_UNKNOWN:
46553541Sshin			vbytes = 0;
466243882Sglebius			break;
467133592Srwatson		case CTF_K_POINTER:
468133592Srwatson		case CTF_K_TYPEDEF:
469133592Srwatson		case CTF_K_VOLATILE:
470133592Srwatson		case CTF_K_CONST:
47153541Sshin		case CTF_K_RESTRICT:
47253541Sshin			child |= CTF_TYPE_ISCHILD(tp->ctt_type);
47353541Sshin			vbytes = 0;
47453541Sshin			break;
47553541Sshin		default:
476194777Sbz			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
477194777Sbz			return (EIO);
478194777Sbz		}
479121472Sume		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
480207277Sbz		pop[kind]++;
481188144Sjamie	}
482188144Sjamie
483194777Sbz	/* account for a sentinel value below */
484148385Sume	ctf_typemax++;
485148385Sume	*lc->typlenp = ctf_typemax;
486148385Sume
487148385Sume	if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL)
488148385Sume		return (ENOMEM);
489148385Sume
490148385Sume	*lc->typoffp = xp;
491148385Sume
492148385Sume	/* type id 0 is used as a sentinel value */
493148385Sume	*xp++ = 0;
494148385Sume
495148385Sume	/*
496148385Sume	 * In the second pass, fill in the type offset.
497148385Sume	 */
498148385Sume	for (tp = tbuf; tp < tend; xp++) {
499148385Sume		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
500180305Srwatson		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
501180305Srwatson		ssize_t size, increment;
502180305Srwatson
50355009Sshin		size_t vbytes;
504186141Sbz		uint_t n;
50555009Sshin
506180305Srwatson		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);
507180305Srwatson
508180305Srwatson		switch (kind) {
509180305Srwatson		case CTF_K_INTEGER:
510180305Srwatson		case CTF_K_FLOAT:
511186141Sbz			vbytes = sizeof (uint_t);
51253541Sshin			break;
51353541Sshin		case CTF_K_ARRAY:
51453541Sshin			vbytes = sizeof (ctf_array_t);
51553541Sshin			break;
51653541Sshin		case CTF_K_FUNCTION:
51753541Sshin			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
51853541Sshin			break;
51953541Sshin		case CTF_K_STRUCT:
520180305Srwatson		case CTF_K_UNION:
52153541Sshin			if (size < CTF_LSTRUCT_THRESH) {
52253541Sshin				ctf_member_t *mp = (ctf_member_t *)
52353541Sshin				    ((uintptr_t)tp + increment);
52453541Sshin
52553541Sshin				vbytes = sizeof (ctf_member_t) * vlen;
52653541Sshin				for (n = vlen; n != 0; n--, mp++)
52753541Sshin					child |= CTF_TYPE_ISCHILD(mp->ctm_type);
52853541Sshin			} else {
52953541Sshin				ctf_lmember_t *lmp = (ctf_lmember_t *)
53053541Sshin				    ((uintptr_t)tp + increment);
53153541Sshin
53253541Sshin				vbytes = sizeof (ctf_lmember_t) * vlen;
53353541Sshin				for (n = vlen; n != 0; n--, lmp++)
53453541Sshin					child |=
53553541Sshin					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
53653541Sshin			}
53753541Sshin			break;
53853541Sshin		case CTF_K_ENUM:
53953541Sshin			vbytes = sizeof (ctf_enum_t) * vlen;
54053541Sshin			break;
54153541Sshin		case CTF_K_FORWARD:
54253541Sshin		case CTF_K_UNKNOWN:
543211501Sanchie			vbytes = 0;
544211501Sanchie			break;
545211501Sanchie		case CTF_K_POINTER:
546211501Sanchie		case CTF_K_TYPEDEF:
547211501Sanchie		case CTF_K_VOLATILE:
548211501Sanchie		case CTF_K_CONST:
549211501Sanchie		case CTF_K_RESTRICT:
550211501Sanchie			vbytes = 0;
551211501Sanchie			break;
552211501Sanchie		default:
553211501Sanchie			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
554211501Sanchie			return (EIO);
555211501Sanchie		}
556211501Sanchie		*xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata);
557211501Sanchie		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
558211501Sanchie	}
559211501Sanchie
560148247Sume	return (0);
56153541Sshin}
56253541Sshin
56353541Sshin/*
564190964Srwatson * CTF Declaration Stack
56578064Sume *
566252007Sae * In order to implement ctf_type_name(), we must convert a type graph back
56753541Sshin * into a C type declaration.  Unfortunately, a type graph represents a storage
56853541Sshin * class ordering of the type whereas a type declaration must obey the C rules
56953541Sshin * for operator precedence, and the two orderings are frequently in conflict.
57053541Sshin * For example, consider these CTF type graphs and their C declarations:
57153541Sshin *
57253541Sshin * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER  : int (*)()
57353541Sshin * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER     : int (*)[]
57453541Sshin *
575186170Skmacy * In each case, parentheses are used to raise operator * to higher lexical
576148247Sume * precedence, so the string form of the C declaration cannot be constructed by
57753541Sshin * walking the type graph links and forming the string from left to right.
57878064Sume *
579178285Srwatson * The functions in this file build a set of stacks from the type graph nodes
580120856Sume * corresponding to the C operator precedence levels in the appropriate order.
58153541Sshin * The code in ctf_type_name() can then iterate over the levels and nodes in
58253541Sshin * lexical precedence order and construct the final C declaration string.
58353541Sshin */
58453541Sshintypedef struct ctf_list {
58553541Sshin	struct ctf_list *l_prev; /* previous pointer or tail pointer */
58653541Sshin	struct ctf_list *l_next; /* next pointer or head pointer */
587171259Sdelphij} ctf_list_t;
58853541Sshin
589231852Sbz#define	ctf_list_prev(elem)	((void *)(((ctf_list_t *)(elem))->l_prev))
59053541Sshin#define	ctf_list_next(elem)	((void *)(((ctf_list_t *)(elem))->l_next))
59153541Sshin
59253541Sshintypedef enum {
59353541Sshin	CTF_PREC_BASE,
59453541Sshin	CTF_PREC_POINTER,
59553541Sshin	CTF_PREC_ARRAY,
59653541Sshin	CTF_PREC_FUNCTION,
597120856Sume	CTF_PREC_MAX
598231852Sbz} ctf_decl_prec_t;
599231852Sbz
600231852Sbztypedef struct ctf_decl_node {
601231852Sbz	ctf_list_t cd_list;			/* linked list pointers */
602231852Sbz	ctf_id_t cd_type;			/* type identifier */
603231852Sbz	uint_t cd_kind;				/* type kind */
604231852Sbz	uint_t cd_n;				/* type dimension if array */
605231852Sbz} ctf_decl_node_t;
606231852Sbz
60753541Sshintypedef struct ctf_decl {
608231852Sbz	ctf_list_t cd_nodes[CTF_PREC_MAX];	/* declaration node stacks */
60953541Sshin	int cd_order[CTF_PREC_MAX];		/* storage order of decls */
61053541Sshin	ctf_decl_prec_t cd_qualp;		/* qualifier precision */
61153541Sshin	ctf_decl_prec_t cd_ordp;		/* ordered precision */
61253541Sshin	char *cd_buf;				/* buffer for output */
61353541Sshin	char *cd_ptr;				/* buffer location */
61453541Sshin	char *cd_end;				/* buffer limit */
61556723Sshin	size_t cd_len;				/* buffer space required */
61656723Sshin	int cd_err;				/* saved error value */
61756723Sshin} ctf_decl_t;
61856723Sshin
61956723Sshin/*
62056723Sshin * Simple doubly-linked list append routine.  This implementation assumes that
62156723Sshin * each list element contains an embedded ctf_list_t as the first member.
622166938Sbms * An additional ctf_list_t is used to store the head (l_next) and tail
623166938Sbms * (l_prev) pointers.  The current head and tail list elements have their
62456723Sshin * previous and next pointers set to NULL, respectively.
625121578Sume */
626121578Sumestatic void
627121578Sumectf_list_append(ctf_list_t *lp, void *new)
62853541Sshin{
62953541Sshin	ctf_list_t *p = lp->l_prev;	/* p = tail list element */
63053541Sshin	ctf_list_t *q = new;		/* q = new list element */
63153541Sshin
63253541Sshin	lp->l_prev = q;
63353541Sshin	q->l_prev = p;
63453541Sshin	q->l_next = NULL;
63553541Sshin
63656723Sshin	if (p != NULL)
63756723Sshin		p->l_next = q;
63856723Sshin	else
63956723Sshin		lp->l_next = q;
64056723Sshin}
64156723Sshin
64256723Sshin/*
643166938Sbms * Prepend the specified existing element to the given ctf_list_t.  The
644166938Sbms * existing pointer should be pointing at a struct with embedded ctf_list_t.
64556723Sshin */
646121578Sumestatic void
647121578Sumectf_list_prepend(ctf_list_t *lp, void *new)
648121578Sume{
64953541Sshin	ctf_list_t *p = new;		/* p = new list element */
65053541Sshin	ctf_list_t *q = lp->l_next;	/* q = head list element */
65153541Sshin
65253541Sshin	lp->l_next = p;
65353541Sshin	p->l_prev = NULL;
65453541Sshin	p->l_next = q;
65553541Sshin
65653541Sshin	if (q != NULL)
65753541Sshin		q->l_prev = p;
65853541Sshin	else
65953541Sshin		lp->l_prev = p;
66083366Sjulian}
66153541Sshin
66253541Sshinstatic void
663144261Ssamctf_decl_init(ctf_decl_t *cd, char *buf, size_t len)
664157676Srwatson{
66553541Sshin	int i;
66653541Sshin
667157374Srwatson	bzero(cd, sizeof (ctf_decl_t));
668180305Srwatson
669175630Sbz	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++)
670175630Sbz		cd->cd_order[i] = CTF_PREC_BASE - 1;
671180305Srwatson
67255009Sshin	cd->cd_qualp = CTF_PREC_BASE;
673157374Srwatson	cd->cd_ordp = CTF_PREC_BASE;
674180305Srwatson
675184214Sdes	cd->cd_buf = buf;
676157374Srwatson	cd->cd_ptr = buf;
677180305Srwatson	cd->cd_end = buf + len;
678181803Sbz}
679181803Sbz
680132714Srwatsonstatic void
681181803Sbzctf_decl_fini(ctf_decl_t *cd)
682184205Sdes{
683180305Srwatson	ctf_decl_node_t *cdp, *ndp;
684132714Srwatson	int i;
68553541Sshin
686181803Sbz	for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) {
68753541Sshin		for (cdp = ctf_list_next(&cd->cd_nodes[i]);
688186141Sbz		    cdp != NULL; cdp = ndp) {
68953541Sshin			ndp = ctf_list_next(cdp);
69053541Sshin			free(cdp, M_FBT);
691144261Ssam		}
69253541Sshin	}
693178285Srwatson}
694180305Srwatson
69553541Sshinstatic const ctf_type_t *
69653541Sshinctf_lookup_by_id(linker_ctf_t *lc, ctf_id_t type)
697157370Srwatson{
69853541Sshin	const ctf_type_t *tp;
69953541Sshin	uint32_t offset;
70053541Sshin	uint32_t *typoff = *lc->typoffp;
70153541Sshin
70253541Sshin	if (type >= *lc->typlenp) {
703157374Srwatson		printf("%s(%d): type %d exceeds max %ld\n",__func__,__LINE__,(int) type,*lc->typlenp);
704160549Srwatson		return(NULL);
705191672Sbms	}
706166938Sbms
70753541Sshin	/* Check if the type isn't cross-referenced. */
708181803Sbz	if ((offset = typoff[type]) == 0) {
709178285Srwatson		printf("%s(%d): type %d isn't cross referenced\n",__func__,__LINE__, (int) type);
710184205Sdes		return(NULL);
711185344Sbz	}
712185370Sbz
713181803Sbz	tp = (const ctf_type_t *)(lc->ctftab + offset + sizeof(ctf_header_t));
71453541Sshin
71553541Sshin	return (tp);
716160549Srwatson}
717157366Srwatson
71853541Sshinstatic void
71953541Sshinfbt_array_info(linker_ctf_t *lc, ctf_id_t type, ctf_arinfo_t *arp)
720160549Srwatson{
721160549Srwatson	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
722160549Srwatson	const ctf_type_t *tp;
723160549Srwatson	const ctf_array_t *ap;
724160549Srwatson	ssize_t increment;
72553541Sshin
72653541Sshin	bzero(arp, sizeof(*arp));
72753541Sshin
728160549Srwatson	if ((tp = ctf_lookup_by_id(lc, type)) == NULL)
729160549Srwatson		return;
730160549Srwatson
731160549Srwatson	if (CTF_INFO_KIND(tp->ctt_info) != CTF_K_ARRAY)
732160549Srwatson		return;
733160549Srwatson
734160549Srwatson	(void) fbt_get_ctt_size(hp->cth_version, tp, NULL, &increment);
735160549Srwatson
736160549Srwatson	ap = (const ctf_array_t *)((uintptr_t)tp + increment);
737160549Srwatson	arp->ctr_contents = ap->cta_contents;
738160549Srwatson	arp->ctr_index = ap->cta_index;
73953541Sshin	arp->ctr_nelems = ap->cta_nelems;
74053541Sshin}
74153541Sshin
742180305Srwatsonstatic const char *
74353541Sshinctf_strptr(linker_ctf_t *lc, int name)
744180305Srwatson{
745180305Srwatson	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;;
746180305Srwatson	const char *strp = "";
74797658Stanimura
748180305Srwatson	if (name < 0 || name >= hp->cth_strlen)
74953541Sshin		return(strp);
750157366Srwatson
751157374Srwatson	strp = (const char *)(lc->ctftab + hp->cth_stroff + name + sizeof(ctf_header_t));
75253541Sshin
75353541Sshin	return (strp);
75453541Sshin}
75583366Sjulian
75653541Sshinstatic void
757180305Srwatsonctf_decl_push(ctf_decl_t *cd, linker_ctf_t *lc, ctf_id_t type)
75853541Sshin{
759194760Srwatson	ctf_decl_node_t *cdp;
760148385Sume	ctf_decl_prec_t prec;
76153541Sshin	uint_t kind, n = 1;
762180305Srwatson	int is_qual = 0;
763157374Srwatson
764180305Srwatson	const ctf_type_t *tp;
76553541Sshin	ctf_arinfo_t ar;
766180305Srwatson
767188144Sjamie	if ((tp = ctf_lookup_by_id(lc, type)) == NULL) {
768188144Sjamie		cd->cd_err = ENOENT;
769181803Sbz		return;
770180305Srwatson	}
771181803Sbz
772180305Srwatson	switch (kind = CTF_INFO_KIND(tp->ctt_info)) {
773148385Sume	case CTF_K_ARRAY:
77453541Sshin		fbt_array_info(lc, type, &ar);
775194760Srwatson		ctf_decl_push(cd, lc, ar.ctr_contents);
776180305Srwatson		n = ar.ctr_nelems;
777194760Srwatson		prec = CTF_PREC_ARRAY;
778194760Srwatson		break;
77953541Sshin
78053541Sshin	case CTF_K_TYPEDEF:
781194760Srwatson		if (ctf_strptr(lc, tp->ctt_name)[0] == '\0') {
782120856Sume			ctf_decl_push(cd, lc, tp->ctt_type);
78353541Sshin			return;
784194760Srwatson		}
785194760Srwatson		prec = CTF_PREC_BASE;
786181803Sbz		break;
787178285Srwatson
78853541Sshin	case CTF_K_FUNCTION:
789178285Srwatson		ctf_decl_push(cd, lc, tp->ctt_type);
790181803Sbz		prec = CTF_PREC_FUNCTION;
791180305Srwatson		break;
79253541Sshin
79353541Sshin	case CTF_K_POINTER:
79453541Sshin		ctf_decl_push(cd, lc, tp->ctt_type);
79583366Sjulian		prec = CTF_PREC_POINTER;
79653541Sshin		break;
797180305Srwatson
79853541Sshin	case CTF_K_VOLATILE:
799194777Sbz	case CTF_K_CONST:
800148385Sume	case CTF_K_RESTRICT:
801148385Sume		ctf_decl_push(cd, lc, tp->ctt_type);
80253541Sshin		prec = cd->cd_qualp;
803180305Srwatson		is_qual++;
804157374Srwatson		break;
805180305Srwatson
80653541Sshin	default:
807180305Srwatson		prec = CTF_PREC_BASE;
808181803Sbz	}
809180305Srwatson
81053541Sshin	if ((cdp = malloc(sizeof (ctf_decl_node_t), M_FBT, M_WAITOK)) == NULL) {
811180305Srwatson		cd->cd_err = EAGAIN;
812148385Sume		return;
813148385Sume	}
814180305Srwatson
815180305Srwatson	cdp->cd_type = type;
816180305Srwatson	cdp->cd_kind = kind;
817180305Srwatson	cdp->cd_n = n;
818180305Srwatson
819180305Srwatson	if (ctf_list_next(&cd->cd_nodes[prec]) == NULL)
820148385Sume		cd->cd_order[prec] = cd->cd_ordp++;
821181803Sbz
822148385Sume	/*
823181803Sbz	 * Reset cd_qualp to the highest precedence level that we've seen so
824180305Srwatson	 * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER).
825148385Sume	 */
826181803Sbz	if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY)
827178285Srwatson		cd->cd_qualp = prec;
82853541Sshin
829194777Sbz	/*
830194777Sbz	 * C array declarators are ordered inside out so prepend them.  Also by
831194777Sbz	 * convention qualifiers of base types precede the type specifier (e.g.
832178285Srwatson	 * const int vs. int const) even though the two forms are equivalent.
833181803Sbz	 */
834194777Sbz	if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE))
835132714Srwatson		ctf_list_prepend(&cd->cd_nodes[prec], cdp);
836148385Sume	else
837148385Sume		ctf_list_append(&cd->cd_nodes[prec], cdp);
838148385Sume}
839148385Sume
840178285Srwatsonstatic void
841181803Sbzctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...)
842180305Srwatson{
843148385Sume	size_t len = (size_t)(cd->cd_end - cd->cd_ptr);
844148385Sume	va_list ap;
845194777Sbz	size_t n;
84653541Sshin
847178285Srwatson	va_start(ap, format);
848181803Sbz	n = vsnprintf(cd->cd_ptr, len, format, ap);
849180305Srwatson	va_end(ap);
85053541Sshin
85153541Sshin	cd->cd_ptr += MIN(n, len);
85253541Sshin	cd->cd_len += n;
85353541Sshin}
85453541Sshin
855132714Srwatsonstatic ssize_t
856132714Srwatsonfbt_type_name(linker_ctf_t *lc, ctf_id_t type, char *buf, size_t len)
857132714Srwatson{
858157374Srwatson	ctf_decl_t cd;
859180305Srwatson	ctf_decl_node_t *cdp;
860178285Srwatson	ctf_decl_prec_t prec, lp, rp;
86153541Sshin	int ptr, arr;
862178285Srwatson	uint_t k;
863180305Srwatson
86453541Sshin	if (lc == NULL && type == CTF_ERR)
86553541Sshin		return (-1); /* simplify caller code by permitting CTF_ERR */
86653541Sshin
86753541Sshin	ctf_decl_init(&cd, buf, len);
868171260Sdelphij	ctf_decl_push(&cd, lc, type);
86953541Sshin
870180305Srwatson	if (cd.cd_err != 0) {
87153541Sshin		ctf_decl_fini(&cd);
87253541Sshin		return (-1);
873132714Srwatson	}
87453541Sshin
875180305Srwatson	/*
876157374Srwatson	 * If the type graph's order conflicts with lexical precedence order
877180305Srwatson	 * for pointers or arrays, then we need to surround the declarations at
878180305Srwatson	 * the corresponding lexical precedence with parentheses.  This can
879132714Srwatson	 * result in either a parenthesized pointer (*) as in int (*)() or
88053541Sshin	 * int (*)[], or in a parenthesized pointer and array as in int (*[])().
88153541Sshin	 */
88253541Sshin	ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER;
883180305Srwatson	arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY;
88453541Sshin
88553541Sshin	rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1;
88653541Sshin	lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1;
88753541Sshin
88853541Sshin	k = CTF_K_POINTER; /* avoid leading whitespace (see below) */
889180990Srwatson
89053541Sshin	for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) {
891180990Srwatson		for (cdp = ctf_list_next(&cd.cd_nodes[prec]);
892180990Srwatson		    cdp != NULL; cdp = ctf_list_next(cdp)) {
89353541Sshin
89453541Sshin			const ctf_type_t *tp =
89553541Sshin			    ctf_lookup_by_id(lc, cdp->cd_type);
89653541Sshin			const char *name = ctf_strptr(lc, tp->ctt_name);
897180305Srwatson
89853541Sshin			if (k != CTF_K_POINTER && k != CTF_K_ARRAY)
899148385Sume				ctf_decl_sprintf(&cd, " ");
900148385Sume
901180305Srwatson			if (lp == prec) {
902148385Sume				ctf_decl_sprintf(&cd, "(");
90362587Sitojun				lp = -1;
90462587Sitojun			}
905148385Sume
906148385Sume			switch (cdp->cd_kind) {
907148385Sume			case CTF_K_INTEGER:
908148385Sume			case CTF_K_FLOAT:
909148385Sume			case CTF_K_TYPEDEF:
910148385Sume				ctf_decl_sprintf(&cd, "%s", name);
911148385Sume				break;
912148385Sume			case CTF_K_POINTER:
913148385Sume				ctf_decl_sprintf(&cd, "*");
914148385Sume				break;
915148385Sume			case CTF_K_ARRAY:
916148385Sume				ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n);
917148385Sume				break;
918148385Sume			case CTF_K_FUNCTION:
91953541Sshin				ctf_decl_sprintf(&cd, "()");
920132714Srwatson				break;
921132714Srwatson			case CTF_K_STRUCT:
92253541Sshin			case CTF_K_FORWARD:
92353541Sshin				ctf_decl_sprintf(&cd, "struct %s", name);
92453541Sshin				break;
925137386Sphk			case CTF_K_UNION:
926137386Sphk				ctf_decl_sprintf(&cd, "union %s", name);
927137386Sphk				break;
928137386Sphk			case CTF_K_ENUM:
929137386Sphk				ctf_decl_sprintf(&cd, "enum %s", name);
930137386Sphk				break;
931137386Sphk			case CTF_K_VOLATILE:
932169462Srwatson				ctf_decl_sprintf(&cd, "volatile");
933137386Sphk				break;
934137386Sphk			case CTF_K_CONST:
935169462Srwatson				ctf_decl_sprintf(&cd, "const");
936160549Srwatson				break;
93753541Sshin			case CTF_K_RESTRICT:
938				ctf_decl_sprintf(&cd, "restrict");
939				break;
940			}
941
942			k = cdp->cd_kind;
943		}
944
945		if (rp == prec)
946			ctf_decl_sprintf(&cd, ")");
947	}
948
949	ctf_decl_fini(&cd);
950	return (cd.cd_len);
951}
952
953static void
954fbt_getargdesc(void *arg __unused, dtrace_id_t id __unused, void *parg, dtrace_argdesc_t *desc)
955{
956	const ushort_t *dp;
957	fbt_probe_t *fbt = parg;
958	linker_ctf_t lc;
959	modctl_t *ctl = fbt->fbtp_ctl;
960	int ndx = desc->dtargd_ndx;
961	int symindx = fbt->fbtp_symindx;
962	uint32_t *ctfoff;
963	uint32_t offset;
964	ushort_t info, kind, n;
965
966	if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) {
967		(void) strcpy(desc->dtargd_native, "int");
968		return;
969	}
970
971	desc->dtargd_ndx = DTRACE_ARGNONE;
972
973	/* Get a pointer to the CTF data and it's length. */
974	if (linker_ctf_get(ctl, &lc) != 0)
975		/* No CTF data? Something wrong? *shrug* */
976		return;
977
978	/* Check if this module hasn't been initialised yet. */
979	if (*lc.ctfoffp == NULL) {
980		/*
981		 * Initialise the CTF object and function symindx to
982		 * byte offset array.
983		 */
984		if (fbt_ctfoff_init(ctl, &lc) != 0)
985			return;
986
987		/* Initialise the CTF type to byte offset array. */
988		if (fbt_typoff_init(&lc) != 0)
989			return;
990	}
991
992	ctfoff = *lc.ctfoffp;
993
994	if (ctfoff == NULL || *lc.typoffp == NULL)
995		return;
996
997	/* Check if the symbol index is out of range. */
998	if (symindx >= lc.nsym)
999		return;
1000
1001	/* Check if the symbol isn't cross-referenced. */
1002	if ((offset = ctfoff[symindx]) == 0xffffffff)
1003		return;
1004
1005	dp = (const ushort_t *)(lc.ctftab + offset + sizeof(ctf_header_t));
1006
1007	info = *dp++;
1008	kind = CTF_INFO_KIND(info);
1009	n = CTF_INFO_VLEN(info);
1010
1011	if (kind == CTF_K_UNKNOWN && n == 0) {
1012		printf("%s(%d): Unknown function!\n",__func__,__LINE__);
1013		return;
1014	}
1015
1016	if (kind != CTF_K_FUNCTION) {
1017		printf("%s(%d): Expected a function!\n",__func__,__LINE__);
1018		return;
1019	}
1020
1021	if (fbt->fbtp_roffset != 0) {
1022		/* Only return type is available for args[1] in return probe. */
1023		if (ndx > 1)
1024			return;
1025		ASSERT(ndx == 1);
1026	} else {
1027		/* Check if the requested argument doesn't exist. */
1028		if (ndx >= n)
1029			return;
1030
1031		/* Skip the return type and arguments up to the one requested. */
1032		dp += ndx + 1;
1033	}
1034
1035	if (fbt_type_name(&lc, *dp, desc->dtargd_native, sizeof(desc->dtargd_native)) > 0)
1036		desc->dtargd_ndx = ndx;
1037
1038	return;
1039}
1040
1041static int
1042fbt_linker_file_cb(linker_file_t lf, void *arg)
1043{
1044
1045	fbt_provide_module(arg, lf);
1046
1047	return (0);
1048}
1049
1050static void
1051fbt_load(void *dummy)
1052{
1053	/* Create the /dev/dtrace/fbt entry. */
1054	fbt_cdev = make_dev(&fbt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
1055	    "dtrace/fbt");
1056
1057	/* Default the probe table size if not specified. */
1058	if (fbt_probetab_size == 0)
1059		fbt_probetab_size = FBT_PROBETAB_SIZE;
1060
1061	/* Choose the hash mask for the probe table. */
1062	fbt_probetab_mask = fbt_probetab_size - 1;
1063
1064	/* Allocate memory for the probe table. */
1065	fbt_probetab =
1066	    malloc(fbt_probetab_size * sizeof (fbt_probe_t *), M_FBT, M_WAITOK | M_ZERO);
1067
1068	dtrace_doubletrap_func = fbt_doubletrap;
1069	dtrace_invop_add(fbt_invop);
1070
1071	if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER,
1072	    NULL, &fbt_pops, NULL, &fbt_id) != 0)
1073		return;
1074
1075	/* Create probes for the kernel and already-loaded modules. */
1076	linker_file_foreach(fbt_linker_file_cb, NULL);
1077}
1078
1079static int
1080fbt_unload()
1081{
1082	int error = 0;
1083
1084	/* De-register the invalid opcode handler. */
1085	dtrace_invop_remove(fbt_invop);
1086
1087	dtrace_doubletrap_func = NULL;
1088
1089	/* De-register this DTrace provider. */
1090	if ((error = dtrace_unregister(fbt_id)) != 0)
1091		return (error);
1092
1093	/* Free the probe table. */
1094	free(fbt_probetab, M_FBT);
1095	fbt_probetab = NULL;
1096	fbt_probetab_mask = 0;
1097
1098	destroy_dev(fbt_cdev);
1099
1100	return (error);
1101}
1102
1103static int
1104fbt_modevent(module_t mod __unused, int type, void *data __unused)
1105{
1106	int error = 0;
1107
1108	switch (type) {
1109	case MOD_LOAD:
1110		break;
1111
1112	case MOD_UNLOAD:
1113		break;
1114
1115	case MOD_SHUTDOWN:
1116		break;
1117
1118	default:
1119		error = EOPNOTSUPP;
1120		break;
1121
1122	}
1123
1124	return (error);
1125}
1126
1127static int
1128fbt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused)
1129{
1130	return (0);
1131}
1132
1133SYSINIT(fbt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_load, NULL);
1134SYSUNINIT(fbt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fbt_unload, NULL);
1135
1136DEV_MODULE(fbt, fbt_modevent, NULL);
1137MODULE_VERSION(fbt, 1);
1138MODULE_DEPEND(fbt, dtrace, 1, 1, 1);
1139MODULE_DEPEND(fbt, opensolaris, 1, 1, 1);
1140