xref: /aosp_15_r20/external/bcc/src/cc/api/BPF.h (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 #pragma once
18 
19 #include <cctype>
20 #include <cstdint>
21 #include <memory>
22 #include <ostream>
23 #include <string>
24 
25 #include "BPFTable.h"
26 #include "bcc_exception.h"
27 #include "bcc_syms.h"
28 #include "bpf_module.h"
29 #include "linux/bpf.h"
30 #include "libbpf.h"
31 #include "table_storage.h"
32 
33 static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8;
34 
35 namespace ebpf {
36 
37 struct open_probe_t {
38   int perf_event_fd;
39   std::string func;
40   std::vector<std::pair<int, int>>* per_cpu_fd;
41 };
42 
43 class BPF;
44 
45 class USDT {
46  public:
47   USDT(const std::string& binary_path, const std::string& provider,
48        const std::string& name, const std::string& probe_func);
49   USDT(pid_t pid, const std::string& provider, const std::string& name,
50        const std::string& probe_func);
51   USDT(const std::string& binary_path, pid_t pid, const std::string& provider,
52        const std::string& name, const std::string& probe_func);
53   USDT(const USDT& usdt);
54   USDT(USDT&& usdt) noexcept;
55 
binary_path()56   const std::string &binary_path() const { return binary_path_; }
pid()57   pid_t pid() const { return pid_; }
provider()58   const std::string &provider() const { return provider_; }
name()59   const std::string &name() const { return name_; }
probe_func()60   const std::string &probe_func() const { return probe_func_; }
61 
62   StatusTuple init();
63 
64   bool operator==(const USDT& other) const;
65 
print_name()66   std::string print_name() const {
67     return provider_ + ":" + name_ + " from binary " + binary_path_ + " PID " +
68            std::to_string(pid_) + " for probe " + probe_func_;
69   }
70 
71   friend std::ostream& operator<<(std::ostream& out, const USDT& usdt) {
72     return out << usdt.provider_ << ":" << usdt.name_ << " from binary "
73                << usdt.binary_path_ << " PID " << usdt.pid_ << " for probe "
74                << usdt.probe_func_;
75   }
76 
77   // When the kludge flag is set to 1 (default), we will only match on inode
78   // when searching for modules in /proc/PID/maps that might contain the
79   // tracepoint we're looking for.
80   // By setting this to 0, we will match on both inode and
81   // (dev_major, dev_minor), which is a more accurate way to uniquely
82   // identify a file, but may fail depending on the filesystem backing the
83   // target file (see bcc#2715)
84   //
85   // This hack exists because btrfs and overlayfs report different device
86   // numbers for files in /proc/PID/maps vs stat syscall. Don't use it unless
87   // you've had issues with inode collisions. Both btrfs and overlayfs are
88   // known to require inode-only resolution to accurately match a file.
89   //
90   // set_probe_matching_kludge(0) must be called before USDTs are submitted to
91   // BPF::init()
92   int set_probe_matching_kludge(uint8_t kludge);
93 
94  private:
95   bool initialized_;
96 
97   std::string binary_path_;
98   pid_t pid_;
99 
100   std::string provider_;
101   std::string name_;
102   std::string probe_func_;
103 
104   std::unique_ptr<void, std::function<void(void*)>> probe_;
105   std::string program_text_;
106 
107   uint8_t mod_match_inode_only_;
108 
109   friend class BPF;
110 };
111 
112 class BPF {
113  public:
114   static const int BPF_MAX_STACK_DEPTH = 127;
115 
116   explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr,
117                bool rw_engine_enabled = bpf_module_rw_engine_enabled(),
118                const std::string &maps_ns = "",
119                bool allow_rlimit = true)
flag_(flag)120       : flag_(flag),
121         bsymcache_(NULL),
122         bpf_module_(new BPFModule(flag, ts, rw_engine_enabled, maps_ns,
123                     allow_rlimit)) {}
124   StatusTuple init(const std::string& bpf_program,
125                    const std::vector<std::string>& cflags = {},
126                    const std::vector<USDT>& usdt = {});
127 
128   StatusTuple init_usdt(const USDT& usdt);
129 
130   ~BPF();
131   StatusTuple detach_all();
132 
133   StatusTuple attach_kprobe(const std::string& kernel_func,
134                             const std::string& probe_func,
135                             uint64_t kernel_func_offset = 0,
136                             bpf_probe_attach_type = BPF_PROBE_ENTRY,
137                             int maxactive = 0);
138   StatusTuple detach_kprobe(
139       const std::string& kernel_func,
140       bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
141 
142   StatusTuple attach_uprobe(const std::string& binary_path,
143                             const std::string& symbol,
144                             const std::string& probe_func,
145                             uint64_t symbol_addr = 0,
146                             bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
147                             pid_t pid = -1,
148                             uint64_t symbol_offset = 0,
149                             uint32_t ref_ctr_offset = 0);
150   StatusTuple detach_uprobe(const std::string& binary_path,
151                             const std::string& symbol, uint64_t symbol_addr = 0,
152                             bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
153                             pid_t pid = -1,
154                             uint64_t symbol_offset = 0);
155   StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1);
156   StatusTuple attach_usdt_all();
157   StatusTuple detach_usdt(const USDT& usdt, pid_t pid = -1);
158   StatusTuple detach_usdt_all();
159 
160   StatusTuple attach_tracepoint(const std::string& tracepoint,
161                                 const std::string& probe_func);
162   StatusTuple detach_tracepoint(const std::string& tracepoint);
163 
164   StatusTuple attach_raw_tracepoint(const std::string& tracepoint,
165                                     const std::string& probe_func);
166   StatusTuple detach_raw_tracepoint(const std::string& tracepoint);
167 
168   StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config,
169                                 const std::string& probe_func,
170                                 uint64_t sample_period, uint64_t sample_freq,
171                                 pid_t pid = -1, int cpu = -1,
172                                 int group_fd = -1);
173   StatusTuple attach_perf_event_raw(void* perf_event_attr,
174                                     const std::string& probe_func,
175                                     pid_t pid = -1, int cpu = -1,
176                                     int group_fd = -1,
177                                     unsigned long extra_flags = 0);
178   StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config);
179   StatusTuple detach_perf_event_raw(void* perf_event_attr);
180   std::string get_syscall_fnname(const std::string& name);
181 
get_table(const std::string & name)182   BPFTable get_table(const std::string& name) {
183     TableStorage::iterator it;
184     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
185       return BPFTable(it->second);
186     return BPFTable({});
187   }
188 
189   template <class ValueType>
get_array_table(const std::string & name)190   BPFArrayTable<ValueType> get_array_table(const std::string& name) {
191     TableStorage::iterator it;
192     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
193       return BPFArrayTable<ValueType>(it->second);
194     return BPFArrayTable<ValueType>({});
195   }
196 
197   template <class ValueType>
get_percpu_array_table(const std::string & name)198   BPFPercpuArrayTable<ValueType> get_percpu_array_table(
199       const std::string& name) {
200     TableStorage::iterator it;
201     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
202       return BPFPercpuArrayTable<ValueType>(it->second);
203     return BPFPercpuArrayTable<ValueType>({});
204   }
205 
206   template <class KeyType, class ValueType>
get_hash_table(const std::string & name)207   BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) {
208     TableStorage::iterator it;
209     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
210       return BPFHashTable<KeyType, ValueType>(it->second);
211     return BPFHashTable<KeyType, ValueType>({});
212   }
213 
214   template <class KeyType, class ValueType>
get_percpu_hash_table(const std::string & name)215   BPFPercpuHashTable<KeyType, ValueType> get_percpu_hash_table(
216       const std::string& name) {
217     TableStorage::iterator it;
218     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
219       return BPFPercpuHashTable<KeyType, ValueType>(it->second);
220     return BPFPercpuHashTable<KeyType, ValueType>({});
221   }
222 
223   template <class ValueType>
get_sk_storage_table(const std::string & name)224   BPFSkStorageTable<ValueType> get_sk_storage_table(const std::string& name) {
225     TableStorage::iterator it;
226     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
227       return BPFSkStorageTable<ValueType>(it->second);
228     return BPFSkStorageTable<ValueType>({});
229   }
230 
231   template <class ValueType>
get_inode_storage_table(const std::string & name)232   BPFInodeStorageTable<ValueType> get_inode_storage_table(const std::string& name) {
233     TableStorage::iterator it;
234     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
235       return BPFInodeStorageTable<ValueType>(it->second);
236     return BPFInodeStorageTable<ValueType>({});
237   }
238 
239   template <class ValueType>
get_task_storage_table(const std::string & name)240   BPFTaskStorageTable<ValueType> get_task_storage_table(const std::string& name) {
241     TableStorage::iterator it;
242     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
243       return BPFTaskStorageTable<ValueType>(it->second);
244     return BPFTaskStorageTable<ValueType>({});
245   }
246 
247   template <class ValueType>
get_cg_storage_table(const std::string & name)248   BPFCgStorageTable<ValueType> get_cg_storage_table(const std::string& name) {
249     TableStorage::iterator it;
250     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
251       return BPFCgStorageTable<ValueType>(it->second);
252     return BPFCgStorageTable<ValueType>({});
253   }
254 
255   template <class ValueType>
get_percpu_cg_storage_table(const std::string & name)256   BPFPercpuCgStorageTable<ValueType> get_percpu_cg_storage_table(const std::string& name) {
257     TableStorage::iterator it;
258     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
259       return BPFPercpuCgStorageTable<ValueType>(it->second);
260     return BPFPercpuCgStorageTable<ValueType>({});
261   }
262 
263   template <class ValueType>
get_queuestack_table(const std::string & name)264   BPFQueueStackTable<ValueType> get_queuestack_table(const std::string& name) {
265     TableStorage::iterator it;
266     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
267       return BPFQueueStackTable<ValueType>(it->second);
268     return BPFQueueStackTable<ValueType>({});
269   }
270 
get_bsymcache(void)271   void* get_bsymcache(void) {
272     if (bsymcache_ == NULL) {
273       bsymcache_ = bcc_buildsymcache_new();
274     }
275     return bsymcache_;
276   }
277 
278   BPFProgTable get_prog_table(const std::string& name);
279 
280   BPFCgroupArray get_cgroup_array(const std::string& name);
281 
282   BPFDevmapTable get_devmap_table(const std::string& name);
283 
284   BPFXskmapTable get_xskmap_table(const std::string& name);
285 
286   BPFSockmapTable get_sockmap_table(const std::string& name);
287 
288   BPFSockhashTable get_sockhash_table(const std::string& name);
289 
290   BPFStackTable get_stack_table(const std::string& name,
291                                 bool use_debug_file = true,
292                                 bool check_debug_file_crc = true);
293 
294   BPFStackBuildIdTable get_stackbuildid_table(const std::string &name,
295                                               bool use_debug_file = true,
296                                               bool check_debug_file_crc = true);
297   template <class KeyType>
get_map_in_map_table(const std::string & name)298   BPFMapInMapTable<KeyType> get_map_in_map_table(const std::string& name){
299       TableStorage::iterator it;
300       if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
301         return BPFMapInMapTable<KeyType>(it->second);
302       return BPFMapInMapTable<KeyType>({});
303   }
304 
305   bool add_module(std::string module);
306 
307   StatusTuple open_perf_event(const std::string& name, uint32_t type,
308                               uint64_t config, int pid = -1);
309 
310   StatusTuple close_perf_event(const std::string& name);
311 
312   // Open a Perf Buffer of given name, providing callback and callback cookie
313   // to use when polling. BPF class owns the opened Perf Buffer and will free
314   // it on-demand or on destruction.
315   StatusTuple open_perf_buffer(const std::string& name, perf_reader_raw_cb cb,
316                                perf_reader_lost_cb lost_cb = nullptr,
317                                void* cb_cookie = nullptr,
318                                int page_cnt = DEFAULT_PERF_BUFFER_PAGE_CNT);
319   // Close and free the Perf Buffer of given name.
320   StatusTuple close_perf_buffer(const std::string& name);
321   // Obtain an pointer to the opened BPFPerfBuffer instance of given name.
322   // Will return nullptr if such open Perf Buffer doesn't exist.
323   BPFPerfBuffer* get_perf_buffer(const std::string& name);
324   // Poll an opened Perf Buffer of given name with given timeout, using callback
325   // provided when opening. Do nothing if such open Perf Buffer doesn't exist.
326   // Returns:
327   //   -1 on error or if perf buffer with such name doesn't exist;
328   //   0, if no data was available before timeout;
329   //   number of CPUs that have new data, otherwise.
330   int poll_perf_buffer(const std::string& name, int timeout_ms = -1);
331 
332   StatusTuple load_func(const std::string& func_name, enum bpf_prog_type type,
333                         int& fd, unsigned flags = 0, enum bpf_attach_type = (bpf_attach_type) -1);
334   StatusTuple unload_func(const std::string& func_name);
335 
336   StatusTuple attach_func(int prog_fd, int attachable_fd,
337                           enum bpf_attach_type attach_type,
338                           uint64_t flags);
339   StatusTuple detach_func(int prog_fd, int attachable_fd,
340                           enum bpf_attach_type attach_type);
341 
342   int free_bcc_memory();
343 
344  private:
345   std::string get_kprobe_event(const std::string& kernel_func,
346                                bpf_probe_attach_type type);
347   std::string get_uprobe_event(const std::string& binary_path, uint64_t offset,
348                                bpf_probe_attach_type type, pid_t pid);
349 
350   StatusTuple attach_usdt_without_validation(const USDT& usdt, pid_t pid);
351   StatusTuple detach_usdt_without_validation(const USDT& usdt, pid_t pid);
352 
353   StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr);
354   StatusTuple detach_uprobe_event(const std::string& event, open_probe_t& attr);
355   StatusTuple detach_tracepoint_event(const std::string& tracepoint,
356                                       open_probe_t& attr);
357   StatusTuple detach_raw_tracepoint_event(const std::string& tracepoint,
358                                           open_probe_t& attr);
359   StatusTuple detach_perf_event_all_cpu(open_probe_t& attr);
360 
attach_type_debug(bpf_probe_attach_type type)361   std::string attach_type_debug(bpf_probe_attach_type type) {
362     switch (type) {
363     case BPF_PROBE_ENTRY:
364       return "";
365     case BPF_PROBE_RETURN:
366       return "return ";
367     }
368     return "ERROR";
369   }
370 
attach_type_prefix(bpf_probe_attach_type type)371   std::string attach_type_prefix(bpf_probe_attach_type type) {
372     switch (type) {
373     case BPF_PROBE_ENTRY:
374       return "p";
375     case BPF_PROBE_RETURN:
376       return "r";
377     }
378     return "ERROR";
379   }
380 
kprobe_event_validator(char c)381   static bool kprobe_event_validator(char c) {
382     return (c != '+') && (c != '.');
383   }
384 
uprobe_path_validator(char c)385   static bool uprobe_path_validator(char c) {
386     return std::isalpha(c) || std::isdigit(c) || (c == '_');
387   }
388 
389   StatusTuple check_binary_symbol(const std::string& binary_path,
390                                   const std::string& symbol,
391                                   uint64_t symbol_addr, std::string& module_res,
392                                   uint64_t& offset_res,
393                                   uint64_t symbol_offset = 0);
394 
395   void init_fail_reset();
396 
397   int flag_;
398 
399   void *bsymcache_;
400 
401   std::unique_ptr<std::string> syscall_prefix_;
402 
403   std::unique_ptr<BPFModule> bpf_module_;
404 
405   std::map<std::string, int> funcs_;
406 
407   std::vector<USDT> usdt_;
408   std::string all_bpf_program_;
409 
410   std::map<std::string, open_probe_t> kprobes_;
411   std::map<std::string, open_probe_t> uprobes_;
412   std::map<std::string, open_probe_t> tracepoints_;
413   std::map<std::string, open_probe_t> raw_tracepoints_;
414   std::map<std::string, BPFPerfBuffer*> perf_buffers_;
415   std::map<std::string, BPFPerfEventArray*> perf_event_arrays_;
416   std::map<std::pair<uint32_t, uint32_t>, open_probe_t> perf_events_;
417 };
418 
419 }  // namespace ebpf
420