BPF.h 7.96 KB
Newer Older
Teng Qin's avatar
Teng Qin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (c) 2016 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <cctype>
20
#include <cstdint>
Teng Qin's avatar
Teng Qin committed
21 22 23 24
#include <memory>
#include <string>

#include "BPFTable.h"
25
#include "bcc_exception.h"
Teng Qin's avatar
Teng Qin committed
26 27 28 29
#include "bcc_syms.h"
#include "bpf_module.h"
#include "compat/linux/bpf.h"
#include "libbpf.h"
30
#include "table_storage.h"
Teng Qin's avatar
Teng Qin committed
31

32 33
static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8;

Teng Qin's avatar
Teng Qin committed
34 35 36 37 38
namespace ebpf {

struct open_probe_t {
  void* reader_ptr;
  std::string func;
39
  std::map<int, int>* per_cpu_fd;
Teng Qin's avatar
Teng Qin committed
40 41
};

Teng Qin's avatar
Teng Qin committed
42 43
class USDT;

Teng Qin's avatar
Teng Qin committed
44 45 46 47
class BPF {
public:
  static const int BPF_MAX_STACK_DEPTH = 127;

48
  explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr)
49
      : bpf_module_(new BPFModule(flag, ts)) {}
Teng Qin's avatar
Teng Qin committed
50
  StatusTuple init(const std::string& bpf_program,
Teng Qin's avatar
Teng Qin committed
51 52
                   const std::vector<std::string>& cflags = {},
                   const std::vector<USDT>& usdt = {});
Teng Qin's avatar
Teng Qin committed
53 54 55 56 57 58

  ~BPF();
  StatusTuple detach_all();

  StatusTuple attach_kprobe(
      const std::string& kernel_func, const std::string& probe_func,
59
      bpf_probe_attach_type = BPF_PROBE_ENTRY,
Teng Qin's avatar
Teng Qin committed
60 61 62 63
      pid_t pid = -1, int cpu = 0, int group_fd = -1,
      perf_reader_cb cb = nullptr, void* cb_cookie = nullptr);
  StatusTuple detach_kprobe(
      const std::string& kernel_func,
64
      bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
Teng Qin's avatar
Teng Qin committed
65 66 67 68

  StatusTuple attach_uprobe(
      const std::string& binary_path, const std::string& symbol,
      const std::string& probe_func, uint64_t symbol_addr = 0,
69
      bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
Teng Qin's avatar
Teng Qin committed
70 71 72 73 74
      pid_t pid = -1, int cpu = 0, int group_fd = -1,
      perf_reader_cb cb = nullptr, void* cb_cookie = nullptr);
  StatusTuple detach_uprobe(
      const std::string& binary_path, const std::string& symbol,
      uint64_t symbol_addr = 0,
75 76
      bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
      pid_t pid = -1);
Teng Qin's avatar
Teng Qin committed
77 78 79
  StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1, int cpu = 0,
                          int group_fd = -1);
  StatusTuple detach_usdt(const USDT& usdt);
Teng Qin's avatar
Teng Qin committed
80 81 82 83 84 85 86 87

  StatusTuple attach_tracepoint(const std::string& tracepoint,
                                const std::string& probe_func,
                                pid_t pid = -1, int cpu = 0, int group_fd = -1,
                                perf_reader_cb cb = nullptr,
                                void* cb_cookie = nullptr);
  StatusTuple detach_tracepoint(const std::string& tracepoint);

88 89 90 91 92 93 94
  StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config,
                                const std::string& probe_func,
                                uint64_t sample_period, uint64_t sample_freq,
                                pid_t pid = -1, int cpu = -1,
                                int group_fd = -1);
  StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config);

95 96 97 98 99 100 101
  BPFTable get_table(const std::string& name) {
    TableStorage::iterator it;
    if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
      return BPFTable(it->second);
    return BPFTable({});
  }

102 103 104 105 106 107 108 109
  template <class ValueType>
  BPFArrayTable<ValueType> get_array_table(const std::string& name) {
    TableStorage::iterator it;
    if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
      return BPFArrayTable<ValueType>(it->second);
    return BPFArrayTable<ValueType>({});
  }

Teng Qin's avatar
Teng Qin committed
110 111
  template <class KeyType, class ValueType>
  BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) {
112 113 114 115
    TableStorage::iterator it;
    if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
      return BPFHashTable<KeyType, ValueType>(it->second);
    return BPFHashTable<KeyType, ValueType>({});
Teng Qin's avatar
Teng Qin committed
116 117
  }

118 119
  BPFProgTable get_prog_table(const std::string& name);

120 121 122
  BPFStackTable get_stack_table(const std::string& name,
                                bool use_debug_file = true,
                                bool check_debug_file_crc = true);
Teng Qin's avatar
Teng Qin committed
123

