blob: 08bdd15c94e0373f2776e8edd89749689d7f10d8 [file] [log] [blame]
Teng Qin335cbe42016-11-23 12:23:03 -08001/*
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 <unistd.h>
19#include <cstdio>
20#include <exception>
21#include <iostream>
22#include <memory>
23#include <sstream>
24#include <vector>
25
Teng Qin3b4e31f2016-11-28 21:58:46 -080026#include "bcc_exception.h"
Teng Qin335cbe42016-11-23 12:23:03 -080027#include "bcc_syms.h"
28#include "bpf_module.h"
Teng Qin335cbe42016-11-23 12:23:03 -080029#include "libbpf.h"
30#include "perf_reader.h"
31
32#include "BPF.h"
33
34namespace ebpf {
35
36std::string uint_to_hex(uint64_t value) {
37 std::stringstream ss;
38 ss << std::hex << value;
39 return ss.str();
40}
41
42std::string sanitize_str(std::string str, bool (*validator)(char),
43 char replacement = '_') {
44 for (size_t i = 0; i < str.length(); i++)
45 if (!validator(str[i]))
46 str[i] = replacement;
47 return str;
48}
49
50StatusTuple BPF::init(const std::string& bpf_program,
51 std::vector<std::string> cflags) {
52 auto flags_len = cflags.size();
53 const char* flags[flags_len];
54 for (size_t i = 0; i < flags_len; i++)
55 flags[i] = cflags[i].c_str();
56 if (bpf_module_->load_string(bpf_program, flags, flags_len) != 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -080057 return StatusTuple(-1, "Unable to initialize BPF program");
58 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -080059};
60
61BPF::~BPF() {
62 auto res = detach_all();
Teng Qin13ebe8e2016-11-29 16:29:08 -080063 if (res.code() != 0)
Teng Qin335cbe42016-11-23 12:23:03 -080064 std::cerr << "Failed to detach all probes on destruction: " << std::endl
Teng Qin13ebe8e2016-11-29 16:29:08 -080065 << res.msg() << std::endl;
Teng Qin335cbe42016-11-23 12:23:03 -080066}
67
68StatusTuple BPF::detach_all() {
69 bool has_error = false;
70 std::string error_msg;
71
72 for (auto it : kprobes_) {
73 auto res = detach_kprobe_event(it.first, it.second);
Teng Qin13ebe8e2016-11-29 16:29:08 -080074 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -080075 error_msg += "Failed to detach kprobe event " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -080076 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -080077 has_error = true;
78 }
79 }
80
81 for (auto it : uprobes_) {
82 auto res = detach_uprobe_event(it.first, it.second);
Teng Qin13ebe8e2016-11-29 16:29:08 -080083 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -080084 error_msg += "Failed to detach uprobe event " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -080085 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -080086 has_error = true;
87 }
88 }
89
90 for (auto it : tracepoints_) {
91 auto res = detach_tracepoint_event(it.first, it.second);
Teng Qin13ebe8e2016-11-29 16:29:08 -080092 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -080093 error_msg += "Failed to detach Tracepoint " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -080094 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -080095 has_error = true;
96 }
97 }
98
99 for (auto it : perf_buffers_) {
100 auto res = it.second->close();
Teng Qin13ebe8e2016-11-29 16:29:08 -0800101 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -0800102 error_msg += "Failed to close perf buffer " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -0800103 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -0800104 has_error = true;
105 }
106 delete it.second;
107 }
108
109 if (has_error)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800110 return StatusTuple(-1, error_msg);
Teng Qin335cbe42016-11-23 12:23:03 -0800111 else
Teng Qin13ebe8e2016-11-29 16:29:08 -0800112 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800113}
114
115StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
116 const std::string& probe_func,
117 bpf_attach_type attach_type,
118 pid_t pid, int cpu, int group_fd,
119 perf_reader_cb cb, void* cb_cookie) {
120 int probe_fd;
121 TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
122
123 std::string probe_event = get_kprobe_event(kernel_func, attach_type);
124 if (kprobes_.find(probe_event) != kprobes_.end()) {
125 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800126 return StatusTuple(-1, "kprobe %s already attached", probe_event.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800127 }
128
129 std::string probe_event_desc = attach_type_prefix(attach_type);
130 probe_event_desc += ":kprobes/" + probe_event + " " + kernel_func;
131
132 void* res =
133 bpf_attach_kprobe(probe_fd, probe_event.c_str(), probe_event_desc.c_str(),
134 pid, cpu, group_fd, cb, cb_cookie);
135
136 if (!res) {
137 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800138 return StatusTuple(-1, "Unable to attach %skprobe for %s using %s",
139 attach_type_debug(attach_type).c_str(),
140 kernel_func.c_str(), probe_func.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800141 }
142
143 open_probe_t p = {};
144 p.reader_ptr = res;
145 p.func = probe_func;
146 kprobes_[probe_event] = std::move(p);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800147 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800148}
149
150StatusTuple BPF::attach_uprobe(const std::string& binary_path,
151 const std::string& symbol,
152 const std::string& probe_func,
153 uint64_t symbol_addr,
154 bpf_attach_type attach_type,
155 pid_t pid, int cpu, int group_fd,
156 perf_reader_cb cb, void* cb_cookie) {
157 int probe_fd;
158 TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
159
160 bcc_symbol sym = bcc_symbol();
161 TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
162
163 std::string probe_event =
164 get_uprobe_event(sym.module, sym.offset, attach_type);
165 if (uprobes_.find(probe_event) != uprobes_.end()) {
166 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800167 return StatusTuple(-1, "uprobe %s already attached", probe_event.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800168 }
169
170 std::string probe_event_desc = attach_type_prefix(attach_type);
171 probe_event_desc += ":uprobes/" + probe_event + " ";
172 probe_event_desc += binary_path + ":0x" + uint_to_hex(sym.offset);
173
174 void* res =
175 bpf_attach_uprobe(probe_fd, probe_event.c_str(), probe_event_desc.c_str(),
176 pid, cpu, group_fd, cb, cb_cookie);
177
178 if (!res) {
179 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800180 return StatusTuple(
Teng Qin335cbe42016-11-23 12:23:03 -0800181 -1,
182 "Unable to attach %suprobe for binary %s symbol %s addr %lx using %s\n",
183 attach_type_debug(attach_type).c_str(), binary_path.c_str(),
184 symbol.c_str(), symbol_addr, probe_func.c_str());
185 }
186
187 open_probe_t p = {};
188 p.reader_ptr = res;
189 p.func = probe_func;
190 uprobes_[probe_event] = std::move(p);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800191 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800192}
193
194StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
195 const std::string& probe_func,
196 pid_t pid, int cpu, int group_fd,
197 perf_reader_cb cb, void* cb_cookie) {
198 int probe_fd;
199 TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
200
201 if (tracepoints_.find(tracepoint) != tracepoints_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800202 return StatusTuple(-1, "Tracepoint %s already attached",
203 tracepoint.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800204
205 auto pos = tracepoint.find(":");
206 if ((pos == std::string::npos) || (pos != tracepoint.rfind(":")))
Teng Qin13ebe8e2016-11-29 16:29:08 -0800207 return StatusTuple(-1, "Unable to parse Tracepoint %s", tracepoint.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800208 std::string tp_category = tracepoint.substr(0, pos);
209 std::string tp_name = tracepoint.substr(pos + 1);
210
211 void* res =
212 bpf_attach_tracepoint(probe_fd, tp_category.c_str(), tp_name.c_str(), pid,
213 cpu, group_fd, cb, cb_cookie);
214
215 if (!res) {
216 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800217 return StatusTuple(-1, "Unable to attach Tracepoint %s using %s",
218 tracepoint.c_str(), probe_func.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800219 }
220
221 open_probe_t p = {};
222 p.reader_ptr = res;
223 p.func = probe_func;
224 tracepoints_[tracepoint] = std::move(p);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800225 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800226}
227
228StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
229 bpf_attach_type attach_type) {
230 std::string event = get_kprobe_event(kernel_func, attach_type);
231
232 auto it = kprobes_.find(event);
233 if (it == kprobes_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800234 return StatusTuple(-1, "No open %skprobe for %s",
235 attach_type_debug(attach_type).c_str(),
236 kernel_func.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800237
238 TRY2(detach_kprobe_event(it->first, it->second));
239 kprobes_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800240 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800241}
242
243StatusTuple BPF::detach_uprobe(const std::string& binary_path,
244 const std::string& symbol, uint64_t symbol_addr,
245 bpf_attach_type attach_type) {
246 bcc_symbol sym = bcc_symbol();
247 TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
248
249 std::string event = get_uprobe_event(sym.module, sym.offset, attach_type);
250 auto it = uprobes_.find(event);
251 if (it == uprobes_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800252 return StatusTuple(-1, "No open %suprobe for binary %s symbol %s addr %lx",
253 attach_type_debug(attach_type).c_str(),
254 binary_path.c_str(), symbol.c_str(), symbol_addr);
Teng Qin335cbe42016-11-23 12:23:03 -0800255
256 TRY2(detach_uprobe_event(it->first, it->second));
257 uprobes_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800258 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800259}
260
261StatusTuple BPF::detach_tracepoint(const std::string& tracepoint) {
262 auto it = tracepoints_.find(tracepoint);
263 if (it == tracepoints_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800264 return StatusTuple(-1, "No open Tracepoint %s", tracepoint.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800265
266 TRY2(detach_tracepoint_event(it->first, it->second));
267 tracepoints_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800268 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800269}
270
271StatusTuple BPF::open_perf_buffer(const std::string& name,
272 perf_reader_raw_cb cb, void* cb_cookie) {
273 if (perf_buffers_.find(name) == perf_buffers_.end())
274 perf_buffers_[name] = new BPFPerfBuffer(bpf_module_.get(), name);
275 auto table = perf_buffers_[name];
276 TRY2(table->open(cb, cb_cookie));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800277 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800278}
279
280StatusTuple BPF::close_perf_buffer(const std::string& name) {
281 auto it = perf_buffers_.find(name);
282 if (it == perf_buffers_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800283 return StatusTuple(-1, "Perf buffer for %s not open", name.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800284 TRY2(it->second->close());
Teng Qin13ebe8e2016-11-29 16:29:08 -0800285 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800286}
287
288void BPF::poll_perf_buffer(const std::string& name, int timeout) {
289 auto it = perf_buffers_.find(name);
290 if (it == perf_buffers_.end())
291 return;
292 it->second->poll(timeout);
293}
294
295StatusTuple BPF::load_func(const std::string& func_name,
296 enum bpf_prog_type type, int& fd) {
297 if (funcs_.find(func_name) != funcs_.end()) {
298 fd = funcs_[func_name];
Teng Qin13ebe8e2016-11-29 16:29:08 -0800299 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800300 }
301
302 uint8_t* func_start = bpf_module_->function_start(func_name);
303 if (!func_start)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800304 return StatusTuple(-1, "Can't find start of function %s",
305 func_name.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800306 size_t func_size = bpf_module_->function_size(func_name);
307
308 fd = bpf_prog_load(type, reinterpret_cast<struct bpf_insn*>(func_start),
309 func_size, bpf_module_->license(),
310 bpf_module_->kern_version(), nullptr,
311 0 // BPFModule will handle error printing
312 );
313
314 if (fd < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800315 return StatusTuple(-1, "Failed to load %s: %d", func_name.c_str(), fd);
Teng Qin335cbe42016-11-23 12:23:03 -0800316 funcs_[func_name] = fd;
Teng Qin13ebe8e2016-11-29 16:29:08 -0800317 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800318}
319
320StatusTuple BPF::unload_func(const std::string& func_name) {
321 auto it = funcs_.find(func_name);
322 if (it == funcs_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800323 return StatusTuple(-1, "Probe function %s not loaded", func_name.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800324
325 int res = close(it->second);
326 if (res != 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800327 return StatusTuple(-1, "Can't close FD for %s: %d", it->first.c_str(), res);
Teng Qin335cbe42016-11-23 12:23:03 -0800328
329 funcs_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800330 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800331}
332
333StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
334 const std::string& symbol,
335 uint64_t symbol_addr, bcc_symbol* output) {
336 int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
337 symbol_addr, output);
338 if (res < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800339 return StatusTuple(
340 -1, "Unable to find offset for binary %s symbol %s address %lx",
341 binary_path.c_str(), symbol.c_str(), symbol_addr);
342 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800343}
344
345std::string BPF::get_kprobe_event(const std::string& kernel_func,
346 bpf_attach_type type) {
347 std::string res = attach_type_prefix(type) + "_";
348 res += sanitize_str(kernel_func, &BPF::kprobe_event_validator);
349 return res;
350}
351
352std::string BPF::get_uprobe_event(const std::string& binary_path,
353 uint64_t offset, bpf_attach_type type) {
354 std::string res = attach_type_prefix(type) + "_";
355 res += sanitize_str(binary_path, &BPF::uprobe_path_validator);
356 res += "_0x" + uint_to_hex(offset);
357 return res;
358}
359
360StatusTuple BPF::detach_kprobe_event(const std::string& event,
361 open_probe_t& attr) {
362 if (attr.reader_ptr) {
363 perf_reader_free(attr.reader_ptr);
364 attr.reader_ptr = nullptr;
365 }
366 TRY2(unload_func(attr.func));
367 std::string detach_event = "-:kprobes/" + event;
368 if (bpf_detach_kprobe(detach_event.c_str()) < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800369 return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str());
370 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800371}
372
373StatusTuple BPF::detach_uprobe_event(const std::string& event,
374 open_probe_t& attr) {
375 if (attr.reader_ptr) {
376 perf_reader_free(attr.reader_ptr);
377 attr.reader_ptr = nullptr;
378 }
379 TRY2(unload_func(attr.func));
380 std::string detach_event = "-:uprobes/" + event;
381 if (bpf_detach_uprobe(detach_event.c_str()) < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800382 return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str());
383 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800384}
385
386StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint,
387 open_probe_t& attr) {
388 if (attr.reader_ptr) {
389 perf_reader_free(attr.reader_ptr);
390 attr.reader_ptr = nullptr;
391 }
392 TRY2(unload_func(attr.func));
393
394 // TODO: bpf_detach_tracepoint currently does nothing.
Teng Qin13ebe8e2016-11-29 16:29:08 -0800395 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800396}
397
398} // namespace ebpf