dis_target.c revision dc986d9f4cb40f3ff88fe0d9c9fb3a51ad50f0d9
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 *
25 * Copyright 2011 Jason King.  All rights reserved.
26 */
27
28#include <assert.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <gelf.h>
32#include <libelf.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37#include <sys/fcntl.h>
38#include <sys/stat.h>
39#include <sys/sysmacros.h>
40#include <sys/types.h>
41
42#include "dis_target.h"
43#include "dis_util.h"
44
45/*
46 * Standard ELF disassembler target.
47 *
48 * We only support disassembly of ELF files, though this target interface could
49 * be extended in the future.  Each basic type (target, func, section) contains
50 * enough information to uniquely identify the location within the file.  The
51 * interfaces use libelf(3LIB) to do the actual processing of the file.
52 */
53
54/*
55 * Symbol table entry type.  We maintain our own symbol table sorted by address,
56 * with the symbol name already resolved against the ELF symbol table.
57 */
58typedef struct sym_entry {
59	GElf_Sym	se_sym;		/* value of symbol */
60	char		*se_name;	/* name of symbol */
61	int		se_shndx;	/* section where symbol is located */
62} sym_entry_t;
63
64/*
65 * Create a map of the virtual address ranges of every section.  This will
66 * allow us to create dummpy mappings for unassigned addresses.  Otherwise
67 * multiple sections with unassigned addresses will appear to overlap and
68 * mess up symbol resolution (which uses the virtual address).
69 */
70typedef struct dis_shnmap {
71	const char 	*dm_name;	/* name of section */
72	uint64_t	dm_start;	/* virtual address of section */
73	size_t		dm_length;	/* address length */
74	boolean_t	dm_mapped;	/* did we assign the mapping */
75} dis_shnmap_t;
76
77/*
78 * Target data structure.  This structure keeps track of the ELF file
79 * information, a few bits of pre-processed section index information, and
80 * sorted versions of the symbol table.  We also keep track of the last symbol
81 * looked up, as the majority of lookups remain within the same symbol.
82 */
83struct dis_tgt {
84	Elf		*dt_elf;	/* libelf handle */
85	Elf		*dt_elf_root;	/* main libelf handle (for archives) */
86	const char	*dt_filename;	/* name of file */
87	int		dt_fd;		/* underlying file descriptor */
88	size_t		dt_shstrndx;	/* section index of .shstrtab */
89	size_t		dt_symidx;	/* section index of symbol table */
90	sym_entry_t	*dt_symcache;	/* last symbol looked up */
91	sym_entry_t	*dt_symtab;	/* sorted symbol table */
92	int		dt_symcount;	/* # of symbol table entries */
93	struct dis_tgt	*dt_next;	/* next target (for archives) */
94	Elf_Arhdr	*dt_arhdr;	/* archive header (for archives) */
95	dis_shnmap_t	*dt_shnmap;	/* section address map */
96	size_t		dt_shncount;	/* # of sections in target */
97};
98
99/*
100 * Function data structure.  We resolve the symbol and lookup the associated ELF
101 * data when building this structure.  The offset is calculated based on the
102 * section's starting address.
103 */
104struct dis_func {
105	sym_entry_t	*df_sym;	/* symbol table reference */
106	Elf_Data	*df_data;	/* associated ELF data */
107	size_t		df_offset;	/* offset within data */
108};
109
110/*
111 * Section data structure.  We store the entire section header so that we can
112 * determine some properties (such as whether or not it contains text) after
113 * building the structure.
114 */
115struct dis_scn {
116	GElf_Shdr	ds_shdr;
117	const char	*ds_name;
118	Elf_Data	*ds_data;
119};
120
121/* Lifted from Psymtab.c, omitting STT_TLS */
122#define	DATA_TYPES      \
123	((1 << STT_OBJECT) | (1 << STT_FUNC) | (1 << STT_COMMON))
124#define	IS_DATA_TYPE(tp)	(((1 << (tp)) & DATA_TYPES) != 0)
125
126/*
127 * Save the virtual address range for this section and select the
128 * best section to use as the symbol table.  We prefer SHT_SYMTAB
129 * over SHT_DYNSYM.
130 */
131/* ARGSUSED */
132static void
133tgt_scn_init(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
134{
135	int *index = data;
136
137	*index += 1;
138
139	tgt->dt_shnmap[*index].dm_name = scn->ds_name;
140	tgt->dt_shnmap[*index].dm_start = scn->ds_shdr.sh_addr;
141	tgt->dt_shnmap[*index].dm_length = scn->ds_shdr.sh_size;
142	tgt->dt_shnmap[*index].dm_mapped = B_FALSE;
143
144	/*
145	 * Prefer SHT_SYMTAB over SHT_DYNSYM
146	 */
147	if (scn->ds_shdr.sh_type == SHT_DYNSYM && tgt->dt_symidx == 0)
148		tgt->dt_symidx = *index;
149	else if (scn->ds_shdr.sh_type == SHT_SYMTAB)
150		tgt->dt_symidx = *index;
151}
152
153static int
154sym_compare(const void *a, const void *b)
155{
156	const sym_entry_t *syma = a;
157	const sym_entry_t *symb = b;
158	const char *aname = syma->se_name;
159	const char *bname = symb->se_name;
160
161	if (syma->se_sym.st_value < symb->se_sym.st_value)
162		return (-1);
163
164	if (syma->se_sym.st_value > symb->se_sym.st_value)
165		return (1);
166
167	/*
168	 * Prefer functions over non-functions
169	 */
170	if (GELF_ST_TYPE(syma->se_sym.st_info) !=
171	    GELF_ST_TYPE(symb->se_sym.st_info)) {
172		if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC)
173			return (-1);
174		if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC)
175			return (1);
176	}
177
178	/*
179	 * For symbols with the same address and type, we sort them according to
180	 * a hierarchy:
181	 *
182	 * 	1. weak symbols (common name)
183	 * 	2. global symbols (external name)
184	 * 	3. local symbols
185	 */
186	if (GELF_ST_BIND(syma->se_sym.st_info) !=
187	    GELF_ST_BIND(symb->se_sym.st_info)) {
188		if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK)
189			return (-1);
190		if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK)
191			return (1);
192
193		if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL)
194			return (-1);
195		if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL)
196			return (1);
197	}
198
199	/*
200	 * As a last resort, if we have multiple symbols of the same type at the
201	 * same address, prefer the version with the fewest leading underscores.
202	 */
203	if (aname == NULL)
204		return (-1);
205	if (bname == NULL)
206		return (1);
207
208	while (*aname == '_' && *bname == '_') {
209		aname++;
210		bname++;
211	}
212
213	if (*bname == '_')
214		return (-1);
215	if (*aname == '_')
216		return (1);
217
218	/*
219	 * Prefer the symbol with the smaller size.
220	 */
221	if (syma->se_sym.st_size < symb->se_sym.st_size)
222		return (-1);
223	if (syma->se_sym.st_size > symb->se_sym.st_size)
224		return (1);
225
226	/*
227	 * We really do have two identical symbols for some reason.  Just report
228	 * them as equal, and to the lucky one go the spoils.
229	 */
230	return (0);
231}
232
233/*
234 * Construct an optimized symbol table sorted by starting address.
235 */
236static void
237construct_symtab(dis_tgt_t *tgt)
238{
239	Elf_Scn *scn;
240	GElf_Shdr shdr;
241	Elf_Data *symdata;
242	int i;
243	GElf_Word *symshndx = NULL;
244	int symshndx_size;
245	sym_entry_t *sym;
246	sym_entry_t *p_symtab = NULL;
247	int nsym = 0; /* count of symbols we're not interested in */
248
249	/*
250	 * Find the symshndx section, if any
251	 */
252	for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL;
253	    scn = elf_nextscn(tgt->dt_elf, scn)) {
254		if (gelf_getshdr(scn, &shdr) == NULL)
255			break;
256		if (shdr.sh_type == SHT_SYMTAB_SHNDX &&
257		    shdr.sh_link == tgt->dt_symidx) {
258			Elf_Data	*data;
259
260			if ((data = elf_getdata(scn, NULL)) != NULL) {
261				symshndx = (GElf_Word *)data->d_buf;
262				symshndx_size = data->d_size /
263				    sizeof (GElf_Word);
264				break;
265			}
266		}
267	}
268
269	if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL)
270		die("%s: failed to get section information", tgt->dt_filename);
271	if (gelf_getshdr(scn, &shdr) == NULL)
272		die("%s: failed to get section header", tgt->dt_filename);
273	if (shdr.sh_entsize == 0)
274		die("%s: symbol table has zero size", tgt->dt_filename);
275
276	if ((symdata = elf_getdata(scn, NULL)) == NULL)
277		die("%s: failed to get symbol table", tgt->dt_filename);
278
279	tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM,
280	    1, EV_CURRENT);
281
282	p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t));
283
284	for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) {
285		if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) {
286			warn("%s: gelf_getsym returned NULL for %d",
287			    tgt->dt_filename, i);
288			nsym++;
289			continue;
290		}
291
292		/*
293		 * We're only interested in data symbols.
294		 */
295		if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) {
296			nsym++;
297			continue;
298		}
299
300		if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) {
301			if (i > symshndx_size) {
302				warn("%s: bad SHNX_XINDEX %d",
303				    tgt->dt_filename, i);
304				sym->se_shndx = -1;
305			} else {
306				sym->se_shndx = symshndx[i];
307			}
308		} else {
309			sym->se_shndx = sym->se_sym.st_shndx;
310		}
311
312		/* Deal with symbols with special section indicies */
313		if (sym->se_shndx == SHN_ABS) {
314			/*
315			 * If st_value == 0, references to these
316			 * symbols in code are modified in situ
317			 * thus we will never attempt to look
318			 * them up.
319			 */
320			if (sym->se_sym.st_value == 0) {
321				/*
322				 * References to these symbols in code
323				 * are modified in situ by the runtime
324				 * linker and no code on disk will ever
325				 * attempt to look them up.
326				 */
327				nsym++;
328				continue;
329			} else {
330				/*
331				 * If st_value != 0, (such as examining
332				 * something in /system/object/.../object)
333				 * the values should resolve to a value
334				 * within an existing section (such as
335				 * .data).  This also means it never needs
336				 * to have st_value mapped.
337				 */
338				sym++;
339				continue;
340			}
341		}
342
343		/*
344		 * Ignore the symbol if it has some other special
345		 * section index
346		 */
347		if (sym->se_shndx == SHN_UNDEF ||
348		    sym->se_shndx >= SHN_LORESERVE) {
349			nsym++;
350			continue;
351		}
352
353		if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link,
354		    (size_t)sym->se_sym.st_name)) == NULL) {
355			warn("%s: failed to lookup symbol %d name",
356			    tgt->dt_filename, i);
357			nsym++;
358			continue;
359		}
360
361		/*
362		 * If we had to map this section, its symbol value
363		 * also needs to be mapped.
364		 */
365		if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
366			sym->se_sym.st_value +=
367			    tgt->dt_shnmap[sym->se_shndx].dm_start;
368
369		sym++;
370	}
371
372	tgt->dt_symcount -= nsym;
373	tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount *
374	    sizeof (sym_entry_t));
375
376	qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t),
377	    sym_compare);
378}
379
380/*
381 * Assign virtual address ranges for sections that need it
382 */
383static void
384create_addrmap(dis_tgt_t *tgt)
385{
386	uint64_t addr;
387	int i;
388
389	if (tgt->dt_shnmap == NULL)
390		return;
391
392	/* find the greatest used address */
393	for (addr = 0, i = 1; i < tgt->dt_shncount; i++)
394		if (tgt->dt_shnmap[i].dm_start > addr)
395			addr = tgt->dt_shnmap[i].dm_start +
396			    tgt->dt_shnmap[i].dm_length;
397
398	addr = P2ROUNDUP(addr, 0x1000);
399
400	/*
401	 * Assign section a starting address beyond the largest mapped section
402	 * if no address was given.
403	 */
404	for (i = 1; i < tgt->dt_shncount; i++) {
405		if (tgt->dt_shnmap[i].dm_start != 0)
406			continue;
407
408		tgt->dt_shnmap[i].dm_start = addr;
409		tgt->dt_shnmap[i].dm_mapped = B_TRUE;
410		addr = P2ROUNDUP(addr + tgt->dt_shnmap[i].dm_length, 0x1000);
411	}
412}
413
414/*
415 * Create a target backed by an ELF file.
416 */
417dis_tgt_t *
418dis_tgt_create(const char *file)
419{
420	dis_tgt_t *tgt, *current;
421	int idx;
422	Elf *elf;
423	GElf_Ehdr ehdr;
424	Elf_Arhdr *arhdr = NULL;
425	int cmd;
426
427	if (elf_version(EV_CURRENT) == EV_NONE)
428		die("libelf(3ELF) out of date");
429
430	tgt = safe_malloc(sizeof (dis_tgt_t));
431
432	if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) {
433		warn("%s: failed opening file, reason: %s", file,
434		    strerror(errno));
435		free(tgt);
436		return (NULL);
437	}
438
439	if ((tgt->dt_elf_root =
440	    elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) {
441		warn("%s: invalid or corrupt ELF file", file);
442		dis_tgt_destroy(tgt);
443		return (NULL);
444	}
445
446	current = tgt;
447	cmd = ELF_C_READ;
448	while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) {
449		size_t shnum = 0;
450
451		if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
452		    (arhdr = elf_getarhdr(elf)) == NULL) {
453			warn("%s: malformed archive", file);
454			dis_tgt_destroy(tgt);
455			return (NULL);
456		}
457
458		/*
459		 * Make sure that this Elf file is sane
460		 */
461		if (gelf_getehdr(elf, &ehdr) == NULL) {
462			if (arhdr != NULL) {
463				/*
464				 * For archives, we drive on in the face of bad
465				 * members.  The "/" and "//" members are
466				 * special, and should be silently ignored.
467				 */
468				if (strcmp(arhdr->ar_name, "/") != 0 &&
469				    strcmp(arhdr->ar_name, "//") != 0)
470					warn("%s[%s]: invalid file type",
471					    file, arhdr->ar_name);
472				cmd = elf_next(elf);
473				(void) elf_end(elf);
474				continue;
475			}
476
477			warn("%s: invalid file type", file);
478			dis_tgt_destroy(tgt);
479			return (NULL);
480		}
481
482		/*
483		 * If we're seeing a new Elf object, then we have an
484		 * archive. In this case, we create a new target, and chain it
485		 * off the master target.  We can later iterate over these
486		 * targets using dis_tgt_next().
487		 */
488		if (current->dt_elf != NULL) {
489			dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t));
490			next->dt_elf_root = tgt->dt_elf_root;
491			next->dt_fd = -1;
492			current->dt_next = next;
493			current = next;
494		}
495		current->dt_elf = elf;
496		current->dt_arhdr = arhdr;
497
498		if (elf_getshdrstrndx(elf, &current->dt_shstrndx) == -1) {
499			warn("%s: failed to get section string table for "
500			    "file", file);
501			dis_tgt_destroy(tgt);
502			return (NULL);
503		}
504
505		if (elf_getshdrnum(elf, &shnum) == -1) {
506			warn("%s: failed to get number of sections in file",
507			    file);
508			dis_tgt_destroy(tgt);
509			return (NULL);
510		}
511
512		current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) *
513		    shnum);
514		current->dt_shncount = shnum;
515
516		idx = 0;
517		dis_tgt_section_iter(current, tgt_scn_init, &idx);
518		current->dt_filename = file;
519
520		create_addrmap(current);
521		if (current->dt_symidx != 0)
522			construct_symtab(current);
523
524		cmd = elf_next(elf);
525	}
526
527	/*
528	 * Final sanity check.  If we had an archive with no members, then bail
529	 * out with a nice message.
530	 */
531	if (tgt->dt_elf == NULL) {
532		warn("%s: empty archive\n", file);
533		dis_tgt_destroy(tgt);
534		return (NULL);
535	}
536
537	return (tgt);
538}
539
540/*
541 * Return the filename associated with the target.
542 */
543const char *
544dis_tgt_name(dis_tgt_t *tgt)
545{
546	return (tgt->dt_filename);
547}
548
549/*
550 * Return the archive member name, if any.
551 */
552const char *
553dis_tgt_member(dis_tgt_t *tgt)
554{
555	if (tgt->dt_arhdr)
556		return (tgt->dt_arhdr->ar_name);
557	else
558		return (NULL);
559}
560
561/*
562 * Return the Elf_Ehdr associated with this target.  Needed to determine which
563 * disassembler to use.
564 */
565void
566dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr)
567{
568	(void) gelf_getehdr(tgt->dt_elf, ehdr);
569}
570
571/*
572 * Return the next target in the list, if this is an archive.
573 */
574dis_tgt_t *
575dis_tgt_next(dis_tgt_t *tgt)
576{
577	return (tgt->dt_next);
578}
579
580/*
581 * Destroy a target and free up any associated memory.
582 */
583void
584dis_tgt_destroy(dis_tgt_t *tgt)
585{
586	dis_tgt_t *current, *next;
587
588	current = tgt->dt_next;
589	while (current != NULL) {
590		next = current->dt_next;
591		if (current->dt_elf)
592			(void) elf_end(current->dt_elf);
593		if (current->dt_symtab)
594			free(current->dt_symtab);
595		free(current);
596		current = next;
597	}
598
599	if (tgt->dt_elf)
600		(void) elf_end(tgt->dt_elf);
601	if (tgt->dt_elf_root)
602		(void) elf_end(tgt->dt_elf_root);
603
604	if (tgt->dt_symtab)
605		free(tgt->dt_symtab);
606
607	free(tgt);
608}
609
610/*
611 * Given an address, return the section it is in and set the offset within
612 * the section.
613 */
614const char *
615dis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset)
616{
617	int i;
618
619	for (i = 1; i < tgt->dt_shncount; i++) {
620		if ((addr >= tgt->dt_shnmap[i].dm_start) &&
621		    (addr < tgt->dt_shnmap[i].dm_start +
622		    tgt->dt_shnmap[i].dm_length)) {
623			*offset = addr - tgt->dt_shnmap[i].dm_start;
624			return (tgt->dt_shnmap[i].dm_name);
625		}
626	}
627
628	*offset = 0;
629	return (NULL);
630}
631
632/*
633 * Given an address, returns the name of the corresponding symbol, as well as
634 * the offset within that symbol.  If no matching symbol is found, then NULL is
635 * returned.
636 *
637 * If 'cache_result' is specified, then we keep track of the resulting symbol.
638 * This cached result is consulted first on subsequent lookups in order to avoid
639 * unecessary lookups.  This flag should be used for resolving the current PC,
640 * as the majority of addresses stay within the current function.
641 */
642const char *
643dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
644    size_t *size, int *isfunc)
645{
646	int lo, hi, mid;
647	sym_entry_t *sym, *osym, *match;
648	int found;
649
650	*offset = 0;
651	*size = 0;
652	if (isfunc != NULL)
653		*isfunc = 0;
654
655	if (tgt->dt_symcache != NULL &&
656	    addr >= tgt->dt_symcache->se_sym.st_value &&
657	    addr < tgt->dt_symcache->se_sym.st_value +
658	    tgt->dt_symcache->se_sym.st_size) {
659		sym = tgt->dt_symcache;
660		*offset = addr - sym->se_sym.st_value;
661		*size = sym->se_sym.st_size;
662		if (isfunc != NULL)
663			*isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) ==
664			    STT_FUNC);
665		return (sym->se_name);
666	}
667
668	lo = 0;
669	hi = (tgt->dt_symcount - 1);
670	found = 0;
671	match = osym = NULL;
672	while (lo <= hi) {
673		mid = (lo + hi) / 2;
674
675		sym = &tgt->dt_symtab[mid];
676
677		if (addr >= sym->se_sym.st_value &&
678		    addr < sym->se_sym.st_value + sym->se_sym.st_size &&
679		    (!found || sym->se_sym.st_value > osym->se_sym.st_value)) {
680			osym = sym;
681			found = 1;
682		} else if (addr == sym->se_sym.st_value) {
683			/*
684			 * Particularly for .plt objects, it's possible to have
685			 * a zero sized object.  We want to return this, but we
686			 * want it to be a last resort.
687			 */
688			match = sym;
689		}
690
691		if (addr < sym->se_sym.st_value)
692			hi = mid - 1;
693		else
694			lo = mid + 1;
695	}
696
697	if (!found) {
698		if (match)
699			osym = match;
700		else
701			return (NULL);
702	}
703
704	/*
705	 * Walk backwards to find the best match.
706	 */
707	do {
708		sym = osym;
709
710		if (osym == tgt->dt_symtab)
711			break;
712
713		osym = osym - 1;
714	} while ((sym->se_sym.st_value == osym->se_sym.st_value) &&
715	    (addr >= osym->se_sym.st_value) &&
716	    (addr < osym->se_sym.st_value + osym->se_sym.st_size));
717
718	if (cache_result)
719		tgt->dt_symcache = sym;
720
721	*offset = addr - sym->se_sym.st_value;
722	*size = sym->se_sym.st_size;
723	if (isfunc)
724		*isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC);
725
726	return (sym->se_name);
727}
728
729#if !defined(__sparc)
730/*
731 * Given an address, return the starting offset of the next symbol in the file.
732 * Only needed on variable length instruction architectures.
733 */
734off_t
735dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
736{
737	sym_entry_t *sym;
738
739	sym = (tgt->dt_symcache != NULL) ? tgt->dt_symcache : tgt->dt_symtab;
740
741	while (sym != (tgt->dt_symtab + tgt->dt_symcount)) {
742		if (sym->se_sym.st_value >= addr)
743			return (sym->se_sym.st_value - addr);
744		sym++;
745	}
746
747	return (0);
748}
749#endif
750
751/*
752 * Iterate over all sections in the target, executing the given callback for
753 * each.
754 */
755void
756dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data)
757{
758	dis_scn_t sdata;
759	Elf_Scn *scn;
760	int idx;
761
762	for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL;
763	    scn = elf_nextscn(tgt->dt_elf, scn), idx++) {
764
765		if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) {
766			warn("%s: failed to get section %d header",
767			    tgt->dt_filename, idx);
768			continue;
769		}
770
771		if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx,
772		    sdata.ds_shdr.sh_name)) == NULL) {
773			warn("%s: failed to get section %d name",
774			    tgt->dt_filename, idx);
775			continue;
776		}
777
778		if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) {
779			warn("%s: failed to get data for section '%s'",
780			    tgt->dt_filename, sdata.ds_name);
781			continue;
782		}
783
784		/*
785		 * dis_tgt_section_iter is also used before the section map
786		 * is initialized, so only check when we need to.  If the
787		 * section map is uninitialized, it will return 0 and have
788		 * no net effect.
789		 */
790		if (sdata.ds_shdr.sh_addr == 0)
791			sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start;
792
793		func(tgt, &sdata, data);
794	}
795}
796
797/*
798 * Return 1 if the given section contains text, 0 otherwise.
799 */
800int
801dis_section_istext(dis_scn_t *scn)
802{
803	return ((scn->ds_shdr.sh_type == SHT_PROGBITS) &&
804	    (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)));
805}
806
807/*
808 * Return a pointer to the section data.
809 */
810void *
811dis_section_data(dis_scn_t *scn)
812{
813	return (scn->ds_data->d_buf);
814}
815
816/*
817 * Return the size of the section data.
818 */
819size_t
820dis_section_size(dis_scn_t *scn)
821{
822	return (scn->ds_data->d_size);
823}
824
825/*
826 * Return the address for the given section.
827 */
828uint64_t
829dis_section_addr(dis_scn_t *scn)
830{
831	return (scn->ds_shdr.sh_addr);
832}
833
834/*
835 * Return the name of the current section.
836 */
837const char *
838dis_section_name(dis_scn_t *scn)
839{
840	return (scn->ds_name);
841}
842
843/*
844 * Create an allocated copy of the given section
845 */
846dis_scn_t *
847dis_section_copy(dis_scn_t *scn)
848{
849	dis_scn_t *new;
850
851	new = safe_malloc(sizeof (dis_scn_t));
852	(void) memcpy(new, scn, sizeof (dis_scn_t));
853
854	return (new);
855}
856
857/*
858 * Free section memory
859 */
860void
861dis_section_free(dis_scn_t *scn)
862{
863	free(scn);
864}
865
866/*
867 * Iterate over all functions in the target, executing the given callback for
868 * each one.
869 */
870void
871dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data)
872{
873	int i;
874	sym_entry_t *sym;
875	dis_func_t df;
876	Elf_Scn *scn;
877	GElf_Shdr	shdr;
878
879	for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) {
880
881		/* ignore non-functions */
882		if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) ||
883		    (sym->se_name == NULL) ||
884		    (sym->se_sym.st_size == 0) ||
885		    (sym->se_shndx >= SHN_LORESERVE))
886			continue;
887
888		/* get the ELF data associated with this function */
889		if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL ||
890		    gelf_getshdr(scn, &shdr) == NULL ||
891		    (df.df_data = elf_getdata(scn, NULL)) == NULL ||
892		    df.df_data->d_size == 0) {
893			warn("%s: failed to read section %d",
894			    tgt->dt_filename, sym->se_shndx);
895			continue;
896		}
897
898		if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
899			shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start;
900
901		/*
902		 * Verify that the address lies within the section that we think
903		 * it does.
904		 */
905		if (sym->se_sym.st_value < shdr.sh_addr ||
906		    (sym->se_sym.st_value + sym->se_sym.st_size) >
907		    (shdr.sh_addr + shdr.sh_size)) {
908			warn("%s: bad section %d for address %p",
909			    tgt->dt_filename, sym->se_sym.st_shndx,
910			    sym->se_sym.st_value);
911			continue;
912		}
913
914		df.df_sym = sym;
915		df.df_offset = sym->se_sym.st_value - shdr.sh_addr;
916
917		func(tgt, &df, data);
918	}
919}
920
921/*
922 * Return the data associated with a given function.
923 */
924void *
925dis_function_data(dis_func_t *func)
926{
927	return ((char *)func->df_data->d_buf + func->df_offset);
928}
929
930/*
931 * Return the size of a function.
932 */
933size_t
934dis_function_size(dis_func_t *func)
935{
936	return (func->df_sym->se_sym.st_size);
937}
938
939/*
940 * Return the address of a function.
941 */
942uint64_t
943dis_function_addr(dis_func_t *func)
944{
945	return (func->df_sym->se_sym.st_value);
946}
947
948/*
949 * Return the name of the function
950 */
951const char *
952dis_function_name(dis_func_t *func)
953{
954	return (func->df_sym->se_name);
955}
956
957/*
958 * Return a copy of a function.
959 */
960dis_func_t *
961dis_function_copy(dis_func_t *func)
962{
963	dis_func_t *new;
964
965	new = safe_malloc(sizeof (dis_func_t));
966	(void) memcpy(new, func, sizeof (dis_func_t));
967
968	return (new);
969}
970
971/*
972 * Free function memory
973 */
974void
975dis_function_free(dis_func_t *func)
976{
977	free(func);
978}
979