Skip to content

Commit fe92833

Browse files
anakryikoborkmann
authored andcommitted
libbpf: Fix uprobe symbol file offset calculation logic
Fix libbpf's bpf_program__attach_uprobe() logic of determining function's *file offset* (which is what kernel is actually expecting) when attaching uprobe/uretprobe by function name. Previously calculation was determining virtual address offset relative to base load address, which (offset) is not always the same as file offset (though very frequently it is which is why this went unnoticed for a while). Fixes: 433966e ("libbpf: Support function name-based attach uprobes") Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Cc: Riham Selim <rihams@fb.com> Cc: Alan Maguire <alan.maguire@oracle.com> Link: https://lore.kernel.org/bpf/20220606220143.3796908-1-andrii@kernel.org
1 parent 492f99e commit fe92833

File tree

1 file changed

+22
-41
lines changed

1 file changed

+22
-41
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11192,43 +11192,6 @@ static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe,
1119211192
return pfd;
1119311193
}
1119411194

11195-
/* uprobes deal in relative offsets; subtract the base address associated with
11196-
* the mapped binary. See Documentation/trace/uprobetracer.rst for more
11197-
* details.
11198-
*/
11199-
static long elf_find_relative_offset(const char *filename, Elf *elf, long addr)
11200-
{
11201-
size_t n;
11202-
int i;
11203-
11204-
if (elf_getphdrnum(elf, &n)) {
11205-
pr_warn("elf: failed to find program headers for '%s': %s\n", filename,
11206-
elf_errmsg(-1));
11207-
return -ENOENT;
11208-
}
11209-
11210-
for (i = 0; i < n; i++) {
11211-
int seg_start, seg_end, seg_offset;
11212-
GElf_Phdr phdr;
11213-
11214-
if (!gelf_getphdr(elf, i, &phdr)) {
11215-
pr_warn("elf: failed to get program header %d from '%s': %s\n", i, filename,
11216-
elf_errmsg(-1));
11217-
return -ENOENT;
11218-
}
11219-
if (phdr.p_type != PT_LOAD || !(phdr.p_flags & PF_X))
11220-
continue;
11221-
11222-
seg_start = phdr.p_vaddr;
11223-
seg_end = seg_start + phdr.p_memsz;
11224-
seg_offset = phdr.p_offset;
11225-
if (addr >= seg_start && addr < seg_end)
11226-
return addr - seg_start + seg_offset;
11227-
}
11228-
pr_warn("elf: failed to find prog header containing 0x%lx in '%s'\n", addr, filename);
11229-
return -ENOENT;
11230-
}
11231-
1123211195
/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
1123311196
static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
1123411197
{
@@ -11315,6 +11278,8 @@ static long elf_find_func_offset(const char *binary_path, const char *name)
1131511278
for (idx = 0; idx < nr_syms; idx++) {
1131611279
int curr_bind;
1131711280
GElf_Sym sym;
11281+
Elf_Scn *sym_scn;
11282+
GElf_Shdr sym_sh;
1131811283

1131911284
if (!gelf_getsym(symbols, idx, &sym))
1132011285
continue;
@@ -11352,12 +11317,28 @@ static long elf_find_func_offset(const char *binary_path, const char *name)
1135211317
continue;
1135311318
}
1135411319
}
11355-
ret = sym.st_value;
11320+
11321+
/* Transform symbol's virtual address (absolute for
11322+
* binaries and relative for shared libs) into file
11323+
* offset, which is what kernel is expecting for
11324+
* uprobe/uretprobe attachment.
11325+
* See Documentation/trace/uprobetracer.rst for more
11326+
* details.
11327+
* This is done by looking up symbol's containing
11328+
* section's header and using it's virtual address
11329+
* (sh_addr) and corresponding file offset (sh_offset)
11330+
* to transform sym.st_value (virtual address) into
11331+
* desired final file offset.
11332+
*/
11333+
sym_scn = elf_getscn(elf, sym.st_shndx);
11334+
if (!sym_scn)
11335+
continue;
11336+
if (!gelf_getshdr(sym_scn, &sym_sh))
11337+
continue;
11338+
11339+
ret = sym.st_value - sym_sh.sh_addr + sym_sh.sh_offset;
1135611340
last_bind = curr_bind;
1135711341
}
11358-
/* For binaries that are not shared libraries, we need relative offset */
11359-
if (ret > 0 && !is_shared_lib)
11360-
ret = elf_find_relative_offset(binary_path, elf, ret);
1136111342
if (ret > 0)
1136211343
break;
1136311344
}

0 commit comments

Comments
 (0)