// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* * resolve_btfids scans ELF object for .BTF_ids section and resolves * its symbols with BTF ID values. * * Each symbol points to 4 bytes data and is expected to have * following name syntax: * * __BTF_ID__<type>__<symbol>[__<id>] * * type is: * * func - lookup BTF_KIND_FUNC symbol with <symbol> name * and store its ID into the data: * * __BTF_ID__func__vfs_close__1: * .zero 4 * * struct - lookup BTF_KIND_STRUCT symbol with <symbol> name * and store its ID into the data: * * __BTF_ID__struct__sk_buff__1: * .zero 4 * * union - lookup BTF_KIND_UNION symbol with <symbol> name * and store its ID into the data: * * __BTF_ID__union__thread_union__1: * .zero 4 * * typedef - lookup BTF_KIND_TYPEDEF symbol with <symbol> name * and store its ID into the data: * * __BTF_ID__typedef__pid_t__1: * .zero 4 * * set - store symbol size into first 4 bytes and sort following * ID list * * __BTF_ID__set__list: * .zero 4 * list: * __BTF_ID__func__vfs_getattr__3: * .zero 4 * __BTF_ID__func__vfs_fallocate__4: * .zero 4 * * set8 - store symbol size into first 4 bytes and sort following * ID list * * __BTF_ID__set8__list: * .zero 8 * list: * __BTF_ID__func__vfs_getattr__3: * .zero 4 * .word (1 << 0) | (1 << 2) * __BTF_ID__func__vfs_fallocate__5: * .zero 4 * .word (1 << 3) | (1 << 1) | (1 << 2)
*/
id = get_id(name + size); if (!id) {
pr_err("FAILED to parse symbol name: %s\n", name); return NULL;
}
return btf_id__add(root, id, false);
}
/* Older libelf.h and glibc elf.h might not yet define the ELF compression types. */ #ifndef SHF_COMPRESSED #define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ #endif
/* * The data of compressed section should be aligned to 4 * (for 32bit) or 8 (for 64 bit) bytes. The binutils ld * sets sh_addralign to 1, which makes libelf fail with * misaligned section error during the update: * FAILED elf_update(WRITE): invalid section alignment * * While waiting for ld fix, we fix the compressed sections * sh_addralign value manualy.
*/ staticint compressed_section_fix(Elf *elf, Elf_Scn *scn, GElf_Shdr *sh)
{ int expected = gelf_getclass(elf) == ELFCLASS32 ? 4 : 8;
if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) {
pr_err("FAILED cannot get shdr str ndx\n"); return -1;
}
if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) {
pr_err("FAILED cannot get ELF header: %s\n",
elf_errmsg(-1)); return -1;
}
obj->efile.encoding = ehdr.e_ident[EI_DATA];
/* * Scan all the elf sections and look for save data * from .BTF_ids section and symbols.
*/ while ((scn = elf_nextscn(elf, scn)) != NULL) {
Elf_Data *data;
GElf_Shdr sh; char *name;
idx++; if (gelf_getshdr(scn, &sh) != &sh) {
pr_err("FAILED get section(%d) header\n", idx); return -1;
}
name = elf_strptr(elf, shdrstrndx, sh.sh_name); if (!name) {
pr_err("FAILED get section(%d) name\n", idx); return -1;
}
data = elf_getdata(scn, 0); if (!data) {
pr_err("FAILED to get section(%d) data from %s\n",
idx, name); return -1;
}
if (sh.sh_type == SHT_SYMTAB) {
obj->efile.symbols = data;
obj->efile.symbols_shndx = idx;
obj->efile.strtabidx = sh.sh_link;
} elseif (!strcmp(name, BTF_IDS_SECTION)) {
obj->efile.idlist = data;
obj->efile.idlist_shndx = idx;
obj->efile.idlist_addr = sh.sh_addr;
} elseif (!strcmp(name, BTF_BASE_ELF_SEC)) { /* If a .BTF.base section is found, do not resolve * BTF ids relative to vmlinux; resolve relative * to the .BTF.base section instead. btf__parse_split() * will take care of this once the base BTF it is * passed is NULL.
*/
obj->base_btf_path = NULL;
}
if (compressed_section_fix(elf, scn, &sh)) return -1;
}
return 0;
}
staticint symbols_collect(struct object *obj)
{
Elf_Scn *scn = NULL; int n, i;
GElf_Shdr sh; char *name;
scn = elf_getscn(obj->efile.elf, obj->efile.symbols_shndx); if (!scn) return -1;
if (gelf_getshdr(scn, &sh) != &sh) return -1;
n = sh.sh_size / sh.sh_entsize;
/* * Scan symbols and look for the ones starting with * __BTF_ID__* over .BTF_ids section.
*/ for (i = 0; i < n; i++) { char *prefix; struct btf_id *id;
GElf_Sym sym;
if (!gelf_getsym(obj->efile.symbols, i, &sym)) return -1;
if (sym.st_shndx != obj->efile.idlist_shndx) continue;
name = elf_strptr(obj->efile.elf, obj->efile.strtabidx,
sym.st_name);
/* struct */ if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) {
obj->nr_structs++;
id = add_symbol(&obj->structs, prefix, sizeof(BTF_STRUCT) - 1); /* union */
} elseif (!strncmp(prefix, BTF_UNION, sizeof(BTF_UNION) - 1)) {
obj->nr_unions++;
id = add_symbol(&obj->unions, prefix, sizeof(BTF_UNION) - 1); /* typedef */
} elseif (!strncmp(prefix, BTF_TYPEDEF, sizeof(BTF_TYPEDEF) - 1)) {
obj->nr_typedefs++;
id = add_symbol(&obj->typedefs, prefix, sizeof(BTF_TYPEDEF) - 1); /* func */
} elseif (!strncmp(prefix, BTF_FUNC, sizeof(BTF_FUNC) - 1)) {
obj->nr_funcs++;
id = add_symbol(&obj->funcs, prefix, sizeof(BTF_FUNC) - 1); /* set8 */
} elseif (!strncmp(prefix, BTF_SET8, sizeof(BTF_SET8) - 1)) {
id = add_set(obj, prefix, true); /* * SET8 objects store list's count, which is encoded * in symbol's size, together with 'cnt' field hence * that - 1.
*/ if (id) {
id->cnt = sym.st_size / sizeof(uint64_t) - 1;
id->is_set8 = true;
} /* set */
} elseif (!strncmp(prefix, BTF_SET, sizeof(BTF_SET) - 1)) {
id = add_set(obj, prefix, false); /* * SET objects store list's count, which is encoded * in symbol's size, together with 'cnt' field hence * that - 1.
*/ if (id) {
id->cnt = sym.st_size / sizeof(int) - 1;
id->is_set = true;
}
} else {
pr_err("FAILED unsupported prefix %s\n", prefix); return -1;
}
if (!id) return -ENOMEM;
if (id->addr_cnt >= ADDR_CNT) {
pr_err("FAILED symbol %s crossed the number of allowed lists\n",
id->name); return -1;
}
id->addr[id->addr_cnt++] = sym.st_value;
}
return 0;
}
staticint symbols_resolve(struct object *obj)
{ int nr_typedefs = obj->nr_typedefs; int nr_structs = obj->nr_structs; int nr_unions = obj->nr_unions; int nr_funcs = obj->nr_funcs; struct btf *base_btf = NULL; int err, type_id; struct btf *btf;
__u32 nr_types;
if (obj->base_btf_path) {
base_btf = btf__parse(obj->base_btf_path, NULL);
err = libbpf_get_error(base_btf); if (err) {
pr_err("FAILED: load base BTF from %s: %s\n",
obj->base_btf_path, strerror(-err)); return -1;
}
}
staticint id_patch(struct object *obj, struct btf_id *id)
{
Elf_Data *data = obj->efile.idlist; int *ptr = data->d_buf; int i;
/* For set, set8, id->id may be 0 */ if (!id->id && !id->is_set && !id->is_set8) {
pr_err("WARN: resolve_btfids: unresolved symbol %s\n", id->name);
warnings++;
}
for (i = 0; i < id->addr_cnt; i++) { unsignedlong addr = id->addr[i]; unsignedlong idx = addr - obj->efile.idlist_addr;
pr_debug("patching addr %5lu: ID %7d [%s]\n",
idx, id->id, id->name);
if (idx >= data->d_size) {
pr_err("FAILED patching index %lu out of bounds %lu\n",
idx, data->d_size); return -1;
}
id = rb_entry(next, struct btf_id, rb_node);
addr = id->addr[0];
off = addr - obj->efile.idlist_addr;
/* sets are unique */ if (id->addr_cnt != 1) {
pr_err("FAILED malformed data for set '%s'\n",
id->name); return -1;
}
if (id->is_set) {
set = data->d_buf + off;
qsort(set->ids, set->cnt, sizeof(set->ids[0]), cmp_id);
} else {
set8 = data->d_buf + off; /* * Make sure id is at the beginning of the pairs * struct, otherwise the below qsort would not work.
*/
BUILD_BUG_ON((u32 *)set8->pairs != &set8->pairs[0].id);
qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id);
/* * When ELF endianness does not match endianness of the * host, libelf will do the translation when updating * the ELF. This, however, corrupts SET8 flags which are * already in the target endianness. So, let's bswap * them to the host endianness and libelf will then * correctly translate everything.
*/ if (obj->efile.encoding != ELFDATANATIVE) { int i;
set8->flags = bswap_32(set8->flags); for (i = 0; i < set8->cnt; i++) {
set8->pairs[i].flags =
bswap_32(set8->pairs[i].flags);
}
}
}
/* * We did not find .BTF_ids section or symbols section, * nothing to do..
*/ if (obj.efile.idlist_shndx == -1 ||
obj.efile.symbols_shndx == -1) {
pr_debug("Cannot find .BTF_ids or symbols sections, nothing to do\n");
err = 0; goto out;
}
if (symbols_collect(&obj)) goto out;
if (symbols_resolve(&obj)) goto out;
if (symbols_patch(&obj)) goto out;
if (!(fatal_warnings && warnings))
err = 0;
out: if (obj.efile.elf) {
elf_end(obj.efile.elf);
close(obj.efile.fd);
} return err;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
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.