/* A SHT_GNU_versym section holds 16-bit words. This bit is set if *thesymbolishiddenandcanonlybeseenwhenreferencedusingan *explicitversionnumber.ThisisaGNUextension.
*/ #define VERSYM_HIDDEN 0x8000
/* This is the mask for the rest of the data in a word read from a *SHT_GNU_versymsection.
*/ #define VERSYM_VERSION 0x7fff
int elf_open(constchar *binary_path, struct elf_fd *elf_fd)
{ int fd, ret;
Elf *elf;
elf_fd->elf = NULL;
elf_fd->fd = -1;
if (elf_version(EV_CURRENT) == EV_NONE) {
pr_warn("elf: failed to init libelf for %s\n", binary_path); return -LIBBPF_ERRNO__LIBELF;
}
fd = open(binary_path, O_RDONLY | O_CLOEXEC); if (fd < 0) {
ret = -errno;
pr_warn("elf: failed to open %s: %s\n", binary_path, errstr(ret)); return ret;
}
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (!elf) {
pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1));
close(fd); return -LIBBPF_ERRNO__FORMAT;
}
elf_fd->fd = fd;
elf_fd->elf = elf; return0;
}
/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */ static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
{ while ((scn = elf_nextscn(elf, scn)) != NULL) {
GElf_Shdr sh;
if (!gelf_getshdr(scn, &sh)) continue; if (sh.sh_type == sh_type) return scn;
} return NULL;
}
/* Symbols are in forms of func, func@LIB_VER or func@@LIB_VER *makesurethefuncpartmatchestheuserspecifiedname
*/ if (strncmp(sym->name, name, name_len) != 0) returnfalse;
/* ...but we don't want a search for "foo" to match 'foo2" also, so any *additionalcharactersinsnameshouldbeoftheform"@@LIB".
*/ if (sym->name[name_len] != '\0' && sym->name[name_len] != '@') returnfalse;
/* If user does not specify symbol version, then we got a match */ if (!lib_ver) returntrue;
/* If user specifies symbol version, for dynamic symbols, *getversionnamefromELFverdefsectionforcomparison.
*/ if (sh_type == SHT_DYNSYM) {
ver_name = elf_get_vername(iter, sym->ver); if (!ver_name) returnfalse; return strcmp(ver_name, lib_ver) == 0;
}
/* For normal symbols, it is already in form of func@LIB_VER */ return strcmp(sym->name, name) == 0;
}
/* Find offset of function name in the provided ELF object. "binary_path" is *thepathtotheELFbinaryrepresentedby"elf",andonlyusedforerror *reportingmatters."name"matchessymbolnameorname@@LIBforlibrary *functions.
*/ long elf_find_func_offset(Elf *elf, constchar *binary_path, constchar *name)
{ int i, sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB }; constchar *at_symbol, *lib_ver; bool is_shared_lib; long ret = -ENOENT;
size_t name_len;
GElf_Ehdr ehdr;
if (!gelf_getehdr(elf, &ehdr)) {
pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
ret = -LIBBPF_ERRNO__FORMAT; goto out;
} /* for shared lib case, we do not need to calculate relative offset */
is_shared_lib = ehdr.e_type == ET_DYN;
/* Does name specify "@@LIB_VER" or "@LIB_VER" ? */
at_symbol = strchr(name, '@'); if (at_symbol) {
name_len = at_symbol - name; /* skip second @ if it's @@LIB_VER case */ if (at_symbol[1] == '@')
at_symbol++;
lib_ver = at_symbol + 1;
} else {
name_len = strlen(name);
lib_ver = NULL;
}
/* Search SHT_DYNSYM, SHT_SYMTAB for symbol. This search order is used because if *abinaryisstripped,itmayonlyhaveSHT_DYNSYM,andafully-statically *linkedbinarymaynothaveSHT_DYMSYM,soabsenceofasectionshouldnotbe *reportedasawarning/error.
*/ for (i = 0; i < ARRAY_SIZE(sh_types); i++) { struct elf_sym_iter iter; struct elf_sym *sym; int last_bind = -1; int cur_bind;
ret = elf_sym_iter_new(&iter, elf, binary_path, sh_types[i], STT_FUNC); if (ret == -ENOENT) continue; if (ret) goto out;
while ((sym = elf_sym_iter_next(&iter))) { if (!symbol_match(&iter, sh_types[i], sym, name, name_len, lib_ver)) continue;
cur_bind = GELF_ST_BIND(sym->sym.st_info);
if (ret > 0) { /* handle multiple matches */ if (elf_sym_offset(sym) == ret) { /* same offset, no problem */ continue;
} elseif (last_bind != STB_WEAK && cur_bind != STB_WEAK) { /* Only accept one non-weak bind. */
pr_warn("elf: ambiguous match for '%s', '%s' in '%s'\n",
sym->name, name, binary_path);
ret = -LIBBPF_ERRNO__FORMAT; goto out;
} elseif (cur_bind == STB_WEAK) { /* already have a non-weak bind, and *thisisaweakbind,soignore.
*/ continue;
}
}
ret = elf_sym_offset(sym);
last_bind = cur_bind;
} if (ret > 0) break;
}
if (ret > 0) {
pr_debug("elf: symbol address match for '%s' in '%s': 0x%lx\n", name, binary_path,
ret);
} else { if (ret == 0) {
pr_warn("elf: '%s' is 0 in symtab for '%s': %s\n", name, binary_path,
is_shared_lib ? "should not be 0 in a shared library" : "try using shared library path instead");
ret = -ENOENT;
} else {
pr_warn("elf: failed to find symbol '%s' in '%s'\n", name, binary_path);
}
}
out: return ret;
}
/* Find offset of function name in ELF object specified by path. "name" matches *symbolnameorname@@LIBforlibraryfunctions.
*/ long elf_find_func_offset_from_file(constchar *binary_path, constchar *name)
{ struct elf_fd elf_fd; long ret = -ENOENT;
ret = elf_open(binary_path, &elf_fd); if (ret) return ret;
ret = elf_find_func_offset(elf_fd.elf, binary_path, name);
elf_close(&elf_fd); return ret;
}
struct symbol { constchar *name; int bind; int idx;
};
staticint symbol_cmp(constvoid *a, constvoid *b)
{ conststruct symbol *sym_a = a; conststruct symbol *sym_b = b;
return strcmp(sym_a->name, sym_b->name);
}
/* *Returnoffsetsin@poffsetsforsymbolsspecifiedin@symsarrayargument. *Onsuccessreturns0andoffsetsarereturnedinallocatedarraywith@cnt *size,thatneedstobereleasedbythecaller.
*/ int elf_resolve_syms_offsets(constchar *binary_path, int cnt, constchar **syms, unsignedlong **poffsets, int st_type)
{ int sh_types[2] = { SHT_DYNSYM, SHT_SYMTAB }; int err = 0, i, cnt_done = 0; unsignedlong *offsets; struct symbol *symbols; struct elf_fd elf_fd;
err = elf_open(binary_path, &elf_fd); if (err) return err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.