diff --git a/docs/reference_guide.md b/docs/reference_guide.md index 708806a600f0..ef33ab9b4935 100644 --- a/docs/reference_guide.md +++ b/docs/reference_guide.md @@ -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) - [Helpers](#helpers) - [1. ksym()](#1-ksym) - - [2. ksymaddr()](#2-ksymaddr) - - [3. ksymname()](#3-ksymname) - - [4. sym()](#4-sym) - - [5. num_open_kprobes()](#5-num_open_kprobes) + - [2. ksymname()](#2-ksymname) + - [3. sym()](#3-sym) + - [4. num_open_kprobes()](#4-num_open_kprobes) - [BPF Errors](#bpf-errors) - [1. Invalid mem access](#1-invalid-mem-access) @@ -1090,27 +1089,11 @@ Examples in situ: [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) -### 2. ksymaddr() - -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() +### 2. ksymname() 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: @@ -1122,11 +1105,11 @@ Examples in situ: [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) -### 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: @@ -1138,9 +1121,9 @@ Examples in situ: [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) -### 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. diff --git a/src/cc/bcc_syms.cc b/src/cc/bcc_syms.cc index ddbb5b93c8e3..ac9cc610f1a6 100644 --- a/src/cc/bcc_syms.cc +++ b/src/cc/bcc_syms.cc @@ -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; sym->name = (*it).name.c_str(); sym->demangle_name = sym->name; - sym->module = "[kernel]"; + sym->module = "kernel"; sym->offset = addr - (*it).addr; return true; } diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py index a5739ab35c4c..153f08ff25e2 100644 --- a/src/python/bcc/__init__.py +++ b/src/python/bcc/__init__.py @@ -27,7 +27,6 @@ from .libbcc import lib, _CB_TYPE, bcc_symbol, _SYM_CB_TYPE from .table import Table from .perf import Perf -from .usyms import ProcessSymbols from .utils import get_online_cpus _kprobe_limit = 1000 @@ -50,11 +49,24 @@ def __init__(self, pid): self.cache = lib.bcc_symcache_new(pid) 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() psym = ct.pointer(sym) if lib.bcc_symcache_resolve(self.cache, addr, psym) < 0: - return "[unknown]", 0 - return sym.demangle_name.decode(), sym.offset + 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()) def resolve_name(self, name): addr = ct.c_ulonglong() @@ -968,52 +980,49 @@ def _sym_cache(pid): return BPF._sym_caches[pid] @staticmethod - def sym(addr, pid): - """sym(addr, pid) + def sym(addr, pid, show_module=False, show_address=False): + """sym(addr, pid, show_module=False, show_address=False) 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. - """ - 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 - offset as a hexadecimal number, which is returned as a string. - A pid of less than zero will access the kernel symbol cache. + Example output when both show_module and show_address are True: + "start_thread+0x202 [libpthread-2.24.so]" + + Example output when both show_module and show_address are False: + "start_thread" """ - name, offset = BPF._sym_cache(pid).resolve(addr) - return "%s+0x%x" % (name, offset) + name, offset, module = BPF._sym_cache(pid).resolve(addr) + 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 - def ksym(addr): + def ksym(addr, show_module=False, show_address=False): """ksym(addr) Translate a kernel memory address into a kernel function name, which is - returned. - """ - return BPF.sym(addr, -1) - - @staticmethod - def ksymaddr(addr): - """ksymaddr(addr) + returned. When show_module is True, the module name ("kernel") is also + included. When show_address is true, the instruction offset as a + hexadecimal number is also included in the string. - Translate a kernel memory address into a kernel function name plus the - instruction offset as a hexidecimal number, which is returned as a - string. + Example output when both show_module and show_address are True: + "default_idle+0x0 [kernel]" """ - return BPF.symaddr(addr, -1) + return BPF.sym(addr, -1, show_module, show_address) @staticmethod def ksymname(name): """ksymname(name) 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) def num_open_kprobes(self):