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 ®_name) {
143 if (arg_[pos] == 'x') {
144 optional<int> reg_num;
145 new_pos = parse_number(pos + 1, ®_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 ®_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(®name, &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