xref: /aosp_15_r20/external/bcc/src/cc/api/BPF.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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