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 #pragma once
     18 
     19 #include <cctype>
     20 #include <cstdint>
     21 #include <memory>
     22 #include <ostream>
     23 #include <string>
     24 
     25 #include "BPFTable.h"
     26 #include "bcc_exception.h"
     27 #include "bcc_syms.h"
     28 #include "bpf_module.h"
     29 #include "compat/linux/bpf.h"
     30 #include "libbpf.h"
     31 #include "table_storage.h"
     32 
     33 static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8;
     34 
     35 namespace ebpf {
     36 
     37 struct open_probe_t {
     38   int perf_event_fd;
     39   std::string func;
     40   std::vector<std::pair<int, int>>* per_cpu_fd;
     41 };
     42 
     43 class USDT;
     44 
     45 class BPF {
     46  public:
     47   static const int BPF_MAX_STACK_DEPTH = 127;
     48 
     49   explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr,
     50                bool rw_engine_enabled = true, const std::string &maps_ns = "")
     51       : flag_(flag),
     52       bpf_module_(new BPFModule(flag, ts, rw_engine_enabled, maps_ns)) {}
     53   StatusTuple init(const std::string& bpf_program,
     54                    const std::vector<std::string>& cflags = {},
     55                    const std::vector<USDT>& usdt = {});
     56 
     57   ~BPF();
     58   StatusTuple detach_all();
     59 
     60   StatusTuple attach_kprobe(const std::string& kernel_func,
     61                             const std::string& probe_func,
     62                             uint64_t kernel_func_offset = 0,
     63                             bpf_probe_attach_type = BPF_PROBE_ENTRY);
     64   StatusTuple detach_kprobe(
     65       const std::string& kernel_func,
     66       bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
     67 
     68   StatusTuple attach_uprobe(const std::string& binary_path,
     69                             const std::string& symbol,
     70                             const std::string& probe_func,
     71                             uint64_t symbol_addr = 0,
     72                             bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
     73                             pid_t pid = -1);
     74   StatusTuple detach_uprobe(const std::string& binary_path,
     75                             const std::string& symbol, uint64_t symbol_addr = 0,
     76                             bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
     77                             pid_t pid = -1);
     78   StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1);
     79   StatusTuple detach_usdt(const USDT& usdt, pid_t pid = -1);
     80 
     81   StatusTuple attach_tracepoint(const std::string& tracepoint,
     82                                 const std::string& probe_func);
     83   StatusTuple detach_tracepoint(const std::string& tracepoint);
     84 
     85   StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config,
     86                                 const std::string& probe_func,
     87                                 uint64_t sample_period, uint64_t sample_freq,
     88                                 pid_t pid = -1, int cpu = -1,
     89                                 int group_fd = -1);
     90   StatusTuple attach_perf_event_raw(void* perf_event_attr,
     91                                     const std::string& probe_func,
     92                                     pid_t pid = -1, int cpu = -1,
     93                                     int group_fd = -1,
     94                                     unsigned long extra_flags = 0);
     95   StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config);
     96   StatusTuple detach_perf_event_raw(void* perf_event_attr);
     97   std::string get_syscall_fnname(const std::string& name);
     98 
     99   BPFTable get_table(const std::string& name) {
    100     TableStorage::iterator it;
    101     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    102       return BPFTable(it->second);
    103     return BPFTable({});
    104   }
    105 
    106   template <class ValueType>
    107   BPFArrayTable<ValueType> get_array_table(const std::string& name) {
    108     TableStorage::iterator it;
    109     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    110       return BPFArrayTable<ValueType>(it->second);
    111     return BPFArrayTable<ValueType>({});
    112   }
    113 
    114   template <class ValueType>
    115   BPFPercpuArrayTable<ValueType> get_percpu_array_table(
    116       const std::string& name) {
    117     TableStorage::iterator it;
    118     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    119       return BPFPercpuArrayTable<ValueType>(it->second);
    120     return BPFPercpuArrayTable<ValueType>({});
    121   }
    122 
    123   template <class KeyType, class ValueType>
    124   BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) {
    125     TableStorage::iterator it;
    126     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    127       return BPFHashTable<KeyType, ValueType>(it->second);
    128     return BPFHashTable<KeyType, ValueType>({});
    129   }
    130 
    131   template <class KeyType, class ValueType>
    132   BPFPercpuHashTable<KeyType, ValueType> get_percpu_hash_table(
    133       const std::string& name) {
    134     TableStorage::iterator it;
    135     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
    136       return BPFPercpuHashTable<KeyType, ValueType>(it->second);
    137     return BPFPercpuHashTable<KeyType, ValueType>({});
    138   }
    139 
    140   BPFProgTable get_prog_table(const std::string& name);
    141 
    142   BPFCgroupArray get_cgroup_array(const std::string& name);
    143 
    144   BPFDevmapTable get_devmap_table(const std::string& name);
    145 
    146   BPFStackTable get_stack_table(const std::string& name,
    147                                 bool use_debug_file = true,
    148                                 bool check_debug_file_crc = true);
    149 
    150   StatusTuple open_perf_event(const std::string& name, uint32_t type,
    151                               uint64_t config);
    152 
    153   StatusTuple close_perf_event(const std::string& name);
    154 
    155   // Open a Perf Buffer of given name, providing callback and callback cookie
    156   // to use when polling. BPF class owns the opened Perf Buffer and will free
    157   // it on-demand or on destruction.
    158   StatusTuple open_perf_buffer(const std::string& name, perf_reader_raw_cb cb,
    159                                perf_reader_lost_cb lost_cb = nullptr,
    160                                void* cb_cookie = nullptr,
    161                                int page_cnt = DEFAULT_PERF_BUFFER_PAGE_CNT);
    162   // Close and free the Perf Buffer of given name.
    163   StatusTuple close_perf_buffer(const std::string& name);
    164   // Obtain an pointer to the opened BPFPerfBuffer instance of given name.
    165   // Will return nullptr if such open Perf Buffer doesn't exist.
    166   BPFPerfBuffer* get_perf_buffer(const std::string& name);
    167   // Poll an opened Perf Buffer of given name with given timeout, using callback
    168   // provided when opening. Do nothing if such open Perf Buffer doesn't exist.
    169   // Returns:
    170   //   -1 on error or if perf buffer with such name doesn't exist;
    171   //   0, if no data was available before timeout;
    172   //   number of CPUs that have new data, otherwise.
    173   int poll_perf_buffer(const std::string& name, int timeout_ms = -1);
    174 
    175   StatusTuple load_func(const std::string& func_name, enum bpf_prog_type type,
    176                         int& fd);
    177   StatusTuple unload_func(const std::string& func_name);
    178 
    179  private:
    180   std::string get_kprobe_event(const std::string& kernel_func,
    181                                bpf_probe_attach_type type);
    182   std::string get_uprobe_event(const std::string& binary_path, uint64_t offset,
    183                                bpf_probe_attach_type type, pid_t pid);
    184 
    185   StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr);
    186   StatusTuple detach_uprobe_event(const std::string& event, open_probe_t& attr);
    187   StatusTuple detach_tracepoint_event(const std::string& tracepoint,
    188                                       open_probe_t& attr);
    189   StatusTuple detach_perf_event_all_cpu(open_probe_t& attr);
    190 
    191   std::string attach_type_debug(bpf_probe_attach_type type) {
    192     switch (type) {
    193     case BPF_PROBE_ENTRY:
    194       return "";
    195     case BPF_PROBE_RETURN:
    196       return "return ";
    197     }
    198     return "ERROR";
    199   }
    200 
    201   std::string attach_type_prefix(bpf_probe_attach_type type) {
    202     switch (type) {
    203     case BPF_PROBE_ENTRY:
    204       return "p";
    205     case BPF_PROBE_RETURN:
    206       return "r";
    207     }
    208     return "ERROR";
    209   }
    210 
    211   static bool kprobe_event_validator(char c) {
    212     return (c != '+') && (c != '.');
    213   }
    214 
    215   static bool uprobe_path_validator(char c) {
    216     return std::isalpha(c) || std::isdigit(c) || (c == '_');
    217   }
    218 
    219   StatusTuple check_binary_symbol(const std::string& binary_path,
    220                                   const std::string& symbol,
    221                                   uint64_t symbol_addr, std::string& module_res,
    222                                   uint64_t& offset_res);
    223 
    224   int flag_;
    225 
    226   std::unique_ptr<std::string> syscall_prefix_;
    227 
    228   std::unique_ptr<BPFModule> bpf_module_;
    229 
    230   std::map<std::string, int> funcs_;
    231 
    232   std::vector<USDT> usdt_;
    233 
    234   std::map<std::string, open_probe_t> kprobes_;
    235   std::map<std::string, open_probe_t> uprobes_;
    236   std::map<std::string, open_probe_t> tracepoints_;
    237   std::map<std::string, BPFPerfBuffer*> perf_buffers_;
    238   std::map<std::string, BPFPerfEventArray*> perf_event_arrays_;
    239   std::map<std::pair<uint32_t, uint32_t>, open_probe_t> perf_events_;
    240 };
    241 
    242 class USDT {
    243  public:
    244   USDT(const std::string& binary_path, const std::string& provider,
    245        const std::string& name, const std::string& probe_func);
    246   USDT(pid_t pid, const std::string& provider, const std::string& name,
    247        const std::string& probe_func);
    248   USDT(const std::string& binary_path, pid_t pid, const std::string& provider,
    249        const std::string& name, const std::string& probe_func);
    250   USDT(const USDT& usdt);
    251   USDT(USDT&& usdt) noexcept;
    252 
    253   StatusTuple init();
    254 
    255   bool operator==(const USDT& other) const;
    256 
    257   std::string print_name() const {
    258     return provider_ + ":" + name_ + " from binary " + binary_path_ + " PID " +
    259            std::to_string(pid_) + " for probe " + probe_func_;
    260   }
    261 
    262   friend std::ostream& operator<<(std::ostream& out, const USDT& usdt) {
    263     return out << usdt.provider_ << ":" << usdt.name_ << " from binary "
    264                << usdt.binary_path_ << " PID " << usdt.pid_ << " for probe "
    265                << usdt.probe_func_;
    266   }
    267 
    268  private:
    269   bool initialized_;
    270 
    271   std::string binary_path_;
    272   pid_t pid_;
    273 
    274   std::string provider_;
    275   std::string name_;
    276   std::string probe_func_;
    277 
    278   std::unique_ptr<void, std::function<void(void*)>> probe_;
    279   std::string program_text_;
    280 
    281   friend class BPF;
    282 };
    283 
    284 }  // namespace ebpf
    285