124 125 126 127 128 129
  StatusTuple open_perf_event(const std::string& name,
                              uint32_t type,
                              uint64_t config);

  StatusTuple close_perf_event(const std::string& name);

130 131 132
  StatusTuple open_perf_buffer(const std::string& name,
                               perf_reader_raw_cb cb,
                               perf_reader_lost_cb lost_cb = nullptr,
133 134
                               void* cb_cookie = nullptr,
                               int page_cnt = DEFAULT_PERF_BUFFER_PAGE_CNT);
Teng Qin's avatar
Teng Qin committed
135 136 137 138 139 140 141
  StatusTuple close_perf_buffer(const std::string& name);
  void poll_perf_buffer(const std::string& name, int timeout = -1);

  StatusTuple load_func(const std::string& func_name, enum bpf_prog_type type,
                        int& fd);
  StatusTuple unload_func(const std::string& func_name);

142
private:
Teng Qin's avatar
Teng Qin committed
143
  std::string get_kprobe_event(const std::string& kernel_func,
144
                               bpf_probe_attach_type type);
Teng Qin's avatar
Teng Qin committed
145
  std::string get_uprobe_event(const std::string& binary_path, uint64_t offset,
146
                               bpf_probe_attach_type type, pid_t pid);
Teng Qin's avatar
Teng Qin committed
147 148 149 150 151

  StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr);
  StatusTuple detach_uprobe_event(const std::string& event, open_probe_t& attr);
  StatusTuple detach_tracepoint_event(const std::string& tracepoint,
                                      open_probe_t& attr);
152
  StatusTuple detach_perf_event_all_cpu(open_probe_t& attr);
Teng Qin's avatar
Teng Qin committed
153

154 155
  std::string attach_type_debug(bpf_probe_attach_type type) {
    switch (type) {
156
    case BPF_PROBE_ENTRY:
Teng Qin's avatar
Teng Qin committed
157
      return "";
158
    case BPF_PROBE_RETURN:
Teng Qin's avatar
Teng Qin committed
159 160 161 162 163
      return "return ";
    }
    return "ERROR";
  }

164 165
  std::string attach_type_prefix(bpf_probe_attach_type type) {
    switch (type) {
166
    case BPF_PROBE_ENTRY:
Teng Qin's avatar
Teng Qin committed
167
      return "p";
168
    case BPF_PROBE_RETURN:
Teng Qin's avatar
Teng Qin committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
      return "r";
    }
    return "ERROR";
  }

  static bool kprobe_event_validator(char c) {
    return (c != '+') && (c != '.');
  }

  static bool uprobe_path_validator(char c) {
    return std::isalpha(c) || std::isdigit(c) || (c == '_');
  }

  StatusTuple check_binary_symbol(const std::string& binary_path,
                                  const std::string& symbol,
184 185 186
                                  uint64_t symbol_addr,
                                  std::string &module_res,
                                  uint64_t &offset_res);
Teng Qin's avatar
Teng Qin committed
187 188 189 190 191

  std::unique_ptr<BPFModule> bpf_module_;

  std::map<std::string, int> funcs_;

Teng Qin's avatar
Teng Qin committed
192 193
  std::vector<USDT> usdt_;

Teng Qin's avatar
Teng Qin committed
194 195 196 197
  std::map<std::string, open_probe_t> kprobes_;
  std::map<std::string, open_probe_t> uprobes_;
  std::map<std::string, open_probe_t> tracepoints_;
  std::map<std::string, BPFPerfBuffer*> perf_buffers_;
198
  std::map<std::string, BPFPerfEventArray*> perf_event_arrays_;
199
  std::map<std::pair<uint32_t, uint32_t>, open_probe_t> perf_events_;
Teng Qin's avatar
Teng Qin committed
200 201
};

Teng Qin's avatar
Teng Qin committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
class USDT {
public:
  USDT(const std::string& binary_path, const std::string& provider,
       const std::string& name, const std::string& probe_func)
      : initialized_(false),
        binary_path_(binary_path),
        provider_(provider),
        name_(name),
        probe_func_(probe_func) {}

  bool operator==(const USDT& other) const {
    return (provider_ == other.provider_) && (name_ == other.name_) &&
           (binary_path_ == other.binary_path_) &&
           (probe_func_ == other.probe_func_);
  }

  std::string print_name() const {
    return provider_ + ":" + name_ + " from " + binary_path_;
  }

private:
  StatusTuple init();
  bool initialized_;

  std::string binary_path_;
  std::string provider_;
  std::string name_;
  std::string probe_func_;

231
  std::vector<uintptr_t> addresses_;
Teng Qin's avatar
Teng Qin committed
232 233 234 235 236 237

  std::string program_text_;

  friend class BPF;
};

Teng Qin's avatar
Teng Qin committed
238
}  // namespace ebpf