selftests/bpf: Add read_build_id function
Adding read_build_id function that parses out build id from specified binary. It will replace extract_build_id and also be used in following changes. Signed-off-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/r/20230331093157.1749137-3-jolsa@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Родитель
328bafc9a3
Коммит
88dc8b3605
|
@ -11,6 +11,9 @@
|
|||
#include <linux/perf_event.h>
|
||||
#include <sys/mman.h>
|
||||
#include "trace_helpers.h"
|
||||
#include <linux/limits.h>
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
|
||||
#define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe"
|
||||
#define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe"
|
||||
|
@ -234,3 +237,82 @@ ssize_t get_rel_offset(uintptr_t addr)
|
|||
fclose(f);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_build_id_buf(const void *note_start, Elf32_Word note_size, char *build_id)
|
||||
{
|
||||
Elf32_Word note_offs = 0;
|
||||
|
||||
while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
|
||||
Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
|
||||
|
||||
if (nhdr->n_type == 3 && nhdr->n_namesz == sizeof("GNU") &&
|
||||
!strcmp((char *)(nhdr + 1), "GNU") && nhdr->n_descsz > 0 &&
|
||||
nhdr->n_descsz <= BPF_BUILD_ID_SIZE) {
|
||||
memcpy(build_id, note_start + note_offs +
|
||||
ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), nhdr->n_descsz);
|
||||
memset(build_id + nhdr->n_descsz, 0, BPF_BUILD_ID_SIZE - nhdr->n_descsz);
|
||||
return (int) nhdr->n_descsz;
|
||||
}
|
||||
|
||||
note_offs = note_offs + sizeof(Elf32_Nhdr) +
|
||||
ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Reads binary from *path* file and returns it in the *build_id* buffer
|
||||
* with *size* which is expected to be at least BPF_BUILD_ID_SIZE bytes.
|
||||
* Returns size of build id on success. On error the error value is
|
||||
* returned.
|
||||
*/
|
||||
int read_build_id(const char *path, char *build_id, size_t size)
|
||||
{
|
||||
int fd, err = -EINVAL;
|
||||
Elf *elf = NULL;
|
||||
GElf_Ehdr ehdr;
|
||||
size_t max, i;
|
||||
|
||||
if (size < BPF_BUILD_ID_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
(void)elf_version(EV_CURRENT);
|
||||
|
||||
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
||||
if (!elf)
|
||||
goto out;
|
||||
if (elf_kind(elf) != ELF_K_ELF)
|
||||
goto out;
|
||||
if (!gelf_getehdr(elf, &ehdr))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < ehdr.e_phnum; i++) {
|
||||
GElf_Phdr mem, *phdr;
|
||||
char *data;
|
||||
|
||||
phdr = gelf_getphdr(elf, i, &mem);
|
||||
if (!phdr)
|
||||
goto out;
|
||||
if (phdr->p_type != PT_NOTE)
|
||||
continue;
|
||||
data = elf_rawfile(elf, &max);
|
||||
if (!data)
|
||||
goto out;
|
||||
if (phdr->p_offset + phdr->p_memsz > max)
|
||||
goto out;
|
||||
err = parse_build_id_buf(data + phdr->p_offset, phdr->p_memsz, build_id);
|
||||
if (err > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (elf)
|
||||
elf_end(elf);
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include <bpf/libbpf.h>
|
||||
|
||||
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
|
||||
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
|
||||
|
||||
struct ksym {
|
||||
long addr;
|
||||
char *name;
|
||||
|
@ -23,4 +26,6 @@ void read_trace_pipe(void);
|
|||
ssize_t get_uprobe_offset(const void *addr);
|
||||
ssize_t get_rel_offset(uintptr_t addr);
|
||||
|
||||
int read_build_id(const char *path, char *build_id, size_t size);
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче