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#if V8_TARGET_ARCH_IA32 10 11#include "src/base/compiler-specific.h" 12#include "src/disasm.h" 13 14namespace disasm { 15 16enum OperandOrder { 17 UNSET_OP_ORDER = 0, 18 REG_OPER_OP_ORDER, 19 OPER_REG_OP_ORDER 20}; 21 22 23//------------------------------------------------------------------ 24// Tables 25//------------------------------------------------------------------ 26struct ByteMnemonic { 27 int b; // -1 terminates, otherwise must be in range (0..255) 28 const char* mnem; 29 OperandOrder op_order_; 30}; 31 32static const ByteMnemonic two_operands_instr[] = { 33 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER}, 34 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER}, 35 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER}, 36 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER}, 37 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER}, 38 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER}, 39 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER}, 40 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER}, 41 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER}, 42 {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER}, 43 {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER}, 44 {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER}, 45 {-1, "", UNSET_OP_ORDER}}; 46 47static const ByteMnemonic zero_operands_instr[] = { 48 {0xC3, "ret", UNSET_OP_ORDER}, 49 {0xC9, "leave", UNSET_OP_ORDER}, 50 {0x90, "nop", UNSET_OP_ORDER}, 51 {0xF4, "hlt", UNSET_OP_ORDER}, 52 {0xCC, "int3", UNSET_OP_ORDER}, 53 {0x60, "pushad", UNSET_OP_ORDER}, 54 {0x61, "popad", UNSET_OP_ORDER}, 55 {0x9C, "pushfd", UNSET_OP_ORDER}, 56 {0x9D, "popfd", UNSET_OP_ORDER}, 57 {0x9E, "sahf", UNSET_OP_ORDER}, 58 {0x99, "cdq", UNSET_OP_ORDER}, 59 {0x9B, "fwait", UNSET_OP_ORDER}, 60 {0xFC, "cld", UNSET_OP_ORDER}, 61 {0xAB, "stos", UNSET_OP_ORDER}, 62 {-1, "", UNSET_OP_ORDER} 63}; 64 65 66static const ByteMnemonic call_jump_instr[] = { 67 {0xE8, "call", UNSET_OP_ORDER}, 68 {0xE9, "jmp", UNSET_OP_ORDER}, 69 {-1, "", UNSET_OP_ORDER} 70}; 71 72 73static const ByteMnemonic short_immediate_instr[] = { 74 {0x05, "add", UNSET_OP_ORDER}, 75 {0x0D, "or", UNSET_OP_ORDER}, 76 {0x15, "adc", UNSET_OP_ORDER}, 77 {0x25, "and", UNSET_OP_ORDER}, 78 {0x2D, "sub", UNSET_OP_ORDER}, 79 {0x35, "xor", UNSET_OP_ORDER}, 80 {0x3D, "cmp", UNSET_OP_ORDER}, 81 {-1, "", UNSET_OP_ORDER} 82}; 83 84 85// Generally we don't want to generate these because they are subject to partial 86// register stalls. They are included for completeness and because the cmp 87// variant is used by the RecordWrite stub. Because it does not update the 88// register it is not subject to partial register stalls. 89static ByteMnemonic byte_immediate_instr[] = { 90 {0x0c, "or", UNSET_OP_ORDER}, 91 {0x24, "and", UNSET_OP_ORDER}, 92 {0x34, "xor", UNSET_OP_ORDER}, 93 {0x3c, "cmp", UNSET_OP_ORDER}, 94 {-1, "", UNSET_OP_ORDER} 95}; 96 97 98static const char* const jump_conditional_mnem[] = { 99 /*0*/ "jo", "jno", "jc", "jnc", 100 /*4*/ "jz", "jnz", "jna", "ja", 101 /*8*/ "js", "jns", "jpe", "jpo", 102 /*12*/ "jl", "jnl", "jng", "jg" 103}; 104 105 106static const char* const set_conditional_mnem[] = { 107 /*0*/ "seto", "setno", "setc", "setnc", 108 /*4*/ "setz", "setnz", "setna", "seta", 109 /*8*/ "sets", "setns", "setpe", "setpo", 110 /*12*/ "setl", "setnl", "setng", "setg" 111}; 112 113 114static const char* const conditional_move_mnem[] = { 115 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc", 116 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova", 117 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo", 118 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg" 119}; 120 121 122enum InstructionType { 123 NO_INSTR, 124 ZERO_OPERANDS_INSTR, 125 TWO_OPERANDS_INSTR, 126 JUMP_CONDITIONAL_SHORT_INSTR, 127 REGISTER_INSTR, 128 MOVE_REG_INSTR, 129 CALL_JUMP_INSTR, 130 SHORT_IMMEDIATE_INSTR, 131 BYTE_IMMEDIATE_INSTR 132}; 133 134 135struct InstructionDesc { 136 const char* mnem; 137 InstructionType type; 138 OperandOrder op_order_; 139}; 140 141 142class InstructionTable { 143 public: 144 InstructionTable(); 145 const InstructionDesc& Get(byte x) const { return instructions_[x]; } 146 static InstructionTable* get_instance() { 147 static InstructionTable table; 148 return &table; 149 } 150 151 private: 152 InstructionDesc instructions_[256]; 153 void Clear(); 154 void Init(); 155 void CopyTable(const ByteMnemonic bm[], InstructionType type); 156 void SetTableRange(InstructionType type, 157 byte start, 158 byte end, 159 const char* mnem); 160 void AddJumpConditionalShort(); 161}; 162 163 164InstructionTable::InstructionTable() { 165 Clear(); 166 Init(); 167} 168 169 170void InstructionTable::Clear() { 171 for (int i = 0; i < 256; i++) { 172 instructions_[i].mnem = ""; 173 instructions_[i].type = NO_INSTR; 174 instructions_[i].op_order_ = UNSET_OP_ORDER; 175 } 176} 177 178 179void InstructionTable::Init() { 180 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); 181 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); 182 CopyTable(call_jump_instr, CALL_JUMP_INSTR); 183 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); 184 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR); 185 AddJumpConditionalShort(); 186 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc"); 187 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec"); 188 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push"); 189 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop"); 190 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. 191 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); 192} 193 194 195void InstructionTable::CopyTable(const ByteMnemonic bm[], 196 InstructionType type) { 197 for (int i = 0; bm[i].b >= 0; i++) { 198 InstructionDesc* id = &instructions_[bm[i].b]; 199 id->mnem = bm[i].mnem; 200 id->op_order_ = bm[i].op_order_; 201 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 202 id->type = type; 203 } 204} 205 206 207void InstructionTable::SetTableRange(InstructionType type, 208 byte start, 209 byte end, 210 const char* mnem) { 211 for (byte b = start; b <= end; b++) { 212 InstructionDesc* id = &instructions_[b]; 213 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 214 id->mnem = mnem; 215 id->type = type; 216 } 217} 218 219 220void InstructionTable::AddJumpConditionalShort() { 221 for (byte b = 0x70; b <= 0x7F; b++) { 222 InstructionDesc* id = &instructions_[b]; 223 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 224 id->mnem = jump_conditional_mnem[b & 0x0F]; 225 id->type = JUMP_CONDITIONAL_SHORT_INSTR; 226 } 227} 228 229 230// The IA32 disassembler implementation. 231class DisassemblerIA32 { 232 public: 233 DisassemblerIA32(const NameConverter& converter, 234 bool abort_on_unimplemented = true) 235 : converter_(converter), 236 vex_byte0_(0), 237 vex_byte1_(0), 238 vex_byte2_(0), 239 instruction_table_(InstructionTable::get_instance()), 240 tmp_buffer_pos_(0), 241 abort_on_unimplemented_(abort_on_unimplemented) { 242 tmp_buffer_[0] = '\0'; 243 } 244 245 virtual ~DisassemblerIA32() {} 246 247 // Writes one disassembled instruction into 'buffer' (0-terminated). 248 // Returns the length of the disassembled machine instruction in bytes. 249 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); 250 251 private: 252 const NameConverter& converter_; 253 byte vex_byte0_; // 0xc4 or 0xc5 254 byte vex_byte1_; 255 byte vex_byte2_; // only for 3 bytes vex prefix 256 InstructionTable* instruction_table_; 257 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; 258 unsigned int tmp_buffer_pos_; 259 bool abort_on_unimplemented_; 260 261 enum { 262 eax = 0, 263 ecx = 1, 264 edx = 2, 265 ebx = 3, 266 esp = 4, 267 ebp = 5, 268 esi = 6, 269 edi = 7 270 }; 271 272 273 enum ShiftOpcodeExtension { 274 kROL = 0, 275 kROR = 1, 276 kRCL = 2, 277 kRCR = 3, 278 kSHL = 4, 279 KSHR = 5, 280 kSAR = 7 281 }; 282 283 bool vex_128() { 284 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 285 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 286 return (checked & 4) == 0; 287 } 288 289 bool vex_none() { 290 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 291 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 292 return (checked & 3) == 0; 293 } 294 295 bool vex_66() { 296 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 297 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 298 return (checked & 3) == 1; 299 } 300 301 bool vex_f3() { 302 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 303 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 304 return (checked & 3) == 2; 305 } 306 307 bool vex_f2() { 308 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 309 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 310 return (checked & 3) == 3; 311 } 312 313 bool vex_w() { 314 if (vex_byte0_ == 0xc5) return false; 315 return (vex_byte2_ & 0x80) != 0; 316 } 317 318 bool vex_0f() { 319 if (vex_byte0_ == 0xc5) return true; 320 return (vex_byte1_ & 3) == 1; 321 } 322 323 bool vex_0f38() { 324 if (vex_byte0_ == 0xc5) return false; 325 return (vex_byte1_ & 3) == 2; 326 } 327 328 bool vex_0f3a() { 329 if (vex_byte0_ == 0xc5) return false; 330 return (vex_byte1_ & 3) == 3; 331 } 332 333 int vex_vreg() { 334 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 335 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 336 return ~(checked >> 3) & 0xf; 337 } 338 339 char float_size_code() { return "sd"[vex_w()]; } 340 341 const char* NameOfCPURegister(int reg) const { 342 return converter_.NameOfCPURegister(reg); 343 } 344 345 346 const char* NameOfByteCPURegister(int reg) const { 347 return converter_.NameOfByteCPURegister(reg); 348 } 349 350 351 const char* NameOfXMMRegister(int reg) const { 352 return converter_.NameOfXMMRegister(reg); 353 } 354 355 356 const char* NameOfAddress(byte* addr) const { 357 return converter_.NameOfAddress(addr); 358 } 359 360 361 // Disassembler helper functions. 362 static void get_modrm(byte data, int* mod, int* regop, int* rm) { 363 *mod = (data >> 6) & 3; 364 *regop = (data & 0x38) >> 3; 365 *rm = data & 7; 366 } 367 368 369 static void get_sib(byte data, int* scale, int* index, int* base) { 370 *scale = (data >> 6) & 3; 371 *index = (data >> 3) & 7; 372 *base = data & 7; 373 } 374 375 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const; 376 377 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); 378 int PrintRightOperand(byte* modrmp); 379 int PrintRightByteOperand(byte* modrmp); 380 int PrintRightXMMOperand(byte* modrmp); 381 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); 382 int PrintImmediateOp(byte* data); 383 int F7Instruction(byte* data); 384 int D1D3C1Instruction(byte* data); 385 int JumpShort(byte* data); 386 int JumpConditional(byte* data, const char* comment); 387 int JumpConditionalShort(byte* data, const char* comment); 388 int SetCC(byte* data); 389 int CMov(byte* data); 390 int FPUInstruction(byte* data); 391 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); 392 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); 393 int AVXInstruction(byte* data); 394 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...); 395 396 void UnimplementedInstruction() { 397 if (abort_on_unimplemented_) { 398 UNIMPLEMENTED(); 399 } else { 400 AppendToBuffer("'Unimplemented Instruction'"); 401 } 402 } 403}; 404 405 406void DisassemblerIA32::AppendToBuffer(const char* format, ...) { 407 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; 408 va_list args; 409 va_start(args, format); 410 int result = v8::internal::VSNPrintF(buf, format, args); 411 va_end(args); 412 tmp_buffer_pos_ += result; 413} 414 415int DisassemblerIA32::PrintRightOperandHelper( 416 byte* modrmp, 417 RegisterNameMapping direct_register_name) { 418 int mod, regop, rm; 419 get_modrm(*modrmp, &mod, ®op, &rm); 420 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : 421 &DisassemblerIA32::NameOfCPURegister; 422 switch (mod) { 423 case 0: 424 if (rm == ebp) { 425 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); 426 AppendToBuffer("[0x%x]", disp); 427 return 5; 428 } else if (rm == esp) { 429 byte sib = *(modrmp + 1); 430 int scale, index, base; 431 get_sib(sib, &scale, &index, &base); 432 if (index == esp && base == esp && scale == 0 /*times_1*/) { 433 AppendToBuffer("[%s]", (this->*register_name)(rm)); 434 return 2; 435 } else if (base == ebp) { 436 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); 437 AppendToBuffer("[%s*%d%s0x%x]", 438 (this->*register_name)(index), 439 1 << scale, 440 disp < 0 ? "-" : "+", 441 disp < 0 ? -disp : disp); 442 return 6; 443 } else if (index != esp && base != ebp) { 444 // [base+index*scale] 445 AppendToBuffer("[%s+%s*%d]", 446 (this->*register_name)(base), 447 (this->*register_name)(index), 448 1 << scale); 449 return 2; 450 } else { 451 UnimplementedInstruction(); 452 return 1; 453 } 454 } else { 455 AppendToBuffer("[%s]", (this->*register_name)(rm)); 456 return 1; 457 } 458 break; 459 case 1: // fall through 460 case 2: 461 if (rm == esp) { 462 byte sib = *(modrmp + 1); 463 int scale, index, base; 464 get_sib(sib, &scale, &index, &base); 465 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) 466 : *reinterpret_cast<int8_t*>(modrmp + 2); 467 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { 468 AppendToBuffer("[%s%s0x%x]", 469 (this->*register_name)(rm), 470 disp < 0 ? "-" : "+", 471 disp < 0 ? -disp : disp); 472 } else { 473 AppendToBuffer("[%s+%s*%d%s0x%x]", 474 (this->*register_name)(base), 475 (this->*register_name)(index), 476 1 << scale, 477 disp < 0 ? "-" : "+", 478 disp < 0 ? -disp : disp); 479 } 480 return mod == 2 ? 6 : 3; 481 } else { 482 // No sib. 483 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) 484 : *reinterpret_cast<int8_t*>(modrmp + 1); 485 AppendToBuffer("[%s%s0x%x]", 486 (this->*register_name)(rm), 487 disp < 0 ? "-" : "+", 488 disp < 0 ? -disp : disp); 489 return mod == 2 ? 5 : 2; 490 } 491 break; 492 case 3: 493 AppendToBuffer("%s", (this->*register_name)(rm)); 494 return 1; 495 default: 496 UnimplementedInstruction(); 497 return 1; 498 } 499 UNREACHABLE(); 500} 501 502 503int DisassemblerIA32::PrintRightOperand(byte* modrmp) { 504 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); 505} 506 507 508int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { 509 return PrintRightOperandHelper(modrmp, 510 &DisassemblerIA32::NameOfByteCPURegister); 511} 512 513 514int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) { 515 return PrintRightOperandHelper(modrmp, 516 &DisassemblerIA32::NameOfXMMRegister); 517} 518 519 520// Returns number of bytes used including the current *data. 521// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. 522int DisassemblerIA32::PrintOperands(const char* mnem, 523 OperandOrder op_order, 524 byte* data) { 525 byte modrm = *data; 526 int mod, regop, rm; 527 get_modrm(modrm, &mod, ®op, &rm); 528 int advance = 0; 529 switch (op_order) { 530 case REG_OPER_OP_ORDER: { 531 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 532 advance = PrintRightOperand(data); 533 break; 534 } 535 case OPER_REG_OP_ORDER: { 536 AppendToBuffer("%s ", mnem); 537 advance = PrintRightOperand(data); 538 AppendToBuffer(",%s", NameOfCPURegister(regop)); 539 break; 540 } 541 default: 542 UNREACHABLE(); 543 break; 544 } 545 return advance; 546} 547 548 549// Returns number of bytes used by machine instruction, including *data byte. 550// Writes immediate instructions to 'tmp_buffer_'. 551int DisassemblerIA32::PrintImmediateOp(byte* data) { 552 bool sign_extension_bit = (*data & 0x02) != 0; 553 byte modrm = *(data+1); 554 int mod, regop, rm; 555 get_modrm(modrm, &mod, ®op, &rm); 556 const char* mnem = "Imm???"; 557 switch (regop) { 558 case 0: mnem = "add"; break; 559 case 1: mnem = "or"; break; 560 case 2: mnem = "adc"; break; 561 case 4: mnem = "and"; break; 562 case 5: mnem = "sub"; break; 563 case 6: mnem = "xor"; break; 564 case 7: mnem = "cmp"; break; 565 default: UnimplementedInstruction(); 566 } 567 AppendToBuffer("%s ", mnem); 568 int count = PrintRightOperand(data+1); 569 if (sign_extension_bit) { 570 AppendToBuffer(",0x%x", *(data + 1 + count)); 571 return 1 + count + 1 /*int8*/; 572 } else { 573 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); 574 return 1 + count + 4 /*int32_t*/; 575 } 576} 577 578 579// Returns number of bytes used, including *data. 580int DisassemblerIA32::F7Instruction(byte* data) { 581 DCHECK_EQ(0xF7, *data); 582 byte modrm = *++data; 583 int mod, regop, rm; 584 get_modrm(modrm, &mod, ®op, &rm); 585 const char* mnem = NULL; 586 switch (regop) { 587 case 0: 588 mnem = "test"; 589 break; 590 case 2: 591 mnem = "not"; 592 break; 593 case 3: 594 mnem = "neg"; 595 break; 596 case 4: 597 mnem = "mul"; 598 break; 599 case 5: 600 mnem = "imul"; 601 break; 602 case 6: 603 mnem = "div"; 604 break; 605 case 7: 606 mnem = "idiv"; 607 break; 608 default: 609 UnimplementedInstruction(); 610 } 611 AppendToBuffer("%s ", mnem); 612 int count = PrintRightOperand(data); 613 if (regop == 0) { 614 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count)); 615 count += 4; 616 } 617 return 1 + count; 618} 619 620 621int DisassemblerIA32::D1D3C1Instruction(byte* data) { 622 byte op = *data; 623 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1); 624 byte modrm = *++data; 625 int mod, regop, rm; 626 get_modrm(modrm, &mod, ®op, &rm); 627 int imm8 = -1; 628 const char* mnem = NULL; 629 switch (regop) { 630 case kROL: 631 mnem = "rol"; 632 break; 633 case kROR: 634 mnem = "ror"; 635 break; 636 case kRCL: 637 mnem = "rcl"; 638 break; 639 case kRCR: 640 mnem = "rcr"; 641 break; 642 case kSHL: 643 mnem = "shl"; 644 break; 645 case KSHR: 646 mnem = "shr"; 647 break; 648 case kSAR: 649 mnem = "sar"; 650 break; 651 default: 652 UnimplementedInstruction(); 653 } 654 AppendToBuffer("%s ", mnem); 655 int count = PrintRightOperand(data); 656 if (op == 0xD1) { 657 imm8 = 1; 658 } else if (op == 0xC1) { 659 imm8 = *(data + 1); 660 count++; 661 } else if (op == 0xD3) { 662 // Shift/rotate by cl. 663 } 664 if (imm8 >= 0) { 665 AppendToBuffer(",%d", imm8); 666 } else { 667 AppendToBuffer(",cl"); 668 } 669 return 1 + count; 670} 671 672 673// Returns number of bytes used, including *data. 674int DisassemblerIA32::JumpShort(byte* data) { 675 DCHECK_EQ(0xEB, *data); 676 byte b = *(data+1); 677 byte* dest = data + static_cast<int8_t>(b) + 2; 678 AppendToBuffer("jmp %s", NameOfAddress(dest)); 679 return 2; 680} 681 682 683// Returns number of bytes used, including *data. 684int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { 685 DCHECK_EQ(0x0F, *data); 686 byte cond = *(data+1) & 0x0F; 687 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; 688 const char* mnem = jump_conditional_mnem[cond]; 689 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 690 if (comment != NULL) { 691 AppendToBuffer(", %s", comment); 692 } 693 return 6; // includes 0x0F 694} 695 696 697// Returns number of bytes used, including *data. 698int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { 699 byte cond = *data & 0x0F; 700 byte b = *(data+1); 701 byte* dest = data + static_cast<int8_t>(b) + 2; 702 const char* mnem = jump_conditional_mnem[cond]; 703 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 704 if (comment != NULL) { 705 AppendToBuffer(", %s", comment); 706 } 707 return 2; 708} 709 710 711// Returns number of bytes used, including *data. 712int DisassemblerIA32::SetCC(byte* data) { 713 DCHECK_EQ(0x0F, *data); 714 byte cond = *(data+1) & 0x0F; 715 const char* mnem = set_conditional_mnem[cond]; 716 AppendToBuffer("%s ", mnem); 717 PrintRightByteOperand(data+2); 718 return 3; // Includes 0x0F. 719} 720 721 722// Returns number of bytes used, including *data. 723int DisassemblerIA32::CMov(byte* data) { 724 DCHECK_EQ(0x0F, *data); 725 byte cond = *(data + 1) & 0x0F; 726 const char* mnem = conditional_move_mnem[cond]; 727 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); 728 return 2 + op_size; // includes 0x0F 729} 730 731 732int DisassemblerIA32::AVXInstruction(byte* data) { 733 byte opcode = *data; 734 byte* current = data + 1; 735 if (vex_66() && vex_0f38()) { 736 int mod, regop, rm, vvvv = vex_vreg(); 737 get_modrm(*current, &mod, ®op, &rm); 738 switch (opcode) { 739 case 0x99: 740 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(), 741 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 742 current += PrintRightXMMOperand(current); 743 break; 744 case 0xa9: 745 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(), 746 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 747 current += PrintRightXMMOperand(current); 748 break; 749 case 0xb9: 750 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(), 751 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 752 current += PrintRightXMMOperand(current); 753 break; 754 case 0x9b: 755 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(), 756 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 757 current += PrintRightXMMOperand(current); 758 break; 759 case 0xab: 760 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(), 761 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 762 current += PrintRightXMMOperand(current); 763 break; 764 case 0xbb: 765 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(), 766 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 767 current += PrintRightXMMOperand(current); 768 break; 769 case 0x9d: 770 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(), 771 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 772 current += PrintRightXMMOperand(current); 773 break; 774 case 0xad: 775 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(), 776 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 777 current += PrintRightXMMOperand(current); 778 break; 779 case 0xbd: 780 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(), 781 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 782 current += PrintRightXMMOperand(current); 783 break; 784 case 0x9f: 785 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(), 786 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 787 current += PrintRightXMMOperand(current); 788 break; 789 case 0xaf: 790 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(), 791 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 792 current += PrintRightXMMOperand(current); 793 break; 794 case 0xbf: 795 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(), 796 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 797 current += PrintRightXMMOperand(current); 798 break; 799 case 0xf7: 800 AppendToBuffer("shlx %s,", NameOfCPURegister(regop)); 801 current += PrintRightOperand(current); 802 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 803 break; 804 default: 805 UnimplementedInstruction(); 806 } 807 } else if (vex_f2() && vex_0f()) { 808 int mod, regop, rm, vvvv = vex_vreg(); 809 get_modrm(*current, &mod, ®op, &rm); 810 switch (opcode) { 811 case 0x58: 812 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop), 813 NameOfXMMRegister(vvvv)); 814 current += PrintRightXMMOperand(current); 815 break; 816 case 0x59: 817 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop), 818 NameOfXMMRegister(vvvv)); 819 current += PrintRightXMMOperand(current); 820 break; 821 case 0x5c: 822 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop), 823 NameOfXMMRegister(vvvv)); 824 current += PrintRightXMMOperand(current); 825 break; 826 case 0x5d: 827 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop), 828 NameOfXMMRegister(vvvv)); 829 current += PrintRightXMMOperand(current); 830 break; 831 case 0x5e: 832 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop), 833 NameOfXMMRegister(vvvv)); 834 current += PrintRightXMMOperand(current); 835 break; 836 case 0x5f: 837 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop), 838 NameOfXMMRegister(vvvv)); 839 current += PrintRightXMMOperand(current); 840 break; 841 default: 842 UnimplementedInstruction(); 843 } 844 } else if (vex_f3() && vex_0f()) { 845 int mod, regop, rm, vvvv = vex_vreg(); 846 get_modrm(*current, &mod, ®op, &rm); 847 switch (opcode) { 848 case 0x58: 849 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop), 850 NameOfXMMRegister(vvvv)); 851 current += PrintRightXMMOperand(current); 852 break; 853 case 0x59: 854 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop), 855 NameOfXMMRegister(vvvv)); 856 current += PrintRightXMMOperand(current); 857 break; 858 case 0x5c: 859 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop), 860 NameOfXMMRegister(vvvv)); 861 current += PrintRightXMMOperand(current); 862 break; 863 case 0x5d: 864 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop), 865 NameOfXMMRegister(vvvv)); 866 current += PrintRightXMMOperand(current); 867 break; 868 case 0x5e: 869 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop), 870 NameOfXMMRegister(vvvv)); 871 current += PrintRightXMMOperand(current); 872 break; 873 case 0x5f: 874 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop), 875 NameOfXMMRegister(vvvv)); 876 current += PrintRightXMMOperand(current); 877 break; 878 default: 879 UnimplementedInstruction(); 880 } 881 } else if (vex_none() && vex_0f38()) { 882 int mod, regop, rm, vvvv = vex_vreg(); 883 get_modrm(*current, &mod, ®op, &rm); 884 const char* mnem = "?"; 885 switch (opcode) { 886 case 0xf2: 887 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop), 888 NameOfCPURegister(vvvv)); 889 current += PrintRightOperand(current); 890 break; 891 case 0xf5: 892 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop)); 893 current += PrintRightOperand(current); 894 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 895 break; 896 case 0xf7: 897 AppendToBuffer("bextr %s,", NameOfCPURegister(regop)); 898 current += PrintRightOperand(current); 899 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 900 break; 901 case 0xf3: 902 switch (regop) { 903 case 1: 904 mnem = "blsr"; 905 break; 906 case 2: 907 mnem = "blsmsk"; 908 break; 909 case 3: 910 mnem = "blsi"; 911 break; 912 default: 913 UnimplementedInstruction(); 914 } 915 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv)); 916 current += PrintRightOperand(current); 917 mnem = "?"; 918 break; 919 default: 920 UnimplementedInstruction(); 921 } 922 } else if (vex_f2() && vex_0f38()) { 923 int mod, regop, rm, vvvv = vex_vreg(); 924 get_modrm(*current, &mod, ®op, &rm); 925 switch (opcode) { 926 case 0xf5: 927 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop), 928 NameOfCPURegister(vvvv)); 929 current += PrintRightOperand(current); 930 break; 931 case 0xf6: 932 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop), 933 NameOfCPURegister(vvvv)); 934 current += PrintRightOperand(current); 935 break; 936 case 0xf7: 937 AppendToBuffer("shrx %s,", NameOfCPURegister(regop)); 938 current += PrintRightOperand(current); 939 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 940 break; 941 default: 942 UnimplementedInstruction(); 943 } 944 } else if (vex_f3() && vex_0f38()) { 945 int mod, regop, rm, vvvv = vex_vreg(); 946 get_modrm(*current, &mod, ®op, &rm); 947 switch (opcode) { 948 case 0xf5: 949 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop), 950 NameOfCPURegister(vvvv)); 951 current += PrintRightOperand(current); 952 break; 953 case 0xf7: 954 AppendToBuffer("sarx %s,", NameOfCPURegister(regop)); 955 current += PrintRightOperand(current); 956 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 957 break; 958 default: 959 UnimplementedInstruction(); 960 } 961 } else if (vex_f2() && vex_0f3a()) { 962 int mod, regop, rm; 963 get_modrm(*current, &mod, ®op, &rm); 964 switch (opcode) { 965 case 0xf0: 966 AppendToBuffer("rorx %s,", NameOfCPURegister(regop)); 967 current += PrintRightOperand(current); 968 AppendToBuffer(",%d", *current & 0x1f); 969 current += 1; 970 break; 971 default: 972 UnimplementedInstruction(); 973 } 974 } else if (vex_none() && vex_0f()) { 975 int mod, regop, rm, vvvv = vex_vreg(); 976 get_modrm(*current, &mod, ®op, &rm); 977 switch (opcode) { 978 case 0x54: 979 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop), 980 NameOfXMMRegister(vvvv)); 981 current += PrintRightXMMOperand(current); 982 break; 983 case 0x57: 984 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop), 985 NameOfXMMRegister(vvvv)); 986 current += PrintRightXMMOperand(current); 987 break; 988 default: 989 UnimplementedInstruction(); 990 } 991 } else if (vex_66() && vex_0f()) { 992 int mod, regop, rm, vvvv = vex_vreg(); 993 get_modrm(*current, &mod, ®op, &rm); 994 switch (opcode) { 995 case 0x54: 996 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop), 997 NameOfXMMRegister(vvvv)); 998 current += PrintRightXMMOperand(current); 999 break; 1000 case 0x57: 1001 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop), 1002 NameOfXMMRegister(vvvv)); 1003 current += PrintRightXMMOperand(current); 1004 break; 1005 default: 1006 UnimplementedInstruction(); 1007 } 1008 } else { 1009 UnimplementedInstruction(); 1010 } 1011 1012 return static_cast<int>(current - data); 1013} 1014 1015 1016// Returns number of bytes used, including *data. 1017int DisassemblerIA32::FPUInstruction(byte* data) { 1018 byte escape_opcode = *data; 1019 DCHECK_EQ(0xD8, escape_opcode & 0xF8); 1020 byte modrm_byte = *(data+1); 1021 1022 if (modrm_byte >= 0xC0) { 1023 return RegisterFPUInstruction(escape_opcode, modrm_byte); 1024 } else { 1025 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); 1026 } 1027} 1028 1029int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, 1030 int modrm_byte, 1031 byte* modrm_start) { 1032 const char* mnem = "?"; 1033 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. 1034 switch (escape_opcode) { 1035 case 0xD9: switch (regop) { 1036 case 0: mnem = "fld_s"; break; 1037 case 2: mnem = "fst_s"; break; 1038 case 3: mnem = "fstp_s"; break; 1039 case 7: mnem = "fstcw"; break; 1040 default: UnimplementedInstruction(); 1041 } 1042 break; 1043 1044 case 0xDB: switch (regop) { 1045 case 0: mnem = "fild_s"; break; 1046 case 1: mnem = "fisttp_s"; break; 1047 case 2: mnem = "fist_s"; break; 1048 case 3: mnem = "fistp_s"; break; 1049 default: UnimplementedInstruction(); 1050 } 1051 break; 1052 1053 case 0xDD: switch (regop) { 1054 case 0: mnem = "fld_d"; break; 1055 case 1: mnem = "fisttp_d"; break; 1056 case 2: mnem = "fst_d"; break; 1057 case 3: mnem = "fstp_d"; break; 1058 default: UnimplementedInstruction(); 1059 } 1060 break; 1061 1062 case 0xDF: switch (regop) { 1063 case 5: mnem = "fild_d"; break; 1064 case 7: mnem = "fistp_d"; break; 1065 default: UnimplementedInstruction(); 1066 } 1067 break; 1068 1069 default: UnimplementedInstruction(); 1070 } 1071 AppendToBuffer("%s ", mnem); 1072 int count = PrintRightOperand(modrm_start); 1073 return count + 1; 1074} 1075 1076int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, 1077 byte modrm_byte) { 1078 bool has_register = false; // Is the FPU register encoded in modrm_byte? 1079 const char* mnem = "?"; 1080 1081 switch (escape_opcode) { 1082 case 0xD8: 1083 has_register = true; 1084 switch (modrm_byte & 0xF8) { 1085 case 0xC0: mnem = "fadd_i"; break; 1086 case 0xE0: mnem = "fsub_i"; break; 1087 case 0xC8: mnem = "fmul_i"; break; 1088 case 0xF0: mnem = "fdiv_i"; break; 1089 default: UnimplementedInstruction(); 1090 } 1091 break; 1092 1093 case 0xD9: 1094 switch (modrm_byte & 0xF8) { 1095 case 0xC0: 1096 mnem = "fld"; 1097 has_register = true; 1098 break; 1099 case 0xC8: 1100 mnem = "fxch"; 1101 has_register = true; 1102 break; 1103 default: 1104 switch (modrm_byte) { 1105 case 0xE0: mnem = "fchs"; break; 1106 case 0xE1: mnem = "fabs"; break; 1107 case 0xE4: mnem = "ftst"; break; 1108 case 0xE8: mnem = "fld1"; break; 1109 case 0xEB: mnem = "fldpi"; break; 1110 case 0xED: mnem = "fldln2"; break; 1111 case 0xEE: mnem = "fldz"; break; 1112 case 0xF0: mnem = "f2xm1"; break; 1113 case 0xF1: mnem = "fyl2x"; break; 1114 case 0xF4: mnem = "fxtract"; break; 1115 case 0xF5: mnem = "fprem1"; break; 1116 case 0xF7: mnem = "fincstp"; break; 1117 case 0xF8: mnem = "fprem"; break; 1118 case 0xFC: mnem = "frndint"; break; 1119 case 0xFD: mnem = "fscale"; break; 1120 case 0xFE: mnem = "fsin"; break; 1121 case 0xFF: mnem = "fcos"; break; 1122 default: UnimplementedInstruction(); 1123 } 1124 } 1125 break; 1126 1127 case 0xDA: 1128 if (modrm_byte == 0xE9) { 1129 mnem = "fucompp"; 1130 } else { 1131 UnimplementedInstruction(); 1132 } 1133 break; 1134 1135 case 0xDB: 1136 if ((modrm_byte & 0xF8) == 0xE8) { 1137 mnem = "fucomi"; 1138 has_register = true; 1139 } else if (modrm_byte == 0xE2) { 1140 mnem = "fclex"; 1141 } else if (modrm_byte == 0xE3) { 1142 mnem = "fninit"; 1143 } else { 1144 UnimplementedInstruction(); 1145 } 1146 break; 1147 1148 case 0xDC: 1149 has_register = true; 1150 switch (modrm_byte & 0xF8) { 1151 case 0xC0: mnem = "fadd"; break; 1152 case 0xE8: mnem = "fsub"; break; 1153 case 0xC8: mnem = "fmul"; break; 1154 case 0xF8: mnem = "fdiv"; break; 1155 default: UnimplementedInstruction(); 1156 } 1157 break; 1158 1159 case 0xDD: 1160 has_register = true; 1161 switch (modrm_byte & 0xF8) { 1162 case 0xC0: mnem = "ffree"; break; 1163 case 0xD0: mnem = "fst"; break; 1164 case 0xD8: mnem = "fstp"; break; 1165 default: UnimplementedInstruction(); 1166 } 1167 break; 1168 1169 case 0xDE: 1170 if (modrm_byte == 0xD9) { 1171 mnem = "fcompp"; 1172 } else { 1173 has_register = true; 1174 switch (modrm_byte & 0xF8) { 1175 case 0xC0: mnem = "faddp"; break; 1176 case 0xE8: mnem = "fsubp"; break; 1177 case 0xC8: mnem = "fmulp"; break; 1178 case 0xF8: mnem = "fdivp"; break; 1179 default: UnimplementedInstruction(); 1180 } 1181 } 1182 break; 1183 1184 case 0xDF: 1185 if (modrm_byte == 0xE0) { 1186 mnem = "fnstsw_ax"; 1187 } else if ((modrm_byte & 0xF8) == 0xE8) { 1188 mnem = "fucomip"; 1189 has_register = true; 1190 } 1191 break; 1192 1193 default: UnimplementedInstruction(); 1194 } 1195 1196 if (has_register) { 1197 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); 1198 } else { 1199 AppendToBuffer("%s", mnem); 1200 } 1201 return 2; 1202} 1203 1204 1205// Mnemonics for instructions 0xF0 byte. 1206// Returns NULL if the instruction is not handled here. 1207static const char* F0Mnem(byte f0byte) { 1208 switch (f0byte) { 1209 case 0x0B: 1210 return "ud2"; 1211 case 0x18: 1212 return "prefetch"; 1213 case 0xA2: 1214 return "cpuid"; 1215 case 0xBE: 1216 return "movsx_b"; 1217 case 0xBF: 1218 return "movsx_w"; 1219 case 0xB6: 1220 return "movzx_b"; 1221 case 0xB7: 1222 return "movzx_w"; 1223 case 0xAF: 1224 return "imul"; 1225 case 0xA4: 1226 return "shld"; 1227 case 0xA5: 1228 return "shld"; 1229 case 0xAD: 1230 return "shrd"; 1231 case 0xAC: 1232 return "shrd"; // 3-operand version. 1233 case 0xAB: 1234 return "bts"; 1235 case 0xB0: 1236 return "cmpxchg_b"; 1237 case 0xB1: 1238 return "cmpxchg"; 1239 case 0xBC: 1240 return "bsf"; 1241 case 0xBD: 1242 return "bsr"; 1243 default: return NULL; 1244 } 1245} 1246 1247 1248// Disassembled instruction '*instr' and writes it into 'out_buffer'. 1249int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, 1250 byte* instr) { 1251 tmp_buffer_pos_ = 0; // starting to write as position 0 1252 byte* data = instr; 1253 // Check for hints. 1254 const char* branch_hint = NULL; 1255 // We use these two prefixes only with branch prediction 1256 if (*data == 0x3E /*ds*/) { 1257 branch_hint = "predicted taken"; 1258 data++; 1259 } else if (*data == 0x2E /*cs*/) { 1260 branch_hint = "predicted not taken"; 1261 data++; 1262 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) { 1263 vex_byte0_ = *data; 1264 vex_byte1_ = *(data + 1); 1265 vex_byte2_ = *(data + 2); 1266 data += 3; 1267 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) { 1268 vex_byte0_ = *data; 1269 vex_byte1_ = *(data + 1); 1270 data += 2; 1271 } else if (*data == 0xF0 /*lock*/) { 1272 AppendToBuffer("lock "); 1273 data++; 1274 } 1275 1276 bool processed = true; // Will be set to false if the current instruction 1277 // is not in 'instructions' table. 1278 // Decode AVX instructions. 1279 if (vex_byte0_ != 0) { 1280 data += AVXInstruction(data); 1281 } else { 1282 const InstructionDesc& idesc = instruction_table_->Get(*data); 1283 switch (idesc.type) { 1284 case ZERO_OPERANDS_INSTR: 1285 AppendToBuffer("%s", idesc.mnem); 1286 data++; 1287 break; 1288 1289 case TWO_OPERANDS_INSTR: 1290 data++; 1291 data += PrintOperands(idesc.mnem, idesc.op_order_, data); 1292 break; 1293 1294 case JUMP_CONDITIONAL_SHORT_INSTR: 1295 data += JumpConditionalShort(data, branch_hint); 1296 break; 1297 1298 case REGISTER_INSTR: 1299 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); 1300 data++; 1301 break; 1302 1303 case MOVE_REG_INSTR: { 1304 byte* addr = 1305 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); 1306 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07), 1307 NameOfAddress(addr)); 1308 data += 5; 1309 break; 1310 } 1311 1312 case CALL_JUMP_INSTR: { 1313 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5; 1314 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); 1315 data += 5; 1316 break; 1317 } 1318 1319 case SHORT_IMMEDIATE_INSTR: { 1320 byte* addr = 1321 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); 1322 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); 1323 data += 5; 1324 break; 1325 } 1326 1327 case BYTE_IMMEDIATE_INSTR: { 1328 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); 1329 data += 2; 1330 break; 1331 } 1332 1333 case NO_INSTR: 1334 processed = false; 1335 break; 1336 1337 default: 1338 UNIMPLEMENTED(); // This type is not implemented. 1339 } 1340 } 1341 //---------------------------- 1342 if (!processed) { 1343 switch (*data) { 1344 case 0xC2: 1345 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); 1346 data += 3; 1347 break; 1348 1349 case 0x6B: { 1350 data++; 1351 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 1352 AppendToBuffer(",%d", *data); 1353 data++; 1354 } break; 1355 1356 case 0x69: { 1357 data++; 1358 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 1359 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data)); 1360 data += 4; 1361 } 1362 break; 1363 1364 case 0xF6: 1365 { data++; 1366 int mod, regop, rm; 1367 get_modrm(*data, &mod, ®op, &rm); 1368 if (regop == eax) { 1369 AppendToBuffer("test_b "); 1370 data += PrintRightByteOperand(data); 1371 int32_t imm = *data; 1372 AppendToBuffer(",0x%x", imm); 1373 data++; 1374 } else { 1375 UnimplementedInstruction(); 1376 } 1377 } 1378 break; 1379 1380 case 0x81: // fall through 1381 case 0x83: // 0x81 with sign extension bit set 1382 data += PrintImmediateOp(data); 1383 break; 1384 1385 case 0x0F: 1386 { byte f0byte = data[1]; 1387 const char* f0mnem = F0Mnem(f0byte); 1388 if (f0byte == 0x18) { 1389 data += 2; 1390 int mod, regop, rm; 1391 get_modrm(*data, &mod, ®op, &rm); 1392 const char* suffix[] = {"nta", "1", "2", "3"}; 1393 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]); 1394 data += PrintRightOperand(data); 1395 } else if (f0byte == 0x1F && data[2] == 0) { 1396 AppendToBuffer("nop"); // 3 byte nop. 1397 data += 3; 1398 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) { 1399 AppendToBuffer("nop"); // 4 byte nop. 1400 data += 4; 1401 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 && 1402 data[4] == 0) { 1403 AppendToBuffer("nop"); // 5 byte nop. 1404 data += 5; 1405 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 && 1406 data[4] == 0 && data[5] == 0 && data[6] == 0) { 1407 AppendToBuffer("nop"); // 7 byte nop. 1408 data += 7; 1409 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 && 1410 data[4] == 0 && data[5] == 0 && data[6] == 0 && 1411 data[7] == 0) { 1412 AppendToBuffer("nop"); // 8 byte nop. 1413 data += 8; 1414 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) { 1415 AppendToBuffer("%s", f0mnem); 1416 data += 2; 1417 } else if (f0byte == 0x28) { 1418 data += 2; 1419 int mod, regop, rm; 1420 get_modrm(*data, &mod, ®op, &rm); 1421 AppendToBuffer("movaps %s,%s", 1422 NameOfXMMRegister(regop), 1423 NameOfXMMRegister(rm)); 1424 data++; 1425 } else if (f0byte == 0x2e) { 1426 data += 2; 1427 int mod, regop, rm; 1428 get_modrm(*data, &mod, ®op, &rm); 1429 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop)); 1430 data += PrintRightXMMOperand(data); 1431 } else if (f0byte >= 0x53 && f0byte <= 0x5F) { 1432 const char* const pseudo_op[] = { 1433 "rcpps", 1434 "andps", 1435 "andnps", 1436 "orps", 1437 "xorps", 1438 "addps", 1439 "mulps", 1440 "cvtps2pd", 1441 "cvtdq2ps", 1442 "subps", 1443 "minps", 1444 "divps", 1445 "maxps", 1446 }; 1447 1448 data += 2; 1449 int mod, regop, rm; 1450 get_modrm(*data, &mod, ®op, &rm); 1451 AppendToBuffer("%s %s,", 1452 pseudo_op[f0byte - 0x53], 1453 NameOfXMMRegister(regop)); 1454 data += PrintRightXMMOperand(data); 1455 } else if (f0byte == 0x50) { 1456 data += 2; 1457 int mod, regop, rm; 1458 get_modrm(*data, &mod, ®op, &rm); 1459 AppendToBuffer("movmskps %s,%s", 1460 NameOfCPURegister(regop), 1461 NameOfXMMRegister(rm)); 1462 data++; 1463 } else if (f0byte== 0xC6) { 1464 // shufps xmm, xmm/m128, imm8 1465 data += 2; 1466 int mod, regop, rm; 1467 get_modrm(*data, &mod, ®op, &rm); 1468 int8_t imm8 = static_cast<int8_t>(data[1]); 1469 AppendToBuffer("shufps %s,%s,%d", 1470 NameOfXMMRegister(rm), 1471 NameOfXMMRegister(regop), 1472 static_cast<int>(imm8)); 1473 data += 2; 1474 } else if ((f0byte & 0xF0) == 0x80) { 1475 data += JumpConditional(data, branch_hint); 1476 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || 1477 f0byte == 0xB7 || f0byte == 0xAF) { 1478 data += 2; 1479 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); 1480 } else if ((f0byte & 0xF0) == 0x90) { 1481 data += SetCC(data); 1482 } else if ((f0byte & 0xF0) == 0x40) { 1483 data += CMov(data); 1484 } else if (f0byte == 0xA4 || f0byte == 0xAC) { 1485 // shld, shrd 1486 data += 2; 1487 AppendToBuffer("%s ", f0mnem); 1488 int mod, regop, rm; 1489 get_modrm(*data, &mod, ®op, &rm); 1490 int8_t imm8 = static_cast<int8_t>(data[1]); 1491 data += 2; 1492 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm), 1493 NameOfCPURegister(regop), static_cast<int>(imm8)); 1494 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { 1495 // shrd_cl, shld_cl, bts 1496 data += 2; 1497 AppendToBuffer("%s ", f0mnem); 1498 int mod, regop, rm; 1499 get_modrm(*data, &mod, ®op, &rm); 1500 data += PrintRightOperand(data); 1501 if (f0byte == 0xAB) { 1502 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1503 } else { 1504 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); 1505 } 1506 } else if (f0byte == 0xB0) { 1507 // cmpxchg_b 1508 data += 2; 1509 AppendToBuffer("%s ", f0mnem); 1510 int mod, regop, rm; 1511 get_modrm(*data, &mod, ®op, &rm); 1512 data += PrintRightOperand(data); 1513 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1514 } else if (f0byte == 0xB1) { 1515 // cmpxchg 1516 data += 2; 1517 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data); 1518 } else if (f0byte == 0xBC) { 1519 data += 2; 1520 int mod, regop, rm; 1521 get_modrm(*data, &mod, ®op, &rm); 1522 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); 1523 data += PrintRightOperand(data); 1524 } else if (f0byte == 0xBD) { 1525 data += 2; 1526 int mod, regop, rm; 1527 get_modrm(*data, &mod, ®op, &rm); 1528 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); 1529 data += PrintRightOperand(data); 1530 } else { 1531 UnimplementedInstruction(); 1532 } 1533 } 1534 break; 1535 1536 case 0x8F: 1537 { data++; 1538 int mod, regop, rm; 1539 get_modrm(*data, &mod, ®op, &rm); 1540 if (regop == eax) { 1541 AppendToBuffer("pop "); 1542 data += PrintRightOperand(data); 1543 } 1544 } 1545 break; 1546 1547 case 0xFF: 1548 { data++; 1549 int mod, regop, rm; 1550 get_modrm(*data, &mod, ®op, &rm); 1551 const char* mnem = NULL; 1552 switch (regop) { 1553 case esi: mnem = "push"; break; 1554 case eax: mnem = "inc"; break; 1555 case ecx: mnem = "dec"; break; 1556 case edx: mnem = "call"; break; 1557 case esp: mnem = "jmp"; break; 1558 default: mnem = "???"; 1559 } 1560 AppendToBuffer("%s ", mnem); 1561 data += PrintRightOperand(data); 1562 } 1563 break; 1564 1565 case 0xC7: // imm32, fall through 1566 case 0xC6: // imm8 1567 { bool is_byte = *data == 0xC6; 1568 data++; 1569 if (is_byte) { 1570 AppendToBuffer("%s ", "mov_b"); 1571 data += PrintRightByteOperand(data); 1572 int32_t imm = *data; 1573 AppendToBuffer(",0x%x", imm); 1574 data++; 1575 } else { 1576 AppendToBuffer("%s ", "mov"); 1577 data += PrintRightOperand(data); 1578 int32_t imm = *reinterpret_cast<int32_t*>(data); 1579 AppendToBuffer(",0x%x", imm); 1580 data += 4; 1581 } 1582 } 1583 break; 1584 1585 case 0x80: 1586 { data++; 1587 int mod, regop, rm; 1588 get_modrm(*data, &mod, ®op, &rm); 1589 const char* mnem = NULL; 1590 switch (regop) { 1591 case 5: mnem = "subb"; break; 1592 case 7: mnem = "cmpb"; break; 1593 default: UnimplementedInstruction(); 1594 } 1595 AppendToBuffer("%s ", mnem); 1596 data += PrintRightByteOperand(data); 1597 int32_t imm = *data; 1598 AppendToBuffer(",0x%x", imm); 1599 data++; 1600 } 1601 break; 1602 1603 case 0x88: // 8bit, fall through 1604 case 0x89: // 32bit 1605 { bool is_byte = *data == 0x88; 1606 int mod, regop, rm; 1607 data++; 1608 get_modrm(*data, &mod, ®op, &rm); 1609 if (is_byte) { 1610 AppendToBuffer("%s ", "mov_b"); 1611 data += PrintRightByteOperand(data); 1612 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1613 } else { 1614 AppendToBuffer("%s ", "mov"); 1615 data += PrintRightOperand(data); 1616 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1617 } 1618 } 1619 break; 1620 1621 case 0x66: // prefix 1622 while (*data == 0x66) data++; 1623 if (*data == 0xf && data[1] == 0x1f) { 1624 AppendToBuffer("nop"); // 0x66 prefix 1625 } else if (*data == 0x39) { 1626 data++; 1627 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data); 1628 } else if (*data == 0x3B) { 1629 data++; 1630 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data); 1631 } else if (*data == 0x81) { 1632 data++; 1633 AppendToBuffer("cmpw "); 1634 data += PrintRightOperand(data); 1635 int imm = *reinterpret_cast<int16_t*>(data); 1636 AppendToBuffer(",0x%x", imm); 1637 data += 2; 1638 } else if (*data == 0x87) { 1639 data++; 1640 int mod, regop, rm; 1641 get_modrm(*data, &mod, ®op, &rm); 1642 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop)); 1643 data += PrintRightOperand(data); 1644 } else if (*data == 0x89) { 1645 data++; 1646 int mod, regop, rm; 1647 get_modrm(*data, &mod, ®op, &rm); 1648 AppendToBuffer("mov_w "); 1649 data += PrintRightOperand(data); 1650 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1651 } else if (*data == 0x8B) { 1652 data++; 1653 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); 1654 } else if (*data == 0x90) { 1655 AppendToBuffer("nop"); // 0x66 prefix 1656 } else if (*data == 0xC7) { 1657 data++; 1658 AppendToBuffer("%s ", "mov_w"); 1659 data += PrintRightOperand(data); 1660 int imm = *reinterpret_cast<int16_t*>(data); 1661 AppendToBuffer(",0x%x", imm); 1662 data += 2; 1663 } else if (*data == 0xF7) { 1664 data++; 1665 AppendToBuffer("%s ", "test_w"); 1666 data += PrintRightOperand(data); 1667 int imm = *reinterpret_cast<int16_t*>(data); 1668 AppendToBuffer(",0x%x", imm); 1669 data += 2; 1670 } else if (*data == 0x0F) { 1671 data++; 1672 if (*data == 0x38) { 1673 data++; 1674 if (*data == 0x17) { 1675 data++; 1676 int mod, regop, rm; 1677 get_modrm(*data, &mod, ®op, &rm); 1678 AppendToBuffer("ptest %s,%s", 1679 NameOfXMMRegister(regop), 1680 NameOfXMMRegister(rm)); 1681 data++; 1682 } else if (*data == 0x2A) { 1683 // movntdqa 1684 UnimplementedInstruction(); 1685 } else { 1686 UnimplementedInstruction(); 1687 } 1688 } else if (*data == 0x3A) { 1689 data++; 1690 if (*data == 0x0A) { 1691 data++; 1692 int mod, regop, rm; 1693 get_modrm(*data, &mod, ®op, &rm); 1694 int8_t imm8 = static_cast<int8_t>(data[1]); 1695 AppendToBuffer("roundss %s,%s,%d", NameOfXMMRegister(regop), 1696 NameOfXMMRegister(rm), static_cast<int>(imm8)); 1697 data += 2; 1698 } else if (*data == 0x0B) { 1699 data++; 1700 int mod, regop, rm; 1701 get_modrm(*data, &mod, ®op, &rm); 1702 int8_t imm8 = static_cast<int8_t>(data[1]); 1703 AppendToBuffer("roundsd %s,%s,%d", 1704 NameOfXMMRegister(regop), 1705 NameOfXMMRegister(rm), 1706 static_cast<int>(imm8)); 1707 data += 2; 1708 } else if (*data == 0x16) { 1709 data++; 1710 int mod, regop, rm; 1711 get_modrm(*data, &mod, &rm, ®op); 1712 int8_t imm8 = static_cast<int8_t>(data[1]); 1713 AppendToBuffer("pextrd %s,%s,%d", 1714 NameOfCPURegister(regop), 1715 NameOfXMMRegister(rm), 1716 static_cast<int>(imm8)); 1717 data += 2; 1718 } else if (*data == 0x17) { 1719 data++; 1720 int mod, regop, rm; 1721 get_modrm(*data, &mod, ®op, &rm); 1722 int8_t imm8 = static_cast<int8_t>(data[1]); 1723 AppendToBuffer("extractps %s,%s,%d", 1724 NameOfCPURegister(rm), 1725 NameOfXMMRegister(regop), 1726 static_cast<int>(imm8)); 1727 data += 2; 1728 } else if (*data == 0x22) { 1729 data++; 1730 int mod, regop, rm; 1731 get_modrm(*data, &mod, ®op, &rm); 1732 int8_t imm8 = static_cast<int8_t>(data[1]); 1733 AppendToBuffer("pinsrd %s,%s,%d", 1734 NameOfXMMRegister(regop), 1735 NameOfCPURegister(rm), 1736 static_cast<int>(imm8)); 1737 data += 2; 1738 } else { 1739 UnimplementedInstruction(); 1740 } 1741 } else if (*data == 0x2E || *data == 0x2F) { 1742 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd"; 1743 data++; 1744 int mod, regop, rm; 1745 get_modrm(*data, &mod, ®op, &rm); 1746 if (mod == 0x3) { 1747 AppendToBuffer("%s %s,%s", mnem, 1748 NameOfXMMRegister(regop), 1749 NameOfXMMRegister(rm)); 1750 data++; 1751 } else { 1752 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1753 data += PrintRightOperand(data); 1754 } 1755 } else if (*data == 0x50) { 1756 data++; 1757 int mod, regop, rm; 1758 get_modrm(*data, &mod, ®op, &rm); 1759 AppendToBuffer("movmskpd %s,%s", 1760 NameOfCPURegister(regop), 1761 NameOfXMMRegister(rm)); 1762 data++; 1763 } else if (*data == 0x54) { 1764 data++; 1765 int mod, regop, rm; 1766 get_modrm(*data, &mod, ®op, &rm); 1767 AppendToBuffer("andpd %s,%s", 1768 NameOfXMMRegister(regop), 1769 NameOfXMMRegister(rm)); 1770 data++; 1771 } else if (*data == 0x56) { 1772 data++; 1773 int mod, regop, rm; 1774 get_modrm(*data, &mod, ®op, &rm); 1775 AppendToBuffer("orpd %s,%s", 1776 NameOfXMMRegister(regop), 1777 NameOfXMMRegister(rm)); 1778 data++; 1779 } else if (*data == 0x57) { 1780 data++; 1781 int mod, regop, rm; 1782 get_modrm(*data, &mod, ®op, &rm); 1783 AppendToBuffer("xorpd %s,%s", 1784 NameOfXMMRegister(regop), 1785 NameOfXMMRegister(rm)); 1786 data++; 1787 } else if (*data == 0x6E) { 1788 data++; 1789 int mod, regop, rm; 1790 get_modrm(*data, &mod, ®op, &rm); 1791 AppendToBuffer("movd %s,", NameOfXMMRegister(regop)); 1792 data += PrintRightOperand(data); 1793 } else if (*data == 0x6F) { 1794 data++; 1795 int mod, regop, rm; 1796 get_modrm(*data, &mod, ®op, &rm); 1797 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop)); 1798 data += PrintRightXMMOperand(data); 1799 } else if (*data == 0x70) { 1800 data++; 1801 int mod, regop, rm; 1802 get_modrm(*data, &mod, ®op, &rm); 1803 int8_t imm8 = static_cast<int8_t>(data[1]); 1804 AppendToBuffer("pshufd %s,%s,%d", 1805 NameOfXMMRegister(regop), 1806 NameOfXMMRegister(rm), 1807 static_cast<int>(imm8)); 1808 data += 2; 1809 } else if (*data == 0x62) { 1810 data++; 1811 int mod, regop, rm; 1812 get_modrm(*data, &mod, ®op, &rm); 1813 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop), 1814 NameOfXMMRegister(rm)); 1815 data++; 1816 } else if (*data == 0x6A) { 1817 data++; 1818 int mod, regop, rm; 1819 get_modrm(*data, &mod, ®op, &rm); 1820 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop), 1821 NameOfXMMRegister(rm)); 1822 data++; 1823 } else if (*data == 0x76) { 1824 data++; 1825 int mod, regop, rm; 1826 get_modrm(*data, &mod, ®op, &rm); 1827 AppendToBuffer("pcmpeqd %s,%s", 1828 NameOfXMMRegister(regop), 1829 NameOfXMMRegister(rm)); 1830 data++; 1831 } else if (*data == 0x90) { 1832 data++; 1833 AppendToBuffer("nop"); // 2 byte nop. 1834 } else if (*data == 0xF3) { 1835 data++; 1836 int mod, regop, rm; 1837 get_modrm(*data, &mod, ®op, &rm); 1838 AppendToBuffer("psllq %s,%s", 1839 NameOfXMMRegister(regop), 1840 NameOfXMMRegister(rm)); 1841 data++; 1842 } else if (*data == 0x72) { 1843 data++; 1844 int mod, regop, rm; 1845 get_modrm(*data, &mod, ®op, &rm); 1846 int8_t imm8 = static_cast<int8_t>(data[1]); 1847 DCHECK(regop == esi || regop == edx); 1848 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld", 1849 NameOfXMMRegister(rm), static_cast<int>(imm8)); 1850 data += 2; 1851 } else if (*data == 0x73) { 1852 data++; 1853 int mod, regop, rm; 1854 get_modrm(*data, &mod, ®op, &rm); 1855 int8_t imm8 = static_cast<int8_t>(data[1]); 1856 DCHECK(regop == esi || regop == edx); 1857 AppendToBuffer("%s %s,%d", 1858 (regop == esi) ? "psllq" : "psrlq", 1859 NameOfXMMRegister(rm), 1860 static_cast<int>(imm8)); 1861 data += 2; 1862 } else if (*data == 0xD3) { 1863 data++; 1864 int mod, regop, rm; 1865 get_modrm(*data, &mod, ®op, &rm); 1866 AppendToBuffer("psrlq %s,%s", 1867 NameOfXMMRegister(regop), 1868 NameOfXMMRegister(rm)); 1869 data++; 1870 } else if (*data == 0x7F) { 1871 AppendToBuffer("movdqa "); 1872 data++; 1873 int mod, regop, rm; 1874 get_modrm(*data, &mod, ®op, &rm); 1875 data += PrintRightXMMOperand(data); 1876 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1877 } else if (*data == 0x7E) { 1878 data++; 1879 int mod, regop, rm; 1880 get_modrm(*data, &mod, ®op, &rm); 1881 AppendToBuffer("movd "); 1882 data += PrintRightOperand(data); 1883 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1884 } else if (*data == 0xDB) { 1885 data++; 1886 int mod, regop, rm; 1887 get_modrm(*data, &mod, ®op, &rm); 1888 AppendToBuffer("pand %s,%s", 1889 NameOfXMMRegister(regop), 1890 NameOfXMMRegister(rm)); 1891 data++; 1892 } else if (*data == 0xE7) { 1893 data++; 1894 int mod, regop, rm; 1895 get_modrm(*data, &mod, ®op, &rm); 1896 if (mod == 3) { 1897 // movntdq 1898 UnimplementedInstruction(); 1899 } else { 1900 UnimplementedInstruction(); 1901 } 1902 } else if (*data == 0xEF) { 1903 data++; 1904 int mod, regop, rm; 1905 get_modrm(*data, &mod, ®op, &rm); 1906 AppendToBuffer("pxor %s,%s", 1907 NameOfXMMRegister(regop), 1908 NameOfXMMRegister(rm)); 1909 data++; 1910 } else if (*data == 0xEB) { 1911 data++; 1912 int mod, regop, rm; 1913 get_modrm(*data, &mod, ®op, &rm); 1914 AppendToBuffer("por %s,%s", 1915 NameOfXMMRegister(regop), 1916 NameOfXMMRegister(rm)); 1917 data++; 1918 } else if (*data == 0xB1) { 1919 data++; 1920 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data); 1921 } else { 1922 UnimplementedInstruction(); 1923 } 1924 } else { 1925 UnimplementedInstruction(); 1926 } 1927 break; 1928 1929 case 0xFE: 1930 { data++; 1931 int mod, regop, rm; 1932 get_modrm(*data, &mod, ®op, &rm); 1933 if (regop == ecx) { 1934 AppendToBuffer("dec_b "); 1935 data += PrintRightOperand(data); 1936 } else { 1937 UnimplementedInstruction(); 1938 } 1939 } 1940 break; 1941 1942 case 0x68: 1943 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1)); 1944 data += 5; 1945 break; 1946 1947 case 0x6A: 1948 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); 1949 data += 2; 1950 break; 1951 1952 case 0xA8: 1953 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1)); 1954 data += 2; 1955 break; 1956 1957 case 0xA9: 1958 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1)); 1959 data += 5; 1960 break; 1961 1962 case 0xD1: // fall through 1963 case 0xD3: // fall through 1964 case 0xC1: 1965 data += D1D3C1Instruction(data); 1966 break; 1967 1968 case 0xD8: // fall through 1969 case 0xD9: // fall through 1970 case 0xDA: // fall through 1971 case 0xDB: // fall through 1972 case 0xDC: // fall through 1973 case 0xDD: // fall through 1974 case 0xDE: // fall through 1975 case 0xDF: 1976 data += FPUInstruction(data); 1977 break; 1978 1979 case 0xEB: 1980 data += JumpShort(data); 1981 break; 1982 1983 case 0xF2: 1984 if (*(data+1) == 0x0F) { 1985 byte b2 = *(data+2); 1986 if (b2 == 0x11) { 1987 AppendToBuffer("movsd "); 1988 data += 3; 1989 int mod, regop, rm; 1990 get_modrm(*data, &mod, ®op, &rm); 1991 data += PrintRightXMMOperand(data); 1992 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1993 } else if (b2 == 0x10) { 1994 data += 3; 1995 int mod, regop, rm; 1996 get_modrm(*data, &mod, ®op, &rm); 1997 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); 1998 data += PrintRightXMMOperand(data); 1999 } else if (b2 == 0x5A) { 2000 data += 3; 2001 int mod, regop, rm; 2002 get_modrm(*data, &mod, ®op, &rm); 2003 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop)); 2004 data += PrintRightXMMOperand(data); 2005 } else { 2006 const char* mnem = "?"; 2007 switch (b2) { 2008 case 0x2A: 2009 mnem = "cvtsi2sd"; 2010 break; 2011 case 0x2C: 2012 mnem = "cvttsd2si"; 2013 break; 2014 case 0x2D: 2015 mnem = "cvtsd2si"; 2016 break; 2017 case 0x51: 2018 mnem = "sqrtsd"; 2019 break; 2020 case 0x58: 2021 mnem = "addsd"; 2022 break; 2023 case 0x59: 2024 mnem = "mulsd"; 2025 break; 2026 case 0x5C: 2027 mnem = "subsd"; 2028 break; 2029 case 0x5D: 2030 mnem = "minsd"; 2031 break; 2032 case 0x5E: 2033 mnem = "divsd"; 2034 break; 2035 case 0x5F: 2036 mnem = "maxsd"; 2037 break; 2038 } 2039 data += 3; 2040 int mod, regop, rm; 2041 get_modrm(*data, &mod, ®op, &rm); 2042 if (b2 == 0x2A) { 2043 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2044 data += PrintRightOperand(data); 2045 } else if (b2 == 0x2C || b2 == 0x2D) { 2046 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 2047 data += PrintRightXMMOperand(data); 2048 } else if (b2 == 0xC2) { 2049 // Intel manual 2A, Table 3-18. 2050 const char* const pseudo_op[] = { 2051 "cmpeqsd", 2052 "cmpltsd", 2053 "cmplesd", 2054 "cmpunordsd", 2055 "cmpneqsd", 2056 "cmpnltsd", 2057 "cmpnlesd", 2058 "cmpordsd" 2059 }; 2060 AppendToBuffer("%s %s,%s", 2061 pseudo_op[data[1]], 2062 NameOfXMMRegister(regop), 2063 NameOfXMMRegister(rm)); 2064 data += 2; 2065 } else { 2066 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2067 data += PrintRightXMMOperand(data); 2068 } 2069 } 2070 } else { 2071 UnimplementedInstruction(); 2072 } 2073 break; 2074 2075 case 0xF3: 2076 if (*(data+1) == 0x0F) { 2077 byte b2 = *(data+2); 2078 if (b2 == 0x11) { 2079 AppendToBuffer("movss "); 2080 data += 3; 2081 int mod, regop, rm; 2082 get_modrm(*data, &mod, ®op, &rm); 2083 data += PrintRightXMMOperand(data); 2084 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 2085 } else if (b2 == 0x10) { 2086 data += 3; 2087 int mod, regop, rm; 2088 get_modrm(*data, &mod, ®op, &rm); 2089 AppendToBuffer("movss %s,", NameOfXMMRegister(regop)); 2090 data += PrintRightXMMOperand(data); 2091 } else if (b2 == 0x5A) { 2092 data += 3; 2093 int mod, regop, rm; 2094 get_modrm(*data, &mod, ®op, &rm); 2095 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); 2096 data += PrintRightXMMOperand(data); 2097 } else if (b2 == 0x6F) { 2098 data += 3; 2099 int mod, regop, rm; 2100 get_modrm(*data, &mod, ®op, &rm); 2101 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop)); 2102 data += PrintRightXMMOperand(data); 2103 } else if (b2 == 0x7F) { 2104 AppendToBuffer("movdqu "); 2105 data += 3; 2106 int mod, regop, rm; 2107 get_modrm(*data, &mod, ®op, &rm); 2108 data += PrintRightXMMOperand(data); 2109 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 2110 } else if (b2 == 0xB8) { 2111 data += 3; 2112 int mod, regop, rm; 2113 get_modrm(*data, &mod, ®op, &rm); 2114 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop)); 2115 data += PrintRightOperand(data); 2116 } else if (b2 == 0xBC) { 2117 data += 3; 2118 int mod, regop, rm; 2119 get_modrm(*data, &mod, ®op, &rm); 2120 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop)); 2121 data += PrintRightOperand(data); 2122 } else if (b2 == 0xBD) { 2123 data += 3; 2124 int mod, regop, rm; 2125 get_modrm(*data, &mod, ®op, &rm); 2126 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop)); 2127 data += PrintRightOperand(data); 2128 } else { 2129 const char* mnem = "?"; 2130 switch (b2) { 2131 case 0x2A: 2132 mnem = "cvtsi2ss"; 2133 break; 2134 case 0x2C: 2135 mnem = "cvttss2si"; 2136 break; 2137 case 0x2D: 2138 mnem = "cvtss2si"; 2139 break; 2140 case 0x51: 2141 mnem = "sqrtss"; 2142 break; 2143 case 0x58: 2144 mnem = "addss"; 2145 break; 2146 case 0x59: 2147 mnem = "mulss"; 2148 break; 2149 case 0x5C: 2150 mnem = "subss"; 2151 break; 2152 case 0x5D: 2153 mnem = "minss"; 2154 break; 2155 case 0x5E: 2156 mnem = "divss"; 2157 break; 2158 case 0x5F: 2159 mnem = "maxss"; 2160 break; 2161 } 2162 data += 3; 2163 int mod, regop, rm; 2164 get_modrm(*data, &mod, ®op, &rm); 2165 if (b2 == 0x2A) { 2166 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2167 data += PrintRightOperand(data); 2168 } else if (b2 == 0x2C || b2 == 0x2D) { 2169 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 2170 data += PrintRightXMMOperand(data); 2171 } else if (b2 == 0xC2) { 2172 // Intel manual 2A, Table 3-18. 2173 const char* const pseudo_op[] = { 2174 "cmpeqss", "cmpltss", "cmpless", "cmpunordss", 2175 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"}; 2176 AppendToBuffer("%s %s,%s", pseudo_op[data[1]], 2177 NameOfXMMRegister(regop), NameOfXMMRegister(rm)); 2178 data += 2; 2179 } else { 2180 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2181 data += PrintRightXMMOperand(data); 2182 } 2183 } 2184 } else if (*(data+1) == 0xA5) { 2185 data += 2; 2186 AppendToBuffer("rep_movs"); 2187 } else if (*(data+1) == 0xAB) { 2188 data += 2; 2189 AppendToBuffer("rep_stos"); 2190 } else { 2191 UnimplementedInstruction(); 2192 } 2193 break; 2194 2195 case 0xF7: 2196 data += F7Instruction(data); 2197 break; 2198 2199 default: 2200 UnimplementedInstruction(); 2201 } 2202 } 2203 2204 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { 2205 tmp_buffer_[tmp_buffer_pos_] = '\0'; 2206 } 2207 2208 int instr_len = data - instr; 2209 if (instr_len == 0) { 2210 printf("%02x", *data); 2211 } 2212 DCHECK(instr_len > 0); // Ensure progress. 2213 2214 int outp = 0; 2215 // Instruction bytes. 2216 for (byte* bp = instr; bp < data; bp++) { 2217 outp += v8::internal::SNPrintF(out_buffer + outp, 2218 "%02x", 2219 *bp); 2220 } 2221 for (int i = 6 - instr_len; i >= 0; i--) { 2222 outp += v8::internal::SNPrintF(out_buffer + outp, " "); 2223 } 2224 2225 outp += v8::internal::SNPrintF(out_buffer + outp, 2226 " %s", 2227 tmp_buffer_.start()); 2228 return instr_len; 2229} // NOLINT (function is too long) 2230 2231 2232//------------------------------------------------------------------------------ 2233 2234 2235static const char* const cpu_regs[8] = { 2236 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 2237}; 2238 2239 2240static const char* const byte_cpu_regs[8] = { 2241 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 2242}; 2243 2244 2245static const char* const xmm_regs[8] = { 2246 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" 2247}; 2248 2249 2250const char* NameConverter::NameOfAddress(byte* addr) const { 2251 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); 2252 return tmp_buffer_.start(); 2253} 2254 2255 2256const char* NameConverter::NameOfConstant(byte* addr) const { 2257 return NameOfAddress(addr); 2258} 2259 2260 2261const char* NameConverter::NameOfCPURegister(int reg) const { 2262 if (0 <= reg && reg < 8) return cpu_regs[reg]; 2263 return "noreg"; 2264} 2265 2266 2267const char* NameConverter::NameOfByteCPURegister(int reg) const { 2268 if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; 2269 return "noreg"; 2270} 2271 2272 2273const char* NameConverter::NameOfXMMRegister(int reg) const { 2274 if (0 <= reg && reg < 8) return xmm_regs[reg]; 2275 return "noxmmreg"; 2276} 2277 2278 2279const char* NameConverter::NameInCode(byte* addr) const { 2280 // IA32 does not embed debug strings at the moment. 2281 UNREACHABLE(); 2282 return ""; 2283} 2284 2285 2286//------------------------------------------------------------------------------ 2287 2288Disassembler::Disassembler(const NameConverter& converter) 2289 : converter_(converter) {} 2290 2291 2292Disassembler::~Disassembler() {} 2293 2294 2295int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 2296 byte* instruction) { 2297 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/); 2298 return d.InstructionDecode(buffer, instruction); 2299} 2300 2301 2302// The IA-32 assembler does not currently use constant pools. 2303int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } 2304 2305 2306/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { 2307 NameConverter converter; 2308 Disassembler d(converter); 2309 for (byte* pc = begin; pc < end;) { 2310 v8::internal::EmbeddedVector<char, 128> buffer; 2311 buffer[0] = '\0'; 2312 byte* prev_pc = pc; 2313 pc += d.InstructionDecode(buffer, pc); 2314 fprintf(f, "%p", static_cast<void*>(prev_pc)); 2315 fprintf(f, " "); 2316 2317 for (byte* bp = prev_pc; bp < pc; bp++) { 2318 fprintf(f, "%02x", *bp); 2319 } 2320 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { 2321 fprintf(f, " "); 2322 } 2323 fprintf(f, " %s\n", buffer.start()); 2324 } 2325} 2326 2327 2328} // namespace disasm 2329 2330#endif // V8_TARGET_ARCH_IA32 2331