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