this repo has no description
at trunk 1984 lines 60 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2// Copyright (c) 2013, the Dart project authors and Facebook, Inc. and its 3// affiliates. Please see the AUTHORS-Dart file for details. All rights 4// reserved. Use of this source code is governed by a BSD-style license that 5// can be found in the LICENSE-Dart file. 6 7// A combined disassembler for IA32 and X64. 8 9#include "disassembler.h" 10 11#include <cinttypes> 12#include <cstdarg> 13 14#include "assembler-x64.h" 15 16namespace py { 17 18namespace x64 { 19 20enum OperandType { 21 UNSET_OP_ORDER = 0, 22 // Operand size decides between 16, 32 and 64 bit operands. 23 REG_OPER_OP_ORDER = 1, // Register destination, operand source. 24 OPER_REG_OP_ORDER = 2, // Operand destination, register source. 25 // Fixed 8-bit operands. 26 BYTE_SIZE_OPERAND_FLAG = 4, 27 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG, 28 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG 29}; 30 31//------------------------------------------------------------------ 32// Tables 33//------------------------------------------------------------------ 34struct ByteMnemonic { 35 int b; // -1 terminates, otherwise must be in range (0..255) 36 OperandType op_order_; 37 const char* mnem; 38}; 39 40#define ALU_ENTRY(name, code) \ 41 {code * 8 + 0, BYTE_OPER_REG_OP_ORDER, #name}, \ 42 {code * 8 + 1, OPER_REG_OP_ORDER, #name}, \ 43 {code * 8 + 2, BYTE_REG_OPER_OP_ORDER, #name}, \ 44 {code * 8 + 3, REG_OPER_OP_ORDER, #name}, 45static const ByteMnemonic kTwoOperandInstructions[] = { 46 X86_ALU_CODES(ALU_ENTRY){0x63, REG_OPER_OP_ORDER, "movsxd"}, 47 {0x84, BYTE_REG_OPER_OP_ORDER, "test"}, 48 {0x85, REG_OPER_OP_ORDER, "test"}, 49 {0x86, BYTE_REG_OPER_OP_ORDER, "xchg"}, 50 {0x87, REG_OPER_OP_ORDER, "xchg"}, 51 {0x88, BYTE_OPER_REG_OP_ORDER, "mov"}, 52 {0x89, OPER_REG_OP_ORDER, "mov"}, 53 {0x8A, BYTE_REG_OPER_OP_ORDER, "mov"}, 54 {0x8B, REG_OPER_OP_ORDER, "mov"}, 55 {0x8D, REG_OPER_OP_ORDER, "lea"}, 56 {-1, UNSET_OP_ORDER, ""}}; 57 58#define ZERO_OPERAND_ENTRY(name, opcode) {opcode, UNSET_OP_ORDER, #name}, 59static const ByteMnemonic kZeroOperandInstructions[] = { 60 X86_ZERO_OPERAND_1_BYTE_INSTRUCTIONS(ZERO_OPERAND_ENTRY){-1, UNSET_OP_ORDER, 61 ""}}; 62 63static const ByteMnemonic kCallJumpInstructions[] = { 64 {0xE8, UNSET_OP_ORDER, "call"}, 65 {0xE9, UNSET_OP_ORDER, "jmp"}, 66 {-1, UNSET_OP_ORDER, ""}}; 67 68#define SHORT_IMMEDIATE_ENTRY(name, code) {code * 8 + 5, UNSET_OP_ORDER, #name}, 69static const ByteMnemonic kShortImmediateInstructions[] = { 70 X86_ALU_CODES(SHORT_IMMEDIATE_ENTRY){-1, UNSET_OP_ORDER, ""}}; 71 72static const char* const kConditionalCodeSuffix[] = { 73#define STRINGIFY(name, number) #name, 74 X86_CONDITIONAL_SUFFIXES(STRINGIFY) 75#undef STRINGIFY 76}; 77 78#define STRINGIFY_NAME(name, code) #name, 79static const char* const kXmmConditionalCodeSuffix[] = { 80 XMM_CONDITIONAL_CODES(STRINGIFY_NAME)}; 81#undef STRINGIFY_NAME 82 83enum InstructionType { 84 NO_INSTR, 85 ZERO_OPERANDS_INSTR, 86 TWO_OPERANDS_INSTR, 87 JUMP_CONDITIONAL_SHORT_INSTR, 88 REGISTER_INSTR, 89 PUSHPOP_INSTR, // Has implicit 64-bit operand size. 90 MOVE_REG_INSTR, 91 CALL_JUMP_INSTR, 92 SHORT_IMMEDIATE_INSTR 93}; 94 95enum Prefixes { 96 ESCAPE_PREFIX = 0x0F, 97 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66, 98 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67, 99 REPNE_PREFIX = 0xF2, 100 REP_PREFIX = 0xF3, 101 REPEQ_PREFIX = REP_PREFIX 102}; 103 104struct XmmMnemonic { 105 const char* ps_name; 106 const char* pd_name; 107 const char* ss_name; 108 const char* sd_name; 109}; 110 111#define XMM_INSTRUCTION_ENTRY(name, code) \ 112 {#name "ps", #name "pd", #name "ss", #name "sd"}, 113static const XmmMnemonic kXmmInstructions[] = { 114 XMM_ALU_CODES(XMM_INSTRUCTION_ENTRY)}; 115 116struct InstructionDesc { 117 const char* mnem; 118 InstructionType type; 119 OperandType op_order_; 120 bool byte_size_operation; // Fixed 8-bit operation. 121}; 122 123class InstructionTable { 124 public: 125 InstructionTable(); 126 const InstructionDesc& get(uint8_t x) const { return instructions_[x]; } 127 128 private: 129 InstructionDesc instructions_[256]; 130 void clear(); 131 void init(); 132 void copyTable(const ByteMnemonic bm[], InstructionType type); 133 void setTableRange(InstructionType type, uint8_t start, uint8_t end, 134 bool byte_size, const char* mnem); 135 void addJumpConditionalShort(); 136 137 DISALLOW_COPY_AND_ASSIGN(InstructionTable); 138}; 139 140InstructionTable::InstructionTable() { 141 clear(); 142 init(); 143} 144 145void InstructionTable::clear() { 146 for (int i = 0; i < 256; i++) { 147 instructions_[i].mnem = "(bad)"; 148 instructions_[i].type = NO_INSTR; 149 instructions_[i].op_order_ = UNSET_OP_ORDER; 150 instructions_[i].byte_size_operation = false; 151 } 152} 153 154void InstructionTable::init() { 155 copyTable(kTwoOperandInstructions, TWO_OPERANDS_INSTR); 156 copyTable(kZeroOperandInstructions, ZERO_OPERANDS_INSTR); 157 copyTable(kCallJumpInstructions, CALL_JUMP_INSTR); 158 copyTable(kShortImmediateInstructions, SHORT_IMMEDIATE_INSTR); 159 addJumpConditionalShort(); 160 setTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push"); 161 setTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop"); 162 setTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov"); 163} 164 165void InstructionTable::copyTable(const ByteMnemonic bm[], 166 InstructionType type) { 167 for (int i = 0; bm[i].b >= 0; i++) { 168 InstructionDesc* id = &instructions_[bm[i].b]; 169 id->mnem = bm[i].mnem; 170 OperandType op_order = bm[i].op_order_; 171 id->op_order_ = 172 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); 173 DCHECK(NO_INSTR == id->type, ""); // Information not already entered 174 id->type = type; 175 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); 176 } 177} 178 179void InstructionTable::setTableRange(InstructionType type, uint8_t start, 180 uint8_t end, bool byte_size, 181 const char* mnem) { 182 for (uint8_t b = start; b <= end; b++) { 183 InstructionDesc* id = &instructions_[b]; 184 DCHECK(NO_INSTR == id->type, ""); // Information not already entered 185 id->mnem = mnem; 186 id->type = type; 187 id->byte_size_operation = byte_size; 188 } 189} 190 191void InstructionTable::addJumpConditionalShort() { 192 for (uint8_t b = 0x70; b <= 0x7F; b++) { 193 InstructionDesc* id = &instructions_[b]; 194 DCHECK(NO_INSTR == id->type, ""); // Information not already entered 195 id->mnem = nullptr; // Computed depending on condition code. 196 id->type = JUMP_CONDITIONAL_SHORT_INSTR; 197 } 198} 199 200static InstructionTable instruction_table; 201 202static InstructionDesc cmov_instructions[16] = { 203 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 204 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 205 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 206 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 207 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 208 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 209 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 210 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 211 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 212 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 213 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 214 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 215 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 216 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 217 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}, 218 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}}; 219 220//------------------------------------------------- 221// DisassemblerX64 implementation. 222 223static const char* kRegisterNames[] = { 224 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", 225 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 226}; 227 228static_assert(ARRAYSIZE(kRegisterNames) == kNumRegisters, 229 "register count mismatch"); 230 231static const char* kXmmRegisterNames[kNumXmmRegisters] = { 232 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", 233 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"}; 234 235static_assert(ARRAYSIZE(kXmmRegisterNames) == kNumXmmRegisters, 236 "register count mismatch"); 237 238class DisassemblerX64 { 239 public: 240 DisassemblerX64(char* buffer, intptr_t buffer_size) 241 : buffer_(buffer), 242 buffer_size_(buffer_size), 243 buffer_pos_(0), 244 rex_(0), 245 operand_size_(0), 246 group_1_prefix_(0), 247 byte_size_operand_(false) { 248 buffer_[buffer_pos_] = '\0'; 249 } 250 251 virtual ~DisassemblerX64() {} 252 253 int instructionDecode(uword pc); 254 255 private: 256 enum OperandSize { 257 BYTE_SIZE = 0, 258 WORD_SIZE = 1, 259 DOUBLEWORD_SIZE = 2, 260 QUADWORD_SIZE = 3 261 }; 262 263 void setRex(uint8_t rex) { 264 DCHECK(0x40 == (rex & 0xF0), ""); 265 rex_ = rex; 266 } 267 268 bool rex() { return rex_ != 0; } 269 270 bool rexB() { return (rex_ & 0x01) != 0; } 271 272 // Actual number of base register given the low bits and the rex.b state. 273 int baseReg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } 274 275 bool rexX() { return (rex_ & 0x02) != 0; } 276 277 bool rexR() { return (rex_ & 0x04) != 0; } 278 279 bool rexW() { return (rex_ & 0x08) != 0; } 280 281 OperandSize operandSize() { 282 if (byte_size_operand_) return BYTE_SIZE; 283 if (rexW()) return QUADWORD_SIZE; 284 if (operand_size_ != 0) return WORD_SIZE; 285 return DOUBLEWORD_SIZE; 286 } 287 288 const char* operandSizeCode() { return &"b\0w\0l\0q\0"[2 * operandSize()]; } 289 290 // Disassembler helper functions. 291 void getModRM(uint8_t data, int* mod, int* regop, int* rm) { 292 *mod = (data >> 6) & 3; 293 *regop = ((data & 0x38) >> 3) | (rexR() ? 8 : 0); 294 *rm = (data & 7) | (rexB() ? 8 : 0); 295 DCHECK(*rm < kNumRegisters, ""); 296 } 297 298 void getSIB(uint8_t data, int* scale, int* index, int* base) { 299 *scale = (data >> 6) & 3; 300 *index = ((data >> 3) & 7) | (rexX() ? 8 : 0); 301 *base = (data & 7) | (rexB() ? 8 : 0); 302 DCHECK(*base < kNumRegisters, ""); 303 } 304 305 const char* nameOfCPURegister(int reg) const { return kRegisterNames[reg]; } 306 307 const char* nameOfByteCPURegister(int reg) const { 308 return nameOfCPURegister(reg); 309 } 310 311 // A way to get rax or eax's name. 312 const char* rax() const { return nameOfCPURegister(0); } 313 314 const char* nameOfXMMRegister(int reg) const { 315 DCHECK((0 <= reg) && (reg < kNumXmmRegisters), ""); 316 return kXmmRegisterNames[reg]; 317 } 318 319 void print(const char* format, ...); 320 void printJump(uint8_t* pc, int32_t disp); 321 void printAddress(uint8_t* addr); 322 323 int printOperands(const char* mnem, OperandType op_order, uint8_t* data); 324 325 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; 326 327 int printRightOperandHelper(uint8_t* modrmp, 328 RegisterNameMapping register_name); 329 int printRightOperand(uint8_t* modrmp); 330 int printRightByteOperand(uint8_t* modrmp); 331 int printRightXMMOperand(uint8_t* modrmp); 332 void printDisp(int disp, const char* after); 333 int printImmediate(uint8_t* data, OperandSize size, bool sign_extend = false); 334 void printImmediateValue(int64_t value, bool signed_value = false, 335 int byte_count = -1); 336 int printImmediateOp(uint8_t* data); 337 const char* twoByteMnemonic(uint8_t opcode); 338 int twoByteOpcodeInstruction(uint8_t* data); 339 int print660F38Instruction(uint8_t* data); 340 341 int f6F7Instruction(uint8_t* data); 342 int shiftInstruction(uint8_t* data); 343 int jumpShort(uint8_t* data); 344 int jumpConditional(uint8_t* data); 345 int jumpConditionalShort(uint8_t* data); 346 int setCC(uint8_t* data); 347 int fPUInstruction(uint8_t* data); 348 int memoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start); 349 int registerFPUInstruction(int escape_opcode, uint8_t modrm_byte); 350 351 bool decodeInstructionType(uint8_t** data); 352 353 void unimplementedInstruction() { UNREACHABLE("unimplemented instruction"); } 354 355 char* buffer_; // Decode instructions into this buffer. 356 intptr_t buffer_size_; // The size of the buffer_. 357 intptr_t buffer_pos_; // Current character position in the buffer_. 358 359 // Prefixes parsed 360 uint8_t rex_; 361 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. 362 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. 363 uint8_t group_1_prefix_; 364 // Byte size operand override. 365 bool byte_size_operand_; 366 367 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); 368}; 369 370// Append the str to the output buffer. 371void DisassemblerX64::print(const char* format, ...) { 372 intptr_t available = buffer_size_ - buffer_pos_; 373 if (available <= 1) { 374 DCHECK(buffer_[buffer_pos_] == '\0', ""); 375 return; 376 } 377 char* buf = buffer_ + buffer_pos_; 378 va_list args; 379 va_start(args, format); 380 int length = std::vsnprintf(buf, available, format, args); 381 va_end(args); 382 buffer_pos_ = 383 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); 384 DCHECK(buffer_pos_ < buffer_size_, ""); 385} 386 387template <typename T> 388static inline T LoadUnaligned(const T* ptr) { 389 return *ptr; 390} 391 392int DisassemblerX64::printRightOperandHelper( 393 uint8_t* modrmp, RegisterNameMapping direct_register_name) { 394 int mod, regop, rm; 395 getModRM(*modrmp, &mod, &regop, &rm); 396 RegisterNameMapping register_name = 397 (mod == 3) ? direct_register_name : &DisassemblerX64::nameOfCPURegister; 398 switch (mod) { 399 case 0: 400 if ((rm & 7) == 5) { 401 int32_t disp = Utils::readBytes<int32_t>(modrmp + 1); 402 print("[rip"); 403 printDisp(disp, "]"); 404 return 5; 405 } 406 if ((rm & 7) == 4) { 407 // Codes for SIB byte. 408 uint8_t sib = *(modrmp + 1); 409 int scale, index, base; 410 getSIB(sib, &scale, &index, &base); 411 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { 412 // index == rsp means no index. Only use sib byte with no index for 413 // rsp and r12 base. 414 print("[%s]", nameOfCPURegister(base)); 415 return 2; 416 } 417 if (base == 5) { 418 // base == rbp means no base register (when mod == 0). 419 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 2)); 420 print("[%s*%d", nameOfCPURegister(index), 1 << scale); 421 printDisp(disp, "]"); 422 return 6; 423 } 424 if (index != 4 && base != 5) { 425 // [base+index*scale] 426 print("[%s+%s*%d]", nameOfCPURegister(base), nameOfCPURegister(index), 427 1 << scale); 428 return 2; 429 } 430 unimplementedInstruction(); 431 return 1; 432 } 433 print("[%s]", nameOfCPURegister(rm)); 434 return 1; 435 break; 436 case 1: 437 FALLTHROUGH; 438 case 2: 439 if ((rm & 7) == 4) { 440 uint8_t sib = *(modrmp + 1); 441 int scale, index, base; 442 getSIB(sib, &scale, &index, &base); 443 int disp = (mod == 2) 444 ? LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 2)) 445 : *reinterpret_cast<int8_t*>(modrmp + 2); 446 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { 447 print("[%s", nameOfCPURegister(base)); 448 printDisp(disp, "]"); 449 } else { 450 print("[%s+%s*%d", nameOfCPURegister(base), nameOfCPURegister(index), 451 1 << scale); 452 printDisp(disp, "]"); 453 } 454 return mod == 2 ? 6 : 3; 455 } else { 456 // No sib. 457 int disp = (mod == 2) 458 ? LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 1)) 459 : *reinterpret_cast<int8_t*>(modrmp + 1); 460 print("[%s", nameOfCPURegister(rm)); 461 printDisp(disp, "]"); 462 return (mod == 2) ? 5 : 2; 463 } 464 break; 465 case 3: 466 print("%s", (this->*register_name)(rm)); 467 return 1; 468 default: 469 unimplementedInstruction(); 470 return 1; 471 } 472 UNREACHABLE("unreachable"); 473} 474 475int DisassemblerX64::printImmediate(uint8_t* data, OperandSize size, 476 bool sign_extend) { 477 int64_t value; 478 int count; 479 switch (size) { 480 case BYTE_SIZE: 481 if (sign_extend) { 482 value = *reinterpret_cast<int8_t*>(data); 483 } else { 484 value = *data; 485 } 486 count = 1; 487 break; 488 case WORD_SIZE: 489 if (sign_extend) { 490 value = LoadUnaligned(reinterpret_cast<int16_t*>(data)); 491 } else { 492 value = LoadUnaligned(reinterpret_cast<uint16_t*>(data)); 493 } 494 count = 2; 495 break; 496 case DOUBLEWORD_SIZE: 497 case QUADWORD_SIZE: 498 if (sign_extend) { 499 value = LoadUnaligned(reinterpret_cast<int32_t*>(data)); 500 } else { 501 value = LoadUnaligned(reinterpret_cast<uint32_t*>(data)); 502 } 503 count = 4; 504 break; 505 default: 506 UNREACHABLE("unreachable"); 507 value = 0; // Initialize variables on all paths to satisfy the compiler. 508 count = 0; 509 } 510 printImmediateValue(value, sign_extend, count); 511 return count; 512} 513 514void DisassemblerX64::printImmediateValue(int64_t value, bool signed_value, 515 int byte_count) { 516 if ((value >= 0) && (value <= 9)) { 517 print("%" PRId64, value); 518 } else if (signed_value && (value < 0) && (value >= -9)) { 519 print("-%" PRId64, -value); 520 } else { 521 if (byte_count == 1) { 522 int8_t v8 = static_cast<int8_t>(value); 523 if (v8 < 0 && signed_value) { 524 print("-%#" PRIX32, -static_cast<uint8_t>(v8)); 525 } else { 526 print("%#" PRIX32, static_cast<uint8_t>(v8)); 527 } 528 } else if (byte_count == 2) { 529 int16_t v16 = static_cast<int16_t>(value); 530 if (v16 < 0 && signed_value) { 531 print("-%#" PRIX32, -static_cast<uint16_t>(v16)); 532 } else { 533 print("%#" PRIX32, static_cast<uint16_t>(v16)); 534 } 535 } else if (byte_count == 4) { 536 int32_t v32 = static_cast<int32_t>(value); 537 if (v32 < 0 && signed_value) { 538 print("-%#010" PRIX32, -static_cast<uint32_t>(v32)); 539 } else { 540 if (v32 > 0xffff) { 541 print("%#010" PRIX32, v32); 542 } else { 543 print("%#" PRIX32, v32); 544 } 545 } 546 } else if (byte_count == 8) { 547 int64_t v64 = static_cast<int64_t>(value); 548 if (v64 < 0 && signed_value) { 549 print("-%#018" PRIX64, -static_cast<uint64_t>(v64)); 550 } else { 551 if (v64 > 0xffffffffll) { 552 print("%#018" PRIX64, v64); 553 } else { 554 print("%#" PRIX64, v64); 555 } 556 } 557 } else { 558 // Natural-sized immediates. 559 if (value < 0 && signed_value) { 560 print("-%#" PRIX64, -value); 561 } else { 562 print("%#" PRIX64, value); 563 } 564 } 565 } 566} 567 568void DisassemblerX64::printDisp(int disp, const char* after) { 569 if (-disp > 0) { 570 print("-%#x", -disp); 571 } else { 572 print("+%#x", disp); 573 } 574 if (after != nullptr) print("%s", after); 575} 576 577// Returns number of bytes used by machine instruction, including *data byte. 578// Writes immediate instructions to 'tmp_buffer_'. 579int DisassemblerX64::printImmediateOp(uint8_t* data) { 580 bool byte_size_immediate = (*data & 0x03) != 1; 581 uint8_t modrm = *(data + 1); 582 int mod, regop, rm; 583 getModRM(modrm, &mod, &regop, &rm); 584 const char* mnem = "Imm???"; 585 switch (regop) { 586 case 0: 587 mnem = "add"; 588 break; 589 case 1: 590 mnem = "or"; 591 break; 592 case 2: 593 mnem = "adc"; 594 break; 595 case 3: 596 mnem = "sbb"; 597 break; 598 case 4: 599 mnem = "and"; 600 break; 601 case 5: 602 mnem = "sub"; 603 break; 604 case 6: 605 mnem = "xor"; 606 break; 607 case 7: 608 mnem = "cmp"; 609 break; 610 default: 611 unimplementedInstruction(); 612 } 613 print("%s%s ", mnem, operandSizeCode()); 614 int count = printRightOperand(data + 1); 615 print(","); 616 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operandSize(); 617 count += 618 printImmediate(data + 1 + count, immediate_size, byte_size_immediate); 619 return 1 + count; 620} 621 622// Returns number of bytes used, including *data. 623int DisassemblerX64::f6F7Instruction(uint8_t* data) { 624 DCHECK(*data == 0xF7 || *data == 0xF6, ""); 625 uint8_t modrm = *(data + 1); 626 int mod, regop, rm; 627 getModRM(modrm, &mod, &regop, &rm); 628 static const char* mnemonics[] = {"test", nullptr, "not", "neg", 629 "mul", "imul", "div", "idiv"}; 630 const char* mnem = mnemonics[regop]; 631 if (mod == 3 && regop != 0) { 632 if (regop > 3) { 633 // These are instructions like idiv that implicitly use EAX and EDX as a 634 // source and destination. We make this explicit in the disassembly. 635 print("%s%s (%s,%s),%s", mnem, operandSizeCode(), rax(), 636 nameOfCPURegister(2), nameOfCPURegister(rm)); 637 } else { 638 print("%s%s %s", mnem, operandSizeCode(), nameOfCPURegister(rm)); 639 } 640 return 2; 641 } 642 if (regop == 0) { 643 print("test%s ", operandSizeCode()); 644 int count = printRightOperand(data + 1); // Use name of 64-bit register. 645 print(","); 646 count += printImmediate(data + 1 + count, operandSize()); 647 return 1 + count; 648 } 649 if (regop >= 4) { 650 print("%s%s (%s,%s),", mnem, operandSizeCode(), rax(), 651 nameOfCPURegister(2)); 652 return 1 + printRightOperand(data + 1); 653 } 654 unimplementedInstruction(); 655 return 2; 656} 657 658int DisassemblerX64::shiftInstruction(uint8_t* data) { 659 // C0/C1: Shift Imm8 660 // D0/D1: Shift 1 661 // D2/D3: Shift CL 662 uint8_t op = *data & (~1); 663 if (op != 0xD0 && op != 0xD2 && op != 0xC0) { 664 unimplementedInstruction(); 665 return 1; 666 } 667 uint8_t* modrm = data + 1; 668 int mod, regop, rm; 669 getModRM(*modrm, &mod, &regop, &rm); 670 regop &= 0x7; // The REX.R bit does not affect the operation. 671 int num_bytes = 1; 672 const char* mnem = nullptr; 673 switch (regop) { 674 case 0: 675 mnem = "rol"; 676 break; 677 case 1: 678 mnem = "ror"; 679 break; 680 case 2: 681 mnem = "rcl"; 682 break; 683 case 3: 684 mnem = "rcr"; 685 break; 686 case 4: 687 mnem = "shl"; 688 break; 689 case 5: 690 mnem = "shr"; 691 break; 692 case 7: 693 mnem = "sar"; 694 break; 695 default: 696 unimplementedInstruction(); 697 return num_bytes; 698 } 699 DCHECK(nullptr != mnem, ""); 700 print("%s%s ", mnem, operandSizeCode()); 701 if (byte_size_operand_) { 702 num_bytes += printRightByteOperand(modrm); 703 } else { 704 num_bytes += printRightOperand(modrm); 705 } 706 707 if (op == 0xD0) { 708 print(",1"); 709 } else if (op == 0xC0) { 710 uint8_t imm8 = *(data + num_bytes); 711 print(",%d", imm8); 712 num_bytes++; 713 } else { 714 DCHECK(op == 0xD2, ""); 715 print(",cl"); 716 } 717 return num_bytes; 718} 719 720int DisassemblerX64::printRightOperand(uint8_t* modrmp) { 721 return printRightOperandHelper(modrmp, &DisassemblerX64::nameOfCPURegister); 722} 723 724int DisassemblerX64::printRightByteOperand(uint8_t* modrmp) { 725 return printRightOperandHelper(modrmp, 726 &DisassemblerX64::nameOfByteCPURegister); 727} 728 729int DisassemblerX64::printRightXMMOperand(uint8_t* modrmp) { 730 return printRightOperandHelper(modrmp, &DisassemblerX64::nameOfXMMRegister); 731} 732 733// Returns number of bytes used including the current *data. 734// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. 735int DisassemblerX64::printOperands(const char* mnem, OperandType op_order, 736 uint8_t* data) { 737 uint8_t modrm = *data; 738 int mod, regop, rm; 739 getModRM(modrm, &mod, &regop, &rm); 740 int advance = 0; 741 const char* register_name = byte_size_operand_ ? nameOfByteCPURegister(regop) 742 : nameOfCPURegister(regop); 743 switch (op_order) { 744 case REG_OPER_OP_ORDER: { 745 print("%s%s %s,", mnem, operandSizeCode(), register_name); 746 advance = byte_size_operand_ ? printRightByteOperand(data) 747 : printRightOperand(data); 748 break; 749 } 750 case OPER_REG_OP_ORDER: { 751 print("%s%s ", mnem, operandSizeCode()); 752 advance = byte_size_operand_ ? printRightByteOperand(data) 753 : printRightOperand(data); 754 print(",%s", register_name); 755 break; 756 } 757 default: 758 UNREACHABLE("unreachable"); 759 break; 760 } 761 return advance; 762} 763 764void DisassemblerX64::printJump(uint8_t* pc, int32_t disp) { 765 // TODO(emacs): Support relative disassembly flag. 766 bool flag_disassemble_relative = false; 767 if (flag_disassemble_relative) { 768 print("%+d", disp); 769 } else { 770 printAddress( 771 reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(pc) + disp)); 772 } 773} 774 775void DisassemblerX64::printAddress(uint8_t* addr_byte_ptr) { 776 print("%#018" PRIX64 "", reinterpret_cast<uint64_t>(addr_byte_ptr)); 777 778 // TODO(emacs): Add support for mapping from address to stub name. 779} 780 781// Returns number of bytes used, including *data. 782int DisassemblerX64::jumpShort(uint8_t* data) { 783 DCHECK(0xEB == *data, ""); 784 uint8_t b = *(data + 1); 785 int32_t disp = static_cast<int8_t>(b) + 2; 786 print("jmp "); 787 printJump(data, disp); 788 return 2; 789} 790 791// Returns number of bytes used, including *data. 792int DisassemblerX64::jumpConditional(uint8_t* data) { 793 DCHECK(0x0F == *data, ""); 794 uint8_t cond = *(data + 1) & 0x0F; 795 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(data + 2)) + 6; 796 const char* mnem = kConditionalCodeSuffix[cond]; 797 print("j%s ", mnem); 798 printJump(data, disp); 799 return 6; // includes 0x0F 800} 801 802// Returns number of bytes used, including *data. 803int DisassemblerX64::jumpConditionalShort(uint8_t* data) { 804 uint8_t cond = *data & 0x0F; 805 uint8_t b = *(data + 1); 806 int32_t disp = static_cast<int8_t>(b) + 2; 807 const char* mnem = kConditionalCodeSuffix[cond]; 808 print("j%s ", mnem); 809 printJump(data, disp); 810 return 2; 811} 812 813// Returns number of bytes used, including *data. 814int DisassemblerX64::setCC(uint8_t* data) { 815 DCHECK(0x0F == *data, ""); 816 uint8_t cond = *(data + 1) & 0x0F; 817 const char* mnem = kConditionalCodeSuffix[cond]; 818 print("set%s%s ", mnem, operandSizeCode()); 819 printRightByteOperand(data + 2); 820 return 3; // includes 0x0F 821} 822 823// Returns number of bytes used, including *data. 824int DisassemblerX64::fPUInstruction(uint8_t* data) { 825 uint8_t escape_opcode = *data; 826 DCHECK(0xD8 == (escape_opcode & 0xF8), ""); 827 uint8_t modrm_byte = *(data + 1); 828 829 if (modrm_byte >= 0xC0) { 830 return registerFPUInstruction(escape_opcode, modrm_byte); 831 } 832 return memoryFPUInstruction(escape_opcode, modrm_byte, data + 1); 833} 834 835int DisassemblerX64::memoryFPUInstruction(int escape_opcode, int modrm_byte, 836 uint8_t* modrm_start) { 837 const char* mnem = "?"; 838 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. 839 switch (escape_opcode) { 840 case 0xD9: 841 switch (regop) { 842 case 0: 843 mnem = "fld_s"; 844 break; 845 case 3: 846 mnem = "fstp_s"; 847 break; 848 case 5: 849 mnem = "fldcw"; 850 break; 851 case 7: 852 mnem = "fnstcw"; 853 break; 854 default: 855 unimplementedInstruction(); 856 } 857 break; 858 859 case 0xDB: 860 switch (regop) { 861 case 0: 862 mnem = "fild_s"; 863 break; 864 case 1: 865 mnem = "fisttp_s"; 866 break; 867 case 2: 868 mnem = "fist_s"; 869 break; 870 case 3: 871 mnem = "fistp_s"; 872 break; 873 default: 874 unimplementedInstruction(); 875 } 876 break; 877 878 case 0xDD: 879 switch (regop) { 880 case 0: 881 mnem = "fld_d"; 882 break; 883 case 3: 884 mnem = "fstp_d"; 885 break; 886 default: 887 unimplementedInstruction(); 888 } 889 break; 890 891 case 0xDF: 892 switch (regop) { 893 case 5: 894 mnem = "fild_d"; 895 break; 896 case 7: 897 mnem = "fistp_d"; 898 break; 899 default: 900 unimplementedInstruction(); 901 } 902 break; 903 904 default: 905 unimplementedInstruction(); 906 } 907 print("%s ", mnem); 908 int count = printRightOperand(modrm_start); 909 return count + 1; 910} 911 912int DisassemblerX64::registerFPUInstruction(int escape_opcode, 913 uint8_t modrm_byte) { 914 bool has_register = false; // Is the FPU register encoded in modrm_byte? 915 const char* mnem = "?"; 916 917 switch (escape_opcode) { 918 case 0xD8: 919 unimplementedInstruction(); 920 break; 921 922 case 0xD9: 923 switch (modrm_byte & 0xF8) { 924 case 0xC0: 925 mnem = "fld"; 926 has_register = true; 927 break; 928 case 0xC8: 929 mnem = "fxch"; 930 has_register = true; 931 break; 932 default: 933 switch (modrm_byte) { 934 case 0xE0: 935 mnem = "fchs"; 936 break; 937 case 0xE1: 938 mnem = "fabs"; 939 break; 940 case 0xE3: 941 mnem = "fninit"; 942 break; 943 case 0xE4: 944 mnem = "ftst"; 945 break; 946 case 0xE8: 947 mnem = "fld1"; 948 break; 949 case 0xEB: 950 mnem = "fldpi"; 951 break; 952 case 0xED: 953 mnem = "fldln2"; 954 break; 955 case 0xEE: 956 mnem = "fldz"; 957 break; 958 case 0xF0: 959 mnem = "f2xm1"; 960 break; 961 case 0xF1: 962 mnem = "fyl2x"; 963 break; 964 case 0xF2: 965 mnem = "fptan"; 966 break; 967 case 0xF5: 968 mnem = "fprem1"; 969 break; 970 case 0xF7: 971 mnem = "fincstp"; 972 break; 973 case 0xF8: 974 mnem = "fprem"; 975 break; 976 case 0xFB: 977 mnem = "fsincos"; 978 break; 979 case 0xFD: 980 mnem = "fscale"; 981 break; 982 case 0xFE: 983 mnem = "fsin"; 984 break; 985 case 0xFF: 986 mnem = "fcos"; 987 break; 988 default: 989 unimplementedInstruction(); 990 } 991 } 992 break; 993 994 case 0xDA: 995 if (modrm_byte == 0xE9) { 996 mnem = "fucompp"; 997 } else { 998 unimplementedInstruction(); 999 } 1000 break; 1001 1002 case 0xDB: 1003 if ((modrm_byte & 0xF8) == 0xE8) { 1004 mnem = "fucomi"; 1005 has_register = true; 1006 } else if (modrm_byte == 0xE2) { 1007 mnem = "fclex"; 1008 } else { 1009 unimplementedInstruction(); 1010 } 1011 break; 1012 1013 case 0xDC: 1014 has_register = true; 1015 switch (modrm_byte & 0xF8) { 1016 case 0xC0: 1017 mnem = "fadd"; 1018 break; 1019 case 0xE8: 1020 mnem = "fsub"; 1021 break; 1022 case 0xC8: 1023 mnem = "fmul"; 1024 break; 1025 case 0xF8: 1026 mnem = "fdiv"; 1027 break; 1028 default: 1029 unimplementedInstruction(); 1030 } 1031 break; 1032 1033 case 0xDD: 1034 has_register = true; 1035 switch (modrm_byte & 0xF8) { 1036 case 0xC0: 1037 mnem = "ffree"; 1038 break; 1039 case 0xD8: 1040 mnem = "fstp"; 1041 break; 1042 default: 1043 unimplementedInstruction(); 1044 } 1045 break; 1046 1047 case 0xDE: 1048 if (modrm_byte == 0xD9) { 1049 mnem = "fcompp"; 1050 } else { 1051 has_register = true; 1052 switch (modrm_byte & 0xF8) { 1053 case 0xC0: 1054 mnem = "faddp"; 1055 break; 1056 case 0xE8: 1057 mnem = "fsubp"; 1058 break; 1059 case 0xC8: 1060 mnem = "fmulp"; 1061 break; 1062 case 0xF8: 1063 mnem = "fdivp"; 1064 break; 1065 default: 1066 unimplementedInstruction(); 1067 } 1068 } 1069 break; 1070 1071 case 0xDF: 1072 if (modrm_byte == 0xE0) { 1073 mnem = "fnstsw_ax"; 1074 } else if ((modrm_byte & 0xF8) == 0xE8) { 1075 mnem = "fucomip"; 1076 has_register = true; 1077 } 1078 break; 1079 1080 default: 1081 unimplementedInstruction(); 1082 } 1083 1084 if (has_register) { 1085 print("%s st%d", mnem, modrm_byte & 0x7); 1086 } else { 1087 print("%s", mnem); 1088 } 1089 return 2; 1090} 1091 1092// TODO(srdjan): Should we add a branch hint argument? 1093bool DisassemblerX64::decodeInstructionType(uint8_t** data) { 1094 uint8_t current; 1095 1096 // Scan for prefixes. 1097 while (true) { 1098 current = **data; 1099 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. 1100 operand_size_ = current; 1101 } else if ((current & 0xF0) == 0x40) { 1102 // REX prefix. 1103 setRex(current); 1104 // TODO(srdjan): Should we enable printing of REX.W? 1105 // if (rexW()) print("REX.W "); 1106 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). 1107 group_1_prefix_ = current; 1108 } else if (current == 0xF0) { 1109 print("lock "); 1110 } else { // Not a prefix - an opcode. 1111 break; 1112 } 1113 (*data)++; 1114 } 1115 1116 const InstructionDesc& idesc = instruction_table.get(current); 1117 byte_size_operand_ = idesc.byte_size_operation; 1118 1119 switch (idesc.type) { 1120 case ZERO_OPERANDS_INSTR: 1121 if (current >= 0xA4 && current <= 0xA7) { 1122 // String move or compare operations. 1123 if (group_1_prefix_ == REP_PREFIX) { 1124 // REP. 1125 print("rep "); 1126 } 1127 if ((current & 0x01) == 0x01) { 1128 // Operation size: word, dword or qword 1129 switch (operandSize()) { 1130 case WORD_SIZE: 1131 print("%sw", idesc.mnem); 1132 break; 1133 case DOUBLEWORD_SIZE: 1134 print("%sl", idesc.mnem); 1135 break; 1136 case QUADWORD_SIZE: 1137 print("%sq", idesc.mnem); 1138 break; 1139 default: 1140 UNREACHABLE("bad operand size"); 1141 } 1142 } else { 1143 // Operation size: byte 1144 print("%s", idesc.mnem); 1145 } 1146 } else if (current == 0x99 && rexW()) { 1147 print("cqo"); // Cdql is called cdq and cdqq is called cqo. 1148 } else { 1149 print("%s", idesc.mnem); 1150 } 1151 (*data)++; 1152 break; 1153 1154 case TWO_OPERANDS_INSTR: 1155 (*data)++; 1156 (*data) += printOperands(idesc.mnem, idesc.op_order_, *data); 1157 break; 1158 1159 case JUMP_CONDITIONAL_SHORT_INSTR: 1160 (*data) += jumpConditionalShort(*data); 1161 break; 1162 1163 case REGISTER_INSTR: 1164 print("%s%s %s", idesc.mnem, operandSizeCode(), 1165 nameOfCPURegister(baseReg(current & 0x07))); 1166 (*data)++; 1167 break; 1168 case PUSHPOP_INSTR: 1169 print("%s %s", idesc.mnem, nameOfCPURegister(baseReg(current & 0x07))); 1170 (*data)++; 1171 break; 1172 case MOVE_REG_INSTR: { 1173 intptr_t addr = 0; 1174 int imm_bytes = 0; 1175 switch (operandSize()) { 1176 case WORD_SIZE: 1177 addr = LoadUnaligned(reinterpret_cast<int16_t*>(*data + 1)); 1178 imm_bytes = 2; 1179 break; 1180 case DOUBLEWORD_SIZE: 1181 addr = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1)); 1182 imm_bytes = 4; 1183 break; 1184 case QUADWORD_SIZE: 1185 addr = LoadUnaligned(reinterpret_cast<int64_t*>(*data + 1)); 1186 imm_bytes = 8; 1187 break; 1188 default: 1189 UNREACHABLE("bad operand size"); 1190 } 1191 (*data) += 1 + imm_bytes; 1192 print("mov%s %s,", operandSizeCode(), 1193 nameOfCPURegister(baseReg(current & 0x07))); 1194 printImmediateValue(addr, /*signed_value=*/false, imm_bytes); 1195 break; 1196 } 1197 1198 case CALL_JUMP_INSTR: { 1199 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1)) + 5; 1200 print("%s ", idesc.mnem); 1201 printJump(*data, disp); 1202 (*data) += 5; 1203 break; 1204 } 1205 1206 case SHORT_IMMEDIATE_INSTR: { 1207 print("%s%s %s,", idesc.mnem, operandSizeCode(), rax()); 1208 printImmediate(*data + 1, DOUBLEWORD_SIZE); 1209 (*data) += 5; 1210 break; 1211 } 1212 1213 case NO_INSTR: 1214 return false; 1215 1216 default: 1217 UNIMPLEMENTED("type not implemented"); 1218 } 1219 return true; 1220} 1221 1222int DisassemblerX64::print660F38Instruction(uint8_t* current) { 1223 int mod, regop, rm; 1224 if (*current == 0x25) { 1225 getModRM(*(current + 1), &mod, &regop, &rm); 1226 print("pmovsxdq %s,", nameOfXMMRegister(regop)); 1227 return 1 + printRightXMMOperand(current + 1); 1228 } 1229 if (*current == 0x29) { 1230 getModRM(*(current + 1), &mod, &regop, &rm); 1231 print("pcmpeqq %s,", nameOfXMMRegister(regop)); 1232 return 1 + printRightXMMOperand(current + 1); 1233 } 1234 unimplementedInstruction(); 1235 return 1; 1236} 1237 1238#pragma GCC diagnostic push 1239#pragma GCC diagnostic ignored "-Wshadow" 1240// Handle all two-byte opcodes, which start with 0x0F. 1241// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. 1242// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. 1243int DisassemblerX64::twoByteOpcodeInstruction(uint8_t* data) { 1244 uint8_t opcode = *(data + 1); 1245 uint8_t* current = data + 2; 1246 // At return, "current" points to the start of the next instruction. 1247 const char* mnemonic = twoByteMnemonic(opcode); 1248 if (operand_size_ == 0x66) { 1249 // 0x66 0x0F prefix. 1250 int mod, regop, rm; 1251 if (opcode == 0xC6) { 1252 int mod, regop, rm; 1253 getModRM(*current, &mod, &regop, &rm); 1254 print("shufpd %s, ", nameOfXMMRegister(regop)); 1255 current += printRightXMMOperand(current); 1256 print(" [%x]", *current); 1257 current++; 1258 } else if (opcode == 0x3A) { 1259 uint8_t third_byte = *current; 1260 current = data + 3; 1261 if (third_byte == 0x16) { 1262 getModRM(*current, &mod, &regop, &rm); 1263 print("pextrd "); // reg/m32, xmm, imm8 1264 current += printRightOperand(current); 1265 print(",%s,%d", nameOfXMMRegister(regop), (*current) & 7); 1266 current += 1; 1267 } else if (third_byte == 0x17) { 1268 getModRM(*current, &mod, &regop, &rm); 1269 print("extractps "); // reg/m32, xmm, imm8 1270 current += printRightOperand(current); 1271 print(", %s, %d", nameOfCPURegister(regop), (*current) & 3); 1272 current += 1; 1273 } else if (third_byte == 0x0b) { 1274 getModRM(*current, &mod, &regop, &rm); 1275 // roundsd xmm, xmm/m64, imm8 1276 print("roundsd %s, ", nameOfCPURegister(regop)); 1277 current += printRightOperand(current); 1278 print(", %d", (*current) & 3); 1279 current += 1; 1280 } else { 1281 unimplementedInstruction(); 1282 } 1283 } else { 1284 getModRM(*current, &mod, &regop, &rm); 1285 if (opcode == 0x1f) { 1286 current++; 1287 if (rm == 4) { // SIB byte present. 1288 current++; 1289 } 1290 if (mod == 1) { // Byte displacement. 1291 current += 1; 1292 } else if (mod == 2) { // 32-bit displacement. 1293 current += 4; 1294 } // else no immediate displacement. 1295 print("nop"); 1296 } else if (opcode == 0x28) { 1297 print("movapd %s, ", nameOfXMMRegister(regop)); 1298 current += printRightXMMOperand(current); 1299 } else if (opcode == 0x29) { 1300 print("movapd "); 1301 current += printRightXMMOperand(current); 1302 print(", %s", nameOfXMMRegister(regop)); 1303 } else if (opcode == 0x38) { 1304 current += print660F38Instruction(current); 1305 } else if (opcode == 0x6E) { 1306 print("mov%c %s,", rexW() ? 'q' : 'd', nameOfXMMRegister(regop)); 1307 current += printRightOperand(current); 1308 } else if (opcode == 0x6F) { 1309 print("movdqa %s,", nameOfXMMRegister(regop)); 1310 current += printRightXMMOperand(current); 1311 } else if (opcode == 0x7E) { 1312 print("mov%c ", rexW() ? 'q' : 'd'); 1313 current += printRightOperand(current); 1314 print(",%s", nameOfXMMRegister(regop)); 1315 } else if (opcode == 0x7F) { 1316 print("movdqa "); 1317 current += printRightXMMOperand(current); 1318 print(",%s", nameOfXMMRegister(regop)); 1319 } else if (opcode == 0xD6) { 1320 print("movq "); 1321 current += printRightXMMOperand(current); 1322 print(",%s", nameOfXMMRegister(regop)); 1323 } else if (opcode == 0x50) { 1324 print("movmskpd %s,", nameOfCPURegister(regop)); 1325 current += printRightXMMOperand(current); 1326 } else if (opcode == 0xD7) { 1327 print("pmovmskb %s,", nameOfCPURegister(regop)); 1328 current += printRightXMMOperand(current); 1329 } else { 1330 const char* mnemonic = "?"; 1331 if (opcode == 0x5A) { 1332 mnemonic = "cvtpd2ps"; 1333 } else if (0x51 <= opcode && opcode <= 0x5F) { 1334 mnemonic = kXmmInstructions[opcode & 0xF].pd_name; 1335 } else if (opcode == 0x14) { 1336 mnemonic = "unpcklpd"; 1337 } else if (opcode == 0x15) { 1338 mnemonic = "unpckhpd"; 1339 } else if (opcode == 0x2E) { 1340 mnemonic = "ucomisd"; 1341 } else if (opcode == 0x2F) { 1342 mnemonic = "comisd"; 1343 } else if (opcode == 0xFE) { 1344 mnemonic = "paddd"; 1345 } else if (opcode == 0xFA) { 1346 mnemonic = "psubd"; 1347 } else if (opcode == 0xEF) { 1348 mnemonic = "pxor"; 1349 } else { 1350 unimplementedInstruction(); 1351 } 1352 print("%s %s,", mnemonic, nameOfXMMRegister(regop)); 1353 current += printRightXMMOperand(current); 1354 } 1355 } 1356 } else if (group_1_prefix_ == 0xF2) { 1357 // Beginning of instructions with prefix 0xF2. 1358 1359 if (opcode == 0x11 || opcode == 0x10) { 1360 // MOVSD: Move scalar double-precision fp to/from/between XMM registers. 1361 print("movsd "); 1362 int mod, regop, rm; 1363 getModRM(*current, &mod, &regop, &rm); 1364 if (opcode == 0x11) { 1365 current += printRightXMMOperand(current); 1366 print(",%s", nameOfXMMRegister(regop)); 1367 } else { 1368 print("%s,", nameOfXMMRegister(regop)); 1369 current += printRightXMMOperand(current); 1370 } 1371 } else if (opcode == 0x2A) { 1372 // CVTSI2SD: integer to XMM double conversion. 1373 int mod, regop, rm; 1374 getModRM(*current, &mod, &regop, &rm); 1375 print("%sd %s,", mnemonic, nameOfXMMRegister(regop)); 1376 current += printRightOperand(current); 1377 } else if (opcode == 0x2C) { 1378 // CVTTSD2SI: 1379 // Convert with truncation scalar double-precision FP to integer. 1380 int mod, regop, rm; 1381 getModRM(*current, &mod, &regop, &rm); 1382 print("cvttsd2si%s %s,", operandSizeCode(), nameOfCPURegister(regop)); 1383 current += printRightXMMOperand(current); 1384 } else if (opcode == 0x2D) { 1385 // CVTSD2SI: Convert scalar double-precision FP to integer. 1386 int mod, regop, rm; 1387 getModRM(*current, &mod, &regop, &rm); 1388 print("cvtsd2si%s %s,", operandSizeCode(), nameOfCPURegister(regop)); 1389 current += printRightXMMOperand(current); 1390 } else if (0x51 <= opcode && opcode <= 0x5F) { 1391 // XMM arithmetic. get the F2 0F prefix version of the mnemonic. 1392 int mod, regop, rm; 1393 getModRM(*current, &mod, &regop, &rm); 1394 const char* mnemonic = 1395 opcode == 0x5A ? "cvtsd2ss" : kXmmInstructions[opcode & 0xF].sd_name; 1396 print("%s %s,", mnemonic, nameOfXMMRegister(regop)); 1397 current += printRightXMMOperand(current); 1398 } else { 1399 unimplementedInstruction(); 1400 } 1401 } else if (group_1_prefix_ == 0xF3) { 1402 // Instructions with prefix 0xF3. 1403 if (opcode == 0x11 || opcode == 0x10) { 1404 // MOVSS: Move scalar double-precision fp to/from/between XMM registers. 1405 print("movss "); 1406 int mod, regop, rm; 1407 getModRM(*current, &mod, &regop, &rm); 1408 if (opcode == 0x11) { 1409 current += printRightOperand(current); 1410 print(",%s", nameOfXMMRegister(regop)); 1411 } else { 1412 print("%s,", nameOfXMMRegister(regop)); 1413 current += printRightOperand(current); 1414 } 1415 } else if (opcode == 0x2A) { 1416 // CVTSI2SS: integer to XMM single conversion. 1417 int mod, regop, rm; 1418 getModRM(*current, &mod, &regop, &rm); 1419 print("%ss %s,", mnemonic, nameOfXMMRegister(regop)); 1420 current += printRightOperand(current); 1421 } else if (opcode == 0x2C || opcode == 0x2D) { 1422 bool truncating = (opcode & 1) == 0; 1423 // CVTTSS2SI/CVTSS2SI: 1424 // Convert (with truncation) scalar single-precision FP to dword integer. 1425 int mod, regop, rm; 1426 getModRM(*current, &mod, &regop, &rm); 1427 print("cvt%sss2si%s %s,", truncating ? "t" : "", operandSizeCode(), 1428 nameOfCPURegister(regop)); 1429 current += printRightXMMOperand(current); 1430 } else if (0x51 <= opcode && opcode <= 0x5F) { 1431 int mod, regop, rm; 1432 getModRM(*current, &mod, &regop, &rm); 1433 const char* mnemonic = 1434 opcode == 0x5A ? "cvtss2sd" : kXmmInstructions[opcode & 0xF].ss_name; 1435 print("%s %s,", mnemonic, nameOfXMMRegister(regop)); 1436 current += printRightXMMOperand(current); 1437 } else if (opcode == 0x7E) { 1438 int mod, regop, rm; 1439 getModRM(*current, &mod, &regop, &rm); 1440 print("movq %s, ", nameOfXMMRegister(regop)); 1441 current += printRightXMMOperand(current); 1442 } else if (opcode == 0xE6) { 1443 int mod, regop, rm; 1444 getModRM(*current, &mod, &regop, &rm); 1445 print("cvtdq2pd %s,", nameOfXMMRegister(regop)); 1446 current += printRightXMMOperand(current); 1447 } else if (opcode == 0xB8) { 1448 // POPCNT. 1449 current += printOperands(mnemonic, REG_OPER_OP_ORDER, current); 1450 } else if (opcode == 0xBD) { 1451 // LZCNT (rep BSR encoding). 1452 current += printOperands("lzcnt", REG_OPER_OP_ORDER, current); 1453 } else { 1454 unimplementedInstruction(); 1455 } 1456 } else if (opcode == 0x1F) { 1457 // NOP 1458 int mod, regop, rm; 1459 getModRM(*current, &mod, &regop, &rm); 1460 current++; 1461 if (rm == 4) { // SIB byte present. 1462 current++; 1463 } 1464 if (mod == 1) { // Byte displacement. 1465 current += 1; 1466 } else if (mod == 2) { // 32-bit displacement. 1467 current += 4; 1468 } // else no immediate displacement. 1469 print("nop"); 1470 1471 } else if (opcode == 0x28 || opcode == 0x2f) { 1472 // ...s xmm, xmm/m128 1473 int mod, regop, rm; 1474 getModRM(*current, &mod, &regop, &rm); 1475 const char* mnemonic = opcode == 0x28 ? "movaps" : "comiss"; 1476 print("%s %s,", mnemonic, nameOfXMMRegister(regop)); 1477 current += printRightXMMOperand(current); 1478 } else if (opcode == 0x29) { 1479 // movaps xmm/m128, xmm 1480 int mod, regop, rm; 1481 getModRM(*current, &mod, &regop, &rm); 1482 print("movaps "); 1483 current += printRightXMMOperand(current); 1484 print(",%s", nameOfXMMRegister(regop)); 1485 } else if (opcode == 0x11) { 1486 // movups xmm/m128, xmm 1487 int mod, regop, rm; 1488 getModRM(*current, &mod, &regop, &rm); 1489 print("movups "); 1490 current += printRightXMMOperand(current); 1491 print(",%s", nameOfXMMRegister(regop)); 1492 } else if (opcode == 0x50) { 1493 int mod, regop, rm; 1494 getModRM(*current, &mod, &regop, &rm); 1495 print("movmskps %s,", nameOfCPURegister(regop)); 1496 current += printRightXMMOperand(current); 1497 } else if (opcode == 0xA2 || opcode == 0x31) { 1498 // RDTSC or CPUID 1499 print("%s", mnemonic); 1500 } else if ((opcode & 0xF0) == 0x40) { 1501 // CMOVcc: conditional move. 1502 int condition = opcode & 0x0F; 1503 const InstructionDesc& idesc = cmov_instructions[condition]; 1504 byte_size_operand_ = idesc.byte_size_operation; 1505 current += printOperands(idesc.mnem, idesc.op_order_, current); 1506 } else if (0x10 <= opcode && opcode <= 0x16) { 1507 // ...ps xmm, xmm/m128 1508 static const char* mnemonics[] = {"movups", nullptr, "movhlps", 1509 nullptr, "unpcklps", "unpckhps", 1510 "movlhps"}; 1511 const char* mnemonic = mnemonics[opcode - 0x10]; 1512 if (mnemonic == nullptr) { 1513 unimplementedInstruction(); 1514 mnemonic = "???"; 1515 } 1516 int mod, regop, rm; 1517 getModRM(*current, &mod, &regop, &rm); 1518 print("%s %s,", mnemonic, nameOfXMMRegister(regop)); 1519 current += printRightXMMOperand(current); 1520 } else if (0x51 <= opcode && opcode <= 0x5F) { 1521 int mod, regop, rm; 1522 getModRM(*current, &mod, &regop, &rm); 1523 const char* mnemonic = 1524 opcode == 0x5A ? "cvtps2pd" : kXmmInstructions[opcode & 0xF].ps_name; 1525 print("%s %s,", mnemonic, nameOfXMMRegister(regop)); 1526 current += printRightXMMOperand(current); 1527 } else if (opcode == 0xC2 || opcode == 0xC6) { 1528 int mod, regop, rm; 1529 getModRM(*current, &mod, &regop, &rm); 1530 if (opcode == 0xC2) { 1531 print("cmpps %s,", nameOfXMMRegister(regop)); 1532 current += printRightXMMOperand(current); 1533 print(" [%s]", kXmmConditionalCodeSuffix[*current]); 1534 } else { 1535 DCHECK(opcode == 0xC6, ""); 1536 print("shufps %s,", nameOfXMMRegister(regop)); 1537 current += printRightXMMOperand(current); 1538 print(" [%x]", *current); 1539 } 1540 current++; 1541 } else if ((opcode & 0xF0) == 0x80) { 1542 // Jcc: Conditional jump (branch). 1543 current = data + jumpConditional(data); 1544 1545 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 || 1546 opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 || 1547 opcode == 0xB1 || opcode == 0xBC || opcode == 0xBD) { 1548 // Size-extending moves, IMUL, cmpxchg, BSF, BSR. 1549 current += printOperands(mnemonic, REG_OPER_OP_ORDER, current); 1550 } else if ((opcode & 0xF0) == 0x90) { 1551 // SETcc: Set byte on condition. Needs pointer to beginning of instruction. 1552 current = data + setCC(data); 1553 } else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) || 1554 (opcode == 0xAB) || (opcode == 0xA3)) { 1555 // SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test). 1556 print("%s%s ", mnemonic, operandSizeCode()); 1557 int mod, regop, rm; 1558 getModRM(*current, &mod, &regop, &rm); 1559 current += printRightOperand(current); 1560 print(",%s", nameOfCPURegister(regop)); 1561 if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) { 1562 // Done. 1563 } else if ((opcode == 0xA5) || (opcode == 0xAD)) { 1564 print(",cl"); 1565 } else { 1566 print(","); 1567 current += printImmediate(current, BYTE_SIZE); 1568 } 1569 } else if (opcode == 0xBA && (*current & 0x60) == 0x60) { 1570 // bt? immediate instruction 1571 int r = (*current >> 3) & 7; 1572 static const char* const names[4] = {"bt", "bts", "btr", "btc"}; 1573 print("%s ", names[r - 4]); 1574 current += printRightOperand(current); 1575 uint8_t bit = *current++; 1576 print(",%d", bit); 1577 } else if (opcode == 0x0B) { 1578 print("ud2"); 1579 } else { 1580 unimplementedInstruction(); 1581 } 1582 return static_cast<int>(current - data); 1583} 1584#pragma GCC diagnostic pop 1585 1586// Mnemonics for two-byte opcode instructions starting with 0x0F. 1587// The argument is the second byte of the two-byte opcode. 1588// Returns nullptr if the instruction is not handled here. 1589const char* DisassemblerX64::twoByteMnemonic(uint8_t opcode) { 1590 if (opcode == 0x5A) { 1591 return "cvtps2pd"; 1592 } 1593 if (0x51 <= opcode && opcode <= 0x5F) { 1594 return kXmmInstructions[opcode & 0xF].ps_name; 1595 } 1596 if (0xA2 <= opcode && opcode <= 0xBF) { 1597 static const char* mnemonics[] = { 1598 "cpuid", "bt", "shld", "shld", nullptr, nullptr, 1599 nullptr, nullptr, nullptr, "bts", "shrd", "shrd", 1600 nullptr, "imul", "cmpxchg", "cmpxchg", nullptr, nullptr, 1601 nullptr, nullptr, "movzxb", "movzxw", "popcnt", nullptr, 1602 nullptr, nullptr, "bsf", "bsr", "movsxb", "movsxw"}; 1603 return mnemonics[opcode - 0xA2]; 1604 } 1605 switch (opcode) { 1606 case 0x12: 1607 return "movhlps"; 1608 case 0x16: 1609 return "movlhps"; 1610 case 0x1F: 1611 return "nop"; 1612 case 0x2A: // F2/F3 prefix. 1613 return "cvtsi2s"; 1614 case 0x31: 1615 return "rdtsc"; 1616 default: 1617 return nullptr; 1618 } 1619} 1620 1621int DisassemblerX64::instructionDecode(uword pc) { 1622 uint8_t* data = reinterpret_cast<uint8_t*>(pc); 1623 1624 const bool processed = decodeInstructionType(&data); 1625 1626 if (!processed) { 1627 switch (*data) { 1628 case 0xC2: 1629 print("ret "); 1630 printImmediateValue(*reinterpret_cast<uint16_t*>(data + 1)); 1631 data += 3; 1632 break; 1633 1634 case 0xC8: 1635 print("enter %d, %d", *reinterpret_cast<uint16_t*>(data + 1), data[3]); 1636 data += 4; 1637 break; 1638 1639 case 0x69: 1640 FALLTHROUGH; 1641 case 0x6B: { 1642 int mod, regop, rm; 1643 getModRM(*(data + 1), &mod, &regop, &rm); 1644 int32_t imm = *data == 0x6B 1645 ? *(data + 2) 1646 : LoadUnaligned(reinterpret_cast<int32_t*>(data + 2)); 1647 print("imul%s %s,%s,", operandSizeCode(), nameOfCPURegister(regop), 1648 nameOfCPURegister(rm)); 1649 printImmediateValue(imm); 1650 data += 2 + (*data == 0x6B ? 1 : 4); 1651 break; 1652 } 1653 1654 case 0x81: 1655 FALLTHROUGH; 1656 case 0x83: // 0x81 with sign extension bit set 1657 data += printImmediateOp(data); 1658 break; 1659 1660 case 0x0F: 1661 data += twoByteOpcodeInstruction(data); 1662 break; 1663 1664 case 0x8F: { 1665 data++; 1666 int mod, regop, rm; 1667 getModRM(*data, &mod, &regop, &rm); 1668 if (regop == 0) { 1669 print("pop "); 1670 data += printRightOperand(data); 1671 } 1672 } break; 1673 1674 case 0xFF: { 1675 data++; 1676 int mod, regop, rm; 1677 getModRM(*data, &mod, &regop, &rm); 1678 const char* mnem = nullptr; 1679 switch (regop) { 1680 case 0: 1681 mnem = "inc"; 1682 break; 1683 case 1: 1684 mnem = "dec"; 1685 break; 1686 case 2: 1687 mnem = "call"; 1688 break; 1689 case 4: 1690 mnem = "jmp"; 1691 break; 1692 case 6: 1693 mnem = "push"; 1694 break; 1695 default: 1696 mnem = "???"; 1697 } 1698 if (regop <= 1) { 1699 print("%s%s ", mnem, operandSizeCode()); 1700 } else { 1701 print("%s ", mnem); 1702 } 1703 data += printRightOperand(data); 1704 } break; 1705 1706 case 0xC7: // imm32, fall through 1707 case 0xC6: // imm8 1708 { 1709 bool is_byte = *data == 0xC6; 1710 data++; 1711 if (is_byte) { 1712 print("movb "); 1713 data += printRightByteOperand(data); 1714 print(","); 1715 data += printImmediate(data, BYTE_SIZE); 1716 } else { 1717 print("mov%s ", operandSizeCode()); 1718 data += printRightOperand(data); 1719 print(","); 1720 data += printImmediate(data, operandSize(), /* sign extend = */ true); 1721 } 1722 } break; 1723 1724 case 0x80: { 1725 byte_size_operand_ = true; 1726 data += printImmediateOp(data); 1727 } break; 1728 1729 case 0x88: // 8bit, fall through 1730 case 0x89: // 32bit 1731 { 1732 bool is_byte = *data == 0x88; 1733 int mod, regop, rm; 1734 data++; 1735 getModRM(*data, &mod, &regop, &rm); 1736 if (is_byte) { 1737 print("movb "); 1738 data += printRightByteOperand(data); 1739 print(",%s", nameOfByteCPURegister(regop)); 1740 } else { 1741 print("mov%s ", operandSizeCode()); 1742 data += printRightOperand(data); 1743 print(",%s", nameOfCPURegister(regop)); 1744 } 1745 } break; 1746 1747 case 0x90: 1748 case 0x91: 1749 case 0x92: 1750 case 0x93: 1751 case 0x94: 1752 case 0x95: 1753 case 0x96: 1754 case 0x97: { 1755 int reg = (*data & 0x7) | (rexB() ? 8 : 0); 1756 if (reg == 0) { 1757 print("nop"); // Common name for xchg rax,rax. 1758 } else { 1759 print("xchg%s %s, %s", operandSizeCode(), rax(), 1760 nameOfCPURegister(reg)); 1761 } 1762 data++; 1763 } break; 1764 case 0xB0: 1765 case 0xB1: 1766 case 0xB2: 1767 case 0xB3: 1768 case 0xB4: 1769 case 0xB5: 1770 case 0xB6: 1771 case 0xB7: 1772 case 0xB8: 1773 case 0xB9: 1774 case 0xBA: 1775 case 0xBB: 1776 case 0xBC: 1777 case 0xBD: 1778 case 0xBE: 1779 case 0xBF: { 1780 // mov reg8,imm8 or mov reg32,imm32 1781 uint8_t opcode = *data; 1782 data++; 1783 const bool is_not_8bit = opcode >= 0xB8; 1784 int reg = (opcode & 0x7) | (rexB() ? 8 : 0); 1785 if (is_not_8bit) { 1786 print("mov%s %s,", operandSizeCode(), nameOfCPURegister(reg)); 1787 data += 1788 printImmediate(data, operandSize(), /* sign extend = */ false); 1789 } else { 1790 print("movb %s,", nameOfByteCPURegister(reg)); 1791 data += printImmediate(data, BYTE_SIZE, /* sign extend = */ false); 1792 } 1793 break; 1794 } 1795 case 0xFE: { 1796 data++; 1797 int mod, regop, rm; 1798 getModRM(*data, &mod, &regop, &rm); 1799 if (regop == 1) { 1800 print("decb "); 1801 data += printRightByteOperand(data); 1802 } else { 1803 unimplementedInstruction(); 1804 } 1805 break; 1806 } 1807 case 0x68: 1808 print("push "); 1809 printImmediateValue( 1810 LoadUnaligned(reinterpret_cast<int32_t*>(data + 1))); 1811 data += 5; 1812 break; 1813 1814 case 0x6A: 1815 print("push "); 1816 printImmediateValue(*reinterpret_cast<int8_t*>(data + 1)); 1817 data += 2; 1818 break; 1819 1820 case 0xA1: 1821 FALLTHROUGH; 1822 case 0xA3: 1823 switch (operandSize()) { 1824 case DOUBLEWORD_SIZE: { 1825 printAddress(reinterpret_cast<uint8_t*>( 1826 *reinterpret_cast<int32_t*>(data + 1))); 1827 if (*data == 0xA1) { // Opcode 0xA1 1828 print("movzxlq %s,(", rax()); 1829 printAddress(reinterpret_cast<uint8_t*>( 1830 *reinterpret_cast<int32_t*>(data + 1))); 1831 print(")"); 1832 } else { // Opcode 0xA3 1833 print("movzxlq ("); 1834 printAddress(reinterpret_cast<uint8_t*>( 1835 *reinterpret_cast<int32_t*>(data + 1))); 1836 print("),%s", rax()); 1837 } 1838 data += 5; 1839 break; 1840 } 1841 case QUADWORD_SIZE: { 1842 // New x64 instruction mov rax,(imm_64). 1843 if (*data == 0xA1) { // Opcode 0xA1 1844 print("movq %s,(", rax()); 1845 printAddress(*reinterpret_cast<uint8_t**>(data + 1)); 1846 print(")"); 1847 } else { // Opcode 0xA3 1848 print("movq ("); 1849 printAddress(*reinterpret_cast<uint8_t**>(data + 1)); 1850 print("),%s", rax()); 1851 } 1852 data += 9; 1853 break; 1854 } 1855 default: 1856 unimplementedInstruction(); 1857 data += 2; 1858 } 1859 break; 1860 1861 case 0xA8: 1862 print("test al,"); 1863 printImmediateValue(*reinterpret_cast<uint8_t*>(data + 1)); 1864 data += 2; 1865 break; 1866 1867 case 0xA9: { 1868 data++; 1869 print("test%s %s,", operandSizeCode(), rax()); 1870 data += printImmediate(data, operandSize()); 1871 break; 1872 } 1873 case 0xD1: 1874 FALLTHROUGH; 1875 case 0xD3: 1876 FALLTHROUGH; 1877 case 0xC1: 1878 data += shiftInstruction(data); 1879 break; 1880 case 0xD0: 1881 FALLTHROUGH; 1882 case 0xD2: 1883 FALLTHROUGH; 1884 case 0xC0: 1885 byte_size_operand_ = true; 1886 data += shiftInstruction(data); 1887 break; 1888 1889 case 0xD9: 1890 FALLTHROUGH; 1891 case 0xDA: 1892 FALLTHROUGH; 1893 case 0xDB: 1894 FALLTHROUGH; 1895 case 0xDC: 1896 FALLTHROUGH; 1897 case 0xDD: 1898 FALLTHROUGH; 1899 case 0xDE: 1900 FALLTHROUGH; 1901 case 0xDF: 1902 data += fPUInstruction(data); 1903 break; 1904 1905 case 0xEB: 1906 data += jumpShort(data); 1907 break; 1908 1909 case 0xF6: 1910 byte_size_operand_ = true; 1911 FALLTHROUGH; 1912 case 0xF7: 1913 data += f6F7Instruction(data); 1914 break; 1915 1916 case 0x0c: 1917 case 0x3c: 1918 data += printImmediateOp(data); 1919 break; 1920 1921 // These encodings for inc and dec are IA32 only, but we don't get here 1922 // on X64 - the REX prefix recoginizer catches them earlier. 1923 case 0x40: 1924 case 0x41: 1925 case 0x42: 1926 case 0x43: 1927 case 0x44: 1928 case 0x45: 1929 case 0x46: 1930 case 0x47: 1931 print("inc %s", nameOfCPURegister(*data & 7)); 1932 data += 1; 1933 break; 1934 1935 case 0x48: 1936 case 0x49: 1937 case 0x4a: 1938 case 0x4b: 1939 case 0x4c: 1940 case 0x4d: 1941 case 0x4e: 1942 case 0x4f: 1943 print("dec %s", nameOfCPURegister(*data & 7)); 1944 data += 1; 1945 break; 1946 1947 default: 1948 unimplementedInstruction(); 1949 data += 1; 1950 } 1951 } // !processed 1952 1953 DCHECK(buffer_[buffer_pos_] == '\0', ""); 1954 1955 int instr_len = data - reinterpret_cast<uint8_t*>(pc); 1956 DCHECK(instr_len > 0, ""); // Ensure progress. 1957 1958 return instr_len; 1959} 1960 1961} // namespace x64 1962 1963void Disassembler::decodeInstruction(char* hex_buffer, intptr_t hex_size, 1964 char* human_buffer, intptr_t human_size, 1965 int* out_instr_len, uword pc) { 1966 DCHECK(hex_size > 0, ""); 1967 DCHECK(human_size > 0, ""); 1968 x64::DisassemblerX64 decoder(human_buffer, human_size); 1969 int instruction_length = decoder.instructionDecode(pc); 1970 uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc); 1971 int hex_index = 0; 1972 int remaining_size = hex_size - hex_index; 1973 for (int i = 0; (i < instruction_length) && (remaining_size > 2); ++i) { 1974 std::snprintf(&hex_buffer[hex_index], remaining_size, "%02x", pc_ptr[i]); 1975 hex_index += 2; 1976 remaining_size -= 2; 1977 } 1978 hex_buffer[hex_index] = '\0'; 1979 if (out_instr_len != nullptr) { 1980 *out_instr_len = instruction_length; 1981 } 1982} 1983 1984} // namespace py