Home | History | Annotate | Download | only in api
      1 /*
      2  * Copyright (c) 2016 Facebook, Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <linux/bpf.h>
     18 #include <linux/perf_event.h>
     19 #include <unistd.h>
     20 #include <cstdio>
     21 #include <cstring>
     22 #include <exception>
     23 #include <iostream>
     24 #include <memory>
     25 #include <sstream>
     26 #include <utility>
     27 #include <vector>
     28 
     29 #include "bcc_exception.h"
     30 #include "bcc_syms.h"
     31 #include "bpf_module.h"
     32 #include "common.h"
     33 #include "libbpf.h"
     34 #include "perf_reader.h"
     35 #include "syms.h"
     36 #include "table_storage.h"
     37 #include "usdt.h"
     38 
     39 #include "BPF.h"
     40 
     41 namespace ebpf {
     42 
     43 std::string uint_to_hex(uint64_t value) {
     44   std::stringstream ss;
     45   ss << std::hex << value;
     46   return ss.str();
     47 }
     48 
     49 std::string sanitize_str(std::string str, bool (*validator)(char),
     50                          char replacement = '_') {
     51   for (size_t i = 0; i < str.length(); i++)
     52     if (!validator(str[i]))
     53       str[i] = replacement;
     54   return str;
     55 }
     56 
     57 StatusTuple BPF::init(const std::string& bpf_program,
     58                       const std::vector<std::string>& cflags,
     59                       const std::vector<USDT>& usdt) {
     60   std::string all_bpf_program;
     61 
     62   usdt_.reserve(usdt.size());
     63   for (const auto& u : usdt) {
     64     usdt_.emplace_back(u);
     65   }
     66   for (auto& u : usdt_) {
     67     TRY2(u.init());
     68     all_bpf_program += u.program_text_;
     69   }
     70 
     71   auto flags_len = cflags.size();
     72   const char* flags[flags_len];
     73   for (size_t i = 0; i < flags_len; i++)
     74     flags[i] = cflags[i].c_str();
     75 
     76   all_bpf_program += bpf_program;
     77   if (bpf_module_->load_string(all_bpf_program, flags, flags_len) != 0)
     78     return StatusTuple(-1, "Unable to initialize BPF program");
     79 
     80   return StatusTuple(0);
     81 };
     82 
     83 BPF::~BPF() {
     84   auto res = detach_all();
     85   if (res.code() != 0)
     86     std::cerr << "Failed to detach all probes on destruction: " << std::endl
     87               << res.msg() << std::endl;
     88 }
     89 
     90 StatusTuple BPF::detach_all() {
     91   bool has_error = false;
     92   std::string error_msg;
     93 
     94   for (auto& it : kprobes_) {
     95     auto res = detach_kprobe_event(it.first, it.second);
     96     if (res.code() != 0) {
     97       error_msg += "Failed to detach kprobe event " + it.first + ": ";
     98       error_msg += res.msg() + "\n";
     99       has_error = true;
    100     }
    101   }
    102 
    103   for (auto& it : uprobes_) {
    104     auto res = detach_uprobe_event(it.first, it.second);
    105     if (res.code() != 0) {
    106       error_msg += "Failed to detach uprobe event " + it.first + ": ";
    107       error_msg += res.msg() + "\n";
    108       has_error = true;
    109     }
    110   }
    111 
    112   for (auto& it : tracepoints_) {
    113     auto res = detach_tracepoint_event(it.first, it.second);
    114     if (res.code() != 0) {
    115       error_msg += "Failed to detach Tracepoint " + it.first + ": ";
    116       error_msg += res.msg() + "\n";
    117       has_error = true;
    118     }
    119   }
    120 
    121   for (auto& it : perf_buffers_) {
    122     auto res = it.second->close_all_cpu();
    123     if (res.code() != 0) {
    124       error_msg += "Failed to close perf buffer " + it.first + ": ";
    125       error_msg += res.msg() + "\n";
    126       has_error = true;
    127     }
    128     delete it.second;
    129   }
    130 
    131   for (auto& it : perf_event_arrays_) {
    132     auto res = it.second->close_all_cpu();
    133     if (res.code() != 0) {
    134       error_msg += "Failed to close perf event array " + it.first + ": ";
    135       error_msg += res.msg() + "\n";
    136       has_error = true;
    137     }
    138     delete it.second;
    139   }
    140 
    141   for (auto& it : perf_events_) {
    142     auto res = detach_perf_event_all_cpu(it.second);
    143     if (res.code() != 0) {
    144       error_msg += res.msg() + "\n";
    145       has_error = true;
    146     }
    147   }
    148 
    149   for (auto& it : funcs_) {
    150     int res = close(it.second);
    151     if (res != 0) {
    152       error_msg += "Failed to unload BPF program for " + it.first + ": ";
    153       error_msg += std::string(std::strerror(errno)) + "\n";
    154       has_error = true;
    155     }
    156   }
    157 
    158   if (has_error)
    159     return StatusTuple(-1, error_msg);
    160   else
    161     return StatusTuple(0);
    162 }
    163 
    164 StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
    165                                const std::string& probe_func,
    166                                uint64_t kernel_func_offset,
    167                                bpf_probe_attach_type attach_type) {
    168   std::string probe_event = get_kprobe_event(kernel_func, attach_type);
    169   if (kprobes_.find(probe_event) != kprobes_.end())
    170     return StatusTuple(-1, "kprobe %s already attached", probe_event.c_str());
    171 
    172   int probe_fd;
    173   TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
    174 
    175   int res_fd = bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(),
    176                                  kernel_func.c_str(), kernel_func_offset);
    177 
    178   if (res_fd < 0) {
    179     TRY2(unload_func(probe_func));
    180     return StatusTuple(-1, "Unable to attach %skprobe for %s using %s",
    181                        attach_type_debug(attach_type).c_str(),
    182                        kernel_func.c_str(), probe_func.c_str());
    183   }
    184 
    185   open_probe_t p = {};
    186   p.perf_event_fd = res_fd;
    187   p.func = probe_func;
    188   kprobes_[probe_event] = std::move(p);
    189   return StatusTuple(0);
    190 }
    191 
    192 StatusTuple BPF::attach_uprobe(const std::string& binary_path,
    193                                const std::string& symbol,
    194                                const std::string& probe_func,
    195                                uint64_t symbol_addr,
    196                                bpf_probe_attach_type attach_type, pid_t pid) {
    197   std::string module;
    198   uint64_t offset;
    199   TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset));
    200 
    201   std::string probe_event = get_uprobe_event(module, offset, attach_type, pid);
    202   if (uprobes_.find(probe_event) != uprobes_.end())
    203     return StatusTuple(-1, "uprobe %s already attached", probe_event.c_str());
    204 
    205   int probe_fd;
    206   TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
    207 
    208   int res_fd = bpf_attach_uprobe(probe_fd, attach_type, probe_event.c_str(),
    209                                  binary_path.c_str(), offset, pid);
    210 
    211   if (res_fd < 0) {
    212     TRY2(unload_func(probe_func));
    213     return StatusTuple(
    214         -1,
    215         "Unable to attach %suprobe for binary %s symbol %s addr %lx using %s\n",
    216         attach_type_debug(attach_type).c_str(), binary_path.c_str(),
    217         symbol.c_str(), symbol_addr, probe_func.c_str());
    218   }
    219 
    220   open_probe_t p = {};
    221   p.perf_event_fd = res_fd;
    222   p.func = probe_func;
    223   uprobes_[probe_event] = std::move(p);
    224   return StatusTuple(0);
    225 }
    226 
    227 StatusTuple BPF::attach_usdt(const USDT& usdt, pid_t pid) {
    228   for (const auto& u : usdt_) {
    229     if (u == usdt) {
    230       auto& probe = *static_cast<::USDT::Probe*>(u.probe_.get());
    231       if (!probe.enable(u.probe_func_))
    232         return StatusTuple(-1, "Unable to enable USDT " + u.print_name());
    233 
    234       bool failed = false;
    235       std::string err_msg;
    236       int cnt = 0;
    237       for (const auto& loc : probe.locations_) {
    238         auto res = attach_uprobe(loc.bin_path_, std::string(), u.probe_func_,
    239                                  loc.address_, BPF_PROBE_ENTRY, pid);
    240         if (res.code() != 0) {
    241           failed = true;
    242           err_msg += "USDT " + u.print_name() + " at " + loc.bin_path_ +
    243                      " address " + std::to_string(loc.address_);
    244           err_msg += ": " + res.msg() + "\n";
    245           break;
    246         }
    247         cnt++;
    248       }
    249       if (failed) {
    250         for (int i = 0; i < cnt; i++) {
    251           auto res =
    252               detach_uprobe(probe.locations_[i].bin_path_, std::string(),
    253                             probe.locations_[i].address_, BPF_PROBE_ENTRY, pid);
    254           if (res.code() != 0)
    255             err_msg += "During clean up: " + res.msg() + "\n";
    256         }
    257         return StatusTuple(-1, err_msg);
    258       } else {
    259         return StatusTuple(0);
    260       }
    261     }
    262   }
    263 
    264   return StatusTuple(-1, "USDT %s not found", usdt.print_name().c_str());
    265 }
    266 
    267 StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
    268                                    const std::string& probe_func) {
    269   if (tracepoints_.find(tracepoint) != tracepoints_.end())
    270     return StatusTuple(-1, "Tracepoint %s already attached",
    271                        tracepoint.c_str());
    272 
    273   auto pos = tracepoint.find(":");
    274   if ((pos == std::string::npos) || (pos != tracepoint.rfind(":")))
    275     return StatusTuple(-1, "Unable to parse Tracepoint %s", tracepoint.c_str());
    276   std::string tp_category = tracepoint.substr(0, pos);
    277   std::string tp_name = tracepoint.substr(pos + 1);
    278 
    279   int probe_fd;
    280   TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
    281 
    282   int res_fd =
    283       bpf_attach_tracepoint(probe_fd, tp_category.c_str(), tp_name.c_str());
    284 
    285   if (res_fd < 0) {
    286     TRY2(unload_func(probe_func));
    287     return StatusTuple(-1, "Unable to attach Tracepoint %s using %s",
    288                        tracepoint.c_str(), probe_func.c_str());
    289   }
    290 
    291   open_probe_t p = {};
    292   p.perf_event_fd = res_fd;
    293   p.func = probe_func;
    294   tracepoints_[tracepoint] = std::move(p);
    295   return StatusTuple(0);
    296 }
    297 
    298 StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config,
    299                                    const std::string& probe_func,
    300                                    uint64_t sample_period, uint64_t sample_freq,
    301                                    pid_t pid, int cpu, int group_fd) {
    302   auto ev_pair = std::make_pair(ev_type, ev_config);
    303   if (perf_events_.find(ev_pair) != perf_events_.end())
    304     return StatusTuple(-1, "Perf event type %d config %d already attached",
    305                        ev_type, ev_config);
    306 
    307   int probe_fd;
    308   TRY2(load_func(probe_func, BPF_PROG_TYPE_PERF_EVENT, probe_fd));
    309 
    310   std::vector<int> cpus;
    311   if (cpu >= 0)
    312     cpus.push_back(cpu);
    313   else
    314     cpus = get_online_cpus();
    315   auto fds = new std::vector<std::pair<int, int>>();
    316   fds->reserve(cpus.size());
    317   for (int i : cpus) {
    318     int fd = bpf_attach_perf_event(probe_fd, ev_type, ev_config, sample_period,
    319                                    sample_freq, pid, i, group_fd);
    320     if (fd < 0) {
    321       for (const auto& it : *fds)
    322         close(it.second);
    323       delete fds;
    324       TRY2(unload_func(probe_func));
    325       return StatusTuple(-1, "Failed to attach perf event type %d config %d",
    326                          ev_type, ev_config);
    327     }
    328     fds->emplace_back(i, fd);
    329   }
    330 
    331   open_probe_t p = {};
    332   p.func = probe_func;
    333   p.per_cpu_fd = fds;
    334   perf_events_[ev_pair] = std::move(p);
    335   return StatusTuple(0);
    336 }
    337 
    338 StatusTuple BPF::attach_perf_event_raw(void* perf_event_attr,
    339                                        const std::string& probe_func, pid_t pid,
    340                                        int cpu, int group_fd,
    341                                        unsigned long extra_flags) {
    342   auto attr = static_cast<struct perf_event_attr*>(perf_event_attr);
    343   auto ev_pair = std::make_pair(attr->type, attr->config);
    344   if (perf_events_.find(ev_pair) != perf_events_.end())
    345     return StatusTuple(-1, "Perf event type %d config %d already attached",
    346                        attr->type, attr->config);
    347 
    348   int probe_fd;
    349   TRY2(load_func(probe_func, BPF_PROG_TYPE_PERF_EVENT, probe_fd));
    350 
    351   std::vector<int> cpus;
    352   if (cpu >= 0)
    353     cpus.push_back(cpu);
    354   else
    355     cpus = get_online_cpus();
    356   auto fds = new std::vector<std::pair<int, int>>();
    357   fds->reserve(cpus.size());
    358   for (int i : cpus) {
    359     int fd = bpf_attach_perf_event_raw(probe_fd, attr, pid, i, group_fd,
    360                                        extra_flags);
    361     if (fd < 0) {
    362       for (const auto& it : *fds)
    363         close(it.second);
    364       delete fds;
    365       TRY2(unload_func(probe_func));
    366       return StatusTuple(-1, "Failed to attach perf event type %d config %d",
    367                          attr->type, attr->config);
    368     }
    369     fds->emplace_back(i, fd);
    370   }
    371 
    372   open_probe_t p = {};
    373   p.func = probe_func;
    374   p.per_cpu_fd = fds;
    375   perf_events_[ev_pair] = std::move(p);
    376   return StatusTuple(0);
    377 }
    378 
    379 StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
    380                                bpf_probe_attach_type attach_type) {
    381   std::string event = get_kprobe_event(kernel_func, attach_type);
    382 
    383   auto it = kprobes_.find(event);
    384   if (it == kprobes_.end())
    385     return StatusTuple(-1, "No open %skprobe for %s",
    386                        attach_type_debug(attach_type).c_str(),
    387                        kernel_func.c_str());
    388 
    389   TRY2(detach_kprobe_event(it->first, it->second));
    390   kprobes_.erase(it);
    391   return StatusTuple(0);
    392 }
    393 
    394 StatusTuple BPF::detach_uprobe(const std::string& binary_path,
    395                                const std::string& symbol, uint64_t symbol_addr,
    396                                bpf_probe_attach_type attach_type, pid_t pid) {
    397   std::string module;
    398   uint64_t offset;
    399   TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset));
    400 
    401   std::string event = get_uprobe_event(module, offset, attach_type, pid);
    402   auto it = uprobes_.find(event);
    403   if (it == uprobes_.end())
    404     return StatusTuple(-1, "No open %suprobe for binary %s symbol %s addr %lx",
    405                        attach_type_debug(attach_type).c_str(),
    406                        binary_path.c_str(), symbol.c_str(), symbol_addr);
    407 
    408   TRY2(detach_uprobe_event(it->first, it->second));
    409   uprobes_.erase(it);
    410   return StatusTuple(0);
    411 }
    412 
    413 StatusTuple BPF::detach_usdt(const USDT& usdt, pid_t pid) {
    414   for (const auto& u : usdt_) {
    415     if (u == usdt) {
    416       auto& probe = *static_cast<::USDT::Probe*>(u.probe_.get());
    417       bool failed = false;
    418       std::string err_msg;
    419       for (const auto& loc : probe.locations_) {
    420         auto res = detach_uprobe(loc.bin_path_, std::string(), loc.address_,
    421                                  BPF_PROBE_ENTRY, pid);
    422         if (res.code() != 0) {
    423           failed = true;
    424           err_msg += "USDT " + u.print_name() + " at " + loc.bin_path_ +
    425                      " address " + std::to_string(loc.address_);
    426           err_msg += ": " + res.msg() + "\n";
    427         }
    428       }
    429 
    430       if (!probe.disable()) {
    431         failed = true;
    432         err_msg += "Unable to disable USDT " + u.print_name();
    433       }
    434 
    435       if (failed)
    436         return StatusTuple(-1, err_msg);
    437       else
    438         return StatusTuple(0);
    439     }
    440   }
    441 
    442   return StatusTuple(-1, "USDT %s not found", usdt.print_name().c_str());
    443 }
    444 
    445 StatusTuple BPF::detach_tracepoint(const std::string& tracepoint) {
    446   auto it = tracepoints_.find(tracepoint);
    447   if (it == tracepoints_.end())
    448     return StatusTuple(-1, "No open Tracepoint %s", tracepoint.c_str());
    449 
    450   TRY2(detach_tracepoint_event(it->first, it->second));
    451   tracepoints_.erase(it);
    452   return StatusTuple(0);
    453 }
    454 
    455 StatusTuple BPF::detach_perf_event(uint32_t ev_type, uint32_t ev_config) {
    456   auto it = perf_events_.find(std::make_pair(ev_type, ev_config));
    457   if (it == perf_events_.end())
    458     return StatusTuple(-1, "Perf Event type %d config %d not attached", ev_type,
    459                        ev_config);
    460   TRY2(detach_perf_event_all_cpu(it->second));
    461   perf_events_.erase(it);
    462   return StatusTuple(0);
    463 }
    464 
    465 StatusTuple BPF::detach_perf_event_raw(void* perf_event_attr) {
    466   auto attr = static_cast<struct perf_event_attr*>(perf_event_attr);
    467   return detach_perf_event(attr->type, attr->config);
    468 }
    469 
    470 StatusTuple BPF::open_perf_event(const std::string& name, uint32_t type,
    471                                  uint64_t config) {
    472   if (perf_event_arrays_.find(name) == perf_event_arrays_.end()) {
    473     TableStorage::iterator it;
    474     if (!bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    475       return StatusTuple(-1, "open_perf_event: unable to find table_storage %s",
    476                          name.c_str());
    477     perf_event_arrays_[name] = new BPFPerfEventArray(it->second);
    478   }
    479   auto table = perf_event_arrays_[name];
    480   TRY2(table->open_all_cpu(type, config));
    481   return StatusTuple(0);
    482 }
    483 
    484 StatusTuple BPF::close_perf_event(const std::string& name) {
    485   auto it = perf_event_arrays_.find(name);
    486   if (it == perf_event_arrays_.end())
    487     return StatusTuple(-1, "Perf Event for %s not open", name.c_str());
    488   TRY2(it->second->close_all_cpu());
    489   return StatusTuple(0);
    490 }
    491 
    492 StatusTuple BPF::open_perf_buffer(const std::string& name,
    493                                   perf_reader_raw_cb cb,
    494                                   perf_reader_lost_cb lost_cb, void* cb_cookie,
    495                                   int page_cnt) {
    496   if (perf_buffers_.find(name) == perf_buffers_.end()) {
    497     TableStorage::iterator it;
    498     if (!bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    499       return StatusTuple(-1,
    500                          "open_perf_buffer: unable to find table_storage %s",
    501                          name.c_str());
    502     perf_buffers_[name] = new BPFPerfBuffer(it->second);
    503   }
    504   if ((page_cnt & (page_cnt - 1)) != 0)
    505     return StatusTuple(-1, "open_perf_buffer page_cnt must be a power of two");
    506   auto table = perf_buffers_[name];
    507   TRY2(table->open_all_cpu(cb, lost_cb, cb_cookie, page_cnt));
    508   return StatusTuple(0);
    509 }
    510 
    511 StatusTuple BPF::close_perf_buffer(const std::string& name) {
    512   auto it = perf_buffers_.find(name);
    513   if (it == perf_buffers_.end())
    514     return StatusTuple(-1, "Perf buffer for %s not open", name.c_str());
    515   TRY2(it->second->close_all_cpu());
    516   return StatusTuple(0);
    517 }
    518 
    519 BPFPerfBuffer* BPF::get_perf_buffer(const std::string& name) {
    520   auto it = perf_buffers_.find(name);
    521   return (it == perf_buffers_.end()) ? nullptr : it->second;
    522 }
    523 
    524 int BPF::poll_perf_buffer(const std::string& name, int timeout_ms) {
    525   auto it = perf_buffers_.find(name);
    526   if (it == perf_buffers_.end())
    527     return -1;
    528   return it->second->poll(timeout_ms);
    529 }
    530 
    531 StatusTuple BPF::load_func(const std::string& func_name, bpf_prog_type type,
    532                            int& fd) {
    533   if (funcs_.find(func_name) != funcs_.end()) {
    534     fd = funcs_[func_name];
    535     return StatusTuple(0);
    536   }
    537 
    538   uint8_t* func_start = bpf_module_->function_start(func_name);
    539   if (!func_start)
    540     return StatusTuple(-1, "Can't find start of function %s",
    541                        func_name.c_str());
    542   size_t func_size = bpf_module_->function_size(func_name);
    543 
    544   int log_level = 0;
    545   if (flag_ & DEBUG_BPF_REGISTER_STATE)
    546     log_level = 2;
    547   else if (flag_ & DEBUG_BPF)
    548     log_level = 1;
    549 
    550   fd = bpf_prog_load(type, func_name.c_str(),
    551                      reinterpret_cast<struct bpf_insn*>(func_start), func_size,
    552                      bpf_module_->license(), bpf_module_->kern_version(),
    553                      log_level, nullptr, 0);
    554 
    555   if (fd < 0)
    556     return StatusTuple(-1, "Failed to load %s: %d", func_name.c_str(), fd);
    557 
    558   bpf_module_->annotate_prog_tag(
    559       func_name, fd, reinterpret_cast<struct bpf_insn*>(func_start), func_size);
    560   funcs_[func_name] = fd;
    561   return StatusTuple(0);
    562 }
    563 
    564 StatusTuple BPF::unload_func(const std::string& func_name) {
    565   auto it = funcs_.find(func_name);
    566   if (it == funcs_.end())
    567     return StatusTuple(0);
    568 
    569   int res = close(it->second);
    570   if (res != 0)
    571     return StatusTuple(-1, "Can't close FD for %s: %d", it->first.c_str(), res);
    572 
    573   funcs_.erase(it);
    574   return StatusTuple(0);
    575 }
    576 
    577 std::string BPF::get_syscall_fnname(const std::string& name) {
    578   if (syscall_prefix_ == nullptr) {
    579     KSyms ksym;
    580     uint64_t addr;
    581 
    582     if (ksym.resolve_name(nullptr, "sys_bpf", &addr))
    583       syscall_prefix_.reset(new std::string("sys_"));
    584     else if (ksym.resolve_name(nullptr, "__x64_sys_bpf", &addr))
    585       syscall_prefix_.reset(new std::string("__x64_sys_"));
    586     else
    587       syscall_prefix_.reset(new std::string());
    588   }
    589 
    590   return *syscall_prefix_ + name;
    591 }
    592 
    593 StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
    594                                      const std::string& symbol,
    595                                      uint64_t symbol_addr,
    596                                      std::string& module_res,
    597                                      uint64_t& offset_res) {
    598   bcc_symbol output;
    599   int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
    600                                 symbol_addr, -1, nullptr, &output);
    601   if (res < 0)
    602     return StatusTuple(
    603         -1, "Unable to find offset for binary %s symbol %s address %lx",
    604         binary_path.c_str(), symbol.c_str(), symbol_addr);
    605 
    606   if (output.module) {
    607     module_res = output.module;
    608     ::free(const_cast<char*>(output.module));
    609   } else {
    610     module_res = "";
    611   }
    612   offset_res = output.offset;
    613   return StatusTuple(0);
    614 }
    615 
    616 std::string BPF::get_kprobe_event(const std::string& kernel_func,
    617                                   bpf_probe_attach_type type) {
    618   std::string res = attach_type_prefix(type) + "_";
    619   res += sanitize_str(kernel_func, &BPF::kprobe_event_validator);
    620   return res;
    621 }
    622 
    623 BPFProgTable BPF::get_prog_table(const std::string& name) {
    624   TableStorage::iterator it;
    625   if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    626     return BPFProgTable(it->second);
    627   return BPFProgTable({});
    628 }
    629 
    630 BPFCgroupArray BPF::get_cgroup_array(const std::string& name) {
    631   TableStorage::iterator it;
    632   if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    633     return BPFCgroupArray(it->second);
    634   return BPFCgroupArray({});
    635 }
    636 
    637 BPFDevmapTable BPF::get_devmap_table(const std::string& name) {
    638   TableStorage::iterator it;
    639   if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    640     return BPFDevmapTable(it->second);
    641   return BPFDevmapTable({});
    642 }
    643 
    644 BPFStackTable BPF::get_stack_table(const std::string& name, bool use_debug_file,
    645                                    bool check_debug_file_crc) {
    646   TableStorage::iterator it;
    647   if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    648     return BPFStackTable(it->second, use_debug_file, check_debug_file_crc);
    649   return BPFStackTable({}, use_debug_file, check_debug_file_crc);
    650 }
    651 
    652 std::string BPF::get_uprobe_event(const std::string& binary_path,
    653                                   uint64_t offset, bpf_probe_attach_type type,
    654                                   pid_t pid) {
    655   std::string res = attach_type_prefix(type) + "_";
    656   res += sanitize_str(binary_path, &BPF::uprobe_path_validator);
    657   res += "_0x" + uint_to_hex(offset);
    658   if (pid != -1)
    659     res += "_" + std::to_string(pid);
    660   return res;
    661 }
    662 
    663 StatusTuple BPF::detach_kprobe_event(const std::string& event,
    664                                      open_probe_t& attr) {
    665   bpf_close_perf_event_fd(attr.perf_event_fd);
    666   TRY2(unload_func(attr.func));
    667   if (bpf_detach_kprobe(event.c_str()) < 0)
    668     return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str());
    669   return StatusTuple(0);
    670 }
    671 
    672 StatusTuple BPF::detach_uprobe_event(const std::string& event,
    673                                      open_probe_t& attr) {
    674   bpf_close_perf_event_fd(attr.perf_event_fd);
    675   TRY2(unload_func(attr.func));
    676   if (bpf_detach_uprobe(event.c_str()) < 0)
    677     return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str());
    678   return StatusTuple(0);
    679 }
    680 
    681 StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint,
    682                                          open_probe_t& attr) {
    683   bpf_close_perf_event_fd(attr.perf_event_fd);
    684   TRY2(unload_func(attr.func));
    685 
    686   // TODO: bpf_detach_tracepoint currently does nothing.
    687   return StatusTuple(0);
    688 }
    689 
    690 StatusTuple BPF::detach_perf_event_all_cpu(open_probe_t& attr) {
    691   bool has_error = false;
    692   std::string err_msg;
    693   for (const auto& it : *attr.per_cpu_fd) {
    694     int res = bpf_close_perf_event_fd(it.second);
    695     if (res != 0) {
    696       has_error = true;
    697       err_msg += "Failed to close perf event FD " + std::to_string(it.second) +
    698                  " For CPU " + std::to_string(it.first) + ": ";
    699       err_msg += std::string(std::strerror(errno)) + "\n";
    700     }
    701   }
    702   delete attr.per_cpu_fd;
    703   TRY2(unload_func(attr.func));
    704 
    705   if (has_error)
    706     return StatusTuple(-1, err_msg);
    707   return StatusTuple(0);
    708 }
    709 
    710 USDT::USDT(const std::string& binary_path, const std::string& provider,
    711            const std::string& name, const std::string& probe_func)
    712     : initialized_(false),
    713       binary_path_(binary_path),
    714       pid_(-1),
    715       provider_(provider),
    716       name_(name),
    717       probe_func_(probe_func) {}
    718 
    719 USDT::USDT(pid_t pid, const std::string& provider, const std::string& name,
    720            const std::string& probe_func)
    721     : initialized_(false),
    722       binary_path_(),
    723       pid_(pid),
    724       provider_(provider),
    725       name_(name),
    726       probe_func_(probe_func) {}
    727 
    728 USDT::USDT(const std::string& binary_path, pid_t pid,
    729            const std::string& provider, const std::string& name,
    730            const std::string& probe_func)
    731     : initialized_(false),
    732       binary_path_(binary_path),
    733       pid_(pid),
    734       provider_(provider),
    735       name_(name),
    736       probe_func_(probe_func) {}
    737 
    738 USDT::USDT(const USDT& usdt)
    739     : initialized_(false),
    740       binary_path_(usdt.binary_path_),
    741       pid_(usdt.pid_),
    742       provider_(usdt.provider_),
    743       name_(usdt.name_),
    744       probe_func_(usdt.probe_func_) {}
    745 
    746 USDT::USDT(USDT&& usdt) noexcept
    747     : initialized_(usdt.initialized_),
    748       binary_path_(std::move(usdt.binary_path_)),
    749       pid_(usdt.pid_),
    750       provider_(std::move(usdt.provider_)),
    751       name_(std::move(usdt.name_)),
    752       probe_func_(std::move(usdt.probe_func_)),
    753       probe_(std::move(usdt.probe_)),
    754       program_text_(std::move(usdt.program_text_)) {
    755   usdt.initialized_ = false;
    756 }
    757 
    758 bool USDT::operator==(const USDT& other) const {
    759   return (provider_ == other.provider_) && (name_ == other.name_) &&
    760          (binary_path_ == other.binary_path_) && (pid_ == other.pid_) &&
    761          (probe_func_ == other.probe_func_);
    762 }
    763 
    764 StatusTuple USDT::init() {
    765   std::unique_ptr<::USDT::Context> ctx;
    766   if (!binary_path_.empty() && pid_ > 0)
    767     ctx.reset(new ::USDT::Context(pid_, binary_path_));
    768   else if (!binary_path_.empty())
    769     ctx.reset(new ::USDT::Context(binary_path_));
    770   else if (pid_ > 0)
    771     ctx.reset(new ::USDT::Context(pid_));
    772   else
    773     return StatusTuple(-1, "No valid Binary Path or PID provided");
    774 
    775   if (!ctx->loaded())
    776     return StatusTuple(-1, "Unable to load USDT " + print_name());
    777 
    778   auto deleter = [](void* probe) { delete static_cast<::USDT::Probe*>(probe); };
    779   for (auto& p : ctx->probes_) {
    780     if (p->provider_ == provider_ && p->name_ == name_) {
    781       // Take ownership of the probe that we are interested in, and avoid it
    782       // being destrcuted when we destruct the USDT::Context instance
    783       probe_ = std::unique_ptr<void, std::function<void(void*)>>(p.release(),
    784                                                                  deleter);
    785       p.swap(ctx->probes_.back());
    786       ctx->probes_.pop_back();
    787       break;
    788     }
    789   }
    790   if (!probe_)
    791     return StatusTuple(-1, "Unable to find USDT " + print_name());
    792   ctx.reset(nullptr);
    793   auto& probe = *static_cast<::USDT::Probe*>(probe_.get());
    794 
    795   std::ostringstream stream;
    796   if (!probe.usdt_getarg(stream, probe_func_))
    797     return StatusTuple(
    798         -1, "Unable to generate program text for USDT " + print_name());
    799   program_text_ = ::USDT::USDT_PROGRAM_HEADER + stream.str();
    800 
    801   initialized_ = true;
    802   return StatusTuple(0);
    803 }
    804 
    805 }  // namespace ebpf
    806