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