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