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 "ns_guard.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<int> 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 67 int arg_size() const { return arg_size_.value_or(sizeof(void *)); } 68 std::string ctype() const; 69 70 const optional<std::string> &deref_ident() const { return deref_ident_; } 71 const optional<std::string> &base_register_name() const { 72 return base_register_name_; 73 } 74 const optional<std::string> &index_register_name() const { 75 return index_register_name_; 76 } 77 const optional<int> scale() const { return scale_; } 78 const optional<int> constant() const { return constant_; } 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_x64; 85 }; 86 87 class ArgumentParser { 88 protected: 89 const char *arg_; 90 ssize_t cur_pos_; 91 92 void skip_whitespace_from(size_t pos); 93 void skip_until_whitespace_from(size_t pos); 94 void print_error(ssize_t pos); 95 ssize_t parse_number(ssize_t pos, optional<int> *result) { 96 char *endp; 97 int number = strtol(arg_ + pos, &endp, 0); 98 if (endp > arg_ + pos) 99 *result = number; 100 return endp - arg_; 101 } 102 bool error_return(ssize_t error_start, ssize_t skip_start) { 103 print_error(error_start); 104 skip_until_whitespace_from(skip_start); 105 return false; 106 } 107 108 public: 109 virtual bool parse(Argument *dest) = 0; 110 bool done() { return cur_pos_ < 0 || arg_[cur_pos_] == '\0'; } 111 112 ArgumentParser(const char *arg) : arg_(arg), cur_pos_(0) {} 113 }; 114 115 class ArgumentParser_aarch64 : public ArgumentParser { 116 private: 117 bool parse_register(ssize_t pos, ssize_t &new_pos, optional<int> *reg_num); 118 bool parse_size(ssize_t pos, ssize_t &new_pos, optional<int> *arg_size); 119 bool parse_mem(ssize_t pos, ssize_t &new_pos, optional<int> *reg_num, 120 optional<int> *offset); 121 122 public: 123 bool parse(Argument *dest); 124 ArgumentParser_aarch64(const char *arg) : ArgumentParser(arg) {} 125 }; 126 127 class ArgumentParser_powerpc64 : public ArgumentParser { 128 public: 129 bool parse(Argument *dest); 130 ArgumentParser_powerpc64(const char *arg) : ArgumentParser(arg) {} 131 }; 132 133 class ArgumentParser_x64 : public ArgumentParser { 134 private: 135 enum Register { 136 REG_A, 137 REG_B, 138 REG_C, 139 REG_D, 140 REG_SI, 141 REG_DI, 142 REG_BP, 143 REG_SP, 144 REG_8, 145 REG_9, 146 REG_10, 147 REG_11, 148 REG_12, 149 REG_13, 150 REG_14, 151 REG_15, 152 REG_RIP, 153 }; 154 155 struct RegInfo { 156 Register reg; 157 int size; 158 }; 159 160 static const std::unordered_map<std::string, RegInfo> registers_; 161 bool normalize_register(std::string *reg, int *reg_size); 162 void reg_to_name(std::string *norm, Register reg); 163 ssize_t parse_register(ssize_t pos, std::string &name, int &size); 164 ssize_t parse_identifier(ssize_t pos, optional<std::string> *ident); 165 ssize_t parse_base_register(ssize_t pos, Argument *dest); 166 ssize_t parse_index_register(ssize_t pos, Argument *dest); 167 ssize_t parse_scale(ssize_t pos, Argument *dest); 168 ssize_t parse_expr(ssize_t pos, Argument *dest); 169 ssize_t parse_1(ssize_t pos, Argument *dest); 170 171 public: 172 bool parse(Argument *dest); 173 ArgumentParser_x64(const char *arg) : ArgumentParser(arg) {} 174 }; 175 176 struct Location { 177 uint64_t address_; 178 std::string bin_path_; 179 std::vector<Argument> arguments_; 180 Location(uint64_t addr, const std::string &bin_path, const char *arg_fmt); 181 }; 182 183 class Probe { 184 std::string bin_path_; // initial bin_path when Probe is created 185 std::string provider_; 186 std::string name_; 187 uint64_t semaphore_; 188 189 std::vector<Location> locations_; 190 191 optional<int> pid_; 192 ProcMountNS *mount_ns_; 193 std::unordered_map<std::string, bool> object_type_map_; // bin_path => is shared lib? 194 195 optional<std::string> attached_to_; 196 optional<uint64_t> attached_semaphore_; 197 198 std::string largest_arg_type(size_t arg_n); 199 200 bool add_to_semaphore(int16_t val); 201 bool resolve_global_address(uint64_t *global, const std::string &bin_path, 202 const uint64_t addr); 203 bool lookup_semaphore_addr(uint64_t *address); 204 void add_location(uint64_t addr, const std::string &bin_path, const char *fmt); 205 206 public: 207 Probe(const char *bin_path, const char *provider, const char *name, 208 uint64_t semaphore, const optional<int> &pid, ProcMountNS *ns); 209 210 size_t num_locations() const { return locations_.size(); } 211 size_t num_arguments() const { return locations_.front().arguments_.size(); } 212 uint64_t semaphore() const { return semaphore_; } 213 214 uint64_t address(size_t n = 0) const { return locations_[n].address_; } 215 const char *location_bin_path(size_t n = 0) const { return locations_[n].bin_path_.c_str(); } 216 const Location &location(size_t n) const { return locations_[n]; } 217 218 bool usdt_getarg(std::ostream &stream); 219 bool usdt_getarg(std::ostream &stream, const std::string& probe_func); 220 std::string get_arg_ctype(int arg_index) { 221 return largest_arg_type(arg_index); 222 } 223 224 void finalize_locations(); 225 bool need_enable() const { return semaphore_ != 0x0; } 226 bool enable(const std::string &fn_name); 227 bool disable(); 228 bool enabled() const { return !!attached_to_; } 229 230 bool in_shared_object(const std::string &bin_path); 231 const std::string &name() { return name_; } 232 const std::string &bin_path() { return bin_path_; } 233 const std::string &provider() { return provider_; } 234 235 friend class Context; 236 237 friend class ::ebpf::BPF; 238 friend class ::ebpf::USDT; 239 }; 240 241 class Context { 242 std::vector<std::unique_ptr<Probe>> probes_; 243 std::unordered_set<std::string> modules_; 244 245 optional<int> pid_; 246 optional<ProcStat> pid_stat_; 247 std::unique_ptr<ProcMountNS> mount_ns_instance_; 248 std::string cmd_bin_path_; 249 bool loaded_; 250 251 static void _each_probe(const char *binpath, const struct bcc_elf_usdt *probe, 252 void *p); 253 static int _each_module(const char *modpath, uint64_t, uint64_t, uint64_t, 254 bool, void *p); 255 256 void add_probe(const char *binpath, const struct bcc_elf_usdt *probe); 257 std::string resolve_bin_path(const std::string &bin_path); 258 259 public: 260 Context(const std::string &bin_path); 261 Context(int pid); 262 Context(int pid, const std::string &bin_path); 263 ~Context(); 264 265 optional<int> pid() const { return pid_; } 266 bool loaded() const { return loaded_; } 267 size_t num_probes() const { return probes_.size(); } 268 const std::string & cmd_bin_path() const { return cmd_bin_path_; } 269 ino_t inode() const { return mount_ns_instance_->target_ino(); } 270 271 Probe *get(const std::string &probe_name); 272 Probe *get(const std::string &provider_name, const std::string &probe_name); 273 Probe *get(int pos) { return probes_[pos].get(); } 274 275 bool enable_probe(const std::string &probe_name, const std::string &fn_name); 276 277 typedef void (*each_cb)(struct bcc_usdt *); 278 void each(each_cb callback); 279 280 typedef void (*each_uprobe_cb)(const char *, const char *, uint64_t, int); 281 void each_uprobe(each_uprobe_cb callback); 282 283 friend class ::ebpf::BPF; 284 friend class ::ebpf::USDT; 285 }; 286 } 287