Home | History | Annotate | Download | only in includes
      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