Commit 690b7e6d authored by Paul Chaignon's avatar Paul Chaignon

cc: Resolve library names using loaded libraries

To resolve library names, bcc_procutils_which_so leverages mapped
libraries of the targeted process, if one is given. Uses the kernel's
/proc/$pid/maps
parent 23e0de79
...@@ -462,7 +462,7 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path, ...@@ -462,7 +462,7 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
const std::string& symbol, const std::string& symbol,
uint64_t symbol_addr, bcc_symbol* output) { uint64_t symbol_addr, bcc_symbol* output) {
int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(), int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
symbol_addr, output); symbol_addr, 0, output);
if (res < 0) if (res < 0)
return StatusTuple( return StatusTuple(
-1, "Unable to find offset for binary %s symbol %s address %lx", -1, "Unable to find offset for binary %s symbol %s address %lx",
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include "bcc_perf_map.h" #include "bcc_perf_map.h"
#include "bcc_proc.h" #include "bcc_proc.h"
...@@ -196,6 +197,8 @@ static struct ld_lib { ...@@ -196,6 +197,8 @@ static struct ld_lib {
int flags; int flags;
} * lib_cache; } * lib_cache;
static char libpath[4096];
static int read_cache1(const char *ld_map) { static int read_cache1(const char *ld_map) {
struct ld_cache1 *ldcache = (struct ld_cache1 *)ld_map; struct ld_cache1 *ldcache = (struct ld_cache1 *)ld_map;
const char *ldstrings = const char *ldstrings =
...@@ -307,7 +310,47 @@ static bool match_so_flags(int flags) { ...@@ -307,7 +310,47 @@ static bool match_so_flags(int flags) {
return true; return true;
} }
const char *bcc_procutils_which_so(const char *libname) { static bool which_so_in_process(const char* libname, int pid) {
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));
break;
}
} while (ret != EOF);
fclose(fp);
return found;
}
const char *bcc_procutils_which_so(const char *libname, int pid) {
const size_t soname_len = strlen(libname) + strlen("lib.so"); const size_t soname_len = strlen(libname) + strlen("lib.so");
char soname[soname_len + 1]; char soname[soname_len + 1];
int i; int i;
...@@ -315,6 +358,9 @@ const char *bcc_procutils_which_so(const char *libname) { ...@@ -315,6 +358,9 @@ const char *bcc_procutils_which_so(const char *libname) {
if (strchr(libname, '/')) if (strchr(libname, '/'))
return libname; return libname;
if (pid && which_so_in_process(libname, pid))
return libpath;
if (lib_cache_count < 0) if (lib_cache_count < 0)
return NULL; return NULL;
...@@ -327,8 +373,9 @@ const char *bcc_procutils_which_so(const char *libname) { ...@@ -327,8 +373,9 @@ const char *bcc_procutils_which_so(const char *libname) {
for (i = 0; i < lib_cache_count; ++i) { for (i = 0; i < lib_cache_count; ++i) {
if (!strncmp(lib_cache[i].libname, soname, soname_len) && if (!strncmp(lib_cache[i].libname, soname, soname_len) &&
match_so_flags(lib_cache[i].flags)) match_so_flags(lib_cache[i].flags)) {
return lib_cache[i].path; return lib_cache[i].path;
}
} }
return NULL; return NULL;
} }
...@@ -27,7 +27,7 @@ extern "C" { ...@@ -27,7 +27,7 @@ extern "C" {
typedef int (*bcc_procutils_modulecb)(const char *, uint64_t, uint64_t, void *); typedef int (*bcc_procutils_modulecb)(const char *, uint64_t, uint64_t, void *);
typedef void (*bcc_procutils_ksymcb)(const char *, uint64_t, void *); typedef void (*bcc_procutils_ksymcb)(const char *, uint64_t, void *);
const char *bcc_procutils_which_so(const char *libname); const char *bcc_procutils_which_so(const char *libname, int pid);
char *bcc_procutils_which(const char *binpath); char *bcc_procutils_which(const char *binpath);
int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback, int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
void *payload); void *payload);
......
...@@ -304,7 +304,7 @@ int bcc_foreach_symbol(const char *module, SYM_CB cb) { ...@@ -304,7 +304,7 @@ int bcc_foreach_symbol(const char *module, SYM_CB cb) {
} }
int bcc_resolve_symname(const char *module, const char *symname, 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; uint64_t load_addr;
sym->module = NULL; sym->module = NULL;
...@@ -317,7 +317,7 @@ int bcc_resolve_symname(const char *module, const char *symname, ...@@ -317,7 +317,7 @@ int bcc_resolve_symname(const char *module, const char *symname,
if (strchr(module, '/')) { if (strchr(module, '/')) {
sym->module = module; sym->module = module;
} else { } else {
sym->module = bcc_procutils_which_so(module); sym->module = bcc_procutils_which_so(module, pid);
} }
if (sym->module == NULL) if (sym->module == NULL)
......
...@@ -43,7 +43,7 @@ int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address, ...@@ -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_foreach_symbol(const char *module, SYM_CB cb);
int bcc_find_symbol_addr(struct bcc_symbol *sym); int bcc_find_symbol_addr(struct bcc_symbol *sym);
int bcc_resolve_symname(const char *module, const char *symname, 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 #ifdef __cplusplus
} }
#endif #endif
......
...@@ -223,7 +223,7 @@ std::string Context::resolve_bin_path(const std::string &bin_path) { ...@@ -223,7 +223,7 @@ std::string Context::resolve_bin_path(const std::string &bin_path) {
if (char *which = bcc_procutils_which(bin_path.c_str())) { if (char *which = bcc_procutils_which(bin_path.c_str())) {
result = which; result = which;
::free(which); ::free(which);
} else if (const char *which_so = bcc_procutils_which_so(bin_path.c_str())) { } else if (const char *which_so = bcc_procutils_which_so(bin_path.c_str(), 0)) {
result = which_so; result = which_so;
} }
......
...@@ -109,7 +109,7 @@ struct bcc_symbol { ...@@ -109,7 +109,7 @@ struct bcc_symbol {
}; };
int bcc_resolve_symname(const char *module, const char *symname, const uint64_t addr, 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_symcache_new(int pid); void *bcc_symcache_new(int pid);
int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym); int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym);
void bcc_symcache_refresh(void *resolver); void bcc_symcache_refresh(void *resolver);
......
...@@ -32,7 +32,7 @@ end ...@@ -32,7 +32,7 @@ end
local function check_path_symbol(module, symname, addr) local function check_path_symbol(module, symname, addr)
local sym = SYM() local sym = SYM()
if libbcc.bcc_resolve_symname(module, symname, addr or 0x0, sym) < 0 then if libbcc.bcc_resolve_symname(module, symname, addr or 0x0, 0, sym) < 0 then
if sym[0].module == nil then if sym[0].module == nil then
error("could not find library '%s' in the library path" % module) error("could not find library '%s' in the library path" % module)
else else
......
...@@ -554,11 +554,12 @@ class BPF(object): ...@@ -554,11 +554,12 @@ class BPF(object):
@classmethod @classmethod
def _check_path_symbol(cls, module, symname, addr): def _check_path_symbol(cls, module, symname, addr, pid):
sym = bcc_symbol() sym = bcc_symbol()
psym = ct.pointer(sym) psym = ct.pointer(sym)
c_pid = 0 if pid == -1 else pid
if lib.bcc_resolve_symname(module.encode("ascii"), 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: if not sym.module:
raise Exception("could not find library %s" % module) raise Exception("could not find library %s" % module)
raise Exception("could not determine address of symbol %s" % symname) raise Exception("could not determine address of symbol %s" % symname)
...@@ -566,7 +567,7 @@ class BPF(object): ...@@ -566,7 +567,7 @@ class BPF(object):
@staticmethod @staticmethod
def find_library(libname): def find_library(libname):
res = lib.bcc_procutils_which_so(libname.encode("ascii")) res = lib.bcc_procutils_which_so(libname.encode("ascii"), 0)
return res if res is None else res.decode() return res if res is None else res.decode()
@staticmethod @staticmethod
...@@ -736,7 +737,8 @@ class BPF(object): ...@@ -736,7 +737,8 @@ class BPF(object):
Libraries can be given in the name argument without the lib prefix, or 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 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") Example: BPF(text).attach_uprobe("c", "malloc")
BPF(text).attach_uprobe("/usr/bin/python", "main") BPF(text).attach_uprobe("/usr/bin/python", "main")
...@@ -753,7 +755,7 @@ class BPF(object): ...@@ -753,7 +755,7 @@ class BPF(object):
group_fd=group_fd) group_fd=group_fd)
return 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) self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE) fn = self.load_func(fn_name, BPF.KPROBE)
...@@ -776,7 +778,7 @@ class BPF(object): ...@@ -776,7 +778,7 @@ class BPF(object):
""" """
name = str(name) name = str(name)
(path, addr) = BPF._check_path_symbol(name, sym, addr) (path, addr) = BPF._check_path_symbol(name, sym, addr, -1)
ev_name = "p_%s_0x%x" % (self._probe_repl.sub("_", path), addr) ev_name = "p_%s_0x%x" % (self._probe_repl.sub("_", path), addr)
if ev_name not in self.open_uprobes: if ev_name not in self.open_uprobes:
raise Exception("Uprobe %s is not attached" % ev_name) raise Exception("Uprobe %s is not attached" % ev_name)
...@@ -805,7 +807,7 @@ class BPF(object): ...@@ -805,7 +807,7 @@ class BPF(object):
return return
name = str(name) 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) self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE) fn = self.load_func(fn_name, BPF.KPROBE)
...@@ -828,7 +830,7 @@ class BPF(object): ...@@ -828,7 +830,7 @@ class BPF(object):
""" """
name = str(name) name = str(name)
(path, addr) = BPF._check_path_symbol(name, sym, addr) (path, addr) = BPF._check_path_symbol(name, sym, addr, -1)
ev_name = "r_%s_0x%x" % (self._probe_repl.sub("_", path), addr) ev_name = "r_%s_0x%x" % (self._probe_repl.sub("_", path), addr)
if ev_name not in self.open_uprobes: if ev_name not in self.open_uprobes:
raise Exception("Uretprobe %s is not attached" % ev_name) raise Exception("Uretprobe %s is not attached" % ev_name)
......
...@@ -131,11 +131,11 @@ class bcc_symbol(ct.Structure): ...@@ -131,11 +131,11 @@ class bcc_symbol(ct.Structure):
] ]
lib.bcc_procutils_which_so.restype = ct.c_char_p 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.argtypes = [ct.c_char_p, ct.c_int]
lib.bcc_resolve_symname.restype = ct.c_int lib.bcc_resolve_symname.restype = ct.c_int
lib.bcc_resolve_symname.argtypes = [ 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) _SYM_CB_TYPE = ct.CFUNCTYPE(ct.c_int, ct.c_char_p, ct.c_ulonglong)
lib.bcc_foreach_symbol.restype = ct.c_int lib.bcc_foreach_symbol.restype = ct.c_int
......
...@@ -30,12 +30,19 @@ ...@@ -30,12 +30,19 @@
using namespace std; using namespace std;
TEST_CASE("shared object resolution", "[c_api]") { TEST_CASE("shared object resolution", "[c_api]") {
const char *libm = bcc_procutils_which_so("m"); const char *libm = bcc_procutils_which_so("m", 0);
REQUIRE(libm); REQUIRE(libm);
REQUIRE(libm[0] == '/'); REQUIRE(libm[0] == '/');
REQUIRE(string(libm).find("libm.so") != string::npos); REQUIRE(string(libm).find("libm.so") != string::npos);
} }
TEST_CASE("shared object resolution using loaded libraries", "[c_api]") {
const char *libelf = bcc_procutils_which_so("elf", getpid());
REQUIRE(libelf);
REQUIRE(libelf[0] == '/');
REQUIRE(string(libelf).find("libelf") != string::npos);
}
TEST_CASE("binary resolution with `which`", "[c_api]") { TEST_CASE("binary resolution with `which`", "[c_api]") {
char *ld = bcc_procutils_which("ld"); char *ld = bcc_procutils_which("ld");
REQUIRE(ld); REQUIRE(ld);
...@@ -57,12 +64,21 @@ TEST_CASE("list all kernel symbols", "[c_api]") { ...@@ -57,12 +64,21 @@ TEST_CASE("list all kernel symbols", "[c_api]") {
TEST_CASE("resolve symbol name in external library", "[c_api]") { TEST_CASE("resolve symbol name in external library", "[c_api]") {
struct bcc_symbol sym; 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(string(sym.module).find("libc.so") != string::npos);
REQUIRE(sym.module[0] == '/'); REQUIRE(sym.module[0] == '/');
REQUIRE(sym.offset != 0); REQUIRE(sym.offset != 0);
} }
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);
}
extern "C" int _a_test_function(const char *a_string) { extern "C" int _a_test_function(const char *a_string) {
int i; int i;
for (i = 0; a_string[i]; ++i) for (i = 0; a_string[i]; ++i)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment