18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <fcntl.h> 38c2ecf20Sopenharmony_ci#include <stdio.h> 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <stdlib.h> 68c2ecf20Sopenharmony_ci#include <string.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <inttypes.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "dso.h" 118c2ecf20Sopenharmony_ci#include "map.h" 128c2ecf20Sopenharmony_ci#include "maps.h" 138c2ecf20Sopenharmony_ci#include "symbol.h" 148c2ecf20Sopenharmony_ci#include "symsrc.h" 158c2ecf20Sopenharmony_ci#include "demangle-java.h" 168c2ecf20Sopenharmony_ci#include "demangle-rust.h" 178c2ecf20Sopenharmony_ci#include "machine.h" 188c2ecf20Sopenharmony_ci#include "vdso.h" 198c2ecf20Sopenharmony_ci#include "debug.h" 208c2ecf20Sopenharmony_ci#include "util/copyfile.h" 218c2ecf20Sopenharmony_ci#include <linux/ctype.h> 228c2ecf20Sopenharmony_ci#include <linux/kernel.h> 238c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 248c2ecf20Sopenharmony_ci#include <symbol/kallsyms.h> 258c2ecf20Sopenharmony_ci#include <internal/lib.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#ifndef EM_AARCH64 288c2ecf20Sopenharmony_ci#define EM_AARCH64 183 /* ARM 64 bit */ 298c2ecf20Sopenharmony_ci#endif 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifndef ELF32_ST_VISIBILITY 328c2ecf20Sopenharmony_ci#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* For ELF64 the definitions are the same. */ 368c2ecf20Sopenharmony_ci#ifndef ELF64_ST_VISIBILITY 378c2ecf20Sopenharmony_ci#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) 388c2ecf20Sopenharmony_ci#endif 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* How to extract information held in the st_other field. */ 418c2ecf20Sopenharmony_ci#ifndef GELF_ST_VISIBILITY 428c2ecf20Sopenharmony_ci#define GELF_ST_VISIBILITY(val) ELF64_ST_VISIBILITY (val) 438c2ecf20Sopenharmony_ci#endif 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_citypedef Elf64_Nhdr GElf_Nhdr; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#ifndef DMGL_PARAMS 488c2ecf20Sopenharmony_ci#define DMGL_NO_OPTS 0 /* For readability... */ 498c2ecf20Sopenharmony_ci#define DMGL_PARAMS (1 << 0) /* Include function args */ 508c2ecf20Sopenharmony_ci#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 518c2ecf20Sopenharmony_ci#endif 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT 548c2ecf20Sopenharmony_ci#define PACKAGE 'perf' 558c2ecf20Sopenharmony_ci#include <bfd.h> 568c2ecf20Sopenharmony_ci#else 578c2ecf20Sopenharmony_ci#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT 588c2ecf20Sopenharmony_ciextern char *cplus_demangle(const char *, int); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci return cplus_demangle(c, i); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci#else 658c2ecf20Sopenharmony_ci#ifdef NO_DEMANGLE 668c2ecf20Sopenharmony_cistatic inline char *bfd_demangle(void __maybe_unused *v, 678c2ecf20Sopenharmony_ci const char __maybe_unused *c, 688c2ecf20Sopenharmony_ci int __maybe_unused i) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return NULL; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci#endif 748c2ecf20Sopenharmony_ci#endif 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT 778c2ecf20Sopenharmony_cistatic int elf_getphdrnum(Elf *elf, size_t *dst) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci GElf_Ehdr gehdr; 808c2ecf20Sopenharmony_ci GElf_Ehdr *ehdr; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ehdr = gelf_getehdr(elf, &gehdr); 838c2ecf20Sopenharmony_ci if (!ehdr) 848c2ecf20Sopenharmony_ci return -1; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci *dst = ehdr->e_phnum; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci#endif 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#ifndef HAVE_ELF_GETSHDRSTRNDX_SUPPORT 938c2ecf20Sopenharmony_cistatic int elf_getshdrstrndx(Elf *elf __maybe_unused, size_t *dst __maybe_unused) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci pr_err("%s: update your libelf to > 0.140, this one lacks elf_getshdrstrndx().\n", __func__); 968c2ecf20Sopenharmony_ci return -1; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#ifndef NT_GNU_BUILD_ID 1018c2ecf20Sopenharmony_ci#define NT_GNU_BUILD_ID 3 1028c2ecf20Sopenharmony_ci#endif 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/** 1058c2ecf20Sopenharmony_ci * elf_symtab__for_each_symbol - iterate thru all the symbols 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * @syms: struct elf_symtab instance to iterate 1088c2ecf20Sopenharmony_ci * @idx: uint32_t idx 1098c2ecf20Sopenharmony_ci * @sym: GElf_Sym iterator 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 1128c2ecf20Sopenharmony_ci for (idx = 0, gelf_getsym(syms, idx, &sym);\ 1138c2ecf20Sopenharmony_ci idx < nr_syms; \ 1148c2ecf20Sopenharmony_ci idx++, gelf_getsym(syms, idx, &sym)) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline uint8_t elf_sym__type(const GElf_Sym *sym) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return GELF_ST_TYPE(sym->st_info); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic inline uint8_t elf_sym__visibility(const GElf_Sym *sym) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return GELF_ST_VISIBILITY(sym->st_other); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#ifndef STT_GNU_IFUNC 1278c2ecf20Sopenharmony_ci#define STT_GNU_IFUNC 10 1288c2ecf20Sopenharmony_ci#endif 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline int elf_sym__is_function(const GElf_Sym *sym) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci return (elf_sym__type(sym) == STT_FUNC || 1338c2ecf20Sopenharmony_ci elf_sym__type(sym) == STT_GNU_IFUNC) && 1348c2ecf20Sopenharmony_ci sym->st_name != 0 && 1358c2ecf20Sopenharmony_ci sym->st_shndx != SHN_UNDEF; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic inline bool elf_sym__is_object(const GElf_Sym *sym) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return elf_sym__type(sym) == STT_OBJECT && 1418c2ecf20Sopenharmony_ci sym->st_name != 0 && 1428c2ecf20Sopenharmony_ci sym->st_shndx != SHN_UNDEF; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic inline int elf_sym__is_label(const GElf_Sym *sym) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci return elf_sym__type(sym) == STT_NOTYPE && 1488c2ecf20Sopenharmony_ci sym->st_name != 0 && 1498c2ecf20Sopenharmony_ci sym->st_shndx != SHN_UNDEF && 1508c2ecf20Sopenharmony_ci sym->st_shndx != SHN_ABS && 1518c2ecf20Sopenharmony_ci elf_sym__visibility(sym) != STV_HIDDEN && 1528c2ecf20Sopenharmony_ci elf_sym__visibility(sym) != STV_INTERNAL; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic bool elf_sym__filter(GElf_Sym *sym) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return elf_sym__is_function(sym) || elf_sym__is_object(sym); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline const char *elf_sym__name(const GElf_Sym *sym, 1618c2ecf20Sopenharmony_ci const Elf_Data *symstrs) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci return symstrs->d_buf + sym->st_name; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline const char *elf_sec__name(const GElf_Shdr *shdr, 1678c2ecf20Sopenharmony_ci const Elf_Data *secstrs) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return secstrs->d_buf + shdr->sh_name; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic inline int elf_sec__is_text(const GElf_Shdr *shdr, 1738c2ecf20Sopenharmony_ci const Elf_Data *secstrs) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic inline bool elf_sec__is_data(const GElf_Shdr *shdr, 1798c2ecf20Sopenharmony_ci const Elf_Data *secstrs) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic bool elf_sec__filter(GElf_Shdr *shdr, Elf_Data *secstrs) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return elf_sec__is_text(shdr, secstrs) || 1878c2ecf20Sopenharmony_ci elf_sec__is_data(shdr, secstrs); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci Elf_Scn *sec = NULL; 1938c2ecf20Sopenharmony_ci GElf_Shdr shdr; 1948c2ecf20Sopenharmony_ci size_t cnt = 1; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci while ((sec = elf_nextscn(elf, sec)) != NULL) { 1978c2ecf20Sopenharmony_ci gelf_getshdr(sec, &shdr); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if ((addr >= shdr.sh_addr) && 2008c2ecf20Sopenharmony_ci (addr < (shdr.sh_addr + shdr.sh_size))) 2018c2ecf20Sopenharmony_ci return cnt; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ++cnt; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return -1; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ciElf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 2108c2ecf20Sopenharmony_ci GElf_Shdr *shp, const char *name, size_t *idx) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci Elf_Scn *sec = NULL; 2138c2ecf20Sopenharmony_ci size_t cnt = 1; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Elf is corrupted/truncated, avoid calling elf_strptr. */ 2168c2ecf20Sopenharmony_ci if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) 2178c2ecf20Sopenharmony_ci return NULL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci while ((sec = elf_nextscn(elf, sec)) != NULL) { 2208c2ecf20Sopenharmony_ci char *str; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci gelf_getshdr(sec, shp); 2238c2ecf20Sopenharmony_ci str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 2248c2ecf20Sopenharmony_ci if (str && !strcmp(name, str)) { 2258c2ecf20Sopenharmony_ci if (idx) 2268c2ecf20Sopenharmony_ci *idx = cnt; 2278c2ecf20Sopenharmony_ci return sec; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci ++cnt; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return NULL; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int elf_read_program_header(Elf *elf, u64 vaddr, GElf_Phdr *phdr) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci size_t i, phdrnum; 2388c2ecf20Sopenharmony_ci u64 sz; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (elf_getphdrnum(elf, &phdrnum)) 2418c2ecf20Sopenharmony_ci return -1; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci for (i = 0; i < phdrnum; i++) { 2448c2ecf20Sopenharmony_ci if (gelf_getphdr(elf, i, phdr) == NULL) 2458c2ecf20Sopenharmony_ci return -1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (phdr->p_type != PT_LOAD) 2488c2ecf20Sopenharmony_ci continue; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci sz = max(phdr->p_memsz, phdr->p_filesz); 2518c2ecf20Sopenharmony_ci if (!sz) 2528c2ecf20Sopenharmony_ci continue; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (vaddr >= phdr->p_vaddr && (vaddr < phdr->p_vaddr + sz)) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Not found any valid program header */ 2598c2ecf20Sopenharmony_ci return -1; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic bool want_demangle(bool is_kernel_sym) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci int demangle_flags = verbose > 0 ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS; 2708c2ecf20Sopenharmony_ci char *demangled = NULL; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* 2738c2ecf20Sopenharmony_ci * We need to figure out if the object was created from C++ sources 2748c2ecf20Sopenharmony_ci * DWARF DW_compile_unit has this, but we don't always have access 2758c2ecf20Sopenharmony_ci * to it... 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (!want_demangle(dso->kernel || kmodule)) 2788c2ecf20Sopenharmony_ci return demangled; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci demangled = bfd_demangle(NULL, elf_name, demangle_flags); 2818c2ecf20Sopenharmony_ci if (demangled == NULL) 2828c2ecf20Sopenharmony_ci demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET); 2838c2ecf20Sopenharmony_ci else if (rust_is_mangled(demangled)) 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * Input to Rust demangling is the BFD-demangled 2868c2ecf20Sopenharmony_ci * name which it Rust-demangles in place. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci rust_demangle_sym(demangled); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return demangled; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 2948c2ecf20Sopenharmony_ci for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 2958c2ecf20Sopenharmony_ci idx < nr_entries; \ 2968c2ecf20Sopenharmony_ci ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 2998c2ecf20Sopenharmony_ci for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 3008c2ecf20Sopenharmony_ci idx < nr_entries; \ 3018c2ecf20Sopenharmony_ci ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci * We need to check if we have a .dynsym, so that we can handle the 3058c2ecf20Sopenharmony_ci * .plt, synthesizing its symbols, that aren't on the symtabs (be it 3068c2ecf20Sopenharmony_ci * .dynsym or .symtab). 3078c2ecf20Sopenharmony_ci * And always look at the original dso, not at debuginfo packages, that 3088c2ecf20Sopenharmony_ci * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ciint dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci uint32_t nr_rel_entries, idx; 3138c2ecf20Sopenharmony_ci GElf_Sym sym; 3148c2ecf20Sopenharmony_ci u64 plt_offset, plt_header_size, plt_entry_size; 3158c2ecf20Sopenharmony_ci GElf_Shdr shdr_plt; 3168c2ecf20Sopenharmony_ci struct symbol *f; 3178c2ecf20Sopenharmony_ci GElf_Shdr shdr_rel_plt, shdr_dynsym; 3188c2ecf20Sopenharmony_ci Elf_Data *reldata, *syms, *symstrs; 3198c2ecf20Sopenharmony_ci Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 3208c2ecf20Sopenharmony_ci size_t dynsym_idx; 3218c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 3228c2ecf20Sopenharmony_ci char sympltname[1024]; 3238c2ecf20Sopenharmony_ci Elf *elf; 3248c2ecf20Sopenharmony_ci int nr = 0, symidx, err = 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!ss->dynsym) 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci elf = ss->elf; 3308c2ecf20Sopenharmony_ci ehdr = ss->ehdr; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci scn_dynsym = ss->dynsym; 3338c2ecf20Sopenharmony_ci shdr_dynsym = ss->dynshdr; 3348c2ecf20Sopenharmony_ci dynsym_idx = ss->dynsym_idx; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (scn_dynsym == NULL) 3378c2ecf20Sopenharmony_ci goto out_elf_end; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 3408c2ecf20Sopenharmony_ci ".rela.plt", NULL); 3418c2ecf20Sopenharmony_ci if (scn_plt_rel == NULL) { 3428c2ecf20Sopenharmony_ci scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 3438c2ecf20Sopenharmony_ci ".rel.plt", NULL); 3448c2ecf20Sopenharmony_ci if (scn_plt_rel == NULL) 3458c2ecf20Sopenharmony_ci goto out_elf_end; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci err = -1; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (shdr_rel_plt.sh_link != dynsym_idx) 3518c2ecf20Sopenharmony_ci goto out_elf_end; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 3548c2ecf20Sopenharmony_ci goto out_elf_end; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * Fetch the relocation section to find the idxes to the GOT 3588c2ecf20Sopenharmony_ci * and the symbols in the .dynsym they refer to. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci reldata = elf_getdata(scn_plt_rel, NULL); 3618c2ecf20Sopenharmony_ci if (reldata == NULL) 3628c2ecf20Sopenharmony_ci goto out_elf_end; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci syms = elf_getdata(scn_dynsym, NULL); 3658c2ecf20Sopenharmony_ci if (syms == NULL) 3668c2ecf20Sopenharmony_ci goto out_elf_end; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 3698c2ecf20Sopenharmony_ci if (scn_symstrs == NULL) 3708c2ecf20Sopenharmony_ci goto out_elf_end; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci symstrs = elf_getdata(scn_symstrs, NULL); 3738c2ecf20Sopenharmony_ci if (symstrs == NULL) 3748c2ecf20Sopenharmony_ci goto out_elf_end; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (symstrs->d_size == 0) 3778c2ecf20Sopenharmony_ci goto out_elf_end; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 3808c2ecf20Sopenharmony_ci plt_offset = shdr_plt.sh_offset; 3818c2ecf20Sopenharmony_ci switch (ehdr.e_machine) { 3828c2ecf20Sopenharmony_ci case EM_ARM: 3838c2ecf20Sopenharmony_ci plt_header_size = 20; 3848c2ecf20Sopenharmony_ci plt_entry_size = 12; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci case EM_AARCH64: 3888c2ecf20Sopenharmony_ci plt_header_size = 32; 3898c2ecf20Sopenharmony_ci plt_entry_size = 16; 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci case EM_SPARC: 3938c2ecf20Sopenharmony_ci plt_header_size = 48; 3948c2ecf20Sopenharmony_ci plt_entry_size = 12; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci case EM_SPARCV9: 3988c2ecf20Sopenharmony_ci plt_header_size = 128; 3998c2ecf20Sopenharmony_ci plt_entry_size = 32; 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci default: /* FIXME: s390/alpha/mips/parisc/poperpc/sh/xtensa need to be checked */ 4038c2ecf20Sopenharmony_ci plt_header_size = shdr_plt.sh_entsize; 4048c2ecf20Sopenharmony_ci plt_entry_size = shdr_plt.sh_entsize; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci plt_offset += plt_header_size; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (shdr_rel_plt.sh_type == SHT_RELA) { 4108c2ecf20Sopenharmony_ci GElf_Rela pos_mem, *pos; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci elf_section__for_each_rela(reldata, pos, pos_mem, idx, 4138c2ecf20Sopenharmony_ci nr_rel_entries) { 4148c2ecf20Sopenharmony_ci const char *elf_name = NULL; 4158c2ecf20Sopenharmony_ci char *demangled = NULL; 4168c2ecf20Sopenharmony_ci symidx = GELF_R_SYM(pos->r_info); 4178c2ecf20Sopenharmony_ci gelf_getsym(syms, symidx, &sym); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci elf_name = elf_sym__name(&sym, symstrs); 4208c2ecf20Sopenharmony_ci demangled = demangle_sym(dso, 0, elf_name); 4218c2ecf20Sopenharmony_ci if (demangled != NULL) 4228c2ecf20Sopenharmony_ci elf_name = demangled; 4238c2ecf20Sopenharmony_ci snprintf(sympltname, sizeof(sympltname), 4248c2ecf20Sopenharmony_ci "%s@plt", elf_name); 4258c2ecf20Sopenharmony_ci free(demangled); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci f = symbol__new(plt_offset, plt_entry_size, 4288c2ecf20Sopenharmony_ci STB_GLOBAL, STT_FUNC, sympltname); 4298c2ecf20Sopenharmony_ci if (!f) 4308c2ecf20Sopenharmony_ci goto out_elf_end; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci plt_offset += plt_entry_size; 4338c2ecf20Sopenharmony_ci symbols__insert(&dso->symbols, f); 4348c2ecf20Sopenharmony_ci ++nr; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci } else if (shdr_rel_plt.sh_type == SHT_REL) { 4378c2ecf20Sopenharmony_ci GElf_Rel pos_mem, *pos; 4388c2ecf20Sopenharmony_ci elf_section__for_each_rel(reldata, pos, pos_mem, idx, 4398c2ecf20Sopenharmony_ci nr_rel_entries) { 4408c2ecf20Sopenharmony_ci const char *elf_name = NULL; 4418c2ecf20Sopenharmony_ci char *demangled = NULL; 4428c2ecf20Sopenharmony_ci symidx = GELF_R_SYM(pos->r_info); 4438c2ecf20Sopenharmony_ci gelf_getsym(syms, symidx, &sym); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci elf_name = elf_sym__name(&sym, symstrs); 4468c2ecf20Sopenharmony_ci demangled = demangle_sym(dso, 0, elf_name); 4478c2ecf20Sopenharmony_ci if (demangled != NULL) 4488c2ecf20Sopenharmony_ci elf_name = demangled; 4498c2ecf20Sopenharmony_ci snprintf(sympltname, sizeof(sympltname), 4508c2ecf20Sopenharmony_ci "%s@plt", elf_name); 4518c2ecf20Sopenharmony_ci free(demangled); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci f = symbol__new(plt_offset, plt_entry_size, 4548c2ecf20Sopenharmony_ci STB_GLOBAL, STT_FUNC, sympltname); 4558c2ecf20Sopenharmony_ci if (!f) 4568c2ecf20Sopenharmony_ci goto out_elf_end; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci plt_offset += plt_entry_size; 4598c2ecf20Sopenharmony_ci symbols__insert(&dso->symbols, f); 4608c2ecf20Sopenharmony_ci ++nr; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci err = 0; 4658c2ecf20Sopenharmony_ciout_elf_end: 4668c2ecf20Sopenharmony_ci if (err == 0) 4678c2ecf20Sopenharmony_ci return nr; 4688c2ecf20Sopenharmony_ci pr_debug("%s: problems reading %s PLT info.\n", 4698c2ecf20Sopenharmony_ci __func__, dso->long_name); 4708c2ecf20Sopenharmony_ci return 0; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cichar *dso__demangle_sym(struct dso *dso, int kmodule, const char *elf_name) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci return demangle_sym(dso, kmodule, elf_name); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* 4798c2ecf20Sopenharmony_ci * Align offset to 4 bytes as needed for note name and descriptor data. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_ci#define NOTE_ALIGN(n) (((n) + 3) & -4U) 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int elf_read_build_id(Elf *elf, void *bf, size_t size) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci int err = -1; 4868c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 4878c2ecf20Sopenharmony_ci GElf_Shdr shdr; 4888c2ecf20Sopenharmony_ci Elf_Data *data; 4898c2ecf20Sopenharmony_ci Elf_Scn *sec; 4908c2ecf20Sopenharmony_ci Elf_Kind ek; 4918c2ecf20Sopenharmony_ci void *ptr; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (size < BUILD_ID_SIZE) 4948c2ecf20Sopenharmony_ci goto out; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ek = elf_kind(elf); 4978c2ecf20Sopenharmony_ci if (ek != ELF_K_ELF) 4988c2ecf20Sopenharmony_ci goto out; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) { 5018c2ecf20Sopenharmony_ci pr_err("%s: cannot get elf header.\n", __func__); 5028c2ecf20Sopenharmony_ci goto out; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* 5068c2ecf20Sopenharmony_ci * Check following sections for notes: 5078c2ecf20Sopenharmony_ci * '.note.gnu.build-id' 5088c2ecf20Sopenharmony_ci * '.notes' 5098c2ecf20Sopenharmony_ci * '.note' (VDSO specific) 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_ci do { 5128c2ecf20Sopenharmony_ci sec = elf_section_by_name(elf, &ehdr, &shdr, 5138c2ecf20Sopenharmony_ci ".note.gnu.build-id", NULL); 5148c2ecf20Sopenharmony_ci if (sec) 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci sec = elf_section_by_name(elf, &ehdr, &shdr, 5188c2ecf20Sopenharmony_ci ".notes", NULL); 5198c2ecf20Sopenharmony_ci if (sec) 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci sec = elf_section_by_name(elf, &ehdr, &shdr, 5238c2ecf20Sopenharmony_ci ".note", NULL); 5248c2ecf20Sopenharmony_ci if (sec) 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return err; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci } while (0); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci data = elf_getdata(sec, NULL); 5328c2ecf20Sopenharmony_ci if (data == NULL) 5338c2ecf20Sopenharmony_ci goto out; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ptr = data->d_buf; 5368c2ecf20Sopenharmony_ci while (ptr < (data->d_buf + data->d_size)) { 5378c2ecf20Sopenharmony_ci GElf_Nhdr *nhdr = ptr; 5388c2ecf20Sopenharmony_ci size_t namesz = NOTE_ALIGN(nhdr->n_namesz), 5398c2ecf20Sopenharmony_ci descsz = NOTE_ALIGN(nhdr->n_descsz); 5408c2ecf20Sopenharmony_ci const char *name; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ptr += sizeof(*nhdr); 5438c2ecf20Sopenharmony_ci name = ptr; 5448c2ecf20Sopenharmony_ci ptr += namesz; 5458c2ecf20Sopenharmony_ci if (nhdr->n_type == NT_GNU_BUILD_ID && 5468c2ecf20Sopenharmony_ci nhdr->n_namesz == sizeof("GNU")) { 5478c2ecf20Sopenharmony_ci if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 5488c2ecf20Sopenharmony_ci size_t sz = min(size, descsz); 5498c2ecf20Sopenharmony_ci memcpy(bf, ptr, sz); 5508c2ecf20Sopenharmony_ci memset(bf + sz, 0, size - sz); 5518c2ecf20Sopenharmony_ci err = sz; 5528c2ecf20Sopenharmony_ci break; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci ptr += descsz; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ciout: 5598c2ecf20Sopenharmony_ci return err; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_BUILDID_SUPPORT 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ciint filename__read_build_id(const char *filename, struct build_id *bid) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci size_t size = sizeof(bid->data); 5678c2ecf20Sopenharmony_ci int err = -1; 5688c2ecf20Sopenharmony_ci bfd *abfd; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci abfd = bfd_openr(filename, NULL); 5718c2ecf20Sopenharmony_ci if (!abfd) 5728c2ecf20Sopenharmony_ci return -1; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (!bfd_check_format(abfd, bfd_object)) { 5758c2ecf20Sopenharmony_ci pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); 5768c2ecf20Sopenharmony_ci goto out_close; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (!abfd->build_id || abfd->build_id->size > size) 5808c2ecf20Sopenharmony_ci goto out_close; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci memcpy(bid->data, abfd->build_id->data, abfd->build_id->size); 5838c2ecf20Sopenharmony_ci memset(bid->data + abfd->build_id->size, 0, size - abfd->build_id->size); 5848c2ecf20Sopenharmony_ci err = bid->size = abfd->build_id->size; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ciout_close: 5878c2ecf20Sopenharmony_ci bfd_close(abfd); 5888c2ecf20Sopenharmony_ci return err; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci#else // HAVE_LIBBFD_BUILDID_SUPPORT 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ciint filename__read_build_id(const char *filename, struct build_id *bid) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci size_t size = sizeof(bid->data); 5968c2ecf20Sopenharmony_ci int fd, err = -1; 5978c2ecf20Sopenharmony_ci Elf *elf; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (size < BUILD_ID_SIZE) 6008c2ecf20Sopenharmony_ci goto out; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci fd = open(filename, O_RDONLY); 6038c2ecf20Sopenharmony_ci if (fd < 0) 6048c2ecf20Sopenharmony_ci goto out; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 6078c2ecf20Sopenharmony_ci if (elf == NULL) { 6088c2ecf20Sopenharmony_ci pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 6098c2ecf20Sopenharmony_ci goto out_close; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci err = elf_read_build_id(elf, bid->data, size); 6138c2ecf20Sopenharmony_ci if (err > 0) 6148c2ecf20Sopenharmony_ci bid->size = err; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci elf_end(elf); 6178c2ecf20Sopenharmony_ciout_close: 6188c2ecf20Sopenharmony_ci close(fd); 6198c2ecf20Sopenharmony_ciout: 6208c2ecf20Sopenharmony_ci return err; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci#endif // HAVE_LIBBFD_BUILDID_SUPPORT 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ciint sysfs__read_build_id(const char *filename, struct build_id *bid) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci size_t size = sizeof(bid->data); 6288c2ecf20Sopenharmony_ci int fd, err = -1; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci fd = open(filename, O_RDONLY); 6318c2ecf20Sopenharmony_ci if (fd < 0) 6328c2ecf20Sopenharmony_ci goto out; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci while (1) { 6358c2ecf20Sopenharmony_ci char bf[BUFSIZ]; 6368c2ecf20Sopenharmony_ci GElf_Nhdr nhdr; 6378c2ecf20Sopenharmony_ci size_t namesz, descsz; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 6408c2ecf20Sopenharmony_ci break; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci namesz = NOTE_ALIGN(nhdr.n_namesz); 6438c2ecf20Sopenharmony_ci descsz = NOTE_ALIGN(nhdr.n_descsz); 6448c2ecf20Sopenharmony_ci if (nhdr.n_type == NT_GNU_BUILD_ID && 6458c2ecf20Sopenharmony_ci nhdr.n_namesz == sizeof("GNU")) { 6468c2ecf20Sopenharmony_ci if (read(fd, bf, namesz) != (ssize_t)namesz) 6478c2ecf20Sopenharmony_ci break; 6488c2ecf20Sopenharmony_ci if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 6498c2ecf20Sopenharmony_ci size_t sz = min(descsz, size); 6508c2ecf20Sopenharmony_ci if (read(fd, bid->data, sz) == (ssize_t)sz) { 6518c2ecf20Sopenharmony_ci memset(bid->data + sz, 0, size - sz); 6528c2ecf20Sopenharmony_ci bid->size = sz; 6538c2ecf20Sopenharmony_ci err = 0; 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } else if (read(fd, bf, descsz) != (ssize_t)descsz) 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci } else { 6598c2ecf20Sopenharmony_ci int n = namesz + descsz; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (n > (int)sizeof(bf)) { 6628c2ecf20Sopenharmony_ci n = sizeof(bf); 6638c2ecf20Sopenharmony_ci pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n", 6648c2ecf20Sopenharmony_ci __func__, filename, nhdr.n_namesz, nhdr.n_descsz); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci if (read(fd, bf, n) != n) 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci close(fd); 6718c2ecf20Sopenharmony_ciout: 6728c2ecf20Sopenharmony_ci return err; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ciint filename__read_debuglink(const char *filename, char *debuglink, 6788c2ecf20Sopenharmony_ci size_t size) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci int err = -1; 6818c2ecf20Sopenharmony_ci asection *section; 6828c2ecf20Sopenharmony_ci bfd *abfd; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci abfd = bfd_openr(filename, NULL); 6858c2ecf20Sopenharmony_ci if (!abfd) 6868c2ecf20Sopenharmony_ci return -1; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (!bfd_check_format(abfd, bfd_object)) { 6898c2ecf20Sopenharmony_ci pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); 6908c2ecf20Sopenharmony_ci goto out_close; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci section = bfd_get_section_by_name(abfd, ".gnu_debuglink"); 6948c2ecf20Sopenharmony_ci if (!section) 6958c2ecf20Sopenharmony_ci goto out_close; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (section->size > size) 6988c2ecf20Sopenharmony_ci goto out_close; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!bfd_get_section_contents(abfd, section, debuglink, 0, 7018c2ecf20Sopenharmony_ci section->size)) 7028c2ecf20Sopenharmony_ci goto out_close; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci err = 0; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ciout_close: 7078c2ecf20Sopenharmony_ci bfd_close(abfd); 7088c2ecf20Sopenharmony_ci return err; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci#else 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ciint filename__read_debuglink(const char *filename, char *debuglink, 7148c2ecf20Sopenharmony_ci size_t size) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci int fd, err = -1; 7178c2ecf20Sopenharmony_ci Elf *elf; 7188c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 7198c2ecf20Sopenharmony_ci GElf_Shdr shdr; 7208c2ecf20Sopenharmony_ci Elf_Data *data; 7218c2ecf20Sopenharmony_ci Elf_Scn *sec; 7228c2ecf20Sopenharmony_ci Elf_Kind ek; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci fd = open(filename, O_RDONLY); 7258c2ecf20Sopenharmony_ci if (fd < 0) 7268c2ecf20Sopenharmony_ci goto out; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 7298c2ecf20Sopenharmony_ci if (elf == NULL) { 7308c2ecf20Sopenharmony_ci pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 7318c2ecf20Sopenharmony_ci goto out_close; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci ek = elf_kind(elf); 7358c2ecf20Sopenharmony_ci if (ek != ELF_K_ELF) 7368c2ecf20Sopenharmony_ci goto out_elf_end; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) { 7398c2ecf20Sopenharmony_ci pr_err("%s: cannot get elf header.\n", __func__); 7408c2ecf20Sopenharmony_ci goto out_elf_end; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci sec = elf_section_by_name(elf, &ehdr, &shdr, 7448c2ecf20Sopenharmony_ci ".gnu_debuglink", NULL); 7458c2ecf20Sopenharmony_ci if (sec == NULL) 7468c2ecf20Sopenharmony_ci goto out_elf_end; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci data = elf_getdata(sec, NULL); 7498c2ecf20Sopenharmony_ci if (data == NULL) 7508c2ecf20Sopenharmony_ci goto out_elf_end; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* the start of this section is a zero-terminated string */ 7538c2ecf20Sopenharmony_ci strncpy(debuglink, data->d_buf, size); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci err = 0; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ciout_elf_end: 7588c2ecf20Sopenharmony_ci elf_end(elf); 7598c2ecf20Sopenharmony_ciout_close: 7608c2ecf20Sopenharmony_ci close(fd); 7618c2ecf20Sopenharmony_ciout: 7628c2ecf20Sopenharmony_ci return err; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci#endif 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic int dso__swap_init(struct dso *dso, unsigned char eidata) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci static unsigned int const endian = 1; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci dso->needs_swap = DSO_SWAP__NO; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci switch (eidata) { 7748c2ecf20Sopenharmony_ci case ELFDATA2LSB: 7758c2ecf20Sopenharmony_ci /* We are big endian, DSO is little endian. */ 7768c2ecf20Sopenharmony_ci if (*(unsigned char const *)&endian != 1) 7778c2ecf20Sopenharmony_ci dso->needs_swap = DSO_SWAP__YES; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci case ELFDATA2MSB: 7818c2ecf20Sopenharmony_ci /* We are little endian, DSO is big endian. */ 7828c2ecf20Sopenharmony_ci if (*(unsigned char const *)&endian != 0) 7838c2ecf20Sopenharmony_ci dso->needs_swap = DSO_SWAP__YES; 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci default: 7878c2ecf20Sopenharmony_ci pr_err("unrecognized DSO data encoding %d\n", eidata); 7888c2ecf20Sopenharmony_ci return -EINVAL; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return 0; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cibool symsrc__possibly_runtime(struct symsrc *ss) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci return ss->dynsym || ss->opdsec; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cibool symsrc__has_symtab(struct symsrc *ss) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci return ss->symtab != NULL; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_civoid symsrc__destroy(struct symsrc *ss) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci zfree(&ss->name); 8078c2ecf20Sopenharmony_ci elf_end(ss->elf); 8088c2ecf20Sopenharmony_ci close(ss->fd); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cibool elf__needs_adjust_symbols(GElf_Ehdr ehdr) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci /* 8148c2ecf20Sopenharmony_ci * Usually vmlinux is an ELF file with type ET_EXEC for most 8158c2ecf20Sopenharmony_ci * architectures; except Arm64 kernel is linked with option 8168c2ecf20Sopenharmony_ci * '-share', so need to check type ET_DYN. 8178c2ecf20Sopenharmony_ci */ 8188c2ecf20Sopenharmony_ci return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL || 8198c2ecf20Sopenharmony_ci ehdr.e_type == ET_DYN; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ciint symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, 8238c2ecf20Sopenharmony_ci enum dso_binary_type type) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 8268c2ecf20Sopenharmony_ci Elf *elf; 8278c2ecf20Sopenharmony_ci int fd; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (dso__needs_decompress(dso)) { 8308c2ecf20Sopenharmony_ci fd = dso__decompress_kmodule_fd(dso, name); 8318c2ecf20Sopenharmony_ci if (fd < 0) 8328c2ecf20Sopenharmony_ci return -1; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci type = dso->symtab_type; 8358c2ecf20Sopenharmony_ci } else { 8368c2ecf20Sopenharmony_ci fd = open(name, O_RDONLY); 8378c2ecf20Sopenharmony_ci if (fd < 0) { 8388c2ecf20Sopenharmony_ci dso->load_errno = errno; 8398c2ecf20Sopenharmony_ci return -1; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 8448c2ecf20Sopenharmony_ci if (elf == NULL) { 8458c2ecf20Sopenharmony_ci pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 8468c2ecf20Sopenharmony_ci dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF; 8478c2ecf20Sopenharmony_ci goto out_close; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) { 8518c2ecf20Sopenharmony_ci dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF; 8528c2ecf20Sopenharmony_ci pr_debug("%s: cannot get elf header.\n", __func__); 8538c2ecf20Sopenharmony_ci goto out_elf_end; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) { 8578c2ecf20Sopenharmony_ci dso->load_errno = DSO_LOAD_ERRNO__INTERNAL_ERROR; 8588c2ecf20Sopenharmony_ci goto out_elf_end; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Always reject images with a mismatched build-id: */ 8628c2ecf20Sopenharmony_ci if (dso->has_build_id && !symbol_conf.ignore_vmlinux_buildid) { 8638c2ecf20Sopenharmony_ci u8 build_id[BUILD_ID_SIZE]; 8648c2ecf20Sopenharmony_ci struct build_id bid; 8658c2ecf20Sopenharmony_ci int size; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci size = elf_read_build_id(elf, build_id, BUILD_ID_SIZE); 8688c2ecf20Sopenharmony_ci if (size <= 0) { 8698c2ecf20Sopenharmony_ci dso->load_errno = DSO_LOAD_ERRNO__CANNOT_READ_BUILDID; 8708c2ecf20Sopenharmony_ci goto out_elf_end; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci build_id__init(&bid, build_id, size); 8748c2ecf20Sopenharmony_ci if (!dso__build_id_equal(dso, &bid)) { 8758c2ecf20Sopenharmony_ci pr_debug("%s: build id mismatch for %s.\n", __func__, name); 8768c2ecf20Sopenharmony_ci dso->load_errno = DSO_LOAD_ERRNO__MISMATCHING_BUILDID; 8778c2ecf20Sopenharmony_ci goto out_elf_end; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", 8848c2ecf20Sopenharmony_ci NULL); 8858c2ecf20Sopenharmony_ci if (ss->symshdr.sh_type != SHT_SYMTAB) 8868c2ecf20Sopenharmony_ci ss->symtab = NULL; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci ss->dynsym_idx = 0; 8898c2ecf20Sopenharmony_ci ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym", 8908c2ecf20Sopenharmony_ci &ss->dynsym_idx); 8918c2ecf20Sopenharmony_ci if (ss->dynshdr.sh_type != SHT_DYNSYM) 8928c2ecf20Sopenharmony_ci ss->dynsym = NULL; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci ss->opdidx = 0; 8958c2ecf20Sopenharmony_ci ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd", 8968c2ecf20Sopenharmony_ci &ss->opdidx); 8978c2ecf20Sopenharmony_ci if (ss->opdshdr.sh_type != SHT_PROGBITS) 8988c2ecf20Sopenharmony_ci ss->opdsec = NULL; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__USER) 9018c2ecf20Sopenharmony_ci ss->adjust_symbols = true; 9028c2ecf20Sopenharmony_ci else 9038c2ecf20Sopenharmony_ci ss->adjust_symbols = elf__needs_adjust_symbols(ehdr); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci ss->name = strdup(name); 9068c2ecf20Sopenharmony_ci if (!ss->name) { 9078c2ecf20Sopenharmony_ci dso->load_errno = errno; 9088c2ecf20Sopenharmony_ci goto out_elf_end; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci ss->elf = elf; 9128c2ecf20Sopenharmony_ci ss->fd = fd; 9138c2ecf20Sopenharmony_ci ss->ehdr = ehdr; 9148c2ecf20Sopenharmony_ci ss->type = type; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return 0; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ciout_elf_end: 9198c2ecf20Sopenharmony_ci elf_end(elf); 9208c2ecf20Sopenharmony_ciout_close: 9218c2ecf20Sopenharmony_ci close(fd); 9228c2ecf20Sopenharmony_ci return -1; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci/** 9268c2ecf20Sopenharmony_ci * ref_reloc_sym_not_found - has kernel relocation symbol been found. 9278c2ecf20Sopenharmony_ci * @kmap: kernel maps and relocation reference symbol 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * This function returns %true if we are dealing with the kernel maps and the 9308c2ecf20Sopenharmony_ci * relocation reference symbol has not yet been found. Otherwise %false is 9318c2ecf20Sopenharmony_ci * returned. 9328c2ecf20Sopenharmony_ci */ 9338c2ecf20Sopenharmony_cistatic bool ref_reloc_sym_not_found(struct kmap *kmap) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci return kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 9368c2ecf20Sopenharmony_ci !kmap->ref_reloc_sym->unrelocated_addr; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci/** 9408c2ecf20Sopenharmony_ci * ref_reloc - kernel relocation offset. 9418c2ecf20Sopenharmony_ci * @kmap: kernel maps and relocation reference symbol 9428c2ecf20Sopenharmony_ci * 9438c2ecf20Sopenharmony_ci * This function returns the offset of kernel addresses as determined by using 9448c2ecf20Sopenharmony_ci * the relocation reference symbol i.e. if the kernel has not been relocated 9458c2ecf20Sopenharmony_ci * then the return value is zero. 9468c2ecf20Sopenharmony_ci */ 9478c2ecf20Sopenharmony_cistatic u64 ref_reloc(struct kmap *kmap) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci if (kmap && kmap->ref_reloc_sym && 9508c2ecf20Sopenharmony_ci kmap->ref_reloc_sym->unrelocated_addr) 9518c2ecf20Sopenharmony_ci return kmap->ref_reloc_sym->addr - 9528c2ecf20Sopenharmony_ci kmap->ref_reloc_sym->unrelocated_addr; 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_civoid __weak arch__sym_update(struct symbol *s __maybe_unused, 9578c2ecf20Sopenharmony_ci GElf_Sym *sym __maybe_unused) { } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic int dso__process_kernel_symbol(struct dso *dso, struct map *map, 9608c2ecf20Sopenharmony_ci GElf_Sym *sym, GElf_Shdr *shdr, 9618c2ecf20Sopenharmony_ci struct maps *kmaps, struct kmap *kmap, 9628c2ecf20Sopenharmony_ci struct dso **curr_dsop, struct map **curr_mapp, 9638c2ecf20Sopenharmony_ci const char *section_name, 9648c2ecf20Sopenharmony_ci bool adjust_kernel_syms, bool kmodule, bool *remap_kernel) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct dso *curr_dso = *curr_dsop; 9678c2ecf20Sopenharmony_ci struct map *curr_map; 9688c2ecf20Sopenharmony_ci char dso_name[PATH_MAX]; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* Adjust symbol to map to file offset */ 9718c2ecf20Sopenharmony_ci if (adjust_kernel_syms) 9728c2ecf20Sopenharmony_ci sym->st_value -= shdr->sh_addr - shdr->sh_offset; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (strcmp(section_name, (curr_dso->short_name + dso->short_name_len)) == 0) 9758c2ecf20Sopenharmony_ci return 0; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (strcmp(section_name, ".text") == 0) { 9788c2ecf20Sopenharmony_ci /* 9798c2ecf20Sopenharmony_ci * The initial kernel mapping is based on 9808c2ecf20Sopenharmony_ci * kallsyms and identity maps. Overwrite it to 9818c2ecf20Sopenharmony_ci * map to the kernel dso. 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci if (*remap_kernel && dso->kernel && !kmodule) { 9848c2ecf20Sopenharmony_ci *remap_kernel = false; 9858c2ecf20Sopenharmony_ci map->start = shdr->sh_addr + ref_reloc(kmap); 9868c2ecf20Sopenharmony_ci map->end = map->start + shdr->sh_size; 9878c2ecf20Sopenharmony_ci map->pgoff = shdr->sh_offset; 9888c2ecf20Sopenharmony_ci map->map_ip = map__map_ip; 9898c2ecf20Sopenharmony_ci map->unmap_ip = map__unmap_ip; 9908c2ecf20Sopenharmony_ci /* Ensure maps are correctly ordered */ 9918c2ecf20Sopenharmony_ci if (kmaps) { 9928c2ecf20Sopenharmony_ci map__get(map); 9938c2ecf20Sopenharmony_ci maps__remove(kmaps, map); 9948c2ecf20Sopenharmony_ci maps__insert(kmaps, map); 9958c2ecf20Sopenharmony_ci map__put(map); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* 10008c2ecf20Sopenharmony_ci * The initial module mapping is based on 10018c2ecf20Sopenharmony_ci * /proc/modules mapped to offset zero. 10028c2ecf20Sopenharmony_ci * Overwrite it to map to the module dso. 10038c2ecf20Sopenharmony_ci */ 10048c2ecf20Sopenharmony_ci if (*remap_kernel && kmodule) { 10058c2ecf20Sopenharmony_ci *remap_kernel = false; 10068c2ecf20Sopenharmony_ci map->pgoff = shdr->sh_offset; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci *curr_mapp = map; 10108c2ecf20Sopenharmony_ci *curr_dsop = dso; 10118c2ecf20Sopenharmony_ci return 0; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (!kmap) 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci snprintf(dso_name, sizeof(dso_name), "%s%s", dso->short_name, section_name); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci curr_map = maps__find_by_name(kmaps, dso_name); 10208c2ecf20Sopenharmony_ci if (curr_map == NULL) { 10218c2ecf20Sopenharmony_ci u64 start = sym->st_value; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (kmodule) 10248c2ecf20Sopenharmony_ci start += map->start + shdr->sh_offset; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci curr_dso = dso__new(dso_name); 10278c2ecf20Sopenharmony_ci if (curr_dso == NULL) 10288c2ecf20Sopenharmony_ci return -1; 10298c2ecf20Sopenharmony_ci curr_dso->kernel = dso->kernel; 10308c2ecf20Sopenharmony_ci curr_dso->long_name = dso->long_name; 10318c2ecf20Sopenharmony_ci curr_dso->long_name_len = dso->long_name_len; 10328c2ecf20Sopenharmony_ci curr_map = map__new2(start, curr_dso); 10338c2ecf20Sopenharmony_ci dso__put(curr_dso); 10348c2ecf20Sopenharmony_ci if (curr_map == NULL) 10358c2ecf20Sopenharmony_ci return -1; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (curr_dso->kernel) 10388c2ecf20Sopenharmony_ci map__kmap(curr_map)->kmaps = kmaps; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (adjust_kernel_syms) { 10418c2ecf20Sopenharmony_ci curr_map->start = shdr->sh_addr + ref_reloc(kmap); 10428c2ecf20Sopenharmony_ci curr_map->end = curr_map->start + shdr->sh_size; 10438c2ecf20Sopenharmony_ci curr_map->pgoff = shdr->sh_offset; 10448c2ecf20Sopenharmony_ci } else { 10458c2ecf20Sopenharmony_ci curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci curr_dso->symtab_type = dso->symtab_type; 10488c2ecf20Sopenharmony_ci maps__insert(kmaps, curr_map); 10498c2ecf20Sopenharmony_ci /* 10508c2ecf20Sopenharmony_ci * Add it before we drop the referece to curr_map, i.e. while 10518c2ecf20Sopenharmony_ci * we still are sure to have a reference to this DSO via 10528c2ecf20Sopenharmony_ci * *curr_map->dso. 10538c2ecf20Sopenharmony_ci */ 10548c2ecf20Sopenharmony_ci dsos__add(&kmaps->machine->dsos, curr_dso); 10558c2ecf20Sopenharmony_ci /* kmaps already got it */ 10568c2ecf20Sopenharmony_ci map__put(curr_map); 10578c2ecf20Sopenharmony_ci dso__set_loaded(curr_dso); 10588c2ecf20Sopenharmony_ci *curr_mapp = curr_map; 10598c2ecf20Sopenharmony_ci *curr_dsop = curr_dso; 10608c2ecf20Sopenharmony_ci } else 10618c2ecf20Sopenharmony_ci *curr_dsop = curr_map->dso; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci return 0; 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ciint dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 10678c2ecf20Sopenharmony_ci struct symsrc *runtime_ss, int kmodule) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; 10708c2ecf20Sopenharmony_ci struct maps *kmaps = kmap ? map__kmaps(map) : NULL; 10718c2ecf20Sopenharmony_ci struct map *curr_map = map; 10728c2ecf20Sopenharmony_ci struct dso *curr_dso = dso; 10738c2ecf20Sopenharmony_ci Elf_Data *symstrs, *secstrs; 10748c2ecf20Sopenharmony_ci uint32_t nr_syms; 10758c2ecf20Sopenharmony_ci int err = -1; 10768c2ecf20Sopenharmony_ci uint32_t idx; 10778c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 10788c2ecf20Sopenharmony_ci GElf_Shdr shdr; 10798c2ecf20Sopenharmony_ci GElf_Shdr tshdr; 10808c2ecf20Sopenharmony_ci Elf_Data *syms, *opddata = NULL; 10818c2ecf20Sopenharmony_ci GElf_Sym sym; 10828c2ecf20Sopenharmony_ci Elf_Scn *sec, *sec_strndx; 10838c2ecf20Sopenharmony_ci Elf *elf; 10848c2ecf20Sopenharmony_ci int nr = 0; 10858c2ecf20Sopenharmony_ci bool remap_kernel = false, adjust_kernel_syms = false; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (kmap && !kmaps) 10888c2ecf20Sopenharmony_ci return -1; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci dso->symtab_type = syms_ss->type; 10918c2ecf20Sopenharmony_ci dso->is_64_bit = syms_ss->is_64_bit; 10928c2ecf20Sopenharmony_ci dso->rel = syms_ss->ehdr.e_type == ET_REL; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* 10958c2ecf20Sopenharmony_ci * Modules may already have symbols from kallsyms, but those symbols 10968c2ecf20Sopenharmony_ci * have the wrong values for the dso maps, so remove them. 10978c2ecf20Sopenharmony_ci */ 10988c2ecf20Sopenharmony_ci if (kmodule && syms_ss->symtab) 10998c2ecf20Sopenharmony_ci symbols__delete(&dso->symbols); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (!syms_ss->symtab) { 11028c2ecf20Sopenharmony_ci /* 11038c2ecf20Sopenharmony_ci * If the vmlinux is stripped, fail so we will fall back 11048c2ecf20Sopenharmony_ci * to using kallsyms. The vmlinux runtime symbols aren't 11058c2ecf20Sopenharmony_ci * of much use. 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci if (dso->kernel) 11088c2ecf20Sopenharmony_ci goto out_elf_end; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci syms_ss->symtab = syms_ss->dynsym; 11118c2ecf20Sopenharmony_ci syms_ss->symshdr = syms_ss->dynshdr; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci elf = syms_ss->elf; 11158c2ecf20Sopenharmony_ci ehdr = syms_ss->ehdr; 11168c2ecf20Sopenharmony_ci sec = syms_ss->symtab; 11178c2ecf20Sopenharmony_ci shdr = syms_ss->symshdr; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (elf_section_by_name(runtime_ss->elf, &runtime_ss->ehdr, &tshdr, 11208c2ecf20Sopenharmony_ci ".text", NULL)) 11218c2ecf20Sopenharmony_ci dso->text_offset = tshdr.sh_addr - tshdr.sh_offset; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (runtime_ss->opdsec) 11248c2ecf20Sopenharmony_ci opddata = elf_rawdata(runtime_ss->opdsec, NULL); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci syms = elf_getdata(sec, NULL); 11278c2ecf20Sopenharmony_ci if (syms == NULL) 11288c2ecf20Sopenharmony_ci goto out_elf_end; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci sec = elf_getscn(elf, shdr.sh_link); 11318c2ecf20Sopenharmony_ci if (sec == NULL) 11328c2ecf20Sopenharmony_ci goto out_elf_end; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci symstrs = elf_getdata(sec, NULL); 11358c2ecf20Sopenharmony_ci if (symstrs == NULL) 11368c2ecf20Sopenharmony_ci goto out_elf_end; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx); 11398c2ecf20Sopenharmony_ci if (sec_strndx == NULL) 11408c2ecf20Sopenharmony_ci goto out_elf_end; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci secstrs = elf_getdata(sec_strndx, NULL); 11438c2ecf20Sopenharmony_ci if (secstrs == NULL) 11448c2ecf20Sopenharmony_ci goto out_elf_end; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci nr_syms = shdr.sh_size / shdr.sh_entsize; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci memset(&sym, 0, sizeof(sym)); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* 11518c2ecf20Sopenharmony_ci * The kernel relocation symbol is needed in advance in order to adjust 11528c2ecf20Sopenharmony_ci * kernel maps correctly. 11538c2ecf20Sopenharmony_ci */ 11548c2ecf20Sopenharmony_ci if (ref_reloc_sym_not_found(kmap)) { 11558c2ecf20Sopenharmony_ci elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 11568c2ecf20Sopenharmony_ci const char *elf_name = elf_sym__name(&sym, symstrs); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (strcmp(elf_name, kmap->ref_reloc_sym->name)) 11598c2ecf20Sopenharmony_ci continue; 11608c2ecf20Sopenharmony_ci kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 11618c2ecf20Sopenharmony_ci map->reloc = kmap->ref_reloc_sym->addr - 11628c2ecf20Sopenharmony_ci kmap->ref_reloc_sym->unrelocated_addr; 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * Handle any relocation of vdso necessary because older kernels 11698c2ecf20Sopenharmony_ci * attempted to prelink vdso to its virtual address. 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_ci if (dso__is_vdso(dso)) 11728c2ecf20Sopenharmony_ci map->reloc = map->start - dso->text_offset; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap); 11758c2ecf20Sopenharmony_ci /* 11768c2ecf20Sopenharmony_ci * Initial kernel and module mappings do not map to the dso. 11778c2ecf20Sopenharmony_ci * Flag the fixups. 11788c2ecf20Sopenharmony_ci */ 11798c2ecf20Sopenharmony_ci if (dso->kernel) { 11808c2ecf20Sopenharmony_ci remap_kernel = true; 11818c2ecf20Sopenharmony_ci adjust_kernel_syms = dso->adjust_symbols; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 11848c2ecf20Sopenharmony_ci struct symbol *f; 11858c2ecf20Sopenharmony_ci const char *elf_name = elf_sym__name(&sym, symstrs); 11868c2ecf20Sopenharmony_ci char *demangled = NULL; 11878c2ecf20Sopenharmony_ci int is_label = elf_sym__is_label(&sym); 11888c2ecf20Sopenharmony_ci const char *section_name; 11898c2ecf20Sopenharmony_ci bool used_opd = false; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (!is_label && !elf_sym__filter(&sym)) 11928c2ecf20Sopenharmony_ci continue; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* Reject ARM ELF "mapping symbols": these aren't unique and 11958c2ecf20Sopenharmony_ci * don't identify functions, so will confuse the profile 11968c2ecf20Sopenharmony_ci * output: */ 11978c2ecf20Sopenharmony_ci if (ehdr.e_machine == EM_ARM || ehdr.e_machine == EM_AARCH64) { 11988c2ecf20Sopenharmony_ci if (elf_name[0] == '$' && strchr("adtx", elf_name[1]) 11998c2ecf20Sopenharmony_ci && (elf_name[2] == '\0' || elf_name[2] == '.')) 12008c2ecf20Sopenharmony_ci continue; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (runtime_ss->opdsec && sym.st_shndx == runtime_ss->opdidx) { 12048c2ecf20Sopenharmony_ci u32 offset = sym.st_value - syms_ss->opdshdr.sh_addr; 12058c2ecf20Sopenharmony_ci u64 *opd = opddata->d_buf + offset; 12068c2ecf20Sopenharmony_ci sym.st_value = DSO__SWAP(dso, u64, *opd); 12078c2ecf20Sopenharmony_ci sym.st_shndx = elf_addr_to_index(runtime_ss->elf, 12088c2ecf20Sopenharmony_ci sym.st_value); 12098c2ecf20Sopenharmony_ci used_opd = true; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci /* 12138c2ecf20Sopenharmony_ci * When loading symbols in a data mapping, ABS symbols (which 12148c2ecf20Sopenharmony_ci * has a value of SHN_ABS in its st_shndx) failed at 12158c2ecf20Sopenharmony_ci * elf_getscn(). And it marks the loading as a failure so 12168c2ecf20Sopenharmony_ci * already loaded symbols cannot be fixed up. 12178c2ecf20Sopenharmony_ci * 12188c2ecf20Sopenharmony_ci * I'm not sure what should be done. Just ignore them for now. 12198c2ecf20Sopenharmony_ci * - Namhyung Kim 12208c2ecf20Sopenharmony_ci */ 12218c2ecf20Sopenharmony_ci if (sym.st_shndx == SHN_ABS) 12228c2ecf20Sopenharmony_ci continue; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci sec = elf_getscn(runtime_ss->elf, sym.st_shndx); 12258c2ecf20Sopenharmony_ci if (!sec) 12268c2ecf20Sopenharmony_ci goto out_elf_end; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci gelf_getshdr(sec, &shdr); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (is_label && !elf_sec__filter(&shdr, secstrs)) 12318c2ecf20Sopenharmony_ci continue; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci section_name = elf_sec__name(&shdr, secstrs); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* On ARM, symbols for thumb functions have 1 added to 12368c2ecf20Sopenharmony_ci * the symbol address as a flag - remove it */ 12378c2ecf20Sopenharmony_ci if ((ehdr.e_machine == EM_ARM) && 12388c2ecf20Sopenharmony_ci (GELF_ST_TYPE(sym.st_info) == STT_FUNC) && 12398c2ecf20Sopenharmony_ci (sym.st_value & 1)) 12408c2ecf20Sopenharmony_ci --sym.st_value; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci if (dso->kernel) { 12438c2ecf20Sopenharmony_ci if (dso__process_kernel_symbol(dso, map, &sym, &shdr, kmaps, kmap, &curr_dso, &curr_map, 12448c2ecf20Sopenharmony_ci section_name, adjust_kernel_syms, kmodule, &remap_kernel)) 12458c2ecf20Sopenharmony_ci goto out_elf_end; 12468c2ecf20Sopenharmony_ci } else if ((used_opd && runtime_ss->adjust_symbols) || 12478c2ecf20Sopenharmony_ci (!used_opd && syms_ss->adjust_symbols)) { 12488c2ecf20Sopenharmony_ci GElf_Phdr phdr; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (elf_read_program_header(runtime_ss->elf, 12518c2ecf20Sopenharmony_ci (u64)sym.st_value, &phdr)) { 12528c2ecf20Sopenharmony_ci pr_debug4("%s: failed to find program header for " 12538c2ecf20Sopenharmony_ci "symbol: %s st_value: %#" PRIx64 "\n", 12548c2ecf20Sopenharmony_ci __func__, elf_name, (u64)sym.st_value); 12558c2ecf20Sopenharmony_ci pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " 12568c2ecf20Sopenharmony_ci "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", 12578c2ecf20Sopenharmony_ci __func__, (u64)sym.st_value, (u64)shdr.sh_addr, 12588c2ecf20Sopenharmony_ci (u64)shdr.sh_offset); 12598c2ecf20Sopenharmony_ci /* 12608c2ecf20Sopenharmony_ci * Fail to find program header, let's rollback 12618c2ecf20Sopenharmony_ci * to use shdr.sh_addr and shdr.sh_offset to 12628c2ecf20Sopenharmony_ci * calibrate symbol's file address, though this 12638c2ecf20Sopenharmony_ci * is not necessary for normal C ELF file, we 12648c2ecf20Sopenharmony_ci * still need to handle java JIT symbols in this 12658c2ecf20Sopenharmony_ci * case. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci sym.st_value -= shdr.sh_addr - shdr.sh_offset; 12688c2ecf20Sopenharmony_ci } else { 12698c2ecf20Sopenharmony_ci pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " 12708c2ecf20Sopenharmony_ci "p_vaddr: %#" PRIx64 " p_offset: %#" PRIx64 "\n", 12718c2ecf20Sopenharmony_ci __func__, (u64)sym.st_value, (u64)phdr.p_vaddr, 12728c2ecf20Sopenharmony_ci (u64)phdr.p_offset); 12738c2ecf20Sopenharmony_ci sym.st_value -= phdr.p_vaddr - phdr.p_offset; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci demangled = demangle_sym(dso, kmodule, elf_name); 12788c2ecf20Sopenharmony_ci if (demangled != NULL) 12798c2ecf20Sopenharmony_ci elf_name = demangled; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci f = symbol__new(sym.st_value, sym.st_size, 12828c2ecf20Sopenharmony_ci GELF_ST_BIND(sym.st_info), 12838c2ecf20Sopenharmony_ci GELF_ST_TYPE(sym.st_info), elf_name); 12848c2ecf20Sopenharmony_ci free(demangled); 12858c2ecf20Sopenharmony_ci if (!f) 12868c2ecf20Sopenharmony_ci goto out_elf_end; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci arch__sym_update(f, &sym); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci __symbols__insert(&curr_dso->symbols, f, dso->kernel); 12918c2ecf20Sopenharmony_ci nr++; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* 12958c2ecf20Sopenharmony_ci * For misannotated, zeroed, ASM function sizes. 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_ci if (nr > 0) { 12988c2ecf20Sopenharmony_ci symbols__fixup_end(&dso->symbols, false); 12998c2ecf20Sopenharmony_ci symbols__fixup_duplicate(&dso->symbols); 13008c2ecf20Sopenharmony_ci if (kmap) { 13018c2ecf20Sopenharmony_ci /* 13028c2ecf20Sopenharmony_ci * We need to fixup this here too because we create new 13038c2ecf20Sopenharmony_ci * maps here, for things like vsyscall sections. 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_ci maps__fixup_end(kmaps); 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci err = nr; 13098c2ecf20Sopenharmony_ciout_elf_end: 13108c2ecf20Sopenharmony_ci return err; 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_cistatic int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci GElf_Phdr phdr; 13168c2ecf20Sopenharmony_ci size_t i, phdrnum; 13178c2ecf20Sopenharmony_ci int err; 13188c2ecf20Sopenharmony_ci u64 sz; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (elf_getphdrnum(elf, &phdrnum)) 13218c2ecf20Sopenharmony_ci return -1; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci for (i = 0; i < phdrnum; i++) { 13248c2ecf20Sopenharmony_ci if (gelf_getphdr(elf, i, &phdr) == NULL) 13258c2ecf20Sopenharmony_ci return -1; 13268c2ecf20Sopenharmony_ci if (phdr.p_type != PT_LOAD) 13278c2ecf20Sopenharmony_ci continue; 13288c2ecf20Sopenharmony_ci if (exe) { 13298c2ecf20Sopenharmony_ci if (!(phdr.p_flags & PF_X)) 13308c2ecf20Sopenharmony_ci continue; 13318c2ecf20Sopenharmony_ci } else { 13328c2ecf20Sopenharmony_ci if (!(phdr.p_flags & PF_R)) 13338c2ecf20Sopenharmony_ci continue; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci sz = min(phdr.p_memsz, phdr.p_filesz); 13368c2ecf20Sopenharmony_ci if (!sz) 13378c2ecf20Sopenharmony_ci continue; 13388c2ecf20Sopenharmony_ci err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data); 13398c2ecf20Sopenharmony_ci if (err) 13408c2ecf20Sopenharmony_ci return err; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci return 0; 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ciint file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, 13468c2ecf20Sopenharmony_ci bool *is_64_bit) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci int err; 13498c2ecf20Sopenharmony_ci Elf *elf; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 13528c2ecf20Sopenharmony_ci if (elf == NULL) 13538c2ecf20Sopenharmony_ci return -1; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (is_64_bit) 13568c2ecf20Sopenharmony_ci *is_64_bit = (gelf_getclass(elf) == ELFCLASS64); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci err = elf_read_maps(elf, exe, mapfn, data); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci elf_end(elf); 13618c2ecf20Sopenharmony_ci return err; 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cienum dso_type dso__type_fd(int fd) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci enum dso_type dso_type = DSO__TYPE_UNKNOWN; 13678c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 13688c2ecf20Sopenharmony_ci Elf_Kind ek; 13698c2ecf20Sopenharmony_ci Elf *elf; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 13728c2ecf20Sopenharmony_ci if (elf == NULL) 13738c2ecf20Sopenharmony_ci goto out; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci ek = elf_kind(elf); 13768c2ecf20Sopenharmony_ci if (ek != ELF_K_ELF) 13778c2ecf20Sopenharmony_ci goto out_end; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (gelf_getclass(elf) == ELFCLASS64) { 13808c2ecf20Sopenharmony_ci dso_type = DSO__TYPE_64BIT; 13818c2ecf20Sopenharmony_ci goto out_end; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) 13858c2ecf20Sopenharmony_ci goto out_end; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci if (ehdr.e_machine == EM_X86_64) 13888c2ecf20Sopenharmony_ci dso_type = DSO__TYPE_X32BIT; 13898c2ecf20Sopenharmony_ci else 13908c2ecf20Sopenharmony_ci dso_type = DSO__TYPE_32BIT; 13918c2ecf20Sopenharmony_ciout_end: 13928c2ecf20Sopenharmony_ci elf_end(elf); 13938c2ecf20Sopenharmony_ciout: 13948c2ecf20Sopenharmony_ci return dso_type; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci ssize_t r; 14008c2ecf20Sopenharmony_ci size_t n; 14018c2ecf20Sopenharmony_ci int err = -1; 14028c2ecf20Sopenharmony_ci char *buf = malloc(page_size); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (buf == NULL) 14058c2ecf20Sopenharmony_ci return -1; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (lseek(to, to_offs, SEEK_SET) != to_offs) 14088c2ecf20Sopenharmony_ci goto out; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (lseek(from, from_offs, SEEK_SET) != from_offs) 14118c2ecf20Sopenharmony_ci goto out; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci while (len) { 14148c2ecf20Sopenharmony_ci n = page_size; 14158c2ecf20Sopenharmony_ci if (len < n) 14168c2ecf20Sopenharmony_ci n = len; 14178c2ecf20Sopenharmony_ci /* Use read because mmap won't work on proc files */ 14188c2ecf20Sopenharmony_ci r = read(from, buf, n); 14198c2ecf20Sopenharmony_ci if (r < 0) 14208c2ecf20Sopenharmony_ci goto out; 14218c2ecf20Sopenharmony_ci if (!r) 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci n = r; 14248c2ecf20Sopenharmony_ci r = write(to, buf, n); 14258c2ecf20Sopenharmony_ci if (r < 0) 14268c2ecf20Sopenharmony_ci goto out; 14278c2ecf20Sopenharmony_ci if ((size_t)r != n) 14288c2ecf20Sopenharmony_ci goto out; 14298c2ecf20Sopenharmony_ci len -= n; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci err = 0; 14338c2ecf20Sopenharmony_ciout: 14348c2ecf20Sopenharmony_ci free(buf); 14358c2ecf20Sopenharmony_ci return err; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistruct kcore { 14398c2ecf20Sopenharmony_ci int fd; 14408c2ecf20Sopenharmony_ci int elfclass; 14418c2ecf20Sopenharmony_ci Elf *elf; 14428c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 14438c2ecf20Sopenharmony_ci}; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic int kcore__open(struct kcore *kcore, const char *filename) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci GElf_Ehdr *ehdr; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci kcore->fd = open(filename, O_RDONLY); 14508c2ecf20Sopenharmony_ci if (kcore->fd == -1) 14518c2ecf20Sopenharmony_ci return -1; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci kcore->elf = elf_begin(kcore->fd, ELF_C_READ, NULL); 14548c2ecf20Sopenharmony_ci if (!kcore->elf) 14558c2ecf20Sopenharmony_ci goto out_close; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci kcore->elfclass = gelf_getclass(kcore->elf); 14588c2ecf20Sopenharmony_ci if (kcore->elfclass == ELFCLASSNONE) 14598c2ecf20Sopenharmony_ci goto out_end; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr); 14628c2ecf20Sopenharmony_ci if (!ehdr) 14638c2ecf20Sopenharmony_ci goto out_end; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci return 0; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ciout_end: 14688c2ecf20Sopenharmony_ci elf_end(kcore->elf); 14698c2ecf20Sopenharmony_ciout_close: 14708c2ecf20Sopenharmony_ci close(kcore->fd); 14718c2ecf20Sopenharmony_ci return -1; 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic int kcore__init(struct kcore *kcore, char *filename, int elfclass, 14758c2ecf20Sopenharmony_ci bool temp) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci kcore->elfclass = elfclass; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (temp) 14808c2ecf20Sopenharmony_ci kcore->fd = mkstemp(filename); 14818c2ecf20Sopenharmony_ci else 14828c2ecf20Sopenharmony_ci kcore->fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400); 14838c2ecf20Sopenharmony_ci if (kcore->fd == -1) 14848c2ecf20Sopenharmony_ci return -1; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci kcore->elf = elf_begin(kcore->fd, ELF_C_WRITE, NULL); 14878c2ecf20Sopenharmony_ci if (!kcore->elf) 14888c2ecf20Sopenharmony_ci goto out_close; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci if (!gelf_newehdr(kcore->elf, elfclass)) 14918c2ecf20Sopenharmony_ci goto out_end; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci memset(&kcore->ehdr, 0, sizeof(GElf_Ehdr)); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return 0; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ciout_end: 14988c2ecf20Sopenharmony_ci elf_end(kcore->elf); 14998c2ecf20Sopenharmony_ciout_close: 15008c2ecf20Sopenharmony_ci close(kcore->fd); 15018c2ecf20Sopenharmony_ci unlink(filename); 15028c2ecf20Sopenharmony_ci return -1; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic void kcore__close(struct kcore *kcore) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci elf_end(kcore->elf); 15088c2ecf20Sopenharmony_ci close(kcore->fd); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic int kcore__copy_hdr(struct kcore *from, struct kcore *to, size_t count) 15128c2ecf20Sopenharmony_ci{ 15138c2ecf20Sopenharmony_ci GElf_Ehdr *ehdr = &to->ehdr; 15148c2ecf20Sopenharmony_ci GElf_Ehdr *kehdr = &from->ehdr; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci memcpy(ehdr->e_ident, kehdr->e_ident, EI_NIDENT); 15178c2ecf20Sopenharmony_ci ehdr->e_type = kehdr->e_type; 15188c2ecf20Sopenharmony_ci ehdr->e_machine = kehdr->e_machine; 15198c2ecf20Sopenharmony_ci ehdr->e_version = kehdr->e_version; 15208c2ecf20Sopenharmony_ci ehdr->e_entry = 0; 15218c2ecf20Sopenharmony_ci ehdr->e_shoff = 0; 15228c2ecf20Sopenharmony_ci ehdr->e_flags = kehdr->e_flags; 15238c2ecf20Sopenharmony_ci ehdr->e_phnum = count; 15248c2ecf20Sopenharmony_ci ehdr->e_shentsize = 0; 15258c2ecf20Sopenharmony_ci ehdr->e_shnum = 0; 15268c2ecf20Sopenharmony_ci ehdr->e_shstrndx = 0; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci if (from->elfclass == ELFCLASS32) { 15298c2ecf20Sopenharmony_ci ehdr->e_phoff = sizeof(Elf32_Ehdr); 15308c2ecf20Sopenharmony_ci ehdr->e_ehsize = sizeof(Elf32_Ehdr); 15318c2ecf20Sopenharmony_ci ehdr->e_phentsize = sizeof(Elf32_Phdr); 15328c2ecf20Sopenharmony_ci } else { 15338c2ecf20Sopenharmony_ci ehdr->e_phoff = sizeof(Elf64_Ehdr); 15348c2ecf20Sopenharmony_ci ehdr->e_ehsize = sizeof(Elf64_Ehdr); 15358c2ecf20Sopenharmony_ci ehdr->e_phentsize = sizeof(Elf64_Phdr); 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (!gelf_update_ehdr(to->elf, ehdr)) 15398c2ecf20Sopenharmony_ci return -1; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (!gelf_newphdr(to->elf, count)) 15428c2ecf20Sopenharmony_ci return -1; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci return 0; 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_cistatic int kcore__add_phdr(struct kcore *kcore, int idx, off_t offset, 15488c2ecf20Sopenharmony_ci u64 addr, u64 len) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci GElf_Phdr phdr = { 15518c2ecf20Sopenharmony_ci .p_type = PT_LOAD, 15528c2ecf20Sopenharmony_ci .p_flags = PF_R | PF_W | PF_X, 15538c2ecf20Sopenharmony_ci .p_offset = offset, 15548c2ecf20Sopenharmony_ci .p_vaddr = addr, 15558c2ecf20Sopenharmony_ci .p_paddr = 0, 15568c2ecf20Sopenharmony_ci .p_filesz = len, 15578c2ecf20Sopenharmony_ci .p_memsz = len, 15588c2ecf20Sopenharmony_ci .p_align = page_size, 15598c2ecf20Sopenharmony_ci }; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (!gelf_update_phdr(kcore->elf, idx, &phdr)) 15628c2ecf20Sopenharmony_ci return -1; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci return 0; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic off_t kcore__write(struct kcore *kcore) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci return elf_update(kcore->elf, ELF_C_WRITE); 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_cistruct phdr_data { 15738c2ecf20Sopenharmony_ci off_t offset; 15748c2ecf20Sopenharmony_ci off_t rel; 15758c2ecf20Sopenharmony_ci u64 addr; 15768c2ecf20Sopenharmony_ci u64 len; 15778c2ecf20Sopenharmony_ci struct list_head node; 15788c2ecf20Sopenharmony_ci struct phdr_data *remaps; 15798c2ecf20Sopenharmony_ci}; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistruct sym_data { 15828c2ecf20Sopenharmony_ci u64 addr; 15838c2ecf20Sopenharmony_ci struct list_head node; 15848c2ecf20Sopenharmony_ci}; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistruct kcore_copy_info { 15878c2ecf20Sopenharmony_ci u64 stext; 15888c2ecf20Sopenharmony_ci u64 etext; 15898c2ecf20Sopenharmony_ci u64 first_symbol; 15908c2ecf20Sopenharmony_ci u64 last_symbol; 15918c2ecf20Sopenharmony_ci u64 first_module; 15928c2ecf20Sopenharmony_ci u64 first_module_symbol; 15938c2ecf20Sopenharmony_ci u64 last_module_symbol; 15948c2ecf20Sopenharmony_ci size_t phnum; 15958c2ecf20Sopenharmony_ci struct list_head phdrs; 15968c2ecf20Sopenharmony_ci struct list_head syms; 15978c2ecf20Sopenharmony_ci}; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci#define kcore_copy__for_each_phdr(k, p) \ 16008c2ecf20Sopenharmony_ci list_for_each_entry((p), &(k)->phdrs, node) 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistatic struct phdr_data *phdr_data__new(u64 addr, u64 len, off_t offset) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci struct phdr_data *p = zalloc(sizeof(*p)); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (p) { 16078c2ecf20Sopenharmony_ci p->addr = addr; 16088c2ecf20Sopenharmony_ci p->len = len; 16098c2ecf20Sopenharmony_ci p->offset = offset; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci return p; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic struct phdr_data *kcore_copy_info__addnew(struct kcore_copy_info *kci, 16168c2ecf20Sopenharmony_ci u64 addr, u64 len, 16178c2ecf20Sopenharmony_ci off_t offset) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct phdr_data *p = phdr_data__new(addr, len, offset); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (p) 16228c2ecf20Sopenharmony_ci list_add_tail(&p->node, &kci->phdrs); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci return p; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_cistatic void kcore_copy__free_phdrs(struct kcore_copy_info *kci) 16288c2ecf20Sopenharmony_ci{ 16298c2ecf20Sopenharmony_ci struct phdr_data *p, *tmp; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, tmp, &kci->phdrs, node) { 16328c2ecf20Sopenharmony_ci list_del_init(&p->node); 16338c2ecf20Sopenharmony_ci free(p); 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistatic struct sym_data *kcore_copy__new_sym(struct kcore_copy_info *kci, 16388c2ecf20Sopenharmony_ci u64 addr) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci struct sym_data *s = zalloc(sizeof(*s)); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (s) { 16438c2ecf20Sopenharmony_ci s->addr = addr; 16448c2ecf20Sopenharmony_ci list_add_tail(&s->node, &kci->syms); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci return s; 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_cistatic void kcore_copy__free_syms(struct kcore_copy_info *kci) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci struct sym_data *s, *tmp; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci list_for_each_entry_safe(s, tmp, &kci->syms, node) { 16558c2ecf20Sopenharmony_ci list_del_init(&s->node); 16568c2ecf20Sopenharmony_ci free(s); 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_cistatic int kcore_copy__process_kallsyms(void *arg, const char *name, char type, 16618c2ecf20Sopenharmony_ci u64 start) 16628c2ecf20Sopenharmony_ci{ 16638c2ecf20Sopenharmony_ci struct kcore_copy_info *kci = arg; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (!kallsyms__is_function(type)) 16668c2ecf20Sopenharmony_ci return 0; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (strchr(name, '[')) { 16698c2ecf20Sopenharmony_ci if (!kci->first_module_symbol || start < kci->first_module_symbol) 16708c2ecf20Sopenharmony_ci kci->first_module_symbol = start; 16718c2ecf20Sopenharmony_ci if (start > kci->last_module_symbol) 16728c2ecf20Sopenharmony_ci kci->last_module_symbol = start; 16738c2ecf20Sopenharmony_ci return 0; 16748c2ecf20Sopenharmony_ci } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (!kci->first_symbol || start < kci->first_symbol) 16778c2ecf20Sopenharmony_ci kci->first_symbol = start; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (!kci->last_symbol || start > kci->last_symbol) 16808c2ecf20Sopenharmony_ci kci->last_symbol = start; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (!strcmp(name, "_stext")) { 16838c2ecf20Sopenharmony_ci kci->stext = start; 16848c2ecf20Sopenharmony_ci return 0; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (!strcmp(name, "_etext")) { 16888c2ecf20Sopenharmony_ci kci->etext = start; 16898c2ecf20Sopenharmony_ci return 0; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (is_entry_trampoline(name) && !kcore_copy__new_sym(kci, start)) 16938c2ecf20Sopenharmony_ci return -1; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci, 16998c2ecf20Sopenharmony_ci const char *dir) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci char kallsyms_filename[PATH_MAX]; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci scnprintf(kallsyms_filename, PATH_MAX, "%s/kallsyms", dir); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (symbol__restricted_filename(kallsyms_filename, "/proc/kallsyms")) 17068c2ecf20Sopenharmony_ci return -1; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (kallsyms__parse(kallsyms_filename, kci, 17098c2ecf20Sopenharmony_ci kcore_copy__process_kallsyms) < 0) 17108c2ecf20Sopenharmony_ci return -1; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci return 0; 17138c2ecf20Sopenharmony_ci} 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_cistatic int kcore_copy__process_modules(void *arg, 17168c2ecf20Sopenharmony_ci const char *name __maybe_unused, 17178c2ecf20Sopenharmony_ci u64 start, u64 size __maybe_unused) 17188c2ecf20Sopenharmony_ci{ 17198c2ecf20Sopenharmony_ci struct kcore_copy_info *kci = arg; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci if (!kci->first_module || start < kci->first_module) 17228c2ecf20Sopenharmony_ci kci->first_module = start; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci return 0; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic int kcore_copy__parse_modules(struct kcore_copy_info *kci, 17288c2ecf20Sopenharmony_ci const char *dir) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci char modules_filename[PATH_MAX]; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci scnprintf(modules_filename, PATH_MAX, "%s/modules", dir); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (symbol__restricted_filename(modules_filename, "/proc/modules")) 17358c2ecf20Sopenharmony_ci return -1; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci if (modules__parse(modules_filename, kci, 17388c2ecf20Sopenharmony_ci kcore_copy__process_modules) < 0) 17398c2ecf20Sopenharmony_ci return -1; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci return 0; 17428c2ecf20Sopenharmony_ci} 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic int kcore_copy__map(struct kcore_copy_info *kci, u64 start, u64 end, 17458c2ecf20Sopenharmony_ci u64 pgoff, u64 s, u64 e) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci u64 len, offset; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (s < start || s >= end) 17508c2ecf20Sopenharmony_ci return 0; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci offset = (s - start) + pgoff; 17538c2ecf20Sopenharmony_ci len = e < end ? e - s : end - s; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci return kcore_copy_info__addnew(kci, s, len, offset) ? 0 : -1; 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci struct kcore_copy_info *kci = data; 17618c2ecf20Sopenharmony_ci u64 end = start + len; 17628c2ecf20Sopenharmony_ci struct sym_data *sdat; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (kcore_copy__map(kci, start, end, pgoff, kci->stext, kci->etext)) 17658c2ecf20Sopenharmony_ci return -1; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci if (kcore_copy__map(kci, start, end, pgoff, kci->first_module, 17688c2ecf20Sopenharmony_ci kci->last_module_symbol)) 17698c2ecf20Sopenharmony_ci return -1; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci list_for_each_entry(sdat, &kci->syms, node) { 17728c2ecf20Sopenharmony_ci u64 s = round_down(sdat->addr, page_size); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci if (kcore_copy__map(kci, start, end, pgoff, s, s + len)) 17758c2ecf20Sopenharmony_ci return -1; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci return 0; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci if (elf_read_maps(elf, true, kcore_copy__read_map, kci) < 0) 17848c2ecf20Sopenharmony_ci return -1; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci return 0; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_cistatic void kcore_copy__find_remaps(struct kcore_copy_info *kci) 17908c2ecf20Sopenharmony_ci{ 17918c2ecf20Sopenharmony_ci struct phdr_data *p, *k = NULL; 17928c2ecf20Sopenharmony_ci u64 kend; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (!kci->stext) 17958c2ecf20Sopenharmony_ci return; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* Find phdr that corresponds to the kernel map (contains stext) */ 17988c2ecf20Sopenharmony_ci kcore_copy__for_each_phdr(kci, p) { 17998c2ecf20Sopenharmony_ci u64 pend = p->addr + p->len - 1; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (p->addr <= kci->stext && pend >= kci->stext) { 18028c2ecf20Sopenharmony_ci k = p; 18038c2ecf20Sopenharmony_ci break; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (!k) 18088c2ecf20Sopenharmony_ci return; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci kend = k->offset + k->len; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci /* Find phdrs that remap the kernel */ 18138c2ecf20Sopenharmony_ci kcore_copy__for_each_phdr(kci, p) { 18148c2ecf20Sopenharmony_ci u64 pend = p->offset + p->len; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (p == k) 18178c2ecf20Sopenharmony_ci continue; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci if (p->offset >= k->offset && pend <= kend) 18208c2ecf20Sopenharmony_ci p->remaps = k; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic void kcore_copy__layout(struct kcore_copy_info *kci) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci struct phdr_data *p; 18278c2ecf20Sopenharmony_ci off_t rel = 0; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci kcore_copy__find_remaps(kci); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci kcore_copy__for_each_phdr(kci, p) { 18328c2ecf20Sopenharmony_ci if (!p->remaps) { 18338c2ecf20Sopenharmony_ci p->rel = rel; 18348c2ecf20Sopenharmony_ci rel += p->len; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci kci->phnum += 1; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci kcore_copy__for_each_phdr(kci, p) { 18408c2ecf20Sopenharmony_ci struct phdr_data *k = p->remaps; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (k) 18438c2ecf20Sopenharmony_ci p->rel = p->offset - k->offset + k->rel; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci} 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_cistatic int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir, 18488c2ecf20Sopenharmony_ci Elf *elf) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci if (kcore_copy__parse_kallsyms(kci, dir)) 18518c2ecf20Sopenharmony_ci return -1; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci if (kcore_copy__parse_modules(kci, dir)) 18548c2ecf20Sopenharmony_ci return -1; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci if (kci->stext) 18578c2ecf20Sopenharmony_ci kci->stext = round_down(kci->stext, page_size); 18588c2ecf20Sopenharmony_ci else 18598c2ecf20Sopenharmony_ci kci->stext = round_down(kci->first_symbol, page_size); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (kci->etext) { 18628c2ecf20Sopenharmony_ci kci->etext = round_up(kci->etext, page_size); 18638c2ecf20Sopenharmony_ci } else if (kci->last_symbol) { 18648c2ecf20Sopenharmony_ci kci->etext = round_up(kci->last_symbol, page_size); 18658c2ecf20Sopenharmony_ci kci->etext += page_size; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (kci->first_module_symbol && 18698c2ecf20Sopenharmony_ci (!kci->first_module || kci->first_module_symbol < kci->first_module)) 18708c2ecf20Sopenharmony_ci kci->first_module = kci->first_module_symbol; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci kci->first_module = round_down(kci->first_module, page_size); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci if (kci->last_module_symbol) { 18758c2ecf20Sopenharmony_ci kci->last_module_symbol = round_up(kci->last_module_symbol, 18768c2ecf20Sopenharmony_ci page_size); 18778c2ecf20Sopenharmony_ci kci->last_module_symbol += page_size; 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (!kci->stext || !kci->etext) 18818c2ecf20Sopenharmony_ci return -1; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (kci->first_module && !kci->last_module_symbol) 18848c2ecf20Sopenharmony_ci return -1; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (kcore_copy__read_maps(kci, elf)) 18878c2ecf20Sopenharmony_ci return -1; 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci kcore_copy__layout(kci); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci return 0; 18928c2ecf20Sopenharmony_ci} 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_cistatic int kcore_copy__copy_file(const char *from_dir, const char *to_dir, 18958c2ecf20Sopenharmony_ci const char *name) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci char from_filename[PATH_MAX]; 18988c2ecf20Sopenharmony_ci char to_filename[PATH_MAX]; 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name); 19018c2ecf20Sopenharmony_ci scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name); 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci return copyfile_mode(from_filename, to_filename, 0400); 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_cistatic int kcore_copy__unlink(const char *dir, const char *name) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci char filename[PATH_MAX]; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci scnprintf(filename, PATH_MAX, "%s/%s", dir, name); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci return unlink(filename); 19138c2ecf20Sopenharmony_ci} 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_cistatic int kcore_copy__compare_fds(int from, int to) 19168c2ecf20Sopenharmony_ci{ 19178c2ecf20Sopenharmony_ci char *buf_from; 19188c2ecf20Sopenharmony_ci char *buf_to; 19198c2ecf20Sopenharmony_ci ssize_t ret; 19208c2ecf20Sopenharmony_ci size_t len; 19218c2ecf20Sopenharmony_ci int err = -1; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci buf_from = malloc(page_size); 19248c2ecf20Sopenharmony_ci buf_to = malloc(page_size); 19258c2ecf20Sopenharmony_ci if (!buf_from || !buf_to) 19268c2ecf20Sopenharmony_ci goto out; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci while (1) { 19298c2ecf20Sopenharmony_ci /* Use read because mmap won't work on proc files */ 19308c2ecf20Sopenharmony_ci ret = read(from, buf_from, page_size); 19318c2ecf20Sopenharmony_ci if (ret < 0) 19328c2ecf20Sopenharmony_ci goto out; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (!ret) 19358c2ecf20Sopenharmony_ci break; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci len = ret; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (readn(to, buf_to, len) != (int)len) 19408c2ecf20Sopenharmony_ci goto out; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci if (memcmp(buf_from, buf_to, len)) 19438c2ecf20Sopenharmony_ci goto out; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci err = 0; 19478c2ecf20Sopenharmony_ciout: 19488c2ecf20Sopenharmony_ci free(buf_to); 19498c2ecf20Sopenharmony_ci free(buf_from); 19508c2ecf20Sopenharmony_ci return err; 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic int kcore_copy__compare_files(const char *from_filename, 19548c2ecf20Sopenharmony_ci const char *to_filename) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci int from, to, err = -1; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci from = open(from_filename, O_RDONLY); 19598c2ecf20Sopenharmony_ci if (from < 0) 19608c2ecf20Sopenharmony_ci return -1; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci to = open(to_filename, O_RDONLY); 19638c2ecf20Sopenharmony_ci if (to < 0) 19648c2ecf20Sopenharmony_ci goto out_close_from; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci err = kcore_copy__compare_fds(from, to); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci close(to); 19698c2ecf20Sopenharmony_ciout_close_from: 19708c2ecf20Sopenharmony_ci close(from); 19718c2ecf20Sopenharmony_ci return err; 19728c2ecf20Sopenharmony_ci} 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_cistatic int kcore_copy__compare_file(const char *from_dir, const char *to_dir, 19758c2ecf20Sopenharmony_ci const char *name) 19768c2ecf20Sopenharmony_ci{ 19778c2ecf20Sopenharmony_ci char from_filename[PATH_MAX]; 19788c2ecf20Sopenharmony_ci char to_filename[PATH_MAX]; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name); 19818c2ecf20Sopenharmony_ci scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci return kcore_copy__compare_files(from_filename, to_filename); 19848c2ecf20Sopenharmony_ci} 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci/** 19878c2ecf20Sopenharmony_ci * kcore_copy - copy kallsyms, modules and kcore from one directory to another. 19888c2ecf20Sopenharmony_ci * @from_dir: from directory 19898c2ecf20Sopenharmony_ci * @to_dir: to directory 19908c2ecf20Sopenharmony_ci * 19918c2ecf20Sopenharmony_ci * This function copies kallsyms, modules and kcore files from one directory to 19928c2ecf20Sopenharmony_ci * another. kallsyms and modules are copied entirely. Only code segments are 19938c2ecf20Sopenharmony_ci * copied from kcore. It is assumed that two segments suffice: one for the 19948c2ecf20Sopenharmony_ci * kernel proper and one for all the modules. The code segments are determined 19958c2ecf20Sopenharmony_ci * from kallsyms and modules files. The kernel map starts at _stext or the 19968c2ecf20Sopenharmony_ci * lowest function symbol, and ends at _etext or the highest function symbol. 19978c2ecf20Sopenharmony_ci * The module map starts at the lowest module address and ends at the highest 19988c2ecf20Sopenharmony_ci * module symbol. Start addresses are rounded down to the nearest page. End 19998c2ecf20Sopenharmony_ci * addresses are rounded up to the nearest page. An extra page is added to the 20008c2ecf20Sopenharmony_ci * highest kernel symbol and highest module symbol to, hopefully, encompass that 20018c2ecf20Sopenharmony_ci * symbol too. Because it contains only code sections, the resulting kcore is 20028c2ecf20Sopenharmony_ci * unusual. One significant peculiarity is that the mapping (start -> pgoff) 20038c2ecf20Sopenharmony_ci * is not the same for the kernel map and the modules map. That happens because 20048c2ecf20Sopenharmony_ci * the data is copied adjacently whereas the original kcore has gaps. Finally, 20058c2ecf20Sopenharmony_ci * kallsyms file is compared with its copy to check that modules have not been 20068c2ecf20Sopenharmony_ci * loaded or unloaded while the copies were taking place. 20078c2ecf20Sopenharmony_ci * 20088c2ecf20Sopenharmony_ci * Return: %0 on success, %-1 on failure. 20098c2ecf20Sopenharmony_ci */ 20108c2ecf20Sopenharmony_ciint kcore_copy(const char *from_dir, const char *to_dir) 20118c2ecf20Sopenharmony_ci{ 20128c2ecf20Sopenharmony_ci struct kcore kcore; 20138c2ecf20Sopenharmony_ci struct kcore extract; 20148c2ecf20Sopenharmony_ci int idx = 0, err = -1; 20158c2ecf20Sopenharmony_ci off_t offset, sz; 20168c2ecf20Sopenharmony_ci struct kcore_copy_info kci = { .stext = 0, }; 20178c2ecf20Sopenharmony_ci char kcore_filename[PATH_MAX]; 20188c2ecf20Sopenharmony_ci char extract_filename[PATH_MAX]; 20198c2ecf20Sopenharmony_ci struct phdr_data *p; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&kci.phdrs); 20228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&kci.syms); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (kcore_copy__copy_file(from_dir, to_dir, "kallsyms")) 20258c2ecf20Sopenharmony_ci return -1; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (kcore_copy__copy_file(from_dir, to_dir, "modules")) 20288c2ecf20Sopenharmony_ci goto out_unlink_kallsyms; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci scnprintf(kcore_filename, PATH_MAX, "%s/kcore", from_dir); 20318c2ecf20Sopenharmony_ci scnprintf(extract_filename, PATH_MAX, "%s/kcore", to_dir); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if (kcore__open(&kcore, kcore_filename)) 20348c2ecf20Sopenharmony_ci goto out_unlink_modules; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (kcore_copy__calc_maps(&kci, from_dir, kcore.elf)) 20378c2ecf20Sopenharmony_ci goto out_kcore_close; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci if (kcore__init(&extract, extract_filename, kcore.elfclass, false)) 20408c2ecf20Sopenharmony_ci goto out_kcore_close; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci if (kcore__copy_hdr(&kcore, &extract, kci.phnum)) 20438c2ecf20Sopenharmony_ci goto out_extract_close; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci offset = gelf_fsize(extract.elf, ELF_T_EHDR, 1, EV_CURRENT) + 20468c2ecf20Sopenharmony_ci gelf_fsize(extract.elf, ELF_T_PHDR, kci.phnum, EV_CURRENT); 20478c2ecf20Sopenharmony_ci offset = round_up(offset, page_size); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci kcore_copy__for_each_phdr(&kci, p) { 20508c2ecf20Sopenharmony_ci off_t offs = p->rel + offset; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci if (kcore__add_phdr(&extract, idx++, offs, p->addr, p->len)) 20538c2ecf20Sopenharmony_ci goto out_extract_close; 20548c2ecf20Sopenharmony_ci } 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci sz = kcore__write(&extract); 20578c2ecf20Sopenharmony_ci if (sz < 0 || sz > offset) 20588c2ecf20Sopenharmony_ci goto out_extract_close; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci kcore_copy__for_each_phdr(&kci, p) { 20618c2ecf20Sopenharmony_ci off_t offs = p->rel + offset; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (p->remaps) 20648c2ecf20Sopenharmony_ci continue; 20658c2ecf20Sopenharmony_ci if (copy_bytes(kcore.fd, p->offset, extract.fd, offs, p->len)) 20668c2ecf20Sopenharmony_ci goto out_extract_close; 20678c2ecf20Sopenharmony_ci } 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci if (kcore_copy__compare_file(from_dir, to_dir, "kallsyms")) 20708c2ecf20Sopenharmony_ci goto out_extract_close; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci err = 0; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ciout_extract_close: 20758c2ecf20Sopenharmony_ci kcore__close(&extract); 20768c2ecf20Sopenharmony_ci if (err) 20778c2ecf20Sopenharmony_ci unlink(extract_filename); 20788c2ecf20Sopenharmony_ciout_kcore_close: 20798c2ecf20Sopenharmony_ci kcore__close(&kcore); 20808c2ecf20Sopenharmony_ciout_unlink_modules: 20818c2ecf20Sopenharmony_ci if (err) 20828c2ecf20Sopenharmony_ci kcore_copy__unlink(to_dir, "modules"); 20838c2ecf20Sopenharmony_ciout_unlink_kallsyms: 20848c2ecf20Sopenharmony_ci if (err) 20858c2ecf20Sopenharmony_ci kcore_copy__unlink(to_dir, "kallsyms"); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci kcore_copy__free_phdrs(&kci); 20888c2ecf20Sopenharmony_ci kcore_copy__free_syms(&kci); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci return err; 20918c2ecf20Sopenharmony_ci} 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ciint kcore_extract__create(struct kcore_extract *kce) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci struct kcore kcore; 20968c2ecf20Sopenharmony_ci struct kcore extract; 20978c2ecf20Sopenharmony_ci size_t count = 1; 20988c2ecf20Sopenharmony_ci int idx = 0, err = -1; 20998c2ecf20Sopenharmony_ci off_t offset = page_size, sz; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci if (kcore__open(&kcore, kce->kcore_filename)) 21028c2ecf20Sopenharmony_ci return -1; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci strcpy(kce->extract_filename, PERF_KCORE_EXTRACT); 21058c2ecf20Sopenharmony_ci if (kcore__init(&extract, kce->extract_filename, kcore.elfclass, true)) 21068c2ecf20Sopenharmony_ci goto out_kcore_close; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci if (kcore__copy_hdr(&kcore, &extract, count)) 21098c2ecf20Sopenharmony_ci goto out_extract_close; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (kcore__add_phdr(&extract, idx, offset, kce->addr, kce->len)) 21128c2ecf20Sopenharmony_ci goto out_extract_close; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci sz = kcore__write(&extract); 21158c2ecf20Sopenharmony_ci if (sz < 0 || sz > offset) 21168c2ecf20Sopenharmony_ci goto out_extract_close; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci if (copy_bytes(kcore.fd, kce->offs, extract.fd, offset, kce->len)) 21198c2ecf20Sopenharmony_ci goto out_extract_close; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci err = 0; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ciout_extract_close: 21248c2ecf20Sopenharmony_ci kcore__close(&extract); 21258c2ecf20Sopenharmony_ci if (err) 21268c2ecf20Sopenharmony_ci unlink(kce->extract_filename); 21278c2ecf20Sopenharmony_ciout_kcore_close: 21288c2ecf20Sopenharmony_ci kcore__close(&kcore); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci return err; 21318c2ecf20Sopenharmony_ci} 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_civoid kcore_extract__delete(struct kcore_extract *kce) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci unlink(kce->extract_filename); 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci#ifdef HAVE_GELF_GETNOTE_SUPPORT 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic void sdt_adjust_loc(struct sdt_note *tmp, GElf_Addr base_off) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci if (!base_off) 21438c2ecf20Sopenharmony_ci return; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci if (tmp->bit32) 21468c2ecf20Sopenharmony_ci tmp->addr.a32[SDT_NOTE_IDX_LOC] = 21478c2ecf20Sopenharmony_ci tmp->addr.a32[SDT_NOTE_IDX_LOC] + base_off - 21488c2ecf20Sopenharmony_ci tmp->addr.a32[SDT_NOTE_IDX_BASE]; 21498c2ecf20Sopenharmony_ci else 21508c2ecf20Sopenharmony_ci tmp->addr.a64[SDT_NOTE_IDX_LOC] = 21518c2ecf20Sopenharmony_ci tmp->addr.a64[SDT_NOTE_IDX_LOC] + base_off - 21528c2ecf20Sopenharmony_ci tmp->addr.a64[SDT_NOTE_IDX_BASE]; 21538c2ecf20Sopenharmony_ci} 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_cistatic void sdt_adjust_refctr(struct sdt_note *tmp, GElf_Addr base_addr, 21568c2ecf20Sopenharmony_ci GElf_Addr base_off) 21578c2ecf20Sopenharmony_ci{ 21588c2ecf20Sopenharmony_ci if (!base_off) 21598c2ecf20Sopenharmony_ci return; 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci if (tmp->bit32 && tmp->addr.a32[SDT_NOTE_IDX_REFCTR]) 21628c2ecf20Sopenharmony_ci tmp->addr.a32[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off); 21638c2ecf20Sopenharmony_ci else if (tmp->addr.a64[SDT_NOTE_IDX_REFCTR]) 21648c2ecf20Sopenharmony_ci tmp->addr.a64[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off); 21658c2ecf20Sopenharmony_ci} 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci/** 21688c2ecf20Sopenharmony_ci * populate_sdt_note : Parse raw data and identify SDT note 21698c2ecf20Sopenharmony_ci * @elf: elf of the opened file 21708c2ecf20Sopenharmony_ci * @data: raw data of a section with description offset applied 21718c2ecf20Sopenharmony_ci * @len: note description size 21728c2ecf20Sopenharmony_ci * @type: type of the note 21738c2ecf20Sopenharmony_ci * @sdt_notes: List to add the SDT note 21748c2ecf20Sopenharmony_ci * 21758c2ecf20Sopenharmony_ci * Responsible for parsing the @data in section .note.stapsdt in @elf and 21768c2ecf20Sopenharmony_ci * if its an SDT note, it appends to @sdt_notes list. 21778c2ecf20Sopenharmony_ci */ 21788c2ecf20Sopenharmony_cistatic int populate_sdt_note(Elf **elf, const char *data, size_t len, 21798c2ecf20Sopenharmony_ci struct list_head *sdt_notes) 21808c2ecf20Sopenharmony_ci{ 21818c2ecf20Sopenharmony_ci const char *provider, *name, *args; 21828c2ecf20Sopenharmony_ci struct sdt_note *tmp = NULL; 21838c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 21848c2ecf20Sopenharmony_ci GElf_Shdr shdr; 21858c2ecf20Sopenharmony_ci int ret = -EINVAL; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci union { 21888c2ecf20Sopenharmony_ci Elf64_Addr a64[NR_ADDR]; 21898c2ecf20Sopenharmony_ci Elf32_Addr a32[NR_ADDR]; 21908c2ecf20Sopenharmony_ci } buf; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci Elf_Data dst = { 21938c2ecf20Sopenharmony_ci .d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT, 21948c2ecf20Sopenharmony_ci .d_size = gelf_fsize((*elf), ELF_T_ADDR, NR_ADDR, EV_CURRENT), 21958c2ecf20Sopenharmony_ci .d_off = 0, .d_align = 0 21968c2ecf20Sopenharmony_ci }; 21978c2ecf20Sopenharmony_ci Elf_Data src = { 21988c2ecf20Sopenharmony_ci .d_buf = (void *) data, .d_type = ELF_T_ADDR, 21998c2ecf20Sopenharmony_ci .d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0, 22008c2ecf20Sopenharmony_ci .d_align = 0 22018c2ecf20Sopenharmony_ci }; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note)); 22048c2ecf20Sopenharmony_ci if (!tmp) { 22058c2ecf20Sopenharmony_ci ret = -ENOMEM; 22068c2ecf20Sopenharmony_ci goto out_err; 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp->note_list); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci if (len < dst.d_size + 3) 22128c2ecf20Sopenharmony_ci goto out_free_note; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci /* Translation from file representation to memory representation */ 22158c2ecf20Sopenharmony_ci if (gelf_xlatetom(*elf, &dst, &src, 22168c2ecf20Sopenharmony_ci elf_getident(*elf, NULL)[EI_DATA]) == NULL) { 22178c2ecf20Sopenharmony_ci pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1)); 22188c2ecf20Sopenharmony_ci goto out_free_note; 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci /* Populate the fields of sdt_note */ 22228c2ecf20Sopenharmony_ci provider = data + dst.d_size; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci name = (const char *)memchr(provider, '\0', data + len - provider); 22258c2ecf20Sopenharmony_ci if (name++ == NULL) 22268c2ecf20Sopenharmony_ci goto out_free_note; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci tmp->provider = strdup(provider); 22298c2ecf20Sopenharmony_ci if (!tmp->provider) { 22308c2ecf20Sopenharmony_ci ret = -ENOMEM; 22318c2ecf20Sopenharmony_ci goto out_free_note; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci tmp->name = strdup(name); 22348c2ecf20Sopenharmony_ci if (!tmp->name) { 22358c2ecf20Sopenharmony_ci ret = -ENOMEM; 22368c2ecf20Sopenharmony_ci goto out_free_prov; 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci args = memchr(name, '\0', data + len - name); 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci /* 22428c2ecf20Sopenharmony_ci * There is no argument if: 22438c2ecf20Sopenharmony_ci * - We reached the end of the note; 22448c2ecf20Sopenharmony_ci * - There is not enough room to hold a potential string; 22458c2ecf20Sopenharmony_ci * - The argument string is empty or just contains ':'. 22468c2ecf20Sopenharmony_ci */ 22478c2ecf20Sopenharmony_ci if (args == NULL || data + len - args < 2 || 22488c2ecf20Sopenharmony_ci args[1] == ':' || args[1] == '\0') 22498c2ecf20Sopenharmony_ci tmp->args = NULL; 22508c2ecf20Sopenharmony_ci else { 22518c2ecf20Sopenharmony_ci tmp->args = strdup(++args); 22528c2ecf20Sopenharmony_ci if (!tmp->args) { 22538c2ecf20Sopenharmony_ci ret = -ENOMEM; 22548c2ecf20Sopenharmony_ci goto out_free_name; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (gelf_getclass(*elf) == ELFCLASS32) { 22598c2ecf20Sopenharmony_ci memcpy(&tmp->addr, &buf, 3 * sizeof(Elf32_Addr)); 22608c2ecf20Sopenharmony_ci tmp->bit32 = true; 22618c2ecf20Sopenharmony_ci } else { 22628c2ecf20Sopenharmony_ci memcpy(&tmp->addr, &buf, 3 * sizeof(Elf64_Addr)); 22638c2ecf20Sopenharmony_ci tmp->bit32 = false; 22648c2ecf20Sopenharmony_ci } 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci if (!gelf_getehdr(*elf, &ehdr)) { 22678c2ecf20Sopenharmony_ci pr_debug("%s : cannot get elf header.\n", __func__); 22688c2ecf20Sopenharmony_ci ret = -EBADF; 22698c2ecf20Sopenharmony_ci goto out_free_args; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci /* Adjust the prelink effect : 22738c2ecf20Sopenharmony_ci * Find out the .stapsdt.base section. 22748c2ecf20Sopenharmony_ci * This scn will help us to handle prelinking (if present). 22758c2ecf20Sopenharmony_ci * Compare the retrieved file offset of the base section with the 22768c2ecf20Sopenharmony_ci * base address in the description of the SDT note. If its different, 22778c2ecf20Sopenharmony_ci * then accordingly, adjust the note location. 22788c2ecf20Sopenharmony_ci */ 22798c2ecf20Sopenharmony_ci if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) 22808c2ecf20Sopenharmony_ci sdt_adjust_loc(tmp, shdr.sh_offset); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci /* Adjust reference counter offset */ 22838c2ecf20Sopenharmony_ci if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_PROBES_SCN, NULL)) 22848c2ecf20Sopenharmony_ci sdt_adjust_refctr(tmp, shdr.sh_addr, shdr.sh_offset); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci list_add_tail(&tmp->note_list, sdt_notes); 22878c2ecf20Sopenharmony_ci return 0; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ciout_free_args: 22908c2ecf20Sopenharmony_ci zfree(&tmp->args); 22918c2ecf20Sopenharmony_ciout_free_name: 22928c2ecf20Sopenharmony_ci zfree(&tmp->name); 22938c2ecf20Sopenharmony_ciout_free_prov: 22948c2ecf20Sopenharmony_ci zfree(&tmp->provider); 22958c2ecf20Sopenharmony_ciout_free_note: 22968c2ecf20Sopenharmony_ci free(tmp); 22978c2ecf20Sopenharmony_ciout_err: 22988c2ecf20Sopenharmony_ci return ret; 22998c2ecf20Sopenharmony_ci} 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci/** 23028c2ecf20Sopenharmony_ci * construct_sdt_notes_list : constructs a list of SDT notes 23038c2ecf20Sopenharmony_ci * @elf : elf to look into 23048c2ecf20Sopenharmony_ci * @sdt_notes : empty list_head 23058c2ecf20Sopenharmony_ci * 23068c2ecf20Sopenharmony_ci * Scans the sections in 'elf' for the section 23078c2ecf20Sopenharmony_ci * .note.stapsdt. It, then calls populate_sdt_note to find 23088c2ecf20Sopenharmony_ci * out the SDT events and populates the 'sdt_notes'. 23098c2ecf20Sopenharmony_ci */ 23108c2ecf20Sopenharmony_cistatic int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes) 23118c2ecf20Sopenharmony_ci{ 23128c2ecf20Sopenharmony_ci GElf_Ehdr ehdr; 23138c2ecf20Sopenharmony_ci Elf_Scn *scn = NULL; 23148c2ecf20Sopenharmony_ci Elf_Data *data; 23158c2ecf20Sopenharmony_ci GElf_Shdr shdr; 23168c2ecf20Sopenharmony_ci size_t shstrndx, next; 23178c2ecf20Sopenharmony_ci GElf_Nhdr nhdr; 23188c2ecf20Sopenharmony_ci size_t name_off, desc_off, offset; 23198c2ecf20Sopenharmony_ci int ret = 0; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (gelf_getehdr(elf, &ehdr) == NULL) { 23228c2ecf20Sopenharmony_ci ret = -EBADF; 23238c2ecf20Sopenharmony_ci goto out_ret; 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci if (elf_getshdrstrndx(elf, &shstrndx) != 0) { 23268c2ecf20Sopenharmony_ci ret = -EBADF; 23278c2ecf20Sopenharmony_ci goto out_ret; 23288c2ecf20Sopenharmony_ci } 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci /* Look for the required section */ 23318c2ecf20Sopenharmony_ci scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL); 23328c2ecf20Sopenharmony_ci if (!scn) { 23338c2ecf20Sopenharmony_ci ret = -ENOENT; 23348c2ecf20Sopenharmony_ci goto out_ret; 23358c2ecf20Sopenharmony_ci } 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) { 23388c2ecf20Sopenharmony_ci ret = -ENOENT; 23398c2ecf20Sopenharmony_ci goto out_ret; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci data = elf_getdata(scn, NULL); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* Get the SDT notes */ 23458c2ecf20Sopenharmony_ci for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off, 23468c2ecf20Sopenharmony_ci &desc_off)) > 0; offset = next) { 23478c2ecf20Sopenharmony_ci if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) && 23488c2ecf20Sopenharmony_ci !memcmp(data->d_buf + name_off, SDT_NOTE_NAME, 23498c2ecf20Sopenharmony_ci sizeof(SDT_NOTE_NAME))) { 23508c2ecf20Sopenharmony_ci /* Check the type of the note */ 23518c2ecf20Sopenharmony_ci if (nhdr.n_type != SDT_NOTE_TYPE) 23528c2ecf20Sopenharmony_ci goto out_ret; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci ret = populate_sdt_note(&elf, ((data->d_buf) + desc_off), 23558c2ecf20Sopenharmony_ci nhdr.n_descsz, sdt_notes); 23568c2ecf20Sopenharmony_ci if (ret < 0) 23578c2ecf20Sopenharmony_ci goto out_ret; 23588c2ecf20Sopenharmony_ci } 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci if (list_empty(sdt_notes)) 23618c2ecf20Sopenharmony_ci ret = -ENOENT; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ciout_ret: 23648c2ecf20Sopenharmony_ci return ret; 23658c2ecf20Sopenharmony_ci} 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci/** 23688c2ecf20Sopenharmony_ci * get_sdt_note_list : Wrapper to construct a list of sdt notes 23698c2ecf20Sopenharmony_ci * @head : empty list_head 23708c2ecf20Sopenharmony_ci * @target : file to find SDT notes from 23718c2ecf20Sopenharmony_ci * 23728c2ecf20Sopenharmony_ci * This opens the file, initializes 23738c2ecf20Sopenharmony_ci * the ELF and then calls construct_sdt_notes_list. 23748c2ecf20Sopenharmony_ci */ 23758c2ecf20Sopenharmony_ciint get_sdt_note_list(struct list_head *head, const char *target) 23768c2ecf20Sopenharmony_ci{ 23778c2ecf20Sopenharmony_ci Elf *elf; 23788c2ecf20Sopenharmony_ci int fd, ret; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci fd = open(target, O_RDONLY); 23818c2ecf20Sopenharmony_ci if (fd < 0) 23828c2ecf20Sopenharmony_ci return -EBADF; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 23858c2ecf20Sopenharmony_ci if (!elf) { 23868c2ecf20Sopenharmony_ci ret = -EBADF; 23878c2ecf20Sopenharmony_ci goto out_close; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci ret = construct_sdt_notes_list(elf, head); 23908c2ecf20Sopenharmony_ci elf_end(elf); 23918c2ecf20Sopenharmony_ciout_close: 23928c2ecf20Sopenharmony_ci close(fd); 23938c2ecf20Sopenharmony_ci return ret; 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci/** 23978c2ecf20Sopenharmony_ci * cleanup_sdt_note_list : free the sdt notes' list 23988c2ecf20Sopenharmony_ci * @sdt_notes: sdt notes' list 23998c2ecf20Sopenharmony_ci * 24008c2ecf20Sopenharmony_ci * Free up the SDT notes in @sdt_notes. 24018c2ecf20Sopenharmony_ci * Returns the number of SDT notes free'd. 24028c2ecf20Sopenharmony_ci */ 24038c2ecf20Sopenharmony_ciint cleanup_sdt_note_list(struct list_head *sdt_notes) 24048c2ecf20Sopenharmony_ci{ 24058c2ecf20Sopenharmony_ci struct sdt_note *tmp, *pos; 24068c2ecf20Sopenharmony_ci int nr_free = 0; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, tmp, sdt_notes, note_list) { 24098c2ecf20Sopenharmony_ci list_del_init(&pos->note_list); 24108c2ecf20Sopenharmony_ci zfree(&pos->args); 24118c2ecf20Sopenharmony_ci zfree(&pos->name); 24128c2ecf20Sopenharmony_ci zfree(&pos->provider); 24138c2ecf20Sopenharmony_ci free(pos); 24148c2ecf20Sopenharmony_ci nr_free++; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci return nr_free; 24178c2ecf20Sopenharmony_ci} 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci/** 24208c2ecf20Sopenharmony_ci * sdt_notes__get_count: Counts the number of sdt events 24218c2ecf20Sopenharmony_ci * @start: list_head to sdt_notes list 24228c2ecf20Sopenharmony_ci * 24238c2ecf20Sopenharmony_ci * Returns the number of SDT notes in a list 24248c2ecf20Sopenharmony_ci */ 24258c2ecf20Sopenharmony_ciint sdt_notes__get_count(struct list_head *start) 24268c2ecf20Sopenharmony_ci{ 24278c2ecf20Sopenharmony_ci struct sdt_note *sdt_ptr; 24288c2ecf20Sopenharmony_ci int count = 0; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci list_for_each_entry(sdt_ptr, start, note_list) 24318c2ecf20Sopenharmony_ci count++; 24328c2ecf20Sopenharmony_ci return count; 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci#endif 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_civoid symbol__elf_init(void) 24378c2ecf20Sopenharmony_ci{ 24388c2ecf20Sopenharmony_ci elf_version(EV_CURRENT); 24398c2ecf20Sopenharmony_ci} 2440