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() {
}
}
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,6 +61,7 @@ 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();
if (demangle)
sym->demangle_name = sym->name;
sym->module = "kernel";
sym->offset = addr - (*it).addr;
......@@ -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);
......
......@@ -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);
......
......@@ -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);
};
......@@ -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):
......
......@@ -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)]
......
#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):
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())
......
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