• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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<int> 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_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);
parse_number(ssize_t pos,optional<int> * result)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   }
error_return(ssize_t error_start,ssize_t skip_start)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;
done()110   bool done() { return cur_pos_ < 0 || arg_[cur_pos_] == '\0'; }
111 
ArgumentParser(const char * arg)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);
ArgumentParser_aarch64(const char * arg)124   ArgumentParser_aarch64(const char *arg) : ArgumentParser(arg) {}
125 };
126 
127 class ArgumentParser_powerpc64 : public ArgumentParser {
128 public:
129   bool parse(Argument *dest);
ArgumentParser_powerpc64(const char * arg)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);
ArgumentParser_x64(const char * arg)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 
num_locations()210   size_t num_locations() const { return locations_.size(); }
num_arguments()211   size_t num_arguments() const { return locations_.front().arguments_.size(); }
semaphore()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(); }
location(size_t n)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);
get_arg_ctype(int arg_index)220   std::string get_arg_ctype(int arg_index) {
221     return largest_arg_type(arg_index);
222   }
223 
224   void finalize_locations();
need_enable()225   bool need_enable() const { return semaphore_ != 0x0; }
226   bool enable(const std::string &fn_name);
227   bool disable();
enabled()228   bool enabled() const { return !!attached_to_; }
229 
230   bool in_shared_object(const std::string &bin_path);
name()231   const std::string &name() { return name_; }
bin_path()232   const std::string &bin_path() { return bin_path_; }
provider()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 
pid()265   optional<int> pid() const { return pid_; }
loaded()266   bool loaded() const { return loaded_; }
num_probes()267   size_t num_probes() const { return probes_.size(); }
cmd_bin_path()268   const std::string & cmd_bin_path() const { return cmd_bin_path_; }
inode()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);
get(int pos)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