1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <assert.h> 29#include <stdio.h> 30#include <stdarg.h> 31 32#include "v8.h" 33 34#if V8_TARGET_ARCH_IA32 35 36#include "disasm.h" 37 38namespace disasm { 39 40enum OperandOrder { 41 UNSET_OP_ORDER = 0, 42 REG_OPER_OP_ORDER, 43 OPER_REG_OP_ORDER 44}; 45 46 47//------------------------------------------------------------------ 48// Tables 49//------------------------------------------------------------------ 50struct ByteMnemonic { 51 int b; // -1 terminates, otherwise must be in range (0..255) 52 const char* mnem; 53 OperandOrder op_order_; 54}; 55 56 57static const ByteMnemonic two_operands_instr[] = { 58 {0x01, "add", OPER_REG_OP_ORDER}, 59 {0x03, "add", REG_OPER_OP_ORDER}, 60 {0x09, "or", OPER_REG_OP_ORDER}, 61 {0x0B, "or", REG_OPER_OP_ORDER}, 62 {0x1B, "sbb", REG_OPER_OP_ORDER}, 63 {0x21, "and", OPER_REG_OP_ORDER}, 64 {0x23, "and", REG_OPER_OP_ORDER}, 65 {0x29, "sub", OPER_REG_OP_ORDER}, 66 {0x2A, "subb", REG_OPER_OP_ORDER}, 67 {0x2B, "sub", REG_OPER_OP_ORDER}, 68 {0x31, "xor", OPER_REG_OP_ORDER}, 69 {0x33, "xor", REG_OPER_OP_ORDER}, 70 {0x38, "cmpb", OPER_REG_OP_ORDER}, 71 {0x3A, "cmpb", REG_OPER_OP_ORDER}, 72 {0x3B, "cmp", REG_OPER_OP_ORDER}, 73 {0x84, "test_b", REG_OPER_OP_ORDER}, 74 {0x85, "test", REG_OPER_OP_ORDER}, 75 {0x87, "xchg", REG_OPER_OP_ORDER}, 76 {0x8A, "mov_b", REG_OPER_OP_ORDER}, 77 {0x8B, "mov", REG_OPER_OP_ORDER}, 78 {0x8D, "lea", REG_OPER_OP_ORDER}, 79 {-1, "", UNSET_OP_ORDER} 80}; 81 82 83static const ByteMnemonic zero_operands_instr[] = { 84 {0xC3, "ret", UNSET_OP_ORDER}, 85 {0xC9, "leave", UNSET_OP_ORDER}, 86 {0x90, "nop", UNSET_OP_ORDER}, 87 {0xF4, "hlt", UNSET_OP_ORDER}, 88 {0xCC, "int3", UNSET_OP_ORDER}, 89 {0x60, "pushad", UNSET_OP_ORDER}, 90 {0x61, "popad", UNSET_OP_ORDER}, 91 {0x9C, "pushfd", UNSET_OP_ORDER}, 92 {0x9D, "popfd", UNSET_OP_ORDER}, 93 {0x9E, "sahf", UNSET_OP_ORDER}, 94 {0x99, "cdq", UNSET_OP_ORDER}, 95 {0x9B, "fwait", UNSET_OP_ORDER}, 96 {0xFC, "cld", UNSET_OP_ORDER}, 97 {0xAB, "stos", UNSET_OP_ORDER}, 98 {-1, "", UNSET_OP_ORDER} 99}; 100 101 102static const ByteMnemonic call_jump_instr[] = { 103 {0xE8, "call", UNSET_OP_ORDER}, 104 {0xE9, "jmp", UNSET_OP_ORDER}, 105 {-1, "", UNSET_OP_ORDER} 106}; 107 108 109static const ByteMnemonic short_immediate_instr[] = { 110 {0x05, "add", UNSET_OP_ORDER}, 111 {0x0D, "or", UNSET_OP_ORDER}, 112 {0x15, "adc", UNSET_OP_ORDER}, 113 {0x25, "and", UNSET_OP_ORDER}, 114 {0x2D, "sub", UNSET_OP_ORDER}, 115 {0x35, "xor", UNSET_OP_ORDER}, 116 {0x3D, "cmp", UNSET_OP_ORDER}, 117 {-1, "", UNSET_OP_ORDER} 118}; 119 120 121// Generally we don't want to generate these because they are subject to partial 122// register stalls. They are included for completeness and because the cmp 123// variant is used by the RecordWrite stub. Because it does not update the 124// register it is not subject to partial register stalls. 125static ByteMnemonic byte_immediate_instr[] = { 126 {0x0c, "or", UNSET_OP_ORDER}, 127 {0x24, "and", UNSET_OP_ORDER}, 128 {0x34, "xor", UNSET_OP_ORDER}, 129 {0x3c, "cmp", UNSET_OP_ORDER}, 130 {-1, "", UNSET_OP_ORDER} 131}; 132 133 134static const char* const jump_conditional_mnem[] = { 135 /*0*/ "jo", "jno", "jc", "jnc", 136 /*4*/ "jz", "jnz", "jna", "ja", 137 /*8*/ "js", "jns", "jpe", "jpo", 138 /*12*/ "jl", "jnl", "jng", "jg" 139}; 140 141 142static const char* const set_conditional_mnem[] = { 143 /*0*/ "seto", "setno", "setc", "setnc", 144 /*4*/ "setz", "setnz", "setna", "seta", 145 /*8*/ "sets", "setns", "setpe", "setpo", 146 /*12*/ "setl", "setnl", "setng", "setg" 147}; 148 149 150static const char* const conditional_move_mnem[] = { 151 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc", 152 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova", 153 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo", 154 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg" 155}; 156 157 158enum InstructionType { 159 NO_INSTR, 160 ZERO_OPERANDS_INSTR, 161 TWO_OPERANDS_INSTR, 162 JUMP_CONDITIONAL_SHORT_INSTR, 163 REGISTER_INSTR, 164 MOVE_REG_INSTR, 165 CALL_JUMP_INSTR, 166 SHORT_IMMEDIATE_INSTR, 167 BYTE_IMMEDIATE_INSTR 168}; 169 170 171struct InstructionDesc { 172 const char* mnem; 173 InstructionType type; 174 OperandOrder op_order_; 175}; 176 177 178class InstructionTable { 179 public: 180 InstructionTable(); 181 const InstructionDesc& Get(byte x) const { return instructions_[x]; } 182 static InstructionTable* get_instance() { 183 static InstructionTable table; 184 return &table; 185 } 186 187 private: 188 InstructionDesc instructions_[256]; 189 void Clear(); 190 void Init(); 191 void CopyTable(const ByteMnemonic bm[], InstructionType type); 192 void SetTableRange(InstructionType type, 193 byte start, 194 byte end, 195 const char* mnem); 196 void AddJumpConditionalShort(); 197}; 198 199 200InstructionTable::InstructionTable() { 201 Clear(); 202 Init(); 203} 204 205 206void InstructionTable::Clear() { 207 for (int i = 0; i < 256; i++) { 208 instructions_[i].mnem = ""; 209 instructions_[i].type = NO_INSTR; 210 instructions_[i].op_order_ = UNSET_OP_ORDER; 211 } 212} 213 214 215void InstructionTable::Init() { 216 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); 217 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); 218 CopyTable(call_jump_instr, CALL_JUMP_INSTR); 219 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); 220 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR); 221 AddJumpConditionalShort(); 222 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc"); 223 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec"); 224 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push"); 225 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop"); 226 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. 227 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); 228} 229 230 231void InstructionTable::CopyTable(const ByteMnemonic bm[], 232 InstructionType type) { 233 for (int i = 0; bm[i].b >= 0; i++) { 234 InstructionDesc* id = &instructions_[bm[i].b]; 235 id->mnem = bm[i].mnem; 236 id->op_order_ = bm[i].op_order_; 237 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. 238 id->type = type; 239 } 240} 241 242 243void InstructionTable::SetTableRange(InstructionType type, 244 byte start, 245 byte end, 246 const char* mnem) { 247 for (byte b = start; b <= end; b++) { 248 InstructionDesc* id = &instructions_[b]; 249 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. 250 id->mnem = mnem; 251 id->type = type; 252 } 253} 254 255 256void InstructionTable::AddJumpConditionalShort() { 257 for (byte b = 0x70; b <= 0x7F; b++) { 258 InstructionDesc* id = &instructions_[b]; 259 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. 260 id->mnem = jump_conditional_mnem[b & 0x0F]; 261 id->type = JUMP_CONDITIONAL_SHORT_INSTR; 262 } 263} 264 265 266// The IA32 disassembler implementation. 267class DisassemblerIA32 { 268 public: 269 DisassemblerIA32(const NameConverter& converter, 270 bool abort_on_unimplemented = true) 271 : converter_(converter), 272 instruction_table_(InstructionTable::get_instance()), 273 tmp_buffer_pos_(0), 274 abort_on_unimplemented_(abort_on_unimplemented) { 275 tmp_buffer_[0] = '\0'; 276 } 277 278 virtual ~DisassemblerIA32() {} 279 280 // Writes one disassembled instruction into 'buffer' (0-terminated). 281 // Returns the length of the disassembled machine instruction in bytes. 282 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); 283 284 private: 285 const NameConverter& converter_; 286 InstructionTable* instruction_table_; 287 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; 288 unsigned int tmp_buffer_pos_; 289 bool abort_on_unimplemented_; 290 291 enum { 292 eax = 0, 293 ecx = 1, 294 edx = 2, 295 ebx = 3, 296 esp = 4, 297 ebp = 5, 298 esi = 6, 299 edi = 7 300 }; 301 302 303 enum ShiftOpcodeExtension { 304 kROL = 0, 305 kROR = 1, 306 kRCL = 2, 307 kRCR = 3, 308 kSHL = 4, 309 KSHR = 5, 310 kSAR = 7 311 }; 312 313 314 const char* NameOfCPURegister(int reg) const { 315 return converter_.NameOfCPURegister(reg); 316 } 317 318 319 const char* NameOfByteCPURegister(int reg) const { 320 return converter_.NameOfByteCPURegister(reg); 321 } 322 323 324 const char* NameOfXMMRegister(int reg) const { 325 return converter_.NameOfXMMRegister(reg); 326 } 327 328 329 const char* NameOfAddress(byte* addr) const { 330 return converter_.NameOfAddress(addr); 331 } 332 333 334 // Disassembler helper functions. 335 static void get_modrm(byte data, int* mod, int* regop, int* rm) { 336 *mod = (data >> 6) & 3; 337 *regop = (data & 0x38) >> 3; 338 *rm = data & 7; 339 } 340 341 342 static void get_sib(byte data, int* scale, int* index, int* base) { 343 *scale = (data >> 6) & 3; 344 *index = (data >> 3) & 7; 345 *base = data & 7; 346 } 347 348 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const; 349 350 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); 351 int PrintRightOperand(byte* modrmp); 352 int PrintRightByteOperand(byte* modrmp); 353 int PrintRightXMMOperand(byte* modrmp); 354 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); 355 int PrintImmediateOp(byte* data); 356 int F7Instruction(byte* data); 357 int D1D3C1Instruction(byte* data); 358 int JumpShort(byte* data); 359 int JumpConditional(byte* data, const char* comment); 360 int JumpConditionalShort(byte* data, const char* comment); 361 int SetCC(byte* data); 362 int CMov(byte* data); 363 int FPUInstruction(byte* data); 364 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); 365 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); 366 void AppendToBuffer(const char* format, ...); 367 368 369 void UnimplementedInstruction() { 370 if (abort_on_unimplemented_) { 371 UNIMPLEMENTED(); 372 } else { 373 AppendToBuffer("'Unimplemented Instruction'"); 374 } 375 } 376}; 377 378 379void DisassemblerIA32::AppendToBuffer(const char* format, ...) { 380 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; 381 va_list args; 382 va_start(args, format); 383 int result = v8::internal::OS::VSNPrintF(buf, format, args); 384 va_end(args); 385 tmp_buffer_pos_ += result; 386} 387 388int DisassemblerIA32::PrintRightOperandHelper( 389 byte* modrmp, 390 RegisterNameMapping direct_register_name) { 391 int mod, regop, rm; 392 get_modrm(*modrmp, &mod, ®op, &rm); 393 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : 394 &DisassemblerIA32::NameOfCPURegister; 395 switch (mod) { 396 case 0: 397 if (rm == ebp) { 398 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); 399 AppendToBuffer("[0x%x]", disp); 400 return 5; 401 } else if (rm == esp) { 402 byte sib = *(modrmp + 1); 403 int scale, index, base; 404 get_sib(sib, &scale, &index, &base); 405 if (index == esp && base == esp && scale == 0 /*times_1*/) { 406 AppendToBuffer("[%s]", (this->*register_name)(rm)); 407 return 2; 408 } else if (base == ebp) { 409 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); 410 AppendToBuffer("[%s*%d+0x%x]", 411 (this->*register_name)(index), 412 1 << scale, 413 disp); 414 return 6; 415 } else if (index != esp && base != ebp) { 416 // [base+index*scale] 417 AppendToBuffer("[%s+%s*%d]", 418 (this->*register_name)(base), 419 (this->*register_name)(index), 420 1 << scale); 421 return 2; 422 } else { 423 UnimplementedInstruction(); 424 return 1; 425 } 426 } else { 427 AppendToBuffer("[%s]", (this->*register_name)(rm)); 428 return 1; 429 } 430 break; 431 case 1: // fall through 432 case 2: 433 if (rm == esp) { 434 byte sib = *(modrmp + 1); 435 int scale, index, base; 436 get_sib(sib, &scale, &index, &base); 437 int disp = 438 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2); 439 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { 440 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); 441 } else { 442 AppendToBuffer("[%s+%s*%d+0x%x]", 443 (this->*register_name)(base), 444 (this->*register_name)(index), 445 1 << scale, 446 disp); 447 } 448 return mod == 2 ? 6 : 3; 449 } else { 450 // No sib. 451 int disp = 452 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1); 453 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); 454 return mod == 2 ? 5 : 2; 455 } 456 break; 457 case 3: 458 AppendToBuffer("%s", (this->*register_name)(rm)); 459 return 1; 460 default: 461 UnimplementedInstruction(); 462 return 1; 463 } 464 UNREACHABLE(); 465} 466 467 468int DisassemblerIA32::PrintRightOperand(byte* modrmp) { 469 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); 470} 471 472 473int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { 474 return PrintRightOperandHelper(modrmp, 475 &DisassemblerIA32::NameOfByteCPURegister); 476} 477 478 479int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) { 480 return PrintRightOperandHelper(modrmp, 481 &DisassemblerIA32::NameOfXMMRegister); 482} 483 484 485// Returns number of bytes used including the current *data. 486// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. 487int DisassemblerIA32::PrintOperands(const char* mnem, 488 OperandOrder op_order, 489 byte* data) { 490 byte modrm = *data; 491 int mod, regop, rm; 492 get_modrm(modrm, &mod, ®op, &rm); 493 int advance = 0; 494 switch (op_order) { 495 case REG_OPER_OP_ORDER: { 496 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 497 advance = PrintRightOperand(data); 498 break; 499 } 500 case OPER_REG_OP_ORDER: { 501 AppendToBuffer("%s ", mnem); 502 advance = PrintRightOperand(data); 503 AppendToBuffer(",%s", NameOfCPURegister(regop)); 504 break; 505 } 506 default: 507 UNREACHABLE(); 508 break; 509 } 510 return advance; 511} 512 513 514// Returns number of bytes used by machine instruction, including *data byte. 515// Writes immediate instructions to 'tmp_buffer_'. 516int DisassemblerIA32::PrintImmediateOp(byte* data) { 517 bool sign_extension_bit = (*data & 0x02) != 0; 518 byte modrm = *(data+1); 519 int mod, regop, rm; 520 get_modrm(modrm, &mod, ®op, &rm); 521 const char* mnem = "Imm???"; 522 switch (regop) { 523 case 0: mnem = "add"; break; 524 case 1: mnem = "or"; break; 525 case 2: mnem = "adc"; break; 526 case 4: mnem = "and"; break; 527 case 5: mnem = "sub"; break; 528 case 6: mnem = "xor"; break; 529 case 7: mnem = "cmp"; break; 530 default: UnimplementedInstruction(); 531 } 532 AppendToBuffer("%s ", mnem); 533 int count = PrintRightOperand(data+1); 534 if (sign_extension_bit) { 535 AppendToBuffer(",0x%x", *(data + 1 + count)); 536 return 1 + count + 1 /*int8*/; 537 } else { 538 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); 539 return 1 + count + 4 /*int32_t*/; 540 } 541} 542 543 544// Returns number of bytes used, including *data. 545int DisassemblerIA32::F7Instruction(byte* data) { 546 ASSERT_EQ(0xF7, *data); 547 byte modrm = *(data+1); 548 int mod, regop, rm; 549 get_modrm(modrm, &mod, ®op, &rm); 550 if (mod == 3 && regop != 0) { 551 const char* mnem = NULL; 552 switch (regop) { 553 case 2: mnem = "not"; break; 554 case 3: mnem = "neg"; break; 555 case 4: mnem = "mul"; break; 556 case 5: mnem = "imul"; break; 557 case 7: mnem = "idiv"; break; 558 default: UnimplementedInstruction(); 559 } 560 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm)); 561 return 2; 562 } else if (mod == 3 && regop == eax) { 563 int32_t imm = *reinterpret_cast<int32_t*>(data+2); 564 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm); 565 return 6; 566 } else if (regop == eax) { 567 AppendToBuffer("test "); 568 int count = PrintRightOperand(data+1); 569 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count); 570 AppendToBuffer(",0x%x", imm); 571 return 1+count+4 /*int32_t*/; 572 } else { 573 UnimplementedInstruction(); 574 return 2; 575 } 576} 577 578 579int DisassemblerIA32::D1D3C1Instruction(byte* data) { 580 byte op = *data; 581 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1); 582 byte modrm = *(data+1); 583 int mod, regop, rm; 584 get_modrm(modrm, &mod, ®op, &rm); 585 int imm8 = -1; 586 int num_bytes = 2; 587 if (mod == 3) { 588 const char* mnem = NULL; 589 switch (regop) { 590 case kROL: mnem = "rol"; break; 591 case kROR: mnem = "ror"; break; 592 case kRCL: mnem = "rcl"; break; 593 case kRCR: mnem = "rcr"; break; 594 case kSHL: mnem = "shl"; break; 595 case KSHR: mnem = "shr"; break; 596 case kSAR: mnem = "sar"; break; 597 default: UnimplementedInstruction(); 598 } 599 if (op == 0xD1) { 600 imm8 = 1; 601 } else if (op == 0xC1) { 602 imm8 = *(data+2); 603 num_bytes = 3; 604 } else if (op == 0xD3) { 605 // Shift/rotate by cl. 606 } 607 ASSERT_NE(NULL, mnem); 608 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm)); 609 if (imm8 > 0) { 610 AppendToBuffer("%d", imm8); 611 } else { 612 AppendToBuffer("cl"); 613 } 614 } else { 615 UnimplementedInstruction(); 616 } 617 return num_bytes; 618} 619 620 621// Returns number of bytes used, including *data. 622int DisassemblerIA32::JumpShort(byte* data) { 623 ASSERT_EQ(0xEB, *data); 624 byte b = *(data+1); 625 byte* dest = data + static_cast<int8_t>(b) + 2; 626 AppendToBuffer("jmp %s", NameOfAddress(dest)); 627 return 2; 628} 629 630 631// Returns number of bytes used, including *data. 632int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { 633 ASSERT_EQ(0x0F, *data); 634 byte cond = *(data+1) & 0x0F; 635 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; 636 const char* mnem = jump_conditional_mnem[cond]; 637 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 638 if (comment != NULL) { 639 AppendToBuffer(", %s", comment); 640 } 641 return 6; // includes 0x0F 642} 643 644 645// Returns number of bytes used, including *data. 646int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { 647 byte cond = *data & 0x0F; 648 byte b = *(data+1); 649 byte* dest = data + static_cast<int8_t>(b) + 2; 650 const char* mnem = jump_conditional_mnem[cond]; 651 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 652 if (comment != NULL) { 653 AppendToBuffer(", %s", comment); 654 } 655 return 2; 656} 657 658 659// Returns number of bytes used, including *data. 660int DisassemblerIA32::SetCC(byte* data) { 661 ASSERT_EQ(0x0F, *data); 662 byte cond = *(data+1) & 0x0F; 663 const char* mnem = set_conditional_mnem[cond]; 664 AppendToBuffer("%s ", mnem); 665 PrintRightByteOperand(data+2); 666 return 3; // Includes 0x0F. 667} 668 669 670// Returns number of bytes used, including *data. 671int DisassemblerIA32::CMov(byte* data) { 672 ASSERT_EQ(0x0F, *data); 673 byte cond = *(data + 1) & 0x0F; 674 const char* mnem = conditional_move_mnem[cond]; 675 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); 676 return 2 + op_size; // includes 0x0F 677} 678 679 680// Returns number of bytes used, including *data. 681int DisassemblerIA32::FPUInstruction(byte* data) { 682 byte escape_opcode = *data; 683 ASSERT_EQ(0xD8, escape_opcode & 0xF8); 684 byte modrm_byte = *(data+1); 685 686 if (modrm_byte >= 0xC0) { 687 return RegisterFPUInstruction(escape_opcode, modrm_byte); 688 } else { 689 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); 690 } 691} 692 693int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, 694 int modrm_byte, 695 byte* modrm_start) { 696 const char* mnem = "?"; 697 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. 698 switch (escape_opcode) { 699 case 0xD9: switch (regop) { 700 case 0: mnem = "fld_s"; break; 701 case 3: mnem = "fstp_s"; break; 702 case 7: mnem = "fstcw"; break; 703 default: UnimplementedInstruction(); 704 } 705 break; 706 707 case 0xDB: switch (regop) { 708 case 0: mnem = "fild_s"; break; 709 case 1: mnem = "fisttp_s"; break; 710 case 2: mnem = "fist_s"; break; 711 case 3: mnem = "fistp_s"; break; 712 default: UnimplementedInstruction(); 713 } 714 break; 715 716 case 0xDD: switch (regop) { 717 case 0: mnem = "fld_d"; break; 718 case 1: mnem = "fisttp_d"; break; 719 case 2: mnem = "fst_d"; break; 720 case 3: mnem = "fstp_d"; break; 721 default: UnimplementedInstruction(); 722 } 723 break; 724 725 case 0xDF: switch (regop) { 726 case 5: mnem = "fild_d"; break; 727 case 7: mnem = "fistp_d"; break; 728 default: UnimplementedInstruction(); 729 } 730 break; 731 732 default: UnimplementedInstruction(); 733 } 734 AppendToBuffer("%s ", mnem); 735 int count = PrintRightOperand(modrm_start); 736 return count + 1; 737} 738 739int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, 740 byte modrm_byte) { 741 bool has_register = false; // Is the FPU register encoded in modrm_byte? 742 const char* mnem = "?"; 743 744 switch (escape_opcode) { 745 case 0xD8: 746 UnimplementedInstruction(); 747 break; 748 749 case 0xD9: 750 switch (modrm_byte & 0xF8) { 751 case 0xC0: 752 mnem = "fld"; 753 has_register = true; 754 break; 755 case 0xC8: 756 mnem = "fxch"; 757 has_register = true; 758 break; 759 default: 760 switch (modrm_byte) { 761 case 0xE0: mnem = "fchs"; break; 762 case 0xE1: mnem = "fabs"; break; 763 case 0xE4: mnem = "ftst"; break; 764 case 0xE8: mnem = "fld1"; break; 765 case 0xEB: mnem = "fldpi"; break; 766 case 0xED: mnem = "fldln2"; break; 767 case 0xEE: mnem = "fldz"; break; 768 case 0xF0: mnem = "f2xm1"; break; 769 case 0xF1: mnem = "fyl2x"; break; 770 case 0xF5: mnem = "fprem1"; break; 771 case 0xF7: mnem = "fincstp"; break; 772 case 0xF8: mnem = "fprem"; break; 773 case 0xFC: mnem = "frndint"; break; 774 case 0xFD: mnem = "fscale"; break; 775 case 0xFE: mnem = "fsin"; break; 776 case 0xFF: mnem = "fcos"; break; 777 default: UnimplementedInstruction(); 778 } 779 } 780 break; 781 782 case 0xDA: 783 if (modrm_byte == 0xE9) { 784 mnem = "fucompp"; 785 } else { 786 UnimplementedInstruction(); 787 } 788 break; 789 790 case 0xDB: 791 if ((modrm_byte & 0xF8) == 0xE8) { 792 mnem = "fucomi"; 793 has_register = true; 794 } else if (modrm_byte == 0xE2) { 795 mnem = "fclex"; 796 } else if (modrm_byte == 0xE3) { 797 mnem = "fninit"; 798 } else { 799 UnimplementedInstruction(); 800 } 801 break; 802 803 case 0xDC: 804 has_register = true; 805 switch (modrm_byte & 0xF8) { 806 case 0xC0: mnem = "fadd"; break; 807 case 0xE8: mnem = "fsub"; break; 808 case 0xC8: mnem = "fmul"; break; 809 case 0xF8: mnem = "fdiv"; break; 810 default: UnimplementedInstruction(); 811 } 812 break; 813 814 case 0xDD: 815 has_register = true; 816 switch (modrm_byte & 0xF8) { 817 case 0xC0: mnem = "ffree"; break; 818 case 0xD8: mnem = "fstp"; break; 819 default: UnimplementedInstruction(); 820 } 821 break; 822 823 case 0xDE: 824 if (modrm_byte == 0xD9) { 825 mnem = "fcompp"; 826 } else { 827 has_register = true; 828 switch (modrm_byte & 0xF8) { 829 case 0xC0: mnem = "faddp"; break; 830 case 0xE8: mnem = "fsubp"; break; 831 case 0xC8: mnem = "fmulp"; break; 832 case 0xF8: mnem = "fdivp"; break; 833 default: UnimplementedInstruction(); 834 } 835 } 836 break; 837 838 case 0xDF: 839 if (modrm_byte == 0xE0) { 840 mnem = "fnstsw_ax"; 841 } else if ((modrm_byte & 0xF8) == 0xE8) { 842 mnem = "fucomip"; 843 has_register = true; 844 } 845 break; 846 847 default: UnimplementedInstruction(); 848 } 849 850 if (has_register) { 851 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); 852 } else { 853 AppendToBuffer("%s", mnem); 854 } 855 return 2; 856} 857 858 859// Mnemonics for instructions 0xF0 byte. 860// Returns NULL if the instruction is not handled here. 861static const char* F0Mnem(byte f0byte) { 862 switch (f0byte) { 863 case 0x18: return "prefetch"; 864 case 0xA2: return "cpuid"; 865 case 0x31: return "rdtsc"; 866 case 0xBE: return "movsx_b"; 867 case 0xBF: return "movsx_w"; 868 case 0xB6: return "movzx_b"; 869 case 0xB7: return "movzx_w"; 870 case 0xAF: return "imul"; 871 case 0xA5: return "shld"; 872 case 0xAD: return "shrd"; 873 case 0xAC: return "shrd"; // 3-operand version. 874 case 0xAB: return "bts"; 875 default: return NULL; 876 } 877} 878 879 880// Disassembled instruction '*instr' and writes it into 'out_buffer'. 881int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, 882 byte* instr) { 883 tmp_buffer_pos_ = 0; // starting to write as position 0 884 byte* data = instr; 885 // Check for hints. 886 const char* branch_hint = NULL; 887 // We use these two prefixes only with branch prediction 888 if (*data == 0x3E /*ds*/) { 889 branch_hint = "predicted taken"; 890 data++; 891 } else if (*data == 0x2E /*cs*/) { 892 branch_hint = "predicted not taken"; 893 data++; 894 } 895 bool processed = true; // Will be set to false if the current instruction 896 // is not in 'instructions' table. 897 const InstructionDesc& idesc = instruction_table_->Get(*data); 898 switch (idesc.type) { 899 case ZERO_OPERANDS_INSTR: 900 AppendToBuffer(idesc.mnem); 901 data++; 902 break; 903 904 case TWO_OPERANDS_INSTR: 905 data++; 906 data += PrintOperands(idesc.mnem, idesc.op_order_, data); 907 break; 908 909 case JUMP_CONDITIONAL_SHORT_INSTR: 910 data += JumpConditionalShort(data, branch_hint); 911 break; 912 913 case REGISTER_INSTR: 914 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); 915 data++; 916 break; 917 918 case MOVE_REG_INSTR: { 919 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); 920 AppendToBuffer("mov %s,%s", 921 NameOfCPURegister(*data & 0x07), 922 NameOfAddress(addr)); 923 data += 5; 924 break; 925 } 926 927 case CALL_JUMP_INSTR: { 928 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5; 929 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); 930 data += 5; 931 break; 932 } 933 934 case SHORT_IMMEDIATE_INSTR: { 935 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); 936 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr)); 937 data += 5; 938 break; 939 } 940 941 case BYTE_IMMEDIATE_INSTR: { 942 AppendToBuffer("%s al, 0x%x", idesc.mnem, data[1]); 943 data += 2; 944 break; 945 } 946 947 case NO_INSTR: 948 processed = false; 949 break; 950 951 default: 952 UNIMPLEMENTED(); // This type is not implemented. 953 } 954 //---------------------------- 955 if (!processed) { 956 switch (*data) { 957 case 0xC2: 958 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); 959 data += 3; 960 break; 961 962 case 0x69: // fall through 963 case 0x6B: 964 { int mod, regop, rm; 965 get_modrm(*(data+1), &mod, ®op, &rm); 966 int32_t imm = 967 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2); 968 AppendToBuffer("imul %s,%s,0x%x", 969 NameOfCPURegister(regop), 970 NameOfCPURegister(rm), 971 imm); 972 data += 2 + (*data == 0x6B ? 1 : 4); 973 } 974 break; 975 976 case 0xF6: 977 { data++; 978 int mod, regop, rm; 979 get_modrm(*data, &mod, ®op, &rm); 980 if (regop == eax) { 981 AppendToBuffer("test_b "); 982 data += PrintRightByteOperand(data); 983 int32_t imm = *data; 984 AppendToBuffer(",0x%x", imm); 985 data++; 986 } else { 987 UnimplementedInstruction(); 988 } 989 } 990 break; 991 992 case 0x81: // fall through 993 case 0x83: // 0x81 with sign extension bit set 994 data += PrintImmediateOp(data); 995 break; 996 997 case 0x0F: 998 { byte f0byte = data[1]; 999 const char* f0mnem = F0Mnem(f0byte); 1000 if (f0byte == 0x18) { 1001 int mod, regop, rm; 1002 get_modrm(*data, &mod, ®op, &rm); 1003 const char* suffix[] = {"nta", "1", "2", "3"}; 1004 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]); 1005 data += PrintRightOperand(data); 1006 } else if (f0byte == 0x1F && data[2] == 0) { 1007 AppendToBuffer("nop"); // 3 byte nop. 1008 data += 3; 1009 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) { 1010 AppendToBuffer("nop"); // 4 byte nop. 1011 data += 4; 1012 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 && 1013 data[4] == 0) { 1014 AppendToBuffer("nop"); // 5 byte nop. 1015 data += 5; 1016 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 && 1017 data[4] == 0 && data[5] == 0 && data[6] == 0) { 1018 AppendToBuffer("nop"); // 7 byte nop. 1019 data += 7; 1020 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 && 1021 data[4] == 0 && data[5] == 0 && data[6] == 0 && 1022 data[7] == 0) { 1023 AppendToBuffer("nop"); // 8 byte nop. 1024 data += 8; 1025 } else if (f0byte == 0xA2 || f0byte == 0x31) { 1026 AppendToBuffer("%s", f0mnem); 1027 data += 2; 1028 } else if (f0byte == 0x28) { 1029 data += 2; 1030 int mod, regop, rm; 1031 get_modrm(*data, &mod, ®op, &rm); 1032 AppendToBuffer("movaps %s,%s", 1033 NameOfXMMRegister(regop), 1034 NameOfXMMRegister(rm)); 1035 data++; 1036 } else if (f0byte == 0x57) { 1037 data += 2; 1038 int mod, regop, rm; 1039 get_modrm(*data, &mod, ®op, &rm); 1040 AppendToBuffer("xorps %s,%s", 1041 NameOfXMMRegister(regop), 1042 NameOfXMMRegister(rm)); 1043 data++; 1044 } else if (f0byte == 0x50) { 1045 data += 2; 1046 int mod, regop, rm; 1047 get_modrm(*data, &mod, ®op, &rm); 1048 AppendToBuffer("movmskps %s,%s", 1049 NameOfCPURegister(regop), 1050 NameOfXMMRegister(rm)); 1051 data++; 1052 } else if ((f0byte & 0xF0) == 0x80) { 1053 data += JumpConditional(data, branch_hint); 1054 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || 1055 f0byte == 0xB7 || f0byte == 0xAF) { 1056 data += 2; 1057 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); 1058 } else if ((f0byte & 0xF0) == 0x90) { 1059 data += SetCC(data); 1060 } else if ((f0byte & 0xF0) == 0x40) { 1061 data += CMov(data); 1062 } else { 1063 data += 2; 1064 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { 1065 // shrd, shld, bts 1066 AppendToBuffer("%s ", f0mnem); 1067 int mod, regop, rm; 1068 get_modrm(*data, &mod, ®op, &rm); 1069 data += PrintRightOperand(data); 1070 if (f0byte == 0xAB) { 1071 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1072 } else { 1073 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); 1074 } 1075 } else { 1076 UnimplementedInstruction(); 1077 } 1078 } 1079 } 1080 break; 1081 1082 case 0x8F: 1083 { data++; 1084 int mod, regop, rm; 1085 get_modrm(*data, &mod, ®op, &rm); 1086 if (regop == eax) { 1087 AppendToBuffer("pop "); 1088 data += PrintRightOperand(data); 1089 } 1090 } 1091 break; 1092 1093 case 0xFF: 1094 { data++; 1095 int mod, regop, rm; 1096 get_modrm(*data, &mod, ®op, &rm); 1097 const char* mnem = NULL; 1098 switch (regop) { 1099 case esi: mnem = "push"; break; 1100 case eax: mnem = "inc"; break; 1101 case ecx: mnem = "dec"; break; 1102 case edx: mnem = "call"; break; 1103 case esp: mnem = "jmp"; break; 1104 default: mnem = "???"; 1105 } 1106 AppendToBuffer("%s ", mnem); 1107 data += PrintRightOperand(data); 1108 } 1109 break; 1110 1111 case 0xC7: // imm32, fall through 1112 case 0xC6: // imm8 1113 { bool is_byte = *data == 0xC6; 1114 data++; 1115 if (is_byte) { 1116 AppendToBuffer("%s ", "mov_b"); 1117 data += PrintRightByteOperand(data); 1118 int32_t imm = *data; 1119 AppendToBuffer(",0x%x", imm); 1120 data++; 1121 } else { 1122 AppendToBuffer("%s ", "mov"); 1123 data += PrintRightOperand(data); 1124 int32_t imm = *reinterpret_cast<int32_t*>(data); 1125 AppendToBuffer(",0x%x", imm); 1126 data += 4; 1127 } 1128 } 1129 break; 1130 1131 case 0x80: 1132 { data++; 1133 int mod, regop, rm; 1134 get_modrm(*data, &mod, ®op, &rm); 1135 const char* mnem = NULL; 1136 switch (regop) { 1137 case 5: mnem = "subb"; break; 1138 case 7: mnem = "cmpb"; break; 1139 default: UnimplementedInstruction(); 1140 } 1141 AppendToBuffer("%s ", mnem); 1142 data += PrintRightByteOperand(data); 1143 int32_t imm = *data; 1144 AppendToBuffer(",0x%x", imm); 1145 data++; 1146 } 1147 break; 1148 1149 case 0x88: // 8bit, fall through 1150 case 0x89: // 32bit 1151 { bool is_byte = *data == 0x88; 1152 int mod, regop, rm; 1153 data++; 1154 get_modrm(*data, &mod, ®op, &rm); 1155 if (is_byte) { 1156 AppendToBuffer("%s ", "mov_b"); 1157 data += PrintRightByteOperand(data); 1158 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1159 } else { 1160 AppendToBuffer("%s ", "mov"); 1161 data += PrintRightOperand(data); 1162 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1163 } 1164 } 1165 break; 1166 1167 case 0x66: // prefix 1168 while (*data == 0x66) data++; 1169 if (*data == 0xf && data[1] == 0x1f) { 1170 AppendToBuffer("nop"); // 0x66 prefix 1171 } else if (*data == 0x90) { 1172 AppendToBuffer("nop"); // 0x66 prefix 1173 } else if (*data == 0x8B) { 1174 data++; 1175 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); 1176 } else if (*data == 0x89) { 1177 data++; 1178 int mod, regop, rm; 1179 get_modrm(*data, &mod, ®op, &rm); 1180 AppendToBuffer("mov_w "); 1181 data += PrintRightOperand(data); 1182 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1183 } else if (*data == 0x0F) { 1184 data++; 1185 if (*data == 0x38) { 1186 data++; 1187 if (*data == 0x17) { 1188 data++; 1189 int mod, regop, rm; 1190 get_modrm(*data, &mod, ®op, &rm); 1191 AppendToBuffer("ptest %s,%s", 1192 NameOfXMMRegister(regop), 1193 NameOfXMMRegister(rm)); 1194 data++; 1195 } else if (*data == 0x2A) { 1196 // movntdqa 1197 data++; 1198 int mod, regop, rm; 1199 get_modrm(*data, &mod, ®op, &rm); 1200 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop)); 1201 data += PrintRightOperand(data); 1202 } else { 1203 UnimplementedInstruction(); 1204 } 1205 } else if (*data == 0x3A) { 1206 data++; 1207 if (*data == 0x0B) { 1208 data++; 1209 int mod, regop, rm; 1210 get_modrm(*data, &mod, ®op, &rm); 1211 int8_t imm8 = static_cast<int8_t>(data[1]); 1212 AppendToBuffer("roundsd %s,%s,%d", 1213 NameOfXMMRegister(regop), 1214 NameOfXMMRegister(rm), 1215 static_cast<int>(imm8)); 1216 data += 2; 1217 } else if (*data == 0x16) { 1218 data++; 1219 int mod, regop, rm; 1220 get_modrm(*data, &mod, ®op, &rm); 1221 int8_t imm8 = static_cast<int8_t>(data[1]); 1222 AppendToBuffer("pextrd %s,%s,%d", 1223 NameOfCPURegister(regop), 1224 NameOfXMMRegister(rm), 1225 static_cast<int>(imm8)); 1226 data += 2; 1227 } else if (*data == 0x17) { 1228 data++; 1229 int mod, regop, rm; 1230 get_modrm(*data, &mod, ®op, &rm); 1231 int8_t imm8 = static_cast<int8_t>(data[1]); 1232 AppendToBuffer("extractps %s,%s,%d", 1233 NameOfCPURegister(regop), 1234 NameOfXMMRegister(rm), 1235 static_cast<int>(imm8)); 1236 data += 2; 1237 } else if (*data == 0x22) { 1238 data++; 1239 int mod, regop, rm; 1240 get_modrm(*data, &mod, ®op, &rm); 1241 int8_t imm8 = static_cast<int8_t>(data[1]); 1242 AppendToBuffer("pinsrd %s,%s,%d", 1243 NameOfXMMRegister(regop), 1244 NameOfCPURegister(rm), 1245 static_cast<int>(imm8)); 1246 data += 2; 1247 } else { 1248 UnimplementedInstruction(); 1249 } 1250 } else if (*data == 0x2E || *data == 0x2F) { 1251 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd"; 1252 data++; 1253 int mod, regop, rm; 1254 get_modrm(*data, &mod, ®op, &rm); 1255 if (mod == 0x3) { 1256 AppendToBuffer("%s %s,%s", mnem, 1257 NameOfXMMRegister(regop), 1258 NameOfXMMRegister(rm)); 1259 data++; 1260 } else { 1261 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1262 data += PrintRightOperand(data); 1263 } 1264 } else if (*data == 0x50) { 1265 data++; 1266 int mod, regop, rm; 1267 get_modrm(*data, &mod, ®op, &rm); 1268 AppendToBuffer("movmskpd %s,%s", 1269 NameOfCPURegister(regop), 1270 NameOfXMMRegister(rm)); 1271 data++; 1272 } else if (*data == 0x54) { 1273 data++; 1274 int mod, regop, rm; 1275 get_modrm(*data, &mod, ®op, &rm); 1276 AppendToBuffer("andpd %s,%s", 1277 NameOfXMMRegister(regop), 1278 NameOfXMMRegister(rm)); 1279 data++; 1280 } else if (*data == 0x56) { 1281 data++; 1282 int mod, regop, rm; 1283 get_modrm(*data, &mod, ®op, &rm); 1284 AppendToBuffer("orpd %s,%s", 1285 NameOfXMMRegister(regop), 1286 NameOfXMMRegister(rm)); 1287 data++; 1288 } else if (*data == 0x57) { 1289 data++; 1290 int mod, regop, rm; 1291 get_modrm(*data, &mod, ®op, &rm); 1292 AppendToBuffer("xorpd %s,%s", 1293 NameOfXMMRegister(regop), 1294 NameOfXMMRegister(rm)); 1295 data++; 1296 } else if (*data == 0x6E) { 1297 data++; 1298 int mod, regop, rm; 1299 get_modrm(*data, &mod, ®op, &rm); 1300 AppendToBuffer("movd %s,", NameOfXMMRegister(regop)); 1301 data += PrintRightOperand(data); 1302 } else if (*data == 0x6F) { 1303 data++; 1304 int mod, regop, rm; 1305 get_modrm(*data, &mod, ®op, &rm); 1306 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop)); 1307 data += PrintRightXMMOperand(data); 1308 } else if (*data == 0x70) { 1309 data++; 1310 int mod, regop, rm; 1311 get_modrm(*data, &mod, ®op, &rm); 1312 int8_t imm8 = static_cast<int8_t>(data[1]); 1313 AppendToBuffer("pshufd %s,%s,%d", 1314 NameOfXMMRegister(regop), 1315 NameOfXMMRegister(rm), 1316 static_cast<int>(imm8)); 1317 data += 2; 1318 } else if (*data == 0x76) { 1319 data++; 1320 int mod, regop, rm; 1321 get_modrm(*data, &mod, ®op, &rm); 1322 AppendToBuffer("pcmpeqd %s,%s", 1323 NameOfXMMRegister(regop), 1324 NameOfXMMRegister(rm)); 1325 data++; 1326 } else if (*data == 0x90) { 1327 data++; 1328 AppendToBuffer("nop"); // 2 byte nop. 1329 } else if (*data == 0xF3) { 1330 data++; 1331 int mod, regop, rm; 1332 get_modrm(*data, &mod, ®op, &rm); 1333 AppendToBuffer("psllq %s,%s", 1334 NameOfXMMRegister(regop), 1335 NameOfXMMRegister(rm)); 1336 data++; 1337 } else if (*data == 0x73) { 1338 data++; 1339 int mod, regop, rm; 1340 get_modrm(*data, &mod, ®op, &rm); 1341 int8_t imm8 = static_cast<int8_t>(data[1]); 1342 ASSERT(regop == esi || regop == edx); 1343 AppendToBuffer("%s %s,%d", 1344 (regop == esi) ? "psllq" : "psrlq", 1345 NameOfXMMRegister(rm), 1346 static_cast<int>(imm8)); 1347 data += 2; 1348 } else if (*data == 0xD3) { 1349 data++; 1350 int mod, regop, rm; 1351 get_modrm(*data, &mod, ®op, &rm); 1352 AppendToBuffer("psrlq %s,%s", 1353 NameOfXMMRegister(regop), 1354 NameOfXMMRegister(rm)); 1355 data++; 1356 } else if (*data == 0x7F) { 1357 AppendToBuffer("movdqa "); 1358 data++; 1359 int mod, regop, rm; 1360 get_modrm(*data, &mod, ®op, &rm); 1361 data += PrintRightXMMOperand(data); 1362 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1363 } else if (*data == 0x7E) { 1364 data++; 1365 int mod, regop, rm; 1366 get_modrm(*data, &mod, ®op, &rm); 1367 AppendToBuffer("movd "); 1368 data += PrintRightOperand(data); 1369 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1370 } else if (*data == 0xDB) { 1371 data++; 1372 int mod, regop, rm; 1373 get_modrm(*data, &mod, ®op, &rm); 1374 AppendToBuffer("pand %s,%s", 1375 NameOfXMMRegister(regop), 1376 NameOfXMMRegister(rm)); 1377 data++; 1378 } else if (*data == 0xE7) { 1379 data++; 1380 int mod, regop, rm; 1381 get_modrm(*data, &mod, ®op, &rm); 1382 if (mod == 3) { 1383 AppendToBuffer("movntdq "); 1384 data += PrintRightOperand(data); 1385 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1386 } else { 1387 UnimplementedInstruction(); 1388 } 1389 } else if (*data == 0xEF) { 1390 data++; 1391 int mod, regop, rm; 1392 get_modrm(*data, &mod, ®op, &rm); 1393 AppendToBuffer("pxor %s,%s", 1394 NameOfXMMRegister(regop), 1395 NameOfXMMRegister(rm)); 1396 data++; 1397 } else if (*data == 0xEB) { 1398 data++; 1399 int mod, regop, rm; 1400 get_modrm(*data, &mod, ®op, &rm); 1401 AppendToBuffer("por %s,%s", 1402 NameOfXMMRegister(regop), 1403 NameOfXMMRegister(rm)); 1404 data++; 1405 } else { 1406 UnimplementedInstruction(); 1407 } 1408 } else { 1409 UnimplementedInstruction(); 1410 } 1411 break; 1412 1413 case 0xFE: 1414 { data++; 1415 int mod, regop, rm; 1416 get_modrm(*data, &mod, ®op, &rm); 1417 if (regop == ecx) { 1418 AppendToBuffer("dec_b "); 1419 data += PrintRightOperand(data); 1420 } else { 1421 UnimplementedInstruction(); 1422 } 1423 } 1424 break; 1425 1426 case 0x68: 1427 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1)); 1428 data += 5; 1429 break; 1430 1431 case 0x6A: 1432 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); 1433 data += 2; 1434 break; 1435 1436 case 0xA8: 1437 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1)); 1438 data += 2; 1439 break; 1440 1441 case 0xA9: 1442 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1)); 1443 data += 5; 1444 break; 1445 1446 case 0xD1: // fall through 1447 case 0xD3: // fall through 1448 case 0xC1: 1449 data += D1D3C1Instruction(data); 1450 break; 1451 1452 case 0xD9: // fall through 1453 case 0xDA: // fall through 1454 case 0xDB: // fall through 1455 case 0xDC: // fall through 1456 case 0xDD: // fall through 1457 case 0xDE: // fall through 1458 case 0xDF: 1459 data += FPUInstruction(data); 1460 break; 1461 1462 case 0xEB: 1463 data += JumpShort(data); 1464 break; 1465 1466 case 0xF2: 1467 if (*(data+1) == 0x0F) { 1468 byte b2 = *(data+2); 1469 if (b2 == 0x11) { 1470 AppendToBuffer("movsd "); 1471 data += 3; 1472 int mod, regop, rm; 1473 get_modrm(*data, &mod, ®op, &rm); 1474 data += PrintRightXMMOperand(data); 1475 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1476 } else if (b2 == 0x10) { 1477 data += 3; 1478 int mod, regop, rm; 1479 get_modrm(*data, &mod, ®op, &rm); 1480 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); 1481 data += PrintRightXMMOperand(data); 1482 } else if (b2 == 0x5A) { 1483 data += 3; 1484 int mod, regop, rm; 1485 get_modrm(*data, &mod, ®op, &rm); 1486 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop)); 1487 data += PrintRightXMMOperand(data); 1488 } else { 1489 const char* mnem = "?"; 1490 switch (b2) { 1491 case 0x2A: mnem = "cvtsi2sd"; break; 1492 case 0x2C: mnem = "cvttsd2si"; break; 1493 case 0x2D: mnem = "cvtsd2si"; break; 1494 case 0x51: mnem = "sqrtsd"; break; 1495 case 0x58: mnem = "addsd"; break; 1496 case 0x59: mnem = "mulsd"; break; 1497 case 0x5C: mnem = "subsd"; break; 1498 case 0x5E: mnem = "divsd"; break; 1499 } 1500 data += 3; 1501 int mod, regop, rm; 1502 get_modrm(*data, &mod, ®op, &rm); 1503 if (b2 == 0x2A) { 1504 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1505 data += PrintRightOperand(data); 1506 } else if (b2 == 0x2C || b2 == 0x2D) { 1507 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 1508 data += PrintRightXMMOperand(data); 1509 } else if (b2 == 0xC2) { 1510 // Intel manual 2A, Table 3-18. 1511 const char* const pseudo_op[] = { 1512 "cmpeqsd", 1513 "cmpltsd", 1514 "cmplesd", 1515 "cmpunordsd", 1516 "cmpneqsd", 1517 "cmpnltsd", 1518 "cmpnlesd", 1519 "cmpordsd" 1520 }; 1521 AppendToBuffer("%s %s,%s", 1522 pseudo_op[data[1]], 1523 NameOfXMMRegister(regop), 1524 NameOfXMMRegister(rm)); 1525 data += 2; 1526 } else { 1527 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1528 data += PrintRightXMMOperand(data); 1529 } 1530 } 1531 } else { 1532 UnimplementedInstruction(); 1533 } 1534 break; 1535 1536 case 0xF3: 1537 if (*(data+1) == 0x0F) { 1538 byte b2 = *(data+2); 1539 if (b2 == 0x11) { 1540 AppendToBuffer("movss "); 1541 data += 3; 1542 int mod, regop, rm; 1543 get_modrm(*data, &mod, ®op, &rm); 1544 data += PrintRightXMMOperand(data); 1545 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1546 } else if (b2 == 0x10) { 1547 data += 3; 1548 int mod, regop, rm; 1549 get_modrm(*data, &mod, ®op, &rm); 1550 AppendToBuffer("movss %s,", NameOfXMMRegister(regop)); 1551 data += PrintRightXMMOperand(data); 1552 } else if (b2 == 0x2C) { 1553 data += 3; 1554 int mod, regop, rm; 1555 get_modrm(*data, &mod, ®op, &rm); 1556 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop)); 1557 data += PrintRightXMMOperand(data); 1558 } else if (b2 == 0x5A) { 1559 data += 3; 1560 int mod, regop, rm; 1561 get_modrm(*data, &mod, ®op, &rm); 1562 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); 1563 data += PrintRightXMMOperand(data); 1564 } else if (b2 == 0x6F) { 1565 data += 3; 1566 int mod, regop, rm; 1567 get_modrm(*data, &mod, ®op, &rm); 1568 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop)); 1569 data += PrintRightXMMOperand(data); 1570 } else if (b2 == 0x7F) { 1571 AppendToBuffer("movdqu "); 1572 data += 3; 1573 int mod, regop, rm; 1574 get_modrm(*data, &mod, ®op, &rm); 1575 data += PrintRightXMMOperand(data); 1576 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1577 } else { 1578 UnimplementedInstruction(); 1579 } 1580 } else if (*(data+1) == 0xA5) { 1581 data += 2; 1582 AppendToBuffer("rep_movs"); 1583 } else if (*(data+1) == 0xAB) { 1584 data += 2; 1585 AppendToBuffer("rep_stos"); 1586 } else { 1587 UnimplementedInstruction(); 1588 } 1589 break; 1590 1591 case 0xF7: 1592 data += F7Instruction(data); 1593 break; 1594 1595 default: 1596 UnimplementedInstruction(); 1597 } 1598 } 1599 1600 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { 1601 tmp_buffer_[tmp_buffer_pos_] = '\0'; 1602 } 1603 1604 int instr_len = data - instr; 1605 if (instr_len == 0) { 1606 printf("%02x", *data); 1607 } 1608 ASSERT(instr_len > 0); // Ensure progress. 1609 1610 int outp = 0; 1611 // Instruction bytes. 1612 for (byte* bp = instr; bp < data; bp++) { 1613 outp += v8::internal::OS::SNPrintF(out_buffer + outp, 1614 "%02x", 1615 *bp); 1616 } 1617 for (int i = 6 - instr_len; i >= 0; i--) { 1618 outp += v8::internal::OS::SNPrintF(out_buffer + outp, 1619 " "); 1620 } 1621 1622 outp += v8::internal::OS::SNPrintF(out_buffer + outp, 1623 " %s", 1624 tmp_buffer_.start()); 1625 return instr_len; 1626} // NOLINT (function is too long) 1627 1628 1629//------------------------------------------------------------------------------ 1630 1631 1632static const char* cpu_regs[8] = { 1633 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 1634}; 1635 1636 1637static const char* byte_cpu_regs[8] = { 1638 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 1639}; 1640 1641 1642static const char* xmm_regs[8] = { 1643 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" 1644}; 1645 1646 1647const char* NameConverter::NameOfAddress(byte* addr) const { 1648 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr); 1649 return tmp_buffer_.start(); 1650} 1651 1652 1653const char* NameConverter::NameOfConstant(byte* addr) const { 1654 return NameOfAddress(addr); 1655} 1656 1657 1658const char* NameConverter::NameOfCPURegister(int reg) const { 1659 if (0 <= reg && reg < 8) return cpu_regs[reg]; 1660 return "noreg"; 1661} 1662 1663 1664const char* NameConverter::NameOfByteCPURegister(int reg) const { 1665 if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; 1666 return "noreg"; 1667} 1668 1669 1670const char* NameConverter::NameOfXMMRegister(int reg) const { 1671 if (0 <= reg && reg < 8) return xmm_regs[reg]; 1672 return "noxmmreg"; 1673} 1674 1675 1676const char* NameConverter::NameInCode(byte* addr) const { 1677 // IA32 does not embed debug strings at the moment. 1678 UNREACHABLE(); 1679 return ""; 1680} 1681 1682 1683//------------------------------------------------------------------------------ 1684 1685Disassembler::Disassembler(const NameConverter& converter) 1686 : converter_(converter) {} 1687 1688 1689Disassembler::~Disassembler() {} 1690 1691 1692int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 1693 byte* instruction) { 1694 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/); 1695 return d.InstructionDecode(buffer, instruction); 1696} 1697 1698 1699// The IA-32 assembler does not currently use constant pools. 1700int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } 1701 1702 1703/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { 1704 NameConverter converter; 1705 Disassembler d(converter); 1706 for (byte* pc = begin; pc < end;) { 1707 v8::internal::EmbeddedVector<char, 128> buffer; 1708 buffer[0] = '\0'; 1709 byte* prev_pc = pc; 1710 pc += d.InstructionDecode(buffer, pc); 1711 fprintf(f, "%p", prev_pc); 1712 fprintf(f, " "); 1713 1714 for (byte* bp = prev_pc; bp < pc; bp++) { 1715 fprintf(f, "%02x", *bp); 1716 } 1717 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { 1718 fprintf(f, " "); 1719 } 1720 fprintf(f, " %s\n", buffer.start()); 1721 } 1722} 1723 1724 1725} // namespace disasm 1726 1727#endif // V8_TARGET_ARCH_IA32 1728