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 "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 BPF; 44 45 class USDT { 46 public: 47 USDT(const std::string& binary_path, const std::string& provider, 48 const std::string& name, const std::string& probe_func); 49 USDT(pid_t pid, const std::string& provider, const std::string& name, 50 const std::string& probe_func); 51 USDT(const std::string& binary_path, pid_t pid, const std::string& provider, 52 const std::string& name, const std::string& probe_func); 53 USDT(const USDT& usdt); 54 USDT(USDT&& usdt) noexcept; 55 binary_path()56 const std::string &binary_path() const { return binary_path_; } pid()57 pid_t pid() const { return pid_; } provider()58 const std::string &provider() const { return provider_; } name()59 const std::string &name() const { return name_; } probe_func()60 const std::string &probe_func() const { return probe_func_; } 61 62 StatusTuple init(); 63 64 bool operator==(const USDT& other) const; 65 print_name()66 std::string print_name() const { 67 return provider_ + ":" + name_ + " from binary " + binary_path_ + " PID " + 68 std::to_string(pid_) + " for probe " + probe_func_; 69 } 70 71 friend std::ostream& operator<<(std::ostream& out, const USDT& usdt) { 72 return out << usdt.provider_ << ":" << usdt.name_ << " from binary " 73 << usdt.binary_path_ << " PID " << usdt.pid_ << " for probe " 74 << usdt.probe_func_; 75 } 76 77 // When the kludge flag is set to 1 (default), we will only match on inode 78 // when searching for modules in /proc/PID/maps that might contain the 79 // tracepoint we're looking for. 80 // By setting this to 0, we will match on both inode and 81 // (dev_major, dev_minor), which is a more accurate way to uniquely 82 // identify a file, but may fail depending on the filesystem backing the 83 // target file (see bcc#2715) 84 // 85 // This hack exists because btrfs and overlayfs report different device 86 // numbers for files in /proc/PID/maps vs stat syscall. Don't use it unless 87 // you've had issues with inode collisions. Both btrfs and overlayfs are 88 // known to require inode-only resolution to accurately match a file. 89 // 90 // set_probe_matching_kludge(0) must be called before USDTs are submitted to 91 // BPF::init() 92 int set_probe_matching_kludge(uint8_t kludge); 93 94 private: 95 bool initialized_; 96 97 std::string binary_path_; 98 pid_t pid_; 99 100 std::string provider_; 101 std::string name_; 102 std::string probe_func_; 103 104 std::unique_ptr<void, std::function<void(void*)>> probe_; 105 std::string program_text_; 106 107 uint8_t mod_match_inode_only_; 108 109 friend class BPF; 110 }; 111 112 class BPF { 113 public: 114 static const int BPF_MAX_STACK_DEPTH = 127; 115 116 explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr, 117 bool rw_engine_enabled = bpf_module_rw_engine_enabled(), 118 const std::string &maps_ns = "", 119 bool allow_rlimit = true) flag_(flag)120 : flag_(flag), 121 bsymcache_(NULL), 122 bpf_module_(new BPFModule(flag, ts, rw_engine_enabled, maps_ns, 123 allow_rlimit)) {} 124 StatusTuple init(const std::string& bpf_program, 125 const std::vector<std::string>& cflags = {}, 126 const std::vector<USDT>& usdt = {}); 127 128 StatusTuple init_usdt(const USDT& usdt); 129 130 ~BPF(); 131 StatusTuple detach_all(); 132 133 StatusTuple attach_kprobe(const std::string& kernel_func, 134 const std::string& probe_func, 135 uint64_t kernel_func_offset = 0, 136 bpf_probe_attach_type = BPF_PROBE_ENTRY, 137 int maxactive = 0); 138 StatusTuple detach_kprobe( 139 const std::string& kernel_func, 140 bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY); 141 142 StatusTuple attach_uprobe(const std::string& binary_path, 143 const std::string& symbol, 144 const std::string& probe_func, 145 uint64_t symbol_addr = 0, 146 bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY, 147 pid_t pid = -1, 148 uint64_t symbol_offset = 0, 149 uint32_t ref_ctr_offset = 0); 150 StatusTuple detach_uprobe(const std::string& binary_path, 151 const std::string& symbol, uint64_t symbol_addr = 0, 152 bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY, 153 pid_t pid = -1, 154 uint64_t symbol_offset = 0); 155 StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1); 156 StatusTuple attach_usdt_all(); 157 StatusTuple detach_usdt(const USDT& usdt, pid_t pid = -1); 158 StatusTuple detach_usdt_all(); 159 160 StatusTuple attach_tracepoint(const std::string& tracepoint, 161 const std::string& probe_func); 162 StatusTuple detach_tracepoint(const std::string& tracepoint); 163 164 StatusTuple attach_raw_tracepoint(const std::string& tracepoint, 165 const std::string& probe_func); 166 StatusTuple detach_raw_tracepoint(const std::string& tracepoint); 167 168 StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config, 169 const std::string& probe_func, 170 uint64_t sample_period, uint64_t sample_freq, 171 pid_t pid = -1, int cpu = -1, 172 int group_fd = -1); 173 StatusTuple attach_perf_event_raw(void* perf_event_attr, 174 const std::string& probe_func, 175 pid_t pid = -1, int cpu = -1, 176 int group_fd = -1, 177 unsigned long extra_flags = 0); 178 StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config); 179 StatusTuple detach_perf_event_raw(void* perf_event_attr); 180 std::string get_syscall_fnname(const std::string& name); 181 get_table(const std::string & name)182 BPFTable get_table(const std::string& name) { 183 TableStorage::iterator it; 184 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 185 return BPFTable(it->second); 186 return BPFTable({}); 187 } 188 189 template <class ValueType> get_array_table(const std::string & name)190 BPFArrayTable<ValueType> get_array_table(const std::string& name) { 191 TableStorage::iterator it; 192 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 193 return BPFArrayTable<ValueType>(it->second); 194 return BPFArrayTable<ValueType>({}); 195 } 196 197 template <class ValueType> get_percpu_array_table(const std::string & name)198 BPFPercpuArrayTable<ValueType> get_percpu_array_table( 199 const std::string& name) { 200 TableStorage::iterator it; 201 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 202 return BPFPercpuArrayTable<ValueType>(it->second); 203 return BPFPercpuArrayTable<ValueType>({}); 204 } 205 206 template <class KeyType, class ValueType> get_hash_table(const std::string & name)207 BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) { 208 TableStorage::iterator it; 209 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 210 return BPFHashTable<KeyType, ValueType>(it->second); 211 return BPFHashTable<KeyType, ValueType>({}); 212 } 213 214 template <class KeyType, class ValueType> get_percpu_hash_table(const std::string & name)215 BPFPercpuHashTable<KeyType, ValueType> get_percpu_hash_table( 216 const std::string& name) { 217 TableStorage::iterator it; 218 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 219 return BPFPercpuHashTable<KeyType, ValueType>(it->second); 220 return BPFPercpuHashTable<KeyType, ValueType>({}); 221 } 222 223 template <class ValueType> get_sk_storage_table(const std::string & name)224 BPFSkStorageTable<ValueType> get_sk_storage_table(const std::string& name) { 225 TableStorage::iterator it; 226 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 227 return BPFSkStorageTable<ValueType>(it->second); 228 return BPFSkStorageTable<ValueType>({}); 229 } 230 231 template <class ValueType> get_inode_storage_table(const std::string & name)232 BPFInodeStorageTable<ValueType> get_inode_storage_table(const std::string& name) { 233 TableStorage::iterator it; 234 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 235 return BPFInodeStorageTable<ValueType>(it->second); 236 return BPFInodeStorageTable<ValueType>({}); 237 } 238 239 template <class ValueType> get_task_storage_table(const std::string & name)240 BPFTaskStorageTable<ValueType> get_task_storage_table(const std::string& name) { 241 TableStorage::iterator it; 242 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 243 return BPFTaskStorageTable<ValueType>(it->second); 244 return BPFTaskStorageTable<ValueType>({}); 245 } 246 247 template <class ValueType> get_cg_storage_table(const std::string & name)248 BPFCgStorageTable<ValueType> get_cg_storage_table(const std::string& name) { 249 TableStorage::iterator it; 250 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 251 return BPFCgStorageTable<ValueType>(it->second); 252 return BPFCgStorageTable<ValueType>({}); 253 } 254 255 template <class ValueType> get_percpu_cg_storage_table(const std::string & name)256 BPFPercpuCgStorageTable<ValueType> get_percpu_cg_storage_table(const std::string& name) { 257 TableStorage::iterator it; 258 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 259 return BPFPercpuCgStorageTable<ValueType>(it->second); 260 return BPFPercpuCgStorageTable<ValueType>({}); 261 } 262 263 template <class ValueType> get_queuestack_table(const std::string & name)264 BPFQueueStackTable<ValueType> get_queuestack_table(const std::string& name) { 265 TableStorage::iterator it; 266 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 267 return BPFQueueStackTable<ValueType>(it->second); 268 return BPFQueueStackTable<ValueType>({}); 269 } 270 get_bsymcache(void)271 void* get_bsymcache(void) { 272 if (bsymcache_ == NULL) { 273 bsymcache_ = bcc_buildsymcache_new(); 274 } 275 return bsymcache_; 276 } 277 278 BPFProgTable get_prog_table(const std::string& name); 279 280 BPFCgroupArray get_cgroup_array(const std::string& name); 281 282 BPFDevmapTable get_devmap_table(const std::string& name); 283 284 BPFXskmapTable get_xskmap_table(const std::string& name); 285 286 BPFSockmapTable get_sockmap_table(const std::string& name); 287 288 BPFSockhashTable get_sockhash_table(const std::string& name); 289 290 BPFStackTable get_stack_table(const std::string& name, 291 bool use_debug_file = true, 292 bool check_debug_file_crc = true); 293 294 BPFStackBuildIdTable get_stackbuildid_table(const std::string &name, 295 bool use_debug_file = true, 296 bool check_debug_file_crc = true); 297 template <class KeyType> get_map_in_map_table(const std::string & name)298 BPFMapInMapTable<KeyType> get_map_in_map_table(const std::string& name){ 299 TableStorage::iterator it; 300 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) 301 return BPFMapInMapTable<KeyType>(it->second); 302 return BPFMapInMapTable<KeyType>({}); 303 } 304 305 bool add_module(std::string module); 306 307 StatusTuple open_perf_event(const std::string& name, uint32_t type, 308 uint64_t config, int pid = -1); 309 310 StatusTuple close_perf_event(const std::string& name); 311 312 // Open a Perf Buffer of given name, providing callback and callback cookie 313 // to use when polling. BPF class owns the opened Perf Buffer and will free 314 // it on-demand or on destruction. 315 StatusTuple open_perf_buffer(const std::string& name, perf_reader_raw_cb cb, 316 perf_reader_lost_cb lost_cb = nullptr, 317 void* cb_cookie = nullptr, 318 int page_cnt = DEFAULT_PERF_BUFFER_PAGE_CNT); 319 // Close and free the Perf Buffer of given name. 320 StatusTuple close_perf_buffer(const std::string& name); 321 // Obtain an pointer to the opened BPFPerfBuffer instance of given name. 322 // Will return nullptr if such open Perf Buffer doesn't exist. 323 BPFPerfBuffer* get_perf_buffer(const std::string& name); 324 // Poll an opened Perf Buffer of given name with given timeout, using callback 325 // provided when opening. Do nothing if such open Perf Buffer doesn't exist. 326 // Returns: 327 // -1 on error or if perf buffer with such name doesn't exist; 328 // 0, if no data was available before timeout; 329 // number of CPUs that have new data, otherwise. 330 int poll_perf_buffer(const std::string& name, int timeout_ms = -1); 331 332 StatusTuple load_func(const std::string& func_name, enum bpf_prog_type type, 333 int& fd, unsigned flags = 0, enum bpf_attach_type = (bpf_attach_type) -1); 334 StatusTuple unload_func(const std::string& func_name); 335 336 StatusTuple attach_func(int prog_fd, int attachable_fd, 337 enum bpf_attach_type attach_type, 338 uint64_t flags); 339 StatusTuple detach_func(int prog_fd, int attachable_fd, 340 enum bpf_attach_type attach_type); 341 342 int free_bcc_memory(); 343 344 private: 345 std::string get_kprobe_event(const std::string& kernel_func, 346 bpf_probe_attach_type type); 347 std::string get_uprobe_event(const std::string& binary_path, uint64_t offset, 348 bpf_probe_attach_type type, pid_t pid); 349 350 StatusTuple attach_usdt_without_validation(const USDT& usdt, pid_t pid); 351 StatusTuple detach_usdt_without_validation(const USDT& usdt, pid_t pid); 352 353 StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr); 354 StatusTuple detach_uprobe_event(const std::string& event, open_probe_t& attr); 355 StatusTuple detach_tracepoint_event(const std::string& tracepoint, 356 open_probe_t& attr); 357 StatusTuple detach_raw_tracepoint_event(const std::string& tracepoint, 358 open_probe_t& attr); 359 StatusTuple detach_perf_event_all_cpu(open_probe_t& attr); 360 attach_type_debug(bpf_probe_attach_type type)361 std::string attach_type_debug(bpf_probe_attach_type type) { 362 switch (type) { 363 case BPF_PROBE_ENTRY: 364 return ""; 365 case BPF_PROBE_RETURN: 366 return "return "; 367 } 368 return "ERROR"; 369 } 370 attach_type_prefix(bpf_probe_attach_type type)371 std::string attach_type_prefix(bpf_probe_attach_type type) { 372 switch (type) { 373 case BPF_PROBE_ENTRY: 374 return "p"; 375 case BPF_PROBE_RETURN: 376 return "r"; 377 } 378 return "ERROR"; 379 } 380 kprobe_event_validator(char c)381 static bool kprobe_event_validator(char c) { 382 return (c != '+') && (c != '.'); 383 } 384 uprobe_path_validator(char c)385 static bool uprobe_path_validator(char c) { 386 return std::isalpha(c) || std::isdigit(c) || (c == '_'); 387 } 388 389 StatusTuple check_binary_symbol(const std::string& binary_path, 390 const std::string& symbol, 391 uint64_t symbol_addr, std::string& module_res, 392 uint64_t& offset_res, 393 uint64_t symbol_offset = 0); 394 395 void init_fail_reset(); 396 397 int flag_; 398 399 void *bsymcache_; 400 401 std::unique_ptr<std::string> syscall_prefix_; 402 403 std::unique_ptr<BPFModule> bpf_module_; 404 405 std::map<std::string, int> funcs_; 406 407 std::vector<USDT> usdt_; 408 std::string all_bpf_program_; 409 410 std::map<std::string, open_probe_t> kprobes_; 411 std::map<std::string, open_probe_t> uprobes_; 412 std::map<std::string, open_probe_t> tracepoints_; 413 std::map<std::string, open_probe_t> raw_tracepoints_; 414 std::map<std::string, BPFPerfBuffer*> perf_buffers_; 415 std::map<std::string, BPFPerfEventArray*> perf_event_arrays_; 416 std::map<std::pair<uint32_t, uint32_t>, open_probe_t> perf_events_; 417 }; 418 419 } // namespace ebpf 420