xref: /aosp_15_r20/external/bcc/src/cc/usdt/usdt_args.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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 #include <cmath>
17 #include <unordered_map>
18 #include <regex>
19 
20 #include "syms.h"
21 #include "usdt.h"
22 #include "vendor/tinyformat.hpp"
23 
24 #include "bcc_elf.h"
25 #include "bcc_syms.h"
26 
27 namespace USDT {
28 
Argument()29 Argument::Argument() {}
~Argument()30 Argument::~Argument() {}
31 
ctype() const32 std::string Argument::ctype() const {
33   const int s = arg_size() * 8;
34   return (s < 0) ? tfm::format("int%d_t", -s) : tfm::format("uint%d_t", s);
35 }
36 
37 static const char *type_names[][4] = {
38   { "int8_t", "int16_t", "int32_t", "int64_t" },
39   { "uint8_t", "uint16_t", "uint32_t", "uint64_t" },
40 };
41 
ctype_name() const42 const char *Argument::ctype_name() const {
43   const int s = arg_size();
44   const int r = log2(abs(s));
45   return s < 0 ? type_names[0][r] : type_names[1][r];
46 }
47 
get_global_address(uint64_t * address,const std::string & binpath,const optional<int> & pid) const48 bool Argument::get_global_address(uint64_t *address, const std::string &binpath,
49                                   const optional<int> &pid) const {
50   if (pid) {
51     static struct bcc_symbol_option default_option = {
52       .use_debug_file = 1,
53       .check_debug_file_crc = 1,
54       .lazy_symbolize = 1,
55       .use_symbol_type = BCC_SYM_ALL_TYPES
56     };
57     return ProcSyms(*pid, &default_option)
58         .resolve_name(binpath.c_str(), deref_ident_->c_str(), address);
59   }
60 
61   if (!bcc_elf_is_shared_obj(binpath.c_str())) {
62     struct bcc_symbol sym;
63     if (bcc_resolve_symname(binpath.c_str(), deref_ident_->c_str(), 0x0, -1, nullptr, &sym) == 0) {
64       *address = sym.offset;
65       if (sym.module)
66         ::free(const_cast<char*>(sym.module));
67       return true;
68     }
69   }
70 
71   return false;
72 }
73 
assign_to_local(std::ostream & stream,const std::string & local_name,const std::string & binpath,const optional<int> & pid) const74 bool Argument::assign_to_local(std::ostream &stream,
75                                const std::string &local_name,
76                                const std::string &binpath,
77                                const optional<int> &pid) const {
78   if (constant_) {
79     tfm::format(stream, "%s = %lld;", local_name, *constant_);
80     return true;
81   }
82 
83   if (!deref_offset_) {
84     if(base_register_name_->substr(0,3) == "xmm") {
85       // TODO: When we can read xmm registers from BPF, update this to read
86       // the actual value
87       tfm::format(stream, "%s = 0;", local_name);
88     } else {
89       tfm::format(stream, "%s = ctx->%s;", local_name, *base_register_name_);
90     }
91     // Put a compiler barrier to prevent optimization
92     // like llvm SimplifyCFG SinkThenElseCodeToEnd
93     // Volatile marking is not sufficient to prevent such optimization.
94     tfm::format(stream, " %s", COMPILER_BARRIER);
95     return true;
96   }
97 
98   if (deref_offset_ && !deref_ident_) {
99     tfm::format(stream, "{ u64 __addr = ctx->%s + %d",
100                 *base_register_name_, *deref_offset_);
101     if (index_register_name_) {
102       int scale = scale_.value_or(1);
103       tfm::format(stream, " + (ctx->%s * %d);", *index_register_name_, scale);
104     } else {
105       tfm::format(stream, ";");
106     }
107     // Theoretically, llvm SimplifyCFG SinkThenElseCodeToEnd may still
108     // sink bpf_probe_read call, so put a barrier here to prevent sinking
109     // of ctx->#fields.
110     tfm::format(stream, " %s ", COMPILER_BARRIER);
111     tfm::format(stream,
112                 "%s __res = 0x0; "
113                 "bpf_probe_read_user(&__res, sizeof(__res), (void *)__addr); "
114                 "%s = __res; }",
115                 ctype(), local_name);
116     return true;
117   }
118 
119   if (deref_offset_ && deref_ident_ && *base_register_name_ == "ip") {
120     uint64_t global_address;
121     if (!get_global_address(&global_address, binpath, pid))
122       return false;
123 
124     tfm::format(stream,
125                 "{ u64 __addr = 0x%xull + %d; %s __res = 0x0; "
126                 "bpf_probe_read_user(&__res, sizeof(__res), (void *)__addr); "
127                 "%s = __res; }",
128                 global_address, *deref_offset_, ctype(), local_name);
129     return true;
130   }
131 
132   return false;
133 }
134 
print_error(ssize_t pos)135 void ArgumentParser::print_error(ssize_t pos) {
136   fprintf(stderr, "Parse error:\n    %s\n", arg_);
137   for (ssize_t i = 0; i < pos + 4; ++i) fputc('-', stderr);
138   fputc('^', stderr);
139   fputc('\n', stderr);
140 }
141 
skip_whitespace_from(size_t pos)142 void ArgumentParser::skip_whitespace_from(size_t pos) {
143     while (isspace(arg_[pos])) pos++;
144     cur_pos_ = pos;
145 }
146 
skip_until_whitespace_from(size_t pos)147 void ArgumentParser::skip_until_whitespace_from(size_t pos) {
148     while (arg_[pos] != '\0' && !isspace(arg_[pos]))
149         pos++;
150     cur_pos_ = pos;
151 }
152 
parse_register(ssize_t pos,ssize_t & new_pos,std::string & reg_name)153 bool ArgumentParser_aarch64::parse_register(ssize_t pos, ssize_t &new_pos,
154                                             std::string &reg_name) {
155   if (arg_[pos] == 'x') {
156     optional<int> reg_num;
157     new_pos = parse_number(pos + 1, &reg_num);
158     if (new_pos == pos + 1 || *reg_num < 0 || *reg_num > 31)
159       return error_return(pos + 1, pos + 1);
160 
161     if (*reg_num == 31) {
162       reg_name = "sp";
163     } else {
164       reg_name = "regs[" + std::to_string(reg_num.value()) + "]";
165     }
166 
167     return true;
168   } else if (arg_[pos] == 's' && arg_[pos + 1] == 'p') {
169     reg_name = "sp";
170     new_pos = pos + 2;
171     return true;
172   } else {
173     return error_return(pos, pos);
174   }
175 }
176 
parse_size(ssize_t pos,ssize_t & new_pos,optional<int> * arg_size)177 bool ArgumentParser_aarch64::parse_size(ssize_t pos, ssize_t &new_pos,
178                                         optional<int> *arg_size) {
179   int abs_arg_size;
180 
181   new_pos = parse_number(pos, arg_size);
182   if (new_pos == pos)
183     return error_return(pos, pos);
184 
185   abs_arg_size = abs(arg_size->value());
186   if (abs_arg_size != 1 && abs_arg_size != 2 && abs_arg_size != 4 &&
187       abs_arg_size != 8)
188     return error_return(pos, pos);
189   return true;
190 }
191 
parse_mem(ssize_t pos,ssize_t & new_pos,Argument * dest)192 bool ArgumentParser_aarch64::parse_mem(ssize_t pos, ssize_t &new_pos,
193                                        Argument *dest) {
194   std::string base_reg_name, index_reg_name;
195 
196   if (parse_register(pos, new_pos, base_reg_name) == false)
197     return false;
198   dest->base_register_name_ = base_reg_name;
199 
200   if (arg_[new_pos] == ',') {
201     pos = new_pos + 1;
202     new_pos = parse_number(pos, &dest->deref_offset_);
203     if (new_pos == pos) {
204       // offset isn't a number, so it should be a reg,
205       // which looks like: -1@[x0, x1], rather than -1@[x0, 24]
206       skip_whitespace_from(pos);
207       pos = cur_pos_;
208       if (parse_register(pos, new_pos, index_reg_name) == false)
209         return error_return(pos, pos);
210       dest->index_register_name_ = index_reg_name;
211       dest->scale_ = 1;
212       dest->deref_offset_ = 0;
213     }
214   }
215   if (arg_[new_pos] != ']')
216     return error_return(new_pos, new_pos);
217   new_pos++;
218   return true;
219 }
220 
parse(Argument * dest)221 bool ArgumentParser_aarch64::parse(Argument *dest) {
222   if (done())
223     return false;
224 
225   // Support the following argument patterns:
226   //   [-]<size>@<value>, [-]<size>@<reg>, [-]<size>@[<reg>], or
227   //   [-]<size>@[<reg>,<offset>]
228   //   [-]<size>@[<reg>,<index_reg>]
229   ssize_t cur_pos = cur_pos_, new_pos;
230   optional<int> arg_size;
231 
232   // Parse [-]<size>
233   if (parse_size(cur_pos, new_pos, &arg_size) == false)
234     return false;
235   dest->arg_size_ = arg_size;
236 
237   // Make sure '@' present
238   if (arg_[new_pos] != '@')
239     return error_return(new_pos, new_pos);
240   cur_pos = new_pos + 1;
241 
242   if (arg_[cur_pos] == 'x' || arg_[cur_pos] == 's') {
243     // Parse ...@<reg>
244     std::string reg_name;
245     if (parse_register(cur_pos, new_pos, reg_name) == false)
246       return false;
247 
248     cur_pos_ = new_pos;
249     dest->base_register_name_ = reg_name;
250   } else if (arg_[cur_pos] == '[') {
251     // Parse ...@[<reg>], ...@[<reg,<offset>] and ...@[<reg>,<index_reg>]
252     if (parse_mem(cur_pos + 1, new_pos, dest) == false)
253       return false;
254     cur_pos_ = new_pos;
255   } else {
256     // Parse ...@<value>
257     optional<long long> val;
258     new_pos = parse_number(cur_pos, &val);
259     if (cur_pos == new_pos)
260       return error_return(cur_pos, cur_pos);
261     cur_pos_ = new_pos;
262     dest->constant_ = val;
263   }
264 
265   skip_whitespace_from(cur_pos_);
266   return true;
267 }
268 
parse_register(ssize_t pos,ssize_t & new_pos,std::string & reg_name)269 bool ArgumentParser_loongarch64::parse_register(ssize_t pos, ssize_t &new_pos,
270 						std::string &reg_name) {
271   if (arg_[pos] == '$' && arg_[pos + 1] == 'r') {
272     optional<int> reg_num;
273     new_pos = parse_number(pos + 2, &reg_num);
274     if (new_pos == pos + 2 || *reg_num < 0 || *reg_num > 31)
275       return error_return(pos + 2, pos + 2);
276 
277     if (*reg_num == 3) {
278       reg_name = "sp";
279     } else {
280       reg_name = "regs[" + std::to_string(reg_num.value()) + "]";
281     }
282     return true;
283   } else if (arg_[pos] == 's' && arg_[pos + 1] == 'p') {
284     reg_name = "sp";
285     new_pos = pos + 2;
286     return true;
287   } else {
288     return error_return(pos, pos);
289   }
290 }
291 
parse_size(ssize_t pos,ssize_t & new_pos,optional<int> * arg_size)292 bool ArgumentParser_loongarch64::parse_size(ssize_t pos, ssize_t &new_pos,
293 					    optional<int> *arg_size) {
294   int abs_arg_size;
295 
296   new_pos = parse_number(pos, arg_size);
297   if (new_pos == pos)
298     return error_return(pos, pos);
299 
300   abs_arg_size = abs(arg_size->value());
301   if (abs_arg_size != 1 && abs_arg_size != 2 && abs_arg_size != 4 &&
302       abs_arg_size != 8)
303     return error_return(pos, pos);
304   return true;
305 }
306 
parse_mem(ssize_t pos,ssize_t & new_pos,Argument * dest)307 bool ArgumentParser_loongarch64::parse_mem(ssize_t pos, ssize_t &new_pos,
308 					   Argument *dest) {
309   std::string base_reg_name, index_reg_name;
310 
311   if (parse_register(pos, new_pos, base_reg_name) == false)
312     return false;
313   dest->base_register_name_ = base_reg_name;
314 
315   if (arg_[new_pos] == ',') {
316     pos = new_pos + 1;
317     new_pos = parse_number(pos, &dest->deref_offset_);
318     if (new_pos == pos) {
319       // offset isn't a number, so it should be a reg,
320       // which looks like: -1@[$r0, $r1], rather than -1@[$r0, 24]
321       skip_whitespace_from(pos);
322       pos = cur_pos_;
323       if (parse_register(pos, new_pos, index_reg_name) == false)
324         return error_return(pos, pos);
325       dest->index_register_name_ = index_reg_name;
326       dest->scale_ = 1;
327       dest->deref_offset_ = 0;
328     }
329   }
330   if (arg_[new_pos] != ']')
331     return error_return(new_pos, new_pos);
332   new_pos++;
333   return true;
334 }
335 
parse(Argument * dest)336 bool ArgumentParser_loongarch64::parse(Argument *dest) {
337   if (done())
338     return false;
339 
340   // Support the following argument patterns:
341   //   [-]<size>@<value>, [-]<size>@<reg>, [-]<size>@[<reg>], or
342   //   [-]<size>@[<reg>,<offset>]
343   //   [-]<size>@[<reg>,<index_reg>]
344   ssize_t cur_pos = cur_pos_, new_pos;
345   optional<int> arg_size;
346 
347   // Parse [-]<size>
348   if (parse_size(cur_pos, new_pos, &arg_size) == false)
349     return false;
350   dest->arg_size_ = arg_size;
351 
352   // Make sure '@' present
353   if (arg_[new_pos] != '@')
354     return error_return(new_pos, new_pos);
355   cur_pos = new_pos + 1;
356 
357   if (arg_[cur_pos] == '$' || arg_[cur_pos] == 's') {
358     // Parse ...@<reg>
359     std::string reg_name;
360     if (parse_register(cur_pos, new_pos, reg_name) == false)
361       return false;
362 
363     cur_pos_ = new_pos;
364     dest->base_register_name_ = reg_name;
365   } else if (arg_[cur_pos] == '[') {
366     // Parse ...@[<reg>], ...@[<reg,<offset>] and ...@[<reg>,<index_reg>]
367     if (parse_mem(cur_pos + 1, new_pos, dest) == false)
368       return false;
369     cur_pos_ = new_pos;
370   } else {
371     // Parse ...@<value>
372     optional<long long> val;
373     new_pos = parse_number(cur_pos, &val);
374     if (cur_pos == new_pos)
375       return error_return(cur_pos, cur_pos);
376     cur_pos_ = new_pos;
377     dest->constant_ = val;
378   }
379 
380   skip_whitespace_from(cur_pos_);
381   return true;
382 }
383 
parse(Argument * dest)384 bool ArgumentParser_powerpc64::parse(Argument *dest) {
385   if (done())
386     return false;
387 
388   bool matched;
389   std::smatch matches;
390   std::string arg_str(&arg_[cur_pos_]);
391   std::regex arg_n_regex("^(\\-?[1248])\\@");
392   // Operands with constants of form iNUM or i-NUM
393   std::regex arg_op_regex_const("^i(\\-?[0-9]+)( +|$)");
394   // Operands with register only of form REG or %rREG
395   std::regex arg_op_regex_reg("^(?:%r)?([1-2]?[0-9]|3[0-1])( +|$)");
396   // Operands with a base register and an offset of form
397   // NUM(REG) or -NUM(REG) or NUM(%rREG) or -NUM(%rREG)
398   std::regex arg_op_regex_breg_off(
399         "^(\\-?[0-9]+)\\((?:%r)?([1-2]?[0-9]|3[0-1])\\)( +|$)");
400   // Operands with a base register and an index register
401   // of form REG,REG or %rREG,%rREG
402   std::regex arg_op_regex_breg_ireg(
403         "^(?:%r)?([1-2]?[0-9]|3[0-1])\\,(?:%r)?([1-2]?[0-9]|3[0-1])( +|$)");
404 
405   matched = std::regex_search(arg_str, matches, arg_n_regex);
406   if (matched) {
407     dest->arg_size_ = stoi(matches.str(1));
408     cur_pos_ += matches.length(0);
409     arg_str = &arg_[cur_pos_];
410 
411     if (std::regex_search(arg_str, matches, arg_op_regex_const)) {
412       dest->constant_ = (long long)stoull(matches.str(1));
413     } else if (std::regex_search(arg_str, matches, arg_op_regex_reg)) {
414       dest->base_register_name_ = "gpr[" + matches.str(1) + "]";
415     } else if (std::regex_search(arg_str, matches, arg_op_regex_breg_off)) {
416       dest->deref_offset_ = stoi(matches.str(1));
417       dest->base_register_name_ = "gpr[" + matches.str(2) + "]";
418     } else if (std::regex_search(arg_str, matches, arg_op_regex_breg_ireg)) {
419       dest->deref_offset_ = 0; // In powerpc64, such operands contain a base
420                                // register and an index register which are
421                                // part of an indexed load/store operation.
422                                // Even if no offset value is present, this
423                                // is required by Argument::assign_to_local()
424                                // in order to generate code for reading the
425                                // argument. So, this is set to zero.
426       dest->base_register_name_ = "gpr[" + matches.str(1) + "]";
427       dest->index_register_name_ = "gpr[" + matches.str(2) + "]";
428       dest->scale_ = abs(*dest->arg_size_);
429     } else {
430       matched = false;
431     }
432   }
433 
434   if (!matched) {
435     print_error(cur_pos_);
436     skip_until_whitespace_from(cur_pos_);
437     skip_whitespace_from(cur_pos_);
438     return false;
439   }
440 
441   cur_pos_ += matches.length(0);
442   skip_whitespace_from(cur_pos_);
443   return true;
444 }
445 
parse(Argument * dest)446 bool ArgumentParser_s390x::parse(Argument *dest) {
447   if (done())
448     return false;
449 
450   bool matched;
451   std::cmatch matches;
452 #define S390X_IMM "(-?[0-9]+)"
453   std::regex arg_n_regex("^" S390X_IMM "@");
454   // <imm>
455   std::regex arg_op_regex_imm("^" S390X_IMM "(?: +|$)");
456   // %r<N>
457 #define S390X_REG "%r([0-9]|1[0-5])"
458   std::regex arg_op_regex_reg("^" S390X_REG "(?: +|$)");
459   // <disp>(%r<N>,%r<N>)
460   std::regex arg_op_regex_mem("^" S390X_IMM "?\\(" S390X_REG
461                               "(?:," S390X_REG ")?\\)(?: +|$)");
462 #undef S390X_IMM
463 #undef S390X_REG
464 
465   matched = std::regex_search(arg_ + cur_pos_, matches, arg_n_regex);
466   if (matched) {
467     dest->arg_size_ = stoi(matches.str(1));
468     cur_pos_ += matches.length(0);
469 
470     if (std::regex_search(arg_ + cur_pos_, matches, arg_op_regex_imm)) {
471       dest->constant_ = (long long)stoull(matches.str(1));
472     } else if (std::regex_search(arg_ + cur_pos_, matches, arg_op_regex_reg)) {
473       dest->base_register_name_ = "gprs[" + matches.str(1) + "]";
474     } else if (std::regex_search(arg_ + cur_pos_, matches, arg_op_regex_mem)) {
475       if (matches.length(1) > 0) {
476         dest->deref_offset_ = stoi(matches.str(1));
477       }
478       dest->base_register_name_ = "gprs[" + matches.str(2) + "]";
479       if (matches.length(3) > 0) {
480         dest->index_register_name_ = "gprs[" + matches.str(3) + "]";
481       }
482     } else {
483       matched = false;
484     }
485   }
486 
487   if (!matched) {
488     print_error(cur_pos_);
489     skip_until_whitespace_from(cur_pos_);
490     skip_whitespace_from(cur_pos_);
491     return false;
492   }
493 
494   cur_pos_ += matches.length(0);
495   skip_whitespace_from(cur_pos_);
496   return true;
497 }
498 
parse_identifier(ssize_t pos,optional<std::string> * result)499 ssize_t ArgumentParser_x64::parse_identifier(ssize_t pos,
500                                              optional<std::string> *result) {
501   if (isalpha(arg_[pos]) || arg_[pos] == '_') {
502     ssize_t start = pos++;
503     while (isalnum(arg_[pos]) || arg_[pos] == '_') pos++;
504     if (pos - start)
505       result->emplace(arg_ + start, pos - start);
506   }
507   return pos;
508 }
509 
parse_register(ssize_t pos,std::string & name,int & size)510 ssize_t ArgumentParser_x64::parse_register(ssize_t pos, std::string &name,
511                                            int &size) {
512   ssize_t start = ++pos;
513   if (arg_[start - 1] != '%')
514     return -start;
515 
516   while (isalnum(arg_[pos])) pos++;
517 
518   std::string regname(arg_ + start, pos - start);
519   if (!normalize_register(&regname, &size))
520     return -start;
521 
522   name = regname;
523   return pos;
524 }
525 
parse_base_register(ssize_t pos,Argument * dest)526 ssize_t ArgumentParser_x64::parse_base_register(ssize_t pos, Argument *dest) {
527   int size;
528   std::string name;
529   ssize_t res = parse_register(pos, name, size);
530   if (res < 0)
531       return res;
532 
533   dest->base_register_name_ = name;
534   if (!dest->arg_size_)
535     dest->arg_size_ = size;
536 
537   return res;
538 }
539 
parse_index_register(ssize_t pos,Argument * dest)540 ssize_t ArgumentParser_x64::parse_index_register(ssize_t pos, Argument *dest) {
541   int size;
542   std::string name;
543   ssize_t res = parse_register(pos, name, size);
544   if (res < 0)
545       return res;
546 
547   dest->index_register_name_ = name;
548 
549   return res;
550 }
551 
parse_scale(ssize_t pos,Argument * dest)552 ssize_t ArgumentParser_x64::parse_scale(ssize_t pos, Argument *dest) {
553   return parse_number(pos, &dest->scale_);
554 }
555 
parse_expr(ssize_t pos,Argument * dest)556 ssize_t ArgumentParser_x64::parse_expr(ssize_t pos, Argument *dest) {
557   if (arg_[pos] == '$')
558     return parse_number(pos + 1, &dest->constant_);
559 
560   if (arg_[pos] == '%')
561     return parse_base_register(pos, dest);
562 
563   if (isdigit(arg_[pos]) || arg_[pos] == '-') {
564     pos = parse_number(pos, &dest->deref_offset_);
565     if (arg_[pos] == '+') {
566       pos = parse_identifier(pos + 1, &dest->deref_ident_);
567       if (!dest->deref_ident_)
568         return -pos;
569     }
570   } else {
571     dest->deref_offset_ = 0;
572     pos = parse_identifier(pos, &dest->deref_ident_);
573     if (arg_[pos] == '+' || arg_[pos] == '-') {
574       pos = parse_number(pos, &dest->deref_offset_);
575     }
576   }
577 
578   if (arg_[pos] != '(')
579     return -pos;
580 
581   pos = parse_base_register(pos + 1, dest);
582   if (pos < 0)
583     return pos;
584 
585   if (arg_[pos] == ',') {
586     pos = parse_index_register(pos + 1, dest);
587     if (pos < 0)
588       return pos;
589 
590     if (arg_[pos] == ',') {
591       pos = parse_scale(pos + 1, dest);
592       if (pos < 0)
593         return pos;
594     }
595   }
596 
597   return (arg_[pos] == ')') ? pos + 1 : -pos;
598 }
599 
parse_1(ssize_t pos,Argument * dest)600 ssize_t ArgumentParser_x64::parse_1(ssize_t pos, Argument *dest) {
601   if (isdigit(arg_[pos]) || arg_[pos] == '-') {
602     optional<int> asize;
603     ssize_t m = parse_number(pos, &asize);
604     if (arg_[m] == '@' && asize) {
605       dest->arg_size_ = asize;
606       return parse_expr(m + 1, dest);
607     }
608   }
609   return parse_expr(pos, dest);
610 }
611 
parse(Argument * dest)612 bool ArgumentParser_x64::parse(Argument *dest) {
613   if (done())
614     return false;
615 
616   ssize_t res = parse_1(cur_pos_, dest);
617   if (res < 0)
618     return error_return(-res, -res + 1);
619   if (!isspace(arg_[res]) && arg_[res] != '\0')
620     return error_return(res, res);
621   skip_whitespace_from(res);
622   return true;
623 }
624 
625 const std::unordered_map<std::string, ArgumentParser_x64::RegInfo>
626     ArgumentParser_x64::registers_ = {
627         {"rax", {X64_REG_A, 8}},   {"eax", {X64_REG_A, 4}},
628         {"ax", {X64_REG_A, 2}},    {"al", {X64_REG_A, 1}},
629 
630         {"rbx", {X64_REG_B, 8}},   {"ebx", {X64_REG_B, 4}},
631         {"bx", {X64_REG_B, 2}},    {"bl", {X64_REG_B, 1}},
632 
633         {"rcx", {X64_REG_C, 8}},   {"ecx", {X64_REG_C, 4}},
634         {"cx", {X64_REG_C, 2}},    {"cl", {X64_REG_C, 1}},
635 
636         {"rdx", {X64_REG_D, 8}},   {"edx", {X64_REG_D, 4}},
637         {"dx", {X64_REG_D, 2}},    {"dl", {X64_REG_D, 1}},
638 
639         {"rsi", {X64_REG_SI, 8}},  {"esi", {X64_REG_SI, 4}},
640         {"si", {X64_REG_SI, 2}},   {"sil", {X64_REG_SI, 1}},
641 
642         {"rdi", {X64_REG_DI, 8}},  {"edi", {X64_REG_DI, 4}},
643         {"di", {X64_REG_DI, 2}},   {"dil", {X64_REG_DI, 1}},
644 
645         {"rbp", {X64_REG_BP, 8}},  {"ebp", {X64_REG_BP, 4}},
646         {"bp", {X64_REG_BP, 2}},   {"bpl", {X64_REG_BP, 1}},
647 
648         {"rsp", {X64_REG_SP, 8}},  {"esp", {X64_REG_SP, 4}},
649         {"sp", {X64_REG_SP, 2}},   {"spl", {X64_REG_SP, 1}},
650 
651         {"r8", {X64_REG_8, 8}},    {"r8d", {X64_REG_8, 4}},
652         {"r8w", {X64_REG_8, 2}},   {"r8b", {X64_REG_8, 1}},
653 
654         {"r9", {X64_REG_9, 8}},    {"r9d", {X64_REG_9, 4}},
655         {"r9w", {X64_REG_9, 2}},   {"r9b", {X64_REG_9, 1}},
656 
657         {"r10", {X64_REG_10, 8}},  {"r10d", {X64_REG_10, 4}},
658         {"r10w", {X64_REG_10, 2}}, {"r10b", {X64_REG_10, 1}},
659 
660         {"r11", {X64_REG_11, 8}},  {"r11d", {X64_REG_11, 4}},
661         {"r11w", {X64_REG_11, 2}}, {"r11b", {X64_REG_11, 1}},
662 
663         {"r12", {X64_REG_12, 8}},  {"r12d", {X64_REG_12, 4}},
664         {"r12w", {X64_REG_12, 2}}, {"r12b", {X64_REG_12, 1}},
665 
666         {"r13", {X64_REG_13, 8}},  {"r13d", {X64_REG_13, 4}},
667         {"r13w", {X64_REG_13, 2}}, {"r13b", {X64_REG_13, 1}},
668 
669         {"r14", {X64_REG_14, 8}},  {"r14d", {X64_REG_14, 4}},
670         {"r14w", {X64_REG_14, 2}}, {"r14b", {X64_REG_14, 1}},
671 
672         {"r15", {X64_REG_15, 8}},  {"r15d", {X64_REG_15, 4}},
673         {"r15w", {X64_REG_15, 2}}, {"r15b", {X64_REG_15, 1}},
674 
675         {"rip", {X64_REG_RIP, 8}},
676 
677         {"xmm0", {X64_REG_XMM0, 16}},
678         {"xmm1", {X64_REG_XMM1, 16}},
679         {"xmm2", {X64_REG_XMM2, 16}},
680         {"xmm3", {X64_REG_XMM3, 16}},
681         {"xmm4", {X64_REG_XMM4, 16}},
682         {"xmm5", {X64_REG_XMM5, 16}},
683         {"xmm6", {X64_REG_XMM6, 16}},
684         {"xmm7", {X64_REG_XMM7, 16}},
685         {"xmm8", {X64_REG_XMM8, 16}},
686         {"xmm9", {X64_REG_XMM9, 16}},
687         {"xmm10", {X64_REG_XMM10, 16}},
688         {"xmm11", {X64_REG_XMM11, 16}},
689         {"xmm12", {X64_REG_XMM12, 16}},
690         {"xmm13", {X64_REG_XMM13, 16}},
691         {"xmm14", {X64_REG_XMM14, 16}},
692         {"xmm15", {X64_REG_XMM15, 16}},
693 };
694 
reg_to_name(std::string * norm,Register reg)695 void ArgumentParser_x64::reg_to_name(std::string *norm, Register reg) {
696   switch (reg) {
697   case X64_REG_A:
698     *norm = "ax";
699     break;
700   case X64_REG_B:
701     *norm = "bx";
702     break;
703   case X64_REG_C:
704     *norm = "cx";
705     break;
706   case X64_REG_D:
707     *norm = "dx";
708     break;
709 
710   case X64_REG_SI:
711     *norm = "si";
712     break;
713   case X64_REG_DI:
714     *norm = "di";
715     break;
716   case X64_REG_BP:
717     *norm = "bp";
718     break;
719   case X64_REG_SP:
720     *norm = "sp";
721     break;
722 
723   case X64_REG_8:
724     *norm = "r8";
725     break;
726   case X64_REG_9:
727     *norm = "r9";
728     break;
729   case X64_REG_10:
730     *norm = "r10";
731     break;
732   case X64_REG_11:
733     *norm = "r11";
734     break;
735   case X64_REG_12:
736     *norm = "r12";
737     break;
738   case X64_REG_13:
739     *norm = "r13";
740     break;
741   case X64_REG_14:
742     *norm = "r14";
743     break;
744   case X64_REG_15:
745     *norm = "r15";
746     break;
747 
748   case X64_REG_RIP:
749     *norm = "ip";
750     break;
751 
752   case X64_REG_XMM0:
753     *norm = "xmm0";
754     break;
755   case X64_REG_XMM1:
756     *norm = "xmm1";
757     break;
758   case X64_REG_XMM2:
759     *norm = "xmm2";
760     break;
761   case X64_REG_XMM3:
762     *norm = "xmm3";
763     break;
764   case X64_REG_XMM4:
765     *norm = "xmm4";
766     break;
767   case X64_REG_XMM5:
768     *norm = "xmm5";
769     break;
770   case X64_REG_XMM6:
771     *norm = "xmm6";
772     break;
773   case X64_REG_XMM7:
774     *norm = "xmm7";
775     break;
776   case X64_REG_XMM8:
777     *norm = "xmm8";
778     break;
779   case X64_REG_XMM9:
780     *norm = "xmm9";
781     break;
782   case X64_REG_XMM10:
783     *norm = "xmm10";
784     break;
785   case X64_REG_XMM11:
786     *norm = "xmm11";
787     break;
788   case X64_REG_XMM12:
789     *norm = "xmm12";
790     break;
791   case X64_REG_XMM13:
792     *norm = "xmm13";
793     break;
794   case X64_REG_XMM14:
795     *norm = "xmm14";
796     break;
797   case X64_REG_XMM15:
798     *norm = "xmm15";
799     break;
800 
801   }
802 }
803 
normalize_register(std::string * reg,int * reg_size)804 bool ArgumentParser_x64::normalize_register(std::string *reg, int *reg_size) {
805   auto it = registers_.find(*reg);
806   if (it == registers_.end())
807     return false;
808 
809   *reg_size = it->second.size;
810   reg_to_name(reg, it->second.reg);
811   return true;
812 }
813 }
814