Skip to content

Commit

Permalink
Translate virtual addresses to binary addresses for shared libs as well.
Browse files Browse the repository at this point in the history
Quoting https://refspecs.linuxbase.org/elf/elf.pdf:
```
Symbol table entries for different object file types have slightly different
interpretations for the st_value member.
- In relocatable files, st_value holds alignment constraints for a symbol
whose section index is SHN_COMMON.
- In relocatable files, st_value holds a section offset for a defined symbol.
That is, st_value is an offset from the beginning of the section that st_shndx
identifies.
- In executable and shared object files, st_value holds a virtual address. To
make these files' symbols more useful for the dynamic linker, the section offset
(file interpretation) gives way to a virtual address (memory interpretation) for
which the section number is irrelevant.
```

This is a problem in practice as well. I run into this while tracing shared
libraries on Android with bpftrace. Some of them have text sections mmapped
at different offset than file offset which results in probes being placed
at wrong offsets.
  • Loading branch information
Michał Gregorczyk authored and yonghong-song committed Apr 6, 2020
1 parent f35dae0 commit 007ee49
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 5 deletions.
10 changes: 5 additions & 5 deletions src/cc/bcc_syms.cc
Expand Up @@ -707,6 +707,7 @@ int bcc_resolve_symname(const char *module, const char *symname,
const uint64_t addr, int pid,
struct bcc_symbol_option *option,
struct bcc_symbol *sym) {
int module_type;
static struct bcc_symbol_option default_option = {
.use_debug_file = 1,
.check_debug_file_crc = 1,
Expand Down Expand Up @@ -747,11 +748,10 @@ int bcc_resolve_symname(const char *module, const char *symname,
if (sym->offset == 0x0)
goto invalid_module;

// For executable (ET_EXEC) binaries, translate the virtual address
// to physical address in the binary file.
// For shared object binaries (ET_DYN), the address from symbol table should
// already be physical address in the binary file.
if (bcc_elf_get_type(sym->module) == ET_EXEC) {
// For executable (ET_EXEC) binaries and shared objects (ET_DYN), translate
// the virtual address to physical address in the binary file.
module_type = bcc_elf_get_type(sym->module);
if (module_type == ET_EXEC || module_type == ET_DYN) {
struct load_addr_t addr = {
.target_addr = sym->offset,
.binary_addr = 0x0,
Expand Down
2 changes: 2 additions & 0 deletions tests/python/CMakeLists.txt
Expand Up @@ -55,6 +55,8 @@ add_test(NAME py_array WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_array sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_array.py)
add_test(NAME py_uprobes WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_uprobes sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_uprobes.py)
add_test(NAME py_uprobes_2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_uprobes2 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_uprobes2.py)
add_test(NAME py_test_stackid WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_stackid sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_stackid.py)
add_test(NAME py_test_tracepoint WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
47 changes: 47 additions & 0 deletions tests/python/test_uprobes2.py
@@ -0,0 +1,47 @@
#!/usr/bin/env python
#
# USAGE: test_uprobe2.py
#
# Copyright 2020 Facebook, Inc
# Licensed under the Apache License, Version 2.0 (the "License")

from bcc import BPF
from unittest import main, TestCase
from subprocess import Popen, PIPE
from tempfile import NamedTemporaryFile


class TestUprobes(TestCase):
def setUp(self):
lib_text = b"""
__attribute__((__visibility__("default"))) void fun()
{
}
"""
self.bpf_text = """
int trace_fun_call(void *ctx) {{
return 1;
}}
"""
# Compile and run the application
self.ftemp = NamedTemporaryFile(delete=False)
self.ftemp.close()
comp = Popen([
"gcc",
"-x", "c",
"-shared",
"-Wl,-Ttext-segment,0x2000000",
"-o", self.ftemp.name,
"-"
], stdin=PIPE)
comp.stdin.write(lib_text)
comp.stdin.close()
self.assertEqual(comp.wait(), 0)

def test_attach1(self):
b = BPF(text=self.bpf_text)
b.attach_uprobe(name=self.ftemp.name, sym="fun", fn_name="trace_fun_call")


if __name__ == "__main__":
main()

0 comments on commit 007ee49

Please sign in to comment.