From 9e718f5a2b10cb9e12bf4628d7d0228ccad8b734 Mon Sep 17 00:00:00 2001 From: Teng Qin <palmtenor@gmail.com> Date: Sat, 1 Apr 2017 08:00:23 -0700 Subject: [PATCH] Add an option to resolve address without demangling (#1084) * Add an option to resolve address without demangling * Expose new no-demangling option to Python --- src/cc/bcc_syms.cc | 20 +++++++++++++++----- src/cc/bcc_syms.h | 5 ++++- src/cc/syms.h | 6 +++--- src/python/bcc/__init__.py | 19 ++++++++++++------- src/python/bcc/libbcc.py | 3 +++ tests/python/dummy.c | 15 --------------- tests/python/dummy.cc | 17 +++++++++++++++++ tests/python/test_debuginfo.py | 30 ++++++++++++++++++++++++------ 8 files changed, 78 insertions(+), 37 deletions(-) delete mode 100644 tests/python/dummy.c create mode 100644 tests/python/dummy.cc diff --git a/src/cc/bcc_syms.cc b/src/cc/bcc_syms.cc index f02056c2..3e2bb22b 100644 --- a/src/cc/bcc_syms.cc +++ b/src/cc/bcc_syms.cc @@ -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(); if (syms_.empty()) { @@ -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; sym->name = (*it).name.c_str(); - sym->demangle_name = sym->name; + if (demangle) + sym->demangle_name = sym->name; sym->module = "kernel"; sym->offset = addr - (*it).addr; return true; @@ -135,7 +136,8 @@ int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end, 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()) refresh(); @@ -148,8 +150,10 @@ bool ProcSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { for (Module &mod : modules_) { if (mod.contains(addr)) { bool res = mod.find_addr(addr, sym); - if (sym->name) { - sym->demangle_name = abi::__cxa_demangle(sym->name, nullptr, nullptr, nullptr); + if (demangle) { + if (sym->name) + sym->demangle_name = + abi::__cxa_demangle(sym->name, nullptr, nullptr, nullptr); if (!sym->demangle_name) sym->demangle_name = sym->name; } @@ -309,6 +313,12 @@ int bcc_symcache_resolve(void *resolver, uint64_t addr, 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, const char *name, uint64_t *addr) { SymbolCache *cache = static_cast<SymbolCache *>(resolver); diff --git a/src/cc/bcc_syms.h b/src/cc/bcc_syms.h index 5cb7409c..218fd858 100644 --- a/src/cc/bcc_syms.h +++ b/src/cc/bcc_syms.h @@ -29,12 +29,15 @@ struct bcc_symbol { 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_free_symcache(void *symcache, int pid); 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, const char *name, uint64_t *addr); void bcc_symcache_refresh(void *resolver); diff --git a/src/cc/syms.h b/src/cc/syms.h index 8e089f42..68ead031 100644 --- a/src/cc/syms.h +++ b/src/cc/syms.h @@ -39,7 +39,7 @@ public: virtual ~SymbolCache() = default; 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, uint64_t *addr) = 0; }; @@ -58,7 +58,7 @@ class KSyms : SymbolCache { static void _add_symbol(const char *, uint64_t, void *); 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, uint64_t *addr); virtual void refresh(); @@ -116,7 +116,7 @@ class ProcSyms : SymbolCache { public: ProcSyms(int pid); 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, uint64_t *addr); }; diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py index 5ad8929d..c0cfba38 100644 --- a/src/python/bcc/__init__.py +++ b/src/python/bcc/__init__.py @@ -48,7 +48,7 @@ class SymbolCache(object): def __init__(self, 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 of the function, and the module in which it lies. For example: @@ -60,13 +60,18 @@ class SymbolCache(object): """ sym = bcc_symbol() 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: return (None, sym.offset, ct.cast(sym.module, ct.c_char_p).value.decode()) return (None, addr, None) - return (sym.demangle_name.decode(), sym.offset, - ct.cast(sym.module, ct.c_char_p).value.decode()) + return ( + 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): addr = ct.c_ulonglong() @@ -989,7 +994,7 @@ class BPF(object): return BPF._sym_caches[pid] @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) Translate a memory address into a function name for a pid, which is @@ -1005,7 +1010,7 @@ class BPF(object): Example output when both show_module and show_offset are False: "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 "" name = name or "[unknown]" name = name + offset @@ -1025,7 +1030,7 @@ class BPF(object): Example output when both show_module and show_offset are True: "default_idle+0x0 [kernel]" """ - return BPF.sym(addr, -1, show_module, show_offset) + return BPF.sym(addr, -1, show_module, show_offset, False) @staticmethod def ksymname(name): diff --git a/src/python/bcc/libbcc.py b/src/python/bcc/libbcc.py index 77226b54..19bdb068 100644 --- a/src/python/bcc/libbcc.py +++ b/src/python/bcc/libbcc.py @@ -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.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.argtypes = [ ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.POINTER(ct.c_ulonglong)] diff --git a/tests/python/dummy.c b/tests/python/dummy.c deleted file mode 100644 index 8a3ced2a..00000000 --- a/tests/python/dummy.c +++ /dev/null @@ -1,15 +0,0 @@ -#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; -} diff --git a/tests/python/dummy.cc b/tests/python/dummy.cc new file mode 100644 index 00000000..bf39faa3 --- /dev/null +++ b/tests/python/dummy.cc @@ -0,0 +1,17 @@ +#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; +} diff --git a/tests/python/test_debuginfo.py b/tests/python/test_debuginfo.py index 152bc20c..c82a7fa8 100755 --- a/tests/python/test_debuginfo.py +++ b/tests/python/test_debuginfo.py @@ -44,21 +44,32 @@ class Harness(TestCase): self.process.wait() def resolve_addr(self): - sym, offset, module = self.syms.resolve(self.addr) - self.assertEqual(sym, 'some_function') + sym, offset, module = self.syms.resolve(self.addr, False) + 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.assertTrue(module[-5:] == 'dummy') + def resolve_name(self): script_dir = os.path.dirname(os.path.realpath(__file__)) addr = self.syms.resolve_name(os.path.join(script_dir, 'dummy'), - 'some_function') + self.mangled_name) self.assertEqual(addr, self.addr) pass class TestDebuglink(Harness): 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): subprocess.check_output('objcopy --add-gnu-debuglink=dummy.debug dummy' @@ -76,9 +87,16 @@ class TestDebuglink(Harness): class TestBuildid(Harness): def build_command(self): - subprocess.check_output(('gcc -o dummy -Xlinker ' + \ - '--build-id=0x123456789abcdef0123456789abcdef012345678 dummy.c') + subprocess.check_output(('g++ -o dummy -Xlinker ' + \ + '--build-id=0x123456789abcdef0123456789abcdef012345678 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): subprocess.check_output('mkdir -p /usr/lib/debug/.build-id/12'.split()) -- 2.30.9