• 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 #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 "compat/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 USDT;
44 
45 class BPF {
46  public:
47   static const int BPF_MAX_STACK_DEPTH = 127;
48 
49   explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr,
50                bool rw_engine_enabled = true, const std::string &maps_ns = "")
flag_(flag)51       : flag_(flag),
52       bpf_module_(new BPFModule(flag, ts, rw_engine_enabled, maps_ns)) {}
53   StatusTuple init(const std::string& bpf_program,
54                    const std::vector<std::string>& cflags = {},
55                    const std::vector<USDT>& usdt = {});
56 
57   ~BPF();
58   StatusTuple detach_all();
59 
60   StatusTuple attach_kprobe(const std::string& kernel_func,
61                             const std::string& probe_func,
62                             uint64_t kernel_func_offset = 0,
63                             bpf_probe_attach_type = BPF_PROBE_ENTRY);
64   StatusTuple detach_kprobe(
65       const std::string& kernel_func,
66       bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY);
67 
68   StatusTuple attach_uprobe(const std::string& binary_path,
69                             const std::string& symbol,
70                             const std::string& probe_func,
71                             uint64_t symbol_addr = 0,
72                             bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
73                             pid_t pid = -1);
74   StatusTuple detach_uprobe(const std::string& binary_path,
75                             const std::string& symbol, uint64_t symbol_addr = 0,
76                             bpf_probe_attach_type attach_type = BPF_PROBE_ENTRY,
77                             pid_t pid = -1);
78   StatusTuple attach_usdt(const USDT& usdt, pid_t pid = -1);
79   StatusTuple detach_usdt(const USDT& usdt, pid_t pid = -1);
80 
81   StatusTuple attach_tracepoint(const std::string& tracepoint,
82                                 const std::string& probe_func);
83   StatusTuple detach_tracepoint(const std::string& tracepoint);
84 
85   StatusTuple attach_perf_event(uint32_t ev_type, uint32_t ev_config,
86                                 const std::string& probe_func,
87                                 uint64_t sample_period, uint64_t sample_freq,
88                                 pid_t pid = -1, int cpu = -1,
89                                 int group_fd = -1);
90   StatusTuple attach_perf_event_raw(void* perf_event_attr,
91                                     const std::string& probe_func,
92                                     pid_t pid = -1, int cpu = -1,
93                                     int group_fd = -1,
94                                     unsigned long extra_flags = 0);
95   StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config);
96   StatusTuple detach_perf_event_raw(void* perf_event_attr);
97   std::string get_syscall_fnname(const std::string& name);
98 
get_table(const std::string & name)99   BPFTable get_table(const std::string& name) {
100     TableStorage::iterator it;
101     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
102       return BPFTable(it->second);
103     return BPFTable({});
104   }
105 
106   template <class ValueType>
get_array_table(const std::string & name)107   BPFArrayTable<ValueType> get_array_table(const std::string& name) {
108     TableStorage::iterator it;
109     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
110       return BPFArrayTable<ValueType>(it->second);
111     return BPFArrayTable<ValueType>({});
112   }
113 
114   template <class ValueType>
get_percpu_array_table(const std::string & name)115   BPFPercpuArrayTable<ValueType> get_percpu_array_table(
116       const std::string& name) {
117     TableStorage::iterator it;
118     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
119       return BPFPercpuArrayTable<ValueType>(it->second);
120     return BPFPercpuArrayTable<ValueType>({});
121   }
122 
123   template <class KeyType, class ValueType>
get_hash_table(const std::string & name)124   BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) {
125     TableStorage::iterator it;
126     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
127       return BPFHashTable<KeyType, ValueType>(it->second);
128     return BPFHashTable<KeyType, ValueType>({});
129   }
130 
131   template <class KeyType, class ValueType>
get_percpu_hash_table(const std::string & name)132   BPFPercpuHashTable<KeyType, ValueType> get_percpu_hash_table(
133       const std::string& name) {
134     TableStorage::iterator it;
135     if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
136       return BPFPercpuHashTable<KeyType, ValueType>(it->second);
137     return BPFPercpuHashTable<KeyType, ValueType>({});
138   }
139 
140   BPFProgTable get_prog_table(const std::string& name);
141 
142   BPFCgroupArray get_cgroup_array(const std::string& name);
143 
144   BPFDevmapTable get_devmap_table(const std::string& name);
145 
146   BPFStackTable get_stack_table(const std::string& name,
147                                 bool use_debug_file = true,
148                                 bool check_debug_file_crc = true);
149 
150   StatusTuple open_perf_event(const std::string& name, uint32_t type,
151                               uint64_t config);
152 
153   StatusTuple close_perf_event(const std::string& name);
154 
155   // Open a Perf Buffer of given name, providing callback and callback cookie
156   // to use when polling. BPF class owns the opened Perf Buffer and will free
157   // it on-demand or on destruction.
158   StatusTuple open_perf_buffer(const std::string& name, perf_reader_raw_cb cb,
159                                perf_reader_lost_cb lost_cb = nullptr,
160                                void* cb_cookie = nullptr,
161                                int page_cnt = DEFAULT_PERF_BUFFER_PAGE_CNT);
162   // Close and free the Perf Buffer of given name.
163   StatusTuple close_perf_buffer(const std::string& name);
164   // Obtain an pointer to the opened BPFPerfBuffer instance of given name.
165   // Will return nullptr if such open Perf Buffer doesn't exist.
166   BPFPerfBuffer* get_perf_buffer(const std::string& name);
167   // Poll an opened Perf Buffer of given name with given timeout, using callback
168   // provided when opening. Do nothing if such open Perf Buffer doesn't exist.
169   // Returns:
170   //   -1 on error or if perf buffer with such name doesn't exist;
171   //   0, if no data was available before timeout;
172   //   number of CPUs that have new data, otherwise.
173   int poll_perf_buffer(const std::string& name, int timeout_ms = -1);
174 
175   StatusTuple load_func(const std::string& func_name, enum bpf_prog_type type,
176                         int& fd);
177   StatusTuple unload_func(const std::string& func_name);
178 
179  private:
180   std::string get_kprobe_event(const std::string& kernel_func,
181                                bpf_probe_attach_type type);
182   std::string get_uprobe_event(const std::string& binary_path, uint64_t offset,
183                                bpf_probe_attach_type type, pid_t pid);
184 
185   StatusTuple detach_kprobe_event(const std::string& event, open_probe_t& attr);
186   StatusTuple detach_uprobe_event(const std::string& event, open_probe_t& attr);
187   StatusTuple detach_tracepoint_event(const std::string& tracepoint,
188                                       open_probe_t& attr);
189   StatusTuple detach_perf_event_all_cpu(open_probe_t& attr);
190 
attach_type_debug(bpf_probe_attach_type type)191   std::string attach_type_debug(bpf_probe_attach_type type) {
192     switch (type) {
193     case BPF_PROBE_ENTRY:
194       return "";
195     case BPF_PROBE_RETURN:
196       return "return ";
197     }
198     return "ERROR";
199   }
200 
attach_type_prefix(bpf_probe_attach_type type)201   std::string attach_type_prefix(bpf_probe_attach_type type) {
202     switch (type) {
203     case BPF_PROBE_ENTRY:
204       return "p";
205     case BPF_PROBE_RETURN:
206       return "r";
207     }
208     return "ERROR";
209   }
210 
kprobe_event_validator(char c)211   static bool kprobe_event_validator(char c) {
212     return (c != '+') && (c != '.');
213   }
214 
uprobe_path_validator(char c)215   static bool uprobe_path_validator(char c) {
216     return std::isalpha(c) || std::isdigit(c) || (c == '_');
217   }
218 
219   StatusTuple check_binary_symbol(const std::string& binary_path,
220                                   const std::string& symbol,
221                                   uint64_t symbol_addr, std::string& module_res,
222                                   uint64_t& offset_res);
223 
224   int flag_;
225 
226   std::unique_ptr<std::string> syscall_prefix_;
227 
228   std::unique_ptr<BPFModule> bpf_module_;
229 
230   std::map<std::string, int> funcs_;
231 
232   std::vector<USDT> usdt_;
233 
234   std::map<std::string, open_probe_t> kprobes_;
235   std::map<std::string, open_probe_t> uprobes_;
236   std::map<std::string, open_probe_t> tracepoints_;
237   std::map<std::string, BPFPerfBuffer*> perf_buffers_;
238   std::map<std::string, BPFPerfEventArray*> perf_event_arrays_;
239   std::map<std::pair<uint32_t, uint32_t>, open_probe_t> perf_events_;
240 };
241 
242 class USDT {
243  public:
244   USDT(const std::string& binary_path, const std::string& provider,
245        const std::string& name, const std::string& probe_func);
246   USDT(pid_t pid, const std::string& provider, const std::string& name,
247        const std::string& probe_func);
248   USDT(const std::string& binary_path, pid_t pid, const std::string& provider,
249        const std::string& name, const std::string& probe_func);
250   USDT(const USDT& usdt);
251   USDT(USDT&& usdt) noexcept;
252 
253   StatusTuple init();
254 
255   bool operator==(const USDT& other) const;
256 
print_name()257   std::string print_name() const {
258     return provider_ + ":" + name_ + " from binary " + binary_path_ + " PID " +
259            std::to_string(pid_) + " for probe " + probe_func_;
260   }
261 
262   friend std::ostream& operator<<(std::ostream& out, const USDT& usdt) {
263     return out << usdt.provider_ << ":" << usdt.name_ << " from binary "
264                << usdt.binary_path_ << " PID " << usdt.pid_ << " for probe "
265                << usdt.probe_func_;
266   }
267 
268  private:
269   bool initialized_;
270 
271   std::string binary_path_;
272   pid_t pid_;
273 
274   std::string provider_;
275   std::string name_;
276   std::string probe_func_;
277 
278   std::unique_ptr<void, std::function<void(void*)>> probe_;
279   std::string program_text_;
280 
281   friend class BPF;
282 };
283 
284 }  // namespace ebpf
285