Commit febed330 authored by Sasha Goldshtein's avatar Sasha Goldshtein

Simplify BCC symbol resolution API

The new API has two main methods: `sym` and `ksym` (the second is
a trivial wrapper of the first one). Both methods accept two
Boolean flags arguments: `show_module` and `show_address`. The first
controls whether the resulting symbol name should contain the name
of the symbol's module, in brackets. For kernel symbols, this is
simply "[kernel]". The second controls whether the resulting symbol
name should contain the instruction offset from the beginning of
the symbol, e.g. "start_thread+0x202".
parent 98f5d4e7
...@@ -65,10 +65,9 @@ This guide is incomplete. If something feels missing, check the bcc and kernel s ...@@ -65,10 +65,9 @@ This guide is incomplete. If something feels missing, check the bcc and kernel s
- [7. print_linear_hist()](#6-print_linear_hist) - [7. print_linear_hist()](#6-print_linear_hist)
- [Helpers](#helpers) - [Helpers](#helpers)
- [1. ksym()](#1-ksym) - [1. ksym()](#1-ksym)
- [2. ksymaddr()](#2-ksymaddr) - [2. ksymname()](#2-ksymname)
- [3. ksymname()](#3-ksymname) - [3. sym()](#3-sym)
- [4. sym()](#4-sym) - [4. num_open_kprobes()](#4-num_open_kprobes)
- [5. num_open_kprobes()](#5-num_open_kprobes)
- [BPF Errors](#bpf-errors) - [BPF Errors](#bpf-errors)
- [1. Invalid mem access](#1-invalid-mem-access) - [1. Invalid mem access](#1-invalid-mem-access)
...@@ -1090,27 +1089,11 @@ Examples in situ: ...@@ -1090,27 +1089,11 @@ Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=ksym+path%3Aexamples+language%3Apython&type=Code), [search /examples](https://github.com/iovisor/bcc/search?q=ksym+path%3Aexamples+language%3Apython&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=ksym+path%3Atools+language%3Apython&type=Code) [search /tools](https://github.com/iovisor/bcc/search?q=ksym+path%3Atools+language%3Apython&type=Code)
### 2. ksymaddr() ### 2. ksymname()
Syntax: ```BPF.ksymaddr(addr)```
Translate a kernel memory address into a kernel function name plus the instruction offset as a hexadecimal number, which is returned as a string.
Example:
```Python
print("kernel function+offset: " + b.ksymaddr(addr))
```
Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=ksymaddr+path%3Aexamples+language%3Apython&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=ksymaddr+path%3Atools+language%3Apython&type=Code)
### 3. ksymname()
Syntax: ```BPF.ksymname(name)``` Syntax: ```BPF.ksymname(name)```
Translate a kernel name into an address. This is the reverse of ksymaddr. Returns -1 when the function name is unknown. Translate a kernel name into an address. This is the reverse of ksym. Returns -1 when the function name is unknown.
Example: Example:
...@@ -1122,11 +1105,11 @@ Examples in situ: ...@@ -1122,11 +1105,11 @@ Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=ksymname+path%3Aexamples+language%3Apython&type=Code), [search /examples](https://github.com/iovisor/bcc/search?q=ksymname+path%3Aexamples+language%3Apython&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=ksymname+path%3Atools+language%3Apython&type=Code) [search /tools](https://github.com/iovisor/bcc/search?q=ksymname+path%3Atools+language%3Apython&type=Code)
### 4. sym() ### 3. sym()
Syntax: ```BPF.sym(addr, pid)``` Syntax: ```BPF.sym(addr, pid, show_module=False, show_address=True)```
Translate a memory address into a function name for a pid, which is returned. A pid of less than zero will access the kernel symbol cache. Translate a memory address into a function name for a pid, which is returned. A pid of less than zero will access the kernel symbol cache. The `show_module` and `show_address` parameters control whether the module in which the symbol lies should be displayed, and whether the instruction offset from the beginning of the symbol should be displayed. These extra parameters default to `False`.
Example: Example:
...@@ -1138,9 +1121,9 @@ Examples in situ: ...@@ -1138,9 +1121,9 @@ Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=sym+path%3Aexamples+language%3Apython&type=Code), [search /examples](https://github.com/iovisor/bcc/search?q=sym+path%3Aexamples+language%3Apython&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=sym+path%3Atools+language%3Apython&type=Code) [search /tools](https://github.com/iovisor/bcc/search?q=sym+path%3Atools+language%3Apython&type=Code)
### 5. num_open_kprobes() ### 4. num_open_kprobes()
Syntax: ```BPF.num_open_probes()``` Syntax: ```BPF.num_open_kprobes()```
Returns the number of open k[ret]probes. Can be useful for scenarios where event_re is used while attaching and detaching probes. Excludes perf_events readers. Returns the number of open k[ret]probes. Can be useful for scenarios where event_re is used while attaching and detaching probes. Excludes perf_events readers.
......
...@@ -62,7 +62,7 @@ bool KSyms::resolve_addr(uint64_t addr, struct bcc_symbol *sym) { ...@@ -62,7 +62,7 @@ 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; 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;
} }
......
...@@ -27,7 +27,6 @@ basestring = (unicode if sys.version_info[0] < 3 else str) ...@@ -27,7 +27,6 @@ basestring = (unicode if sys.version_info[0] < 3 else str)
from .libbcc import lib, _CB_TYPE, bcc_symbol, _SYM_CB_TYPE from .libbcc import lib, _CB_TYPE, bcc_symbol, _SYM_CB_TYPE
from .table import Table from .table import Table
from .perf import Perf from .perf import Perf
from .usyms import ProcessSymbols
from .utils import get_online_cpus from .utils import get_online_cpus
_kprobe_limit = 1000 _kprobe_limit = 1000
...@@ -50,11 +49,24 @@ class SymbolCache(object): ...@@ -50,11 +49,24 @@ class SymbolCache(object):
self.cache = lib.bcc_symcache_new(pid) self.cache = lib.bcc_symcache_new(pid)
def resolve(self, addr): def resolve(self, addr):
"""
Return a tuple of the symbol (function), its offset from the beginning
of the function, and the module in which it lies. For example:
("start_thread", 0x202, "/usr/lib/.../libpthread-2.24.so")
If the symbol cannot be found but we know which module it is in,
return the module name and the offset from the beginning of the
module. If we don't even know the module, return the absolute
address as the offset.
"""
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 lib.bcc_symcache_resolve(self.cache, addr, psym) < 0:
return "[unknown]", 0 if sym.module and sym.offset:
return sym.demangle_name.decode(), 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())
def resolve_name(self, name): def resolve_name(self, name):
addr = ct.c_ulonglong() addr = ct.c_ulonglong()
...@@ -968,52 +980,49 @@ class BPF(object): ...@@ -968,52 +980,49 @@ class BPF(object):
return BPF._sym_caches[pid] return BPF._sym_caches[pid]
@staticmethod @staticmethod
def sym(addr, pid): def sym(addr, pid, show_module=False, show_address=False):
"""sym(addr, pid) """sym(addr, pid, show_module=False, show_address=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
returned. returned. When show_module is True, the module name is also included.
When show_address is True, the instruction offset as a hexadecimal
number is also included in the string.
A pid of less than zero will access the kernel symbol cache. A pid of less than zero will access the kernel symbol cache.
"""
name, _ = BPF._sym_cache(pid).resolve(addr)
return name
@staticmethod
def symaddr(addr, pid):
"""symaddr(addr, pid)
Translate a memory address into a function name plus the instruction Example output when both show_module and show_address are True:
offset as a hexadecimal number, which is returned as a string. "start_thread+0x202 [libpthread-2.24.so]"
A pid of less than zero will access the kernel symbol cache.
Example output when both show_module and show_address are False:
"start_thread"
""" """
name, offset = BPF._sym_cache(pid).resolve(addr) name, offset, module = BPF._sym_cache(pid).resolve(addr)
return "%s+0x%x" % (name, offset) offset = "+0x%x" % offset if show_address and name is not None else ""
name = name or "[unknown]"
name = name + offset
module = " [%s]" % os.path.basename(module) if show_module else ""
return name + module
@staticmethod @staticmethod
def ksym(addr): def ksym(addr, show_module=False, show_address=False):
"""ksym(addr) """ksym(addr)
Translate a kernel memory address into a kernel function name, which is Translate a kernel memory address into a kernel function name, which is
returned. returned. When show_module is True, the module name ("kernel") is also
""" included. When show_address is true, the instruction offset as a
return BPF.sym(addr, -1) hexadecimal number is also included in the string.
@staticmethod
def ksymaddr(addr):
"""ksymaddr(addr)
Translate a kernel memory address into a kernel function name plus the Example output when both show_module and show_address are True:
instruction offset as a hexidecimal number, which is returned as a "default_idle+0x0 [kernel]"
string.
""" """
return BPF.symaddr(addr, -1) return BPF.sym(addr, -1, show_module, show_address)
@staticmethod @staticmethod
def ksymname(name): def ksymname(name):
"""ksymname(name) """ksymname(name)
Translate a kernel name into an address. This is the reverse of Translate a kernel name into an address. This is the reverse of
ksymaddr. Returns -1 when the function name is unknown.""" ksym. Returns -1 when the function name is unknown."""
return BPF._sym_cache(-1).resolve_name(name) return BPF._sym_cache(-1).resolve_name(name)
def num_open_kprobes(self): def num_open_kprobes(self):
......
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