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
26 #include <assert.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <gelf.h>
30 #include <libelf.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 #include <sys/fcntl.h>
36 #include <sys/stat.h>
37
38 #include "dis_target.h"
39 #include "dis_util.h"
40
41 /*
42 * Standard ELF disassembler target.
43 *
44 * We only support disassembly of ELF files, though this target interface could
45 * be extended in the future. Each basic type (target, func, section) contains
46 * enough information to uniquely identify the location within the file. The
47 * interfaces use libelf(3LIB) to do the actual processing of the file.
48 */
49
50 /*
51 * Symbol table entry type. We maintain our own symbol table sorted by address,
52 * with the symbol name already resolved against the ELF symbol table.
53 */
54 typedef struct sym_entry {
55 GElf_Sym se_sym; /* value of symbol */
56 char *se_name; /* name of symbol */
57 int se_shndx; /* section where symbol is located */
58 } sym_entry_t;
59
60 /*
61 * Target data structure. This structure keeps track of the ELF file
62 * information, a few bits of pre-processed section index information, and
63 * sorted versions of the symbol table. We also keep track of the last symbol
64 * looked up, as the majority of lookups remain within the same symbol.
65 */
66 struct dis_tgt {
67 Elf *dt_elf; /* libelf handle */
68 Elf *dt_elf_root; /* main libelf handle (for archives) */
69 const char *dt_filename; /* name of file */
70 int dt_fd; /* underlying file descriptor */
71 size_t dt_shstrndx; /* section index of .shstrtab */
72 size_t dt_symidx; /* section index of symbol table */
73 sym_entry_t *dt_symcache; /* last symbol looked up */
74 sym_entry_t *dt_symtab; /* sorted symbol table */
75 int dt_symcount; /* # of symbol table entries */
76 struct dis_tgt *dt_next; /* next target (for archives) */
77 Elf_Arhdr *dt_arhdr; /* archive header (for archives) */
78 };
79
80 /*
81 * Function data structure. We resolve the symbol and lookup the associated ELF
82 * data when building this structure. The offset is calculated based on the
83 * section's starting address.
84 */
85 struct dis_func {
86 sym_entry_t *df_sym; /* symbol table reference */
87 Elf_Data *df_data; /* associated ELF data */
88 size_t df_offset; /* offset within data */
89 };
90
91 /*
92 * Section data structure. We store the entire section header so that we can
93 * determine some properties (such as whether or not it contains text) after
94 * building the structure.
95 */
96 struct dis_scn {
97 GElf_Shdr ds_shdr;
98 const char *ds_name;
99 Elf_Data *ds_data;
100 };
101
102 /* Lifted from Psymtab.c, omitting STT_TLS */
103 #define DATA_TYPES \
104 ((1 << STT_OBJECT) | (1 << STT_FUNC) | (1 << STT_COMMON))
105 #define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0)
106
107 /*
108 * Pick out the best symbol to used based on the sections available in the
109 * target. We prefer SHT_SYMTAB over SHT_DYNSYM.
110 */
111 /* ARGSUSED */
112 static void
get_symtab(dis_tgt_t * tgt,dis_scn_t * scn,void * data)113 get_symtab(dis_tgt_t *tgt, dis_scn_t *scn, void *data)
114 {
115 int *index = data;
116
117 *index += 1;
118
119 /*
120 * Prefer SHT_SYMTAB over SHT_DYNSYM
121 */
122 if (scn->ds_shdr.sh_type == SHT_DYNSYM && tgt->dt_symidx == 0)
123 tgt->dt_symidx = *index;
124 else if (scn->ds_shdr.sh_type == SHT_SYMTAB)
125 tgt->dt_symidx = *index;
126 }
127
128 static int
sym_compare(const void * a,const void * b)129 sym_compare(const void *a, const void *b)
130 {
131 const sym_entry_t *syma = a;
132 const sym_entry_t *symb = b;
133 const char *aname = syma->se_name;
134 const char *bname = symb->se_name;
135
136 if (syma->se_sym.st_value < symb->se_sym.st_value)
137 return (-1);
138
139 if (syma->se_sym.st_value > symb->se_sym.st_value)
140 return (1);
141
142 /*
143 * Prefer functions over non-functions
144 */
145 if (GELF_ST_TYPE(syma->se_sym.st_info) !=
146 GELF_ST_TYPE(symb->se_sym.st_info)) {
147 if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC)
148 return (-1);
149 if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC)
150 return (1);
151 }
152
153 /*
154 * For symbols with the same address and type, we sort them according to
155 * a hierarchy:
156 *
157 * 1. weak symbols (common name)
158 * 2. global symbols (external name)
159 * 3. local symbols
160 */
161 if (GELF_ST_BIND(syma->se_sym.st_info) !=
162 GELF_ST_BIND(symb->se_sym.st_info)) {
163 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK)
164 return (-1);
165 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK)
166 return (1);
167
168 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL)
169 return (-1);
170 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL)
171 return (1);
172 }
173
174 /*
175 * As a last resort, if we have multiple symbols of the same type at the
176 * same address, prefer the version with the fewest leading underscores.
177 */
178 if (aname == NULL)
179 return (-1);
180 if (bname == NULL)
181 return (1);
182
183 while (*aname == '_' && *bname == '_') {
184 aname++;
185 bname++;
186 }
187
188 if (*bname == '_')
189 return (-1);
190 if (*aname == '_')
191 return (1);
192
193 /*
194 * Prefer the symbol with the smaller size.
195 */
196 if (syma->se_sym.st_size < symb->se_sym.st_size)
197 return (-1);
198 if (syma->se_sym.st_size > symb->se_sym.st_size)
199 return (1);
200
201 /*
202 * We really do have two identical symbols for some reason. Just report
203 * them as equal, and to the lucky one go the spoils.
204 */
205 return (0);
206 }
207
208 /*
209 * Construct an optimized symbol table sorted by starting address.
210 */
211 static void
construct_symtab(dis_tgt_t * tgt)212 construct_symtab(dis_tgt_t *tgt)
213 {
214 Elf_Scn *scn;
215 GElf_Shdr shdr;
216 Elf_Data *symdata;
217 int i;
218 GElf_Word *symshndx = NULL;
219 int symshndx_size;
220 sym_entry_t *sym;
221 sym_entry_t *p_symtab = NULL;
222 int nsym = 0; /* count of symbols we're not interested in */
223
224 /*
225 * Find the symshndx section, if any
226 */
227 for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL;
228 scn = elf_nextscn(tgt->dt_elf, scn)) {
229 if (gelf_getshdr(scn, &shdr) == NULL)
230 break;
231 if (shdr.sh_type == SHT_SYMTAB_SHNDX &&
232 shdr.sh_link == tgt->dt_symidx) {
233 Elf_Data *data;
234
235 if ((data = elf_getdata(scn, NULL)) != NULL) {
236 symshndx = (GElf_Word *)data->d_buf;
237 symshndx_size = data->d_size /
238 sizeof (GElf_Word);
239 break;
240 }
241 }
242 }
243
244 if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL)
245 die("%s: failed to get section information", tgt->dt_filename);
246 if (gelf_getshdr(scn, &shdr) == NULL)
247 die("%s: failed to get section header", tgt->dt_filename);
248 if (shdr.sh_entsize == 0)
249 die("%s: symbol table has zero size", tgt->dt_filename);
250
251 if ((symdata = elf_getdata(scn, NULL)) == NULL)
252 die("%s: failed to get symbol table", tgt->dt_filename);
253
254 tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM,
255 1, EV_CURRENT);
256
257 p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t));
258
259 for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) {
260 if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) {
261 warn("%s: gelf_getsym returned NULL for %d",
262 tgt->dt_filename, i);
263 nsym++;
264 continue;
265 }
266
267 /*
268 * We're only interested in data symbols.
269 */
270 if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) {
271 nsym++;
272 continue;
273 }
274
275 if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) {
276 if (i > symshndx_size) {
277 warn("%s: bad SHNX_XINDEX %d",
278 tgt->dt_filename, i);
279 sym->se_shndx = -1;
280 } else {
281 sym->se_shndx = symshndx[i];
282 }
283 } else {
284 sym->se_shndx = sym->se_sym.st_shndx;
285 }
286
287 if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link,
288 (size_t)sym->se_sym.st_name)) == NULL) {
289 warn("%s: failed to lookup symbol %d name",
290 tgt->dt_filename, i);
291 nsym++;
292 continue;
293 }
294
295 sym++;
296 }
297
298 tgt->dt_symcount -= nsym;
299 tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount *
300 sizeof (sym_entry_t));
301
302 qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t),
303 sym_compare);
304 }
305
306 /*
307 * Create a target backed by an ELF file.
308 */
309 dis_tgt_t *
dis_tgt_create(const char * file)310 dis_tgt_create(const char *file)
311 {
312 dis_tgt_t *tgt, *current;
313 int idx;
314 Elf *elf;
315 GElf_Ehdr ehdr;
316 Elf_Arhdr *arhdr = NULL;
317 int cmd;
318
319 if (elf_version(EV_CURRENT) == EV_NONE)
320 die("libelf(3ELF) out of date");
321
322 tgt = safe_malloc(sizeof (dis_tgt_t));
323
324 if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) {
325 warn("%s: failed opening file, reason: %s", file,
326 strerror(errno));
327 free(tgt);
328 return (NULL);
329 }
330
331 if ((tgt->dt_elf_root =
332 elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) {
333 warn("%s: invalid or corrupt ELF file", file);
334 dis_tgt_destroy(tgt);
335 return (NULL);
336 }
337
338 current = tgt;
339 cmd = ELF_C_READ;
340 while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) {
341
342 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
343 (arhdr = elf_getarhdr(elf)) == NULL) {
344 warn("%s: malformed archive", file);
345 dis_tgt_destroy(tgt);
346 return (NULL);
347 }
348
349 /*
350 * Make sure that this Elf file is sane
351 */
352 if (gelf_getehdr(elf, &ehdr) == NULL) {
353 if (arhdr != NULL) {
354 /*
355 * For archives, we drive on in the face of bad
356 * members. The "/" and "//" members are
357 * special, and should be silently ignored.
358 */
359 if (strcmp(arhdr->ar_name, "/") != 0 &&
360 strcmp(arhdr->ar_name, "//") != 0)
361 warn("%s[%s]: invalid file type",
362 file, arhdr->ar_name);
363 cmd = elf_next(elf);
364 (void) elf_end(elf);
365 continue;
366 }
367
368 warn("%s: invalid file type", file);
369 dis_tgt_destroy(tgt);
370 return (NULL);
371 }
372
373 /*
374 * If we're seeing a new Elf object, then we have an
375 * archive. In this case, we create a new target, and chain it
376 * off the master target. We can later iterate over these
377 * targets using dis_tgt_next().
378 */
379 if (current->dt_elf != NULL) {
380 dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t));
381 next->dt_elf_root = tgt->dt_elf_root;
382 next->dt_fd = -1;
383 current->dt_next = next;
384 current = next;
385 }
386 current->dt_elf = elf;
387 current->dt_arhdr = arhdr;
388
389 if (elf_getshdrstrndx(elf, ¤t->dt_shstrndx) == -1) {
390 warn("%s: failed to get section string table for "
391 "file", file);
392 dis_tgt_destroy(tgt);
393 return (NULL);
394 }
395
396 idx = 0;
397 dis_tgt_section_iter(current, get_symtab, &idx);
398
399 if (current->dt_symidx != 0)
400 construct_symtab(current);
401
402 current->dt_filename = file;
403
404 cmd = elf_next(elf);
405 }
406
407 /*
408 * Final sanity check. If we had an archive with no members, then bail
409 * out with a nice message.
410 */
411 if (tgt->dt_elf == NULL) {
412 warn("%s: empty archive\n", file);
413 dis_tgt_destroy(tgt);
414 return (NULL);
415 }
416
417 return (tgt);
418 }
419
420 /*
421 * Return the filename associated with the target.
422 */
423 const char *
dis_tgt_name(dis_tgt_t * tgt)424 dis_tgt_name(dis_tgt_t *tgt)
425 {
426 return (tgt->dt_filename);
427 }
428
429 /*
430 * Return the archive member name, if any.
431 */
432 const char *
dis_tgt_member(dis_tgt_t * tgt)433 dis_tgt_member(dis_tgt_t *tgt)
434 {
435 if (tgt->dt_arhdr)
436 return (tgt->dt_arhdr->ar_name);
437 else
438 return (NULL);
439 }
440
441 /*
442 * Return the Elf_Ehdr associated with this target. Needed to determine which
443 * disassembler to use.
444 */
445 void
dis_tgt_ehdr(dis_tgt_t * tgt,GElf_Ehdr * ehdr)446 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr)
447 {
448 (void) gelf_getehdr(tgt->dt_elf, ehdr);
449 }
450
451 /*
452 * Return the next target in the list, if this is an archive.
453 */
454 dis_tgt_t *
dis_tgt_next(dis_tgt_t * tgt)455 dis_tgt_next(dis_tgt_t *tgt)
456 {
457 return (tgt->dt_next);
458 }
459
460 /*
461 * Destroy a target and free up any associated memory.
462 */
463 void
dis_tgt_destroy(dis_tgt_t * tgt)464 dis_tgt_destroy(dis_tgt_t *tgt)
465 {
466 dis_tgt_t *current, *next;
467
468 current = tgt->dt_next;
469 while (current != NULL) {
470 next = current->dt_next;
471 if (current->dt_elf)
472 (void) elf_end(current->dt_elf);
473 if (current->dt_symtab)
474 free(current->dt_symtab);
475 free(current);
476 current = next;
477 }
478
479 if (tgt->dt_elf)
480 (void) elf_end(tgt->dt_elf);
481 if (tgt->dt_elf_root)
482 (void) elf_end(tgt->dt_elf_root);
483
484 if (tgt->dt_symtab)
485 free(tgt->dt_symtab);
486
487 free(tgt);
488 }
489
490 /*
491 * Given an address, returns the name of the corresponding symbol, as well as
492 * the offset within that symbol. If no matching symbol is found, then NULL is
493 * returned.
494 *
495 * If 'cache_result' is specified, then we keep track of the resulting symbol.
496 * This cached result is consulted first on subsequent lookups in order to avoid
497 * unecessary lookups. This flag should be used for resolving the current PC,
498 * as the majority of addresses stay within the current function.
499 */
500 const char *
dis_tgt_lookup(dis_tgt_t * tgt,uint64_t addr,off_t * offset,int cache_result,size_t * size,int * isfunc)501 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
502 size_t *size, int *isfunc)
503 {
504 int lo, hi, mid;
505 sym_entry_t *sym, *osym, *match;
506 int found;
507
508 if (tgt->dt_symcache != NULL &&
509 addr >= tgt->dt_symcache->se_sym.st_value &&
510 addr < tgt->dt_symcache->se_sym.st_value +
511 tgt->dt_symcache->se_sym.st_size) {
512 *offset = addr - tgt->dt_symcache->se_sym.st_value;
513 *size = tgt->dt_symcache->se_sym.st_size;
514 return (tgt->dt_symcache->se_name);
515 }
516
517 lo = 0;
518 hi = (tgt->dt_symcount - 1);
519 found = 0;
520 match = osym = NULL;
521 while (lo <= hi) {
522 mid = (lo + hi) / 2;
523
524 sym = &tgt->dt_symtab[mid];
525
526 if (addr >= sym->se_sym.st_value &&
527 addr < sym->se_sym.st_value + sym->se_sym.st_size &&
528 (!found || sym->se_sym.st_value > osym->se_sym.st_value)) {
529 osym = sym;
530 found = 1;
531 } else if (addr == sym->se_sym.st_value) {
532 /*
533 * Particularly for .plt objects, it's possible to have
534 * a zero sized object. We want to return this, but we
535 * want it to be a last resort.
536 */
537 match = sym;
538 }
539
540 if (addr < sym->se_sym.st_value)
541 hi = mid - 1;
542 else
543 lo = mid + 1;
544 }
545
546 if (!found) {
547 if (match)
548 osym = match;
549 else
550 return (NULL);
551 }
552
553 /*
554 * Walk backwards to find the best match.
555 */
556 do {
557 sym = osym;
558
559 if (osym == tgt->dt_symtab)
560 break;
561
562 osym = osym - 1;
563 } while ((sym->se_sym.st_value == osym->se_sym.st_value) &&
564 (addr >= osym->se_sym.st_value) &&
565 (addr < osym->se_sym.st_value + osym->se_sym.st_size));
566
567 if (cache_result)
568 tgt->dt_symcache = sym;
569
570 *offset = addr - sym->se_sym.st_value;
571 *size = sym->se_sym.st_size;
572 if (isfunc)
573 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC);
574
575 return (sym->se_name);
576 }
577
578 /*
579 * Given an address, return the starting offset of the next symbol in the file.
580 * Relies on the fact that this is only used when we encounter a bad instruction
581 * in the input stream, so we know that the last symbol looked up will be in the
582 * cache.
583 */
584 off_t
dis_tgt_next_symbol(dis_tgt_t * tgt,uint64_t addr)585 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
586 {
587 sym_entry_t *sym = tgt->dt_symcache;
588 uint64_t start;
589
590 /* make sure the cached symbol and address are valid */
591 if (sym == NULL || addr < sym->se_sym.st_value ||
592 addr >= sym->se_sym.st_value + sym->se_sym.st_size)
593 return (0);
594
595 start = sym->se_sym.st_value;
596
597 /* find the next symbol */
598 while (sym != tgt->dt_symtab + tgt->dt_symcount &&
599 sym->se_sym.st_value == start)
600 sym++;
601
602 return (sym->se_sym.st_value - addr);
603 }
604
605 /*
606 * Iterate over all sections in the target, executing the given callback for
607 * each.
608 */
609 void
dis_tgt_section_iter(dis_tgt_t * tgt,section_iter_f func,void * data)610 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data)
611 {
612 dis_scn_t sdata;
613 Elf_Scn *scn;
614 int idx;
615
616 for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL;
617 scn = elf_nextscn(tgt->dt_elf, scn), idx++) {
618
619 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) {
620 warn("%s: failed to get section %d header",
621 tgt->dt_filename, idx);
622 continue;
623 }
624
625 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx,
626 sdata.ds_shdr.sh_name)) == NULL) {
627 warn("%s: failed to get section %d name",
628 tgt->dt_filename, idx);
629 continue;
630 }
631
632 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) {
633 warn("%s: failed to get data for section '%s'",
634 tgt->dt_filename, sdata.ds_name);
635 continue;
636 }
637
638 func(tgt, &sdata, data);
639 }
640 }
641
642 /*
643 * Return 1 if the given section contains text, 0 otherwise.
644 */
645 int
dis_section_istext(dis_scn_t * scn)646 dis_section_istext(dis_scn_t *scn)
647 {
648 return ((scn->ds_shdr.sh_type == SHT_PROGBITS) &&
649 (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)));
650 }
651
652 /*
653 * Return a pointer to the section data.
654 */
655 void *
dis_section_data(dis_scn_t * scn)656 dis_section_data(dis_scn_t *scn)
657 {
658 return (scn->ds_data->d_buf);
659 }
660
661 /*
662 * Return the size of the section data.
663 */
664 size_t
dis_section_size(dis_scn_t * scn)665 dis_section_size(dis_scn_t *scn)
666 {
667 return (scn->ds_data->d_size);
668 }
669
670 /*
671 * Return the address for the given section.
672 */
673 uint64_t
dis_section_addr(dis_scn_t * scn)674 dis_section_addr(dis_scn_t *scn)
675 {
676 return (scn->ds_shdr.sh_addr);
677 }
678
679 /*
680 * Return the name of the current section.
681 */
682 const char *
dis_section_name(dis_scn_t * scn)683 dis_section_name(dis_scn_t *scn)
684 {
685 return (scn->ds_name);
686 }
687
688 /*
689 * Create an allocated copy of the given section
690 */
691 dis_scn_t *
dis_section_copy(dis_scn_t * scn)692 dis_section_copy(dis_scn_t *scn)
693 {
694 dis_scn_t *new;
695
696 new = safe_malloc(sizeof (dis_scn_t));
697 (void) memcpy(new, scn, sizeof (dis_scn_t));
698
699 return (new);
700 }
701
702 /*
703 * Free section memory
704 */
705 void
dis_section_free(dis_scn_t * scn)706 dis_section_free(dis_scn_t *scn)
707 {
708 free(scn);
709 }
710
711 /*
712 * Iterate over all functions in the target, executing the given callback for
713 * each one.
714 */
715 void
dis_tgt_function_iter(dis_tgt_t * tgt,function_iter_f func,void * data)716 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data)
717 {
718 int i;
719 sym_entry_t *sym;
720 dis_func_t df;
721 Elf_Scn *scn;
722 GElf_Shdr shdr;
723
724 for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) {
725
726 /* ignore non-functions */
727 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) ||
728 (sym->se_name == NULL) ||
729 (sym->se_sym.st_size == 0) ||
730 (sym->se_shndx >= SHN_LORESERVE))
731 continue;
732
733 /* get the ELF data associated with this function */
734 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL ||
735 gelf_getshdr(scn, &shdr) == NULL ||
736 (df.df_data = elf_getdata(scn, NULL)) == NULL ||
737 df.df_data->d_size == 0) {
738 warn("%s: failed to read section %d",
739 tgt->dt_filename, sym->se_shndx);
740 continue;
741 }
742
743 /*
744 * Verify that the address lies within the section that we think
745 * it does.
746 */
747 if (sym->se_sym.st_value < shdr.sh_addr ||
748 (sym->se_sym.st_value + sym->se_sym.st_size) >
749 (shdr.sh_addr + shdr.sh_size)) {
750 warn("%s: bad section %d for address %p",
751 tgt->dt_filename, sym->se_sym.st_shndx,
752 sym->se_sym.st_value);
753 continue;
754 }
755
756 df.df_sym = sym;
757 df.df_offset = sym->se_sym.st_value - shdr.sh_addr;
758
759 func(tgt, &df, data);
760 }
761 }
762
763 /*
764 * Return the data associated with a given function.
765 */
766 void *
dis_function_data(dis_func_t * func)767 dis_function_data(dis_func_t *func)
768 {
769 return ((char *)func->df_data->d_buf + func->df_offset);
770 }
771
772 /*
773 * Return the size of a function.
774 */
775 size_t
dis_function_size(dis_func_t * func)776 dis_function_size(dis_func_t *func)
777 {
778 return (func->df_sym->se_sym.st_size);
779 }
780
781 /*
782 * Return the address of a function.
783 */
784 uint64_t
dis_function_addr(dis_func_t * func)785 dis_function_addr(dis_func_t *func)
786 {
787 return (func->df_sym->se_sym.st_value);
788 }
789
790 /*
791 * Return the name of the function
792 */
793 const char *
dis_function_name(dis_func_t * func)794 dis_function_name(dis_func_t *func)
795 {
796 return (func->df_sym->se_name);
797 }
798
799 /*
800 * Return a copy of a function.
801 */
802 dis_func_t *
dis_function_copy(dis_func_t * func)803 dis_function_copy(dis_func_t *func)
804 {
805 dis_func_t *new;
806
807 new = safe_malloc(sizeof (dis_func_t));
808 (void) memcpy(new, func, sizeof (dis_func_t));
809
810 return (new);
811 }
812
813 /*
814 * Free function memory
815 */
816 void
dis_function_free(dis_func_t * func)817 dis_function_free(dis_func_t *func)
818 {
819 free(func);
820 }
821