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 = "") flag_(flag)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 get_table(const std::string & name)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> get_array_table(const std::string & name)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> get_percpu_array_table(const std::string & name)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> get_hash_table(const std::string & name)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> get_percpu_hash_table(const std::string & name)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 attach_type_debug(bpf_probe_attach_type type)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 attach_type_prefix(bpf_probe_attach_type type)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 kprobe_event_validator(char c)211 static bool kprobe_event_validator(char c) { 212 return (c != '+') && (c != '.'); 213 } 214 uprobe_path_validator(char c)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 print_name()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