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