diff --git a/src/attached_probe.cpp b/src/attached_probe.cpp index f1d2e6de4149..75a071e8c264 100644 --- a/src/attached_probe.cpp +++ b/src/attached_probe.cpp @@ -2,6 +2,7 @@ #define _GNU_SOURCE #endif +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include "attached_probe.h" #include "bpftrace.h" @@ -761,10 +763,14 @@ void AttachedProbe::load_prog(BPFfeature &feature) opts.expected_attach_type = static_cast<::bpf_attach_type>( libbpf::BPF_TRACE_ITER); - if (feature.has_kprobe_multi() && !probe_.funcs.empty()) + if (feature.has_kprobe_multi() && !probe_.funcs.empty() && probe_.type == ProbeType::kprobe) opts.expected_attach_type = static_cast<::bpf_attach_type>( libbpf::BPF_TRACE_KPROBE_MULTI); + if (feature.has_uprobe_multi() && !probe_.funcs.empty() && probe_.type == ProbeType::uprobe) + opts.expected_attach_type = static_cast<::bpf_attach_type>( + libbpf::BPF_TRACE_UPROBE_MULTI); + if (probe_.type == ProbeType::kfunc || probe_.type == ProbeType::kretfunc || probe_.type == ProbeType::iter) { @@ -960,8 +966,109 @@ void AttachedProbe::attach_kprobe(bool safe_mode) perf_event_fds_.push_back(perf_event_fd); } +struct bcc_sym_cb_data +{ + std::vector &syms; + std::set &offsets; +}; + +static int bcc_sym_cb(const char *symname, uint64_t start, uint64_t, void *p) +{ + struct bcc_sym_cb_data *data = static_cast(p); + std::vector &syms = data->syms; + + if (std::binary_search(syms.begin(), syms.end(), symname)) + { + data->offsets.insert(start); + } + + return 0; +} + +void AttachedProbe::attach_multi_uprobe(void) +{ + struct bcc_symbol_option option = {}; + std::vector syms; + unsigned int i; + int err; + + for (i = 0; i < probe_.funcs.size(); i++) + { + auto pos = probe_.funcs[i].find(':'); + + if (pos == std::string::npos) + { + throw std::runtime_error("Error resolving probe: '" + probe_.name + "'"); + } + + syms.push_back(probe_.funcs[i].c_str() + pos + 1); + } + + std::sort(std::begin(syms), std::end(syms)); + + option.use_debug_file = 1; + option.use_symbol_type = 0xffffffff; + + std::vector offsets; + std::set set; + struct bcc_sym_cb_data data = { + .syms = syms, + .offsets = set, + }; + + err = bcc_elf_foreach_sym(probe_.path.c_str(), bcc_sym_cb, &option, &data); + if (err) + { + throw std::runtime_error("Failed to list symbols for probe: '" + + probe_.name + "'"); + } + + for (auto a : set) + { + offsets.push_back(a); + } + + DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts); + + opts.uprobe_multi.path = probe_.path.c_str(); + opts.uprobe_multi.offsets = &offsets[0]; + opts.uprobe_multi.cnt = offsets.size(); + opts.uprobe_multi.flags = probe_.type == ProbeType::uretprobe + ? BPF_F_UPROBE_MULTI_RETURN + : 0; + if (bt_verbose) + { + std::cout << "Attaching to " << probe_.funcs.size() << " functions" + << std::endl; + + if (bt_verbose2) + { + for (i = 0; i < syms.size(); i++) + { + std::cout << probe_.path << ":" << syms[i] << std::endl; + } + } + } + + linkfd_ = bpf_link_create(progfd_, + 0, + static_cast( + libbpf::BPF_TRACE_UPROBE_MULTI), + &opts); + if (linkfd_ < 0) + { + throw std::runtime_error("Error attaching probe: '" + probe_.name + "'"); + } +} + void AttachedProbe::attach_uprobe(bool safe_mode) { + if (!probe_.funcs.empty()) + { + attach_multi_uprobe(); + return; + } + if (!resolve_offset_uprobe(safe_mode)) return; diff --git a/src/attached_probe.h b/src/attached_probe.h index f93da8e6e516..646ee43d6aa0 100644 --- a/src/attached_probe.h +++ b/src/attached_probe.h @@ -47,6 +47,7 @@ class AttachedProbe bool resolve_offset_uprobe(bool safe_mode); void load_prog(BPFfeature &feature); void attach_multi_kprobe(void); + void attach_multi_uprobe(void); void attach_kprobe(bool safe_mode); void attach_uprobe(bool safe_mode); diff --git a/src/bpftrace.cpp b/src/bpftrace.cpp index ee7e51529b7e..b54daa7f502e 100644 --- a/src/bpftrace.cpp +++ b/src/bpftrace.cpp @@ -166,6 +166,26 @@ int BPFtrace::add_probe(ast::Probe &p) resources.probes.push_back(probe); continue; } + + if (feature_->has_uprobe_multi() && has_wildcard(attach_point->func) && + !p.need_expansion && attach_funcs.size() && + (probetype(attach_point->provider) == ProbeType::uprobe || + probetype(attach_point->provider) == ProbeType::uretprobe)) + { + Probe probe; + probe.attach_point = attach_point->func; + probe.path = attach_point->target; + probe.type = probetype(attach_point->provider); + probe.log_size = log_size_; + probe.orig_name = p.name(); + probe.name = attach_point->name(attach_point->target, + attach_point->func); + probe.index = p.index(); + probe.funcs.assign(attach_funcs.begin(), attach_funcs.end()); + + resources.probes.push_back(probe); + continue; + } } else if ((probetype(attach_point->provider) == ProbeType::uprobe || probetype(attach_point->provider) == ProbeType::uretprobe ||