libbpf-tools: fix uprobe helper get_elf_func_offset
authorHengqi Chen <chenhengqi@outlook.com>
Thu, 1 Jul 2021 13:16:15 +0000 (21:16 +0800)
committeryonghong-song <ys114321@gmail.com>
Mon, 12 Jul 2021 06:08:23 +0000 (23:08 -0700)
get_elf_func_offset didn't work properly when use with
statically linked binary. It seems like not subtract the
base load address cause the problem. This commits fixes
that like BCC does. see [0] and [1].

[0]: https://github.com/iovisor/bcc/blob/v0.20.0/src/cc/bcc_syms.cc#L751-L764
[1]: https://github.com/iovisor/bcc/blob/v0.20.0/src/cc/bcc_elf.c#L723-L756

Signed-off-by: Hengqi Chen <chenhengqi@outlook.com>
libbpf-tools/uprobe_helpers.c

index 9f6e3b5493ab7c4317a209e83ded2e9cf2444ab8..953cea1a4e040956f0a7efd32ef656bd71477f2f 100644 (file)
@@ -228,13 +228,18 @@ off_t get_elf_func_offset(const char *path, const char *func)
        Elf *e;
        Elf_Scn *scn;
        Elf_Data *data;
+       GElf_Ehdr ehdr;
        GElf_Shdr shdr[1];
+       GElf_Phdr phdr;
        GElf_Sym sym[1];
-       size_t shstrndx;
+       size_t shstrndx, nhdrs;
        char *n;
 
        e = open_elf(path, &fd);
 
+       if (!gelf_getehdr(e, &ehdr))
+               goto out;
+
        if (elf_getshdrstrndx(e, &shstrndx) != 0)
                goto out;
 
@@ -254,12 +259,30 @@ off_t get_elf_func_offset(const char *path, const char *func)
                                        continue;
                                if (!strcmp(n, func)) {
                                        ret = sym->st_value;
-                                       goto out;
+                                       goto check;
                                }
                        }
                }
        }
 
+check:
+       if (ehdr.e_type == ET_EXEC || ehdr.e_type == ET_DYN) {
+               if (elf_getphdrnum(e, &nhdrs) != 0) {
+                       ret = -1;
+                       goto out;
+               }
+               for (i = 0; i < (int)nhdrs; i++) {
+                       if (!gelf_getphdr(e, i, &phdr))
+                               continue;
+                       if (phdr.p_type != PT_LOAD || !(phdr.p_flags & PF_X))
+                               continue;
+                       if (phdr.p_vaddr <= ret && ret < (phdr.p_vaddr + phdr.p_memsz)) {
+                               ret = ret - phdr.p_vaddr + phdr.p_offset;
+                               goto out;
+                       }
+               }
+               ret = -1;
+       }
 out:
        close_elf(e, fd);
        return ret;