Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use targeted process to resolve library names #875

Merged
merged 3 commits into from
Jan 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cc/BPF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
const std::string& symbol,
uint64_t symbol_addr, bcc_symbol* output) {
int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
symbol_addr, output);
symbol_addr, 0, output);
if (res < 0)
return StatusTuple(
-1, "Unable to find offset for binary %s symbol %s address %lx",
Expand Down
58 changes: 54 additions & 4 deletions src/cc/bcc_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <stdint.h>
#include <ctype.h>
#include <stdio.h>
#include <math.h>

#include "bcc_perf_map.h"
#include "bcc_proc.h"
Expand Down Expand Up @@ -307,13 +308,57 @@ static bool match_so_flags(int flags) {
return true;
}

const char *bcc_procutils_which_so(const char *libname) {
static bool which_so_in_process(const char* libname, int pid, char* libpath) {
int ret, found = false;
char endline[4096], *mapname = NULL, *newline;
char mappings_file[128];
const size_t search_len = strlen(libname) + strlen("/lib.");
char search1[search_len + 1];
char search2[search_len + 1];

sprintf(mappings_file, "/proc/%ld/maps", (long)pid);
FILE *fp = fopen(mappings_file, "r");
if (!fp)
return NULL;

snprintf(search1, search_len + 1, "/lib%s.", libname);
snprintf(search2, search_len + 1, "/lib%s-", libname);

do {
ret = fscanf(fp, "%*x-%*x %*s %*x %*s %*d");
if (!fgets(endline, sizeof(endline), fp))
break;

mapname = endline;
newline = strchr(endline, '\n');
if (newline)
newline[0] = '\0';

while (isspace(mapname[0])) mapname++;

if (strstr(mapname, ".so") && (strstr(mapname, search1) ||
strstr(mapname, search2))) {
found = true;
memcpy(libpath, mapname, strlen(mapname) + 1);
break;
}
} while (ret != EOF);

fclose(fp);
return found;
}

char *bcc_procutils_which_so(const char *libname, int pid) {
const size_t soname_len = strlen(libname) + strlen("lib.so");
char soname[soname_len + 1];
char libpath[4096];
int i;

if (strchr(libname, '/'))
return libname;
return strdup(libname);

if (pid && which_so_in_process(libname, pid, libpath))
return strdup(libpath);

if (lib_cache_count < 0)
return NULL;
Expand All @@ -327,8 +372,13 @@ const char *bcc_procutils_which_so(const char *libname) {

for (i = 0; i < lib_cache_count; ++i) {
if (!strncmp(lib_cache[i].libname, soname, soname_len) &&
match_so_flags(lib_cache[i].flags))
return lib_cache[i].path;
match_so_flags(lib_cache[i].flags)) {
return strdup(lib_cache[i].path);
}
}
return NULL;
}

void bcc_procutils_free(const char *ptr) {
free((void *)ptr);
}
3 changes: 2 additions & 1 deletion src/cc/bcc_proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ extern "C" {
typedef int (*bcc_procutils_modulecb)(const char *, uint64_t, uint64_t, void *);
typedef void (*bcc_procutils_ksymcb)(const char *, uint64_t, void *);

const char *bcc_procutils_which_so(const char *libname);
char *bcc_procutils_which_so(const char *libname, int pid);
char *bcc_procutils_which(const char *binpath);
int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
void *payload);
int bcc_procutils_each_ksym(bcc_procutils_ksymcb callback, void *payload);
void bcc_procutils_free(const char *ptr);

#ifdef __cplusplus
}
Expand Down
6 changes: 3 additions & 3 deletions src/cc/bcc_syms.cc
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ int bcc_foreach_symbol(const char *module, SYM_CB cb) {
}

int bcc_resolve_symname(const char *module, const char *symname,
const uint64_t addr, struct bcc_symbol *sym) {
const uint64_t addr, int pid, struct bcc_symbol *sym) {
uint64_t load_addr;

sym->module = NULL;
Expand All @@ -315,9 +315,9 @@ int bcc_resolve_symname(const char *module, const char *symname,
return -1;

if (strchr(module, '/')) {
sym->module = module;
sym->module = strdup(module);
} else {
sym->module = bcc_procutils_which_so(module);
sym->module = bcc_procutils_which_so(module, pid);
}

if (sym->module == NULL)
Expand Down
2 changes: 1 addition & 1 deletion src/cc/bcc_syms.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address,
int bcc_foreach_symbol(const char *module, SYM_CB cb);
int bcc_find_symbol_addr(struct bcc_symbol *sym);
int bcc_resolve_symname(const char *module, const char *symname,
const uint64_t addr, struct bcc_symbol *sym);
const uint64_t addr, int pid, struct bcc_symbol *sym);
#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 2 additions & 1 deletion src/cc/usdt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ std::string Context::resolve_bin_path(const std::string &bin_path) {
if (char *which = bcc_procutils_which(bin_path.c_str())) {
result = which;
::free(which);
} else if (const char *which_so = bcc_procutils_which_so(bin_path.c_str())) {
} else if (char *which_so = bcc_procutils_which_so(bin_path.c_str(), 0)) {
result = which_so;
::free(which_so);
}

return result;
Expand Down
3 changes: 2 additions & 1 deletion src/lua/bcc/libbcc.lua
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ struct bcc_symbol {
};

int bcc_resolve_symname(const char *module, const char *symname, const uint64_t addr,
struct bcc_symbol *sym);
int pid, struct bcc_symbol *sym);
void bcc_procutils_free(const char *ptr);
void *bcc_symcache_new(int pid);
int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym);
void bcc_symcache_refresh(void *resolver);
Expand Down
11 changes: 8 additions & 3 deletions src/lua/bcc/sym.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,20 @@ end

