Skip to content

Commit

Permalink
Merge pull request iovisor#875 from pchaigno/target-process-library
Browse files Browse the repository at this point in the history
Use targeted process to resolve library names
  • Loading branch information
4ast committed Jan 17, 2017
2 parents 9367ea5 + 81654bf commit 7e78f3a
Show file tree
Hide file tree
Showing 11 changed files with 124 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/cc/BPF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,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 @@ -31,10 +31,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 @@ -58,10 +67,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

0 comments on commit 7e78f3a

Please sign in to comment.