xref: /freebsd-src/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c (revision 7bbcbd43c53b49360969ca82b152fd6d971e9055)
16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell  * CDDL HEADER START
36ff6d951SJohn Birrell  *
46ff6d951SJohn Birrell  * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell  * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell  * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell  *
86ff6d951SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell  * See the License for the specific language governing permissions
116ff6d951SJohn Birrell  * and limitations under the License.
126ff6d951SJohn Birrell  *
136ff6d951SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell  *
196ff6d951SJohn Birrell  * CDDL HEADER END
206ff6d951SJohn Birrell  */
216ff6d951SJohn Birrell 
221670a1c2SRui Paulo /*
231670a1c2SRui Paulo  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
241670a1c2SRui Paulo  */
258e648814SRui Paulo /*
268e648814SRui Paulo  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
27273df429SPedro F. Giffuni  * Copyright (c) 2016, Pedro Giffuni.  All rights reserved.
288e648814SRui Paulo  */
296ff6d951SJohn Birrell 
306ff6d951SJohn Birrell #include <sys/types.h>
31bc96366cSSteven Hartland #ifdef illumos
326ff6d951SJohn Birrell #include <sys/modctl.h>
336ff6d951SJohn Birrell #include <sys/kobj.h>
346ff6d951SJohn Birrell #include <sys/kobj_impl.h>
356ff6d951SJohn Birrell #include <sys/sysmacros.h>
366ff6d951SJohn Birrell #include <sys/elf.h>
376ff6d951SJohn Birrell #include <sys/task.h>
38f1e56186SJohn Birrell #else
39f1e56186SJohn Birrell #include <sys/param.h>
40f1e56186SJohn Birrell #include <sys/linker.h>
418436cb81SMark Johnston #include <sys/module.h>
42f1e56186SJohn Birrell #include <sys/stat.h>
43f1e56186SJohn Birrell #endif
446ff6d951SJohn Birrell 
456ff6d951SJohn Birrell #include <unistd.h>
46bc96366cSSteven Hartland #ifdef illumos
476ff6d951SJohn Birrell #include <project.h>
48f1e56186SJohn Birrell #endif
496ff6d951SJohn Birrell #include <strings.h>
506ff6d951SJohn Birrell #include <stdlib.h>
516ff6d951SJohn Birrell #include <libelf.h>
526ff6d951SJohn Birrell #include <limits.h>
536ff6d951SJohn Birrell #include <assert.h>
546ff6d951SJohn Birrell #include <errno.h>
556ff6d951SJohn Birrell #include <dirent.h>
56bc96366cSSteven Hartland #ifndef illumos
57f1e56186SJohn Birrell #include <fcntl.h>
588e648814SRui Paulo #include <libproc_compat.h>
59f1e56186SJohn Birrell #endif
606ff6d951SJohn Birrell 
616ff6d951SJohn Birrell #include <dt_strtab.h>
626ff6d951SJohn Birrell #include <dt_module.h>
636ff6d951SJohn Birrell #include <dt_impl.h>
646ff6d951SJohn Birrell 
656ff6d951SJohn Birrell static const char *dt_module_strtab; /* active strtab for qsort callbacks */
666ff6d951SJohn Birrell 
676ff6d951SJohn Birrell static void
686ff6d951SJohn Birrell dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id)
696ff6d951SJohn Birrell {
706ff6d951SJohn Birrell 	dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree];
716ff6d951SJohn Birrell 	uint_t h;
726ff6d951SJohn Birrell 
736ff6d951SJohn Birrell 	assert(dmp->dm_symfree < dmp->dm_nsymelems + 1);
746ff6d951SJohn Birrell 
756ff6d951SJohn Birrell 	dsp->ds_symid = id;
766ff6d951SJohn Birrell 	h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
776ff6d951SJohn Birrell 	dsp->ds_next = dmp->dm_symbuckets[h];
786ff6d951SJohn Birrell 	dmp->dm_symbuckets[h] = dmp->dm_symfree++;
796ff6d951SJohn Birrell }
806ff6d951SJohn Birrell 
816ff6d951SJohn Birrell static uint_t
826ff6d951SJohn Birrell dt_module_syminit32(dt_module_t *dmp)
836ff6d951SJohn Birrell {
841670a1c2SRui Paulo #if STT_NUM != (STT_TLS + 1)
851670a1c2SRui Paulo #error "STT_NUM has grown. update dt_module_syminit32()"
861670a1c2SRui Paulo #endif
871670a1c2SRui Paulo 
88f1e56186SJohn Birrell 	Elf32_Sym *sym = dmp->dm_symtab.cts_data;
896ff6d951SJohn Birrell 	const char *base = dmp->dm_strtab.cts_data;
906ff6d951SJohn Birrell 	size_t ss_size = dmp->dm_strtab.cts_size;
916ff6d951SJohn Birrell 	uint_t i, n = dmp->dm_nsymelems;
926ff6d951SJohn Birrell 	uint_t asrsv = 0;
936ff6d951SJohn Birrell 
94556cb98dSAndriy Gapon #if defined(__FreeBSD__)
95556cb98dSAndriy Gapon 	GElf_Ehdr ehdr;
96556cb98dSAndriy Gapon 	int is_elf_obj;
97556cb98dSAndriy Gapon 
98556cb98dSAndriy Gapon 	gelf_getehdr(dmp->dm_elf, &ehdr);
99556cb98dSAndriy Gapon 	is_elf_obj = (ehdr.e_type == ET_REL);
100556cb98dSAndriy Gapon #endif
101556cb98dSAndriy Gapon 
1026ff6d951SJohn Birrell 	for (i = 0; i < n; i++, sym++) {
1036ff6d951SJohn Birrell 		const char *name = base + sym->st_name;
1046ff6d951SJohn Birrell 		uchar_t type = ELF32_ST_TYPE(sym->st_info);
1056ff6d951SJohn Birrell 
1066ff6d951SJohn Birrell 		if (type >= STT_NUM || type == STT_SECTION)
1076ff6d951SJohn Birrell 			continue; /* skip sections and unknown types */
1086ff6d951SJohn Birrell 
1096ff6d951SJohn Birrell 		if (sym->st_name == 0 || sym->st_name >= ss_size)
1106ff6d951SJohn Birrell 			continue; /* skip null or invalid names */
1116ff6d951SJohn Birrell 
1126ff6d951SJohn Birrell 		if (sym->st_value != 0 &&
113f1e56186SJohn Birrell 		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
1146ff6d951SJohn Birrell 			asrsv++; /* reserve space in the address map */
1156ff6d951SJohn Birrell 
116556cb98dSAndriy Gapon #if defined(__FreeBSD__)
117f1e56186SJohn Birrell 			sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
118556cb98dSAndriy Gapon 			if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
119556cb98dSAndriy Gapon 			    sym->st_shndx < ehdr.e_shnum)
120556cb98dSAndriy Gapon 				sym->st_value +=
121556cb98dSAndriy Gapon 				    dmp->dm_sec_offsets[sym->st_shndx];
122f1e56186SJohn Birrell #endif
123f1e56186SJohn Birrell 		}
124f1e56186SJohn Birrell 
1256ff6d951SJohn Birrell 		dt_module_symhash_insert(dmp, name, i);
1266ff6d951SJohn Birrell 	}
1276ff6d951SJohn Birrell 
1286ff6d951SJohn Birrell 	return (asrsv);
1296ff6d951SJohn Birrell }
1306ff6d951SJohn Birrell 
1316ff6d951SJohn Birrell static uint_t
1326ff6d951SJohn Birrell dt_module_syminit64(dt_module_t *dmp)
1336ff6d951SJohn Birrell {
1341670a1c2SRui Paulo #if STT_NUM != (STT_TLS + 1)
1351670a1c2SRui Paulo #error "STT_NUM has grown. update dt_module_syminit64()"
1361670a1c2SRui Paulo #endif
1371670a1c2SRui Paulo 
138f1e56186SJohn Birrell 	Elf64_Sym *sym = dmp->dm_symtab.cts_data;
1396ff6d951SJohn Birrell 	const char *base = dmp->dm_strtab.cts_data;
1406ff6d951SJohn Birrell 	size_t ss_size = dmp->dm_strtab.cts_size;
1416ff6d951SJohn Birrell 	uint_t i, n = dmp->dm_nsymelems;
1426ff6d951SJohn Birrell 	uint_t asrsv = 0;
1436ff6d951SJohn Birrell 
144556cb98dSAndriy Gapon #if defined(__FreeBSD__)
145556cb98dSAndriy Gapon 	GElf_Ehdr ehdr;
146556cb98dSAndriy Gapon 	int is_elf_obj;
147556cb98dSAndriy Gapon 
148556cb98dSAndriy Gapon 	gelf_getehdr(dmp->dm_elf, &ehdr);
149556cb98dSAndriy Gapon 	is_elf_obj = (ehdr.e_type == ET_REL);
150556cb98dSAndriy Gapon #endif
151556cb98dSAndriy Gapon 
1526ff6d951SJohn Birrell 	for (i = 0; i < n; i++, sym++) {
1536ff6d951SJohn Birrell 		const char *name = base + sym->st_name;
1546ff6d951SJohn Birrell 		uchar_t type = ELF64_ST_TYPE(sym->st_info);
1556ff6d951SJohn Birrell 
1566ff6d951SJohn Birrell 		if (type >= STT_NUM || type == STT_SECTION)
1576ff6d951SJohn Birrell 			continue; /* skip sections and unknown types */
1586ff6d951SJohn Birrell 
1596ff6d951SJohn Birrell 		if (sym->st_name == 0 || sym->st_name >= ss_size)
1606ff6d951SJohn Birrell 			continue; /* skip null or invalid names */
1616ff6d951SJohn Birrell 
1626ff6d951SJohn Birrell 		if (sym->st_value != 0 &&
163f1e56186SJohn Birrell 		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
1646ff6d951SJohn Birrell 			asrsv++; /* reserve space in the address map */
165556cb98dSAndriy Gapon #if defined(__FreeBSD__)
166f1e56186SJohn Birrell 			sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
167556cb98dSAndriy Gapon 			if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
168556cb98dSAndriy Gapon 			    sym->st_shndx < ehdr.e_shnum)
169556cb98dSAndriy Gapon 				sym->st_value +=
170556cb98dSAndriy Gapon 				    dmp->dm_sec_offsets[sym->st_shndx];
171f1e56186SJohn Birrell #endif
172f1e56186SJohn Birrell 		}
173f1e56186SJohn Birrell 
1746ff6d951SJohn Birrell 		dt_module_symhash_insert(dmp, name, i);
1756ff6d951SJohn Birrell 	}
1766ff6d951SJohn Birrell 
1776ff6d951SJohn Birrell 	return (asrsv);
1786ff6d951SJohn Birrell }
1796ff6d951SJohn Birrell 
1806ff6d951SJohn Birrell /*
1816ff6d951SJohn Birrell  * Sort comparison function for 32-bit symbol address-to-name lookups.  We sort
1826ff6d951SJohn Birrell  * symbols by value.  If values are equal, we prefer the symbol that is
1836ff6d951SJohn Birrell  * non-zero sized, typed, not weak, or lexically first, in that order.
1846ff6d951SJohn Birrell  */
1856ff6d951SJohn Birrell static int
1866ff6d951SJohn Birrell dt_module_symcomp32(const void *lp, const void *rp)
1876ff6d951SJohn Birrell {
1886ff6d951SJohn Birrell 	Elf32_Sym *lhs = *((Elf32_Sym **)lp);
1896ff6d951SJohn Birrell 	Elf32_Sym *rhs = *((Elf32_Sym **)rp);
1906ff6d951SJohn Birrell 
1916ff6d951SJohn Birrell 	if (lhs->st_value != rhs->st_value)
1926ff6d951SJohn Birrell 		return (lhs->st_value > rhs->st_value ? 1 : -1);
1936ff6d951SJohn Birrell 
1946ff6d951SJohn Birrell 	if ((lhs->st_size == 0) != (rhs->st_size == 0))
1956ff6d951SJohn Birrell 		return (lhs->st_size == 0 ? 1 : -1);
1966ff6d951SJohn Birrell 
1976ff6d951SJohn Birrell 	if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
1986ff6d951SJohn Birrell 	    (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE))
1996ff6d951SJohn Birrell 		return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
2006ff6d951SJohn Birrell 
2016ff6d951SJohn Birrell 	if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) !=
2026ff6d951SJohn Birrell 	    (ELF32_ST_BIND(rhs->st_info) == STB_WEAK))
2036ff6d951SJohn Birrell 		return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
2046ff6d951SJohn Birrell 
2056ff6d951SJohn Birrell 	return (strcmp(dt_module_strtab + lhs->st_name,
2066ff6d951SJohn Birrell 	    dt_module_strtab + rhs->st_name));
2076ff6d951SJohn Birrell }
2086ff6d951SJohn Birrell 
2096ff6d951SJohn Birrell /*
2106ff6d951SJohn Birrell  * Sort comparison function for 64-bit symbol address-to-name lookups.  We sort
2116ff6d951SJohn Birrell  * symbols by value.  If values are equal, we prefer the symbol that is
2126ff6d951SJohn Birrell  * non-zero sized, typed, not weak, or lexically first, in that order.
2136ff6d951SJohn Birrell  */
2146ff6d951SJohn Birrell static int
2156ff6d951SJohn Birrell dt_module_symcomp64(const void *lp, const void *rp)
2166ff6d951SJohn Birrell {
2176ff6d951SJohn Birrell 	Elf64_Sym *lhs = *((Elf64_Sym **)lp);
2186ff6d951SJohn Birrell 	Elf64_Sym *rhs = *((Elf64_Sym **)rp);
2196ff6d951SJohn Birrell 
2206ff6d951SJohn Birrell 	if (lhs->st_value != rhs->st_value)
2216ff6d951SJohn Birrell 		return (lhs->st_value > rhs->st_value ? 1 : -1);
2226ff6d951SJohn Birrell 
2236ff6d951SJohn Birrell 	if ((lhs->st_size == 0) != (rhs->st_size == 0))
2246ff6d951SJohn Birrell 		return (lhs->st_size == 0 ? 1 : -1);
2256ff6d951SJohn Birrell 
2266ff6d951SJohn Birrell 	if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
2276ff6d951SJohn Birrell 	    (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE))
2286ff6d951SJohn Birrell 		return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
2296ff6d951SJohn Birrell 
2306ff6d951SJohn Birrell 	if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) !=
2316ff6d951SJohn Birrell 	    (ELF64_ST_BIND(rhs->st_info) == STB_WEAK))
2326ff6d951SJohn Birrell 		return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
2336ff6d951SJohn Birrell 
2346ff6d951SJohn Birrell 	return (strcmp(dt_module_strtab + lhs->st_name,
2356ff6d951SJohn Birrell 	    dt_module_strtab + rhs->st_name));
2366ff6d951SJohn Birrell }
2376ff6d951SJohn Birrell 
2386ff6d951SJohn Birrell static void
2396ff6d951SJohn Birrell dt_module_symsort32(dt_module_t *dmp)
2406ff6d951SJohn Birrell {
2416ff6d951SJohn Birrell 	Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data;
2426ff6d951SJohn Birrell 	Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap;
2436ff6d951SJohn Birrell 	const dt_sym_t *dsp = dmp->dm_symchains + 1;
2446ff6d951SJohn Birrell 	uint_t i, n = dmp->dm_symfree;
2456ff6d951SJohn Birrell 
2466ff6d951SJohn Birrell 	for (i = 1; i < n; i++, dsp++) {
2476ff6d951SJohn Birrell 		Elf32_Sym *sym = symtab + dsp->ds_symid;
2486ff6d951SJohn Birrell 		if (sym->st_value != 0 &&
2496ff6d951SJohn Birrell 		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
2506ff6d951SJohn Birrell 			*sympp++ = sym;
2516ff6d951SJohn Birrell 	}
2526ff6d951SJohn Birrell 
2536ff6d951SJohn Birrell 	dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap);
2546ff6d951SJohn Birrell 	assert(dmp->dm_aslen <= dmp->dm_asrsv);
2556ff6d951SJohn Birrell 
2566ff6d951SJohn Birrell 	dt_module_strtab = dmp->dm_strtab.cts_data;
2576ff6d951SJohn Birrell 	qsort(dmp->dm_asmap, dmp->dm_aslen,
2586ff6d951SJohn Birrell 	    sizeof (Elf32_Sym *), dt_module_symcomp32);
2596ff6d951SJohn Birrell 	dt_module_strtab = NULL;
2606ff6d951SJohn Birrell }
2616ff6d951SJohn Birrell 
2626ff6d951SJohn Birrell static void
2636ff6d951SJohn Birrell dt_module_symsort64(dt_module_t *dmp)
2646ff6d951SJohn Birrell {
2656ff6d951SJohn Birrell 	Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data;
2666ff6d951SJohn Birrell 	Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap;
2676ff6d951SJohn Birrell 	const dt_sym_t *dsp = dmp->dm_symchains + 1;
2686ff6d951SJohn Birrell 	uint_t i, n = dmp->dm_symfree;
2696ff6d951SJohn Birrell 
2706ff6d951SJohn Birrell 	for (i = 1; i < n; i++, dsp++) {
2716ff6d951SJohn Birrell 		Elf64_Sym *sym = symtab + dsp->ds_symid;
2726ff6d951SJohn Birrell 		if (sym->st_value != 0 &&
2736ff6d951SJohn Birrell 		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
2746ff6d951SJohn Birrell 			*sympp++ = sym;
2756ff6d951SJohn Birrell 	}
2766ff6d951SJohn Birrell 
2776ff6d951SJohn Birrell 	dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap);
2786ff6d951SJohn Birrell 	assert(dmp->dm_aslen <= dmp->dm_asrsv);
2796ff6d951SJohn Birrell 
2806ff6d951SJohn Birrell 	dt_module_strtab = dmp->dm_strtab.cts_data;
2816ff6d951SJohn Birrell 	qsort(dmp->dm_asmap, dmp->dm_aslen,
2826ff6d951SJohn Birrell 	    sizeof (Elf64_Sym *), dt_module_symcomp64);
2836ff6d951SJohn Birrell 	dt_module_strtab = NULL;
2846ff6d951SJohn Birrell }
2856ff6d951SJohn Birrell 
2866ff6d951SJohn Birrell static GElf_Sym *
2876ff6d951SJohn Birrell dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst)
2886ff6d951SJohn Birrell {
2896ff6d951SJohn Birrell 	if (dst != NULL) {
2906ff6d951SJohn Birrell 		dst->st_name = src->st_name;
2916ff6d951SJohn Birrell 		dst->st_info = src->st_info;
2926ff6d951SJohn Birrell 		dst->st_other = src->st_other;
2936ff6d951SJohn Birrell 		dst->st_shndx = src->st_shndx;
2946ff6d951SJohn Birrell 		dst->st_value = src->st_value;
2956ff6d951SJohn Birrell 		dst->st_size = src->st_size;
2966ff6d951SJohn Birrell 	}
2976ff6d951SJohn Birrell 
2986ff6d951SJohn Birrell 	return (dst);
2996ff6d951SJohn Birrell }
3006ff6d951SJohn Birrell 
3016ff6d951SJohn Birrell static GElf_Sym *
3026ff6d951SJohn Birrell dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst)
3036ff6d951SJohn Birrell {
3046ff6d951SJohn Birrell 	if (dst != NULL)
3056ff6d951SJohn Birrell 		bcopy(src, dst, sizeof (GElf_Sym));
3066ff6d951SJohn Birrell 
3076ff6d951SJohn Birrell 	return (dst);
3086ff6d951SJohn Birrell }
3096ff6d951SJohn Birrell 
3106ff6d951SJohn Birrell static GElf_Sym *
3116ff6d951SJohn Birrell dt_module_symname32(dt_module_t *dmp, const char *name,
3126ff6d951SJohn Birrell     GElf_Sym *symp, uint_t *idp)
3136ff6d951SJohn Birrell {
3146ff6d951SJohn Birrell 	const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
3156ff6d951SJohn Birrell 	const char *strtab = dmp->dm_strtab.cts_data;
3166ff6d951SJohn Birrell 
3176ff6d951SJohn Birrell 	const Elf32_Sym *sym;
3186ff6d951SJohn Birrell 	const dt_sym_t *dsp;
3196ff6d951SJohn Birrell 	uint_t i, h;
3206ff6d951SJohn Birrell 
3216ff6d951SJohn Birrell 	if (dmp->dm_nsymelems == 0)
3226ff6d951SJohn Birrell 		return (NULL);
3236ff6d951SJohn Birrell 
3246ff6d951SJohn Birrell 	h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
3256ff6d951SJohn Birrell 
3266ff6d951SJohn Birrell 	for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
3276ff6d951SJohn Birrell 		dsp = &dmp->dm_symchains[i];
3286ff6d951SJohn Birrell 		sym = symtab + dsp->ds_symid;
3296ff6d951SJohn Birrell 
3306ff6d951SJohn Birrell 		if (strcmp(name, strtab + sym->st_name) == 0) {
3316ff6d951SJohn Birrell 			if (idp != NULL)
3326ff6d951SJohn Birrell 				*idp = dsp->ds_symid;
3336ff6d951SJohn Birrell 			return (dt_module_symgelf32(sym, symp));
3346ff6d951SJohn Birrell 		}
3356ff6d951SJohn Birrell 	}
3366ff6d951SJohn Birrell 
3376ff6d951SJohn Birrell 	return (NULL);
3386ff6d951SJohn Birrell }
3396ff6d951SJohn Birrell 
3406ff6d951SJohn Birrell static GElf_Sym *
3416ff6d951SJohn Birrell dt_module_symname64(dt_module_t *dmp, const char *name,
3426ff6d951SJohn Birrell     GElf_Sym *symp, uint_t *idp)
3436ff6d951SJohn Birrell {
3446ff6d951SJohn Birrell 	const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
3456ff6d951SJohn Birrell 	const char *strtab = dmp->dm_strtab.cts_data;
3466ff6d951SJohn Birrell 
3476ff6d951SJohn Birrell 	const Elf64_Sym *sym;
3486ff6d951SJohn Birrell 	const dt_sym_t *dsp;
3496ff6d951SJohn Birrell 	uint_t i, h;
3506ff6d951SJohn Birrell 
3516ff6d951SJohn Birrell 	if (dmp->dm_nsymelems == 0)
3526ff6d951SJohn Birrell 		return (NULL);
3536ff6d951SJohn Birrell 
3546ff6d951SJohn Birrell 	h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
3556ff6d951SJohn Birrell 
3566ff6d951SJohn Birrell 	for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
3576ff6d951SJohn Birrell 		dsp = &dmp->dm_symchains[i];
3586ff6d951SJohn Birrell 		sym = symtab + dsp->ds_symid;
3596ff6d951SJohn Birrell 
3606ff6d951SJohn Birrell 		if (strcmp(name, strtab + sym->st_name) == 0) {
3616ff6d951SJohn Birrell 			if (idp != NULL)
3626ff6d951SJohn Birrell 				*idp = dsp->ds_symid;
3636ff6d951SJohn Birrell 			return (dt_module_symgelf64(sym, symp));
3646ff6d951SJohn Birrell 		}
3656ff6d951SJohn Birrell 	}
3666ff6d951SJohn Birrell 
3676ff6d951SJohn Birrell 	return (NULL);
3686ff6d951SJohn Birrell }
3696ff6d951SJohn Birrell 
3706ff6d951SJohn Birrell static GElf_Sym *
3716ff6d951SJohn Birrell dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr,
3726ff6d951SJohn Birrell     GElf_Sym *symp, uint_t *idp)
3736ff6d951SJohn Birrell {
3746ff6d951SJohn Birrell 	const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap;
3756ff6d951SJohn Birrell 	const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
3766ff6d951SJohn Birrell 	const Elf32_Sym *sym;
3776ff6d951SJohn Birrell 
3786ff6d951SJohn Birrell 	uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
3796ff6d951SJohn Birrell 	Elf32_Addr v;
3806ff6d951SJohn Birrell 
3816ff6d951SJohn Birrell 	if (dmp->dm_aslen == 0)
3826ff6d951SJohn Birrell 		return (NULL);
3836ff6d951SJohn Birrell 
3846ff6d951SJohn Birrell 	while (hi - lo > 1) {
3856ff6d951SJohn Birrell 		mid = (lo + hi) / 2;
3866ff6d951SJohn Birrell 		if (addr >= asmap[mid]->st_value)
3876ff6d951SJohn Birrell 			lo = mid;
3886ff6d951SJohn Birrell 		else
3896ff6d951SJohn Birrell 			hi = mid;
3906ff6d951SJohn Birrell 	}
3916ff6d951SJohn Birrell 
3926ff6d951SJohn Birrell 	i = addr < asmap[hi]->st_value ? lo : hi;
3936ff6d951SJohn Birrell 	sym = asmap[i];
3946ff6d951SJohn Birrell 	v = sym->st_value;
3956ff6d951SJohn Birrell 
3966ff6d951SJohn Birrell 	/*
3976ff6d951SJohn Birrell 	 * If the previous entry has the same value, improve our choice.  The
3986ff6d951SJohn Birrell 	 * order of equal-valued symbols is determined by the comparison func.
3996ff6d951SJohn Birrell 	 */
4006ff6d951SJohn Birrell 	while (i-- != 0 && asmap[i]->st_value == v)
4016ff6d951SJohn Birrell 		sym = asmap[i];
4026ff6d951SJohn Birrell 
4036ff6d951SJohn Birrell 	if (addr - sym->st_value < MAX(sym->st_size, 1)) {
4046ff6d951SJohn Birrell 		if (idp != NULL)
4056ff6d951SJohn Birrell 			*idp = (uint_t)(sym - symtab);
4066ff6d951SJohn Birrell 		return (dt_module_symgelf32(sym, symp));
4076ff6d951SJohn Birrell 	}
4086ff6d951SJohn Birrell 
4096ff6d951SJohn Birrell 	return (NULL);
4106ff6d951SJohn Birrell }
4116ff6d951SJohn Birrell 
4126ff6d951SJohn Birrell static GElf_Sym *
4136ff6d951SJohn Birrell dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr,
4146ff6d951SJohn Birrell     GElf_Sym *symp, uint_t *idp)
4156ff6d951SJohn Birrell {
4166ff6d951SJohn Birrell 	const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap;
4176ff6d951SJohn Birrell 	const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
4186ff6d951SJohn Birrell 	const Elf64_Sym *sym;
4196ff6d951SJohn Birrell 
4206ff6d951SJohn Birrell 	uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
4216ff6d951SJohn Birrell 	Elf64_Addr v;
4226ff6d951SJohn Birrell 
4236ff6d951SJohn Birrell 	if (dmp->dm_aslen == 0)
4246ff6d951SJohn Birrell 		return (NULL);
4256ff6d951SJohn Birrell 
4266ff6d951SJohn Birrell 	while (hi - lo > 1) {
4276ff6d951SJohn Birrell 		mid = (lo + hi) / 2;
4286ff6d951SJohn Birrell 		if (addr >= asmap[mid]->st_value)
4296ff6d951SJohn Birrell 			lo = mid;
4306ff6d951SJohn Birrell 		else
4316ff6d951SJohn Birrell 			hi = mid;
4326ff6d951SJohn Birrell 	}
4336ff6d951SJohn Birrell 
4346ff6d951SJohn Birrell 	i = addr < asmap[hi]->st_value ? lo : hi;
4356ff6d951SJohn Birrell 	sym = asmap[i];
4366ff6d951SJohn Birrell 	v = sym->st_value;
4376ff6d951SJohn Birrell 
4386ff6d951SJohn Birrell 	/*
4396ff6d951SJohn Birrell 	 * If the previous entry has the same value, improve our choice.  The
4406ff6d951SJohn Birrell 	 * order of equal-valued symbols is determined by the comparison func.
4416ff6d951SJohn Birrell 	 */
4426ff6d951SJohn Birrell 	while (i-- != 0 && asmap[i]->st_value == v)
4436ff6d951SJohn Birrell 		sym = asmap[i];
4446ff6d951SJohn Birrell 
4456ff6d951SJohn Birrell 	if (addr - sym->st_value < MAX(sym->st_size, 1)) {
4466ff6d951SJohn Birrell 		if (idp != NULL)
4476ff6d951SJohn Birrell 			*idp = (uint_t)(sym - symtab);
4486ff6d951SJohn Birrell 		return (dt_module_symgelf64(sym, symp));
4496ff6d951SJohn Birrell 	}
4506ff6d951SJohn Birrell 
4516ff6d951SJohn Birrell 	return (NULL);
4526ff6d951SJohn Birrell }
4536ff6d951SJohn Birrell 
4546ff6d951SJohn Birrell static const dt_modops_t dt_modops_32 = {
455f6372351SMark Johnston 	.do_syminit = dt_module_syminit32,
456f6372351SMark Johnston 	.do_symsort = dt_module_symsort32,
457f6372351SMark Johnston 	.do_symname = dt_module_symname32,
458f6372351SMark Johnston 	.do_symaddr = dt_module_symaddr32
4596ff6d951SJohn Birrell };
4606ff6d951SJohn Birrell 
4616ff6d951SJohn Birrell static const dt_modops_t dt_modops_64 = {
462f6372351SMark Johnston 	.do_syminit = dt_module_syminit64,
463f6372351SMark Johnston 	.do_symsort = dt_module_symsort64,
464f6372351SMark Johnston 	.do_symname = dt_module_symname64,
465f6372351SMark Johnston 	.do_symaddr = dt_module_symaddr64
4666ff6d951SJohn Birrell };
4676ff6d951SJohn Birrell 
4686ff6d951SJohn Birrell dt_module_t *
4696ff6d951SJohn Birrell dt_module_create(dtrace_hdl_t *dtp, const char *name)
4706ff6d951SJohn Birrell {
4718e648814SRui Paulo 	long pid;
4728e648814SRui Paulo 	char *eptr;
4738e648814SRui Paulo 	dt_ident_t *idp;
4746ff6d951SJohn Birrell 	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
4756ff6d951SJohn Birrell 	dt_module_t *dmp;
4766ff6d951SJohn Birrell 
4776ff6d951SJohn Birrell 	for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
4786ff6d951SJohn Birrell 		if (strcmp(dmp->dm_name, name) == 0)
4796ff6d951SJohn Birrell 			return (dmp);
4806ff6d951SJohn Birrell 	}
4816ff6d951SJohn Birrell 
4826ff6d951SJohn Birrell 	if ((dmp = malloc(sizeof (dt_module_t))) == NULL)
4836ff6d951SJohn Birrell 		return (NULL); /* caller must handle allocation failure */
4846ff6d951SJohn Birrell 
4856ff6d951SJohn Birrell 	bzero(dmp, sizeof (dt_module_t));
4866ff6d951SJohn Birrell 	(void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name));
4876ff6d951SJohn Birrell 	dt_list_append(&dtp->dt_modlist, dmp);
4886ff6d951SJohn Birrell 	dmp->dm_next = dtp->dt_mods[h];
4896ff6d951SJohn Birrell 	dtp->dt_mods[h] = dmp;
4906ff6d951SJohn Birrell 	dtp->dt_nmods++;
4916ff6d951SJohn Birrell 
4926ff6d951SJohn Birrell 	if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
4936ff6d951SJohn Birrell 		dmp->dm_ops = &dt_modops_64;
4946ff6d951SJohn Birrell 	else
4956ff6d951SJohn Birrell 		dmp->dm_ops = &dt_modops_32;
4966ff6d951SJohn Birrell 
4978e648814SRui Paulo 	/*
4988e648814SRui Paulo 	 * Modules for userland processes are special. They always refer to a
4998e648814SRui Paulo 	 * specific process and have a copy of their CTF data from a specific
5008e648814SRui Paulo 	 * instant in time. Any dt_module_t that begins with 'pid' is a module
5018e648814SRui Paulo 	 * for a specific process, much like how any probe description that
5028e648814SRui Paulo 	 * begins with 'pid' is special. pid123 refers to process 123. A module
5038e648814SRui Paulo 	 * that is just 'pid' refers specifically to pid$target. This is
5048e648814SRui Paulo 	 * generally done as D does not currently allow for macros to be
5058e648814SRui Paulo 	 * evaluated when working with types.
5068e648814SRui Paulo 	 */
5078e648814SRui Paulo 	if (strncmp(dmp->dm_name, "pid", 3) == 0) {
5088e648814SRui Paulo 		errno = 0;
5098e648814SRui Paulo 		if (dmp->dm_name[3] == '\0') {
5108e648814SRui Paulo 			idp = dt_idhash_lookup(dtp->dt_macros, "target");
5118e648814SRui Paulo 			if (idp != NULL && idp->di_id != 0)
5128e648814SRui Paulo 				dmp->dm_pid = idp->di_id;
5138e648814SRui Paulo 		} else {
5148e648814SRui Paulo 			pid = strtol(dmp->dm_name + 3, &eptr, 10);
5158e648814SRui Paulo 			if (errno == 0 && *eptr == '\0')
5168e648814SRui Paulo 				dmp->dm_pid = (pid_t)pid;
5178e648814SRui Paulo 			else
5188e648814SRui Paulo 				dt_dprintf("encountered malformed pid "
5198e648814SRui Paulo 				    "module: %s\n", dmp->dm_name);
5208e648814SRui Paulo 		}
5218e648814SRui Paulo 	}
5228e648814SRui Paulo 
5236ff6d951SJohn Birrell 	return (dmp);
5246ff6d951SJohn Birrell }
5256ff6d951SJohn Birrell 
5266ff6d951SJohn Birrell dt_module_t *
5276ff6d951SJohn Birrell dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name)
5286ff6d951SJohn Birrell {
5296ff6d951SJohn Birrell 	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
5306ff6d951SJohn Birrell 	dt_module_t *dmp;
5316ff6d951SJohn Birrell 
5326ff6d951SJohn Birrell 	for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
5336ff6d951SJohn Birrell 		if (strcmp(dmp->dm_name, name) == 0)
5346ff6d951SJohn Birrell 			return (dmp);
5356ff6d951SJohn Birrell 	}
5366ff6d951SJohn Birrell 
5376ff6d951SJohn Birrell 	return (NULL);
5386ff6d951SJohn Birrell }
5396ff6d951SJohn Birrell 
5406ff6d951SJohn Birrell /*ARGSUSED*/
5416ff6d951SJohn Birrell dt_module_t *
5426ff6d951SJohn Birrell dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp)
5436ff6d951SJohn Birrell {
5446ff6d951SJohn Birrell 	return (ctfp ? ctf_getspecific(ctfp) : NULL);
5456ff6d951SJohn Birrell }
5466ff6d951SJohn Birrell 
5478436cb81SMark Johnston #ifdef __FreeBSD__
5488436cb81SMark Johnston dt_kmodule_t *
5498436cb81SMark Johnston dt_kmodule_lookup(dtrace_hdl_t *dtp, const char *name)
5508436cb81SMark Johnston {
5518436cb81SMark Johnston 	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
5528436cb81SMark Johnston 	dt_kmodule_t *dkmp;
5538436cb81SMark Johnston 
5548436cb81SMark Johnston 	for (dkmp = dtp->dt_kmods[h]; dkmp != NULL; dkmp = dkmp->dkm_next) {
5558436cb81SMark Johnston 		if (strcmp(dkmp->dkm_name, name) == 0)
5568436cb81SMark Johnston 			return (dkmp);
5578436cb81SMark Johnston 	}
5588436cb81SMark Johnston 
5598436cb81SMark Johnston 	return (NULL);
5608436cb81SMark Johnston }
5618436cb81SMark Johnston #endif
5628436cb81SMark Johnston 
5636ff6d951SJohn Birrell static int
5646ff6d951SJohn Birrell dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
5656ff6d951SJohn Birrell {
5666ff6d951SJohn Birrell 	const char *s;
5676ff6d951SJohn Birrell 	size_t shstrs;
5686ff6d951SJohn Birrell 	GElf_Shdr sh;
5696ff6d951SJohn Birrell 	Elf_Data *dp;
5706ff6d951SJohn Birrell 	Elf_Scn *sp;
5716ff6d951SJohn Birrell 
5721670a1c2SRui Paulo 	if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1)
5736ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_NOTLOADED));
5746ff6d951SJohn Birrell 
5756ff6d951SJohn Birrell 	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
5766ff6d951SJohn Birrell 		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
5776ff6d951SJohn Birrell 		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
5786ff6d951SJohn Birrell 			continue; /* skip any malformed sections */
5796ff6d951SJohn Birrell 
5806ff6d951SJohn Birrell 		if (sh.sh_type == ctsp->cts_type &&
5816ff6d951SJohn Birrell 		    sh.sh_entsize == ctsp->cts_entsize &&
5826ff6d951SJohn Birrell 		    strcmp(s, ctsp->cts_name) == 0)
5836ff6d951SJohn Birrell 			break; /* section matches specification */
5846ff6d951SJohn Birrell 	}
5856ff6d951SJohn Birrell 
5866ff6d951SJohn Birrell 	/*
5876ff6d951SJohn Birrell 	 * If the section isn't found, return success but leave cts_data set
5886ff6d951SJohn Birrell 	 * to NULL and cts_size set to zero for our caller.
5896ff6d951SJohn Birrell 	 */
5906ff6d951SJohn Birrell 	if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
5916ff6d951SJohn Birrell 		return (0);
5926ff6d951SJohn Birrell 
593bc96366cSSteven Hartland #ifdef illumos
5946ff6d951SJohn Birrell 	ctsp->cts_data = dp->d_buf;
595f1e56186SJohn Birrell #else
596f1e56186SJohn Birrell 	if ((ctsp->cts_data = malloc(dp->d_size)) == NULL)
597f1e56186SJohn Birrell 		return (0);
598f1e56186SJohn Birrell 	memcpy(ctsp->cts_data, dp->d_buf, dp->d_size);
599f1e56186SJohn Birrell #endif
6006ff6d951SJohn Birrell 	ctsp->cts_size = dp->d_size;
6016ff6d951SJohn Birrell 
6026ff6d951SJohn Birrell 	dt_dprintf("loaded %s [%s] (%lu bytes)\n",
6036ff6d951SJohn Birrell 	    dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size);
6046ff6d951SJohn Birrell 
6056ff6d951SJohn Birrell 	return (0);
6066ff6d951SJohn Birrell }
6076ff6d951SJohn Birrell 
6088e648814SRui Paulo typedef struct dt_module_cb_arg {
6098e648814SRui Paulo 	struct ps_prochandle *dpa_proc;
6108e648814SRui Paulo 	dtrace_hdl_t *dpa_dtp;
6118e648814SRui Paulo 	dt_module_t *dpa_dmp;
6128e648814SRui Paulo 	uint_t dpa_count;
6138e648814SRui Paulo } dt_module_cb_arg_t;
6148e648814SRui Paulo 
6158e648814SRui Paulo /* ARGSUSED */
6168e648814SRui Paulo static int
6178e648814SRui Paulo dt_module_load_proc_count(void *arg, const prmap_t *prmap, const char *obj)
6188e648814SRui Paulo {
6198e648814SRui Paulo 	ctf_file_t *fp;
6208e648814SRui Paulo 	dt_module_cb_arg_t *dcp = arg;
6218e648814SRui Paulo 
6228e648814SRui Paulo 	/* Try to grab a ctf container if it exists */
6238e648814SRui Paulo 	fp = Pname_to_ctf(dcp->dpa_proc, obj);
6248e648814SRui Paulo 	if (fp != NULL)
6258e648814SRui Paulo 		dcp->dpa_count++;
6268e648814SRui Paulo 	return (0);
6278e648814SRui Paulo }
6288e648814SRui Paulo 
6298e648814SRui Paulo /* ARGSUSED */
6308e648814SRui Paulo static int
6318e648814SRui Paulo dt_module_load_proc_build(void *arg, const prmap_t *prmap, const char *obj)
6328e648814SRui Paulo {
6338e648814SRui Paulo 	ctf_file_t *fp;
6348e648814SRui Paulo 	char buf[MAXPATHLEN], *p;
6358e648814SRui Paulo 	dt_module_cb_arg_t *dcp = arg;
6368e648814SRui Paulo 	int count = dcp->dpa_count;
6378e648814SRui Paulo 	Lmid_t lmid;
6388e648814SRui Paulo 
6398e648814SRui Paulo 	fp = Pname_to_ctf(dcp->dpa_proc, obj);
6408e648814SRui Paulo 	if (fp == NULL)
6418e648814SRui Paulo 		return (0);
6428e648814SRui Paulo 	fp = ctf_dup(fp);
6438e648814SRui Paulo 	if (fp == NULL)
6448e648814SRui Paulo 		return (0);
6458e648814SRui Paulo 	dcp->dpa_dmp->dm_libctfp[count] = fp;
6468e648814SRui Paulo 	/*
6478e648814SRui Paulo 	 * While it'd be nice to simply use objname here, because of our prior
6488e648814SRui Paulo 	 * actions we'll always get a resolved object name to its on disk file.
6498e648814SRui Paulo 	 * Like the pid provider, we need to tell a bit of a lie here. The type
6508e648814SRui Paulo 	 * that the user thinks of is in terms of the libraries they requested,
6518e648814SRui Paulo 	 * eg. libc.so.1, they don't care about the fact that it's
6528e648814SRui Paulo 	 * libc_hwcap.so.1.
6538e648814SRui Paulo 	 */
6548e648814SRui Paulo 	(void) Pobjname(dcp->dpa_proc, prmap->pr_vaddr, buf, sizeof (buf));
6558e648814SRui Paulo 	if ((p = strrchr(buf, '/')) == NULL)
6568e648814SRui Paulo 		p = buf;
6578e648814SRui Paulo 	else
6588e648814SRui Paulo 		p++;
6598e648814SRui Paulo 
6608e648814SRui Paulo 	/*
6618e648814SRui Paulo 	 * If for some reason we can't find a link map id for this module, which
6628e648814SRui Paulo 	 * would be really quite weird. We instead just say the link map id is
6638e648814SRui Paulo 	 * zero.
6648e648814SRui Paulo 	 */
6658e648814SRui Paulo 	if (Plmid(dcp->dpa_proc, prmap->pr_vaddr, &lmid) != 0)
6668e648814SRui Paulo 		lmid = 0;
6678e648814SRui Paulo 
6688e648814SRui Paulo 	if (lmid == 0)
6698e648814SRui Paulo 		dcp->dpa_dmp->dm_libctfn[count] = strdup(p);
6708e648814SRui Paulo 	else
6718e648814SRui Paulo 		(void) asprintf(&dcp->dpa_dmp->dm_libctfn[count],
6728e648814SRui Paulo 		    "LM%x`%s", lmid, p);
6738e648814SRui Paulo 	if (dcp->dpa_dmp->dm_libctfn[count] == NULL)
6748e648814SRui Paulo 		return (1);
6758e648814SRui Paulo 	ctf_setspecific(fp, dcp->dpa_dmp);
6768e648814SRui Paulo 	dcp->dpa_count++;
6778e648814SRui Paulo 	return (0);
6788e648814SRui Paulo }
6798e648814SRui Paulo 
6808e648814SRui Paulo /*
6818e648814SRui Paulo  * We've been asked to load data that belongs to another process. As such we're
6828e648814SRui Paulo  * going to pgrab it at this instant, load everything that we might ever care
6838e648814SRui Paulo  * about, and then drive on. The reason for this is that the process that we're
6848e648814SRui Paulo  * interested in might be changing. As long as we have grabbed it, then this
6858e648814SRui Paulo  * can't be a problem for us.
6868e648814SRui Paulo  *
6878e648814SRui Paulo  * For now, we're actually going to punt on most things and just try to get CTF
6888e648814SRui Paulo  * data, nothing else. Basically this is only useful as a source of type
6898e648814SRui Paulo  * information, we can't go and do the stacktrace lookups, etc.
6908e648814SRui Paulo  */
6918e648814SRui Paulo static int
6928e648814SRui Paulo dt_module_load_proc(dtrace_hdl_t *dtp, dt_module_t *dmp)
6938e648814SRui Paulo {
6948e648814SRui Paulo 	struct ps_prochandle *p;
6958e648814SRui Paulo 	dt_module_cb_arg_t arg;
6968e648814SRui Paulo 
6978e648814SRui Paulo 	/*
6988e648814SRui Paulo 	 * Note that on success we do not release this hold. We must hold this
6998e648814SRui Paulo 	 * for our life time.
7008e648814SRui Paulo 	 */
7018e648814SRui Paulo 	p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
7028e648814SRui Paulo 	if (p == NULL) {
7038e648814SRui Paulo 		dt_dprintf("failed to grab pid: %d\n", (int)dmp->dm_pid);
7048e648814SRui Paulo 		return (dt_set_errno(dtp, EDT_CANTLOAD));
7058e648814SRui Paulo 	}
7068e648814SRui Paulo 	dt_proc_lock(dtp, p);
7078e648814SRui Paulo 
7088e648814SRui Paulo 	arg.dpa_proc = p;
7098e648814SRui Paulo 	arg.dpa_dtp = dtp;
7108e648814SRui Paulo 	arg.dpa_dmp = dmp;
7118e648814SRui Paulo 	arg.dpa_count = 0;
7128e648814SRui Paulo 	if (Pobject_iter_resolved(p, dt_module_load_proc_count, &arg) != 0) {
7138e648814SRui Paulo 		dt_dprintf("failed to iterate objects\n");
714f7d5087aSMark Johnston 		dt_proc_unlock(dtp, p);
7158e648814SRui Paulo 		dt_proc_release(dtp, p);
7168e648814SRui Paulo 		return (dt_set_errno(dtp, EDT_CANTLOAD));
7178e648814SRui Paulo 	}
7188e648814SRui Paulo 
7198e648814SRui Paulo 	if (arg.dpa_count == 0) {
7208e648814SRui Paulo 		dt_dprintf("no ctf data present\n");
7218e648814SRui Paulo 		dt_proc_unlock(dtp, p);
7228e648814SRui Paulo 		dt_proc_release(dtp, p);
7238e648814SRui Paulo 		return (dt_set_errno(dtp, EDT_CANTLOAD));
7248e648814SRui Paulo 	}
7258e648814SRui Paulo 
726273df429SPedro F. Giffuni 	dmp->dm_libctfp = calloc(arg.dpa_count, sizeof (ctf_file_t *));
7278e648814SRui Paulo 	if (dmp->dm_libctfp == NULL) {
7288e648814SRui Paulo 		dt_proc_unlock(dtp, p);
7298e648814SRui Paulo 		dt_proc_release(dtp, p);
7308e648814SRui Paulo 		return (dt_set_errno(dtp, EDT_NOMEM));
7318e648814SRui Paulo 	}
7328e648814SRui Paulo 
733273df429SPedro F. Giffuni 	dmp->dm_libctfn = calloc(arg.dpa_count, sizeof (char *));
7348e648814SRui Paulo 	if (dmp->dm_libctfn == NULL) {
7358e648814SRui Paulo 		free(dmp->dm_libctfp);
7368e648814SRui Paulo 		dt_proc_unlock(dtp, p);
7378e648814SRui Paulo 		dt_proc_release(dtp, p);
7388e648814SRui Paulo 		return (dt_set_errno(dtp, EDT_NOMEM));
7398e648814SRui Paulo 	}
7408e648814SRui Paulo 
7418e648814SRui Paulo 	dmp->dm_nctflibs = arg.dpa_count;
7428e648814SRui Paulo 
7438e648814SRui Paulo 	arg.dpa_count = 0;
7448e648814SRui Paulo 	if (Pobject_iter_resolved(p, dt_module_load_proc_build, &arg) != 0) {
7458e648814SRui Paulo 		dt_proc_unlock(dtp, p);
7468e648814SRui Paulo 		dt_module_unload(dtp, dmp);
7478e648814SRui Paulo 		dt_proc_release(dtp, p);
7488e648814SRui Paulo 		return (dt_set_errno(dtp, EDT_CANTLOAD));
7498e648814SRui Paulo 	}
7508e648814SRui Paulo 	assert(arg.dpa_count == dmp->dm_nctflibs);
7518e648814SRui Paulo 	dt_dprintf("loaded %d ctf modules for pid %d\n", arg.dpa_count,
7528e648814SRui Paulo 	    (int)dmp->dm_pid);
7538e648814SRui Paulo 
7548e648814SRui Paulo 	dt_proc_unlock(dtp, p);
7558e648814SRui Paulo 	dt_proc_release(dtp, p);
7568e648814SRui Paulo 	dmp->dm_flags |= DT_DM_LOADED;
7578e648814SRui Paulo 
7588e648814SRui Paulo 	return (0);
7598e648814SRui Paulo }
7608e648814SRui Paulo 
7616ff6d951SJohn Birrell int
7626ff6d951SJohn Birrell dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
7636ff6d951SJohn Birrell {
7646ff6d951SJohn Birrell 	if (dmp->dm_flags & DT_DM_LOADED)
7656ff6d951SJohn Birrell 		return (0); /* module is already loaded */
7666ff6d951SJohn Birrell 
7678e648814SRui Paulo 	if (dmp->dm_pid != 0)
7688e648814SRui Paulo 		return (dt_module_load_proc(dtp, dmp));
7698e648814SRui Paulo 
7706ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_name = ".SUNW_ctf";
7716ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_type = SHT_PROGBITS;
7726ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_flags = 0;
7736ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_data = NULL;
7746ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_size = 0;
7756ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_entsize = 0;
7766ff6d951SJohn Birrell 	dmp->dm_ctdata.cts_offset = 0;
7776ff6d951SJohn Birrell 
7786ff6d951SJohn Birrell 	dmp->dm_symtab.cts_name = ".symtab";
7796ff6d951SJohn Birrell 	dmp->dm_symtab.cts_type = SHT_SYMTAB;
7806ff6d951SJohn Birrell 	dmp->dm_symtab.cts_flags = 0;
7816ff6d951SJohn Birrell 	dmp->dm_symtab.cts_data = NULL;
7826ff6d951SJohn Birrell 	dmp->dm_symtab.cts_size = 0;
7836ff6d951SJohn Birrell 	dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ?
7846ff6d951SJohn Birrell 	    sizeof (Elf64_Sym) : sizeof (Elf32_Sym);
7856ff6d951SJohn Birrell 	dmp->dm_symtab.cts_offset = 0;
7866ff6d951SJohn Birrell 
7876ff6d951SJohn Birrell 	dmp->dm_strtab.cts_name = ".strtab";
7886ff6d951SJohn Birrell 	dmp->dm_strtab.cts_type = SHT_STRTAB;
7896ff6d951SJohn Birrell 	dmp->dm_strtab.cts_flags = 0;
7906ff6d951SJohn Birrell 	dmp->dm_strtab.cts_data = NULL;
7916ff6d951SJohn Birrell 	dmp->dm_strtab.cts_size = 0;
7926ff6d951SJohn Birrell 	dmp->dm_strtab.cts_entsize = 0;
7936ff6d951SJohn Birrell 	dmp->dm_strtab.cts_offset = 0;
7946ff6d951SJohn Birrell 
7956ff6d951SJohn Birrell 	/*
7966ff6d951SJohn Birrell 	 * Attempt to load the module's CTF section, symbol table section, and
7976ff6d951SJohn Birrell 	 * string table section.  Note that modules may not contain CTF data:
7986ff6d951SJohn Birrell 	 * this will result in a successful load_sect but data of size zero.
7996ff6d951SJohn Birrell 	 * We will then fail if dt_module_getctf() is called, as shown below.
8006ff6d951SJohn Birrell 	 */
8016ff6d951SJohn Birrell 	if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 ||
8026ff6d951SJohn Birrell 	    dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 ||
8036ff6d951SJohn Birrell 	    dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) {
8046ff6d951SJohn Birrell 		dt_module_unload(dtp, dmp);
8056ff6d951SJohn Birrell 		return (-1); /* dt_errno is set for us */
8066ff6d951SJohn Birrell 	}
8076ff6d951SJohn Birrell 
8086ff6d951SJohn Birrell 	/*
8096ff6d951SJohn Birrell 	 * Allocate the hash chains and hash buckets for symbol name lookup.
8106ff6d951SJohn Birrell 	 * This is relatively simple since the symbol table is of fixed size
8116ff6d951SJohn Birrell 	 * and is known in advance.  We allocate one extra element since we
8126ff6d951SJohn Birrell 	 * use element indices instead of pointers and zero is our sentinel.
8136ff6d951SJohn Birrell 	 */
8146ff6d951SJohn Birrell 	dmp->dm_nsymelems =
8156ff6d951SJohn Birrell 	    dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize;
8166ff6d951SJohn Birrell 
8176ff6d951SJohn Birrell 	dmp->dm_nsymbuckets = _dtrace_strbuckets;
8186ff6d951SJohn Birrell 	dmp->dm_symfree = 1;		/* first free element is index 1 */
8196ff6d951SJohn Birrell 
820273df429SPedro F. Giffuni 	dmp->dm_symbuckets = calloc(dmp->dm_nsymbuckets, sizeof (uint_t));
821273df429SPedro F. Giffuni 	dmp->dm_symchains = calloc(dmp->dm_nsymelems + 1, sizeof (dt_sym_t));
8226ff6d951SJohn Birrell 
8236ff6d951SJohn Birrell 	if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) {
8246ff6d951SJohn Birrell 		dt_module_unload(dtp, dmp);
8256ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_NOMEM));
8266ff6d951SJohn Birrell 	}
8276ff6d951SJohn Birrell 
8286ff6d951SJohn Birrell 	/*
8296ff6d951SJohn Birrell 	 * Iterate over the symbol table data buffer and insert each symbol
8306ff6d951SJohn Birrell 	 * name into the name hash if the name and type are valid.  Then
8316ff6d951SJohn Birrell 	 * allocate the address map, fill it in, and sort it.
8326ff6d951SJohn Birrell 	 */
8336ff6d951SJohn Birrell 	dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp);
8346ff6d951SJohn Birrell 
8356ff6d951SJohn Birrell 	dt_dprintf("hashed %s [%s] (%u symbols)\n",
8366ff6d951SJohn Birrell 	    dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1);
8376ff6d951SJohn Birrell 
8386ff6d951SJohn Birrell 	if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) {
8396ff6d951SJohn Birrell 		dt_module_unload(dtp, dmp);
8406ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_NOMEM));
8416ff6d951SJohn Birrell 	}
8426ff6d951SJohn Birrell 
8436ff6d951SJohn Birrell 	dmp->dm_ops->do_symsort(dmp);
8446ff6d951SJohn Birrell 
8456ff6d951SJohn Birrell 	dt_dprintf("sorted %s [%s] (%u symbols)\n",
8466ff6d951SJohn Birrell 	    dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen);
8476ff6d951SJohn Birrell 
8486ff6d951SJohn Birrell 	dmp->dm_flags |= DT_DM_LOADED;
8496ff6d951SJohn Birrell 	return (0);
8506ff6d951SJohn Birrell }
8516ff6d951SJohn Birrell 
8528e648814SRui Paulo int
8538e648814SRui Paulo dt_module_hasctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
8548e648814SRui Paulo {
8558e648814SRui Paulo 	if (dmp->dm_pid != 0 && dmp->dm_nctflibs > 0)
8568e648814SRui Paulo 		return (1);
8578e648814SRui Paulo 	return (dt_module_getctf(dtp, dmp) != NULL);
8588e648814SRui Paulo }
8598e648814SRui Paulo 
8606ff6d951SJohn Birrell ctf_file_t *
8616ff6d951SJohn Birrell dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
8626ff6d951SJohn Birrell {
8636ff6d951SJohn Birrell 	const char *parent;
8646ff6d951SJohn Birrell 	dt_module_t *pmp;
8656ff6d951SJohn Birrell 	ctf_file_t *pfp;
8666ff6d951SJohn Birrell 	int model;
8676ff6d951SJohn Birrell 
8686ff6d951SJohn Birrell 	if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0)
8696ff6d951SJohn Birrell 		return (dmp->dm_ctfp);
8706ff6d951SJohn Birrell 
8716ff6d951SJohn Birrell 	if (dmp->dm_ops == &dt_modops_64)
8726ff6d951SJohn Birrell 		model = CTF_MODEL_LP64;
8736ff6d951SJohn Birrell 	else
8746ff6d951SJohn Birrell 		model = CTF_MODEL_ILP32;
8756ff6d951SJohn Birrell 
8766ff6d951SJohn Birrell 	/*
8776ff6d951SJohn Birrell 	 * If the data model of the module does not match our program data
8786ff6d951SJohn Birrell 	 * model, then do not permit CTF from this module to be opened and
8796ff6d951SJohn Birrell 	 * returned to the compiler.  If we support mixed data models in the
8806ff6d951SJohn Birrell 	 * future for combined kernel/user tracing, this can be removed.
8816ff6d951SJohn Birrell 	 */
8826ff6d951SJohn Birrell 	if (dtp->dt_conf.dtc_ctfmodel != model) {
8836ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_DATAMODEL);
8846ff6d951SJohn Birrell 		return (NULL);
8856ff6d951SJohn Birrell 	}
8866ff6d951SJohn Birrell 
8876ff6d951SJohn Birrell 	if (dmp->dm_ctdata.cts_size == 0) {
8886ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_NOCTF);
8896ff6d951SJohn Birrell 		return (NULL);
8906ff6d951SJohn Birrell 	}
8916ff6d951SJohn Birrell 
8926ff6d951SJohn Birrell 	dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata,
8936ff6d951SJohn Birrell 	    &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr);
8946ff6d951SJohn Birrell 
8956ff6d951SJohn Birrell 	if (dmp->dm_ctfp == NULL) {
8966ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_CTF);
8976ff6d951SJohn Birrell 		return (NULL);
8986ff6d951SJohn Birrell 	}
8996ff6d951SJohn Birrell 
9006ff6d951SJohn Birrell 	(void) ctf_setmodel(dmp->dm_ctfp, model);
9016ff6d951SJohn Birrell 	ctf_setspecific(dmp->dm_ctfp, dmp);
9026ff6d951SJohn Birrell 
9036ff6d951SJohn Birrell 	if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) {
9046ff6d951SJohn Birrell 		if ((pmp = dt_module_create(dtp, parent)) == NULL ||
9056ff6d951SJohn Birrell 		    (pfp = dt_module_getctf(dtp, pmp)) == NULL) {
9066ff6d951SJohn Birrell 			if (pmp == NULL)
9076ff6d951SJohn Birrell 				(void) dt_set_errno(dtp, EDT_NOMEM);
9086ff6d951SJohn Birrell 			goto err;
9096ff6d951SJohn Birrell 		}
9106ff6d951SJohn Birrell 
9116ff6d951SJohn Birrell 		if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) {
9126ff6d951SJohn Birrell 			dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
9136ff6d951SJohn Birrell 			(void) dt_set_errno(dtp, EDT_CTF);
9146ff6d951SJohn Birrell 			goto err;
9156ff6d951SJohn Birrell 		}
9166ff6d951SJohn Birrell 	}
9176ff6d951SJohn Birrell 
9186ff6d951SJohn Birrell 	dt_dprintf("loaded CTF container for %s (%p)\n",
9196ff6d951SJohn Birrell 	    dmp->dm_name, (void *)dmp->dm_ctfp);
9206ff6d951SJohn Birrell 
9216ff6d951SJohn Birrell 	return (dmp->dm_ctfp);
9226ff6d951SJohn Birrell 
9236ff6d951SJohn Birrell err:
9246ff6d951SJohn Birrell 	ctf_close(dmp->dm_ctfp);
9256ff6d951SJohn Birrell 	dmp->dm_ctfp = NULL;
9266ff6d951SJohn Birrell 	return (NULL);
9276ff6d951SJohn Birrell }
9286ff6d951SJohn Birrell 
9296ff6d951SJohn Birrell /*ARGSUSED*/
9306ff6d951SJohn Birrell void
9316ff6d951SJohn Birrell dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
9326ff6d951SJohn Birrell {
9338e648814SRui Paulo 	int i;
9348e648814SRui Paulo 
9356ff6d951SJohn Birrell 	ctf_close(dmp->dm_ctfp);
9366ff6d951SJohn Birrell 	dmp->dm_ctfp = NULL;
9376ff6d951SJohn Birrell 
938bc96366cSSteven Hartland #ifndef illumos
939f1e56186SJohn Birrell 	if (dmp->dm_ctdata.cts_data != NULL) {
940f1e56186SJohn Birrell 		free(dmp->dm_ctdata.cts_data);
941f1e56186SJohn Birrell 	}
942f1e56186SJohn Birrell 	if (dmp->dm_symtab.cts_data != NULL) {
943f1e56186SJohn Birrell 		free(dmp->dm_symtab.cts_data);
944f1e56186SJohn Birrell 	}
945f1e56186SJohn Birrell 	if (dmp->dm_strtab.cts_data != NULL) {
946f1e56186SJohn Birrell 		free(dmp->dm_strtab.cts_data);
947f1e56186SJohn Birrell 	}
948f1e56186SJohn Birrell #endif
949f1e56186SJohn Birrell 
9508e648814SRui Paulo 	if (dmp->dm_libctfp != NULL) {
9518e648814SRui Paulo 		for (i = 0; i < dmp->dm_nctflibs; i++) {
9528e648814SRui Paulo 			ctf_close(dmp->dm_libctfp[i]);
9538e648814SRui Paulo 			free(dmp->dm_libctfn[i]);
9548e648814SRui Paulo 		}
9558e648814SRui Paulo 		free(dmp->dm_libctfp);
9568e648814SRui Paulo 		free(dmp->dm_libctfn);
9578e648814SRui Paulo 		dmp->dm_libctfp = NULL;
9588e648814SRui Paulo 		dmp->dm_nctflibs = 0;
9598e648814SRui Paulo 	}
9608e648814SRui Paulo 
9616ff6d951SJohn Birrell 	bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
9626ff6d951SJohn Birrell 	bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
9636ff6d951SJohn Birrell 	bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));
9646ff6d951SJohn Birrell 
9656ff6d951SJohn Birrell 	if (dmp->dm_symbuckets != NULL) {
9666ff6d951SJohn Birrell 		free(dmp->dm_symbuckets);
9676ff6d951SJohn Birrell 		dmp->dm_symbuckets = NULL;
9686ff6d951SJohn Birrell 	}
9696ff6d951SJohn Birrell 
9706ff6d951SJohn Birrell 	if (dmp->dm_symchains != NULL) {
9716ff6d951SJohn Birrell 		free(dmp->dm_symchains);
9726ff6d951SJohn Birrell 		dmp->dm_symchains = NULL;
9736ff6d951SJohn Birrell 	}
9746ff6d951SJohn Birrell 
9756ff6d951SJohn Birrell 	if (dmp->dm_asmap != NULL) {
9766ff6d951SJohn Birrell 		free(dmp->dm_asmap);
9776ff6d951SJohn Birrell 		dmp->dm_asmap = NULL;
9786ff6d951SJohn Birrell 	}
979556cb98dSAndriy Gapon #if defined(__FreeBSD__)
980556cb98dSAndriy Gapon 	if (dmp->dm_sec_offsets != NULL) {
981556cb98dSAndriy Gapon 		free(dmp->dm_sec_offsets);
982556cb98dSAndriy Gapon 		dmp->dm_sec_offsets = NULL;
983556cb98dSAndriy Gapon 	}
984556cb98dSAndriy Gapon #endif
9856ff6d951SJohn Birrell 	dmp->dm_symfree = 0;
9866ff6d951SJohn Birrell 	dmp->dm_nsymbuckets = 0;
9876ff6d951SJohn Birrell 	dmp->dm_nsymelems = 0;
9886ff6d951SJohn Birrell 	dmp->dm_asrsv = 0;
9896ff6d951SJohn Birrell 	dmp->dm_aslen = 0;
9906ff6d951SJohn Birrell 
991f1e56186SJohn Birrell 	dmp->dm_text_va = 0;
9926ff6d951SJohn Birrell 	dmp->dm_text_size = 0;
993f1e56186SJohn Birrell 	dmp->dm_data_va = 0;
9946ff6d951SJohn Birrell 	dmp->dm_data_size = 0;
995f1e56186SJohn Birrell 	dmp->dm_bss_va = 0;
9966ff6d951SJohn Birrell 	dmp->dm_bss_size = 0;
9976ff6d951SJohn Birrell 
9986ff6d951SJohn Birrell 	if (dmp->dm_extern != NULL) {
9996ff6d951SJohn Birrell 		dt_idhash_destroy(dmp->dm_extern);
10006ff6d951SJohn Birrell 		dmp->dm_extern = NULL;
10016ff6d951SJohn Birrell 	}
10026ff6d951SJohn Birrell 
10036ff6d951SJohn Birrell 	(void) elf_end(dmp->dm_elf);
10046ff6d951SJohn Birrell 	dmp->dm_elf = NULL;
10056ff6d951SJohn Birrell 
10068e648814SRui Paulo 	dmp->dm_pid = 0;
10078e648814SRui Paulo 
10086ff6d951SJohn Birrell 	dmp->dm_flags &= ~DT_DM_LOADED;
10096ff6d951SJohn Birrell }
10106ff6d951SJohn Birrell 
10116ff6d951SJohn Birrell void
10126ff6d951SJohn Birrell dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
10136ff6d951SJohn Birrell {
10141670a1c2SRui Paulo 	uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets;
10151670a1c2SRui Paulo 	dt_module_t **dmpp = &dtp->dt_mods[h];
10161670a1c2SRui Paulo 
10176ff6d951SJohn Birrell 	dt_list_delete(&dtp->dt_modlist, dmp);
10186ff6d951SJohn Birrell 	assert(dtp->dt_nmods != 0);
10196ff6d951SJohn Birrell 	dtp->dt_nmods--;
10206ff6d951SJohn Birrell 
10211670a1c2SRui Paulo 	/*
10221670a1c2SRui Paulo 	 * Now remove this module from its hash chain.  We expect to always
10231670a1c2SRui Paulo 	 * find the module on its hash chain, so in this loop we assert that
10241670a1c2SRui Paulo 	 * we don't run off the end of the list.
10251670a1c2SRui Paulo 	 */
10261670a1c2SRui Paulo 	while (*dmpp != dmp) {
10271670a1c2SRui Paulo 		dmpp = &((*dmpp)->dm_next);
10281670a1c2SRui Paulo 		assert(*dmpp != NULL);
10291670a1c2SRui Paulo 	}
10301670a1c2SRui Paulo 
10311670a1c2SRui Paulo 	*dmpp = dmp->dm_next;
10321670a1c2SRui Paulo 
10336ff6d951SJohn Birrell 	dt_module_unload(dtp, dmp);
10346ff6d951SJohn Birrell 	free(dmp);
10356ff6d951SJohn Birrell }
10366ff6d951SJohn Birrell 
10376ff6d951SJohn Birrell /*
10386ff6d951SJohn Birrell  * Insert a new external symbol reference into the specified module.  The new
10396ff6d951SJohn Birrell  * symbol will be marked as undefined and is assigned a symbol index beyond
10406ff6d951SJohn Birrell  * any existing cached symbols from this module.  We use the ident's di_data
10416ff6d951SJohn Birrell  * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol.
10426ff6d951SJohn Birrell  */
10436ff6d951SJohn Birrell dt_ident_t *
10446ff6d951SJohn Birrell dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp,
10456ff6d951SJohn Birrell     const char *name, const dtrace_typeinfo_t *tip)
10466ff6d951SJohn Birrell {
10476ff6d951SJohn Birrell 	dtrace_syminfo_t *sip;
10486ff6d951SJohn Birrell 	dt_ident_t *idp;
10496ff6d951SJohn Birrell 	uint_t id;
10506ff6d951SJohn Birrell 
10516ff6d951SJohn Birrell 	if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create(
10526ff6d951SJohn Birrell 	    "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) {
10536ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_NOMEM);
10546ff6d951SJohn Birrell 		return (NULL);
10556ff6d951SJohn Birrell 	}
10566ff6d951SJohn Birrell 
10576ff6d951SJohn Birrell 	if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) {
10586ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_SYMOFLOW);
10596ff6d951SJohn Birrell 		return (NULL);
10606ff6d951SJohn Birrell 	}
10616ff6d951SJohn Birrell 
10626ff6d951SJohn Birrell 	if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) {
10636ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_NOMEM);
10646ff6d951SJohn Birrell 		return (NULL);
10656ff6d951SJohn Birrell 	}
10666ff6d951SJohn Birrell 
10676ff6d951SJohn Birrell 	idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id,
10686ff6d951SJohn Birrell 	    _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
10696ff6d951SJohn Birrell 
10706ff6d951SJohn Birrell 	if (idp == NULL) {
10716ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, EDT_NOMEM);
10726ff6d951SJohn Birrell 		free(sip);
10736ff6d951SJohn Birrell 		return (NULL);
10746ff6d951SJohn Birrell 	}
10756ff6d951SJohn Birrell 
10766ff6d951SJohn Birrell 	sip->dts_object = dmp->dm_name;
10776ff6d951SJohn Birrell 	sip->dts_name = idp->di_name;
10786ff6d951SJohn Birrell 	sip->dts_id = idp->di_id;
10796ff6d951SJohn Birrell 
10806ff6d951SJohn Birrell 	idp->di_data = sip;
10816ff6d951SJohn Birrell 	idp->di_ctfp = tip->dtt_ctfp;
10826ff6d951SJohn Birrell 	idp->di_type = tip->dtt_type;
10836ff6d951SJohn Birrell 
10846ff6d951SJohn Birrell 	return (idp);
10856ff6d951SJohn Birrell }
10866ff6d951SJohn Birrell 
10876ff6d951SJohn Birrell const char *
10886ff6d951SJohn Birrell dt_module_modelname(dt_module_t *dmp)
10896ff6d951SJohn Birrell {
10906ff6d951SJohn Birrell 	if (dmp->dm_ops == &dt_modops_64)
10916ff6d951SJohn Birrell 		return ("64-bit");
10926ff6d951SJohn Birrell 	else
10936ff6d951SJohn Birrell 		return ("32-bit");
10946ff6d951SJohn Birrell }
10956ff6d951SJohn Birrell 
10968e648814SRui Paulo /* ARGSUSED */
10978e648814SRui Paulo int
10988e648814SRui Paulo dt_module_getlibid(dtrace_hdl_t *dtp, dt_module_t *dmp, const ctf_file_t *fp)
10998e648814SRui Paulo {
11008e648814SRui Paulo 	int i;
11018e648814SRui Paulo 
11028e648814SRui Paulo 	for (i = 0; i < dmp->dm_nctflibs; i++) {
11038e648814SRui Paulo 		if (dmp->dm_libctfp[i] == fp)
11048e648814SRui Paulo 			return (i);
11058e648814SRui Paulo 	}
11068e648814SRui Paulo 
11078e648814SRui Paulo 	return (-1);
11088e648814SRui Paulo }
11098e648814SRui Paulo 
11108e648814SRui Paulo /* ARGSUSED */
11118e648814SRui Paulo ctf_file_t *
11128e648814SRui Paulo dt_module_getctflib(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name)
11138e648814SRui Paulo {
11148e648814SRui Paulo 	int i;
11158e648814SRui Paulo 
11168e648814SRui Paulo 	for (i = 0; i < dmp->dm_nctflibs; i++) {
11178e648814SRui Paulo 		if (strcmp(dmp->dm_libctfn[i], name) == 0)
11188e648814SRui Paulo 			return (dmp->dm_libctfp[i]);
11198e648814SRui Paulo 	}
11208e648814SRui Paulo 
11218e648814SRui Paulo 	return (NULL);
11228e648814SRui Paulo }
11238e648814SRui Paulo 
11246ff6d951SJohn Birrell /*
11256ff6d951SJohn Birrell  * Update our module cache by adding an entry for the specified module 'name'.
11266ff6d951SJohn Birrell  * We create the dt_module_t and populate it using /system/object/<name>/.
1127f1e56186SJohn Birrell  *
1128f1e56186SJohn Birrell  * On FreeBSD, the module name is passed as the full module file name,
1129f1e56186SJohn Birrell  * including the path.
11306ff6d951SJohn Birrell  */
11316ff6d951SJohn Birrell static void
1132f1e56186SJohn Birrell dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
11336ff6d951SJohn Birrell {
11346ff6d951SJohn Birrell 	char fname[MAXPATHLEN];
11356ff6d951SJohn Birrell 	struct stat64 st;
11366ff6d951SJohn Birrell 	int fd, err, bits;
11378436cb81SMark Johnston 	struct module_stat ms;
11388436cb81SMark Johnston 	dt_kmodule_t *dkmp;
11398436cb81SMark Johnston 	uint_t h;
11408436cb81SMark Johnston 	int modid;
11416ff6d951SJohn Birrell 	dt_module_t *dmp;
11426ff6d951SJohn Birrell 	const char *s;
11436ff6d951SJohn Birrell 	size_t shstrs;
11446ff6d951SJohn Birrell 	GElf_Shdr sh;
11456ff6d951SJohn Birrell 	Elf_Data *dp;
11466ff6d951SJohn Birrell 	Elf_Scn *sp;
1147556cb98dSAndriy Gapon 	GElf_Ehdr ehdr;
1148f1e56186SJohn Birrell 	GElf_Phdr ph;
1149f1e56186SJohn Birrell 	char name[MAXPATHLEN];
1150556cb98dSAndriy Gapon 	uintptr_t mapbase, alignmask;
1151f1e56186SJohn Birrell 	int i = 0;
1152556cb98dSAndriy Gapon 	int is_elf_obj;
1153f1e56186SJohn Birrell 
1154f1e56186SJohn Birrell 	(void) strlcpy(name, k_stat->name, sizeof(name));
1155f1e56186SJohn Birrell 	(void) strlcpy(fname, k_stat->pathname, sizeof(fname));
11566ff6d951SJohn Birrell 
11576ff6d951SJohn Birrell 	if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
11586ff6d951SJohn Birrell 	    (dmp = dt_module_create(dtp, name)) == NULL) {
11596ff6d951SJohn Birrell 		dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
11606ff6d951SJohn Birrell 		(void) close(fd);
11616ff6d951SJohn Birrell 		return;
11626ff6d951SJohn Birrell 	}
11636ff6d951SJohn Birrell 
11646265da14SChristos Margiolis 	(void) strlcpy(dmp->dm_file, fname, sizeof(dmp->dm_file));
11656265da14SChristos Margiolis 	dmp->dm_modid = k_stat->id;
11666265da14SChristos Margiolis 
11676ff6d951SJohn Birrell 	/*
11686ff6d951SJohn Birrell 	 * Since the module can unload out from under us (and /system/object
11696ff6d951SJohn Birrell 	 * will return ENOENT), tell libelf to cook the entire file now and
11706ff6d951SJohn Birrell 	 * then close the underlying file descriptor immediately.  If this
11716ff6d951SJohn Birrell 	 * succeeds, we know that we can continue safely using dmp->dm_elf.
11726ff6d951SJohn Birrell 	 */
11736ff6d951SJohn Birrell 	dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL);
11746ff6d951SJohn Birrell 	err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
11756ff6d951SJohn Birrell 	(void) close(fd);
11766ff6d951SJohn Birrell 
11776ff6d951SJohn Birrell 	if (dmp->dm_elf == NULL || err == -1 ||
11781670a1c2SRui Paulo 	    elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) {
11796ff6d951SJohn Birrell 		dt_dprintf("failed to load %s: %s\n",
11806ff6d951SJohn Birrell 		    fname, elf_errmsg(elf_errno()));
11816ff6d951SJohn Birrell 		dt_module_destroy(dtp, dmp);
11826ff6d951SJohn Birrell 		return;
11836ff6d951SJohn Birrell 	}
11846ff6d951SJohn Birrell 
11856ff6d951SJohn Birrell 	switch (gelf_getclass(dmp->dm_elf)) {
11866ff6d951SJohn Birrell 	case ELFCLASS32:
11876ff6d951SJohn Birrell 		dmp->dm_ops = &dt_modops_32;
11886ff6d951SJohn Birrell 		bits = 32;
11896ff6d951SJohn Birrell 		break;
11906ff6d951SJohn Birrell 	case ELFCLASS64:
11916ff6d951SJohn Birrell 		dmp->dm_ops = &dt_modops_64;
11926ff6d951SJohn Birrell 		bits = 64;
11936ff6d951SJohn Birrell 		break;
11946ff6d951SJohn Birrell 	default:
11956ff6d951SJohn Birrell 		dt_dprintf("failed to load %s: unknown ELF class\n", fname);
11966ff6d951SJohn Birrell 		dt_module_destroy(dtp, dmp);
11976ff6d951SJohn Birrell 		return;
11986ff6d951SJohn Birrell 	}
1199556cb98dSAndriy Gapon 	mapbase = (uintptr_t)k_stat->address;
1200556cb98dSAndriy Gapon 	gelf_getehdr(dmp->dm_elf, &ehdr);
1201556cb98dSAndriy Gapon 	is_elf_obj = (ehdr.e_type == ET_REL);
1202556cb98dSAndriy Gapon 	if (is_elf_obj) {
1203556cb98dSAndriy Gapon 		dmp->dm_sec_offsets =
1204556cb98dSAndriy Gapon 		    malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets));
1205556cb98dSAndriy Gapon 		if (dmp->dm_sec_offsets == NULL) {
1206556cb98dSAndriy Gapon 			dt_dprintf("failed to allocate memory\n");
1207556cb98dSAndriy Gapon 			dt_module_destroy(dtp, dmp);
1208556cb98dSAndriy Gapon 			return;
1209556cb98dSAndriy Gapon 		}
1210556cb98dSAndriy Gapon 	}
12116ff6d951SJohn Birrell 	/*
12126ff6d951SJohn Birrell 	 * Iterate over the section headers locating various sections of
12136ff6d951SJohn Birrell 	 * interest and use their attributes to flesh out the dt_module_t.
12146ff6d951SJohn Birrell 	 */
12156ff6d951SJohn Birrell 	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
12166ff6d951SJohn Birrell 		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
12176ff6d951SJohn Birrell 		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
12186ff6d951SJohn Birrell 			continue; /* skip any malformed sections */
1219556cb98dSAndriy Gapon 		if (sh.sh_size == 0)
1220556cb98dSAndriy Gapon 			continue;
1221db4ce668SMark Johnston 		if (sh.sh_type == SHT_PROGBITS || sh.sh_type == SHT_NOBITS) {
1222556cb98dSAndriy Gapon 			alignmask = sh.sh_addralign - 1;
1223556cb98dSAndriy Gapon 			mapbase += alignmask;
1224556cb98dSAndriy Gapon 			mapbase &= ~alignmask;
1225556cb98dSAndriy Gapon 			sh.sh_addr = mapbase;
1226db4ce668SMark Johnston 			if (is_elf_obj)
1227556cb98dSAndriy Gapon 				dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
1228556cb98dSAndriy Gapon 			mapbase += sh.sh_size;
1229556cb98dSAndriy Gapon 		}
12306ff6d951SJohn Birrell 		if (strcmp(s, ".text") == 0) {
12316ff6d951SJohn Birrell 			dmp->dm_text_size = sh.sh_size;
12326ff6d951SJohn Birrell 			dmp->dm_text_va = sh.sh_addr;
12336ff6d951SJohn Birrell 		} else if (strcmp(s, ".data") == 0) {
12346ff6d951SJohn Birrell 			dmp->dm_data_size = sh.sh_size;
12356ff6d951SJohn Birrell 			dmp->dm_data_va = sh.sh_addr;
12366ff6d951SJohn Birrell 		} else if (strcmp(s, ".bss") == 0) {
12376ff6d951SJohn Birrell 			dmp->dm_bss_size = sh.sh_size;
12386ff6d951SJohn Birrell 			dmp->dm_bss_va = sh.sh_addr;
12396ff6d951SJohn Birrell 		} else if (strcmp(s, ".info") == 0 &&
12406ff6d951SJohn Birrell 		    (dp = elf_getdata(sp, NULL)) != NULL) {
12416ff6d951SJohn Birrell 			bcopy(dp->d_buf, &dmp->dm_info,
12426ff6d951SJohn Birrell 			    MIN(sh.sh_size, sizeof (dmp->dm_info)));
12436ff6d951SJohn Birrell 		}
12446ff6d951SJohn Birrell 	}
12456ff6d951SJohn Birrell 
12466ff6d951SJohn Birrell 	dmp->dm_flags |= DT_DM_KERNEL;
1247556cb98dSAndriy Gapon 	/*
1248556cb98dSAndriy Gapon 	 * Include .rodata and special sections into .text.
1249556cb98dSAndriy Gapon 	 * This depends on default section layout produced by GNU ld
1250556cb98dSAndriy Gapon 	 * for ELF objects and libraries:
1251556cb98dSAndriy Gapon 	 * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable]
1252556cb98dSAndriy Gapon 	 */
1253556cb98dSAndriy Gapon 	dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va;
1254*7bbcbd43SMark Johnston 
1255*7bbcbd43SMark Johnston 	if (!is_elf_obj) {
1256f1e56186SJohn Birrell 		/*
1257f1e56186SJohn Birrell 		 * Find the first load section and figure out the relocation
1258f1e56186SJohn Birrell 		 * offset for the symbols. The kernel module will not need
1259f1e56186SJohn Birrell 		 * relocation, but the kernel linker modules will.
1260f1e56186SJohn Birrell 		 */
1261f1e56186SJohn Birrell 		for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) {
1262f1e56186SJohn Birrell 			if (ph.p_type == PT_LOAD) {
1263*7bbcbd43SMark Johnston 				dmp->dm_reloc_offset =
1264*7bbcbd43SMark Johnston 				    k_stat->address - ph.p_vaddr;
1265f1e56186SJohn Birrell 				break;
1266f1e56186SJohn Birrell 			}
1267f1e56186SJohn Birrell 		}
1268*7bbcbd43SMark Johnston 	}
12696ff6d951SJohn Birrell 
12706ff6d951SJohn Birrell 	if (dmp->dm_info.objfs_info_primary)
12716ff6d951SJohn Birrell 		dmp->dm_flags |= DT_DM_PRIMARY;
12726ff6d951SJohn Birrell 
12738436cb81SMark Johnston 	ms.version = sizeof(ms);
12748436cb81SMark Johnston 	for (modid = kldfirstmod(k_stat->id); modid > 0;
12758436cb81SMark Johnston 	    modid = modnext(modid)) {
12768436cb81SMark Johnston 		if (modstat(modid, &ms) != 0) {
12778436cb81SMark Johnston 			dt_dprintf("modstat failed for id %d in %s: %s\n",
12788436cb81SMark Johnston 			    modid, k_stat->name, strerror(errno));
12798436cb81SMark Johnston 			continue;
12808436cb81SMark Johnston 		}
12818436cb81SMark Johnston 		if (dt_kmodule_lookup(dtp, ms.name) != NULL)
12828436cb81SMark Johnston 			continue;
12838436cb81SMark Johnston 
12848436cb81SMark Johnston 		dkmp = malloc(sizeof (*dkmp));
12858436cb81SMark Johnston 		if (dkmp == NULL) {
12868436cb81SMark Johnston 			dt_dprintf("failed to allocate memory\n");
12878436cb81SMark Johnston 			dt_module_destroy(dtp, dmp);
12888436cb81SMark Johnston 			return;
12898436cb81SMark Johnston 		}
12908436cb81SMark Johnston 
12918436cb81SMark Johnston 		h = dt_strtab_hash(ms.name, NULL) % dtp->dt_modbuckets;
12928436cb81SMark Johnston 		dkmp->dkm_next = dtp->dt_kmods[h];
12938436cb81SMark Johnston 		dkmp->dkm_name = strdup(ms.name);
12948436cb81SMark Johnston 		dkmp->dkm_module = dmp;
12958436cb81SMark Johnston 		dtp->dt_kmods[h] = dkmp;
12968436cb81SMark Johnston 	}
12978436cb81SMark Johnston 
12986ff6d951SJohn Birrell 	dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
12996ff6d951SJohn Birrell 	    bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
13006ff6d951SJohn Birrell }
13016ff6d951SJohn Birrell 
13026ff6d951SJohn Birrell /*
13036ff6d951SJohn Birrell  * Unload all the loaded modules and then refresh the module cache with the
13046ff6d951SJohn Birrell  * latest list of loaded modules and their address ranges.
13056ff6d951SJohn Birrell  */
13066ff6d951SJohn Birrell void
13076ff6d951SJohn Birrell dtrace_update(dtrace_hdl_t *dtp)
13086ff6d951SJohn Birrell {
13096ff6d951SJohn Birrell 	dt_module_t *dmp;
13106ff6d951SJohn Birrell 	DIR *dirp;
1311f1e56186SJohn Birrell #if defined(__FreeBSD__)
1312f1e56186SJohn Birrell 	int fileid;
1313f1e56186SJohn Birrell #endif
13146ff6d951SJohn Birrell 
13156ff6d951SJohn Birrell 	for (dmp = dt_list_next(&dtp->dt_modlist);
13166ff6d951SJohn Birrell 	    dmp != NULL; dmp = dt_list_next(dmp))
13176ff6d951SJohn Birrell 		dt_module_unload(dtp, dmp);
13186ff6d951SJohn Birrell 
1319bc96366cSSteven Hartland #ifdef illumos
13206ff6d951SJohn Birrell 	/*
13216ff6d951SJohn Birrell 	 * Open /system/object and attempt to create a libdtrace module for
13226ff6d951SJohn Birrell 	 * each kernel module that is loaded on the current system.
13236ff6d951SJohn Birrell 	 */
13246ff6d951SJohn Birrell 	if (!(dtp->dt_oflags & DTRACE_O_NOSYS) &&
13256ff6d951SJohn Birrell 	    (dirp = opendir(OBJFS_ROOT)) != NULL) {
13266ff6d951SJohn Birrell 		struct dirent *dp;
13276ff6d951SJohn Birrell 
13286ff6d951SJohn Birrell 		while ((dp = readdir(dirp)) != NULL) {
13296ff6d951SJohn Birrell 			if (dp->d_name[0] != '.')
13306ff6d951SJohn Birrell 				dt_module_update(dtp, dp->d_name);
13316ff6d951SJohn Birrell 		}
13326ff6d951SJohn Birrell 
13336ff6d951SJohn Birrell 		(void) closedir(dirp);
13346ff6d951SJohn Birrell 	}
1335f1e56186SJohn Birrell #elif defined(__FreeBSD__)
1336f1e56186SJohn Birrell 	/*
1337f1e56186SJohn Birrell 	 * Use FreeBSD's kernel loader interface to discover what kernel
1338f1e56186SJohn Birrell 	 * modules are loaded and create a libdtrace module for each one.
1339f1e56186SJohn Birrell 	 */
1340f1e56186SJohn Birrell 	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
1341f1e56186SJohn Birrell 		struct kld_file_stat k_stat;
1342f1e56186SJohn Birrell 		k_stat.version = sizeof(k_stat);
1343f1e56186SJohn Birrell 		if (kldstat(fileid, &k_stat) == 0)
1344f1e56186SJohn Birrell 			dt_module_update(dtp, &k_stat);
1345f1e56186SJohn Birrell 	}
1346f1e56186SJohn Birrell #endif
13476ff6d951SJohn Birrell 
13486ff6d951SJohn Birrell 	/*
13496ff6d951SJohn Birrell 	 * Look up all the macro identifiers and set di_id to the latest value.
13506ff6d951SJohn Birrell 	 * This code collaborates with dt_lex.l on the use of di_id.  We will
13516ff6d951SJohn Birrell 	 * need to implement something fancier if we need to support non-ints.
13526ff6d951SJohn Birrell 	 */
13536ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid();
13546ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid();
13556ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid();
13566ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
13576ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
13586ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
1359bc96366cSSteven Hartland #ifdef illumos
13606ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
1361f1e56186SJohn Birrell #endif
13626ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
1363bc96366cSSteven Hartland #ifdef illumos
13646ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
1365f1e56186SJohn Birrell #endif
13666ff6d951SJohn Birrell 	dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();
13676ff6d951SJohn Birrell 
13686ff6d951SJohn Birrell 	/*
13696ff6d951SJohn Birrell 	 * Cache the pointers to the modules representing the base executable
13706ff6d951SJohn Birrell 	 * and the run-time linker in the dtrace client handle. Note that on
13716ff6d951SJohn Birrell 	 * x86 krtld is folded into unix, so if we don't find it, use unix
13726ff6d951SJohn Birrell 	 * instead.
13736ff6d951SJohn Birrell 	 */
13746ff6d951SJohn Birrell 	dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix");
13756ff6d951SJohn Birrell 	dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld");
13766ff6d951SJohn Birrell 	if (dtp->dt_rtld == NULL)
13776ff6d951SJohn Birrell 		dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix");
13786ff6d951SJohn Birrell 
13796ff6d951SJohn Birrell 	/*
13806ff6d951SJohn Birrell 	 * If this is the first time we are initializing the module list,
13816ff6d951SJohn Birrell 	 * remove the module for genunix from the module list and then move it
13826ff6d951SJohn Birrell 	 * to the front of the module list.  We do this so that type and symbol
13836ff6d951SJohn Birrell 	 * queries encounter genunix and thereby optimize for the common case
13846ff6d951SJohn Birrell 	 * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below.
13856ff6d951SJohn Birrell 	 */
13866ff6d951SJohn Birrell 	if (dtp->dt_exec != NULL &&
13876ff6d951SJohn Birrell 	    dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) {
13886ff6d951SJohn Birrell 		dt_list_delete(&dtp->dt_modlist, dtp->dt_exec);
13896ff6d951SJohn Birrell 		dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec);
13906ff6d951SJohn Birrell 	}
13916ff6d951SJohn Birrell }
13926ff6d951SJohn Birrell 
13936ff6d951SJohn Birrell static dt_module_t *
13946ff6d951SJohn Birrell dt_module_from_object(dtrace_hdl_t *dtp, const char *object)
13956ff6d951SJohn Birrell {
13966ff6d951SJohn Birrell 	int err = EDT_NOMOD;
13976ff6d951SJohn Birrell 	dt_module_t *dmp;
13986ff6d951SJohn Birrell 
13996ff6d951SJohn Birrell 	switch ((uintptr_t)object) {
14006ff6d951SJohn Birrell 	case (uintptr_t)DTRACE_OBJ_EXEC:
14016ff6d951SJohn Birrell 		dmp = dtp->dt_exec;
14026ff6d951SJohn Birrell 		break;
14036ff6d951SJohn Birrell 	case (uintptr_t)DTRACE_OBJ_RTLD:
14046ff6d951SJohn Birrell 		dmp = dtp->dt_rtld;
14056ff6d951SJohn Birrell 		break;
14066ff6d951SJohn Birrell 	case (uintptr_t)DTRACE_OBJ_CDEFS:
14076ff6d951SJohn Birrell 		dmp = dtp->dt_cdefs;
14086ff6d951SJohn Birrell 		break;
14096ff6d951SJohn Birrell 	case (uintptr_t)DTRACE_OBJ_DDEFS:
14106ff6d951SJohn Birrell 		dmp = dtp->dt_ddefs;
14116ff6d951SJohn Birrell 		break;
14126ff6d951SJohn Birrell 	default:
14136ff6d951SJohn Birrell 		dmp = dt_module_create(dtp, object);
14146ff6d951SJohn Birrell 		err = EDT_NOMEM;
14156ff6d951SJohn Birrell 	}
14166ff6d951SJohn Birrell 
14176ff6d951SJohn Birrell 	if (dmp == NULL)
14186ff6d951SJohn Birrell 		(void) dt_set_errno(dtp, err);
14196ff6d951SJohn Birrell 
14206ff6d951SJohn Birrell 	return (dmp);
14216ff6d951SJohn Birrell }
14226ff6d951SJohn Birrell 
14236ff6d951SJohn Birrell /*
14246ff6d951SJohn Birrell  * Exported interface to look up a symbol by name.  We return the GElf_Sym and
14256ff6d951SJohn Birrell  * complete symbol information for the matching symbol.
14266ff6d951SJohn Birrell  */
14276ff6d951SJohn Birrell int
14286ff6d951SJohn Birrell dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name,
14296ff6d951SJohn Birrell     GElf_Sym *symp, dtrace_syminfo_t *sip)
14306ff6d951SJohn Birrell {
14316ff6d951SJohn Birrell 	dt_module_t *dmp;
14326ff6d951SJohn Birrell 	dt_ident_t *idp;
14336ff6d951SJohn Birrell 	uint_t n, id;
14346ff6d951SJohn Birrell 	GElf_Sym sym;
14356ff6d951SJohn Birrell 
14366ff6d951SJohn Birrell 	uint_t mask = 0; /* mask of dt_module flags to match */
14376ff6d951SJohn Birrell 	uint_t bits = 0; /* flag bits that must be present */
14386ff6d951SJohn Birrell 
14396ff6d951SJohn Birrell 	if (object != DTRACE_OBJ_EVERY &&
14406ff6d951SJohn Birrell 	    object != DTRACE_OBJ_KMODS &&
14416ff6d951SJohn Birrell 	    object != DTRACE_OBJ_UMODS) {
14426ff6d951SJohn Birrell 		if ((dmp = dt_module_from_object(dtp, object)) == NULL)
14436ff6d951SJohn Birrell 			return (-1); /* dt_errno is set for us */
14446ff6d951SJohn Birrell 
14456ff6d951SJohn Birrell 		if (dt_module_load(dtp, dmp) == -1)
14466ff6d951SJohn Birrell 			return (-1); /* dt_errno is set for us */
14476ff6d951SJohn Birrell 		n = 1;
14486ff6d951SJohn Birrell 
14496ff6d951SJohn Birrell 	} else {
14506ff6d951SJohn Birrell 		if (object == DTRACE_OBJ_KMODS)
14516ff6d951SJohn Birrell 			mask = bits = DT_DM_KERNEL;
14526ff6d951SJohn Birrell 		else if (object == DTRACE_OBJ_UMODS)
14536ff6d951SJohn Birrell 			mask = DT_DM_KERNEL;
14546ff6d951SJohn Birrell 
14556ff6d951SJohn Birrell 		dmp = dt_list_next(&dtp->dt_modlist);
14566ff6d951SJohn Birrell 		n = dtp->dt_nmods;
14576ff6d951SJohn Birrell 	}
14586ff6d951SJohn Birrell 
14596ff6d951SJohn Birrell 	if (symp == NULL)
14606ff6d951SJohn Birrell 		symp = &sym;
14616ff6d951SJohn Birrell 
14626ff6d951SJohn Birrell 	for (; n > 0; n--, dmp = dt_list_next(dmp)) {
14636ff6d951SJohn Birrell 		if ((dmp->dm_flags & mask) != bits)
14646ff6d951SJohn Birrell 			continue; /* failed to match required attributes */
14656ff6d951SJohn Birrell 
14666ff6d951SJohn Birrell 		if (dt_module_load(dtp, dmp) == -1)
14676ff6d951SJohn Birrell 			continue; /* failed to load symbol table */
14686ff6d951SJohn Birrell 
14696ff6d951SJohn Birrell 		if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) {
14706ff6d951SJohn Birrell 			if (sip != NULL) {
14716ff6d951SJohn Birrell 				sip->dts_object = dmp->dm_name;
14726ff6d951SJohn Birrell 				sip->dts_name = (const char *)
14736ff6d951SJohn Birrell 				    dmp->dm_strtab.cts_data + symp->st_name;
14746ff6d951SJohn Birrell 				sip->dts_id = id;
14756ff6d951SJohn Birrell 			}
14766ff6d951SJohn Birrell 			return (0);
14776ff6d951SJohn Birrell 		}
14786ff6d951SJohn Birrell 
14796ff6d951SJohn Birrell 		if (dmp->dm_extern != NULL &&
14806ff6d951SJohn Birrell 		    (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) {
14816ff6d951SJohn Birrell 			if (symp != &sym) {
14826ff6d951SJohn Birrell 				symp->st_name = (uintptr_t)idp->di_name;
14836ff6d951SJohn Birrell 				symp->st_info =
14846ff6d951SJohn Birrell 				    GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
14856ff6d951SJohn Birrell 				symp->st_other = 0;
14866ff6d951SJohn Birrell 				symp->st_shndx = SHN_UNDEF;
14876ff6d951SJohn Birrell 				symp->st_value = 0;
14886ff6d951SJohn Birrell 				symp->st_size =
14896ff6d951SJohn Birrell 				    ctf_type_size(idp->di_ctfp, idp->di_type);
14906ff6d951SJohn Birrell 			}
14916ff6d951SJohn Birrell 
14926ff6d951SJohn Birrell 			if (sip != NULL) {
14936ff6d951SJohn Birrell 				sip->dts_object = dmp->dm_name;
14946ff6d951SJohn Birrell 				sip->dts_name = idp->di_name;
14956ff6d951SJohn Birrell 				sip->dts_id = idp->di_id;
14966ff6d951SJohn Birrell 			}
14976ff6d951SJohn Birrell 
14986ff6d951SJohn Birrell 			return (0);
14996ff6d951SJohn Birrell 		}
15006ff6d951SJohn Birrell 	}
15016ff6d951SJohn Birrell 
15026ff6d951SJohn Birrell 	return (dt_set_errno(dtp, EDT_NOSYM));
15036ff6d951SJohn Birrell }
15046ff6d951SJohn Birrell 
15056ff6d951SJohn Birrell /*
15066ff6d951SJohn Birrell  * Exported interface to look up a symbol by address.  We return the GElf_Sym
15076ff6d951SJohn Birrell  * and complete symbol information for the matching symbol.
15086ff6d951SJohn Birrell  */
15096ff6d951SJohn Birrell int
15106ff6d951SJohn Birrell dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr,
15116ff6d951SJohn Birrell     GElf_Sym *symp, dtrace_syminfo_t *sip)
15126ff6d951SJohn Birrell {
15136ff6d951SJohn Birrell 	dt_module_t *dmp;
15146ff6d951SJohn Birrell 	uint_t id;
15156ff6d951SJohn Birrell 	const dtrace_vector_t *v = dtp->dt_vector;
15166ff6d951SJohn Birrell 
15176ff6d951SJohn Birrell 	if (v != NULL)
15186ff6d951SJohn Birrell 		return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip));
15196ff6d951SJohn Birrell 
15206ff6d951SJohn Birrell 	for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
15216ff6d951SJohn Birrell 	    dmp = dt_list_next(dmp)) {
15226ff6d951SJohn Birrell 		if (addr - dmp->dm_text_va < dmp->dm_text_size ||
15236ff6d951SJohn Birrell 		    addr - dmp->dm_data_va < dmp->dm_data_size ||
15246ff6d951SJohn Birrell 		    addr - dmp->dm_bss_va < dmp->dm_bss_size)
15256ff6d951SJohn Birrell 			break;
15266ff6d951SJohn Birrell 	}
15276ff6d951SJohn Birrell 
15286ff6d951SJohn Birrell 	if (dmp == NULL)
15296ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_NOSYMADDR));
15306ff6d951SJohn Birrell 
15316ff6d951SJohn Birrell 	if (dt_module_load(dtp, dmp) == -1)
15326ff6d951SJohn Birrell 		return (-1); /* dt_errno is set for us */
15336ff6d951SJohn Birrell 
15346ff6d951SJohn Birrell 	if (symp != NULL) {
15356ff6d951SJohn Birrell 		if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL)
15366ff6d951SJohn Birrell 			return (dt_set_errno(dtp, EDT_NOSYMADDR));
15376ff6d951SJohn Birrell 	}
15386ff6d951SJohn Birrell 
15396ff6d951SJohn Birrell 	if (sip != NULL) {
15406ff6d951SJohn Birrell 		sip->dts_object = dmp->dm_name;
15416ff6d951SJohn Birrell 
15426ff6d951SJohn Birrell 		if (symp != NULL) {
15436ff6d951SJohn Birrell 			sip->dts_name = (const char *)
15446ff6d951SJohn Birrell 			    dmp->dm_strtab.cts_data + symp->st_name;
15456ff6d951SJohn Birrell 			sip->dts_id = id;
15466ff6d951SJohn Birrell 		} else {
15476ff6d951SJohn Birrell 			sip->dts_name = NULL;
15486ff6d951SJohn Birrell 			sip->dts_id = 0;
15496ff6d951SJohn Birrell 		}
15506ff6d951SJohn Birrell 	}
15516ff6d951SJohn Birrell 
15526ff6d951SJohn Birrell 	return (0);
15536ff6d951SJohn Birrell }
15546ff6d951SJohn Birrell 
15556ff6d951SJohn Birrell int
15566ff6d951SJohn Birrell dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
15576ff6d951SJohn Birrell     dtrace_typeinfo_t *tip)
15586ff6d951SJohn Birrell {
15596ff6d951SJohn Birrell 	dtrace_typeinfo_t ti;
15606ff6d951SJohn Birrell 	dt_module_t *dmp;
15616ff6d951SJohn Birrell 	int found = 0;
15626ff6d951SJohn Birrell 	ctf_id_t id;
15638e648814SRui Paulo 	uint_t n, i;
15646ff6d951SJohn Birrell 	int justone;
15658e648814SRui Paulo 	ctf_file_t *fp;
15668e648814SRui Paulo 	char *buf, *p, *q;
15676ff6d951SJohn Birrell 
15686ff6d951SJohn Birrell 	uint_t mask = 0; /* mask of dt_module flags to match */
15696ff6d951SJohn Birrell 	uint_t bits = 0; /* flag bits that must be present */
15706ff6d951SJohn Birrell 
15716ff6d951SJohn Birrell 	if (object != DTRACE_OBJ_EVERY &&
15726ff6d951SJohn Birrell 	    object != DTRACE_OBJ_KMODS &&
15736ff6d951SJohn Birrell 	    object != DTRACE_OBJ_UMODS) {
15746ff6d951SJohn Birrell 		if ((dmp = dt_module_from_object(dtp, object)) == NULL)
15756ff6d951SJohn Birrell 			return (-1); /* dt_errno is set for us */
15766ff6d951SJohn Birrell 
15776ff6d951SJohn Birrell 		if (dt_module_load(dtp, dmp) == -1)
15786ff6d951SJohn Birrell 			return (-1); /* dt_errno is set for us */
15796ff6d951SJohn Birrell 		n = 1;
15806ff6d951SJohn Birrell 		justone = 1;
15816ff6d951SJohn Birrell 	} else {
15826ff6d951SJohn Birrell 		if (object == DTRACE_OBJ_KMODS)
15836ff6d951SJohn Birrell 			mask = bits = DT_DM_KERNEL;
15846ff6d951SJohn Birrell 		else if (object == DTRACE_OBJ_UMODS)
15856ff6d951SJohn Birrell 			mask = DT_DM_KERNEL;
15866ff6d951SJohn Birrell 
15876ff6d951SJohn Birrell 		dmp = dt_list_next(&dtp->dt_modlist);
15886ff6d951SJohn Birrell 		n = dtp->dt_nmods;
15896ff6d951SJohn Birrell 		justone = 0;
15906ff6d951SJohn Birrell 	}
15916ff6d951SJohn Birrell 
15926ff6d951SJohn Birrell 	if (tip == NULL)
15936ff6d951SJohn Birrell 		tip = &ti;
15946ff6d951SJohn Birrell 
15956ff6d951SJohn Birrell 	for (; n > 0; n--, dmp = dt_list_next(dmp)) {
15966ff6d951SJohn Birrell 		if ((dmp->dm_flags & mask) != bits)
15976ff6d951SJohn Birrell 			continue; /* failed to match required attributes */
15986ff6d951SJohn Birrell 
15996ff6d951SJohn Birrell 		/*
16006ff6d951SJohn Birrell 		 * If we can't load the CTF container, continue on to the next
16016ff6d951SJohn Birrell 		 * module.  If our search was scoped to only one module then
16026ff6d951SJohn Birrell 		 * return immediately leaving dt_errno unmodified.
16036ff6d951SJohn Birrell 		 */
16048e648814SRui Paulo 		if (dt_module_hasctf(dtp, dmp) == 0) {
16056ff6d951SJohn Birrell 			if (justone)
16066ff6d951SJohn Birrell 				return (-1);
16076ff6d951SJohn Birrell 			continue;
16086ff6d951SJohn Birrell 		}
16096ff6d951SJohn Birrell 
16106ff6d951SJohn Birrell 		/*
16116ff6d951SJohn Birrell 		 * Look up the type in the module's CTF container.  If our
16126ff6d951SJohn Birrell 		 * match is a forward declaration tag, save this choice in
16136ff6d951SJohn Birrell 		 * 'tip' and keep going in the hope that we will locate the
16146ff6d951SJohn Birrell 		 * underlying structure definition.  Otherwise just return.
16156ff6d951SJohn Birrell 		 */
16168e648814SRui Paulo 		if (dmp->dm_pid == 0) {
16178e648814SRui Paulo 			id = ctf_lookup_by_name(dmp->dm_ctfp, name);
16188e648814SRui Paulo 			fp = dmp->dm_ctfp;
16198e648814SRui Paulo 		} else {
16208e648814SRui Paulo 			if ((p = strchr(name, '`')) != NULL) {
16218e648814SRui Paulo 				buf = strdup(name);
16228e648814SRui Paulo 				if (buf == NULL)
16238e648814SRui Paulo 					return (dt_set_errno(dtp, EDT_NOMEM));
16248e648814SRui Paulo 				p = strchr(buf, '`');
16258e648814SRui Paulo 				if ((q = strchr(p + 1, '`')) != NULL)
16268e648814SRui Paulo 					p = q;
16278e648814SRui Paulo 				*p = '\0';
16288e648814SRui Paulo 				fp = dt_module_getctflib(dtp, dmp, buf);
16298e648814SRui Paulo 				if (fp == NULL || (id = ctf_lookup_by_name(fp,
16308e648814SRui Paulo 				    p + 1)) == CTF_ERR)
16318e648814SRui Paulo 					id = CTF_ERR;
16328e648814SRui Paulo 				free(buf);
16338e648814SRui Paulo 			} else {
16348e648814SRui Paulo 				for (i = 0; i < dmp->dm_nctflibs; i++) {
16358e648814SRui Paulo 					fp = dmp->dm_libctfp[i];
16368e648814SRui Paulo 					id = ctf_lookup_by_name(fp, name);
16378e648814SRui Paulo 					if (id != CTF_ERR)
16388e648814SRui Paulo 						break;
16398e648814SRui Paulo 				}
16408e648814SRui Paulo 			}
16418e648814SRui Paulo 		}
16428e648814SRui Paulo 		if (id != CTF_ERR) {
16436ff6d951SJohn Birrell 			tip->dtt_object = dmp->dm_name;
16448e648814SRui Paulo 			tip->dtt_ctfp = fp;
16456ff6d951SJohn Birrell 			tip->dtt_type = id;
16468e648814SRui Paulo 			if (ctf_type_kind(fp, ctf_type_resolve(fp, id)) !=
16478e648814SRui Paulo 			    CTF_K_FORWARD)
16486ff6d951SJohn Birrell 				return (0);
16496ff6d951SJohn Birrell 
16506ff6d951SJohn Birrell 			found++;
16516ff6d951SJohn Birrell 		}
16526ff6d951SJohn Birrell 	}
16536ff6d951SJohn Birrell 
16546ff6d951SJohn Birrell 	if (found == 0)
16556ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_NOTYPE));
16566ff6d951SJohn Birrell 
16576ff6d951SJohn Birrell 	return (0);
16586ff6d951SJohn Birrell }
16596ff6d951SJohn Birrell 
16606ff6d951SJohn Birrell int
16616ff6d951SJohn Birrell dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp,
16626ff6d951SJohn Birrell     const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip)
16636ff6d951SJohn Birrell {
16646ff6d951SJohn Birrell 	dt_module_t *dmp;
16656ff6d951SJohn Birrell 
16666ff6d951SJohn Birrell 	tip->dtt_object = NULL;
16676ff6d951SJohn Birrell 	tip->dtt_ctfp = NULL;
16686ff6d951SJohn Birrell 	tip->dtt_type = CTF_ERR;
16698e648814SRui Paulo 	tip->dtt_flags = 0;
16706ff6d951SJohn Birrell 
16716ff6d951SJohn Birrell 	if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL)
16726ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EDT_NOMOD));
16736ff6d951SJohn Birrell 
16746ff6d951SJohn Birrell 	if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) {
16756ff6d951SJohn Birrell 		dt_ident_t *idp =
16766ff6d951SJohn Birrell 		    dt_idhash_lookup(dmp->dm_extern, sip->dts_name);
16776ff6d951SJohn Birrell 
16786ff6d951SJohn Birrell 		if (idp == NULL)
16796ff6d951SJohn Birrell 			return (dt_set_errno(dtp, EDT_NOSYM));
16806ff6d951SJohn Birrell 
16816ff6d951SJohn Birrell 		tip->dtt_ctfp = idp->di_ctfp;
16826ff6d951SJohn Birrell 		tip->dtt_type = idp->di_type;
16836ff6d951SJohn Birrell 
16846ff6d951SJohn Birrell 	} else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) {
16856ff6d951SJohn Birrell 		if (dt_module_getctf(dtp, dmp) == NULL)
16866ff6d951SJohn Birrell 			return (-1); /* errno is set for us */
16876ff6d951SJohn Birrell 
16886ff6d951SJohn Birrell 		tip->dtt_ctfp = dmp->dm_ctfp;
16896ff6d951SJohn Birrell 		tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id);
16906ff6d951SJohn Birrell 
16916ff6d951SJohn Birrell 		if (tip->dtt_type == CTF_ERR) {
16926ff6d951SJohn Birrell 			dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp);
16936ff6d951SJohn Birrell 			return (dt_set_errno(dtp, EDT_CTF));
16946ff6d951SJohn Birrell 		}
16956ff6d951SJohn Birrell 
16966ff6d951SJohn Birrell 	} else {
16976ff6d951SJohn Birrell 		tip->dtt_ctfp = DT_FPTR_CTFP(dtp);
16986ff6d951SJohn Birrell 		tip->dtt_type = DT_FPTR_TYPE(dtp);
16996ff6d951SJohn Birrell 	}
17006ff6d951SJohn Birrell 
17016ff6d951SJohn Birrell 	tip->dtt_object = dmp->dm_name;
17026ff6d951SJohn Birrell 	return (0);
17036ff6d951SJohn Birrell }
17046ff6d951SJohn Birrell 
17056ff6d951SJohn Birrell static dtrace_objinfo_t *
17066ff6d951SJohn Birrell dt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto)
17076ff6d951SJohn Birrell {
17086ff6d951SJohn Birrell 	dto->dto_name = dmp->dm_name;
17096ff6d951SJohn Birrell 	dto->dto_file = dmp->dm_file;
17106ff6d951SJohn Birrell 	dto->dto_id = dmp->dm_modid;
17116ff6d951SJohn Birrell 	dto->dto_flags = 0;
17126ff6d951SJohn Birrell 
17136ff6d951SJohn Birrell 	if (dmp->dm_flags & DT_DM_KERNEL)
17146ff6d951SJohn Birrell 		dto->dto_flags |= DTRACE_OBJ_F_KERNEL;
17156ff6d951SJohn Birrell 	if (dmp->dm_flags & DT_DM_PRIMARY)
17166ff6d951SJohn Birrell 		dto->dto_flags |= DTRACE_OBJ_F_PRIMARY;
17176ff6d951SJohn Birrell 
17186ff6d951SJohn Birrell 	dto->dto_text_va = dmp->dm_text_va;
17196ff6d951SJohn Birrell 	dto->dto_text_size = dmp->dm_text_size;
17206ff6d951SJohn Birrell 	dto->dto_data_va = dmp->dm_data_va;
17216ff6d951SJohn Birrell 	dto->dto_data_size = dmp->dm_data_size;
17226ff6d951SJohn Birrell 	dto->dto_bss_va = dmp->dm_bss_va;
17236ff6d951SJohn Birrell 	dto->dto_bss_size = dmp->dm_bss_size;
17246ff6d951SJohn Birrell 
17256ff6d951SJohn Birrell 	return (dto);
17266ff6d951SJohn Birrell }
17276ff6d951SJohn Birrell 
17286ff6d951SJohn Birrell int
17296ff6d951SJohn Birrell dtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data)
17306ff6d951SJohn Birrell {
17316ff6d951SJohn Birrell 	const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist);
17326ff6d951SJohn Birrell 	dtrace_objinfo_t dto;
17336ff6d951SJohn Birrell 	int rv;
17346ff6d951SJohn Birrell 
17356ff6d951SJohn Birrell 	for (; dmp != NULL; dmp = dt_list_next(dmp)) {
17366ff6d951SJohn Birrell 		if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0)
17376ff6d951SJohn Birrell 			return (rv);
17386ff6d951SJohn Birrell 	}
17396ff6d951SJohn Birrell 
17406ff6d951SJohn Birrell 	return (0);
17416ff6d951SJohn Birrell }
17426ff6d951SJohn Birrell 
17436ff6d951SJohn Birrell int
17446ff6d951SJohn Birrell dtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto)
17456ff6d951SJohn Birrell {
17466ff6d951SJohn Birrell 	dt_module_t *dmp;
17476ff6d951SJohn Birrell 
17486ff6d951SJohn Birrell 	if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS ||
17496ff6d951SJohn Birrell 	    object == DTRACE_OBJ_UMODS || dto == NULL)
17506ff6d951SJohn Birrell 		return (dt_set_errno(dtp, EINVAL));
17516ff6d951SJohn Birrell 
17526ff6d951SJohn Birrell 	if ((dmp = dt_module_from_object(dtp, object)) == NULL)
17536ff6d951SJohn Birrell 		return (-1); /* dt_errno is set for us */
17546ff6d951SJohn Birrell 
17556ff6d951SJohn Birrell 	if (dt_module_load(dtp, dmp) == -1)
17566ff6d951SJohn Birrell 		return (-1); /* dt_errno is set for us */
17576ff6d951SJohn Birrell 
17586ff6d951SJohn Birrell 	(void) dt_module_info(dmp, dto);
17596ff6d951SJohn Birrell 	return (0);
17606ff6d951SJohn Birrell }
1761