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