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