blob: 3b0ad35c152f1807c3d8c8d8e2a3227655400574 [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>
Teng Qin53c7f4c2016-12-08 18:03:33 -080020#include <cstring>
Teng Qin335cbe42016-11-23 12:23:03 -080021#include <exception>
22#include <iostream>
23#include <memory>
24#include <sstream>
Teng Qindfd9c632016-12-08 17:46:13 -080025#include <utility>
Teng Qin335cbe42016-11-23 12:23:03 -080026#include <vector>
27
Teng Qin3b4e31f2016-11-28 21:58:46 -080028#include "bcc_exception.h"
Teng Qin335cbe42016-11-23 12:23:03 -080029#include "bcc_syms.h"
30#include "bpf_module.h"
Brenden Blancofaea8c82017-03-29 09:58:31 -070031#include "common.h"
Teng Qin335cbe42016-11-23 12:23:03 -080032#include "libbpf.h"
33#include "perf_reader.h"
Brenden Blancofaea8c82017-03-29 09:58:31 -070034#include "table_storage.h"
Teng Qin6e682232016-12-15 13:20:09 -080035#include "usdt.h"
Teng Qin335cbe42016-11-23 12:23:03 -080036
37#include "BPF.h"
38
39namespace ebpf {
40
41std::string uint_to_hex(uint64_t value) {
42 std::stringstream ss;
43 ss << std::hex << value;
44 return ss.str();
45}
46
47std::string sanitize_str(std::string str, bool (*validator)(char),
48 char replacement = '_') {
49 for (size_t i = 0; i < str.length(); i++)
50 if (!validator(str[i]))
51 str[i] = replacement;
52 return str;
53}
54
55StatusTuple BPF::init(const std::string& bpf_program,
Teng Qin6e682232016-12-15 13:20:09 -080056 std::vector<std::string> cflags, std::vector<USDT> usdt) {
57 std::string all_bpf_program;
58
59 for (auto u : usdt) {
60 if (!u.initialized_)
61 TRY2(u.init());
62 all_bpf_program += u.program_text_;
63 usdt_.push_back(std::move(u));
64 }
65
Teng Qin335cbe42016-11-23 12:23:03 -080066 auto flags_len = cflags.size();
67 const char* flags[flags_len];
68 for (size_t i = 0; i < flags_len; i++)
69 flags[i] = cflags[i].c_str();
Teng Qin6e682232016-12-15 13:20:09 -080070
71 all_bpf_program += bpf_program;
72 if (bpf_module_->load_string(all_bpf_program, flags, flags_len) != 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -080073 return StatusTuple(-1, "Unable to initialize BPF program");
Teng Qin6e682232016-12-15 13:20:09 -080074
Teng Qin13ebe8e2016-11-29 16:29:08 -080075 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -080076};
77
78BPF::~BPF() {
79 auto res = detach_all();
Teng Qin13ebe8e2016-11-29 16:29:08 -080080 if (res.code() != 0)
Teng Qin335cbe42016-11-23 12:23:03 -080081 std::cerr << "Failed to detach all probes on destruction: " << std::endl
Teng Qin13ebe8e2016-11-29 16:29:08 -080082 << res.msg() << std::endl;
Teng Qin335cbe42016-11-23 12:23:03 -080083}
84
85StatusTuple BPF::detach_all() {
86 bool has_error = false;
87 std::string error_msg;
88
89 for (auto it : kprobes_) {
90 auto res = detach_kprobe_event(it.first, it.second);
Teng Qin13ebe8e2016-11-29 16:29:08 -080091 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -080092 error_msg += "Failed to detach kprobe event " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -080093 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -080094 has_error = true;
95 }
96 }
97
98 for (auto it : uprobes_) {
99 auto res = detach_uprobe_event(it.first, it.second);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800100 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -0800101 error_msg += "Failed to detach uprobe event " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -0800102 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -0800103 has_error = true;
104 }
105 }
106
107 for (auto it : tracepoints_) {
108 auto res = detach_tracepoint_event(it.first, it.second);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800109 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -0800110 error_msg += "Failed to detach Tracepoint " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -0800111 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -0800112 has_error = true;
113 }
114 }
115
116 for (auto it : perf_buffers_) {
Teng Qincae072a2016-12-09 00:07:55 -0800117 auto res = it.second->close_all_cpu();
Teng Qin13ebe8e2016-11-29 16:29:08 -0800118 if (res.code() != 0) {
Teng Qin335cbe42016-11-23 12:23:03 -0800119 error_msg += "Failed to close perf buffer " + it.first + ": ";
Teng Qin13ebe8e2016-11-29 16:29:08 -0800120 error_msg += res.msg() + "\n";
Teng Qin335cbe42016-11-23 12:23:03 -0800121 has_error = true;
122 }
123 delete it.second;
124 }
125
Teng Qindfd9c632016-12-08 17:46:13 -0800126 for (auto it : perf_events_) {
127 auto res = detach_perf_event_all_cpu(it.second);
128 if (res.code() != 0) {
129 error_msg += res.msg() + "\n";
130 has_error = true;
131 }
132 }
133
Teng Qin53c7f4c2016-12-08 18:03:33 -0800134 for (auto it : funcs_) {
135 int res = close(it.second);
136 if (res != 0) {
137 error_msg += "Failed to unload BPF program for " + it.first + ": ";
Teng Qindfd9c632016-12-08 17:46:13 -0800138 error_msg += std::string(std::strerror(errno)) + "\n";
Teng Qin53c7f4c2016-12-08 18:03:33 -0800139 has_error = true;
140 }
141 }
142
Teng Qin335cbe42016-11-23 12:23:03 -0800143 if (has_error)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800144 return StatusTuple(-1, error_msg);
Teng Qin335cbe42016-11-23 12:23:03 -0800145 else
Teng Qin13ebe8e2016-11-29 16:29:08 -0800146 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800147}
148
149StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
150 const std::string& probe_func,
Derek7174d932017-01-30 21:03:02 -0800151 bpf_probe_attach_type attach_type,
Teng Qin335cbe42016-11-23 12:23:03 -0800152 pid_t pid, int cpu, int group_fd,
153 perf_reader_cb cb, void* cb_cookie) {
Teng Qin53c7f4c2016-12-08 18:03:33 -0800154 std::string probe_event = get_kprobe_event(kernel_func, attach_type);
155 if (kprobes_.find(probe_event) != kprobes_.end())
156 return StatusTuple(-1, "kprobe %s already attached", probe_event.c_str());
157
Teng Qin335cbe42016-11-23 12:23:03 -0800158 int probe_fd;
159 TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
160
Teng Qin335cbe42016-11-23 12:23:03 -0800161 void* res =
Dereke4da6c22017-01-28 16:11:28 -0800162 bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(), kernel_func.c_str(),
Teng Qin335cbe42016-11-23 12:23:03 -0800163 pid, cpu, group_fd, cb, cb_cookie);
164
165 if (!res) {
166 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800167 return StatusTuple(-1, "Unable to attach %skprobe for %s using %s",
168 attach_type_debug(attach_type).c_str(),
169 kernel_func.c_str(), probe_func.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800170 }
171
172 open_probe_t p = {};
173 p.reader_ptr = res;
174 p.func = probe_func;
175 kprobes_[probe_event] = std::move(p);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800176 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800177}
178
179StatusTuple BPF::attach_uprobe(const std::string& binary_path,
180 const std::string& symbol,
181 const std::string& probe_func,
182 uint64_t symbol_addr,
Derek7174d932017-01-30 21:03:02 -0800183 bpf_probe_attach_type attach_type,
Teng Qin335cbe42016-11-23 12:23:03 -0800184 pid_t pid, int cpu, int group_fd,
185 perf_reader_cb cb, void* cb_cookie) {
Teng Qin335cbe42016-11-23 12:23:03 -0800186 bcc_symbol sym = bcc_symbol();
187 TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
188
189 std::string probe_event =
190 get_uprobe_event(sym.module, sym.offset, attach_type);
Teng Qin53c7f4c2016-12-08 18:03:33 -0800191 if (uprobes_.find(probe_event) != uprobes_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800192 return StatusTuple(-1, "uprobe %s already attached", probe_event.c_str());
Teng Qin53c7f4c2016-12-08 18:03:33 -0800193
194 int probe_fd;
195 TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd));
Teng Qin335cbe42016-11-23 12:23:03 -0800196
Teng Qin335cbe42016-11-23 12:23:03 -0800197 void* res =
Dereke4da6c22017-01-28 16:11:28 -0800198 bpf_attach_uprobe(probe_fd, attach_type, probe_event.c_str(), binary_path.c_str(),
199 sym.offset, pid, cpu, group_fd, cb, cb_cookie);
Teng Qin335cbe42016-11-23 12:23:03 -0800200
201 if (!res) {
202 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800203 return StatusTuple(
Teng Qin335cbe42016-11-23 12:23:03 -0800204 -1,
205 "Unable to attach %suprobe for binary %s symbol %s addr %lx using %s\n",
206 attach_type_debug(attach_type).c_str(), binary_path.c_str(),
207 symbol.c_str(), symbol_addr, probe_func.c_str());
208 }
209
210 open_probe_t p = {};
211 p.reader_ptr = res;
212 p.func = probe_func;
213 uprobes_[probe_event] = std::move(p);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800214 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800215}
216
Teng Qin6e682232016-12-15 13:20:09 -0800217StatusTuple BPF::attach_usdt(const USDT& usdt, pid_t pid, int cpu,
218 int group_fd) {
219 for (auto& u : usdt_)
220 if (u == usdt) {
221 bool failed = false;
222 std::string err_msg;
223 int cnt = 0;
224 for (auto addr : u.addresses_) {
225 auto res =
226 attach_uprobe(u.binary_path_, std::string(), u.probe_func_, addr);
227 if (res.code() != 0) {
228 failed = true;
229 err_msg += "USDT " + u.print_name() + " at " + std::to_string(addr);
230 err_msg += ": " + res.msg() + "\n";
231 break;
232 }
233 cnt++;
234 }
235 if (failed) {
236 for (int i = 0; i < cnt; i++) {
237 auto res =
238 detach_uprobe(u.binary_path_, std::string(), u.addresses_[i]);
239 err_msg += "During clean up: " + res.msg() + "\n";
240 }
241 return StatusTuple(-1, err_msg);
242 } else
243 return StatusTuple(0);
244 }
245 return StatusTuple(-1, "USDT %s not found", usdt.print_name().c_str());
246}
247
Teng Qin335cbe42016-11-23 12:23:03 -0800248StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
249 const std::string& probe_func,
250 pid_t pid, int cpu, int group_fd,
251 perf_reader_cb cb, void* cb_cookie) {
Teng Qin335cbe42016-11-23 12:23:03 -0800252 if (tracepoints_.find(tracepoint) != tracepoints_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800253 return StatusTuple(-1, "Tracepoint %s already attached",
254 tracepoint.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800255
256 auto pos = tracepoint.find(":");
257 if ((pos == std::string::npos) || (pos != tracepoint.rfind(":")))
Teng Qin13ebe8e2016-11-29 16:29:08 -0800258 return StatusTuple(-1, "Unable to parse Tracepoint %s", tracepoint.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800259 std::string tp_category = tracepoint.substr(0, pos);
260 std::string tp_name = tracepoint.substr(pos + 1);
261
Teng Qin53c7f4c2016-12-08 18:03:33 -0800262 int probe_fd;
263 TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
264
Teng Qin335cbe42016-11-23 12:23:03 -0800265 void* res =
266 bpf_attach_tracepoint(probe_fd, tp_category.c_str(), tp_name.c_str(), pid,
267 cpu, group_fd, cb, cb_cookie);
268
269 if (!res) {
270 TRY2(unload_func(probe_func));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800271 return StatusTuple(-1, "Unable to attach Tracepoint %s using %s",
272 tracepoint.c_str(), probe_func.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800273 }
274
275 open_probe_t p = {};
276 p.reader_ptr = res;
277 p.func = probe_func;
278 tracepoints_[tracepoint] = std::move(p);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800279 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800280}
281
Teng Qindfd9c632016-12-08 17:46:13 -0800282StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config,
283 const std::string& probe_func,
284 uint64_t sample_period, uint64_t sample_freq,
285 pid_t pid, int cpu, int group_fd) {
286 auto ev_pair = std::make_pair(ev_type, ev_config);
287 if (perf_events_.find(ev_pair) != perf_events_.end())
288 return StatusTuple(-1, "Perf event type %d config %d already attached",
289 ev_type, ev_config);
290
291 int probe_fd;
292 TRY2(load_func(probe_func, BPF_PROG_TYPE_PERF_EVENT, probe_fd));
293
294 auto fds = new std::map<int, int>();
Andreas Gerstmayr7e0784d2017-01-16 16:35:58 +0100295 std::vector<int> cpus;
Teng Qindfd9c632016-12-08 17:46:13 -0800296 if (cpu >= 0)
Andreas Gerstmayr7e0784d2017-01-16 16:35:58 +0100297 cpus.push_back(cpu);
298 else
299 cpus = get_online_cpus();
300 for (int i: cpus) {
Teng Qindfd9c632016-12-08 17:46:13 -0800301 int fd = bpf_attach_perf_event(probe_fd, ev_type, ev_config, sample_period,
302 sample_freq, pid, i, group_fd);
303 if (fd < 0) {
304 for (auto it : *fds)
305 close(it.second);
306 delete fds;
307 TRY2(unload_func(probe_func));
308 return StatusTuple(-1, "Failed to attach perf event type %d config %d",
309 ev_type, ev_config);
310 }
311 fds->emplace(i, fd);
312 }
313
314 open_probe_t p = {};
315 p.func = probe_func;
316 p.per_cpu_fd = fds;
317 perf_events_[ev_pair] = std::move(p);
318 return StatusTuple(0);
319}
320
Teng Qin335cbe42016-11-23 12:23:03 -0800321StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
Derek7174d932017-01-30 21:03:02 -0800322 bpf_probe_attach_type attach_type) {
Teng Qin335cbe42016-11-23 12:23:03 -0800323 std::string event = get_kprobe_event(kernel_func, attach_type);
324
325 auto it = kprobes_.find(event);
326 if (it == kprobes_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800327 return StatusTuple(-1, "No open %skprobe for %s",
328 attach_type_debug(attach_type).c_str(),
329 kernel_func.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800330
331 TRY2(detach_kprobe_event(it->first, it->second));
332 kprobes_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800333 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800334}
335
336StatusTuple BPF::detach_uprobe(const std::string& binary_path,
337 const std::string& symbol, uint64_t symbol_addr,
Derek7174d932017-01-30 21:03:02 -0800338 bpf_probe_attach_type attach_type) {
Teng Qin335cbe42016-11-23 12:23:03 -0800339 bcc_symbol sym = bcc_symbol();
340 TRY2(check_binary_symbol(binary_path, symbol, symbol_addr, &sym));
341
342 std::string event = get_uprobe_event(sym.module, sym.offset, attach_type);
343 auto it = uprobes_.find(event);
344 if (it == uprobes_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800345 return StatusTuple(-1, "No open %suprobe for binary %s symbol %s addr %lx",
346 attach_type_debug(attach_type).c_str(),
347 binary_path.c_str(), symbol.c_str(), symbol_addr);
Teng Qin335cbe42016-11-23 12:23:03 -0800348
349 TRY2(detach_uprobe_event(it->first, it->second));
350 uprobes_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800351 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800352}
353
Teng Qin6e682232016-12-15 13:20:09 -0800354StatusTuple BPF::detach_usdt(const USDT& usdt) {
355 for (auto& u : usdt_)
356 if (u == usdt) {
357 bool failed = false;
358 std::string err_msg;
359 for (auto addr : u.addresses_) {
360 auto res = detach_uprobe(u.binary_path_, std::string(), addr);
361 if (res.code() != 0) {
362 failed = true;
363 err_msg += "USDT " + u.print_name() + " at " + std::to_string(addr);
364 err_msg += ": " + res.msg() + "\n";
365 }
366 }
367 if (failed)
368 return StatusTuple(-1, err_msg);
369 else
370 return StatusTuple(0);
371 }
372 return StatusTuple(-1, "USDT %s not found", usdt.print_name().c_str());
373}
374
Teng Qin335cbe42016-11-23 12:23:03 -0800375StatusTuple BPF::detach_tracepoint(const std::string& tracepoint) {
376 auto it = tracepoints_.find(tracepoint);
377 if (it == tracepoints_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800378 return StatusTuple(-1, "No open Tracepoint %s", tracepoint.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800379
380 TRY2(detach_tracepoint_event(it->first, it->second));
381 tracepoints_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800382 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800383}
384
Teng Qindfd9c632016-12-08 17:46:13 -0800385StatusTuple BPF::detach_perf_event(uint32_t ev_type, uint32_t ev_config) {
386 auto it = perf_events_.find(std::make_pair(ev_type, ev_config));
387 if (it == perf_events_.end())
388 return StatusTuple(-1, "Perf Event type %d config %d not attached",
389 ev_type, ev_config);
390 TRY2(detach_perf_event_all_cpu(it->second));
391 perf_events_.erase(it);
392 return StatusTuple(0);
393}
394
Teng Qin335cbe42016-11-23 12:23:03 -0800395StatusTuple BPF::open_perf_buffer(const std::string& name,
Mark Drayton5f5687e2017-02-20 18:13:03 +0000396 perf_reader_raw_cb cb, void* cb_cookie,
397 int page_cnt) {
Teng Qin335cbe42016-11-23 12:23:03 -0800398 if (perf_buffers_.find(name) == perf_buffers_.end())
399 perf_buffers_[name] = new BPFPerfBuffer(bpf_module_.get(), name);
Mark Drayton5f5687e2017-02-20 18:13:03 +0000400 if ((page_cnt & (page_cnt - 1)) != 0)
401 return StatusTuple(-1, "open_perf_buffer page_cnt must be a power of two");
Teng Qin335cbe42016-11-23 12:23:03 -0800402 auto table = perf_buffers_[name];
Mark Drayton5f5687e2017-02-20 18:13:03 +0000403 TRY2(table->open_all_cpu(cb, cb_cookie, page_cnt));
Teng Qin13ebe8e2016-11-29 16:29:08 -0800404 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800405}
406
407StatusTuple BPF::close_perf_buffer(const std::string& name) {
408 auto it = perf_buffers_.find(name);
409 if (it == perf_buffers_.end())
Teng Qin13ebe8e2016-11-29 16:29:08 -0800410 return StatusTuple(-1, "Perf buffer for %s not open", name.c_str());
Teng Qincae072a2016-12-09 00:07:55 -0800411 TRY2(it->second->close_all_cpu());
Teng Qin13ebe8e2016-11-29 16:29:08 -0800412 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800413}
414
415void BPF::poll_perf_buffer(const std::string& name, int timeout) {
416 auto it = perf_buffers_.find(name);
417 if (it == perf_buffers_.end())
418 return;
419 it->second->poll(timeout);
420}
421
422StatusTuple BPF::load_func(const std::string& func_name,
Derek7174d932017-01-30 21:03:02 -0800423 bpf_prog_type type, int& fd) {
Teng Qin335cbe42016-11-23 12:23:03 -0800424 if (funcs_.find(func_name) != funcs_.end()) {
425 fd = funcs_[func_name];
Teng Qin13ebe8e2016-11-29 16:29:08 -0800426 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800427 }
428
429 uint8_t* func_start = bpf_module_->function_start(func_name);
430 if (!func_start)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800431 return StatusTuple(-1, "Can't find start of function %s",
432 func_name.c_str());
Teng Qin335cbe42016-11-23 12:23:03 -0800433 size_t func_size = bpf_module_->function_size(func_name);
434
435 fd = bpf_prog_load(type, reinterpret_cast<struct bpf_insn*>(func_start),
436 func_size, bpf_module_->license(),
437 bpf_module_->kern_version(), nullptr,
438 0 // BPFModule will handle error printing
439 );
440
441 if (fd < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800442 return StatusTuple(-1, "Failed to load %s: %d", func_name.c_str(), fd);
Teng Qin335cbe42016-11-23 12:23:03 -0800443 funcs_[func_name] = fd;
Teng Qin13ebe8e2016-11-29 16:29:08 -0800444 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800445}
446
447StatusTuple BPF::unload_func(const std::string& func_name) {
448 auto it = funcs_.find(func_name);
449 if (it == funcs_.end())
Teng Qin6e682232016-12-15 13:20:09 -0800450 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800451
452 int res = close(it->second);
453 if (res != 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800454 return StatusTuple(-1, "Can't close FD for %s: %d", it->first.c_str(), res);
Teng Qin335cbe42016-11-23 12:23:03 -0800455
456 funcs_.erase(it);
Teng Qin13ebe8e2016-11-29 16:29:08 -0800457 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800458}
459
460StatusTuple BPF::check_binary_symbol(const std::string& binary_path,
461 const std::string& symbol,
462 uint64_t symbol_addr, bcc_symbol* output) {
463 int res = bcc_resolve_symname(binary_path.c_str(), symbol.c_str(),
Paul Chaignon690b7e62016-12-25 19:43:41 +0100464 symbol_addr, 0, output);
Teng Qin335cbe42016-11-23 12:23:03 -0800465 if (res < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800466 return StatusTuple(
467 -1, "Unable to find offset for binary %s symbol %s address %lx",
468 binary_path.c_str(), symbol.c_str(), symbol_addr);
469 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800470}
471
472std::string BPF::get_kprobe_event(const std::string& kernel_func,
Derek7174d932017-01-30 21:03:02 -0800473 bpf_probe_attach_type type) {
Teng Qin335cbe42016-11-23 12:23:03 -0800474 std::string res = attach_type_prefix(type) + "_";
475 res += sanitize_str(kernel_func, &BPF::kprobe_event_validator);
476 return res;
477}
478
479std::string BPF::get_uprobe_event(const std::string& binary_path,
Derek7174d932017-01-30 21:03:02 -0800480 uint64_t offset, bpf_probe_attach_type type) {
Teng Qin335cbe42016-11-23 12:23:03 -0800481 std::string res = attach_type_prefix(type) + "_";
482 res += sanitize_str(binary_path, &BPF::uprobe_path_validator);
483 res += "_0x" + uint_to_hex(offset);
484 return res;
485}
486
487StatusTuple BPF::detach_kprobe_event(const std::string& event,
488 open_probe_t& attr) {
489 if (attr.reader_ptr) {
490 perf_reader_free(attr.reader_ptr);
491 attr.reader_ptr = nullptr;
492 }
493 TRY2(unload_func(attr.func));
Dereke4da6c22017-01-28 16:11:28 -0800494 if (bpf_detach_kprobe(event.c_str()) < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800495 return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str());
496 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800497}
498
499StatusTuple BPF::detach_uprobe_event(const std::string& event,
500 open_probe_t& attr) {
501 if (attr.reader_ptr) {
502 perf_reader_free(attr.reader_ptr);
503 attr.reader_ptr = nullptr;
504 }
505 TRY2(unload_func(attr.func));
Dereke4da6c22017-01-28 16:11:28 -0800506 if (bpf_detach_uprobe(event.c_str()) < 0)
Teng Qin13ebe8e2016-11-29 16:29:08 -0800507 return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str());
508 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800509}
510
511StatusTuple BPF::detach_tracepoint_event(const std::string& tracepoint,
512 open_probe_t& attr) {
513 if (attr.reader_ptr) {
514 perf_reader_free(attr.reader_ptr);
515 attr.reader_ptr = nullptr;
516 }
517 TRY2(unload_func(attr.func));
518
519 // TODO: bpf_detach_tracepoint currently does nothing.
Teng Qin13ebe8e2016-11-29 16:29:08 -0800520 return StatusTuple(0);
Teng Qin335cbe42016-11-23 12:23:03 -0800521}
522
Teng Qindfd9c632016-12-08 17:46:13 -0800523StatusTuple BPF::detach_perf_event_all_cpu(open_probe_t& attr) {
524 bool has_error = false;
525 std::string err_msg;
526 for (auto it : *attr.per_cpu_fd) {
527 int res = close(it.second);
528 if (res < 0) {
529 has_error = true;
530 err_msg += "Failed to close perf event FD " + std::to_string(it.second) +
531 " For CPU " + std::to_string(it.first) + ": ";
532 err_msg += std::string(std::strerror(errno)) + "\n";
533 }
534 }
535 delete attr.per_cpu_fd;
536 TRY2(unload_func(attr.func));
537
538 if (has_error)
539 return StatusTuple(-1, err_msg);
540 return StatusTuple(0);
541}
542
Teng Qin6e682232016-12-15 13:20:09 -0800543StatusTuple USDT::init() {
544 auto ctx =
545 std::unique_ptr<::USDT::Context>(new ::USDT::Context(binary_path_));
546 if (!ctx->loaded())
547 return StatusTuple(-1, "Unable to load USDT " + print_name());
548 auto probe = ctx->get(name_);
549 if (probe == nullptr)
550 return StatusTuple(-1, "Unable to find USDT " + print_name());
551
552 if (!probe->enable(probe_func_))
553 return StatusTuple(-1, "Failed to enable USDT " + print_name());
554 std::ostringstream stream;
555 if (!probe->usdt_getarg(stream))
556 return StatusTuple(
557 -1, "Unable to generate program text for USDT " + print_name());
558 program_text_ = ::USDT::USDT_PROGRAM_HEADER + stream.str();
559
560 for (size_t i = 0; i < probe->num_locations(); i++)
561 addresses_.push_back(probe->address(i));
562
563 initialized_ = true;
564 return StatusTuple(0);
565}
566
Teng Qin335cbe42016-11-23 12:23:03 -0800567} // namespace ebpf