1 /* 2 * Copyright (c) 2016 GitHub, 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 #pragma once 17 18 #include <memory> 19 #include <string> 20 #include <unordered_map> 21 #include <vector> 22 23 #include "bcc_proc.h" 24 #include "syms.h" 25 #include "vendor/optional.hpp" 26 27 struct bcc_usdt; 28 29 namespace ebpf { 30 class BPF; 31 class USDT; 32 } 33 34 namespace USDT { 35 36 using std::experimental::optional; 37 using std::experimental::nullopt; 38 class ArgumentParser; 39 40 static const std::string USDT_PROGRAM_HEADER = 41 "#include <uapi/linux/ptrace.h>\n"; 42 43 static const std::string COMPILER_BARRIER = 44 "__asm__ __volatile__(\"\": : :\"memory\");"; 45 46 class Argument { 47 private: 48 optional<int> arg_size_; 49 optional<long long> constant_; 50 optional<int> deref_offset_; 51 optional<std::string> deref_ident_; 52 optional<std::string> base_register_name_; 53 optional<std::string> index_register_name_; 54 optional<int> scale_; 55 56 bool get_global_address(uint64_t *address, const std::string &binpath, 57 const optional<int> &pid) const; 58 59 public: 60 Argument(); 61 ~Argument(); 62 63 bool assign_to_local(std::ostream &stream, const std::string &local_name, 64 const std::string &binpath, 65 const optional<int> &pid = nullopt) const; 66 arg_size()67 int arg_size() const { return arg_size_.value_or(sizeof(void *)); } 68 std::string ctype() const; 69 const char *ctype_name() const; 70 deref_ident()71 const optional<std::string> &deref_ident() const { return deref_ident_; } base_register_name()72 const optional<std::string> &base_register_name() const { 73 return base_register_name_; 74 } index_register_name()75 const optional<std::string> &index_register_name() const { 76 return index_register_name_; 77 } scale()78 const optional<int> scale() const { return scale_; } constant()79 const optional<long long> constant() const { return constant_; } deref_offset()80 const optional<int> deref_offset() const { return deref_offset_; } 81 82 friend class ArgumentParser; 83 friend class ArgumentParser_aarch64; 84 friend class ArgumentParser_loongarch64; 85 friend class ArgumentParser_powerpc64; 86 friend class ArgumentParser_s390x; 87 friend class ArgumentParser_x64; 88 }; 89 90 class ArgumentParser { 91 protected: 92 const char *arg_; 93 ssize_t cur_pos_; 94 95 void skip_whitespace_from(size_t pos); 96 void skip_until_whitespace_from(size_t pos); 97 void print_error(ssize_t pos); parse_number(ssize_t pos,optional<int> * result)98 ssize_t parse_number(ssize_t pos, optional<int> *result) { 99 char *endp; 100 int number = strtol(arg_ + pos, &endp, 0); 101 if (endp > arg_ + pos) 102 *result = number; 103 return endp - arg_; 104 } parse_number(ssize_t pos,optional<long long> * result)105 ssize_t parse_number(ssize_t pos, optional<long long> *result) { 106 char *endp; 107 long long number = (long long)strtoull(arg_ + pos, &endp, 0); 108 if (endp > arg_ + pos) 109 *result = number; 110 return endp - arg_; 111 } error_return(ssize_t error_start,ssize_t skip_start)112 bool error_return(ssize_t error_start, ssize_t skip_start) { 113 print_error(error_start); 114 if (isspace(arg_[skip_start])) 115 skip_start++; // Make sure we skip at least one character 116 skip_until_whitespace_from(skip_start); 117 return false; 118 } 119 120 public: 121 virtual bool parse(Argument *dest) = 0; done()122 bool done() { return cur_pos_ < 0 || arg_[cur_pos_] == '\0'; } 123 ArgumentParser(const char * arg)124 ArgumentParser(const char *arg) : arg_(arg), cur_pos_(0) {} 125 }; 126 127 class ArgumentParser_aarch64 : public ArgumentParser { 128 private: 129 bool parse_register(ssize_t pos, ssize_t &new_pos, std::string ®_name); 130 bool parse_size(ssize_t pos, ssize_t &new_pos, optional<int> *arg_size); 131 bool parse_mem(ssize_t pos, ssize_t &new_pos, Argument *dest); 132 133 public: 134 bool parse(Argument *dest); ArgumentParser_aarch64(const char * arg)135 ArgumentParser_aarch64(const char *arg) : ArgumentParser(arg) {} 136 }; 137 138 class ArgumentParser_loongarch64 : public ArgumentParser { 139 private: 140 bool parse_register(ssize_t pos, ssize_t &new_pos, std::string ®_name); 141 bool parse_size(ssize_t pos, ssize_t &new_pos, optional<int> *arg_size); 142 bool parse_mem(ssize_t pos, ssize_t &new_pos, Argument *dest); 143 144 public: 145 bool parse(Argument *dest); ArgumentParser_loongarch64(const char * arg)146 ArgumentParser_loongarch64(const char *arg) : ArgumentParser(arg) {} 147 }; 148 149 class ArgumentParser_powerpc64 : public ArgumentParser { 150 public: 151 bool parse(Argument *dest); ArgumentParser_powerpc64(const char * arg)152 ArgumentParser_powerpc64(const char *arg) : ArgumentParser(arg) {} 153 }; 154 155 class ArgumentParser_s390x : public ArgumentParser { 156 public: 157 bool parse(Argument *dest); ArgumentParser_s390x(const char * arg)158 ArgumentParser_s390x(const char *arg) : ArgumentParser(arg) {} 159 }; 160 161 class ArgumentParser_x64 : public ArgumentParser { 162 private: 163 enum Register { 164 X64_REG_A, 165 X64_REG_B, 166 X64_REG_C, 167 X64_REG_D, 168 X64_REG_SI, 169 X64_REG_DI, 170 X64_REG_BP, 171 X64_REG_SP, 172 X64_REG_8, 173 X64_REG_9, 174 X64_REG_10, 175 X64_REG_11, 176 X64_REG_12, 177 X64_REG_13, 178 X64_REG_14, 179 X64_REG_15, 180 X64_REG_RIP, 181 X64_REG_XMM0, 182 X64_REG_XMM1, 183 X64_REG_XMM2, 184 X64_REG_XMM3, 185 X64_REG_XMM4, 186 X64_REG_XMM5, 187 X64_REG_XMM6, 188 X64_REG_XMM7, 189 X64_REG_XMM8, 190 X64_REG_XMM9, 191 X64_REG_XMM10, 192 X64_REG_XMM11, 193 X64_REG_XMM12, 194 X64_REG_XMM13, 195 X64_REG_XMM14, 196 X64_REG_XMM15, 197 }; 198 199 struct RegInfo { 200 Register reg; 201 int size; 202 }; 203 204 static const std::unordered_map<std::string, RegInfo> registers_; 205 bool normalize_register(std::string *reg, int *reg_size); 206 void reg_to_name(std::string *norm, Register reg); 207 ssize_t parse_register(ssize_t pos, std::string &name, int &size); 208 ssize_t parse_identifier(ssize_t pos, optional<std::string> *ident); 209 ssize_t parse_base_register(ssize_t pos, Argument *dest); 210 ssize_t parse_index_register(ssize_t pos, Argument *dest); 211 ssize_t parse_scale(ssize_t pos, Argument *dest); 212 ssize_t parse_expr(ssize_t pos, Argument *dest); 213 ssize_t parse_1(ssize_t pos, Argument *dest); 214 215 public: 216 bool parse(Argument *dest); ArgumentParser_x64(const char * arg)217 ArgumentParser_x64(const char *arg) : ArgumentParser(arg) {} 218 }; 219 220 struct Location { 221 uint64_t address_; 222 std::string bin_path_; 223 std::vector<Argument> arguments_; 224 Location(uint64_t addr, const std::string &bin_path, const char *arg_fmt); 225 }; 226 227 class Probe { 228 std::string bin_path_; // initial bin_path when Probe is created 229 std::string provider_; 230 std::string name_; 231 uint64_t semaphore_; 232 uint64_t semaphore_offset_; 233 234 std::vector<Location> locations_; 235 236 optional<int> pid_; 237 std::unordered_map<std::string, bool> object_type_map_; // bin_path => is shared lib? 238 239 optional<std::string> attached_to_; 240 optional<uint64_t> attached_semaphore_; 241 uint8_t mod_match_inode_only_; 242 243 const char *largest_arg_type(size_t arg_n); 244 245 bool add_to_semaphore(int16_t val); 246 bool resolve_global_address(uint64_t *global, const std::string &bin_path, 247 const uint64_t addr); 248 bool lookup_semaphore_addr(uint64_t *address); 249 void add_location(uint64_t addr, const std::string &bin_path, const char *fmt); 250 251 public: 252 Probe(const char *bin_path, const char *provider, const char *name, 253 uint64_t semaphore, uint64_t semaphore_offset, 254 const optional<int> &pid, uint8_t mod_match_inode_only = 1); 255 num_locations()256 size_t num_locations() const { return locations_.size(); } num_arguments()257 size_t num_arguments() const { return locations_.front().arguments_.size(); } semaphore()258 uint64_t semaphore() const { return semaphore_; } semaphore_offset()259 uint64_t semaphore_offset() const { return semaphore_offset_; } 260 261 uint64_t address(size_t n = 0) const { return locations_[n].address_; } 262 const char *location_bin_path(size_t n = 0) const { return locations_[n].bin_path_.c_str(); } location(size_t n)263 const Location &location(size_t n) const { return locations_[n]; } 264 265 bool usdt_getarg(std::ostream &stream); 266 bool usdt_getarg(std::ostream &stream, const std::string& probe_func); get_arg_ctype(int arg_index)267 std::string get_arg_ctype(int arg_index) { 268 return largest_arg_type(arg_index); 269 } 270 get_arg_ctype_name(int arg_index)271 const char *get_arg_ctype_name(int arg_index) { 272 return largest_arg_type(arg_index); 273 } 274 275 void finalize_locations(); need_enable()276 bool need_enable() const { return semaphore_ != 0x0; } 277 bool enable(const std::string &fn_name); 278 bool disable(); enabled()279 bool enabled() const { return !!attached_to_; } 280 281 bool in_shared_object(const std::string &bin_path); name()282 const std::string &name() { return name_; } bin_path()283 const std::string &bin_path() { return bin_path_; } provider()284 const std::string &provider() { return provider_; } 285 286 friend class Context; 287 288 friend class ::ebpf::BPF; 289 friend class ::ebpf::USDT; 290 }; 291 292 class Context { 293 std::vector<std::unique_ptr<Probe>> probes_; 294 std::unordered_set<std::string> modules_; 295 296 optional<int> pid_; 297 optional<ProcStat> pid_stat_; 298 std::string cmd_bin_path_; 299 bool loaded_; 300 301 static void _each_probe(const char *binpath, const struct bcc_elf_usdt *probe, 302 void *p); 303 static int _each_module(mod_info *, int enter_ns, void *p); 304 305 void add_probe(const char *binpath, const struct bcc_elf_usdt *probe); 306 std::string resolve_bin_path(const std::string &bin_path); 307 Probe *get_checked(const std::string &provider_name, 308 const std::string &probe_name); 309 310 private: 311 uint8_t mod_match_inode_only_; 312 313 public: 314 Context(const std::string &bin_path, uint8_t mod_match_inode_only = 1); 315 Context(int pid, uint8_t mod_match_inode_only = 1); 316 Context(int pid, const std::string &bin_path, 317 uint8_t mod_match_inode_only = 1); 318 ~Context(); 319 pid()320 optional<int> pid() const { return pid_; } loaded()321 bool loaded() const { return loaded_; } num_probes()322 size_t num_probes() const { return probes_.size(); } cmd_bin_path()323 const std::string & cmd_bin_path() const { return cmd_bin_path_; } 324 325 Probe *get(const std::string &probe_name); 326 Probe *get(const std::string &provider_name, const std::string &probe_name); get(int pos)327 Probe *get(int pos) { return probes_[pos].get(); } 328 329 bool enable_probe(const std::string &probe_name, const std::string &fn_name); 330 bool enable_probe(const std::string &provider_name, 331 const std::string &probe_name, const std::string &fn_name); 332 bool addsem_probe(const std::string &provider_name, 333 const std::string &probe_name, const std::string &fn_name, 334 int16_t val); 335 336 typedef void (*each_cb)(struct bcc_usdt *); 337 void each(each_cb callback); 338 339 typedef void (*each_uprobe_cb)(const char *, const char *, uint64_t, int); 340 void each_uprobe(each_uprobe_cb callback); 341 342 friend class ::ebpf::BPF; 343 friend class ::ebpf::USDT; 344 }; 345 } 346