• Home
  • 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 "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 &reg_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 &reg_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