• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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