Commit 9e718f5a authored by Teng Qin's avatar Teng Qin Committed by Sasha Goldshtein

Add an option to resolve address without demangling (#1084)

* Add an option to resolve address without demangling

* Expose new no-demangling option to Python
parent af20e1e3
...@@ -48,7 +48,7 @@ void KSyms::refresh() { ...@@ -48,7 +48,7 @@ void KSyms::refresh() {
} }
} }
bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle) {
refresh(); refresh();
if (syms_.empty()) { if (syms_.empty()) {
...@@ -61,7 +61,8 @@ bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { ...@@ -61,7 +61,8 @@ bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) {
auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol("", addr)) - 1; auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol("", addr)) - 1;
sym->name = (*it).name.c_str(); sym->name = (*it).name.c_str();
sym->demangle_name = sym->name; if (demangle)
sym->demangle_name = sym->name;
sym->module = "kernel"; sym->module = "kernel";
sym->offset = addr - (*it).addr; sym->offset = addr - (*it).addr;
return true; return true;
...@@ -135,7 +136,8 @@ int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end, ...@@ -135,7 +136,8 @@ int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end,
return 0; return 0;
} }
bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym,
bool demangle) {
if (procstat_.is_stale()) if (procstat_.is_stale())
refresh(); refresh();
...@@ -148,8 +150,10 @@ bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { ...@@ -148,8 +150,10 @@ bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) {
for (Module &mod : modules_) { for (Module &mod : modules_) {
if (mod.contains(addr)) { if (mod.contains(addr)) {
bool res = mod.find_addr(addr, sym); bool res = mod.find_addr(addr, sym);
if (sym->name) { if (demangle) {
sym->demangle_name = abi::__cxa_demangle(sym->name, nullptr, nullptr, nullptr); if (sym->name)
sym->demangle_name =
abi::__cxa_demangle(sym->name, nullptr, nullptr, nullptr);
if (!sym->demangle_name) if (!sym->demangle_name)
sym->demangle_name = sym->name; sym->demangle_name = sym->name;
} }
...@@ -309,6 +313,12 @@ int bcc_symcache_resolve(void *resolver, uint64_t addr, ...@@ -309,6 +313,12 @@ int bcc_symcache_resolve(void *resolver, uint64_t addr,
return cache->resolve_addr(addr, sym) ? 0 : -1; return cache->resolve_addr(addr, sym) ? 0 : -1;
} }
int bcc_symcache_resolve_no_demangle(void *resolver, uint64_t addr,
struct bcc_symbol *sym) {
SymbolCache *cache = static_cast<SymbolCache *>(resolver);
return cache->resolve_addr(addr, sym, false) ? 0 : -1;
}
int bcc_symcache_resolve_name(void *resolver, const char *module, int bcc_symcache_resolve_name(void *resolver, const char *module,
const char *name, uint64_t *addr) { const char *name, uint64_t *addr) {
SymbolCache *cache = static_cast<SymbolCache *>(resolver); SymbolCache *cache = static_cast<SymbolCache *>(resolver);
......
...@@ -29,12 +29,15 @@ struct bcc_symbol { ...@@ -29,12 +29,15 @@ struct bcc_symbol {
uint64_t offset; uint64_t offset;
}; };
typedef int(* SYM_CB)(const char *symname, uint64_t addr); typedef int (*SYM_CB)(const char *symname, uint64_t addr);
void *bcc_symcache_new(int pid); void *bcc_symcache_new(int pid);
void bcc_free_symcache(void *symcache, int pid); void bcc_free_symcache(void *symcache, 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);
int bcc_symcache_resolve_no_demangle(void *symcache, uint64_t addr,
struct bcc_symbol *sym);
int bcc_symcache_resolve_name(void *resolver, const char *module, int bcc_symcache_resolve_name(void *resolver, const char *module,
const char *name, uint64_t *addr); const char *name, uint64_t *addr);
void bcc_symcache_refresh(void *resolver); void bcc_symcache_refresh(void *resolver);
......
...@@ -39,7 +39,7 @@ public: ...@@ -39,7 +39,7 @@ public:
virtual ~SymbolCache() = default; virtual ~SymbolCache() = default;
virtual void refresh() = 0; virtual void refresh() = 0;
virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym) = 0; virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle = true) = 0;
virtual bool resolve_name(const char *module, const char *name, virtual bool resolve_name(const char *module, const char *name,
uint64_t *addr) = 0; uint64_t *addr) = 0;
}; };
...@@ -58,7 +58,7 @@ class KSyms : SymbolCache { ...@@ -58,7 +58,7 @@ class KSyms : SymbolCache {
static void _add_symbol(const char *, uint64_t, void *); static void _add_symbol(const char *, uint64_t, void *);
public: public:
virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym); virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle = true);
virtual bool resolve_name(const char *unused, const char *name, virtual bool resolve_name(const char *unused, const char *name,
uint64_t *addr); uint64_t *addr);
virtual void refresh(); virtual void refresh();
...@@ -116,7 +116,7 @@ class ProcSyms : SymbolCache { ...@@ -116,7 +116,7 @@ class ProcSyms : SymbolCache {
public: public:
ProcSyms(int pid); ProcSyms(int pid);
virtual void refresh(); virtual void refresh();
virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym); virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle = true);
virtual bool resolve_name(const char *module, const char *name, virtual bool resolve_name(const char *module, const char *name,
uint64_t *addr); uint64_t *addr);
}; };
...@@ -48,7 +48,7 @@ class SymbolCache(object): ...@@ -48,7 +48,7 @@ class SymbolCache(object):
def __init__(self, pid): def __init__(self, pid):
self.cache = lib.bcc_symcache_new(pid) self.cache = lib.bcc_symcache_new(pid)
def resolve(self, addr): def resolve(self, addr, demangle):
""" """
Return a tuple of the symbol (function), its offset from the beginning Return a tuple of the symbol (function), its offset from the beginning
of the function, and the module in which it lies. For example: of the function, and the module in which it lies. For example:
...@@ -60,13 +60,18 @@ class SymbolCache(object): ...@@ -60,13 +60,18 @@ class SymbolCache(object):
""" """
sym = bcc_symbol() sym = bcc_symbol()
psym = ct.pointer(sym) psym = ct.pointer(sym)
if lib.bcc_symcache_resolve(self.cache, addr, psym) < 0: if demangle:
res = lib.bcc_symcache_resolve(self.cache, addr, psym)
else:
res = lib.bcc_symcache_resolve_no_demangle(self.cache, addr, psym)
if res < 0:
if sym.module and sym.offset: if sym.module and sym.offset:
return (None, sym.offset, return (None, sym.offset,
ct.cast(sym.module, ct.c_char_p).value.decode()) ct.cast(sym.module, ct.c_char_p).value.decode())
return (None, addr, None) return (None, addr, None)
return (sym.demangle_name.decode(), sym.offset, return (
ct.cast(sym.module, ct.c_char_p).value.decode()) sym.demangle_name.decode() if demangle else sym.name.decode(),
sym.offset, ct.cast(sym.module, ct.c_char_p).value.decode())
def resolve_name(self, module, name): def resolve_name(self, module, name):
addr = ct.c_ulonglong() addr = ct.c_ulonglong()
...@@ -989,7 +994,7 @@ class BPF(object): ...@@ -989,7 +994,7 @@ class BPF(object):
return BPF._sym_caches[pid] return BPF._sym_caches[pid]
@staticmethod @staticmethod
def sym(addr, pid, show_module=False, show_offset=False): def sym(addr, pid, show_module=False, show_offset=False, demangle=True):
"""sym(addr, pid, show_module=False, show_offset=False) """sym(addr, pid, show_module=False, show_offset=False)
Translate a memory address into a function name for a pid, which is Translate a memory address into a function name for a pid, which is
...@@ -1005,7 +1010,7 @@ class BPF(object): ...@@ -1005,7 +1010,7 @@ class BPF(object):
Example output when both show_module and show_offset are False: Example output when both show_module and show_offset are False:
"start_thread" "start_thread"
""" """
name, offset, module = BPF._sym_cache(pid).resolve(addr) name, offset, module = BPF._sym_cache(pid).resolve(addr, demangle)
offset = "+0x%x" % offset if show_offset and name is not None else "" offset = "+0x%x" % offset if show_offset and name is not None else ""
name = name or "[unknown]" name = name or "[unknown]"
name = name + offset name = name + offset
...@@ -1025,7 +1030,7 @@ class BPF(object): ...@@ -1025,7 +1030,7 @@ class BPF(object):
Example output when both show_module and show_offset are True: Example output when both show_module and show_offset are True:
"default_idle+0x0 [kernel]" "default_idle+0x0 [kernel]"
""" """
return BPF.sym(addr, -1, show_module, show_offset) return BPF.sym(addr, -1, show_module, show_offset, False)
@staticmethod @staticmethod
def ksymname(name): def ksymname(name):
......
...@@ -154,6 +154,9 @@ lib.bcc_free_symcache.argtypes = [ct.c_void_p, ct.c_int] ...@@ -154,6 +154,9 @@ lib.bcc_free_symcache.argtypes = [ct.c_void_p, ct.c_int]
lib.bcc_symcache_resolve.restype = ct.c_int lib.bcc_symcache_resolve.restype = ct.c_int
lib.bcc_symcache_resolve.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.POINTER(bcc_symbol)] lib.bcc_symcache_resolve.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.POINTER(bcc_symbol)]
lib.bcc_symcache_resolve_no_demangle.restype = ct.c_int
lib.bcc_symcache_resolve_no_demangle.argtypes = [ct.c_void_p, ct.c_ulonglong, ct.POINTER(bcc_symbol)]
lib.bcc_symcache_resolve_name.restype = ct.c_int lib.bcc_symcache_resolve_name.restype = ct.c_int
lib.bcc_symcache_resolve_name.argtypes = [ lib.bcc_symcache_resolve_name.argtypes = [
ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.POINTER(ct.c_ulonglong)] ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.POINTER(ct.c_ulonglong)]
......
#include <unistd.h>
#include <stdio.h>
static __attribute__((noinline)) int some_function(int x, int y) {
volatile int z = x + y;
return z;
}
int main() {
printf("%p\n", &some_function);
fflush(stdout);
printf("result = %d\n", some_function(42, 11));
sleep(1000);
return 0;
}
#include <unistd.h>
#include <cstdio>
namespace some_namespace {
static __attribute__((noinline)) int some_function(int x, int y) {
volatile int z = x + y;
return z;
}
}
int main() {
printf("%p\n", &some_namespace::some_function);
fflush(stdout);
printf("result = %d\n", some_namespace::some_function(42, 11));
sleep(1000);
return 0;
}
...@@ -44,21 +44,32 @@ class Harness(TestCase): ...@@ -44,21 +44,32 @@ class Harness(TestCase):
self.process.wait() self.process.wait()
def resolve_addr(self): def resolve_addr(self):
sym, offset, module = self.syms.resolve(self.addr) sym, offset, module = self.syms.resolve(self.addr, False)
self.assertEqual(sym, 'some_function') self.assertEqual(sym, self.mangled_name)
self.assertEqual(offset, 0)
self.assertTrue(module[-5:] == 'dummy')
sym, offset, module = self.syms.resolve(self.addr, True)
self.assertEqual(sym, 'some_namespace::some_function(int, int)')
self.assertEqual(offset, 0) self.assertEqual(offset, 0)
self.assertTrue(module[-5:] == 'dummy') self.assertTrue(module[-5:] == 'dummy')
def resolve_name(self): def resolve_name(self):
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__))
addr = self.syms.resolve_name(os.path.join(script_dir, 'dummy'), addr = self.syms.resolve_name(os.path.join(script_dir, 'dummy'),
'some_function') self.mangled_name)
self.assertEqual(addr, self.addr) self.assertEqual(addr, self.addr)
pass pass
class TestDebuglink(Harness): class TestDebuglink(Harness):
def build_command(self): def build_command(self):
subprocess.check_output('gcc -o dummy dummy.c'.split()) subprocess.check_output('g++ -o dummy dummy.cc'.split())
lines = subprocess.check_output('nm dummy'.split()).splitlines()
for line in lines:
if "some_function" in line:
self.mangled_name = line.split(' ')[2]
break
self.assertTrue(self.mangled_name)
def debug_command(self): def debug_command(self):
subprocess.check_output('objcopy --add-gnu-debuglink=dummy.debug dummy' subprocess.check_output('objcopy --add-gnu-debuglink=dummy.debug dummy'
...@@ -76,9 +87,16 @@ class TestDebuglink(Harness): ...@@ -76,9 +87,16 @@ class TestDebuglink(Harness):
class TestBuildid(Harness): class TestBuildid(Harness):
def build_command(self): def build_command(self):
subprocess.check_output(('gcc -o dummy -Xlinker ' + \ subprocess.check_output(('g++ -o dummy -Xlinker ' + \
'--build-id=0x123456789abcdef0123456789abcdef012345678 dummy.c') '--build-id=0x123456789abcdef0123456789abcdef012345678 dummy.cc')
.split()) .split())
lines = subprocess.check_output('nm dummy'.split()).splitlines()
for line in lines:
if "some_function" in line:
self.mangled_name = line.split(' ')[2]
break
self.assertTrue(self.mangled_name)
def debug_command(self): def debug_command(self):
subprocess.check_output('mkdir -p /usr/lib/debug/.build-id/12'.split()) subprocess.check_output('mkdir -p /usr/lib/debug/.build-id/12'.split())
......
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