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