cregit-Linux how code gets into the kernel

Release 4.10 tools/perf/util/symbol-elf.c

Directory: tools/perf/util
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>

#include "symbol.h"
#include "demangle-java.h"
#include "demangle-rust.h"
#include "machine.h"
#include "vdso.h"
#include <symbol/kallsyms.h>
#include "debug.h"

#ifndef EM_AARCH64

#define EM_AARCH64	183  
/* ARM 64 bit */
#endif


typedef Elf64_Nhdr GElf_Nhdr;

#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
extern char *cplus_demangle(const char *, int);


static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) { return cplus_demangle(c, i); }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo29100.00%1100.00%
Total29100.00%1100.00%

#else #ifdef NO_DEMANGLE
static inline char *bfd_demangle(void __maybe_unused *v, const char __maybe_unused *c, int __maybe_unused i) { return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo26100.00%1100.00%
Total26100.00%1100.00%

#else #define PACKAGE 'perf' #include <bfd.h> #endif #endif #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
static int elf_getphdrnum(Elf *elf, size_t *dst) { GElf_Ehdr gehdr; GElf_Ehdr *ehdr; ehdr = gelf_getehdr(elf, &gehdr); if (!ehdr) return -1; *dst = ehdr->e_phnum; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
adrian hunteradrian hunter4998.00%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo12.00%150.00%
Total50100.00%2100.00%

#endif #ifndef HAVE_ELF_GETSHDRSTRNDX_SUPPORT
static int elf_getshdrstrndx(Elf *elf __maybe_unused, size_t *dst __maybe_unused) { pr_err("%s: update your libelf to > 0.140, this one lacks elf_getshdrstrndx().\n", __func__); return -1; }

Contributors

PersonTokensPropCommitsCommitProp
arnaldo carvalho de meloarnaldo carvalho de melo27100.00%1100.00%
Total27100.00%1100.00%

#endif #ifndef NT_GNU_BUILD_ID #define NT_GNU_BUILD_ID 3 #endif /** * elf_symtab__for_each_symbol - iterate thru all the symbols * * @syms: struct elf_symtab instance to iterate * @idx: uint32_t idx * @sym: GElf_Sym iterator */ #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ for (idx = 0, gelf_getsym(syms, idx, &sym);\ idx < nr_syms; \ idx++, gelf_getsym(syms, idx, &sym))
static inline uint8_t elf_sym__type(const GElf_Sym *sym) { return GELF_ST_TYPE(sym->st_info); }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim20100.00%1100.00%
Total20100.00%1100.00%

#ifndef STT_GNU_IFUNC #define STT_GNU_IFUNC 10 #endif
static inline int elf_sym__is_function(const GElf_Sym *sym) { return (elf_sym__type(sym) == STT_FUNC || elf_sym__type(sym) == STT_GNU_IFUNC) && sym->st_name != 0 && sym->st_shndx != SHN_UNDEF; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim3278.05%150.00%
adrian hunteradrian hunter921.95%150.00%
Total41100.00%2100.00%


static inline bool elf_sym__is_object(const GElf_Sym *sym) { return elf_sym__type(sym) == STT_OBJECT && sym->st_name != 0 && sym->st_shndx != SHN_UNDEF; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim32100.00%1100.00%
Total32100.00%1100.00%


static inline int elf_sym__is_label(const GElf_Sym *sym) { return elf_sym__type(sym) == STT_NOTYPE && sym->st_name != 0 && sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim38100.00%1100.00%
Total38100.00%1100.00%


static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) { switch (type) { case MAP__FUNCTION: return elf_sym__is_function(sym); case MAP__VARIABLE: return elf_sym__is_object(sym); default: return false; } }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim42100.00%1100.00%
Total42100.00%1100.00%


static inline const char *elf_sym__name(const GElf_Sym *sym, const Elf_Data *symstrs) { return symstrs->d_buf + sym->st_name; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim28100.00%1100.00%
Total28100.00%1100.00%


static inline const char *elf_sec__name(const GElf_Shdr *shdr, const Elf_Data *secstrs) { return secstrs->d_buf + shdr->sh_name; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim28100.00%1100.00%
Total28100.00%1100.00%


static inline int elf_sec__is_text(const GElf_Shdr *shdr, const Elf_Data *secstrs) { return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim32100.00%1100.00%
Total32100.00%1100.00%


static inline bool elf_sec__is_data(const GElf_Shdr *shdr, const Elf_Data *secstrs) { return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim32100.00%1100.00%
Total32100.00%1100.00%


static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, enum map_type type) { switch (type) { case MAP__FUNCTION: return elf_sec__is_text(shdr, secstrs); case MAP__VARIABLE: return elf_sec__is_data(shdr, secstrs); default: return false; } }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim50100.00%1100.00%
Total50100.00%1100.00%


static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) { Elf_Scn *sec = NULL; GElf_Shdr shdr; size_t cnt = 1; while ((sec = elf_nextscn(elf, sec)) != NULL) { gelf_getshdr(sec, &shdr); if ((addr >= shdr.sh_addr) && (addr < (shdr.sh_addr + shdr.sh_size))) return cnt; ++cnt; } return -1; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim86100.00%1100.00%
Total86100.00%1100.00%


Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, GElf_Shdr *shp, const char *name, size_t *idx) { Elf_Scn *sec = NULL; size_t cnt = 1; /* Elf is corrupted/truncated, avoid calling elf_strptr. */ if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) return NULL; while ((sec = elf_nextscn(elf, sec)) != NULL) { char *str; gelf_getshdr(sec, shp); str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); if (str && !strcmp(name, str)) { if (idx) *idx = cnt; return sec; } ++cnt; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim10779.85%133.33%
cody p schafercody p schafer2115.67%133.33%
jiri olsajiri olsa64.48%133.33%
Total134100.00%3100.00%


static bool want_demangle(bool is_kernel_sym) { return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; }

Contributors

PersonTokensPropCommitsCommitProp
milian wolffmilian wolff20100.00%1100.00%
Total20100.00%1100.00%


static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name) { int demangle_flags = verbose ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS; char *demangled = NULL; /* * We need to figure out if the object was created from C++ sources * DWARF DW_compile_unit has this, but we don't always have access * to it... */ if (!want_demangle(dso->kernel || kmodule)) return demangled; demangled = bfd_demangle(NULL, elf_name, demangle_flags); if (demangled == NULL) demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); else if (rust_is_mangled(demangled)) /* * Input to Rust demangling is the BFD-demangled * name which it Rust-demangles in place. */ rust_demangle_sym(demangled); return demangled; }

Contributors

PersonTokensPropCommitsCommitProp
milian wolffmilian wolff98100.00%1100.00%
Total98100.00%1100.00%

#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ idx < nr_entries; \ ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ idx < nr_entries; \ ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) /* * We need to check if we have a .dynsym, so that we can handle the * .plt, synthesizing its symbols, that aren't on the symtabs (be it * .dynsym or .symtab). * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map) { uint32_t nr_rel_entries, idx; GElf_Sym sym; u64 plt_offset; GElf_Shdr shdr_plt; struct symbol *f; GElf_Shdr shdr_rel_plt, shdr_dynsym; Elf_Data *reldata, *syms, *symstrs; Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; size_t dynsym_idx; GElf_Ehdr ehdr; char sympltname[1024]; Elf *elf; int nr = 0, symidx, err = 0; if (!ss->dynsym) return 0; elf = ss->elf; ehdr = ss->ehdr; scn_dynsym = ss->dynsym; shdr_dynsym = ss->dynshdr; dynsym_idx = ss->dynsym_idx; if (scn_dynsym == NULL) goto out_elf_end; scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, ".rela.plt", NULL); if (scn_plt_rel == NULL) { scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, ".rel.plt", NULL); if (scn_plt_rel == NULL) goto out_elf_end; } err = -1; if (shdr_rel_plt.sh_link != dynsym_idx) goto out_elf_end; if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) goto out_elf_end; /* * Fetch the relocation section to find the idxes to the GOT * and the symbols in the .dynsym they refer to. */ reldata = elf_getdata(scn_plt_rel, NULL); if (reldata == NULL) goto out_elf_end; syms = elf_getdata(scn_dynsym, NULL); if (syms == NULL) goto out_elf_end; scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); if (scn_symstrs == NULL) goto out_elf_end; symstrs = elf_getdata(scn_symstrs, NULL); if (symstrs == NULL) goto out_elf_end; if (symstrs->d_size == 0) goto out_elf_end; nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; plt_offset = shdr_plt.sh_offset; if (shdr_rel_plt.sh_type == SHT_RELA) { GElf_Rela pos_mem, *pos; elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_rel_entries) { const char *elf_name = NULL; char *demangled = NULL; symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); elf_name = elf_sym__name(&sym, symstrs); demangled = demangle_sym(dso, 0, elf_name); if (demangled != NULL) elf_name = demangled; snprintf(sympltname, sizeof(sympltname), "%s@plt", elf_name); free(demangled); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); if (!f) goto out_elf_end; symbols__insert(&dso->symbols[map->type], f); ++nr; } } else if (shdr_rel_plt.sh_type == SHT_REL) { GElf_Rel pos_mem, *pos; elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_rel_entries) { const char *elf_name = NULL; char *demangled = NULL; symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); elf_name = elf_sym__name(&sym, symstrs); demangled = demangle_sym(dso, 0, elf_name); if (demangled != NULL) elf_name = demangled; snprintf(sympltname, sizeof(sympltname), "%s@plt", elf_name); free(demangled); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); if (!f) goto out_elf_end; symbols__insert(&dso->symbols[map->type], f); ++nr; } } err = 0; out_elf_end: if (err == 0) return nr; pr_debug("%s: problems reading %s PLT info.\n", __func__, dso->long_name); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim53678.94%120.00%
milian wolffmilian wolff9814.43%120.00%
cody p schafercody p schafer355.15%240.00%
david aherndavid ahern101.47%120.00%
Total679100.00%5100.00%

/* * Align offset to 4 bytes as needed for note name and descriptor data. */ #define NOTE_ALIGN(n) (((n) + 3) & -4U)
static int elf_read_build_id(Elf *elf, void *bf, size_t size) { int err = -1; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *data; Elf_Scn *sec; Elf_Kind ek; void *ptr; if (size < BUILD_ID_SIZE) goto out; ek = elf_kind(elf); if (ek != ELF_K_ELF) goto out; if (gelf_getehdr(elf, &ehdr) == NULL) { pr_err("%s: cannot get elf header.\n", __func__); goto out; } /* * Check following sections for notes: * '.note.gnu.build-id' * '.notes' * '.note' (VDSO specific) */ do { sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); if (sec) break; sec = elf_section_by_name(elf, &ehdr, &shdr, ".notes", NULL); if (sec) break; sec = elf_section_by_name(elf, &ehdr, &shdr, ".note", NULL); if (sec) break; return err; } while (0); data = elf_getdata(sec, NULL); if (data == NULL) goto out; ptr = data->d_buf; while (ptr < (data->d_buf + data->d_size)) { GElf_Nhdr *nhdr = ptr; size_t namesz = NOTE_ALIGN(nhdr->n_namesz), descsz = NOTE_ALIGN(nhdr->n_descsz); const char *name; ptr += sizeof(*nhdr); name = ptr; ptr += namesz; if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == sizeof("GNU")) { if (memcmp(name, "GNU", sizeof("GNU")) == 0) { size_t sz = min(size, descsz); memcpy(bf, ptr, sz); memset(bf + sz, 0, size - sz); err = descsz; break; } } ptr += descsz; } out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim340100.00%1100.00%
Total340100.00%1100.00%


int filename__read_build_id(const char *filename, void *bf, size_t size) { int fd, err = -1; Elf *elf; if (size < BUILD_ID_SIZE) goto out; fd = open(filename, O_RDONLY); if (fd < 0) goto out; elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); if (elf == NULL) { pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); goto out_close; } err = elf_read_build_id(elf, bf, size); elf_end(elf); out_close: close(fd); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim115100.00%1100.00%
Total115100.00%1100.00%


int sysfs__read_build_id(const char *filename, void *build_id, size_t size) { int fd, err = -1; if (size < BUILD_ID_SIZE) goto out; fd = open(filename, O_RDONLY); if (fd < 0) goto out; while (1) { char bf[BUFSIZ]; GElf_Nhdr nhdr; size_t namesz, descsz; if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) break; namesz = NOTE_ALIGN(nhdr.n_namesz); descsz = NOTE_ALIGN(nhdr.n_descsz); if (nhdr.n_type == NT_GNU_BUILD_ID && nhdr.n_namesz == sizeof("GNU")) { if (read(fd, bf, namesz) != (ssize_t)namesz) break; if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { size_t sz = min(descsz, size); if (read(fd, build_id, sz) == (ssize_t)sz) { memset(build_id + sz, 0, size - sz); err = 0; break; } } else if (read(fd, bf, descsz) != (ssize_t)descsz) break; } else { int n = namesz + descsz; if (n > (int)sizeof(bf)) { n = sizeof(bf); pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n", __func__, filename, nhdr.n_namesz, nhdr.n_descsz); } if (read(fd, bf, n) != n) break; } } close(fd); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim26387.38%150.00%
arnaldo carvalho de meloarnaldo carvalho de melo3812.62%150.00%
Total301100.00%2100.00%


int filename__read_debuglink(const char *filename, char *debuglink, size_t size) { int fd, err = -1; Elf *elf; GElf_Ehdr ehdr; GElf_Shdr shdr; Elf_Data *data; Elf_Scn *sec; Elf_Kind ek; fd = open(filename, O_RDONLY); if (fd < 0) goto out; elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); if (elf == NULL) { pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); goto out_close; } ek = elf_kind(elf); if (ek != ELF_K_ELF) goto out_elf_end; if (gelf_getehdr(elf, &ehdr) == NULL) { pr_err("%s: cannot get elf header.\n", __func__); goto out_elf_end; } sec = elf_section_by_name(elf, &ehdr, &shdr, ".gnu_debuglink", NULL); if (sec == NULL) goto out_elf_end; data = elf_getdata(sec, NULL); if (data == NULL) goto out_elf_end; /* the start of this section is a zero-terminated string */ strncpy(debuglink, data->d_buf, size); err = 0; out_elf_end: elf_end(elf); out_close: close(fd); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim20495.33%133.33%
chenggang qinchenggang qin62.80%133.33%
stephane eranianstephane eranian41.87%133.33%
Total214100.00%3100.00%


static int dso__swap_init(struct dso *dso, unsigned char eidata) { static unsigned int const endian = 1; dso->needs_swap = DSO_SWAP__NO; switch (eidata) { case ELFDATA2LSB: /* We are big endian, DSO is little endian. */ if (*(unsigned char const *)&endian != 1) dso->needs_swap = DSO_SWAP__YES; break; case ELFDATA2MSB: /* We are little endian, DSO is big endian. */ if (*(unsigned char const *)&endian != 0) dso->needs_swap = DSO_SWAP__YES; break; default: pr_err("unrecognized DSO data encoding %d\n", eidata); return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim100100.00%1100.00%
Total100100.00%1100.00%


static int decompress_kmodule(struct dso *dso, const char *name, enum dso_binary_type type) { int fd = -1; char tmpbuf[] = "/tmp/perf-kmod-XXXXXX"; struct kmod_path m; if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP && type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP && type != DSO_BINARY_TYPE__BUILD_ID_CACHE) return -1; if (type == DSO_BINARY_TYPE__BUILD_ID_CACHE) name = dso->long_name; if (kmod_path__parse_ext(&m, name) || !m.comp) return -1; fd = mkstemp(tmpbuf); if (fd < 0) { dso->load_errno = errno; goto out; } if (!decompress_to_file(m.ext, name, fd)) { dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE; close(fd); fd = -1; } unlink(tmpbuf); out: free(m.ext); return fd; }

Contributors

PersonTokensPropCommitsCommitProp
namhyung kimnamhyung kim10968.99%250.00%
jiri olsajiri olsa3522.15%125.00%
arnaldo carvalho de meloarnaldo carvalho de melo148.86%125.00%
Total158100.00%4100.00%


bool symsrc__possibly_runtime(struct symsrc *ss) { return ss->dynsym || ss->opdsec; }

Contributors

PersonTokensPropCommitsCommitProp
cody p schafercody p schafer19100.00%1100.00%
Total19100.00%1100.00%


bool symsrc__has_symtab(struct symsrc *ss) { return ss->symtab != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
cody p schafercody p schafer17100.00%1100.00%
Total17100.00%1100.00%


void symsrc__destroy(struct symsrc *ss