Add an option to resolve address without demangling (#1084)
authorTeng Qin <palmtenor@gmail.com>
Sat, 1 Apr 2017 15:00:23 +0000 (08:00 -0700)
committerSasha Goldshtein <goldshtn@gmail.com>
Sat, 1 Apr 2017 15:00:23 +0000 (18:00 +0300)
* Add an option to resolve address without demangling

* Expose new no-demangling option to Python

src/cc/bcc_syms.cc
src/cc/bcc_syms.h
src/cc/syms.h
src/python/bcc/__init__.py
src/python/bcc/libbcc.py
tests/python/dummy.c [deleted file]
tests/python/dummy.cc [new file with mode: 0644]
tests/python/test_debuginfo.py

index f02056c..3e2bb22 100644 (file)
@@ -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);
index 5cb7409..218fd85 100644 (file)
@@ -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);
index 8e089f4..68ead03 100644 (file)
@@ -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);
 };
index 5ad8929..c0cfba3 100644 (file)
@@ -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):
index 77226b5..19bdb06 100644 (file)
@@ -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 (file)
index 8a3ced2..0000000
+++ /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 (file)
index 0000000..bf39faa
--- /dev/null
@@ -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;
+}
index 152bc20..c82a7fa 100755 (executable)
@@ -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())