Skip to content

Commit

Permalink
Support attaching uprobe to offset (#2585)
Browse files Browse the repository at this point in the history
* Support attaching uprobe to offset
* C++ API support of attaching uprobe to offset
* Update document of attach_uprobe()
   The document is taken from src/python/bcc/__init__.py:attach_upobe()
  • Loading branch information
mmisono authored and yonghong-song committed Nov 8, 2019
1 parent 77fe428 commit 0429040
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 23 deletions.
9 changes: 7 additions & 2 deletions docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1106,9 +1106,14 @@ Examples in situ:

### 4. attach_uprobe()

Syntax: ```BPF.attach_uprobe(name="location", sym="symbol", fn_name="name")```
Syntax: ```BPF.attach_uprobe(name="location", sym="symbol", fn_name="name" [, sym_off=int])```, ```BPF.attach_uprobe(name="location", sym_re="regex", fn_name="name")```, ```BPF.attach_uprobe(name="location", addr=int, fn_name="name")```

Instruments the user-level function ```symbol()``` from either the library or binary named by ```location``` using user-level dynamic tracing of the function entry, and attach our C defined function ```name()``` to be called whenever the user-level function is called.

Instruments the user-level function ```symbol()``` from either the library or binary named by ```location``` using user-level dynamic tracing of the function entry, and attach our C defined function ```name()``` to be called whenever the user-level function is called. If ```sym_off``` is given, the function is attached to the offset within the symbol.

The real address ```addr``` may be supplied in place of ```sym```, in which case ```sym``` must be set to its default value. If the file is a non-PIE executable, ```addr``` must be a virtual address, otherwise it must be an offset relative to the file load address.

Instead of a symbol name, a regular expression can be provided in ```sym_re```. The uprobe will then attach to symbols that match the provided regular expression.

Libraries can be given in the name argument without the lib prefix, or with the full path (/usr/lib/...). Binaries can be given only with the full path (/bin/sh).

Expand Down
28 changes: 20 additions & 8 deletions src/cc/api/BPF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,18 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
const std::string& symbol,
const std::string& probe_func,
uint64_t symbol_addr,
bpf_probe_attach_type attach_type, pid_t pid) {
bpf_probe_attach_type attach_type, pid_t pid,
uint64_t symbol_offset) {

if (symbol_addr != 0 && symbol_offset != 0)
return StatusTuple(-1,
"Attachng uprobe with addr %lx and offset %lx is not supported",
symbol_addr, symbol_offset);

std::string module;
uint64_t offset;
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset));
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset,
symbol_offset));

std::string probe_event = get_uprobe_event(module, offset, attach_type, pid);
if (uprobes_.find(probe_event) != uprobes_.end())
Expand All @@ -217,9 +225,10 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
TRY2(unload_func(probe_func));
return StatusTuple(
-1,
"Unable to attach %suprobe for binary %s symbol %s addr %lx using %s\n",
"Unable to attach %suprobe for binary %s symbol %s addr %lx "
"offset %lx using %s\n",
attach_type_debug(attach_type).c_str(), binary_path.c_str(),
symbol.c_str(), symbol_addr, probe_func.c_str());
symbol.c_str(), symbol_addr, symbol_offset, probe_func.c_str());
}

open_probe_t p = {};
Expand Down Expand Up @@ -398,10 +407,12 @@ StatusTuple BPF::detach_kprobe(const std::string& kernel_func,

StatusTuple BPF::detach_uprobe(const std::string& binary_path,
const std::string& symbol, uint64_t symbol_addr,
bpf_probe_attach_type attach_type, pid_t pid) {
bpf_probe_attach_type attach_type, pid_t pid,
uint64_t symbol_offset) {
std::string module;
uint64_t offset;
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset));
TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset,
symbol_offset));

std::string event = get_uprobe_event(module, offset, attach_type, pid);
auto it = uprobes_.find(event);
Expand Down Expand Up @@ -601,7 +612,8 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
const std::string& symbol,
uint64_t symbol_addr,
std::string& module_res,
uint64_t& offset_res) {
uint64_t& offset_res,
uint64_t symbol_offset) {
bcc_symbol output;
int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
symbol_addr, -1, nullptr, &output);
Expand All @@ -616,7 +628,7 @@ StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
} else {
module_res = "";
}
offset_res = output.offset;
offset_res = output.offset + symbol_offset;
return StatusTuple(0);
}

Expand Down
9 changes: 6 additions & 3 deletions src/cc/api/BPF.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ class BPF {
const std::string& probe_func,
uint64_t symbol_addr = 0,
bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
pid_t pid = -1);
pid_t pid = -1,
uint64_t symbol_offset = 0);
StatusTuple detach_uprobe(const std::string& binary_path,
const std::string& symbol, uint64_t symbol_addr = 0,
bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
pid_t pid = -1);
pid_t pid = -1,
uint64_t symbol_offset = 0);
StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1);
StatusTuple detach_usdt(const USDT& usdt, pid_t pid = -1);

Expand Down Expand Up @@ -239,7 +241,8 @@ class BPF {
StatusTuple check_binary_symbol(const std::string& binary_path,
const std::string& symbol,
uint64_t symbol_addr, std::string& module_res,
uint64_t& offset_res);
uint64_t& offset_res,
uint64_t symbol_offset = 0);

