/* * Retrieve the nth (where n is the `index` argument) shdr (section * header) from the given elf instance. * * A pointer to the shdr is returned on success, NULL on failure. */ static struct lttng_ust_elf_shdr *lttng_ust_elf_get_shdr(struct lttng_ust_elf *elf, uint16_t index) { struct lttng_ust_elf_shdr *shdr = NULL; off_t offset; if (!elf) { goto error; } if (index >= elf->ehdr->e_shnum) { goto error; } shdr = zmalloc(sizeof(struct lttng_ust_elf_shdr)); if (!shdr) { goto error; } offset = (off_t) elf->ehdr->e_shoff + (off_t) index * elf->ehdr->e_shentsize; if (lseek(elf->fd, offset, SEEK_SET) < 0) { goto error; } if (is_elf_32_bit(elf)) { Elf32_Shdr elf_shdr; if (lttng_ust_read(elf->fd, &elf_shdr, sizeof(elf_shdr)) < sizeof(elf_shdr)) { goto error; } if (!is_elf_native_endian(elf)) { bswap_shdr(elf_shdr); } copy_shdr(elf_shdr, *shdr); } else { Elf64_Shdr elf_shdr; if (lttng_ust_read(elf->fd, &elf_shdr, sizeof(elf_shdr)) < sizeof(elf_shdr)) { goto error; } if (!is_elf_native_endian(elf)) { bswap_shdr(elf_shdr); } copy_shdr(elf_shdr, *shdr); } return shdr; error: free(shdr); return NULL; }
/* Best attempt to load symbols from this ELF object. */ static void load_symbols(struct elfhdr *hdr, int fd) { unsigned int i, nsyms; struct elf_shdr sechdr, symtab, strtab; char *strings; struct syminfo *s; struct elf_sym *syms; lseek(fd, hdr->e_shoff, SEEK_SET); for (i = 0; i < hdr->e_shnum; i++) { if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr)) return; #ifdef BSWAP_NEEDED bswap_shdr(&sechdr); #endif if (sechdr.sh_type == SHT_SYMTAB) { symtab = sechdr; lseek(fd, hdr->e_shoff + sizeof(sechdr) * sechdr.sh_link, SEEK_SET); if (read(fd, &strtab, sizeof(strtab)) != sizeof(strtab)) return; #ifdef BSWAP_NEEDED bswap_shdr(&strtab); #endif goto found; } } return; /* Shouldn't happen... */ found: /* Now know where the strtab and symtab are. Snarf them. */ s = malloc(sizeof(*s)); syms = malloc(symtab.sh_size); if (!syms) return; s->disas_strtab = strings = malloc(strtab.sh_size); if (!s->disas_strtab) return; lseek(fd, symtab.sh_offset, SEEK_SET); if (read(fd, syms, symtab.sh_size) != symtab.sh_size) return; nsyms = symtab.sh_size / sizeof(struct elf_sym); i = 0; while (i < nsyms) { #ifdef BSWAP_NEEDED bswap_sym(syms + i); #endif // Throw away entries which we do not need. if (syms[i].st_shndx == SHN_UNDEF || syms[i].st_shndx >= SHN_LORESERVE || ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { nsyms--; if (i < nsyms) { syms[i] = syms[nsyms]; } continue; } #if defined(TARGET_ARM) || defined (TARGET_MIPS) /* The bottom address bit marks a Thumb or MIPS16 symbol. */ syms[i].st_value &= ~(target_ulong)1; #endif i++; } syms = realloc(syms, nsyms * sizeof(*syms)); qsort(syms, nsyms, sizeof(*syms), symcmp); lseek(fd, strtab.sh_offset, SEEK_SET); if (read(fd, strings, strtab.sh_size) != strtab.sh_size) return; s->disas_num_syms = nsyms; #if ELF_CLASS == ELFCLASS32 s->disas_symtab.elf32 = syms; s->lookup_symbol = lookup_symbolxx; #else s->disas_symtab.elf64 = syms; s->lookup_symbol = lookup_symbolxx; #endif s->next = syminfos; syminfos = s; }