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