local function check_path_symbol(module, symname, addr)
local sym = SYM()
if libbcc.bcc_resolve_symname(module, symname, addr or 0x0, sym) < 0 then
local module_path
if libbcc.bcc_resolve_symname(module, symname, addr or 0x0, 0, sym) < 0 then
if sym[0].module == nil then
error("could not find library '%s' in the library path" % module)
else
module_path = ffi.string(sym[0].module)
libbcc.bcc_procutils_free(sym[0].module)
error("failed to resolve symbol '%s' in '%s'" % {
symname, ffi.string(sym[0].module)})
symname, module_path})
end
end
return ffi.string(sym[0].module), sym[0].offset
module_path = ffi.string(sym[0].module)
libbcc.bcc_procutils_free(sym[0].module)
return module_path, sym[0].offset
end

return { create_cache=create_cache, check_path_symbol=check_path_symbol }
37 changes: 23 additions & 14 deletions src/python/bcc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,20 +554,28 @@ def remove_xdp(dev):


@classmethod
def _check_path_symbol(cls, module, symname, addr):
def _check_path_symbol(cls, module, symname, addr, pid):
sym = bcc_symbol()
psym = ct.pointer(sym)
c_pid = 0 if pid == -1 else pid
if lib.bcc_resolve_symname(module.encode("ascii"),
symname.encode("ascii"), addr or 0x0, psym) < 0:
symname.encode("ascii"), addr or 0x0, c_pid, psym) < 0:
if not sym.module:
raise Exception("could not find library %s" % module)
lib.bcc_procutils_free(sym.module)
raise Exception("could not determine address of symbol %s" % symname)
return sym.module.decode(), sym.offset
module_path = ct.cast(sym.module, ct.c_char_p).value.decode()
lib.bcc_procutils_free(sym.module)
return module_path, sym.offset

@staticmethod
def find_library(libname):
res = lib.bcc_procutils_which_so(libname.encode("ascii"))
return res if res is None else res.decode()
res = lib.bcc_procutils_which_so(libname.encode("ascii"), 0)
if not res:
return None
libpath = ct.cast(res, ct.c_char_p).value.decode()
lib.bcc_procutils_free(res)
return libpath

@staticmethod
def get_tracepoints(tp_re):
Expand Down Expand Up @@ -736,7 +744,8 @@ def attach_uprobe(self, name="", sym="", sym_re="", addr=None,

Libraries can be given in the name argument without the lib prefix, or
with the full path (/usr/lib/...). Binaries can be given only with the
full path (/bin/sh).
full path (/bin/sh). If a PID is given, the uprobe will attach to the
version of the library used by the process.

Example: BPF(text).attach_uprobe("c", "malloc")
BPF(text).attach_uprobe("/usr/bin/python", "main")
Expand All @@ -753,7 +762,7 @@ def attach_uprobe(self, name="", sym="", sym_re="", addr=None,
group_fd=group_fd)
return

(path, addr) = BPF._check_path_symbol(name, sym, addr)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid)

