1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <fcntl.h> 2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdio.h> 3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <errno.h> 4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h> 5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <unistd.h> 6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <inttypes.h> 7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "symbol.h" 9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "debug.h" 10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#ifndef HAVE_ELF_GETPHDRNUM 12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int elf_getphdrnum(Elf *elf, size_t *dst) 13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr gehdr; 15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr *ehdr; 16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ehdr = gelf_getehdr(elf, &gehdr); 18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!ehdr) 19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *dst = ehdr->e_phnum; 22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#endif 26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#ifndef NT_GNU_BUILD_ID 28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define NT_GNU_BUILD_ID 3 29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#endif 30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/** 32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * elf_symtab__for_each_symbol - iterate thru all the symbols 33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * @syms: struct elf_symtab instance to iterate 35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * @idx: uint32_t idx 36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * @sym: GElf_Sym iterator 37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (idx = 0, gelf_getsym(syms, idx, &sym);\ 40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng idx < nr_syms; \ 41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng idx++, gelf_getsym(syms, idx, &sym)) 42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline uint8_t elf_sym__type(const GElf_Sym *sym) 44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return GELF_ST_TYPE(sym->st_info); 46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline int elf_sym__is_function(const GElf_Sym *sym) 49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sym__type(sym) == STT_FUNC && 51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_name != 0 && 52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_shndx != SHN_UNDEF; 53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline bool elf_sym__is_object(const GElf_Sym *sym) 56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sym__type(sym) == STT_OBJECT && 58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_name != 0 && 59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_shndx != SHN_UNDEF; 60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline int elf_sym__is_label(const GElf_Sym *sym) 63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sym__type(sym) == STT_NOTYPE && 65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_name != 0 && 66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_shndx != SHN_UNDEF && 67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym->st_shndx != SHN_ABS; 68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) 71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (type) { 73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case MAP__FUNCTION: 74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sym__is_function(sym); 75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case MAP__VARIABLE: 76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sym__is_object(sym); 77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return false; 79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline const char *elf_sym__name(const GElf_Sym *sym, 83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const Elf_Data *symstrs) 84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return symstrs->d_buf + sym->st_name; 86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline const char *elf_sec__name(const GElf_Shdr *shdr, 89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const Elf_Data *secstrs) 90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return secstrs->d_buf + shdr->sh_name; 92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline int elf_sec__is_text(const GElf_Shdr *shdr, 95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const Elf_Data *secstrs) 96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic inline bool elf_sec__is_data(const GElf_Shdr *shdr, 101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const Elf_Data *secstrs) 102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, 107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng enum map_type type) 108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (type) { 110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case MAP__FUNCTION: 111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sec__is_text(shdr, secstrs); 112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case MAP__VARIABLE: 113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return elf_sec__is_data(shdr, secstrs); 114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return false; 116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *sec = NULL; 122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr; 123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t cnt = 1; 124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while ((sec = elf_nextscn(elf, sec)) != NULL) { 126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng gelf_getshdr(sec, &shdr); 127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((addr >= shdr.sh_addr) && 129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (addr < (shdr.sh_addr + shdr.sh_size))) 130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return cnt; 131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++cnt; 133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr *shp, const char *name, 140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t *idx) 141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *sec = NULL; 143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t cnt = 1; 144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Elf is corrupted/truncated, avoid calling elf_strptr. */ 146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) 147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return NULL; 148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while ((sec = elf_nextscn(elf, sec)) != NULL) { 150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *str; 151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng gelf_getshdr(sec, shp); 153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!strcmp(name, str)) { 155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (idx) 156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *idx = cnt; 157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++cnt; 160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return sec; 163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng idx < nr_entries; \ 168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng idx < nr_entries; \ 173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * We need to check if we have a .dynsym, so that we can handle the 177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * .plt, synthesizing its symbols, that aren't on the symtabs (be it 178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * .dynsym or .symtab). 179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * And always look at the original dso, not at debuginfo packages, that 180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map, 183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol_filter_t filter) 184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng uint32_t nr_rel_entries, idx; 186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Sym sym; 187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 plt_offset; 188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr_plt; 189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct symbol *f; 190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr_rel_plt, shdr_dynsym; 191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Data *reldata, *syms, *symstrs; 192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t dynsym_idx; 194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr ehdr; 195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char sympltname[1024]; 196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int nr = 0, symidx, err = 0; 198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!ss->dynsym) 200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = ss->elf; 203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ehdr = ss->ehdr; 204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng scn_dynsym = ss->dynsym; 206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng shdr_dynsym = ss->dynshdr; 207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dynsym_idx = ss->dynsym_idx; 208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (scn_dynsym == NULL) 210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".rela.plt", NULL); 214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (scn_plt_rel == NULL) { 215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".rel.plt", NULL); 217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (scn_plt_rel == NULL) 218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = -1; 222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (shdr_rel_plt.sh_link != dynsym_idx) 224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Fetch the relocation section to find the idxes to the GOT 231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * and the symbols in the .dynsym they refer to. 232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng reldata = elf_getdata(scn_plt_rel, NULL); 234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (reldata == NULL) 235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng syms = elf_getdata(scn_dynsym, NULL); 238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (syms == NULL) 239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (scn_symstrs == NULL) 243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symstrs = elf_getdata(scn_symstrs, NULL); 246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (symstrs == NULL) 247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (symstrs->d_size == 0) 250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng plt_offset = shdr_plt.sh_offset; 254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (shdr_rel_plt.sh_type == SHT_RELA) { 256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Rela pos_mem, *pos; 257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_section__for_each_rela(reldata, pos, pos_mem, idx, 259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr_rel_entries) { 260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symidx = GELF_R_SYM(pos->r_info); 261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng plt_offset += shdr_plt.sh_entsize; 262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng gelf_getsym(syms, symidx, &sym); 263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng snprintf(sympltname, sizeof(sympltname), 264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "%s@plt", elf_sym__name(&sym, symstrs)); 265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng f = symbol__new(plt_offset, shdr_plt.sh_entsize, 267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng STB_GLOBAL, sympltname); 268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!f) 269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (filter && filter(map, f)) 272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__delete(f); 273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else { 274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbols__insert(&dso->symbols[map->type], f); 275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++nr; 276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else if (shdr_rel_plt.sh_type == SHT_REL) { 279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Rel pos_mem, *pos; 280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_section__for_each_rel(reldata, pos, pos_mem, idx, 281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr_rel_entries) { 282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symidx = GELF_R_SYM(pos->r_info); 283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng plt_offset += shdr_plt.sh_entsize; 284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng gelf_getsym(syms, symidx, &sym); 285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng snprintf(sympltname, sizeof(sympltname), 286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "%s@plt", elf_sym__name(&sym, symstrs)); 287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng f = symbol__new(plt_offset, shdr_plt.sh_entsize, 289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng STB_GLOBAL, sympltname); 290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!f) 291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (filter && filter(map, f)) 294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__delete(f); 295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else { 296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbols__insert(&dso->symbols[map->type], f); 297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ++nr; 298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = 0; 303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_elf_end: 304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (err == 0) 305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return nr; 306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("%s: problems reading %s PLT info.\n", 307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng __func__, dso->long_name); 308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/* 312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Align offset to 4 bytes as needed for note name and descriptor data. 313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define NOTE_ALIGN(n) (((n) + 3) & -4U) 315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int elf_read_build_id(Elf *elf, void *bf, size_t size) 317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int err = -1; 319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr ehdr; 320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr; 321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Data *data; 322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *sec; 323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Kind ek; 324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng void *ptr; 325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (size < BUILD_ID_SIZE) 327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ek = elf_kind(elf); 330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ek != ELF_K_ELF) 331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (gelf_getehdr(elf, &ehdr) == NULL) { 334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("%s: cannot get elf header.\n", __func__); 335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Check following sections for notes: 340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * '.note.gnu.build-id' 341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * '.notes' 342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * '.note' (VDSO specific) 343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng do { 345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = elf_section_by_name(elf, &ehdr, &shdr, 346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".note.gnu.build-id", NULL); 347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sec) 348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = elf_section_by_name(elf, &ehdr, &shdr, 351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".notes", NULL); 352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sec) 353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = elf_section_by_name(elf, &ehdr, &shdr, 356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".note", NULL); 357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sec) 358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 359e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 360e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 361e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 362e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } while (0); 363e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 364e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng data = elf_getdata(sec, NULL); 365e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (data == NULL) 366e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 367e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 368e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ptr = data->d_buf; 369e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (ptr < (data->d_buf + data->d_size)) { 370e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Nhdr *nhdr = ptr; 371e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t namesz = NOTE_ALIGN(nhdr->n_namesz), 372e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng descsz = NOTE_ALIGN(nhdr->n_descsz); 373e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *name; 374e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 375e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ptr += sizeof(*nhdr); 376e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng name = ptr; 377e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ptr += namesz; 378e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (nhdr->n_type == NT_GNU_BUILD_ID && 379e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nhdr->n_namesz == sizeof("GNU")) { 380e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 381e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t sz = min(size, descsz); 382e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memcpy(bf, ptr, sz); 383e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memset(bf + sz, 0, size - sz); 384e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = descsz; 385e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 386e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 387e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 388e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ptr += descsz; 389e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 390e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 391e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout: 392e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 393e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 394e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 395e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint filename__read_build_id(const char *filename, void *bf, size_t size) 396e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 397e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int fd, err = -1; 398e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 399e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 400e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (size < BUILD_ID_SIZE) 401e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 402e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 403e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fd = open(filename, O_RDONLY); 404e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (fd < 0) 405e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 406e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 407e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 408e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf == NULL) { 409e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 410e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 411e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 412e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 413e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = elf_read_build_id(elf, bf, size); 414e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 415e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_end(elf); 416e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_close: 417e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng close(fd); 418e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout: 419e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 420e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 421e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 422e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint sysfs__read_build_id(const char *filename, void *build_id, size_t size) 423e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 424e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int fd, err = -1; 425e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 426e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (size < BUILD_ID_SIZE) 427e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 428e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 429e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fd = open(filename, O_RDONLY); 430e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (fd < 0) 431e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 432e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 433e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng while (1) { 434e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char bf[BUFSIZ]; 435e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Nhdr nhdr; 436e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t namesz, descsz; 437e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 438e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 439e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 440e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 441e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng namesz = NOTE_ALIGN(nhdr.n_namesz); 442e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng descsz = NOTE_ALIGN(nhdr.n_descsz); 443e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (nhdr.n_type == NT_GNU_BUILD_ID && 444e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nhdr.n_namesz == sizeof("GNU")) { 445e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (read(fd, bf, namesz) != (ssize_t)namesz) 446e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 447e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 448e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t sz = min(descsz, size); 449e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (read(fd, build_id, sz) == (ssize_t)sz) { 450e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memset(build_id + sz, 0, size - sz); 451e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = 0; 452e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 453e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 454e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else if (read(fd, bf, descsz) != (ssize_t)descsz) 455e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 456e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else { 457e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int n = namesz + descsz; 458e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (read(fd, bf, n) != n) 459e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 460e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 461e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 462e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng close(fd); 463e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout: 464e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 465e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 466e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 467e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint filename__read_debuglink(const char *filename, char *debuglink, 468e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t size) 469e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 470e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int fd, err = -1; 471e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 472e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr ehdr; 473e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr; 474e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Data *data; 475e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *sec; 476e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Kind ek; 477e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 478e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fd = open(filename, O_RDONLY); 479e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (fd < 0) 480e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out; 481e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 482e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 483e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf == NULL) { 484e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 485e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 486e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 487e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 488e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ek = elf_kind(elf); 489e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ek != ELF_K_ELF) 490e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 491e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 492e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (gelf_getehdr(elf, &ehdr) == NULL) { 493e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("%s: cannot get elf header.\n", __func__); 494e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 495e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 496e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 497e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = elf_section_by_name(elf, &ehdr, &shdr, 498e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".gnu_debuglink", NULL); 499e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sec == NULL) 500e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 501e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 502e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng data = elf_getdata(sec, NULL); 503e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (data == NULL) 504e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 505e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 506e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* the start of this section is a zero-terminated string */ 507e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng strncpy(debuglink, data->d_buf, size); 508e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 509e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_end(elf); 510e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 511e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_close: 512e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng close(fd); 513e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout: 514e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 515e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 516e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 517e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int dso__swap_init(struct dso *dso, unsigned char eidata) 518e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 519e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng static unsigned int const endian = 1; 520e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 521e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->needs_swap = DSO_SWAP__NO; 522e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 523e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng switch (eidata) { 524e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case ELFDATA2LSB: 525e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* We are big endian, DSO is little endian. */ 526e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*(unsigned char const *)&endian != 1) 527e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->needs_swap = DSO_SWAP__YES; 528e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 529e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 530e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng case ELFDATA2MSB: 531e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* We are little endian, DSO is big endian. */ 532e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (*(unsigned char const *)&endian != 0) 533e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->needs_swap = DSO_SWAP__YES; 534e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 535e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 536e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng default: 537e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_err("unrecognized DSO data encoding %d\n", eidata); 538e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -EINVAL; 539e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 540e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 541e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 542e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 543e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 544e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool symsrc__possibly_runtime(struct symsrc *ss) 545e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 546e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ss->dynsym || ss->opdsec; 547e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 548e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 549e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengbool symsrc__has_symtab(struct symsrc *ss) 550e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 551e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return ss->symtab != NULL; 552e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 553e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 554e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid symsrc__destroy(struct symsrc *ss) 555e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 556e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(ss->name); 557e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_end(ss->elf); 558e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng close(ss->fd); 559e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 560e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 561e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, 562e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng enum dso_binary_type type) 563e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 564e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int err = -1; 565e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr ehdr; 566e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 567e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int fd; 568e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 569e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng fd = open(name, O_RDONLY); 570e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (fd < 0) 571e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 572e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 573e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 574e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf == NULL) { 575e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 576e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_close; 577e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 578e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 579e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (gelf_getehdr(elf, &ehdr) == NULL) { 580e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug("%s: cannot get elf header.\n", __func__); 581e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 582e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 583e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 584e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) 585e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 586e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 587e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Always reject images with a mismatched build-id: */ 588e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->has_build_id) { 589e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u8 build_id[BUILD_ID_SIZE]; 590e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 591e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) 592e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 593e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 594e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!dso__build_id_equal(dso, build_id)) 595e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 596e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 597e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 598e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", 599e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng NULL); 600e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ss->symshdr.sh_type != SHT_SYMTAB) 601e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->symtab = NULL; 602e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 603e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->dynsym_idx = 0; 604e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym", 605e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng &ss->dynsym_idx); 606e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ss->dynshdr.sh_type != SHT_DYNSYM) 607e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->dynsym = NULL; 608e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 609e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->opdidx = 0; 610e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd", 611e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng &ss->opdidx); 612e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ss->opdshdr.sh_type != SHT_PROGBITS) 613e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->opdsec = NULL; 614e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 615e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->kernel == DSO_TYPE_USER) { 616e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr; 617e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 618e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ehdr.e_type == ET_REL || 619e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_section_by_name(elf, &ehdr, &shdr, 620e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ".gnu.prelink_undo", 621e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng NULL) != NULL); 622e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else { 623e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->adjust_symbols = ehdr.e_type == ET_EXEC || 624e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ehdr.e_type == ET_REL; 625e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 626e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 627e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->name = strdup(name); 628e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!ss->name) 629e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 630e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 631e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->elf = elf; 632e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->fd = fd; 633e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->ehdr = ehdr; 634e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ss->type = type; 635e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 636e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 637e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 638e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_elf_end: 639e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_end(elf); 640e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_close: 641e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng close(fd); 642e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 643e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 644e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 645e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/** 646e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * ref_reloc_sym_not_found - has kernel relocation symbol been found. 647e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * @kmap: kernel maps and relocation reference symbol 648e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 649e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * This function returns %true if we are dealing with the kernel maps and the 650e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * relocation reference symbol has not yet been found. Otherwise %false is 651e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * returned. 652e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 653e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic bool ref_reloc_sym_not_found(struct kmap *kmap) 654e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 655e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 656e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng !kmap->ref_reloc_sym->unrelocated_addr; 657e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 658e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 659e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/** 660e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * ref_reloc - kernel relocation offset. 661e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * @kmap: kernel maps and relocation reference symbol 662e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 663e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * This function returns the offset of kernel addresses as determined by using 664e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * the relocation reference symbol i.e. if the kernel has not been relocated 665e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * then the return value is zero. 666e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 667e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic u64 ref_reloc(struct kmap *kmap) 668e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 669e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (kmap && kmap->ref_reloc_sym && 670e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng kmap->ref_reloc_sym->unrelocated_addr) 671e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return kmap->ref_reloc_sym->addr - 672e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng kmap->ref_reloc_sym->unrelocated_addr; 673e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 674e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 675e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 676e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint dso__load_sym(struct dso *dso, struct map *map, 677e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct symsrc *syms_ss, struct symsrc *runtime_ss, 678e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol_filter_t filter, int kmodule) 679e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 680e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; 681e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct map *curr_map = map; 682e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct dso *curr_dso = dso; 683e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Data *symstrs, *secstrs; 684e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng uint32_t nr_syms; 685e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int err = -1; 686e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng uint32_t idx; 687e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Ehdr ehdr; 688e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Shdr shdr; 689e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Data *syms, *opddata = NULL; 690e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Sym sym; 691e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf_Scn *sec, *sec_strndx; 692e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 693e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int nr = 0; 694e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng bool remap_kernel = false, adjust_kernel_syms = false; 695e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 696e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->symtab_type = syms_ss->type; 697e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->rel = syms_ss->ehdr.e_type == ET_REL; 698e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 699e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 700e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Modules may already have symbols from kallsyms, but those symbols 701e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * have the wrong values for the dso maps, so remove them. 702e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 703e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (kmodule && syms_ss->symtab) 704e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbols__delete(&dso->symbols[map->type]); 705e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 706e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!syms_ss->symtab) { 707e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng syms_ss->symtab = syms_ss->dynsym; 708e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng syms_ss->symshdr = syms_ss->dynshdr; 709e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 710e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 711e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = syms_ss->elf; 712e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ehdr = syms_ss->ehdr; 713e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = syms_ss->symtab; 714e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng shdr = syms_ss->symshdr; 715e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 716e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (runtime_ss->opdsec) 717e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng opddata = elf_rawdata(runtime_ss->opdsec, NULL); 718e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 719e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng syms = elf_getdata(sec, NULL); 720e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (syms == NULL) 721e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 722e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 723e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = elf_getscn(elf, shdr.sh_link); 724e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sec == NULL) 725e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 726e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 727e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symstrs = elf_getdata(sec, NULL); 728e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (symstrs == NULL) 729e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 730e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 731e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 732e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sec_strndx == NULL) 733e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 734e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 735e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng secstrs = elf_getdata(sec_strndx, NULL); 736e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (secstrs == NULL) 737e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 738e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 739e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr_syms = shdr.sh_size / shdr.sh_entsize; 740e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 741e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng memset(&sym, 0, sizeof(sym)); 742e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 743e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 744e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The kernel relocation symbol is needed in advance in order to adjust 745e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * kernel maps correctly. 746e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 747e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ref_reloc_sym_not_found(kmap)) { 748e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 749e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *elf_name = elf_sym__name(&sym, symstrs); 750e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 751e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (strcmp(elf_name, kmap->ref_reloc_sym->name)) 752e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 753e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 754e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng break; 755e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 756e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 757e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 758e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap); 759e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 760e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Initial kernel and module mappings do not map to the dso. For 761e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * function mappings, flag the fixups. 762e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 763e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (map->type == MAP__FUNCTION && (dso->kernel || kmodule)) { 764e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng remap_kernel = true; 765e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng adjust_kernel_syms = dso->adjust_symbols; 766e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 767e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 768e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng struct symbol *f; 769e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *elf_name = elf_sym__name(&sym, symstrs); 770e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char *demangled = NULL; 771e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int is_label = elf_sym__is_label(&sym); 772e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng const char *section_name; 773e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng bool used_opd = false; 774e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 775e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!is_label && !elf_sym__is_a(&sym, map->type)) 776e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 777e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 778e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Reject ARM ELF "mapping symbols": these aren't unique and 779e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * don't identify functions, so will confuse the profile 780e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * output: */ 781e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (ehdr.e_machine == EM_ARM) { 782e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!strcmp(elf_name, "$a") || 783e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng !strcmp(elf_name, "$d") || 784e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng !strcmp(elf_name, "$t")) 785e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 786e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 787e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 788e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (runtime_ss->opdsec && sym.st_shndx == runtime_ss->opdidx) { 789e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u32 offset = sym.st_value - syms_ss->opdshdr.sh_addr; 790e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 *opd = opddata->d_buf + offset; 791e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym.st_value = DSO__SWAP(dso, u64, *opd); 792e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym.st_shndx = elf_addr_to_index(runtime_ss->elf, 793e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym.st_value); 794e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng used_opd = true; 795e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 796e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 797e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * When loading symbols in a data mapping, ABS symbols (which 798e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * has a value of SHN_ABS in its st_shndx) failed at 799e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * elf_getscn(). And it marks the loading as a failure so 800e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * already loaded symbols cannot be fixed up. 801e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 802e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * I'm not sure what should be done. Just ignore them for now. 803e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * - Namhyung Kim 804e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 805e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (sym.st_shndx == SHN_ABS) 806e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 807e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 808e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sec = elf_getscn(runtime_ss->elf, sym.st_shndx); 809e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!sec) 810e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 811e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 812e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng gelf_getshdr(sec, &shdr); 813e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 814e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 815e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 816e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 817e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng section_name = elf_sec__name(&shdr, secstrs); 818e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 819e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* On ARM, symbols for thumb functions have 1 added to 820e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * the symbol address as a flag - remove it */ 821e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((ehdr.e_machine == EM_ARM) && 822e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (map->type == MAP__FUNCTION) && 823e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (sym.st_value & 1)) 824e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng --sym.st_value; 825e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 826e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (dso->kernel || kmodule) { 827e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng char dso_name[PATH_MAX]; 828e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 829e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Adjust symbol to map to file offset */ 830e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (adjust_kernel_syms) 831e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym.st_value -= shdr.sh_addr - shdr.sh_offset; 832e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 833e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (strcmp(section_name, 834e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (curr_dso->short_name + 835e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso->short_name_len)) == 0) 836e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto new_symbol; 837e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 838e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (strcmp(section_name, ".text") == 0) { 839e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 840e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The initial kernel mapping is based on 841e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * kallsyms and identity maps. Overwrite it to 842e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * map to the kernel dso. 843e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 844e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (remap_kernel && dso->kernel) { 845e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng remap_kernel = false; 846e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->start = shdr.sh_addr + 847e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ref_reloc(kmap); 848e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->end = map->start + shdr.sh_size; 849e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->pgoff = shdr.sh_offset; 850e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->map_ip = map__map_ip; 851e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->unmap_ip = map__unmap_ip; 852e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* Ensure maps are correctly ordered */ 853e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map_groups__remove(kmap->kmaps, map); 854e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map_groups__insert(kmap->kmaps, map); 855e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 856e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 857e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 858e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * The initial module mapping is based on 859e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * /proc/modules mapped to offset zero. 860e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Overwrite it to map to the module dso. 861e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 862e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (remap_kernel && kmodule) { 863e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng remap_kernel = false; 864e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->pgoff = shdr.sh_offset; 865e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 866e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 867e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map = map; 868e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso = dso; 869e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto new_symbol; 870e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 871e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 872e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!kmap) 873e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto new_symbol; 874e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 875e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng snprintf(dso_name, sizeof(dso_name), 876e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "%s%s", dso->short_name, section_name); 877e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 878e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 879e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (curr_map == NULL) { 880e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 start = sym.st_value; 881e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 882e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (kmodule) 883e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng start += map->start + shdr.sh_offset; 884e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 885e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso = dso__new(dso_name); 886e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (curr_dso == NULL) 887e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 888e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso->kernel = dso->kernel; 889e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso->long_name = dso->long_name; 890e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso->long_name_len = dso->long_name_len; 891e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map = map__new2(start, curr_dso, 892e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map->type); 893e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (curr_map == NULL) { 894e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso__delete(curr_dso); 895e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 896e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 897e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (adjust_kernel_syms) { 898e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map->start = shdr.sh_addr + 899e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng ref_reloc(kmap); 900e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map->end = curr_map->start + 901e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng shdr.sh_size; 902e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map->pgoff = shdr.sh_offset; 903e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else { 904e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map->map_ip = identity__map_ip; 905e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_map->unmap_ip = identity__map_ip; 906e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 907e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso->symtab_type = dso->symtab_type; 908e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng map_groups__insert(kmap->kmaps, curr_map); 909e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dsos__add(&dso->node, curr_dso); 910e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng dso__set_loaded(curr_dso, map->type); 911e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else 912e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng curr_dso = curr_map->dso; 913e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 914e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto new_symbol; 915e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 916e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 917e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if ((used_opd && runtime_ss->adjust_symbols) 918e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng || (!used_opd && syms_ss->adjust_symbols)) { 919e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " 920e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, 921e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (u64)sym.st_value, (u64)shdr.sh_addr, 922e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng (u64)shdr.sh_offset); 923e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sym.st_value -= shdr.sh_addr - shdr.sh_offset; 924e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 925e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 926e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * We need to figure out if the object was created from C++ sources 927e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * DWARF DW_compile_unit has this, but we don't always have access 928e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * to it... 929e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 930e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (symbol_conf.demangle) { 931e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng demangled = bfd_demangle(NULL, elf_name, 932e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng DMGL_PARAMS | DMGL_ANSI); 933e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (demangled != NULL) 934e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_name = demangled; 935e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 936e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengnew_symbol: 937e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng f = symbol__new(sym.st_value, sym.st_size, 938e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GELF_ST_BIND(sym.st_info), elf_name); 939e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng free(demangled); 940e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!f) 941e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng goto out_elf_end; 942e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 943e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (filter && filter(curr_map, f)) 944e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbol__delete(f); 945e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng else { 946e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbols__insert(&curr_dso->symbols[curr_map->type], f); 947e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng nr++; 948e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 949e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 950e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 951e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 952e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * For misannotated, zeroed, ASM function sizes. 953e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 954e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (nr > 0) { 955e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbols__fixup_duplicate(&dso->symbols[map->type]); 956e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng symbols__fixup_end(&dso->symbols[map->type]); 957e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (kmap) { 958e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng /* 959e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * We need to fixup this here too because we create new 960e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * maps here, for things like vsyscall sections. 961e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */ 962e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng __map_groups__fixup_end(kmap->kmaps, map->type); 963e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 964e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 965e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = nr; 966e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengout_elf_end: 967e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 968e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 969e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 970e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data) 971e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 972e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng GElf_Phdr phdr; 973e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng size_t i, phdrnum; 974e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int err; 975e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng u64 sz; 976e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 977e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf_getphdrnum(elf, &phdrnum)) 978e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 979e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 980e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng for (i = 0; i < phdrnum; i++) { 981e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (gelf_getphdr(elf, i, &phdr) == NULL) 982e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 983e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (phdr.p_type != PT_LOAD) 984e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 985e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (exe) { 986e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!(phdr.p_flags & PF_X)) 987e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 988e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } else { 989e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!(phdr.p_flags & PF_R)) 990e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 991e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 992e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng sz = min(phdr.p_memsz, phdr.p_filesz); 993e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (!sz) 994e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng continue; 995e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data); 996e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (err) 997e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 998e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng } 999e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return 0; 1000e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1001e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1002e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, 1003e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng bool *is_64_bit) 1004e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1005e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng int err; 1006e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng Elf *elf; 1007e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1008e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1009e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (elf == NULL) 1010e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return -1; 1011e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1012e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng if (is_64_bit) 1013e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng *is_64_bit = (gelf_getclass(elf) == ELFCLASS64); 1014e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1015e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng err = elf_read_maps(elf, exe, mapfn, data); 1016e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1017e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_end(elf); 1018e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng return err; 1019e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1020e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng 1021e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid symbol__elf_init(void) 1022e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{ 1023e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng elf_version(EV_CURRENT); 1024e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng} 1025