Skip to content

Commit

Permalink
libbpf-tools: Fix trace_helper symbol search bug
Browse files Browse the repository at this point in the history
dso__find_sym function considers elf file is not stripped. So it could find
wrong symbol if the target elf file is stripped. Consider if the start address
of each function 'foo', 'bar', 'baz' is '0x1000', '0x4000', '0x9000'
respectively, and 'bar' is stripped. If user wants to find the symbol of
address '0x4080', user expected result will be 'bar', and dso__find_sym
function expected result will be NULL, but actual result is 'foo' which is
incorrect.

To fix this problem, use symbol size on dso__find_sym function to check
whether the offset exists within the found symbol range.

strip can be used to remove certain non-allocable sections from the elf file.
This reduces file size by throwing away information. static function name is
one of the most popular non-allocable information.

Please refer this document for further information:
http:https://www.linker-aliens.org/blogs/ali/entry/inside_elf_symbol_tables/

Followings are the way to reproduce this issue with tool memleak and tell
how this patch fix this issue.

  On folder bcc/libbpf-tools
  Build test program a.out with file libtest.c and test.c

    $ gcc -c -o libtest.o libtest.c
    $ ld -shared libtest.o -o libtest.so
    $ gcc test.c -L. -ltest

  File libtest.c

    #include <stdlib.h>

    int* foo() {
      return NULL;
    }

    static int* bar() {
      return malloc(4);
    }

    int* baz() {
      return bar();
    }

  File test.c

    #include <unistd.h>

    int* baz();

    int main(int argc, char* argv[]) {
      int *a;
      while (1) {
        sleep(5);
        a = baz();
      }
      return 0;
    }

  Build memleak without blazesym

    $ USE_BLAZESYM=0 make memleak

  Run test program a.out and check the normal result

    $ LD_LIBRARY_PATH=. ./a.out &
    [1] 335459
    $ sudo ./memleak -p 335459
    using default object: libc.so.6
    using page size: 4096
    tracing kernel: false
    Tracing outstanding memory allocs...  Hit Ctrl-C to end
    [13:31:12] Top 1 stacks with outstanding allocations:
    4 bytes in 1 allocations from stack
            0 [<00007f60fe8e0051>] bar+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            1 [<00007f60fe8e0065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<000055d3a2992190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007f60fe629d90>] __libc_init_first+0x90 [/usr/lib/x86_64-linux-gnu/libc.so.6]
    [13:31:17] Top 1 stacks with outstanding allocations:
    8 bytes in 2 allocations from stack
            0 [<00007f60fe8e0051>] bar+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            1 [<00007f60fe8e0065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<000055d3a2992190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007f60fe629d90>] __libc_init_first+0x90 [/usr/lib/x86_64-linux-gnu/libc.so.6]
    ^C[13:31:22] Top 1 stacks with outstanding allocations:
    12 bytes in 3 allocations from stack
            0 [<00007f60fe8e0051>] bar+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            1 [<00007f60fe8e0065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<000055d3a2992190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007f60fe629d90>] __libc_init_first+0x90 [/usr/lib/x86_64-linux-gnu/libc.so.6]
    done

  Run test program a.out after strip libtest.so and check the result

    $ strip libtest.so
    $ LD_LIBRARY_PATH=. ./a.out &
    [1] 335467
    $ sudo ./memleak -p 335467
    using default object: libc.so.6
    using page size: 4096
    tracing kernel: false
    Tracing outstanding memory allocs...  Hit Ctrl-C to end
    [13:33:5] Top 1 stacks with outstanding allocations:
    4 bytes in 1 allocations from stack
            0 [<00007fe1eeba5051>] foo+0x21 [/home/bojun/bcc/libbpf-tools/libtest.so]
            1 [<00007fe1eeba5065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<00005648ff9d0190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007fe1ee829d90>] __libc_init_first+0x90 [/usr/lib/x86_64-linux-gnu/libc.so.6]
    [13:33:10] Top 1 stacks with outstanding allocations:
    8 bytes in 2 allocations from stack
            0 [<00007fe1eeba5051>] foo+0x21 [/home/bojun/bcc/libbpf-tools/libtest.so]
            1 [<00007fe1eeba5065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<00005648ff9d0190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007fe1ee829d90>] __libc_init_first+0x90 [/usr/lib/x86_64-linux-gnu/libc.so.6]
    ^C[13:33:12] Top 1 stacks with outstanding allocations:
    8 bytes in 2 allocations from stack
            0 [<00007fe1eeba5051>] foo+0x21 [/home/bojun/bcc/libbpf-tools/libtest.so]
            1 [<00007fe1eeba5065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<00005648ff9d0190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007fe1ee829d90>] __libc_init_first+0x90 [/usr/lib/x86_64-linux-gnu/libc.so.6]
    done

  This is the point, baz never calls foo but the report seems like baz calls foo!

  After apply this patch and build memleak and check the result

    $ USE_BLAZESYM=0 make memleak
    $ LD_LIBRARY_PATH=. ./a.out &
    [1] 335540
    $ sudo ./memleak -p 1234
    using default object: libc.so.6
    using page size: 4096
    tracing kernel: false
    Tracing outstanding memory allocs...  Hit Ctrl-C to end
    [13:35:20] Top 1 stacks with outstanding allocations:
    4 bytes in 1 allocations from stack
            0 [<00007f5e93839051>] <null sym>
            1 [<00007f5e93839065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<000055b4e197d190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007f5e93429d90>] <null sym>
    [13:35:25] Top 1 stacks with outstanding allocations:
    8 bytes in 2 allocations from stack
            0 [<00007f5e93839051>] <null sym>
            1 [<00007f5e93839065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<000055b4e197d190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007f5e93429d90>] <null sym>
    ^C[13:35:28] Top 1 stacks with outstanding allocations:
    8 bytes in 2 allocations from stack
            0 [<00007f5e93839051>] <null sym>
            1 [<00007f5e93839065>] baz+0x12 [/home/bojun/bcc/libbpf-tools/libtest.so]
            2 [<000055b4e197d190>] main+0x27 [/home/bojun/bcc/libbpf-tools/a.out]
            3 [<00007f5e93429d90>] <null sym>
    done

  Unknown symbol is correct result since the symbol bar is stripped
  • Loading branch information
Bojun-Seo authored and chenhengqi committed Dec 17, 2023
1 parent 8bc151f commit 3e27096
Showing 1 changed file with 2 additions and 1 deletion.
3 changes: 2 additions & 1 deletion libbpf-tools/trace_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,8 @@ static struct sym *dso__find_sym(struct dso *dso, uint64_t offset)
end = mid - 1;
}

if (start == end && dso->syms[start].start <= offset) {
if (start == end && dso->syms[start].start <= offset &&
offset < dso->syms[start].start + dso->syms[start].size) {
(dso->syms[start]).offset = offset - dso->syms[start].start;
return &dso->syms[start];
}
Expand Down

0 comments on commit 3e27096

Please sign in to comment.