self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE)
Expand All @@ -768,15 +777,15 @@ def attach_uprobe(self, name="", sym="", sym_re="", addr=None,
self._add_uprobe(ev_name, res)
return self

def detach_uprobe(self, name="", sym="", addr=None):
"""detach_uprobe(name="", sym="", addr=None)
def detach_uprobe(self, name="", sym="", addr=None, pid=-1):
"""detach_uprobe(name="", sym="", addr=None, pid=-1)

Stop running a bpf function that is attached to symbol 'sym' in library
or binary 'name'.
"""

name = str(name)
(path, addr) = BPF._check_path_symbol(name, sym, addr)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid)
ev_name = "p_%s_0x%x" % (self._probe_repl.sub("_", path), addr)
if ev_name not in self.open_uprobes:
raise Exception("Uprobe %s is not attached" % ev_name)
Expand Down Expand Up @@ -805,7 +814,7 @@ def attach_uretprobe(self, name="", sym="", sym_re="", addr=None,
return

name = str(name)
(path, addr) = BPF._check_path_symbol(name, sym, addr)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid)

self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE)
Expand All @@ -820,15 +829,15 @@ def attach_uretprobe(self, name="", sym="", sym_re="", addr=None,
self._add_uprobe(ev_name, res)
return self

def detach_uretprobe(self, name="", sym="", addr=None):
"""detach_uretprobe(name="", sym="", addr=None)
def detach_uretprobe(self, name="", sym="", addr=None, pid=-1):
"""detach_uretprobe(name="", sym="", addr=None, pid=-1)

Stop running a bpf function that is attached to symbol 'sym' in library
or binary 'name'.
"""

name = str(name)
(path, addr) = BPF._check_path_symbol(name, sym, addr)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid)
ev_name = "r_%s_0x%x" % (self._probe_repl.sub("_", path), addr)
if ev_name not in self.open_uprobes:
raise Exception("Uretprobe %s is not attached" % ev_name)
Expand Down
10 changes: 6 additions & 4 deletions src/python/bcc/libbcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,18 @@ class bcc_symbol(ct.Structure):
_fields_ = [
('name', ct.c_char_p),
('demangle_name', ct.c_char_p),
('module', ct.c_char_p),
('module', ct.POINTER(ct.c_char)),
('offset', ct.c_ulonglong),
]

lib.bcc_procutils_which_so.restype = ct.c_char_p
lib.bcc_procutils_which_so.argtypes = [ct.c_char_p]
lib.bcc_procutils_which_so.restype = ct.POINTER(ct.c_char)
lib.bcc_procutils_which_so.argtypes = [ct.c_char_p, ct.c_int]
lib.bcc_procutils_free.restype = None
lib.bcc_procutils_free.argtypes = [ct.c_void_p]

lib.bcc_resolve_symname.restype = ct.c_int
lib.bcc_resolve_symname.argtypes = [
ct.c_char_p, ct.c_char_p, ct.c_ulonglong, ct.POINTER(bcc_symbol)]
ct.c_char_p, ct.c_char_p, ct.c_ulonglong, ct.c_int, ct.POINTER(bcc_symbol)]

_SYM_CB_TYPE = ct.CFUNCTYPE(ct.c_int, ct.c_char_p, ct.c_ulonglong)
lib.bcc_foreach_symbol.restype = ct.c_int
Expand Down
24 changes: 22 additions & 2 deletions tests/cc/test_c_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@
using namespace std;

TEST_CASE("shared object resolution", "[c_api]") {
const char *libm = bcc_procutils_which_so("m");
char *libm = bcc_procutils_which_so("m", 0);
REQUIRE(libm);
REQUIRE(libm[0] == '/');
REQUIRE(string(libm).find("libm.so") != string::npos);
free(libm);
}

TEST_CASE("shared object resolution using loaded libraries", "[c_api]") {
char *libelf = bcc_procutils_which_so("elf", getpid());
REQUIRE(libelf);
REQUIRE(libelf[0] == '/');
REQUIRE(string(libelf).find("libelf") != string::npos);
free(libelf);
}

TEST_CASE("binary resolution with `which`", "[c_api]") {
Expand All @@ -57,10 +66,21 @@ TEST_CASE("list all kernel symbols", "[c_api]") {
TEST_CASE("resolve symbol name in external library", "[c_api]") {
struct bcc_symbol sym;

REQUIRE(bcc_resolve_symname("c", "malloc", 0x0, &sym) == 0);
REQUIRE(bcc_resolve_symname("c", "malloc", 0x0, 0, &sym) == 0);
REQUIRE(string(sym.module).find("libc.so") != string::npos);
REQUIRE(sym.module[0] == '/');
REQUIRE(sym.offset != 0);
bcc_procutils_free(sym.module);
}

TEST_CASE("resolve symbol name in external library using loaded libraries", "[c_api]") {
struct bcc_symbol sym;

REQUIRE(bcc_resolve_symname("bcc", "bcc_procutils_which", 0x0, getpid(), &sym) == 0);
REQUIRE(string(sym.module).find("libbcc.so") != string::npos);
REQUIRE(sym.module[0] == '/');
REQUIRE(sym.offset != 0);
bcc_procutils_free(sym.module);
}

extern "C" int _a_test_function(const char *a_string) {
Expand Down