1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21210767Srpaulo
22178479Sjb/*
23210767Srpaulo * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24178479Sjb */
25178479Sjb
26178479Sjb#include <sys/types.h>
27178559Sjb#if defined(sun)
28178479Sjb#include <sys/modctl.h>
29178479Sjb#include <sys/kobj.h>
30178479Sjb#include <sys/kobj_impl.h>
31178479Sjb#include <sys/sysmacros.h>
32178479Sjb#include <sys/elf.h>
33178479Sjb#include <sys/task.h>
34178559Sjb#else
35178559Sjb#include <sys/param.h>
36178559Sjb#include <sys/linker.h>
37178559Sjb#include <sys/stat.h>
38178559Sjb#endif
39178479Sjb
40178479Sjb#include <unistd.h>
41178559Sjb#if defined(sun)
42178479Sjb#include <project.h>
43178559Sjb#endif
44178479Sjb#include <strings.h>
45178479Sjb#include <stdlib.h>
46178479Sjb#include <libelf.h>
47178479Sjb#include <limits.h>
48178479Sjb#include <assert.h>
49178479Sjb#include <errno.h>
50178479Sjb#include <dirent.h>
51178559Sjb#if !defined(sun)
52178559Sjb#include <fcntl.h>
53178559Sjb#endif
54178479Sjb
55178479Sjb#include <dt_strtab.h>
56178479Sjb#include <dt_module.h>
57178479Sjb#include <dt_impl.h>
58178479Sjb
59178479Sjbstatic const char *dt_module_strtab; /* active strtab for qsort callbacks */
60178479Sjb
61178479Sjbstatic void
62178479Sjbdt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id)
63178479Sjb{
64178479Sjb	dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree];
65178479Sjb	uint_t h;
66178479Sjb
67178479Sjb	assert(dmp->dm_symfree < dmp->dm_nsymelems + 1);
68178479Sjb
69178479Sjb	dsp->ds_symid = id;
70178479Sjb	h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
71178479Sjb	dsp->ds_next = dmp->dm_symbuckets[h];
72178479Sjb	dmp->dm_symbuckets[h] = dmp->dm_symfree++;
73178479Sjb}
74178479Sjb
75178479Sjbstatic uint_t
76178479Sjbdt_module_syminit32(dt_module_t *dmp)
77178479Sjb{
78210767Srpaulo#if STT_NUM != (STT_TLS + 1)
79210767Srpaulo#error "STT_NUM has grown. update dt_module_syminit32()"
80210767Srpaulo#endif
81210767Srpaulo
82178559Sjb	Elf32_Sym *sym = dmp->dm_symtab.cts_data;
83178479Sjb	const char *base = dmp->dm_strtab.cts_data;
84178479Sjb	size_t ss_size = dmp->dm_strtab.cts_size;
85178479Sjb	uint_t i, n = dmp->dm_nsymelems;
86178479Sjb	uint_t asrsv = 0;
87178479Sjb
88210425Savg#if defined(__FreeBSD__)
89210425Savg	GElf_Ehdr ehdr;
90210425Savg	int is_elf_obj;
91210425Savg
92210425Savg	gelf_getehdr(dmp->dm_elf, &ehdr);
93210425Savg	is_elf_obj = (ehdr.e_type == ET_REL);
94210425Savg#endif
95210425Savg
96178479Sjb	for (i = 0; i < n; i++, sym++) {
97178479Sjb		const char *name = base + sym->st_name;
98178479Sjb		uchar_t type = ELF32_ST_TYPE(sym->st_info);
99178479Sjb
100178479Sjb		if (type >= STT_NUM || type == STT_SECTION)
101178479Sjb			continue; /* skip sections and unknown types */
102178479Sjb
103178479Sjb		if (sym->st_name == 0 || sym->st_name >= ss_size)
104178479Sjb			continue; /* skip null or invalid names */
105178479Sjb
106178479Sjb		if (sym->st_value != 0 &&
107178559Sjb		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
108178479Sjb			asrsv++; /* reserve space in the address map */
109178479Sjb
110210425Savg#if defined(__FreeBSD__)
111178559Sjb			sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
112210425Savg			if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
113210425Savg			    sym->st_shndx < ehdr.e_shnum)
114210425Savg				sym->st_value +=
115210425Savg				    dmp->dm_sec_offsets[sym->st_shndx];
116178559Sjb#endif
117178559Sjb		}
118178559Sjb
119178479Sjb		dt_module_symhash_insert(dmp, name, i);
120178479Sjb	}
121178479Sjb
122178479Sjb	return (asrsv);
123178479Sjb}
124178479Sjb
125178479Sjbstatic uint_t
126178479Sjbdt_module_syminit64(dt_module_t *dmp)
127178479Sjb{
128210767Srpaulo#if STT_NUM != (STT_TLS + 1)
129210767Srpaulo#error "STT_NUM has grown. update dt_module_syminit64()"
130210767Srpaulo#endif
131210767Srpaulo
132178559Sjb	Elf64_Sym *sym = dmp->dm_symtab.cts_data;
133178479Sjb	const char *base = dmp->dm_strtab.cts_data;
134178479Sjb	size_t ss_size = dmp->dm_strtab.cts_size;
135178479Sjb	uint_t i, n = dmp->dm_nsymelems;
136178479Sjb	uint_t asrsv = 0;
137178479Sjb
138210425Savg#if defined(__FreeBSD__)
139210425Savg	GElf_Ehdr ehdr;
140210425Savg	int is_elf_obj;
141210425Savg
142210425Savg	gelf_getehdr(dmp->dm_elf, &ehdr);
143210425Savg	is_elf_obj = (ehdr.e_type == ET_REL);
144210425Savg#endif
145210425Savg
146178479Sjb	for (i = 0; i < n; i++, sym++) {
147178479Sjb		const char *name = base + sym->st_name;
148178479Sjb		uchar_t type = ELF64_ST_TYPE(sym->st_info);
149178479Sjb
150178479Sjb		if (type >= STT_NUM || type == STT_SECTION)
151178479Sjb			continue; /* skip sections and unknown types */
152178479Sjb
153178479Sjb		if (sym->st_name == 0 || sym->st_name >= ss_size)
154178479Sjb			continue; /* skip null or invalid names */
155178479Sjb
156178479Sjb		if (sym->st_value != 0 &&
157178559Sjb		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) {
158178479Sjb			asrsv++; /* reserve space in the address map */
159210425Savg#if defined(__FreeBSD__)
160178559Sjb			sym->st_value += (Elf_Addr) dmp->dm_reloc_offset;
161210425Savg			if (is_elf_obj && sym->st_shndx != SHN_UNDEF &&
162210425Savg			    sym->st_shndx < ehdr.e_shnum)
163210425Savg				sym->st_value +=
164210425Savg				    dmp->dm_sec_offsets[sym->st_shndx];
165178559Sjb#endif
166178559Sjb		}
167178559Sjb
168178479Sjb		dt_module_symhash_insert(dmp, name, i);
169178479Sjb	}
170178479Sjb
171178479Sjb	return (asrsv);
172178479Sjb}
173178479Sjb
174178479Sjb/*
175178479Sjb * Sort comparison function for 32-bit symbol address-to-name lookups.  We sort
176178479Sjb * symbols by value.  If values are equal, we prefer the symbol that is
177178479Sjb * non-zero sized, typed, not weak, or lexically first, in that order.
178178479Sjb */
179178479Sjbstatic int
180178479Sjbdt_module_symcomp32(const void *lp, const void *rp)
181178479Sjb{
182178479Sjb	Elf32_Sym *lhs = *((Elf32_Sym **)lp);
183178479Sjb	Elf32_Sym *rhs = *((Elf32_Sym **)rp);
184178479Sjb
185178479Sjb	if (lhs->st_value != rhs->st_value)
186178479Sjb		return (lhs->st_value > rhs->st_value ? 1 : -1);
187178479Sjb
188178479Sjb	if ((lhs->st_size == 0) != (rhs->st_size == 0))
189178479Sjb		return (lhs->st_size == 0 ? 1 : -1);
190178479Sjb
191178479Sjb	if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
192178479Sjb	    (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE))
193178479Sjb		return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
194178479Sjb
195178479Sjb	if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) !=
196178479Sjb	    (ELF32_ST_BIND(rhs->st_info) == STB_WEAK))
197178479Sjb		return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
198178479Sjb
199178479Sjb	return (strcmp(dt_module_strtab + lhs->st_name,
200178479Sjb	    dt_module_strtab + rhs->st_name));
201178479Sjb}
202178479Sjb
203178479Sjb/*
204178479Sjb * Sort comparison function for 64-bit symbol address-to-name lookups.  We sort
205178479Sjb * symbols by value.  If values are equal, we prefer the symbol that is
206178479Sjb * non-zero sized, typed, not weak, or lexically first, in that order.
207178479Sjb */
208178479Sjbstatic int
209178479Sjbdt_module_symcomp64(const void *lp, const void *rp)
210178479Sjb{
211178479Sjb	Elf64_Sym *lhs = *((Elf64_Sym **)lp);
212178479Sjb	Elf64_Sym *rhs = *((Elf64_Sym **)rp);
213178479Sjb
214178479Sjb	if (lhs->st_value != rhs->st_value)
215178479Sjb		return (lhs->st_value > rhs->st_value ? 1 : -1);
216178479Sjb
217178479Sjb	if ((lhs->st_size == 0) != (rhs->st_size == 0))
218178479Sjb		return (lhs->st_size == 0 ? 1 : -1);
219178479Sjb
220178479Sjb	if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) !=
221178479Sjb	    (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE))
222178479Sjb		return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1);
223178479Sjb
224178479Sjb	if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) !=
225178479Sjb	    (ELF64_ST_BIND(rhs->st_info) == STB_WEAK))
226178479Sjb		return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1);
227178479Sjb
228178479Sjb	return (strcmp(dt_module_strtab + lhs->st_name,
229178479Sjb	    dt_module_strtab + rhs->st_name));
230178479Sjb}
231178479Sjb
232178479Sjbstatic void
233178479Sjbdt_module_symsort32(dt_module_t *dmp)
234178479Sjb{
235178479Sjb	Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data;
236178479Sjb	Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap;
237178479Sjb	const dt_sym_t *dsp = dmp->dm_symchains + 1;
238178479Sjb	uint_t i, n = dmp->dm_symfree;
239178479Sjb
240178479Sjb	for (i = 1; i < n; i++, dsp++) {
241178479Sjb		Elf32_Sym *sym = symtab + dsp->ds_symid;
242178479Sjb		if (sym->st_value != 0 &&
243178479Sjb		    (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
244178479Sjb			*sympp++ = sym;
245178479Sjb	}
246178479Sjb
247178479Sjb	dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap);
248178479Sjb	assert(dmp->dm_aslen <= dmp->dm_asrsv);
249178479Sjb
250178479Sjb	dt_module_strtab = dmp->dm_strtab.cts_data;
251178479Sjb	qsort(dmp->dm_asmap, dmp->dm_aslen,
252178479Sjb	    sizeof (Elf32_Sym *), dt_module_symcomp32);
253178479Sjb	dt_module_strtab = NULL;
254178479Sjb}
255178479Sjb
256178479Sjbstatic void
257178479Sjbdt_module_symsort64(dt_module_t *dmp)
258178479Sjb{
259178479Sjb	Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data;
260178479Sjb	Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap;
261178479Sjb	const dt_sym_t *dsp = dmp->dm_symchains + 1;
262178479Sjb	uint_t i, n = dmp->dm_symfree;
263178479Sjb
264178479Sjb	for (i = 1; i < n; i++, dsp++) {
265178479Sjb		Elf64_Sym *sym = symtab + dsp->ds_symid;
266178479Sjb		if (sym->st_value != 0 &&
267178479Sjb		    (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size))
268178479Sjb			*sympp++ = sym;
269178479Sjb	}
270178479Sjb
271178479Sjb	dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap);
272178479Sjb	assert(dmp->dm_aslen <= dmp->dm_asrsv);
273178479Sjb
274178479Sjb	dt_module_strtab = dmp->dm_strtab.cts_data;
275178479Sjb	qsort(dmp->dm_asmap, dmp->dm_aslen,
276178479Sjb	    sizeof (Elf64_Sym *), dt_module_symcomp64);
277178479Sjb	dt_module_strtab = NULL;
278178479Sjb}
279178479Sjb
280178479Sjbstatic GElf_Sym *
281178479Sjbdt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst)
282178479Sjb{
283178479Sjb	if (dst != NULL) {
284178479Sjb		dst->st_name = src->st_name;
285178479Sjb		dst->st_info = src->st_info;
286178479Sjb		dst->st_other = src->st_other;
287178479Sjb		dst->st_shndx = src->st_shndx;
288178479Sjb		dst->st_value = src->st_value;
289178479Sjb		dst->st_size = src->st_size;
290178479Sjb	}
291178479Sjb
292178479Sjb	return (dst);
293178479Sjb}
294178479Sjb
295178479Sjbstatic GElf_Sym *
296178479Sjbdt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst)
297178479Sjb{
298178479Sjb	if (dst != NULL)
299178479Sjb		bcopy(src, dst, sizeof (GElf_Sym));
300178479Sjb
301178479Sjb	return (dst);
302178479Sjb}
303178479Sjb
304178479Sjbstatic GElf_Sym *
305178479Sjbdt_module_symname32(dt_module_t *dmp, const char *name,
306178479Sjb    GElf_Sym *symp, uint_t *idp)
307178479Sjb{
308178479Sjb	const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
309178479Sjb	const char *strtab = dmp->dm_strtab.cts_data;
310178479Sjb
311178479Sjb	const Elf32_Sym *sym;
312178479Sjb	const dt_sym_t *dsp;
313178479Sjb	uint_t i, h;
314178479Sjb
315178479Sjb	if (dmp->dm_nsymelems == 0)
316178479Sjb		return (NULL);
317178479Sjb
318178479Sjb	h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
319178479Sjb
320178479Sjb	for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
321178479Sjb		dsp = &dmp->dm_symchains[i];
322178479Sjb		sym = symtab + dsp->ds_symid;
323178479Sjb
324178479Sjb		if (strcmp(name, strtab + sym->st_name) == 0) {
325178479Sjb			if (idp != NULL)
326178479Sjb				*idp = dsp->ds_symid;
327178479Sjb			return (dt_module_symgelf32(sym, symp));
328178479Sjb		}
329178479Sjb	}
330178479Sjb
331178479Sjb	return (NULL);
332178479Sjb}
333178479Sjb
334178479Sjbstatic GElf_Sym *
335178479Sjbdt_module_symname64(dt_module_t *dmp, const char *name,
336178479Sjb    GElf_Sym *symp, uint_t *idp)
337178479Sjb{
338178479Sjb	const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
339178479Sjb	const char *strtab = dmp->dm_strtab.cts_data;
340178479Sjb
341178479Sjb	const Elf64_Sym *sym;
342178479Sjb	const dt_sym_t *dsp;
343178479Sjb	uint_t i, h;
344178479Sjb
345178479Sjb	if (dmp->dm_nsymelems == 0)
346178479Sjb		return (NULL);
347178479Sjb
348178479Sjb	h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets;
349178479Sjb
350178479Sjb	for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) {
351178479Sjb		dsp = &dmp->dm_symchains[i];
352178479Sjb		sym = symtab + dsp->ds_symid;
353178479Sjb
354178479Sjb		if (strcmp(name, strtab + sym->st_name) == 0) {
355178479Sjb			if (idp != NULL)
356178479Sjb				*idp = dsp->ds_symid;
357178479Sjb			return (dt_module_symgelf64(sym, symp));
358178479Sjb		}
359178479Sjb	}
360178479Sjb
361178479Sjb	return (NULL);
362178479Sjb}
363178479Sjb
364178479Sjbstatic GElf_Sym *
365178479Sjbdt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr,
366178479Sjb    GElf_Sym *symp, uint_t *idp)
367178479Sjb{
368178479Sjb	const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap;
369178479Sjb	const Elf32_Sym *symtab = dmp->dm_symtab.cts_data;
370178479Sjb	const Elf32_Sym *sym;
371178479Sjb
372178479Sjb	uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
373178479Sjb	Elf32_Addr v;
374178479Sjb
375178479Sjb	if (dmp->dm_aslen == 0)
376178479Sjb		return (NULL);
377178479Sjb
378178479Sjb	while (hi - lo > 1) {
379178479Sjb		mid = (lo + hi) / 2;
380178479Sjb		if (addr >= asmap[mid]->st_value)
381178479Sjb			lo = mid;
382178479Sjb		else
383178479Sjb			hi = mid;
384178479Sjb	}
385178479Sjb
386178479Sjb	i = addr < asmap[hi]->st_value ? lo : hi;
387178479Sjb	sym = asmap[i];
388178479Sjb	v = sym->st_value;
389178479Sjb
390178479Sjb	/*
391178479Sjb	 * If the previous entry has the same value, improve our choice.  The
392178479Sjb	 * order of equal-valued symbols is determined by the comparison func.
393178479Sjb	 */
394178479Sjb	while (i-- != 0 && asmap[i]->st_value == v)
395178479Sjb		sym = asmap[i];
396178479Sjb
397178479Sjb	if (addr - sym->st_value < MAX(sym->st_size, 1)) {
398178479Sjb		if (idp != NULL)
399178479Sjb			*idp = (uint_t)(sym - symtab);
400178479Sjb		return (dt_module_symgelf32(sym, symp));
401178479Sjb	}
402178479Sjb
403178479Sjb	return (NULL);
404178479Sjb}
405178479Sjb
406178479Sjbstatic GElf_Sym *
407178479Sjbdt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr,
408178479Sjb    GElf_Sym *symp, uint_t *idp)
409178479Sjb{
410178479Sjb	const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap;
411178479Sjb	const Elf64_Sym *symtab = dmp->dm_symtab.cts_data;
412178479Sjb	const Elf64_Sym *sym;
413178479Sjb
414178479Sjb	uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1;
415178479Sjb	Elf64_Addr v;
416178479Sjb
417178479Sjb	if (dmp->dm_aslen == 0)
418178479Sjb		return (NULL);
419178479Sjb
420178479Sjb	while (hi - lo > 1) {
421178479Sjb		mid = (lo + hi) / 2;
422178479Sjb		if (addr >= asmap[mid]->st_value)
423178479Sjb			lo = mid;
424178479Sjb		else
425178479Sjb			hi = mid;
426178479Sjb	}
427178479Sjb
428178479Sjb	i = addr < asmap[hi]->st_value ? lo : hi;
429178479Sjb	sym = asmap[i];
430178479Sjb	v = sym->st_value;
431178479Sjb
432178479Sjb	/*
433178479Sjb	 * If the previous entry has the same value, improve our choice.  The
434178479Sjb	 * order of equal-valued symbols is determined by the comparison func.
435178479Sjb	 */
436178479Sjb	while (i-- != 0 && asmap[i]->st_value == v)
437178479Sjb		sym = asmap[i];
438178479Sjb
439178479Sjb	if (addr - sym->st_value < MAX(sym->st_size, 1)) {
440178479Sjb		if (idp != NULL)
441178479Sjb			*idp = (uint_t)(sym - symtab);
442178479Sjb		return (dt_module_symgelf64(sym, symp));
443178479Sjb	}
444178479Sjb
445178479Sjb	return (NULL);
446178479Sjb}
447178479Sjb
448178479Sjbstatic const dt_modops_t dt_modops_32 = {
449178479Sjb	dt_module_syminit32,
450178479Sjb	dt_module_symsort32,
451178479Sjb	dt_module_symname32,
452178479Sjb	dt_module_symaddr32
453178479Sjb};
454178479Sjb
455178479Sjbstatic const dt_modops_t dt_modops_64 = {
456178479Sjb	dt_module_syminit64,
457178479Sjb	dt_module_symsort64,
458178479Sjb	dt_module_symname64,
459178479Sjb	dt_module_symaddr64
460178479Sjb};
461178479Sjb
462178479Sjbdt_module_t *
463178479Sjbdt_module_create(dtrace_hdl_t *dtp, const char *name)
464178479Sjb{
465178479Sjb	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
466178479Sjb	dt_module_t *dmp;
467178479Sjb
468178479Sjb	for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
469178479Sjb		if (strcmp(dmp->dm_name, name) == 0)
470178479Sjb			return (dmp);
471178479Sjb	}
472178479Sjb
473178479Sjb	if ((dmp = malloc(sizeof (dt_module_t))) == NULL)
474178479Sjb		return (NULL); /* caller must handle allocation failure */
475178479Sjb
476178479Sjb	bzero(dmp, sizeof (dt_module_t));
477178479Sjb	(void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name));
478178479Sjb	dt_list_append(&dtp->dt_modlist, dmp);
479178479Sjb	dmp->dm_next = dtp->dt_mods[h];
480178479Sjb	dtp->dt_mods[h] = dmp;
481178479Sjb	dtp->dt_nmods++;
482178479Sjb
483178479Sjb	if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
484178479Sjb		dmp->dm_ops = &dt_modops_64;
485178479Sjb	else
486178479Sjb		dmp->dm_ops = &dt_modops_32;
487178479Sjb
488178479Sjb	return (dmp);
489178479Sjb}
490178479Sjb
491178479Sjbdt_module_t *
492178479Sjbdt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name)
493178479Sjb{
494178479Sjb	uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets;
495178479Sjb	dt_module_t *dmp;
496178479Sjb
497178479Sjb	for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) {
498178479Sjb		if (strcmp(dmp->dm_name, name) == 0)
499178479Sjb			return (dmp);
500178479Sjb	}
501178479Sjb
502178479Sjb	return (NULL);
503178479Sjb}
504178479Sjb
505178479Sjb/*ARGSUSED*/
506178479Sjbdt_module_t *
507178479Sjbdt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp)
508178479Sjb{
509178479Sjb	return (ctfp ? ctf_getspecific(ctfp) : NULL);
510178479Sjb}
511178479Sjb
512178479Sjbstatic int
513178479Sjbdt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp)
514178479Sjb{
515178479Sjb	const char *s;
516178479Sjb	size_t shstrs;
517178479Sjb	GElf_Shdr sh;
518178479Sjb	Elf_Data *dp;
519178479Sjb	Elf_Scn *sp;
520178479Sjb
521210767Srpaulo	if (elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1)
522178479Sjb		return (dt_set_errno(dtp, EDT_NOTLOADED));
523178479Sjb
524178479Sjb	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
525178479Sjb		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
526178479Sjb		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
527178479Sjb			continue; /* skip any malformed sections */
528178479Sjb
529178479Sjb		if (sh.sh_type == ctsp->cts_type &&
530178479Sjb		    sh.sh_entsize == ctsp->cts_entsize &&
531178479Sjb		    strcmp(s, ctsp->cts_name) == 0)
532178479Sjb			break; /* section matches specification */
533178479Sjb	}
534178479Sjb
535178479Sjb	/*
536178479Sjb	 * If the section isn't found, return success but leave cts_data set
537178479Sjb	 * to NULL and cts_size set to zero for our caller.
538178479Sjb	 */
539178479Sjb	if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL)
540178479Sjb		return (0);
541178479Sjb
542178559Sjb#if defined(sun)
543178479Sjb	ctsp->cts_data = dp->d_buf;
544178559Sjb#else
545178559Sjb	if ((ctsp->cts_data = malloc(dp->d_size)) == NULL)
546178559Sjb		return (0);
547178559Sjb	memcpy(ctsp->cts_data, dp->d_buf, dp->d_size);
548178559Sjb#endif
549178479Sjb	ctsp->cts_size = dp->d_size;
550178479Sjb
551178479Sjb	dt_dprintf("loaded %s [%s] (%lu bytes)\n",
552178479Sjb	    dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size);
553178479Sjb
554178479Sjb	return (0);
555178479Sjb}
556178479Sjb
557178479Sjbint
558178479Sjbdt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
559178479Sjb{
560178479Sjb	if (dmp->dm_flags & DT_DM_LOADED)
561178479Sjb		return (0); /* module is already loaded */
562178479Sjb
563178479Sjb	dmp->dm_ctdata.cts_name = ".SUNW_ctf";
564178479Sjb	dmp->dm_ctdata.cts_type = SHT_PROGBITS;
565178479Sjb	dmp->dm_ctdata.cts_flags = 0;
566178479Sjb	dmp->dm_ctdata.cts_data = NULL;
567178479Sjb	dmp->dm_ctdata.cts_size = 0;
568178479Sjb	dmp->dm_ctdata.cts_entsize = 0;
569178479Sjb	dmp->dm_ctdata.cts_offset = 0;
570178479Sjb
571178479Sjb	dmp->dm_symtab.cts_name = ".symtab";
572178479Sjb	dmp->dm_symtab.cts_type = SHT_SYMTAB;
573178479Sjb	dmp->dm_symtab.cts_flags = 0;
574178479Sjb	dmp->dm_symtab.cts_data = NULL;
575178479Sjb	dmp->dm_symtab.cts_size = 0;
576178479Sjb	dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ?
577178479Sjb	    sizeof (Elf64_Sym) : sizeof (Elf32_Sym);
578178479Sjb	dmp->dm_symtab.cts_offset = 0;
579178479Sjb
580178479Sjb	dmp->dm_strtab.cts_name = ".strtab";
581178479Sjb	dmp->dm_strtab.cts_type = SHT_STRTAB;
582178479Sjb	dmp->dm_strtab.cts_flags = 0;
583178479Sjb	dmp->dm_strtab.cts_data = NULL;
584178479Sjb	dmp->dm_strtab.cts_size = 0;
585178479Sjb	dmp->dm_strtab.cts_entsize = 0;
586178479Sjb	dmp->dm_strtab.cts_offset = 0;
587178479Sjb
588178479Sjb	/*
589178479Sjb	 * Attempt to load the module's CTF section, symbol table section, and
590178479Sjb	 * string table section.  Note that modules may not contain CTF data:
591178479Sjb	 * this will result in a successful load_sect but data of size zero.
592178479Sjb	 * We will then fail if dt_module_getctf() is called, as shown below.
593178479Sjb	 */
594178479Sjb	if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 ||
595178479Sjb	    dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 ||
596178479Sjb	    dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) {
597178479Sjb		dt_module_unload(dtp, dmp);
598178479Sjb		return (-1); /* dt_errno is set for us */
599178479Sjb	}
600178479Sjb
601178479Sjb	/*
602178479Sjb	 * Allocate the hash chains and hash buckets for symbol name lookup.
603178479Sjb	 * This is relatively simple since the symbol table is of fixed size
604178479Sjb	 * and is known in advance.  We allocate one extra element since we
605178479Sjb	 * use element indices instead of pointers and zero is our sentinel.
606178479Sjb	 */
607178479Sjb	dmp->dm_nsymelems =
608178479Sjb	    dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize;
609178479Sjb
610178479Sjb	dmp->dm_nsymbuckets = _dtrace_strbuckets;
611178479Sjb	dmp->dm_symfree = 1;		/* first free element is index 1 */
612178479Sjb
613178479Sjb	dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets);
614178479Sjb	dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);
615178479Sjb
616178479Sjb	if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) {
617178479Sjb		dt_module_unload(dtp, dmp);
618178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
619178479Sjb	}
620178479Sjb
621178479Sjb	bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets);
622178479Sjb	bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1);
623178479Sjb
624178479Sjb	/*
625178479Sjb	 * Iterate over the symbol table data buffer and insert each symbol
626178479Sjb	 * name into the name hash if the name and type are valid.  Then
627178479Sjb	 * allocate the address map, fill it in, and sort it.
628178479Sjb	 */
629178479Sjb	dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp);
630178479Sjb
631178479Sjb	dt_dprintf("hashed %s [%s] (%u symbols)\n",
632178479Sjb	    dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1);
633178479Sjb
634178479Sjb	if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) {
635178479Sjb		dt_module_unload(dtp, dmp);
636178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
637178479Sjb	}
638178479Sjb
639178479Sjb	dmp->dm_ops->do_symsort(dmp);
640178479Sjb
641178479Sjb	dt_dprintf("sorted %s [%s] (%u symbols)\n",
642178479Sjb	    dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen);
643178479Sjb
644178479Sjb	dmp->dm_flags |= DT_DM_LOADED;
645178479Sjb	return (0);
646178479Sjb}
647178479Sjb
648178479Sjbctf_file_t *
649178479Sjbdt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
650178479Sjb{
651178479Sjb	const char *parent;
652178479Sjb	dt_module_t *pmp;
653178479Sjb	ctf_file_t *pfp;
654178479Sjb	int model;
655178479Sjb
656178479Sjb	if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0)
657178479Sjb		return (dmp->dm_ctfp);
658178479Sjb
659178479Sjb	if (dmp->dm_ops == &dt_modops_64)
660178479Sjb		model = CTF_MODEL_LP64;
661178479Sjb	else
662178479Sjb		model = CTF_MODEL_ILP32;
663178479Sjb
664178479Sjb	/*
665178479Sjb	 * If the data model of the module does not match our program data
666178479Sjb	 * model, then do not permit CTF from this module to be opened and
667178479Sjb	 * returned to the compiler.  If we support mixed data models in the
668178479Sjb	 * future for combined kernel/user tracing, this can be removed.
669178479Sjb	 */
670178479Sjb	if (dtp->dt_conf.dtc_ctfmodel != model) {
671178479Sjb		(void) dt_set_errno(dtp, EDT_DATAMODEL);
672178479Sjb		return (NULL);
673178479Sjb	}
674178479Sjb
675178479Sjb	if (dmp->dm_ctdata.cts_size == 0) {
676178479Sjb		(void) dt_set_errno(dtp, EDT_NOCTF);
677178479Sjb		return (NULL);
678178479Sjb	}
679178479Sjb
680178479Sjb	dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata,
681178479Sjb	    &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr);
682178479Sjb
683178479Sjb	if (dmp->dm_ctfp == NULL) {
684178479Sjb		(void) dt_set_errno(dtp, EDT_CTF);
685178479Sjb		return (NULL);
686178479Sjb	}
687178479Sjb
688178479Sjb	(void) ctf_setmodel(dmp->dm_ctfp, model);
689178479Sjb	ctf_setspecific(dmp->dm_ctfp, dmp);
690178479Sjb
691178479Sjb	if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) {
692178479Sjb		if ((pmp = dt_module_create(dtp, parent)) == NULL ||
693178479Sjb		    (pfp = dt_module_getctf(dtp, pmp)) == NULL) {
694178479Sjb			if (pmp == NULL)
695178479Sjb				(void) dt_set_errno(dtp, EDT_NOMEM);
696178479Sjb			goto err;
697178479Sjb		}
698178479Sjb
699178479Sjb		if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) {
700178479Sjb			dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
701178479Sjb			(void) dt_set_errno(dtp, EDT_CTF);
702178479Sjb			goto err;
703178479Sjb		}
704178479Sjb	}
705178479Sjb
706178479Sjb	dt_dprintf("loaded CTF container for %s (%p)\n",
707178479Sjb	    dmp->dm_name, (void *)dmp->dm_ctfp);
708178479Sjb
709178479Sjb	return (dmp->dm_ctfp);
710178479Sjb
711178479Sjberr:
712178479Sjb	ctf_close(dmp->dm_ctfp);
713178479Sjb	dmp->dm_ctfp = NULL;
714178479Sjb	return (NULL);
715178479Sjb}
716178479Sjb
717178479Sjb/*ARGSUSED*/
718178479Sjbvoid
719178479Sjbdt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
720178479Sjb{
721178479Sjb	ctf_close(dmp->dm_ctfp);
722178479Sjb	dmp->dm_ctfp = NULL;
723178479Sjb
724178559Sjb#if !defined(sun)
725178559Sjb	if (dmp->dm_ctdata.cts_data != NULL) {
726178559Sjb		free(dmp->dm_ctdata.cts_data);
727178559Sjb	}
728178559Sjb	if (dmp->dm_symtab.cts_data != NULL) {
729178559Sjb		free(dmp->dm_symtab.cts_data);
730178559Sjb	}
731178559Sjb	if (dmp->dm_strtab.cts_data != NULL) {
732178559Sjb		free(dmp->dm_strtab.cts_data);
733178559Sjb	}
734178559Sjb#endif
735178559Sjb
736178479Sjb	bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
737178479Sjb	bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
738178479Sjb	bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));
739178479Sjb
740178479Sjb	if (dmp->dm_symbuckets != NULL) {
741178479Sjb		free(dmp->dm_symbuckets);
742178479Sjb		dmp->dm_symbuckets = NULL;
743178479Sjb	}
744178479Sjb
745178479Sjb	if (dmp->dm_symchains != NULL) {
746178479Sjb		free(dmp->dm_symchains);
747178479Sjb		dmp->dm_symchains = NULL;
748178479Sjb	}
749178479Sjb
750178479Sjb	if (dmp->dm_asmap != NULL) {
751178479Sjb		free(dmp->dm_asmap);
752178479Sjb		dmp->dm_asmap = NULL;
753178479Sjb	}
754210425Savg#if defined(__FreeBSD__)
755210425Savg	if (dmp->dm_sec_offsets != NULL) {
756210425Savg		free(dmp->dm_sec_offsets);
757210425Savg		dmp->dm_sec_offsets = NULL;
758210425Savg	}
759210425Savg#endif
760178479Sjb	dmp->dm_symfree = 0;
761178479Sjb	dmp->dm_nsymbuckets = 0;
762178479Sjb	dmp->dm_nsymelems = 0;
763178479Sjb	dmp->dm_asrsv = 0;
764178479Sjb	dmp->dm_aslen = 0;
765178479Sjb
766178559Sjb	dmp->dm_text_va = 0;
767178479Sjb	dmp->dm_text_size = 0;
768178559Sjb	dmp->dm_data_va = 0;
769178479Sjb	dmp->dm_data_size = 0;
770178559Sjb	dmp->dm_bss_va = 0;
771178479Sjb	dmp->dm_bss_size = 0;
772178479Sjb
773178479Sjb	if (dmp->dm_extern != NULL) {
774178479Sjb		dt_idhash_destroy(dmp->dm_extern);
775178479Sjb		dmp->dm_extern = NULL;
776178479Sjb	}
777178479Sjb
778178479Sjb	(void) elf_end(dmp->dm_elf);
779178479Sjb	dmp->dm_elf = NULL;
780178479Sjb
781178479Sjb	dmp->dm_flags &= ~DT_DM_LOADED;
782178479Sjb}
783178479Sjb
784178479Sjbvoid
785178479Sjbdt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp)
786178479Sjb{
787210767Srpaulo	uint_t h = dt_strtab_hash(dmp->dm_name, NULL) % dtp->dt_modbuckets;
788210767Srpaulo	dt_module_t **dmpp = &dtp->dt_mods[h];
789210767Srpaulo
790178479Sjb	dt_list_delete(&dtp->dt_modlist, dmp);
791178479Sjb	assert(dtp->dt_nmods != 0);
792178479Sjb	dtp->dt_nmods--;
793178479Sjb
794210767Srpaulo	/*
795210767Srpaulo	 * Now remove this module from its hash chain.  We expect to always
796210767Srpaulo	 * find the module on its hash chain, so in this loop we assert that
797210767Srpaulo	 * we don't run off the end of the list.
798210767Srpaulo	 */
799210767Srpaulo	while (*dmpp != dmp) {
800210767Srpaulo		dmpp = &((*dmpp)->dm_next);
801210767Srpaulo		assert(*dmpp != NULL);
802210767Srpaulo	}
803210767Srpaulo
804210767Srpaulo	*dmpp = dmp->dm_next;
805210767Srpaulo
806178479Sjb	dt_module_unload(dtp, dmp);
807178479Sjb	free(dmp);
808178479Sjb}
809178479Sjb
810178479Sjb/*
811178479Sjb * Insert a new external symbol reference into the specified module.  The new
812178479Sjb * symbol will be marked as undefined and is assigned a symbol index beyond
813178479Sjb * any existing cached symbols from this module.  We use the ident's di_data
814178479Sjb * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol.
815178479Sjb */
816178479Sjbdt_ident_t *
817178479Sjbdt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp,
818178479Sjb    const char *name, const dtrace_typeinfo_t *tip)
819178479Sjb{
820178479Sjb	dtrace_syminfo_t *sip;
821178479Sjb	dt_ident_t *idp;
822178479Sjb	uint_t id;
823178479Sjb
824178479Sjb	if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create(
825178479Sjb	    "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) {
826178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
827178479Sjb		return (NULL);
828178479Sjb	}
829178479Sjb
830178479Sjb	if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) {
831178479Sjb		(void) dt_set_errno(dtp, EDT_SYMOFLOW);
832178479Sjb		return (NULL);
833178479Sjb	}
834178479Sjb
835178479Sjb	if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) {
836178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
837178479Sjb		return (NULL);
838178479Sjb	}
839178479Sjb
840178479Sjb	idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id,
841178479Sjb	    _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
842178479Sjb
843178479Sjb	if (idp == NULL) {
844178479Sjb		(void) dt_set_errno(dtp, EDT_NOMEM);
845178479Sjb		free(sip);
846178479Sjb		return (NULL);
847178479Sjb	}
848178479Sjb
849178479Sjb	sip->dts_object = dmp->dm_name;
850178479Sjb	sip->dts_name = idp->di_name;
851178479Sjb	sip->dts_id = idp->di_id;
852178479Sjb
853178479Sjb	idp->di_data = sip;
854178479Sjb	idp->di_ctfp = tip->dtt_ctfp;
855178479Sjb	idp->di_type = tip->dtt_type;
856178479Sjb
857178479Sjb	return (idp);
858178479Sjb}
859178479Sjb
860178479Sjbconst char *
861178479Sjbdt_module_modelname(dt_module_t *dmp)
862178479Sjb{
863178479Sjb	if (dmp->dm_ops == &dt_modops_64)
864178479Sjb		return ("64-bit");
865178479Sjb	else
866178479Sjb		return ("32-bit");
867178479Sjb}
868178479Sjb
869178479Sjb/*
870178479Sjb * Update our module cache by adding an entry for the specified module 'name'.
871178479Sjb * We create the dt_module_t and populate it using /system/object/<name>/.
872178559Sjb *
873178559Sjb * On FreeBSD, the module name is passed as the full module file name,
874178559Sjb * including the path.
875178479Sjb */
876178479Sjbstatic void
877178559Sjb#if defined(sun)
878178479Sjbdt_module_update(dtrace_hdl_t *dtp, const char *name)
879178559Sjb#else
880178559Sjbdt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat)
881178559Sjb#endif
882178479Sjb{
883178479Sjb	char fname[MAXPATHLEN];
884178479Sjb	struct stat64 st;
885178479Sjb	int fd, err, bits;
886178479Sjb
887178479Sjb	dt_module_t *dmp;
888178479Sjb	const char *s;
889178479Sjb	size_t shstrs;
890178479Sjb	GElf_Shdr sh;
891178479Sjb	Elf_Data *dp;
892178479Sjb	Elf_Scn *sp;
893178479Sjb
894178559Sjb#if defined(sun)
895178479Sjb	(void) snprintf(fname, sizeof (fname),
896178479Sjb	    "%s/%s/object", OBJFS_ROOT, name);
897178559Sjb#else
898210425Savg	GElf_Ehdr ehdr;
899178559Sjb	GElf_Phdr ph;
900178559Sjb	char name[MAXPATHLEN];
901210425Savg	uintptr_t mapbase, alignmask;
902178559Sjb	int i = 0;
903210425Savg	int is_elf_obj;
904178479Sjb
905178559Sjb	(void) strlcpy(name, k_stat->name, sizeof(name));
906178559Sjb	(void) strlcpy(fname, k_stat->pathname, sizeof(fname));
907178559Sjb#endif
908178559Sjb
909178479Sjb	if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 ||
910178479Sjb	    (dmp = dt_module_create(dtp, name)) == NULL) {
911178479Sjb		dt_dprintf("failed to open %s: %s\n", fname, strerror(errno));
912178479Sjb		(void) close(fd);
913178479Sjb		return;
914178479Sjb	}
915178479Sjb
916178479Sjb	/*
917178479Sjb	 * Since the module can unload out from under us (and /system/object
918178479Sjb	 * will return ENOENT), tell libelf to cook the entire file now and
919178479Sjb	 * then close the underlying file descriptor immediately.  If this
920178479Sjb	 * succeeds, we know that we can continue safely using dmp->dm_elf.
921178479Sjb	 */
922178479Sjb	dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL);
923178479Sjb	err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD);
924178479Sjb	(void) close(fd);
925178479Sjb
926178479Sjb	if (dmp->dm_elf == NULL || err == -1 ||
927210767Srpaulo	    elf_getshdrstrndx(dmp->dm_elf, &shstrs) == -1) {
928178479Sjb		dt_dprintf("failed to load %s: %s\n",
929178479Sjb		    fname, elf_errmsg(elf_errno()));
930178479Sjb		dt_module_destroy(dtp, dmp);
931178479Sjb		return;
932178479Sjb	}
933178479Sjb
934178479Sjb	switch (gelf_getclass(dmp->dm_elf)) {
935178479Sjb	case ELFCLASS32:
936178479Sjb		dmp->dm_ops = &dt_modops_32;
937178479Sjb		bits = 32;
938178479Sjb		break;
939178479Sjb	case ELFCLASS64:
940178479Sjb		dmp->dm_ops = &dt_modops_64;
941178479Sjb		bits = 64;
942178479Sjb		break;
943178479Sjb	default:
944178479Sjb		dt_dprintf("failed to load %s: unknown ELF class\n", fname);
945178479Sjb		dt_module_destroy(dtp, dmp);
946178479Sjb		return;
947178479Sjb	}
948210425Savg#if defined(__FreeBSD__)
949210425Savg	mapbase = (uintptr_t)k_stat->address;
950210425Savg	gelf_getehdr(dmp->dm_elf, &ehdr);
951210425Savg	is_elf_obj = (ehdr.e_type == ET_REL);
952210425Savg	if (is_elf_obj) {
953210425Savg		dmp->dm_sec_offsets =
954210425Savg		    malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets));
955210425Savg		if (dmp->dm_sec_offsets == NULL) {
956210425Savg			dt_dprintf("failed to allocate memory\n");
957210425Savg			dt_module_destroy(dtp, dmp);
958210425Savg			return;
959210425Savg		}
960210425Savg	}
961210425Savg#endif
962178479Sjb	/*
963178479Sjb	 * Iterate over the section headers locating various sections of
964178479Sjb	 * interest and use their attributes to flesh out the dt_module_t.
965178479Sjb	 */
966178479Sjb	for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) {
967178479Sjb		if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL ||
968178479Sjb		    (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL)
969178479Sjb			continue; /* skip any malformed sections */
970210425Savg#if defined(__FreeBSD__)
971210425Savg		if (sh.sh_size == 0)
972210425Savg			continue;
973210425Savg		if (is_elf_obj && (sh.sh_type == SHT_PROGBITS ||
974210425Savg		    sh.sh_type == SHT_NOBITS)) {
975210425Savg			alignmask = sh.sh_addralign - 1;
976210425Savg			mapbase += alignmask;
977210425Savg			mapbase &= ~alignmask;
978210425Savg			sh.sh_addr = mapbase;
979210425Savg			dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr;
980210425Savg			mapbase += sh.sh_size;
981210425Savg		}
982210425Savg#endif
983178479Sjb		if (strcmp(s, ".text") == 0) {
984178479Sjb			dmp->dm_text_size = sh.sh_size;
985178479Sjb			dmp->dm_text_va = sh.sh_addr;
986178479Sjb		} else if (strcmp(s, ".data") == 0) {
987178479Sjb			dmp->dm_data_size = sh.sh_size;
988178479Sjb			dmp->dm_data_va = sh.sh_addr;
989178479Sjb		} else if (strcmp(s, ".bss") == 0) {
990178479Sjb			dmp->dm_bss_size = sh.sh_size;
991178479Sjb			dmp->dm_bss_va = sh.sh_addr;
992178479Sjb		} else if (strcmp(s, ".info") == 0 &&
993178479Sjb		    (dp = elf_getdata(sp, NULL)) != NULL) {
994178479Sjb			bcopy(dp->d_buf, &dmp->dm_info,
995178479Sjb			    MIN(sh.sh_size, sizeof (dmp->dm_info)));
996178479Sjb		} else if (strcmp(s, ".filename") == 0 &&
997178479Sjb		    (dp = elf_getdata(sp, NULL)) != NULL) {
998178479Sjb			(void) strlcpy(dmp->dm_file,
999178479Sjb			    dp->d_buf, sizeof (dmp->dm_file));
1000178479Sjb		}
1001178479Sjb	}
1002178479Sjb
1003178479Sjb	dmp->dm_flags |= DT_DM_KERNEL;
1004178559Sjb#if defined(sun)
1005178479Sjb	dmp->dm_modid = (int)OBJFS_MODID(st.st_ino);
1006178559Sjb#else
1007210425Savg	/*
1008210425Savg	 * Include .rodata and special sections into .text.
1009210425Savg	 * This depends on default section layout produced by GNU ld
1010210425Savg	 * for ELF objects and libraries:
1011210425Savg	 * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable]
1012210425Savg	 */
1013210425Savg	dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va;
1014178559Sjb#if defined(__i386__)
1015178559Sjb	/*
1016178559Sjb	 * Find the first load section and figure out the relocation
1017178559Sjb	 * offset for the symbols. The kernel module will not need
1018178559Sjb	 * relocation, but the kernel linker modules will.
1019178559Sjb	 */
1020178559Sjb	for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) {
1021178559Sjb		if (ph.p_type == PT_LOAD) {
1022178559Sjb			dmp->dm_reloc_offset = k_stat->address - ph.p_vaddr;
1023178559Sjb			break;
1024178559Sjb		}
1025178559Sjb	}
1026178559Sjb#endif
1027178559Sjb#endif
1028178479Sjb
1029178479Sjb	if (dmp->dm_info.objfs_info_primary)
1030178479Sjb		dmp->dm_flags |= DT_DM_PRIMARY;
1031178479Sjb
1032178479Sjb	dt_dprintf("opened %d-bit module %s (%s) [%d]\n",
1033178479Sjb	    bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid);
1034178479Sjb}
1035178479Sjb
1036178479Sjb/*
1037178479Sjb * Unload all the loaded modules and then refresh the module cache with the
1038178479Sjb * latest list of loaded modules and their address ranges.
1039178479Sjb */
1040178479Sjbvoid
1041178479Sjbdtrace_update(dtrace_hdl_t *dtp)
1042178479Sjb{
1043178479Sjb	dt_module_t *dmp;
1044178479Sjb	DIR *dirp;
1045178559Sjb#if defined(__FreeBSD__)
1046178559Sjb	int fileid;
1047178559Sjb#endif
1048178479Sjb
1049178479Sjb	for (dmp = dt_list_next(&dtp->dt_modlist);
1050178479Sjb	    dmp != NULL; dmp = dt_list_next(dmp))
1051178479Sjb		dt_module_unload(dtp, dmp);
1052178479Sjb
1053178559Sjb#if defined(sun)
1054178479Sjb	/*
1055178479Sjb	 * Open /system/object and attempt to create a libdtrace module for
1056178479Sjb	 * each kernel module that is loaded on the current system.
1057178479Sjb	 */
1058178479Sjb	if (!(dtp->dt_oflags & DTRACE_O_NOSYS) &&
1059178479Sjb	    (dirp = opendir(OBJFS_ROOT)) != NULL) {
1060178479Sjb		struct dirent *dp;
1061178479Sjb
1062178479Sjb		while ((dp = readdir(dirp)) != NULL) {
1063178479Sjb			if (dp->d_name[0] != '.')
1064178479Sjb				dt_module_update(dtp, dp->d_name);
1065178479Sjb		}
1066178479Sjb
1067178479Sjb		(void) closedir(dirp);
1068178479Sjb	}
1069178559Sjb#elif defined(__FreeBSD__)
1070178559Sjb	/*
1071178559Sjb	 * Use FreeBSD's kernel loader interface to discover what kernel
1072178559Sjb	 * modules are loaded and create a libdtrace module for each one.
1073178559Sjb	 */
1074178559Sjb	for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
1075178559Sjb		struct kld_file_stat k_stat;
1076178559Sjb		k_stat.version = sizeof(k_stat);
1077178559Sjb		if (kldstat(fileid, &k_stat) == 0)
1078178559Sjb			dt_module_update(dtp, &k_stat);
1079178559Sjb	}
1080178559Sjb#endif
1081178479Sjb
1082178479Sjb	/*
1083178479Sjb	 * Look up all the macro identifiers and set di_id to the latest value.
1084178479Sjb	 * This code collaborates with dt_lex.l on the use of di_id.  We will
1085178479Sjb	 * need to implement something fancier if we need to support non-ints.
1086178479Sjb	 */
1087178479Sjb	dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid();
1088178479Sjb	dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid();
1089178479Sjb	dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid();
1090178479Sjb	dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid();
1091178479Sjb	dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0);
1092178479Sjb	dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid();
1093178559Sjb#if defined(sun)
1094178479Sjb	dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid();
1095178559Sjb#endif
1096178479Sjb	dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0);
1097178559Sjb#if defined(sun)
1098178479Sjb	dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid();
1099178559Sjb#endif
1100178479Sjb	dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid();
1101178479Sjb
1102178479Sjb	/*
1103178479Sjb	 * Cache the pointers to the modules representing the base executable
1104178479Sjb	 * and the run-time linker in the dtrace client handle. Note that on
1105178479Sjb	 * x86 krtld is folded into unix, so if we don't find it, use unix
1106178479Sjb	 * instead.
1107178479Sjb	 */
1108178479Sjb	dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix");
1109178479Sjb	dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld");
1110178479Sjb	if (dtp->dt_rtld == NULL)
1111178479Sjb		dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix");
1112178479Sjb
1113178479Sjb	/*
1114178479Sjb	 * If this is the first time we are initializing the module list,
1115178479Sjb	 * remove the module for genunix from the module list and then move it
1116178479Sjb	 * to the front of the module list.  We do this so that type and symbol
1117178479Sjb	 * queries encounter genunix and thereby optimize for the common case
1118178479Sjb	 * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below.
1119178479Sjb	 */
1120178479Sjb	if (dtp->dt_exec != NULL &&
1121178479Sjb	    dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) {
1122178479Sjb		dt_list_delete(&dtp->dt_modlist, dtp->dt_exec);
1123178479Sjb		dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec);
1124178479Sjb	}
1125178479Sjb}
1126178479Sjb
1127178479Sjbstatic dt_module_t *
1128178479Sjbdt_module_from_object(dtrace_hdl_t *dtp, const char *object)
1129178479Sjb{
1130178479Sjb	int err = EDT_NOMOD;
1131178479Sjb	dt_module_t *dmp;
1132178479Sjb
1133178479Sjb	switch ((uintptr_t)object) {
1134178479Sjb	case (uintptr_t)DTRACE_OBJ_EXEC:
1135178479Sjb		dmp = dtp->dt_exec;
1136178479Sjb		break;
1137178479Sjb	case (uintptr_t)DTRACE_OBJ_RTLD:
1138178479Sjb		dmp = dtp->dt_rtld;
1139178479Sjb		break;
1140178479Sjb	case (uintptr_t)DTRACE_OBJ_CDEFS:
1141178479Sjb		dmp = dtp->dt_cdefs;
1142178479Sjb		break;
1143178479Sjb	case (uintptr_t)DTRACE_OBJ_DDEFS:
1144178479Sjb		dmp = dtp->dt_ddefs;
1145178479Sjb		break;
1146178479Sjb	default:
1147178479Sjb		dmp = dt_module_create(dtp, object);
1148178479Sjb		err = EDT_NOMEM;
1149178479Sjb	}
1150178479Sjb
1151178479Sjb	if (dmp == NULL)
1152178479Sjb		(void) dt_set_errno(dtp, err);
1153178479Sjb
1154178479Sjb	return (dmp);
1155178479Sjb}
1156178479Sjb
1157178479Sjb/*
1158178479Sjb * Exported interface to look up a symbol by name.  We return the GElf_Sym and
1159178479Sjb * complete symbol information for the matching symbol.
1160178479Sjb */
1161178479Sjbint
1162178479Sjbdtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name,
1163178479Sjb    GElf_Sym *symp, dtrace_syminfo_t *sip)
1164178479Sjb{
1165178479Sjb	dt_module_t *dmp;
1166178479Sjb	dt_ident_t *idp;
1167178479Sjb	uint_t n, id;
1168178479Sjb	GElf_Sym sym;
1169178479Sjb
1170178479Sjb	uint_t mask = 0; /* mask of dt_module flags to match */
1171178479Sjb	uint_t bits = 0; /* flag bits that must be present */
1172178479Sjb
1173178479Sjb	if (object != DTRACE_OBJ_EVERY &&
1174178479Sjb	    object != DTRACE_OBJ_KMODS &&
1175178479Sjb	    object != DTRACE_OBJ_UMODS) {
1176178479Sjb		if ((dmp = dt_module_from_object(dtp, object)) == NULL)
1177178479Sjb			return (-1); /* dt_errno is set for us */
1178178479Sjb
1179178479Sjb		if (dt_module_load(dtp, dmp) == -1)
1180178479Sjb			return (-1); /* dt_errno is set for us */
1181178479Sjb		n = 1;
1182178479Sjb
1183178479Sjb	} else {
1184178479Sjb		if (object == DTRACE_OBJ_KMODS)
1185178479Sjb			mask = bits = DT_DM_KERNEL;
1186178479Sjb		else if (object == DTRACE_OBJ_UMODS)
1187178479Sjb			mask = DT_DM_KERNEL;
1188178479Sjb
1189178479Sjb		dmp = dt_list_next(&dtp->dt_modlist);
1190178479Sjb		n = dtp->dt_nmods;
1191178479Sjb	}
1192178479Sjb
1193178479Sjb	if (symp == NULL)
1194178479Sjb		symp = &sym;
1195178479Sjb
1196178479Sjb	for (; n > 0; n--, dmp = dt_list_next(dmp)) {
1197178479Sjb		if ((dmp->dm_flags & mask) != bits)
1198178479Sjb			continue; /* failed to match required attributes */
1199178479Sjb
1200178479Sjb		if (dt_module_load(dtp, dmp) == -1)
1201178479Sjb			continue; /* failed to load symbol table */
1202178479Sjb
1203178479Sjb		if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) {
1204178479Sjb			if (sip != NULL) {
1205178479Sjb				sip->dts_object = dmp->dm_name;
1206178479Sjb				sip->dts_name = (const char *)
1207178479Sjb				    dmp->dm_strtab.cts_data + symp->st_name;
1208178479Sjb				sip->dts_id = id;
1209178479Sjb			}
1210178479Sjb			return (0);
1211178479Sjb		}
1212178479Sjb
1213178479Sjb		if (dmp->dm_extern != NULL &&
1214178479Sjb		    (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) {
1215178479Sjb			if (symp != &sym) {
1216178479Sjb				symp->st_name = (uintptr_t)idp->di_name;
1217178479Sjb				symp->st_info =
1218178479Sjb				    GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
1219178479Sjb				symp->st_other = 0;
1220178479Sjb				symp->st_shndx = SHN_UNDEF;
1221178479Sjb				symp->st_value = 0;
1222178479Sjb				symp->st_size =
1223178479Sjb				    ctf_type_size(idp->di_ctfp, idp->di_type);
1224178479Sjb			}
1225178479Sjb
1226178479Sjb			if (sip != NULL) {
1227178479Sjb				sip->dts_object = dmp->dm_name;
1228178479Sjb				sip->dts_name = idp->di_name;
1229178479Sjb				sip->dts_id = idp->di_id;
1230178479Sjb			}
1231178479Sjb
1232178479Sjb			return (0);
1233178479Sjb		}
1234178479Sjb	}
1235178479Sjb
1236178479Sjb	return (dt_set_errno(dtp, EDT_NOSYM));
1237178479Sjb}
1238178479Sjb
1239178479Sjb/*
1240178479Sjb * Exported interface to look up a symbol by address.  We return the GElf_Sym
1241178479Sjb * and complete symbol information for the matching symbol.
1242178479Sjb */
1243178479Sjbint
1244178479Sjbdtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr,
1245178479Sjb    GElf_Sym *symp, dtrace_syminfo_t *sip)
1246178479Sjb{
1247178479Sjb	dt_module_t *dmp;
1248178479Sjb	uint_t id;
1249178479Sjb	const dtrace_vector_t *v = dtp->dt_vector;
1250178479Sjb
1251178479Sjb	if (v != NULL)
1252178479Sjb		return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip));
1253178479Sjb
1254178479Sjb	for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
1255178479Sjb	    dmp = dt_list_next(dmp)) {
1256178479Sjb		if (addr - dmp->dm_text_va < dmp->dm_text_size ||
1257178479Sjb		    addr - dmp->dm_data_va < dmp->dm_data_size ||
1258178479Sjb		    addr - dmp->dm_bss_va < dmp->dm_bss_size)
1259178479Sjb			break;
1260178479Sjb	}
1261178479Sjb
1262178479Sjb	if (dmp == NULL)
1263178479Sjb		return (dt_set_errno(dtp, EDT_NOSYMADDR));
1264178479Sjb
1265178479Sjb	if (dt_module_load(dtp, dmp) == -1)
1266178479Sjb		return (-1); /* dt_errno is set for us */
1267178479Sjb
1268178479Sjb	if (symp != NULL) {
1269178479Sjb		if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL)
1270178479Sjb			return (dt_set_errno(dtp, EDT_NOSYMADDR));
1271178479Sjb	}
1272178479Sjb
1273178479Sjb	if (sip != NULL) {
1274178479Sjb		sip->dts_object = dmp->dm_name;
1275178479Sjb
1276178479Sjb		if (symp != NULL) {
1277178479Sjb			sip->dts_name = (const char *)
1278178479Sjb			    dmp->dm_strtab.cts_data + symp->st_name;
1279178479Sjb			sip->dts_id = id;
1280178479Sjb		} else {
1281178479Sjb			sip->dts_name = NULL;
1282178479Sjb			sip->dts_id = 0;
1283178479Sjb		}
1284178479Sjb	}
1285178479Sjb
1286178479Sjb	return (0);
1287178479Sjb}
1288178479Sjb
1289178479Sjbint
1290178479Sjbdtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name,
1291178479Sjb    dtrace_typeinfo_t *tip)
1292178479Sjb{
1293178479Sjb	dtrace_typeinfo_t ti;
1294178479Sjb	dt_module_t *dmp;
1295178479Sjb	int found = 0;
1296178479Sjb	ctf_id_t id;
1297178479Sjb	uint_t n;
1298178479Sjb	int justone;
1299178479Sjb
1300178479Sjb	uint_t mask = 0; /* mask of dt_module flags to match */
1301178479Sjb	uint_t bits = 0; /* flag bits that must be present */
1302178479Sjb
1303178479Sjb	if (object != DTRACE_OBJ_EVERY &&
1304178479Sjb	    object != DTRACE_OBJ_KMODS &&
1305178479Sjb	    object != DTRACE_OBJ_UMODS) {
1306178479Sjb		if ((dmp = dt_module_from_object(dtp, object)) == NULL)
1307178479Sjb			return (-1); /* dt_errno is set for us */
1308178479Sjb
1309178479Sjb		if (dt_module_load(dtp, dmp) == -1)
1310178479Sjb			return (-1); /* dt_errno is set for us */
1311178479Sjb		n = 1;
1312178479Sjb		justone = 1;
1313178479Sjb
1314178479Sjb	} else {
1315178479Sjb		if (object == DTRACE_OBJ_KMODS)
1316178479Sjb			mask = bits = DT_DM_KERNEL;
1317178479Sjb		else if (object == DTRACE_OBJ_UMODS)
1318178479Sjb			mask = DT_DM_KERNEL;
1319178479Sjb
1320178479Sjb		dmp = dt_list_next(&dtp->dt_modlist);
1321178479Sjb		n = dtp->dt_nmods;
1322178479Sjb		justone = 0;
1323178479Sjb	}
1324178479Sjb
1325178479Sjb	if (tip == NULL)
1326178479Sjb		tip = &ti;
1327178479Sjb
1328178479Sjb	for (; n > 0; n--, dmp = dt_list_next(dmp)) {
1329178479Sjb		if ((dmp->dm_flags & mask) != bits)
1330178479Sjb			continue; /* failed to match required attributes */
1331178479Sjb
1332178479Sjb		/*
1333178479Sjb		 * If we can't load the CTF container, continue on to the next
1334178479Sjb		 * module.  If our search was scoped to only one module then
1335178479Sjb		 * return immediately leaving dt_errno unmodified.
1336178479Sjb		 */
1337178479Sjb		if (dt_module_getctf(dtp, dmp) == NULL) {
1338178479Sjb			if (justone)
1339178479Sjb				return (-1);
1340178479Sjb			continue;
1341178479Sjb		}
1342178479Sjb
1343178479Sjb		/*
1344178479Sjb		 * Look up the type in the module's CTF container.  If our
1345178479Sjb		 * match is a forward declaration tag, save this choice in
1346178479Sjb		 * 'tip' and keep going in the hope that we will locate the
1347178479Sjb		 * underlying structure definition.  Otherwise just return.
1348178479Sjb		 */
1349178479Sjb		if ((id = ctf_lookup_by_name(dmp->dm_ctfp, name)) != CTF_ERR) {
1350178479Sjb			tip->dtt_object = dmp->dm_name;
1351178479Sjb			tip->dtt_ctfp = dmp->dm_ctfp;
1352178479Sjb			tip->dtt_type = id;
1353178479Sjb
1354178479Sjb			if (ctf_type_kind(dmp->dm_ctfp, ctf_type_resolve(
1355178479Sjb			    dmp->dm_ctfp, id)) != CTF_K_FORWARD)
1356178479Sjb				return (0);
1357178479Sjb
1358178479Sjb			found++;
1359178479Sjb		}
1360178479Sjb	}
1361178479Sjb
1362178479Sjb	if (found == 0)
1363178479Sjb		return (dt_set_errno(dtp, EDT_NOTYPE));
1364178479Sjb
1365178479Sjb	return (0);
1366178479Sjb}
1367178479Sjb
1368178479Sjbint
1369178479Sjbdtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp,
1370178479Sjb    const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip)
1371178479Sjb{
1372178479Sjb	dt_module_t *dmp;
1373178479Sjb
1374178479Sjb	tip->dtt_object = NULL;
1375178479Sjb	tip->dtt_ctfp = NULL;
1376178479Sjb	tip->dtt_type = CTF_ERR;
1377178479Sjb
1378178479Sjb	if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL)
1379178479Sjb		return (dt_set_errno(dtp, EDT_NOMOD));
1380178479Sjb
1381178479Sjb	if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) {
1382178479Sjb		dt_ident_t *idp =
1383178479Sjb		    dt_idhash_lookup(dmp->dm_extern, sip->dts_name);
1384178479Sjb
1385178479Sjb		if (idp == NULL)
1386178479Sjb			return (dt_set_errno(dtp, EDT_NOSYM));
1387178479Sjb
1388178479Sjb		tip->dtt_ctfp = idp->di_ctfp;
1389178479Sjb		tip->dtt_type = idp->di_type;
1390178479Sjb
1391178479Sjb	} else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) {
1392178479Sjb		if (dt_module_getctf(dtp, dmp) == NULL)
1393178479Sjb			return (-1); /* errno is set for us */
1394178479Sjb
1395178479Sjb		tip->dtt_ctfp = dmp->dm_ctfp;
1396178479Sjb		tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id);
1397178479Sjb
1398178479Sjb		if (tip->dtt_type == CTF_ERR) {
1399178479Sjb			dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp);
1400178479Sjb			return (dt_set_errno(dtp, EDT_CTF));
1401178479Sjb		}
1402178479Sjb
1403178479Sjb	} else {
1404178479Sjb		tip->dtt_ctfp = DT_FPTR_CTFP(dtp);
1405178479Sjb		tip->dtt_type = DT_FPTR_TYPE(dtp);
1406178479Sjb	}
1407178479Sjb
1408178479Sjb	tip->dtt_object = dmp->dm_name;
1409178479Sjb	return (0);
1410178479Sjb}
1411178479Sjb
1412178479Sjbstatic dtrace_objinfo_t *
1413178479Sjbdt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto)
1414178479Sjb{
1415178479Sjb	dto->dto_name = dmp->dm_name;
1416178479Sjb	dto->dto_file = dmp->dm_file;
1417178479Sjb	dto->dto_id = dmp->dm_modid;
1418178479Sjb	dto->dto_flags = 0;
1419178479Sjb
1420178479Sjb	if (dmp->dm_flags & DT_DM_KERNEL)
1421178479Sjb		dto->dto_flags |= DTRACE_OBJ_F_KERNEL;
1422178479Sjb	if (dmp->dm_flags & DT_DM_PRIMARY)
1423178479Sjb		dto->dto_flags |= DTRACE_OBJ_F_PRIMARY;
1424178479Sjb
1425178479Sjb	dto->dto_text_va = dmp->dm_text_va;
1426178479Sjb	dto->dto_text_size = dmp->dm_text_size;
1427178479Sjb	dto->dto_data_va = dmp->dm_data_va;
1428178479Sjb	dto->dto_data_size = dmp->dm_data_size;
1429178479Sjb	dto->dto_bss_va = dmp->dm_bss_va;
1430178479Sjb	dto->dto_bss_size = dmp->dm_bss_size;
1431178479Sjb
1432178479Sjb	return (dto);
1433178479Sjb}
1434178479Sjb
1435178479Sjbint
1436178479Sjbdtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data)
1437178479Sjb{
1438178479Sjb	const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist);
1439178479Sjb	dtrace_objinfo_t dto;
1440178479Sjb	int rv;
1441178479Sjb
1442178479Sjb	for (; dmp != NULL; dmp = dt_list_next(dmp)) {
1443178479Sjb		if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0)
1444178479Sjb			return (rv);
1445178479Sjb	}
1446178479Sjb
1447178479Sjb	return (0);
1448178479Sjb}
1449178479Sjb
1450178479Sjbint
1451178479Sjbdtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto)
1452178479Sjb{
1453178479Sjb	dt_module_t *dmp;
1454178479Sjb
1455178479Sjb	if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS ||
1456178479Sjb	    object == DTRACE_OBJ_UMODS || dto == NULL)
1457178479Sjb		return (dt_set_errno(dtp, EINVAL));
1458178479Sjb
1459178479Sjb	if ((dmp = dt_module_from_object(dtp, object)) == NULL)
1460178479Sjb		return (-1); /* dt_errno is set for us */
1461178479Sjb
1462178479Sjb	if (dt_module_load(dtp, dmp) == -1)
1463178479Sjb		return (-1); /* dt_errno is set for us */
1464178479Sjb
1465178479Sjb	(void) dt_module_info(dmp, dto);
1466178479Sjb	return (0);
1467178479Sjb}
1468