int flag_;

Expand Down
2 changes: 1 addition & 1 deletion src/lua/bcc/bpf.lua
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ end
function Bpf:attach_uprobe(args)
Bpf.check_probe_quota(1)

local path, addr = Sym.check_path_symbol(args.name, args.sym, args.addr, args.pid)
local path, addr = Sym.check_path_symbol(args.name, args.sym, args.addr, args.pid, args.sym_off)
local fn = self:load_func(args.fn_name, 'BPF_PROG_TYPE_KPROBE')
local ptype = args.retprobe and "r" or "p"
local ev_name = string.format("%s_%s_0x%p", ptype, path:gsub("[^%a%d]", "_"), addr)
Expand Down
6 changes: 4 additions & 2 deletions src/lua/bcc/sym.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ local function create_cache(pid)
}
end

local function check_path_symbol(module, symname, addr, pid)
local function check_path_symbol(module, symname, addr, pid, sym_off)
local sym = SYM()
local module_path
local new_addr
if libbcc.bcc_resolve_symname(module, symname, addr or 0x0, pid or 0, nil, sym) < 0 then
if sym[0].module == nil then
error("could not find library '%s' in the library path" % module)
Expand All @@ -45,9 +46,10 @@ local function check_path_symbol(module, symname, addr, pid)
symname, module_path})
end
end
new_addr = sym[0].offset + (sym_off or 0)
module_path = ffi.string(sym[0].module)
libbcc.bcc_procutils_free(sym[0].module)
return module_path, sym[0].offset
return module_path, new_addr
end

return { create_cache=create_cache, check_path_symbol=check_path_symbol }
21 changes: 14 additions & 7 deletions src/python/bcc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ def remove_xdp(dev, flags=0):


@classmethod
def _check_path_symbol(cls, module, symname, addr, pid):
def _check_path_symbol(cls, module, symname, addr, pid, sym_off=0):
module = _assert_is_bytes(module)
symname = _assert_is_bytes(symname)
sym = bcc_symbol()
Expand All @@ -754,9 +754,10 @@ def _check_path_symbol(cls, module, symname, addr, pid):
ct.byref(sym),
) < 0:
raise Exception("could not determine address of symbol %s" % symname)
new_addr = sym.offset + sym_off
module_path = ct.cast(sym.module, ct.c_char_p).value
lib.bcc_procutils_free(sym.module)
return module_path, sym.offset
return module_path, new_addr

@staticmethod
def find_library(libname):
Expand Down Expand Up @@ -974,14 +975,16 @@ def _get_uprobe_evname(self, prefix, path, addr, pid):
return b"%s_%s_0x%x_%d" % (prefix, self._probe_repl.sub(b"_", path), addr, pid)

def attach_uprobe(self, name=b"", sym=b"", sym_re=b"", addr=None,
fn_name=b"", pid=-1):
fn_name=b"", pid=-1, sym_off=0):
"""attach_uprobe(name="", sym="", sym_re="", addr=None, fn_name=""
pid=-1)
pid=-1, sym_off=0)
Run the bpf function denoted by fn_name every time the symbol sym in
the library or binary 'name' is encountered. Optional parameters pid,
cpu, and group_fd can be used to filter the probe.
If sym_off is given, attach uprobe to offset within the symbol.
The real address addr may be supplied in place of sym, in which case sym
must be set to its default value. If the file is a non-PIE executable,
addr must be a virtual address, otherwise it must be an offset relative
Expand All @@ -1000,6 +1003,10 @@ def attach_uprobe(self, name=b"", sym=b"", sym_re=b"", addr=None,
BPF(text).attach_uprobe("/usr/bin/python", "main")
"""

assert sym_off >= 0
if addr is not None:
assert sym_off == 0, "offset with addr is not supported"

name = _assert_is_bytes(name)
sym = _assert_is_bytes(sym)
sym_re = _assert_is_bytes(sym_re)
Expand All @@ -1013,7 +1020,7 @@ def attach_uprobe(self, name=b"", sym=b"", sym_re=b"", addr=None,
fn_name=fn_name, pid=pid)
return

(path, addr) = BPF._check_path_symbol(name, sym, addr, pid)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid, sym_off)

self._check_probe_quota(1)
fn = self.load_func(fn_name, BPF.KPROBE)
Expand Down Expand Up @@ -1067,7 +1074,7 @@ def detach_uprobe_event(self, ev_name):
raise Exception("Failed to detach BPF from uprobe")
self._del_uprobe_fd(ev_name)

def detach_uprobe(self, name=b"", sym=b"", addr=None, pid=-1):
def detach_uprobe(self, name=b"", sym=b"", addr=None, pid=-1, sym_off=0):
"""detach_uprobe(name="", sym="", addr=None, pid=-1)
Stop running a bpf function that is attached to symbol 'sym' in library
Expand All @@ -1076,7 +1083,7 @@ def detach_uprobe(self, name=b"", sym=b"", addr=None, pid=-1):

name = _assert_is_bytes(name)
sym = _assert_is_bytes(sym)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid)
(path, addr) = BPF._check_path_symbol(name, sym, addr, pid, sym_off)
ev_name = self._get_uprobe_evname(b"p", path, addr, pid)
self.detach_uprobe_event(ev_name)

Expand Down

0 comments on commit 0429040

Please sign in to comment.