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 <fcntl.h>
24 #include <iostream>
25 #include <memory>
26 #include <sstream>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <utility>
30 #include <vector>
31
32 #include "bcc_exception.h"
33 #include "bcc_elf.h"
34 #include "bcc_syms.h"
35 #include "bpf_module.h"
36 #include "common.h"
37 #include "libbpf.h"
38 #include "perf_reader.h"
39 #include "syms.h"
40 #include "table_storage.h"
41 #include "usdt.h"
42
43 #include "BPF.h"
44
45 namespace {
46 /*
47 * Kernels ~4.20 and later support specifying the ref_ctr_offset as an argument
48 * to attaching a uprobe, which negates the need to seek to this memory offset
49 * in userspace to manage semaphores, as the kernel will do it for us. This
50 * helper function checks if this support is available by reading the uprobe
51 * format for this value, added in a6ca88b241d5e929e6e60b12ad8cd288f0ffa
52 */
uprobe_ref_ctr_supported()53 bool uprobe_ref_ctr_supported() {
54 const char *ref_ctr_pmu_path =
55 "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset";
56 const char *ref_ctr_pmu_expected = "config:32-63\0";
57 char ref_ctr_pmu_fmt[64]; // in Linux source this buffer is compared vs
58 // PAGE_SIZE, but 64 is probably ample
59 int fd = open(ref_ctr_pmu_path, O_RDONLY);
60 if (fd < 0)
61 return false;
62
63 int ret = read(fd, ref_ctr_pmu_fmt, sizeof(ref_ctr_pmu_fmt));
64 close(fd);
65 if (ret < 0) {
66 return false;
67 }
68 if (strncmp(ref_ctr_pmu_expected, ref_ctr_pmu_fmt,
69 strlen(ref_ctr_pmu_expected)) == 0) {
70 return true;
71 }
72 return false;
73 }
74 } // namespace
75
76 namespace ebpf {
77
uint_to_hex(uint64_t value)78 std::string uint_to_hex(uint64_t value) {
79 std::stringstream ss;
80 ss << std::hex << value;
81 return ss.str();
82 }
83
sanitize_str(std::string str,bool (* validator)(char),char replacement='_')84 std::string sanitize_str(std::string str, bool (*validator)(char),
85 char replacement = '_') {
86 for (size_t i = 0; i < str.length(); i++)
87 if (!validator(str[i]))
88 str[i] = replacement;
89 return str;
90 }
91
init_usdt(const USDT & usdt)92 StatusTuple BPF::init_usdt(const USDT& usdt) {
93 USDT u(usdt);
94 StatusTuple init_stp = u.init();
95 if (!init_stp.ok()) {
96 return init_stp;
97 }
98
99 usdt_.push_back(std::move(u));
100 all_bpf_program_ += usdt_.back().program_text_;
101 return StatusTuple::OK();
102 }
103
init_fail_reset()104 void BPF::init_fail_reset() {
105 usdt_.clear();
106 all_bpf_program_ = "";
107 }
108
init(const std::string & bpf_program,const std::vector<std::string> & cflags,const std::vector<USDT> & usdt)109 StatusTuple BPF::init(const std::string& bpf_program,
110 const std::vector<std::string>& cflags,
111 const std::vector<USDT>& usdt) {
112 usdt_.reserve(usdt.size());
113 for (const auto& u : usdt) {
114 StatusTuple init_stp = init_usdt(u);
115 if (!init_stp.ok()) {
116 init_fail_reset();
117 return init_stp;
118 }
119 }
120
121 auto flags_len = cflags.size();
122 const char* flags[flags_len];
123 for (size_t i = 0; i < flags_len; i++)
124 flags[i] = cflags[i].c_str();
125
126 all_bpf_program_ += bpf_program;
127 if (bpf_module_->load_string(all_bpf_program_, flags, flags_len) != 0) {
128 init_fail_reset();
129 return StatusTuple(-1, "Unable to initialize BPF program");
130 }
131
132 return StatusTuple::OK();
133 };
134
~BPF()135 BPF::~BPF() {
136 auto res = detach_all();
137 if (!res.ok())
138 std::cerr << "Failed to detach all probes on destruction: " << std::endl
139 << res.msg() << std::endl;
140 bcc_free_buildsymcache(bsymcache_);
141 bsymcache_ = NULL;
142 }
143
detach_all()144 StatusTuple BPF::detach_all() {
145 bool has_error = false;
146 std::string error_msg;
147
148 for (auto& it : kprobes_) {
149 auto res = detach_kprobe_event(it.first, it.second);
150 if (!res.ok()) {
151 error_msg += "Failed to detach kprobe event " + it.first + ": ";
152 error_msg += res.msg() + "\n";
153 has_error = true;
154 }
155 }
156
157 for (auto& it : uprobes_) {
158 auto res = detach_uprobe_event(it.first, it.second);
159 if (!res.ok()) {
160 error_msg += "Failed to detach uprobe event " + it.first + ": ";
161 error_msg += res.msg() + "\n";
162 has_error = true;
163 }
164 }
165
166 for (auto& it : tracepoints_) {
167 auto res = detach_tracepoint_event(it.first, it.second);
168 if (!res.ok()) {
169 error_msg += "Failed to detach Tracepoint " + it.first + ": ";
170 error_msg += res.msg() + "\n";
171 has_error = true;
172 }
173 }
174
175 for (auto& it : raw_tracepoints_) {
176 auto res = detach_raw_tracepoint_event(it.first, it.second);
177 if (!res.ok()) {
178 error_msg += "Failed to detach Raw tracepoint " + it.first + ": ";
179 error_msg += res.msg() + "\n";
180 has_error = true;
181 }
182 }
183
184 for (auto& it : perf_buffers_) {
185 auto res = it.second->close_all_cpu();
186 if (!res.ok()) {
187 error_msg += "Failed to close perf buffer " + it.first + ": ";
188 error_msg += res.msg() + "\n";
189 has_error = true;
190 }
191 delete it.second;
192 }
193
194 for (auto& it : perf_event_arrays_) {
195 auto res = it.second->close_all_cpu();
196 if (!res.ok()) {
197 error_msg += "Failed to close perf event array " + it.first + ": ";
198 error_msg += res.msg() + "\n";
199 has_error = true;
200 }
201 delete it.second;
202 }
203
204 for (auto& it : perf_events_) {
205 auto res = detach_perf_event_all_cpu(it.second);
206 if (!res.ok()) {
207 error_msg += res.msg() + "\n";
208 has_error = true;
209 }
210 }
211
212 for (auto& it : funcs_) {
213 int res = close(it.second);
214 if (res != 0) {
215 error_msg += "Failed to unload BPF program for " + it.first + ": ";
216 error_msg += std::string(std::strerror(errno)) + "\n";
217 has_error = true;
218 }
219 }
220
221 if (has_error)
222 return StatusTuple(-1, error_msg);
223 else
224 return StatusTuple::OK();
225 }
226
attach_kprobe(const std::string & kernel_func,const std::string & probe_func,uint64_t kernel_func_offset,bpf_probe_attach_type attach_type,int maxactive)227 StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
228 const std::string& probe_func,
229 uint64_t kernel_func_offset,
230 bpf_probe_attach_type attach_type,
231 int maxactive) {
232 std::string probe_event = get_kprobe_event(kernel_func, attach_type);
233 if (kprobes_.find(probe_event) != kprobes_.end())
234 return StatusTuple(-1, "kprobe %s already attached", probe_event.c_str());
235
236 int probe_fd;
237 TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
238
239 int res_fd = bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(),
240 kernel_func.c_str(), kernel_func_offset,
241 maxactive);
242
243 if (res_fd < 0) {
244 TRY2(unload_func(probe_func));
245 return StatusTuple(-1, "Unable to attach %skprobe for %s using %s",
246 attach_type_debug(attach_type).c_str(),
247 kernel_func.c_str(), probe_func.c_str());
248 }
249
250 open_probe_t p = {};
251 p.perf_event_fd = res_fd;
252 p.func = probe_func;
253 kprobes_[probe_event] = std::move(p);
254 return StatusTuple::OK();
255 }
256
attach_uprobe(const std::string & binary_path,const std::string & symbol,const std::string & probe_func,uint64_t symbol_addr,bpf_probe_attach_type attach_type,pid_t pid,uint64_t symbol_offset,uint32_t ref_ctr_offset)257 StatusTuple BPF::attach_uprobe(const std::string& binary_path,
258 const std::string& symbol,
259 const std::string& probe_func,
260 uint64_t symbol_addr,
261 bpf_probe_attach_type attach_type, pid_t pid,
262 uint64_t symbol_offset,
263 uint32_t ref_ctr_offset) {
264
265 if (symbol_addr != 0 && symbol_offset != 0)
266 return StatusTuple(-1,
267 "Attachng uprobe with addr %lx and offset %lx is not supported",
268 symbol_addr, symbol_offset);
269
270 std::string module;
271 uint64_t offset;
272 TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset,
273 symbol_offset));
274
275 std::string probe_event = get_uprobe_event(module, offset, attach_type, pid);
276 if (uprobes_.find(probe_event) != uprobes_.end())
277 return StatusTuple(-1, "uprobe %s already attached", probe_event.c_str());
278
279 int probe_fd;
280 TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
281
282 int res_fd = bpf_attach_uprobe(probe_fd, attach_type, probe_event.c_str(),
283 binary_path.c_str(), offset, pid,
284 ref_ctr_offset);
285
286 if (res_fd < 0) {
287 TRY2(unload_func(probe_func));
288 return StatusTuple(
289 -1,
290 "Unable to attach %suprobe for binary %s symbol %s addr %lx "
291 "offset %lx using %s\n",
292 attach_type_debug(attach_type).c_str(), binary_path.c_str(),
293 symbol.c_str(), symbol_addr, symbol_offset, probe_func.c_str());
294 }
295
296 open_probe_t p = {};
297 p.perf_event_fd = res_fd;
298 p.func = probe_func;
299 uprobes_[probe_event] = std::move(p);
300 return StatusTuple::OK();
301 }
302
attach_usdt_without_validation(const USDT & u,pid_t pid)303 StatusTuple BPF::attach_usdt_without_validation(const USDT& u, pid_t pid) {
304 auto& probe = *static_cast<::USDT::Probe*>(u.probe_.get());
305 if (!uprobe_ref_ctr_supported() && !probe.enable(u.probe_func_))
306 return StatusTuple(-1, "Unable to enable USDT %s", u.print_name().c_str());
307
308 bool failed = false;
309 std::string err_msg;
310 int cnt = 0;
311 for (const auto& loc : probe.locations_) {
312 auto res = attach_uprobe(loc.bin_path_, std::string(), u.probe_func_,
313 loc.address_, BPF_PROBE_ENTRY, pid, 0,
314 probe.semaphore_offset());
315 if (!res.ok()) {
316 failed = true;
317 err_msg += "USDT " + u.print_name() + " at " + loc.bin_path_ +
318 " address " + std::to_string(loc.address_);
319 err_msg += ": " + res.msg() + "\n";
320 break;
321 }
322 cnt++;
323 }
324 if (failed) {
325 for (int i = 0; i < cnt; i++) {
326 auto res = detach_uprobe(probe.locations_[i].bin_path_, std::string(),
327 probe.locations_[i].address_, BPF_PROBE_ENTRY, pid);
328 if (!res.ok())
329 err_msg += "During clean up: " + res.msg() + "\n";
330 }
331 return StatusTuple(-1, err_msg);
332 } else {
333 return StatusTuple::OK();
334 }
335 }
336
attach_usdt(const USDT & usdt,pid_t pid)337 StatusTuple BPF::attach_usdt(const USDT& usdt, pid_t pid) {
338 for (const auto& u : usdt_) {
339 if (u == usdt) {
340 return attach_usdt_without_validation(u, pid);
341 }
342 }
343
344 return StatusTuple(-1, "USDT %s not found", usdt.print_name().c_str());
345 }
346
attach_usdt_all()347 StatusTuple BPF::attach_usdt_all() {
348 for (const auto& u : usdt_) {
349 auto res = attach_usdt_without_validation(u, -1);
350 if (!res.ok()) {
351 return res;
352 }
353 }
354
355 return StatusTuple::OK();
356 }
357
358
attach_tracepoint(const std::string & tracepoint,const std::string & probe_func)359 StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
360 const std::string& probe_func) {
361 if (tracepoints_.find(tracepoint) != tracepoints_.end())
362 return StatusTuple(-1, "Tracepoint %s already attached",
363 tracepoint.c_str());
364
365 auto pos = tracepoint.find(":");
366 if ((pos == std::string::npos) || (pos != tracepoint.rfind(":")))
367 return StatusTuple(-1, "Unable to parse Tracepoint %s", tracepoint.c_str());
368 std::string tp_category = tracepoint.substr(0, pos);
369 std::string tp_name = tracepoint.substr(pos + 1);
370
371 int probe_fd;
372 TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
373
374 int res_fd =
375 bpf_attach_tracepoint(probe_fd, tp_category.c_str(), tp_name.c_str());
376
377 if (res_fd < 0) {
378 TRY2(unload_func(probe_func));
379 return StatusTuple(-1, "Unable to attach Tracepoint %s using %s",
380 tracepoint.c_str(), probe_func.c_str());
381 }
382
383 open_probe_t p = {};
384 p.perf_event_fd = res_fd;
385 p.func = probe_func;
386 tracepoints_[tracepoint] = std::move(p);
387 return StatusTuple::OK();
388 }
389
attach_raw_tracepoint(const std::string & tracepoint,const std::string & probe_func)390 StatusTuple BPF::attach_raw_tracepoint(const std::string& tracepoint, const std::string& probe_func) {
391 if (raw_tracepoints_.find(tracepoint) != raw_tracepoints_.end())
392 return StatusTuple(-1, "Raw tracepoint %s already attached",
393 tracepoint.c_str());
394
395 int probe_fd;
396 TRY2(load_func(probe_func, BPF_PROG_TYPE_RAW_TRACEPOINT, probe_fd));
397
398 int res_fd = bpf_attach_raw_tracepoint(probe_fd, tracepoint.c_str());
399
400 if (res_fd < 0) {
401 TRY2(unload_func(probe_func));
402 return StatusTuple(-1, "Unable to attach Raw tracepoint %s using %s",
403 tracepoint.c_str(), probe_func.c_str());
404 }
405
406 open_probe_t p = {};
407 p.perf_event_fd = res_fd;
408 p.func = probe_func;
409 raw_tracepoints_[tracepoint] = std::move(p);
410 return StatusTuple::OK();
411 }
412
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,int cpu,int group_fd)413 StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config,
414 const std::string& probe_func,
415 uint64_t sample_period, uint64_t sample_freq,
416 pid_t pid, int cpu, int group_fd) {
417 auto ev_pair = std::make_pair(ev_type, ev_config);
418 if (perf_events_.find(ev_pair) != perf_events_.end())
419 return StatusTuple(-1, "Perf event type %d config %d already attached",
420 ev_type, ev_config);
421
422 int probe_fd;
423 TRY2(load_func(probe_func, BPF_PROG_TYPE_PERF_EVENT, probe_fd));
424
425 std::vector<int> cpus;
426 if (cpu >= 0)
427 cpus.push_back(cpu);
428 else
429 cpus = get_online_cpus();
430 auto fds = new std::vector<std::pair<int, int>>();
431 fds->reserve(cpus.size());
432 for (int i : cpus) {
433 int fd = bpf_attach_perf_event(probe_fd, ev_type, ev_config, sample_period,
434 sample_freq, pid, i, group_fd);
435 if (fd < 0) {
436 for (const auto& it : *fds)
437 close(it.second);
438 delete fds;
439 TRY2(unload_func(probe_func));
440 return StatusTuple(-1, "Failed to attach perf event type %d config %d",
441 ev_type, ev_config);
442 }
443 fds->emplace_back(i, fd);
444 }
445
446 open_probe_t p = {};
447 p.func = probe_func;
448 p.per_cpu_fd = fds;
449 perf_events_[ev_pair] = std::move(p);
450 return StatusTuple::OK();
451 }
452
attach_perf_event_raw(void * perf_event_attr,const std::string & probe_func,pid_t pid,int cpu,int group_fd,unsigned long extra_flags)453 StatusTuple BPF::attach_perf_event_raw(void* perf_event_attr,
454 const std::string& probe_func, pid_t pid,
455 int cpu, int group_fd,
456 unsigned long extra_flags) {
457 auto attr = static_cast<struct perf_event_attr*>(perf_event_attr);
458 auto ev_pair = std::make_pair(attr->type, attr->config);
459 if (perf_events_.find(ev_pair) != perf_events_.end())
460 return StatusTuple(-1, "Perf event type %d config %d already attached",
461 attr->type, attr->config);
462
463 int probe_fd;
464 TRY2(load_func(probe_func, BPF_PROG_TYPE_PERF_EVENT, probe_fd));
465
466 std::vector<int> cpus;
467 if (cpu >= 0)
468 cpus.push_back(cpu);
469 else
470 cpus = get_online_cpus();
471 auto fds = new std::vector<std::pair<int, int>>();
472 fds->reserve(cpus.size());
473 for (int i : cpus) {
474 int fd = bpf_attach_perf_event_raw(probe_fd, attr, pid, i, group_fd,
475 extra_flags);
476 if (fd < 0) {
477 for (const auto& it : *fds)
478 close(it.second);
479 delete fds;
480 TRY2(unload_func(probe_func));
481 return StatusTuple(-1, "Failed to attach perf event type %d config %d",
482 attr->type, attr->config);
483 }
484 fds->emplace_back(i, fd);
485 }
486
487 open_probe_t p = {};
488 p.func = probe_func;
489 p.per_cpu_fd = fds;
490 perf_events_[ev_pair] = std::move(p);
491 return StatusTuple::OK();
492 }
493
detach_kprobe(const std::string & kernel_func,bpf_probe_attach_type attach_type)494 StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
495 bpf_probe_attach_type attach_type) {
496 std::string event = get_kprobe_event(kernel_func, attach_type);
497
498 auto it = kprobes_.find(event);
499 if (it == kprobes_.end())
500 return StatusTuple(-1, "No open %skprobe for %s",
501 attach_type_debug(attach_type).c_str(),
502 kernel_func.c_str());
503
504 TRY2(detach_kprobe_event(it->first, it->second));
505 kprobes_.erase(it);
506 return StatusTuple::OK();
507 }
508
detach_uprobe(const std::string & binary_path,const std::string & symbol,uint64_t symbol_addr,bpf_probe_attach_type attach_type,pid_t pid,uint64_t symbol_offset)509 StatusTuple BPF::detach_uprobe(const std::string& binary_path,
510 const std::string& symbol, uint64_t symbol_addr,
511 bpf_probe_attach_type attach_type, pid_t pid,
512 uint64_t symbol_offset) {
513 std::string module;
514 uint64_t offset;
515 TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, module, offset,
516 symbol_offset));
517
518 std::string event = get_uprobe_event(module, offset, attach_type, pid);
519 auto it = uprobes_.find(event);
520 if (it == uprobes_.end())
521 return StatusTuple(-1, "No open %suprobe for binary %s symbol %s addr %lx",
522 attach_type_debug(attach_type).c_str(),
523 binary_path.c_str(), symbol.c_str(), symbol_addr);
524
525 TRY2(detach_uprobe_event(it->first, it->second));
526 uprobes_.erase(it);
527 return StatusTuple::OK();
528 }
529
detach_usdt_without_validation(const USDT & u,pid_t pid)530 StatusTuple BPF::detach_usdt_without_validation(const USDT& u, pid_t pid) {
531 auto& probe = *static_cast<::USDT::Probe*>(u.probe_.get());
532 bool failed = false;
533 std::string err_msg;
534 for (const auto& loc : probe.locations_) {
535 auto res = detach_uprobe(loc.bin_path_, std::string(), loc.address_,
536 BPF_PROBE_ENTRY, pid);
537 if (!res.ok()) {
538 failed = true;
539 err_msg += "USDT " + u.print_name() + " at " + loc.bin_path_ +
540 " address " + std::to_string(loc.address_);
541 err_msg += ": " + res.msg() + "\n";
542 }
543 }
544
545 if (!uprobe_ref_ctr_supported() && !probe.disable()) {
546 failed = true;
547 err_msg += "Unable to disable USDT " + u.print_name();
548 }
549
550 if (failed)
551 return StatusTuple(-1, err_msg);
552 else
553 return StatusTuple::OK();
554 }
555
detach_usdt(const USDT & usdt,pid_t pid)556 StatusTuple BPF::detach_usdt(const USDT& usdt, pid_t pid) {
557 for (const auto& u : usdt_) {
558 if (u == usdt) {
559 return detach_usdt_without_validation(u, pid);
560 }
561 }
562
563 return StatusTuple(-1, "USDT %s not found", usdt.print_name().c_str());
564 }
565
detach_usdt_all()566 StatusTuple BPF::detach_usdt_all() {
567 for (const auto& u : usdt_) {
568 auto ret = detach_usdt_without_validation(u, -1);
569 if (!ret.ok()) {
570 return ret;
571 }
572 }
573
574 return StatusTuple::OK();
575 }
576
detach_tracepoint(const std::string & tracepoint)577 StatusTuple BPF::detach_tracepoint(const std::string& tracepoint) {
578 auto it = tracepoints_.find(tracepoint);
579 if (it == tracepoints_.end())
580 return StatusTuple(-1, "No open Tracepoint %s", tracepoint.c_str());
581
582 TRY2(detach_tracepoint_event(it->first, it->second));
583 tracepoints_.erase(it);
584 return StatusTuple::OK();
585 }
586
detach_raw_tracepoint(const std::string & tracepoint)587 StatusTuple BPF::detach_raw_tracepoint(const std::string& tracepoint) {
588 auto it = raw_tracepoints_.find(tracepoint);
589 if (it == raw_tracepoints_.end())
590 return StatusTuple(-1, "No open Raw tracepoint %s", tracepoint.c_str());
591
592 TRY2(detach_raw_tracepoint_event(it->first, it->second));
593 raw_tracepoints_.erase(it);
594 return StatusTuple::OK();
595 }
596
detach_perf_event(uint32_t ev_type,uint32_t ev_config)597 StatusTuple BPF::detach_perf_event(uint32_t ev_type, uint32_t ev_config) {
598 auto it = perf_events_.find(std::make_pair(ev_type, ev_config));
599 if (it == perf_events_.end())
600 return StatusTuple(-1, "Perf Event type %d config %d not attached", ev_type,
601 ev_config);
602 TRY2(detach_perf_event_all_cpu(it->second));
603 perf_events_.erase(it);
604 return StatusTuple::OK();
605 }
606
detach_perf_event_raw(void * perf_event_attr)607 StatusTuple BPF::detach_perf_event_raw(void* perf_event_attr) {
608 auto attr = static_cast<struct perf_event_attr*>(perf_event_attr);
609 return detach_perf_event(attr->type, attr->config);
610 }
611
open_perf_event(const std::string & name,uint32_t type,uint64_t config)612 StatusTuple BPF::open_perf_event(const std::string& name, uint32_t type,
613 uint64_t config) {
614 if (perf_event_arrays_.find(name) == perf_event_arrays_.end()) {
615 TableStorage::iterator it;
616 if (!bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
617 return StatusTuple(-1, "open_perf_event: unable to find table_storage %s",
618 name.c_str());
619 perf_event_arrays_[name] = new BPFPerfEventArray(it->second);
620 }
621 auto table = perf_event_arrays_[name];
622 TRY2(table->open_all_cpu(type, config));
623 return StatusTuple::OK();
624 }
625
close_perf_event(const std::string & name)626 StatusTuple BPF::close_perf_event(const std::string& name) {
627 auto it = perf_event_arrays_.find(name);
628 if (it == perf_event_arrays_.end())
629 return StatusTuple(-1, "Perf Event for %s not open", name.c_str());
630 TRY2(it->second->close_all_cpu());
631 return StatusTuple::OK();
632 }
633
open_perf_buffer(const std::string & name,perf_reader_raw_cb cb,perf_reader_lost_cb lost_cb,void * cb_cookie,int page_cnt)634 StatusTuple BPF::open_perf_buffer(const std::string& name,
635 perf_reader_raw_cb cb,
636 perf_reader_lost_cb lost_cb, void* cb_cookie,
637 int page_cnt) {
638 if (perf_buffers_.find(name) == perf_buffers_.end()) {
639 TableStorage::iterator it;
640 if (!bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
641 return StatusTuple(-1,
642 "open_perf_buffer: unable to find table_storage %s",
643 name.c_str());
644 perf_buffers_[name] = new BPFPerfBuffer(it->second);
645 }
646 if ((page_cnt & (page_cnt - 1)) != 0)
647 return StatusTuple(-1, "open_perf_buffer page_cnt must be a power of two");
648 auto table = perf_buffers_[name];
649 TRY2(table->open_all_cpu(cb, lost_cb, cb_cookie, page_cnt));
650 return StatusTuple::OK();
651 }
652
close_perf_buffer(const std::string & name)653 StatusTuple BPF::close_perf_buffer(const std::string& name) {
654 auto it = perf_buffers_.find(name);
655 if (it == perf_buffers_.end())
656 return StatusTuple(-1, "Perf buffer for %s not open", name.c_str());
657 TRY2(it->second->close_all_cpu());
658 return StatusTuple::OK();
659 }
660
get_perf_buffer(const std::string & name)661 BPFPerfBuffer* BPF::get_perf_buffer(const std::string& name) {
662 auto it = perf_buffers_.find(name);
663 return (it == perf_buffers_.end()) ? nullptr : it->second;
664 }
665
poll_perf_buffer(const std::string & name,int timeout_ms)666 int BPF::poll_perf_buffer(const std::string& name, int timeout_ms) {
667 auto it = perf_buffers_.find(name);
668 if (it == perf_buffers_.end())
669 return -1;
670 return it->second->poll(timeout_ms);
671 }
672
load_func(const std::string & func_name,bpf_prog_type type,int & fd,unsigned flags)673 StatusTuple BPF::load_func(const std::string& func_name, bpf_prog_type type,
674 int& fd, unsigned flags) {
675 if (funcs_.find(func_name) != funcs_.end()) {
676 fd = funcs_[func_name];
677 return StatusTuple::OK();
678 }
679
680 uint8_t* func_start = bpf_module_->function_start(func_name);
681 if (!func_start)
682 return StatusTuple(-1, "Can't find start of function %s",
683 func_name.c_str());
684 size_t func_size = bpf_module_->function_size(func_name);
685
686 int log_level = 0;
687 if (flag_ & DEBUG_BPF_REGISTER_STATE)
688 log_level = 2;
689 else if (flag_ & DEBUG_BPF)
690 log_level = 1;
691
692 fd = bpf_module_->bcc_func_load(type, func_name.c_str(),
693 reinterpret_cast<struct bpf_insn*>(func_start), func_size,
694 bpf_module_->license(), bpf_module_->kern_version(),
695 log_level, nullptr, 0, nullptr, flags);
696
697 if (fd < 0)
698 return StatusTuple(-1, "Failed to load %s: %d", func_name.c_str(), fd);
699
700 int ret = bpf_module_->annotate_prog_tag(
701 func_name, fd, reinterpret_cast<struct bpf_insn*>(func_start), func_size);
702 if (ret < 0)
703 fprintf(stderr, "WARNING: cannot get prog tag, ignore saving source with program tag\n");
704 funcs_[func_name] = fd;
705 return StatusTuple::OK();
706 }
707
unload_func(const std::string & func_name)708 StatusTuple BPF::unload_func(const std::string& func_name) {
709 auto it = funcs_.find(func_name);
710 if (it == funcs_.end())
711 return StatusTuple::OK();
712
713 int res = close(it->second);
714 if (res != 0)
715 return StatusTuple(-1, "Can't close FD for %s: %d", it->first.c_str(), res);
716
717 funcs_.erase(it);
718 return StatusTuple::OK();
719 }
720
attach_func(int prog_fd,int attachable_fd,enum bpf_attach_type attach_type,uint64_t flags)721 StatusTuple BPF::attach_func(int prog_fd, int attachable_fd,
722 enum bpf_attach_type attach_type,
723 uint64_t flags) {
724 int res = bpf_module_->bcc_func_attach(prog_fd, attachable_fd, attach_type, flags);
725 if (res != 0)
726 return StatusTuple(-1, "Can't attach for prog_fd %d, attachable_fd %d, "
727 "attach_type %d, flags %ld: error %d",
728 prog_fd, attachable_fd, attach_type, flags, res);
729
730 return StatusTuple::OK();
731 }
732
detach_func(int prog_fd,int attachable_fd,enum bpf_attach_type attach_type)733 StatusTuple BPF::detach_func(int prog_fd, int attachable_fd,
734 enum bpf_attach_type attach_type) {
735 int res = bpf_module_->bcc_func_detach(prog_fd, attachable_fd, attach_type);
736 if (res != 0)
737 return StatusTuple(-1, "Can't detach for prog_fd %d, attachable_fd %d, "
738 "attach_type %d: error %d",
739 prog_fd, attachable_fd, attach_type, res);
740
741 return StatusTuple::OK();
742 }
743
get_syscall_fnname(const std::string & name)744 std::string BPF::get_syscall_fnname(const std::string& name) {
745 if (syscall_prefix_ == nullptr) {
746 KSyms ksym;
747 uint64_t addr;
748
749 if (ksym.resolve_name(nullptr, "sys_bpf", &addr))
750 syscall_prefix_.reset(new std::string("sys_"));
751 else if (ksym.resolve_name(nullptr, "__x64_sys_bpf", &addr))
752 syscall_prefix_.reset(new std::string("__x64_sys_"));
753 else
754 syscall_prefix_.reset(new std::string());
755 }
756
757 return *syscall_prefix_ + name;
758 }
759
check_binary_symbol(const std::string & binary_path,const std::string & symbol,uint64_t symbol_addr,std::string & module_res,uint64_t & offset_res,uint64_t symbol_offset)760 StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
761 const std::string& symbol,
762 uint64_t symbol_addr,
763 std::string& module_res,
764 uint64_t& offset_res,
765 uint64_t symbol_offset) {
766 bcc_symbol output;
767 int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
768 symbol_addr, -1, nullptr, &output);
769 if (res < 0)
770 return StatusTuple(
771 -1, "Unable to find offset for binary %s symbol %s address %lx",
772 binary_path.c_str(), symbol.c_str(), symbol_addr);
773
774 if (output.module) {
775 module_res = output.module;
776 ::free(const_cast<char*>(output.module));
777 } else {
778 module_res = "";
779 }
780 offset_res = output.offset + symbol_offset;
781 return StatusTuple::OK();
782 }
783
get_kprobe_event(const std::string & kernel_func,bpf_probe_attach_type type)784 std::string BPF::get_kprobe_event(const std::string& kernel_func,
785 bpf_probe_attach_type type) {
786 std::string res = attach_type_prefix(type) + "_";
787 res += sanitize_str(kernel_func, &BPF::kprobe_event_validator);
788 return res;
789 }
790
get_prog_table(const std::string & name)791 BPFProgTable BPF::get_prog_table(const std::string& name) {
792 TableStorage::iterator it;
793 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
794 return BPFProgTable(it->second);
795 return BPFProgTable({});
796 }
797
get_cgroup_array(const std::string & name)798 BPFCgroupArray BPF::get_cgroup_array(const std::string& name) {
799 TableStorage::iterator it;
800 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
801 return BPFCgroupArray(it->second);
802 return BPFCgroupArray({});
803 }
804
get_devmap_table(const std::string & name)805 BPFDevmapTable BPF::get_devmap_table(const std::string& name) {
806 TableStorage::iterator it;
807 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
808 return BPFDevmapTable(it->second);
809 return BPFDevmapTable({});
810 }
811
get_xskmap_table(const std::string & name)812 BPFXskmapTable BPF::get_xskmap_table(const std::string& name) {
813 TableStorage::iterator it;
814 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
815 return BPFXskmapTable(it->second);
816 return BPFXskmapTable({});
817 }
818
get_stack_table(const std::string & name,bool use_debug_file,bool check_debug_file_crc)819 BPFStackTable BPF::get_stack_table(const std::string& name, bool use_debug_file,
820 bool check_debug_file_crc) {
821 TableStorage::iterator it;
822 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
823 return BPFStackTable(it->second, use_debug_file, check_debug_file_crc);
824 return BPFStackTable({}, use_debug_file, check_debug_file_crc);
825 }
826
get_stackbuildid_table(const std::string & name,bool use_debug_file,bool check_debug_file_crc)827 BPFStackBuildIdTable BPF::get_stackbuildid_table(const std::string &name, bool use_debug_file,
828 bool check_debug_file_crc) {
829 TableStorage::iterator it;
830
831 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
832 return BPFStackBuildIdTable(it->second, use_debug_file, check_debug_file_crc, get_bsymcache());
833 return BPFStackBuildIdTable({}, use_debug_file, check_debug_file_crc, get_bsymcache());
834 }
835
get_sockmap_table(const std::string & name)836 BPFSockmapTable BPF::get_sockmap_table(const std::string& name) {
837 TableStorage::iterator it;
838 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
839 return BPFSockmapTable(it->second);
840 return BPFSockmapTable({});
841 }
842
get_sockhash_table(const std::string & name)843 BPFSockhashTable BPF::get_sockhash_table(const std::string& name) {
844 TableStorage::iterator it;
845 if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
846 return BPFSockhashTable(it->second);
847 return BPFSockhashTable({});
848 }
849
add_module(std::string module)850 bool BPF::add_module(std::string module)
851 {
852 return bcc_buildsymcache_add_module(get_bsymcache(), module.c_str()) != 0 ?
853 false : true;
854 }
855
get_uprobe_event(const std::string & binary_path,uint64_t offset,bpf_probe_attach_type type,pid_t pid)856 std::string BPF::get_uprobe_event(const std::string& binary_path,
857 uint64_t offset, bpf_probe_attach_type type,
858 pid_t pid) {
859 std::string res = attach_type_prefix(type) + "_";
860 res += sanitize_str(binary_path, &BPF::uprobe_path_validator);
861 res += "_0x" + uint_to_hex(offset);
862 if (pid != -1)
863 res += "_" + std::to_string(pid);
864 return res;
865 }
866
detach_kprobe_event(const std::string & event,open_probe_t & attr)867 StatusTuple BPF::detach_kprobe_event(const std::string& event,
868 open_probe_t& attr) {
869 bpf_close_perf_event_fd(attr.perf_event_fd);
870 TRY2(unload_func(attr.func));
871 if (bpf_detach_kprobe(event.c_str()) < 0)
872 return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str());
873 return StatusTuple::OK();
874 }
875
detach_uprobe_event(const std::string & event,open_probe_t & attr)876 StatusTuple BPF::detach_uprobe_event(const std::string& event,
877 open_probe_t& attr) {
878 bpf_close_perf_event_fd(attr.perf_event_fd);
879 TRY2(unload_func(attr.func));
880 if (bpf_detach_uprobe(event.c_str()) < 0)
881 return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str());
882 return StatusTuple::OK();
883 }
884
detach_tracepoint_event(const std::string & tracepoint,open_probe_t & attr)885 StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint,
886 open_probe_t& attr) {
887 bpf_close_perf_event_fd(attr.perf_event_fd);
888 TRY2(unload_func(attr.func));
889
890 // TODO: bpf_detach_tracepoint currently does nothing.
891 return StatusTuple::OK();
892 }
893
detach_raw_tracepoint_event(const std::string & tracepoint,open_probe_t & attr)894 StatusTuple BPF::detach_raw_tracepoint_event(const std::string& tracepoint,
895 open_probe_t& attr) {
896 TRY2(close(attr.perf_event_fd));
897 TRY2(unload_func(attr.func));
898
899 return StatusTuple::OK();
900 }
901
detach_perf_event_all_cpu(open_probe_t & attr)902 StatusTuple BPF::detach_perf_event_all_cpu(open_probe_t& attr) {
903 bool has_error = false;
904 std::string err_msg;
905 for (const auto& it : *attr.per_cpu_fd) {
906 int res = bpf_close_perf_event_fd(it.second);
907 if (res != 0) {
908 has_error = true;
909 err_msg += "Failed to close perf event FD " + std::to_string(it.second) +
910 " For CPU " + std::to_string(it.first) + ": ";
911 err_msg += std::string(std::strerror(errno)) + "\n";
912 }
913 }
914 delete attr.per_cpu_fd;
915 TRY2(unload_func(attr.func));
916
917 if (has_error)
918 return StatusTuple(-1, err_msg);
919 return StatusTuple::OK();
920 }
921
free_bcc_memory()922 int BPF::free_bcc_memory() {
923 return bcc_free_memory();
924 }
925
USDT(const std::string & binary_path,const std::string & provider,const std::string & name,const std::string & probe_func)926 USDT::USDT(const std::string& binary_path, const std::string& provider,
927 const std::string& name, const std::string& probe_func)
928 : initialized_(false),
929 binary_path_(binary_path),
930 pid_(-1),
931 provider_(provider),
932 name_(name),
933 probe_func_(probe_func),
934 mod_match_inode_only_(1) {}
935
USDT(pid_t pid,const std::string & provider,const std::string & name,const std::string & probe_func)936 USDT::USDT(pid_t pid, const std::string& provider, const std::string& name,
937 const std::string& probe_func)
938 : initialized_(false),
939 binary_path_(),
940 pid_(pid),
941 provider_(provider),
942 name_(name),
943 probe_func_(probe_func),
944 mod_match_inode_only_(1) {}
945
USDT(const std::string & binary_path,pid_t pid,const std::string & provider,const std::string & name,const std::string & probe_func)946 USDT::USDT(const std::string& binary_path, pid_t pid,
947 const std::string& provider, const std::string& name,
948 const std::string& probe_func)
949 : initialized_(false),
950 binary_path_(binary_path),
951 pid_(pid),
952 provider_(provider),
953 name_(name),
954 probe_func_(probe_func),
955 mod_match_inode_only_(1) {}
956
USDT(const USDT & usdt)957 USDT::USDT(const USDT& usdt)
958 : initialized_(false),
959 binary_path_(usdt.binary_path_),
960 pid_(usdt.pid_),
961 provider_(usdt.provider_),
962 name_(usdt.name_),
963 probe_func_(usdt.probe_func_),
964 mod_match_inode_only_(usdt.mod_match_inode_only_) {}
965
USDT(USDT && usdt)966 USDT::USDT(USDT&& usdt) noexcept
967 : initialized_(usdt.initialized_),
968 binary_path_(std::move(usdt.binary_path_)),
969 pid_(usdt.pid_),
970 provider_(std::move(usdt.provider_)),
971 name_(std::move(usdt.name_)),
972 probe_func_(std::move(usdt.probe_func_)),
973 probe_(std::move(usdt.probe_)),
974 program_text_(std::move(usdt.program_text_)),
975 mod_match_inode_only_(usdt.mod_match_inode_only_) {
976 usdt.initialized_ = false;
977 }
978
operator ==(const USDT & other) const979 bool USDT::operator==(const USDT& other) const {
980 return (provider_ == other.provider_) && (name_ == other.name_) &&
981 (binary_path_ == other.binary_path_) && (pid_ == other.pid_) &&
982 (probe_func_ == other.probe_func_);
983 }
984
set_probe_matching_kludge(uint8_t kludge)985 int USDT::set_probe_matching_kludge(uint8_t kludge) {
986 if (kludge != 0 && kludge != 1)
987 return -1;
988
989 mod_match_inode_only_ = kludge;
990 return 0;
991 }
992
init()993 StatusTuple USDT::init() {
994 std::unique_ptr<::USDT::Context> ctx;
995 if (!binary_path_.empty() && pid_ > 0)
996 ctx.reset(new ::USDT::Context(pid_, binary_path_, mod_match_inode_only_));
997 else if (!binary_path_.empty())
998 ctx.reset(new ::USDT::Context(binary_path_, mod_match_inode_only_));
999 else if (pid_ > 0)
1000 ctx.reset(new ::USDT::Context(pid_, mod_match_inode_only_));
1001 else
1002 return StatusTuple(-1, "No valid Binary Path or PID provided");
1003
1004 if (!ctx->loaded())
1005 return StatusTuple(-1, "Unable to load USDT " + print_name());
1006
1007 auto deleter = [](void* probe) { delete static_cast<::USDT::Probe*>(probe); };
1008 for (auto& p : ctx->probes_) {
1009 if (p->provider_ == provider_ && p->name_ == name_) {
1010 // Take ownership of the probe that we are interested in, and avoid it
1011 // being destructed when we destruct the USDT::Context instance
1012 probe_ = std::unique_ptr<void, std::function<void(void*)>>(p.release(),
1013 deleter);
1014 p.swap(ctx->probes_.back());
1015 ctx->probes_.pop_back();
1016 break;
1017 }
1018 }
1019 if (!probe_)
1020 return StatusTuple(-1, "Unable to find USDT " + print_name());
1021 ctx.reset(nullptr);
1022 auto& probe = *static_cast<::USDT::Probe*>(probe_.get());
1023
1024 std::ostringstream stream;
1025 if (!probe.usdt_getarg(stream, probe_func_))
1026 return StatusTuple(
1027 -1, "Unable to generate program text for USDT " + print_name());
1028 program_text_ = ::USDT::USDT_PROGRAM_HEADER + stream.str();
1029
1030 initialized_ = true;
1031 return StatusTuple::OK();
1032 }
1033
1034 } // namespace ebpf
1035