Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 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 <unistd.h> |
| 19 | #include <cstdio> |
Teng Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 20 | #include <cstring> |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 21 | #include <exception> |
| 22 | #include <iostream> |
| 23 | #include <memory> |
| 24 | #include <sstream> |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 25 | #include <utility> |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 26 | #include <vector> |
| 27 | |
Teng Qin | 3b4e31f | 2016-11-28 21:58:46 -0800 | [diff] [blame] | 28 | #include "bcc_exception.h" |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 29 | #include "bcc_syms.h" |
| 30 | #include "bpf_module.h" |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame^] | 31 | #include "common.h" |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 32 | #include "libbpf.h" |
| 33 | #include "perf_reader.h" |
Brenden Blanco | faea8c8 | 2017-03-29 09:58:31 -0700 | [diff] [blame^] | 34 | #include "table_storage.h" |
Teng Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 35 | #include "usdt.h" |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 36 | |
| 37 | #include "BPF.h" |
| 38 | |
| 39 | namespace ebpf { |
| 40 | |
| 41 | std::string uint_to_hex(uint64_t value) { |
| 42 | std::stringstream ss; |
| 43 | ss << std::hex << value; |
| 44 | return ss.str(); |
| 45 | } |
| 46 | |
| 47 | std::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 | |
| 55 | StatusTuple BPF::init(const std::string& bpf_program, |
Teng Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 56 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 66 | 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 Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 70 | |
| 71 | all_bpf_program += bpf_program; |
| 72 | if (bpf_module_->load_string(all_bpf_program, flags, flags_len) != 0) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 73 | return StatusTuple(-1, "Unable to initialize BPF program"); |
Teng Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 74 | |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 75 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 76 | }; |
| 77 | |
| 78 | BPF::~BPF() { |
| 79 | auto res = detach_all(); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 80 | if (res.code() != 0) |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 81 | std::cerr << "Failed to detach all probes on destruction: " << std::endl |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 82 | << res.msg() << std::endl; |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | StatusTuple 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 Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 91 | if (res.code() != 0) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 92 | error_msg += "Failed to detach kprobe event " + it.first + ": "; |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 93 | error_msg += res.msg() + "\n"; |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 94 | has_error = true; |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | for (auto it : uprobes_) { |
| 99 | auto res = detach_uprobe_event(it.first, it.second); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 100 | if (res.code() != 0) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 101 | error_msg += "Failed to detach uprobe event " + it.first + ": "; |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 102 | error_msg += res.msg() + "\n"; |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 103 | has_error = true; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | for (auto it : tracepoints_) { |
| 108 | auto res = detach_tracepoint_event(it.first, it.second); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 109 | if (res.code() != 0) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 110 | error_msg += "Failed to detach Tracepoint " + it.first + ": "; |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 111 | error_msg += res.msg() + "\n"; |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 112 | has_error = true; |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | for (auto it : perf_buffers_) { |
Teng Qin | cae072a | 2016-12-09 00:07:55 -0800 | [diff] [blame] | 117 | auto res = it.second->close_all_cpu(); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 118 | if (res.code() != 0) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 119 | error_msg += "Failed to close perf buffer " + it.first + ": "; |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 120 | error_msg += res.msg() + "\n"; |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 121 | has_error = true; |
| 122 | } |
| 123 | delete it.second; |
| 124 | } |
| 125 | |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 126 | 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 Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 134 | 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 Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 138 | error_msg += std::string(std::strerror(errno)) + "\n"; |
Teng Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 139 | has_error = true; |
| 140 | } |
| 141 | } |
| 142 | |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 143 | if (has_error) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 144 | return StatusTuple(-1, error_msg); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 145 | else |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 146 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | StatusTuple BPF::attach_kprobe(const std::string& kernel_func, |
| 150 | const std::string& probe_func, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 151 | bpf_probe_attach_type attach_type, |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 152 | pid_t pid, int cpu, int group_fd, |
| 153 | perf_reader_cb cb, void* cb_cookie) { |
Teng Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 154 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 158 | int probe_fd; |
| 159 | TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd)); |
| 160 | |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 161 | void* res = |
Derek | e4da6c2 | 2017-01-28 16:11:28 -0800 | [diff] [blame] | 162 | bpf_attach_kprobe(probe_fd, attach_type, probe_event.c_str(), kernel_func.c_str(), |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 163 | pid, cpu, group_fd, cb, cb_cookie); |
| 164 | |
| 165 | if (!res) { |
| 166 | TRY2(unload_func(probe_func)); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 167 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 170 | } |
| 171 | |
| 172 | open_probe_t p = {}; |
| 173 | p.reader_ptr = res; |
| 174 | p.func = probe_func; |
| 175 | kprobes_[probe_event] = std::move(p); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 176 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | StatusTuple BPF::attach_uprobe(const std::string& binary_path, |
| 180 | const std::string& symbol, |
| 181 | const std::string& probe_func, |
| 182 | uint64_t symbol_addr, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 183 | bpf_probe_attach_type attach_type, |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 184 | pid_t pid, int cpu, int group_fd, |
| 185 | perf_reader_cb cb, void* cb_cookie) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 186 | 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 Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 191 | if (uprobes_.find(probe_event) != uprobes_.end()) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 192 | return StatusTuple(-1, "uprobe %s already attached", probe_event.c_str()); |
Teng Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 193 | |
| 194 | int probe_fd; |
| 195 | TRY2(load_func(probe_func, BPF_PROG_TYPE_KPROBE, probe_fd)); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 196 | |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 197 | void* res = |
Derek | e4da6c2 | 2017-01-28 16:11:28 -0800 | [diff] [blame] | 198 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 200 | |
| 201 | if (!res) { |
| 202 | TRY2(unload_func(probe_func)); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 203 | return StatusTuple( |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 204 | -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 Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 214 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 215 | } |
| 216 | |
Teng Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 217 | StatusTuple 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 248 | StatusTuple 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 252 | if (tracepoints_.find(tracepoint) != tracepoints_.end()) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 253 | return StatusTuple(-1, "Tracepoint %s already attached", |
| 254 | tracepoint.c_str()); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 255 | |
| 256 | auto pos = tracepoint.find(":"); |
| 257 | if ((pos == std::string::npos) || (pos != tracepoint.rfind(":"))) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 258 | return StatusTuple(-1, "Unable to parse Tracepoint %s", tracepoint.c_str()); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 259 | std::string tp_category = tracepoint.substr(0, pos); |
| 260 | std::string tp_name = tracepoint.substr(pos + 1); |
| 261 | |
Teng Qin | 53c7f4c | 2016-12-08 18:03:33 -0800 | [diff] [blame] | 262 | int probe_fd; |
| 263 | TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd)); |
| 264 | |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 265 | 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 Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 271 | return StatusTuple(-1, "Unable to attach Tracepoint %s using %s", |
| 272 | tracepoint.c_str(), probe_func.c_str()); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 273 | } |
| 274 | |
| 275 | open_probe_t p = {}; |
| 276 | p.reader_ptr = res; |
| 277 | p.func = probe_func; |
| 278 | tracepoints_[tracepoint] = std::move(p); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 279 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 280 | } |
| 281 | |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 282 | StatusTuple 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 Gerstmayr | 7e0784d | 2017-01-16 16:35:58 +0100 | [diff] [blame] | 295 | std::vector<int> cpus; |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 296 | if (cpu >= 0) |
Andreas Gerstmayr | 7e0784d | 2017-01-16 16:35:58 +0100 | [diff] [blame] | 297 | cpus.push_back(cpu); |
| 298 | else |
| 299 | cpus = get_online_cpus(); |
| 300 | for (int i: cpus) { |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 301 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 321 | StatusTuple BPF::detach_kprobe(const std::string& kernel_func, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 322 | bpf_probe_attach_type attach_type) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 323 | std::string event = get_kprobe_event(kernel_func, attach_type); |
| 324 | |
| 325 | auto it = kprobes_.find(event); |
| 326 | if (it == kprobes_.end()) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 327 | return StatusTuple(-1, "No open %skprobe for %s", |
| 328 | attach_type_debug(attach_type).c_str(), |
| 329 | kernel_func.c_str()); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 330 | |
| 331 | TRY2(detach_kprobe_event(it->first, it->second)); |
| 332 | kprobes_.erase(it); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 333 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 334 | } |
| 335 | |
| 336 | StatusTuple BPF::detach_uprobe(const std::string& binary_path, |
| 337 | const std::string& symbol, uint64_t symbol_addr, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 338 | bpf_probe_attach_type attach_type) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 339 | 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 Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 345 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 348 | |
| 349 | TRY2(detach_uprobe_event(it->first, it->second)); |
| 350 | uprobes_.erase(it); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 351 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 352 | } |
| 353 | |
Teng Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 354 | StatusTuple 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 375 | StatusTuple BPF::detach_tracepoint(const std::string& tracepoint) { |
| 376 | auto it = tracepoints_.find(tracepoint); |
| 377 | if (it == tracepoints_.end()) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 378 | return StatusTuple(-1, "No open Tracepoint %s", tracepoint.c_str()); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 379 | |
| 380 | TRY2(detach_tracepoint_event(it->first, it->second)); |
| 381 | tracepoints_.erase(it); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 382 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 383 | } |
| 384 | |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 385 | StatusTuple 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 395 | StatusTuple BPF::open_perf_buffer(const std::string& name, |
Mark Drayton | 5f5687e | 2017-02-20 18:13:03 +0000 | [diff] [blame] | 396 | perf_reader_raw_cb cb, void* cb_cookie, |
| 397 | int page_cnt) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 398 | if (perf_buffers_.find(name) == perf_buffers_.end()) |
| 399 | perf_buffers_[name] = new BPFPerfBuffer(bpf_module_.get(), name); |
Mark Drayton | 5f5687e | 2017-02-20 18:13:03 +0000 | [diff] [blame] | 400 | if ((page_cnt & (page_cnt - 1)) != 0) |
| 401 | return StatusTuple(-1, "open_perf_buffer page_cnt must be a power of two"); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 402 | auto table = perf_buffers_[name]; |
Mark Drayton | 5f5687e | 2017-02-20 18:13:03 +0000 | [diff] [blame] | 403 | TRY2(table->open_all_cpu(cb, cb_cookie, page_cnt)); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 404 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 405 | } |
| 406 | |
| 407 | StatusTuple BPF::close_perf_buffer(const std::string& name) { |
| 408 | auto it = perf_buffers_.find(name); |
| 409 | if (it == perf_buffers_.end()) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 410 | return StatusTuple(-1, "Perf buffer for %s not open", name.c_str()); |
Teng Qin | cae072a | 2016-12-09 00:07:55 -0800 | [diff] [blame] | 411 | TRY2(it->second->close_all_cpu()); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 412 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 413 | } |
| 414 | |
| 415 | void 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 | |
| 422 | StatusTuple BPF::load_func(const std::string& func_name, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 423 | bpf_prog_type type, int& fd) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 424 | if (funcs_.find(func_name) != funcs_.end()) { |
| 425 | fd = funcs_[func_name]; |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 426 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 427 | } |
| 428 | |
| 429 | uint8_t* func_start = bpf_module_->function_start(func_name); |
| 430 | if (!func_start) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 431 | return StatusTuple(-1, "Can't find start of function %s", |
| 432 | func_name.c_str()); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 433 | 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 Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 442 | return StatusTuple(-1, "Failed to load %s: %d", func_name.c_str(), fd); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 443 | funcs_[func_name] = fd; |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 444 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 445 | } |
| 446 | |
| 447 | StatusTuple BPF::unload_func(const std::string& func_name) { |
| 448 | auto it = funcs_.find(func_name); |
| 449 | if (it == funcs_.end()) |
Teng Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 450 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 451 | |
| 452 | int res = close(it->second); |
| 453 | if (res != 0) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 454 | return StatusTuple(-1, "Can't close FD for %s: %d", it->first.c_str(), res); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 455 | |
| 456 | funcs_.erase(it); |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 457 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 458 | } |
| 459 | |
| 460 | StatusTuple 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 Chaignon | 690b7e6 | 2016-12-25 19:43:41 +0100 | [diff] [blame] | 464 | symbol_addr, 0, output); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 465 | if (res < 0) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 466 | 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | std::string BPF::get_kprobe_event(const std::string& kernel_func, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 473 | bpf_probe_attach_type type) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 474 | std::string res = attach_type_prefix(type) + "_"; |
| 475 | res += sanitize_str(kernel_func, &BPF::kprobe_event_validator); |
| 476 | return res; |
| 477 | } |
| 478 | |
| 479 | std::string BPF::get_uprobe_event(const std::string& binary_path, |
Derek | 7174d93 | 2017-01-30 21:03:02 -0800 | [diff] [blame] | 480 | uint64_t offset, bpf_probe_attach_type type) { |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 481 | 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 | |
| 487 | StatusTuple 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)); |
Derek | e4da6c2 | 2017-01-28 16:11:28 -0800 | [diff] [blame] | 494 | if (bpf_detach_kprobe(event.c_str()) < 0) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 495 | return StatusTuple(-1, "Unable to detach kprobe %s", event.c_str()); |
| 496 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 497 | } |
| 498 | |
| 499 | StatusTuple 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)); |
Derek | e4da6c2 | 2017-01-28 16:11:28 -0800 | [diff] [blame] | 506 | if (bpf_detach_uprobe(event.c_str()) < 0) |
Teng Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 507 | return StatusTuple(-1, "Unable to detach uprobe %s", event.c_str()); |
| 508 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 509 | } |
| 510 | |
| 511 | StatusTuple 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 Qin | 13ebe8e | 2016-11-29 16:29:08 -0800 | [diff] [blame] | 520 | return StatusTuple(0); |
Teng Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 521 | } |
| 522 | |
Teng Qin | dfd9c63 | 2016-12-08 17:46:13 -0800 | [diff] [blame] | 523 | StatusTuple 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 Qin | 6e68223 | 2016-12-15 13:20:09 -0800 | [diff] [blame] | 543 | StatusTuple 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 Qin | 335cbe4 | 2016-11-23 12:23:03 -0800 | [diff] [blame] | 567 | } // namespace ebpf |