1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
11 #if V8_TARGET_ARCH_IA32
13 #include "src/disasm.h"
24 //------------------------------------------------------------------
26 //------------------------------------------------------------------
28 int b; // -1 terminates, otherwise must be in range (0..255)
30 OperandOrder op_order_;
34 static const ByteMnemonic two_operands_instr[] = {
35 {0x01, "add", OPER_REG_OP_ORDER},
36 {0x03, "add", REG_OPER_OP_ORDER},
37 {0x09, "or", OPER_REG_OP_ORDER},
38 {0x0B, "or", REG_OPER_OP_ORDER},
39 {0x1B, "sbb", REG_OPER_OP_ORDER},
40 {0x21, "and", OPER_REG_OP_ORDER},
41 {0x23, "and", REG_OPER_OP_ORDER},
42 {0x29, "sub", OPER_REG_OP_ORDER},
43 {0x2A, "subb", REG_OPER_OP_ORDER},
44 {0x2B, "sub", REG_OPER_OP_ORDER},
45 {0x31, "xor", OPER_REG_OP_ORDER},
46 {0x33, "xor", REG_OPER_OP_ORDER},
47 {0x38, "cmpb", OPER_REG_OP_ORDER},
48 {0x3A, "cmpb", REG_OPER_OP_ORDER},
49 {0x3B, "cmp", REG_OPER_OP_ORDER},
50 {0x84, "test_b", REG_OPER_OP_ORDER},
51 {0x85, "test", REG_OPER_OP_ORDER},
52 {0x87, "xchg", REG_OPER_OP_ORDER},
53 {0x8A, "mov_b", REG_OPER_OP_ORDER},
54 {0x8B, "mov", REG_OPER_OP_ORDER},
55 {0x8D, "lea", REG_OPER_OP_ORDER},
56 {-1, "", UNSET_OP_ORDER}
60 static const ByteMnemonic zero_operands_instr[] = {
61 {0xC3, "ret", UNSET_OP_ORDER},
62 {0xC9, "leave", UNSET_OP_ORDER},
63 {0x90, "nop", UNSET_OP_ORDER},
64 {0xF4, "hlt", UNSET_OP_ORDER},
65 {0xCC, "int3", UNSET_OP_ORDER},
66 {0x60, "pushad", UNSET_OP_ORDER},
67 {0x61, "popad", UNSET_OP_ORDER},
68 {0x9C, "pushfd", UNSET_OP_ORDER},
69 {0x9D, "popfd", UNSET_OP_ORDER},
70 {0x9E, "sahf", UNSET_OP_ORDER},
71 {0x99, "cdq", UNSET_OP_ORDER},
72 {0x9B, "fwait", UNSET_OP_ORDER},
73 {0xFC, "cld", UNSET_OP_ORDER},
74 {0xAB, "stos", UNSET_OP_ORDER},
75 {-1, "", UNSET_OP_ORDER}
79 static const ByteMnemonic call_jump_instr[] = {
80 {0xE8, "call", UNSET_OP_ORDER},
81 {0xE9, "jmp", UNSET_OP_ORDER},
82 {-1, "", UNSET_OP_ORDER}
86 static const ByteMnemonic short_immediate_instr[] = {
87 {0x05, "add", UNSET_OP_ORDER},
88 {0x0D, "or", UNSET_OP_ORDER},
89 {0x15, "adc", UNSET_OP_ORDER},
90 {0x25, "and", UNSET_OP_ORDER},
91 {0x2D, "sub", UNSET_OP_ORDER},
92 {0x35, "xor", UNSET_OP_ORDER},
93 {0x3D, "cmp", UNSET_OP_ORDER},
94 {-1, "", UNSET_OP_ORDER}
98 // Generally we don't want to generate these because they are subject to partial
99 // register stalls. They are included for completeness and because the cmp
100 // variant is used by the RecordWrite stub. Because it does not update the
101 // register it is not subject to partial register stalls.
102 static ByteMnemonic byte_immediate_instr[] = {
103 {0x0c, "or", UNSET_OP_ORDER},
104 {0x24, "and", UNSET_OP_ORDER},
105 {0x34, "xor", UNSET_OP_ORDER},
106 {0x3c, "cmp", UNSET_OP_ORDER},
107 {-1, "", UNSET_OP_ORDER}
111 static const char* const jump_conditional_mnem[] = {
112 /*0*/ "jo", "jno", "jc", "jnc",
113 /*4*/ "jz", "jnz", "jna", "ja",
114 /*8*/ "js", "jns", "jpe", "jpo",
115 /*12*/ "jl", "jnl", "jng", "jg"
119 static const char* const set_conditional_mnem[] = {
120 /*0*/ "seto", "setno", "setc", "setnc",
121 /*4*/ "setz", "setnz", "setna", "seta",
122 /*8*/ "sets", "setns", "setpe", "setpo",
123 /*12*/ "setl", "setnl", "setng", "setg"
127 static const char* const conditional_move_mnem[] = {
128 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
129 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
130 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
131 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
135 enum InstructionType {
139 JUMP_CONDITIONAL_SHORT_INSTR,
143 SHORT_IMMEDIATE_INSTR,
148 struct InstructionDesc {
150 InstructionType type;
151 OperandOrder op_order_;
155 class InstructionTable {
158 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
159 static InstructionTable* get_instance() {
160 static InstructionTable table;
165 InstructionDesc instructions_[256];
168 void CopyTable(const ByteMnemonic bm[], InstructionType type);
169 void SetTableRange(InstructionType type,
173 void AddJumpConditionalShort();
177 InstructionTable::InstructionTable() {
183 void InstructionTable::Clear() {
184 for (int i = 0; i < 256; i++) {
185 instructions_[i].mnem = "";
186 instructions_[i].type = NO_INSTR;
187 instructions_[i].op_order_ = UNSET_OP_ORDER;
192 void InstructionTable::Init() {
193 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
194 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
195 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
196 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
197 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
198 AddJumpConditionalShort();
199 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
200 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
201 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
202 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
203 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
204 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
208 void InstructionTable::CopyTable(const ByteMnemonic bm[],
209 InstructionType type) {
210 for (int i = 0; bm[i].b >= 0; i++) {
211 InstructionDesc* id = &instructions_[bm[i].b];
212 id->mnem = bm[i].mnem;
213 id->op_order_ = bm[i].op_order_;
214 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
220 void InstructionTable::SetTableRange(InstructionType type,
224 for (byte b = start; b <= end; b++) {
225 InstructionDesc* id = &instructions_[b];
226 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
233 void InstructionTable::AddJumpConditionalShort() {
234 for (byte b = 0x70; b <= 0x7F; b++) {
235 InstructionDesc* id = &instructions_[b];
236 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
237 id->mnem = jump_conditional_mnem[b & 0x0F];
238 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
243 // The IA32 disassembler implementation.
244 class DisassemblerIA32 {
246 DisassemblerIA32(const NameConverter& converter,
247 bool abort_on_unimplemented = true)
248 : converter_(converter),
252 instruction_table_(InstructionTable::get_instance()),
254 abort_on_unimplemented_(abort_on_unimplemented) {
255 tmp_buffer_[0] = '\0';
258 virtual ~DisassemblerIA32() {}
260 // Writes one disassembled instruction into 'buffer' (0-terminated).
261 // Returns the length of the disassembled machine instruction in bytes.
262 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
265 const NameConverter& converter_;
266 byte vex_byte0_; // 0xc4 or 0xc5
268 byte vex_byte2_; // only for 3 bytes vex prefix
269 InstructionTable* instruction_table_;
270 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
271 unsigned int tmp_buffer_pos_;
272 bool abort_on_unimplemented_;
286 enum ShiftOpcodeExtension {
297 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
298 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
299 return (checked & 4) != 1;
303 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
304 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
305 return (checked & 3) == 1;
309 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
310 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
311 return (checked & 3) == 2;
315 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
316 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
317 return (checked & 3) == 3;
321 if (vex_byte0_ == 0xc5) return false;
322 return (vex_byte2_ & 0x80) != 0;
326 if (vex_byte0_ == 0xc5) return true;
327 return (vex_byte1_ & 3) == 1;
331 if (vex_byte0_ == 0xc5) return false;
332 return (vex_byte1_ & 3) == 2;
336 if (vex_byte0_ == 0xc5) return false;
337 return (vex_byte1_ & 3) == 3;
341 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
342 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
343 return ~(checked >> 3) & 0xf;
346 char float_size_code() { return "sd"[vex_w()]; }
348 const char* NameOfCPURegister(int reg) const {
349 return converter_.NameOfCPURegister(reg);
353 const char* NameOfByteCPURegister(int reg) const {
354 return converter_.NameOfByteCPURegister(reg);
358 const char* NameOfXMMRegister(int reg) const {
359 return converter_.NameOfXMMRegister(reg);
363 const char* NameOfAddress(byte* addr) const {
364 return converter_.NameOfAddress(addr);
368 // Disassembler helper functions.
369 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
370 *mod = (data >> 6) & 3;
371 *regop = (data & 0x38) >> 3;
376 static void get_sib(byte data, int* scale, int* index, int* base) {
377 *scale = (data >> 6) & 3;
378 *index = (data >> 3) & 7;
382 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
384 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
385 int PrintRightOperand(byte* modrmp);
386 int PrintRightByteOperand(byte* modrmp);
387 int PrintRightXMMOperand(byte* modrmp);
388 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
389 int PrintImmediateOp(byte* data);
390 int F7Instruction(byte* data);
391 int D1D3C1Instruction(byte* data);
392 int JumpShort(byte* data);
393 int JumpConditional(byte* data, const char* comment);
394 int JumpConditionalShort(byte* data, const char* comment);
395 int SetCC(byte* data);
396 int CMov(byte* data);
397 int FPUInstruction(byte* data);
398 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
399 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
400 int AVXInstruction(byte* data);
401 void AppendToBuffer(const char* format, ...);
404 void UnimplementedInstruction() {
405 if (abort_on_unimplemented_) {
408 AppendToBuffer("'Unimplemented Instruction'");
414 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
415 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
417 va_start(args, format);
418 int result = v8::internal::VSNPrintF(buf, format, args);
420 tmp_buffer_pos_ += result;
423 int DisassemblerIA32::PrintRightOperandHelper(
425 RegisterNameMapping direct_register_name) {
427 get_modrm(*modrmp, &mod, ®op, &rm);
428 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
429 &DisassemblerIA32::NameOfCPURegister;
433 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
434 AppendToBuffer("[0x%x]", disp);
436 } else if (rm == esp) {
437 byte sib = *(modrmp + 1);
438 int scale, index, base;
439 get_sib(sib, &scale, &index, &base);
440 if (index == esp && base == esp && scale == 0 /*times_1*/) {
441 AppendToBuffer("[%s]", (this->*register_name)(rm));
443 } else if (base == ebp) {
444 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
445 AppendToBuffer("[%s*%d%s0x%x]",
446 (this->*register_name)(index),
448 disp < 0 ? "-" : "+",
449 disp < 0 ? -disp : disp);
451 } else if (index != esp && base != ebp) {
452 // [base+index*scale]
453 AppendToBuffer("[%s+%s*%d]",
454 (this->*register_name)(base),
455 (this->*register_name)(index),
459 UnimplementedInstruction();
463 AppendToBuffer("[%s]", (this->*register_name)(rm));
467 case 1: // fall through
470 byte sib = *(modrmp + 1);
471 int scale, index, base;
472 get_sib(sib, &scale, &index, &base);
473 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
474 : *reinterpret_cast<int8_t*>(modrmp + 2);
475 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
476 AppendToBuffer("[%s%s0x%x]",
477 (this->*register_name)(rm),
478 disp < 0 ? "-" : "+",
479 disp < 0 ? -disp : disp);
481 AppendToBuffer("[%s+%s*%d%s0x%x]",
482 (this->*register_name)(base),
483 (this->*register_name)(index),
485 disp < 0 ? "-" : "+",
486 disp < 0 ? -disp : disp);
488 return mod == 2 ? 6 : 3;
491 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
492 : *reinterpret_cast<int8_t*>(modrmp + 1);
493 AppendToBuffer("[%s%s0x%x]",
494 (this->*register_name)(rm),
495 disp < 0 ? "-" : "+",
496 disp < 0 ? -disp : disp);
497 return mod == 2 ? 5 : 2;
501 AppendToBuffer("%s", (this->*register_name)(rm));
504 UnimplementedInstruction();
511 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
512 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
516 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
517 return PrintRightOperandHelper(modrmp,
518 &DisassemblerIA32::NameOfByteCPURegister);
522 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
523 return PrintRightOperandHelper(modrmp,
524 &DisassemblerIA32::NameOfXMMRegister);
528 // Returns number of bytes used including the current *data.
529 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
530 int DisassemblerIA32::PrintOperands(const char* mnem,
531 OperandOrder op_order,
535 get_modrm(modrm, &mod, ®op, &rm);
538 case REG_OPER_OP_ORDER: {
539 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
540 advance = PrintRightOperand(data);
543 case OPER_REG_OP_ORDER: {
544 AppendToBuffer("%s ", mnem);
545 advance = PrintRightOperand(data);
546 AppendToBuffer(",%s", NameOfCPURegister(regop));
557 // Returns number of bytes used by machine instruction, including *data byte.
558 // Writes immediate instructions to 'tmp_buffer_'.
559 int DisassemblerIA32::PrintImmediateOp(byte* data) {
560 bool sign_extension_bit = (*data & 0x02) != 0;
561 byte modrm = *(data+1);
563 get_modrm(modrm, &mod, ®op, &rm);
564 const char* mnem = "Imm???";
566 case 0: mnem = "add"; break;
567 case 1: mnem = "or"; break;
568 case 2: mnem = "adc"; break;
569 case 4: mnem = "and"; break;
570 case 5: mnem = "sub"; break;
571 case 6: mnem = "xor"; break;
572 case 7: mnem = "cmp"; break;
573 default: UnimplementedInstruction();
575 AppendToBuffer("%s ", mnem);
576 int count = PrintRightOperand(data+1);
577 if (sign_extension_bit) {
578 AppendToBuffer(",0x%x", *(data + 1 + count));
579 return 1 + count + 1 /*int8*/;
581 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
582 return 1 + count + 4 /*int32_t*/;
587 // Returns number of bytes used, including *data.
588 int DisassemblerIA32::F7Instruction(byte* data) {
589 DCHECK_EQ(0xF7, *data);
590 byte modrm = *++data;
592 get_modrm(modrm, &mod, ®op, &rm);
593 const char* mnem = NULL;
617 UnimplementedInstruction();
619 AppendToBuffer("%s ", mnem);
620 int count = PrintRightOperand(data);
622 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
629 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
631 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
632 byte modrm = *++data;
634 get_modrm(modrm, &mod, ®op, &rm);
636 const char* mnem = NULL;
660 UnimplementedInstruction();
662 AppendToBuffer("%s ", mnem);
663 int count = PrintRightOperand(data);
666 } else if (op == 0xC1) {
669 } else if (op == 0xD3) {
670 // Shift/rotate by cl.
673 AppendToBuffer(",%d", imm8);
675 AppendToBuffer(",cl");
681 // Returns number of bytes used, including *data.
682 int DisassemblerIA32::JumpShort(byte* data) {
683 DCHECK_EQ(0xEB, *data);
685 byte* dest = data + static_cast<int8_t>(b) + 2;
686 AppendToBuffer("jmp %s", NameOfAddress(dest));
691 // Returns number of bytes used, including *data.
692 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
693 DCHECK_EQ(0x0F, *data);
694 byte cond = *(data+1) & 0x0F;
695 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
696 const char* mnem = jump_conditional_mnem[cond];
697 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
698 if (comment != NULL) {
699 AppendToBuffer(", %s", comment);
701 return 6; // includes 0x0F
705 // Returns number of bytes used, including *data.
706 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
707 byte cond = *data & 0x0F;
709 byte* dest = data + static_cast<int8_t>(b) + 2;
710 const char* mnem = jump_conditional_mnem[cond];
711 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
712 if (comment != NULL) {
713 AppendToBuffer(", %s", comment);
719 // Returns number of bytes used, including *data.
720 int DisassemblerIA32::SetCC(byte* data) {
721 DCHECK_EQ(0x0F, *data);
722 byte cond = *(data+1) & 0x0F;
723 const char* mnem = set_conditional_mnem[cond];
724 AppendToBuffer("%s ", mnem);
725 PrintRightByteOperand(data+2);
726 return 3; // Includes 0x0F.
730 // Returns number of bytes used, including *data.
731 int DisassemblerIA32::CMov(byte* data) {
732 DCHECK_EQ(0x0F, *data);
733 byte cond = *(data + 1) & 0x0F;
734 const char* mnem = conditional_move_mnem[cond];
735 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
736 return 2 + op_size; // includes 0x0F
740 int DisassemblerIA32::AVXInstruction(byte* data) {
742 byte* current = data + 1;
743 if (vex_66() && vex_0f38()) {
744 int mod, regop, rm, vvvv = vex_vreg();
745 get_modrm(*current, &mod, ®op, &rm);
748 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
749 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
750 current += PrintRightXMMOperand(current);
753 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
754 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
755 current += PrintRightXMMOperand(current);
758 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
759 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
760 current += PrintRightXMMOperand(current);
763 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
764 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
765 current += PrintRightXMMOperand(current);
768 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
769 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
770 current += PrintRightXMMOperand(current);
773 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
774 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
775 current += PrintRightXMMOperand(current);
778 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
779 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
780 current += PrintRightXMMOperand(current);
783 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
784 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
785 current += PrintRightXMMOperand(current);
788 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
789 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
790 current += PrintRightXMMOperand(current);
793 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
794 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
795 current += PrintRightXMMOperand(current);
798 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
799 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
800 current += PrintRightXMMOperand(current);
803 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
804 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
805 current += PrintRightXMMOperand(current);
808 UnimplementedInstruction();
810 } else if (vex_f2() && vex_0f()) {
811 int mod, regop, rm, vvvv = vex_vreg();
812 get_modrm(*current, &mod, ®op, &rm);
815 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
816 NameOfXMMRegister(vvvv));
817 current += PrintRightXMMOperand(current);
820 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
821 NameOfXMMRegister(vvvv));
822 current += PrintRightXMMOperand(current);
825 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
826 NameOfXMMRegister(vvvv));
827 current += PrintRightXMMOperand(current);
830 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
831 NameOfXMMRegister(vvvv));
832 current += PrintRightXMMOperand(current);
835 UnimplementedInstruction();
838 UnimplementedInstruction();
841 return static_cast<int>(current - data);
845 // Returns number of bytes used, including *data.
846 int DisassemblerIA32::FPUInstruction(byte* data) {
847 byte escape_opcode = *data;
848 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
849 byte modrm_byte = *(data+1);
851 if (modrm_byte >= 0xC0) {
852 return RegisterFPUInstruction(escape_opcode, modrm_byte);
854 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
858 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
861 const char* mnem = "?";
862 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
863 switch (escape_opcode) {
864 case 0xD9: switch (regop) {
865 case 0: mnem = "fld_s"; break;
866 case 2: mnem = "fst_s"; break;
867 case 3: mnem = "fstp_s"; break;
868 case 7: mnem = "fstcw"; break;
869 default: UnimplementedInstruction();
873 case 0xDB: switch (regop) {
874 case 0: mnem = "fild_s"; break;
875 case 1: mnem = "fisttp_s"; break;
876 case 2: mnem = "fist_s"; break;
877 case 3: mnem = "fistp_s"; break;
878 default: UnimplementedInstruction();
882 case 0xDD: switch (regop) {
883 case 0: mnem = "fld_d"; break;
884 case 1: mnem = "fisttp_d"; break;
885 case 2: mnem = "fst_d"; break;
886 case 3: mnem = "fstp_d"; break;
887 default: UnimplementedInstruction();
891 case 0xDF: switch (regop) {
892 case 5: mnem = "fild_d"; break;
893 case 7: mnem = "fistp_d"; break;
894 default: UnimplementedInstruction();
898 default: UnimplementedInstruction();
900 AppendToBuffer("%s ", mnem);
901 int count = PrintRightOperand(modrm_start);
905 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
907 bool has_register = false; // Is the FPU register encoded in modrm_byte?
908 const char* mnem = "?";
910 switch (escape_opcode) {
913 switch (modrm_byte & 0xF8) {
914 case 0xC0: mnem = "fadd_i"; break;
915 case 0xE0: mnem = "fsub_i"; break;
916 case 0xC8: mnem = "fmul_i"; break;
917 case 0xF0: mnem = "fdiv_i"; break;
918 default: UnimplementedInstruction();
923 switch (modrm_byte & 0xF8) {
933 switch (modrm_byte) {
934 case 0xE0: mnem = "fchs"; break;
935 case 0xE1: mnem = "fabs"; break;
936 case 0xE4: mnem = "ftst"; break;
937 case 0xE8: mnem = "fld1"; break;
938 case 0xEB: mnem = "fldpi"; break;
939 case 0xED: mnem = "fldln2"; break;
940 case 0xEE: mnem = "fldz"; break;
941 case 0xF0: mnem = "f2xm1"; break;
942 case 0xF1: mnem = "fyl2x"; break;
943 case 0xF4: mnem = "fxtract"; break;
944 case 0xF5: mnem = "fprem1"; break;
945 case 0xF7: mnem = "fincstp"; break;
946 case 0xF8: mnem = "fprem"; break;
947 case 0xFC: mnem = "frndint"; break;
948 case 0xFD: mnem = "fscale"; break;
949 case 0xFE: mnem = "fsin"; break;
950 case 0xFF: mnem = "fcos"; break;
951 default: UnimplementedInstruction();
957 if (modrm_byte == 0xE9) {
960 UnimplementedInstruction();
965 if ((modrm_byte & 0xF8) == 0xE8) {
968 } else if (modrm_byte == 0xE2) {
970 } else if (modrm_byte == 0xE3) {
973 UnimplementedInstruction();
979 switch (modrm_byte & 0xF8) {
980 case 0xC0: mnem = "fadd"; break;
981 case 0xE8: mnem = "fsub"; break;
982 case 0xC8: mnem = "fmul"; break;
983 case 0xF8: mnem = "fdiv"; break;
984 default: UnimplementedInstruction();
990 switch (modrm_byte & 0xF8) {
991 case 0xC0: mnem = "ffree"; break;
992 case 0xD0: mnem = "fst"; break;
993 case 0xD8: mnem = "fstp"; break;
994 default: UnimplementedInstruction();
999 if (modrm_byte == 0xD9) {
1002 has_register = true;
1003 switch (modrm_byte & 0xF8) {
1004 case 0xC0: mnem = "faddp"; break;
1005 case 0xE8: mnem = "fsubp"; break;
1006 case 0xC8: mnem = "fmulp"; break;
1007 case 0xF8: mnem = "fdivp"; break;
1008 default: UnimplementedInstruction();
1014 if (modrm_byte == 0xE0) {
1016 } else if ((modrm_byte & 0xF8) == 0xE8) {
1018 has_register = true;
1022 default: UnimplementedInstruction();
1026 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1028 AppendToBuffer("%s", mnem);
1034 // Mnemonics for instructions 0xF0 byte.
1035 // Returns NULL if the instruction is not handled here.
1036 static const char* F0Mnem(byte f0byte) {
1040 case 0x18: return "prefetch";
1041 case 0xA2: return "cpuid";
1042 case 0xBE: return "movsx_b";
1043 case 0xBF: return "movsx_w";
1044 case 0xB6: return "movzx_b";
1045 case 0xB7: return "movzx_w";
1046 case 0xAF: return "imul";
1047 case 0xA5: return "shld";
1048 case 0xAD: return "shrd";
1049 case 0xAC: return "shrd"; // 3-operand version.
1050 case 0xAB: return "bts";
1051 case 0xBD: return "bsr";
1052 default: return NULL;
1057 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
1058 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1060 tmp_buffer_pos_ = 0; // starting to write as position 0
1063 const char* branch_hint = NULL;
1064 // We use these two prefixes only with branch prediction
1065 if (*data == 0x3E /*ds*/) {
1066 branch_hint = "predicted taken";
1068 } else if (*data == 0x2E /*cs*/) {
1069 branch_hint = "predicted not taken";
1071 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1073 vex_byte1_ = *(data + 1);
1074 vex_byte2_ = *(data + 2);
1076 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1078 vex_byte1_ = *(data + 1);
1082 bool processed = true; // Will be set to false if the current instruction
1083 // is not in 'instructions' table.
1084 // Decode AVX instructions.
1085 if (vex_byte0_ != 0) {
1086 data += AVXInstruction(data);
1088 const InstructionDesc& idesc = instruction_table_->Get(*data);
1089 switch (idesc.type) {
1090 case ZERO_OPERANDS_INSTR:
1091 AppendToBuffer(idesc.mnem);
1095 case TWO_OPERANDS_INSTR:
1097 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1100 case JUMP_CONDITIONAL_SHORT_INSTR:
1101 data += JumpConditionalShort(data, branch_hint);
1104 case REGISTER_INSTR:
1105 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1109 case MOVE_REG_INSTR: {
1111 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1112 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1113 NameOfAddress(addr));
1118 case CALL_JUMP_INSTR: {
1119 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1120 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1125 case SHORT_IMMEDIATE_INSTR: {
1127 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1128 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1133 case BYTE_IMMEDIATE_INSTR: {
1134 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1144 UNIMPLEMENTED(); // This type is not implemented.
1147 //----------------------------
1151 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1157 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1158 AppendToBuffer(",%d", *data);
1164 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1165 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1173 get_modrm(*data, &mod, ®op, &rm);
1175 AppendToBuffer("test_b ");
1176 data += PrintRightByteOperand(data);
1177 int32_t imm = *data;
1178 AppendToBuffer(",0x%x", imm);
1181 UnimplementedInstruction();
1186 case 0x81: // fall through
1187 case 0x83: // 0x81 with sign extension bit set
1188 data += PrintImmediateOp(data);
1192 { byte f0byte = data[1];
1193 const char* f0mnem = F0Mnem(f0byte);
1194 if (f0byte == 0x18) {
1197 get_modrm(*data, &mod, ®op, &rm);
1198 const char* suffix[] = {"nta", "1", "2", "3"};
1199 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1200 data += PrintRightOperand(data);
1201 } else if (f0byte == 0x1F && data[2] == 0) {
1202 AppendToBuffer("nop"); // 3 byte nop.
1204 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1205 AppendToBuffer("nop"); // 4 byte nop.
1207 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1209 AppendToBuffer("nop"); // 5 byte nop.
1211 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1212 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1213 AppendToBuffer("nop"); // 7 byte nop.
1215 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1216 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1218 AppendToBuffer("nop"); // 8 byte nop.
1220 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1221 AppendToBuffer("%s", f0mnem);
1223 } else if (f0byte == 0x28) {
1226 get_modrm(*data, &mod, ®op, &rm);
1227 AppendToBuffer("movaps %s,%s",
1228 NameOfXMMRegister(regop),
1229 NameOfXMMRegister(rm));
1231 } else if (f0byte == 0x2e) {
1234 get_modrm(*data, &mod, ®op, &rm);
1235 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1236 data += PrintRightXMMOperand(data);
1237 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1238 const char* const pseudo_op[] = {
1256 get_modrm(*data, &mod, ®op, &rm);
1257 AppendToBuffer("%s %s,",
1258 pseudo_op[f0byte - 0x53],
1259 NameOfXMMRegister(regop));
1260 data += PrintRightXMMOperand(data);
1261 } else if (f0byte == 0x50) {
1264 get_modrm(*data, &mod, ®op, &rm);
1265 AppendToBuffer("movmskps %s,%s",
1266 NameOfCPURegister(regop),
1267 NameOfXMMRegister(rm));
1269 } else if (f0byte== 0xC6) {
1270 // shufps xmm, xmm/m128, imm8
1273 get_modrm(*data, &mod, ®op, &rm);
1274 int8_t imm8 = static_cast<int8_t>(data[1]);
1275 AppendToBuffer("shufps %s,%s,%d",
1276 NameOfXMMRegister(rm),
1277 NameOfXMMRegister(regop),
1278 static_cast<int>(imm8));
1280 } else if ((f0byte & 0xF0) == 0x80) {
1281 data += JumpConditional(data, branch_hint);
1282 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1283 f0byte == 0xB7 || f0byte == 0xAF) {
1285 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1286 } else if ((f0byte & 0xF0) == 0x90) {
1287 data += SetCC(data);
1288 } else if ((f0byte & 0xF0) == 0x40) {
1290 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1293 AppendToBuffer("%s ", f0mnem);
1295 get_modrm(*data, &mod, ®op, &rm);
1296 data += PrintRightOperand(data);
1297 if (f0byte == 0xAB) {
1298 AppendToBuffer(",%s", NameOfCPURegister(regop));
1300 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1302 } else if (f0byte == 0xBD) {
1305 get_modrm(*data, &mod, ®op, &rm);
1306 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1307 data += PrintRightOperand(data);
1309 UnimplementedInstruction();
1317 get_modrm(*data, &mod, ®op, &rm);
1319 AppendToBuffer("pop ");
1320 data += PrintRightOperand(data);
1328 get_modrm(*data, &mod, ®op, &rm);
1329 const char* mnem = NULL;
1331 case esi: mnem = "push"; break;
1332 case eax: mnem = "inc"; break;
1333 case ecx: mnem = "dec"; break;
1334 case edx: mnem = "call"; break;
1335 case esp: mnem = "jmp"; break;
1336 default: mnem = "???";
1338 AppendToBuffer("%s ", mnem);
1339 data += PrintRightOperand(data);
1343 case 0xC7: // imm32, fall through
1345 { bool is_byte = *data == 0xC6;
1348 AppendToBuffer("%s ", "mov_b");
1349 data += PrintRightByteOperand(data);
1350 int32_t imm = *data;
1351 AppendToBuffer(",0x%x", imm);
1354 AppendToBuffer("%s ", "mov");
1355 data += PrintRightOperand(data);
1356 int32_t imm = *reinterpret_cast<int32_t*>(data);
1357 AppendToBuffer(",0x%x", imm);
1366 get_modrm(*data, &mod, ®op, &rm);
1367 const char* mnem = NULL;
1369 case 5: mnem = "subb"; break;
1370 case 7: mnem = "cmpb"; break;
1371 default: UnimplementedInstruction();
1373 AppendToBuffer("%s ", mnem);
1374 data += PrintRightByteOperand(data);
1375 int32_t imm = *data;
1376 AppendToBuffer(",0x%x", imm);
1381 case 0x88: // 8bit, fall through
1383 { bool is_byte = *data == 0x88;
1386 get_modrm(*data, &mod, ®op, &rm);
1388 AppendToBuffer("%s ", "mov_b");
1389 data += PrintRightByteOperand(data);
1390 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1392 AppendToBuffer("%s ", "mov");
1393 data += PrintRightOperand(data);
1394 AppendToBuffer(",%s", NameOfCPURegister(regop));
1399 case 0x66: // prefix
1400 while (*data == 0x66) data++;
1401 if (*data == 0xf && data[1] == 0x1f) {
1402 AppendToBuffer("nop"); // 0x66 prefix
1403 } else if (*data == 0x90) {
1404 AppendToBuffer("nop"); // 0x66 prefix
1405 } else if (*data == 0x8B) {
1407 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1408 } else if (*data == 0x89) {
1411 get_modrm(*data, &mod, ®op, &rm);
1412 AppendToBuffer("mov_w ");
1413 data += PrintRightOperand(data);
1414 AppendToBuffer(",%s", NameOfCPURegister(regop));
1415 } else if (*data == 0xC7) {
1417 AppendToBuffer("%s ", "mov_w");
1418 data += PrintRightOperand(data);
1419 int imm = *reinterpret_cast<int16_t*>(data);
1420 AppendToBuffer(",0x%x", imm);
1422 } else if (*data == 0x0F) {
1424 if (*data == 0x38) {
1426 if (*data == 0x17) {
1429 get_modrm(*data, &mod, ®op, &rm);
1430 AppendToBuffer("ptest %s,%s",
1431 NameOfXMMRegister(regop),
1432 NameOfXMMRegister(rm));
1434 } else if (*data == 0x2A) {
1438 get_modrm(*data, &mod, ®op, &rm);
1439 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1440 data += PrintRightOperand(data);
1442 UnimplementedInstruction();
1444 } else if (*data == 0x3A) {
1446 if (*data == 0x0B) {
1449 get_modrm(*data, &mod, ®op, &rm);
1450 int8_t imm8 = static_cast<int8_t>(data[1]);
1451 AppendToBuffer("roundsd %s,%s,%d",
1452 NameOfXMMRegister(regop),
1453 NameOfXMMRegister(rm),
1454 static_cast<int>(imm8));
1456 } else if (*data == 0x16) {
1459 get_modrm(*data, &mod, ®op, &rm);
1460 int8_t imm8 = static_cast<int8_t>(data[1]);
1461 AppendToBuffer("pextrd %s,%s,%d",
1462 NameOfCPURegister(regop),
1463 NameOfXMMRegister(rm),
1464 static_cast<int>(imm8));
1466 } else if (*data == 0x17) {
1469 get_modrm(*data, &mod, ®op, &rm);
1470 int8_t imm8 = static_cast<int8_t>(data[1]);
1471 AppendToBuffer("extractps %s,%s,%d",
1472 NameOfCPURegister(rm),
1473 NameOfXMMRegister(regop),
1474 static_cast<int>(imm8));
1476 } else if (*data == 0x22) {
1479 get_modrm(*data, &mod, ®op, &rm);
1480 int8_t imm8 = static_cast<int8_t>(data[1]);
1481 AppendToBuffer("pinsrd %s,%s,%d",
1482 NameOfXMMRegister(regop),
1483 NameOfCPURegister(rm),
1484 static_cast<int>(imm8));
1487 UnimplementedInstruction();
1489 } else if (*data == 0x2E || *data == 0x2F) {
1490 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1493 get_modrm(*data, &mod, ®op, &rm);
1495 AppendToBuffer("%s %s,%s", mnem,
1496 NameOfXMMRegister(regop),
1497 NameOfXMMRegister(rm));
1500 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1501 data += PrintRightOperand(data);
1503 } else if (*data == 0x50) {
1506 get_modrm(*data, &mod, ®op, &rm);
1507 AppendToBuffer("movmskpd %s,%s",
1508 NameOfCPURegister(regop),
1509 NameOfXMMRegister(rm));
1511 } else if (*data == 0x54) {
1514 get_modrm(*data, &mod, ®op, &rm);
1515 AppendToBuffer("andpd %s,%s",
1516 NameOfXMMRegister(regop),
1517 NameOfXMMRegister(rm));
1519 } else if (*data == 0x56) {
1522 get_modrm(*data, &mod, ®op, &rm);
1523 AppendToBuffer("orpd %s,%s",
1524 NameOfXMMRegister(regop),
1525 NameOfXMMRegister(rm));
1527 } else if (*data == 0x57) {
1530 get_modrm(*data, &mod, ®op, &rm);
1531 AppendToBuffer("xorpd %s,%s",
1532 NameOfXMMRegister(regop),
1533 NameOfXMMRegister(rm));
1535 } else if (*data == 0x6E) {
1538 get_modrm(*data, &mod, ®op, &rm);
1539 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1540 data += PrintRightOperand(data);
1541 } else if (*data == 0x6F) {
1544 get_modrm(*data, &mod, ®op, &rm);
1545 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1546 data += PrintRightXMMOperand(data);
1547 } else if (*data == 0x70) {
1550 get_modrm(*data, &mod, ®op, &rm);
1551 int8_t imm8 = static_cast<int8_t>(data[1]);
1552 AppendToBuffer("pshufd %s,%s,%d",
1553 NameOfXMMRegister(regop),
1554 NameOfXMMRegister(rm),
1555 static_cast<int>(imm8));
1557 } else if (*data == 0x76) {
1560 get_modrm(*data, &mod, ®op, &rm);
1561 AppendToBuffer("pcmpeqd %s,%s",
1562 NameOfXMMRegister(regop),
1563 NameOfXMMRegister(rm));
1565 } else if (*data == 0x90) {
1567 AppendToBuffer("nop"); // 2 byte nop.
1568 } else if (*data == 0xF3) {
1571 get_modrm(*data, &mod, ®op, &rm);
1572 AppendToBuffer("psllq %s,%s",
1573 NameOfXMMRegister(regop),
1574 NameOfXMMRegister(rm));
1576 } else if (*data == 0x72) {
1579 get_modrm(*data, &mod, ®op, &rm);
1580 int8_t imm8 = static_cast<int8_t>(data[1]);
1581 DCHECK(regop == esi || regop == edx);
1582 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1583 NameOfXMMRegister(rm), static_cast<int>(imm8));
1585 } else if (*data == 0x73) {
1588 get_modrm(*data, &mod, ®op, &rm);
1589 int8_t imm8 = static_cast<int8_t>(data[1]);
1590 DCHECK(regop == esi || regop == edx);
1591 AppendToBuffer("%s %s,%d",
1592 (regop == esi) ? "psllq" : "psrlq",
1593 NameOfXMMRegister(rm),
1594 static_cast<int>(imm8));
1596 } else if (*data == 0xD3) {
1599 get_modrm(*data, &mod, ®op, &rm);
1600 AppendToBuffer("psrlq %s,%s",
1601 NameOfXMMRegister(regop),
1602 NameOfXMMRegister(rm));
1604 } else if (*data == 0x7F) {
1605 AppendToBuffer("movdqa ");
1608 get_modrm(*data, &mod, ®op, &rm);
1609 data += PrintRightXMMOperand(data);
1610 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1611 } else if (*data == 0x7E) {
1614 get_modrm(*data, &mod, ®op, &rm);
1615 AppendToBuffer("movd ");
1616 data += PrintRightOperand(data);
1617 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1618 } else if (*data == 0xDB) {
1621 get_modrm(*data, &mod, ®op, &rm);
1622 AppendToBuffer("pand %s,%s",
1623 NameOfXMMRegister(regop),
1624 NameOfXMMRegister(rm));
1626 } else if (*data == 0xE7) {
1629 get_modrm(*data, &mod, ®op, &rm);
1631 AppendToBuffer("movntdq ");
1632 data += PrintRightOperand(data);
1633 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1635 UnimplementedInstruction();
1637 } else if (*data == 0xEF) {
1640 get_modrm(*data, &mod, ®op, &rm);
1641 AppendToBuffer("pxor %s,%s",
1642 NameOfXMMRegister(regop),
1643 NameOfXMMRegister(rm));
1645 } else if (*data == 0xEB) {
1648 get_modrm(*data, &mod, ®op, &rm);
1649 AppendToBuffer("por %s,%s",
1650 NameOfXMMRegister(regop),
1651 NameOfXMMRegister(rm));
1654 UnimplementedInstruction();
1657 UnimplementedInstruction();
1664 get_modrm(*data, &mod, ®op, &rm);
1666 AppendToBuffer("dec_b ");
1667 data += PrintRightOperand(data);
1669 UnimplementedInstruction();
1675 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1680 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1685 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1690 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1694 case 0xD1: // fall through
1695 case 0xD3: // fall through
1697 data += D1D3C1Instruction(data);
1700 case 0xD8: // fall through
1701 case 0xD9: // fall through
1702 case 0xDA: // fall through
1703 case 0xDB: // fall through
1704 case 0xDC: // fall through
1705 case 0xDD: // fall through
1706 case 0xDE: // fall through
1708 data += FPUInstruction(data);
1712 data += JumpShort(data);
1716 if (*(data+1) == 0x0F) {
1717 byte b2 = *(data+2);
1719 AppendToBuffer("movsd ");
1722 get_modrm(*data, &mod, ®op, &rm);
1723 data += PrintRightXMMOperand(data);
1724 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1725 } else if (b2 == 0x10) {
1728 get_modrm(*data, &mod, ®op, &rm);
1729 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1730 data += PrintRightXMMOperand(data);
1731 } else if (b2 == 0x5A) {
1734 get_modrm(*data, &mod, ®op, &rm);
1735 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1736 data += PrintRightXMMOperand(data);
1738 const char* mnem = "?";
1740 case 0x2A: mnem = "cvtsi2sd"; break;
1741 case 0x2C: mnem = "cvttsd2si"; break;
1742 case 0x2D: mnem = "cvtsd2si"; break;
1743 case 0x51: mnem = "sqrtsd"; break;
1744 case 0x58: mnem = "addsd"; break;
1745 case 0x59: mnem = "mulsd"; break;
1746 case 0x5C: mnem = "subsd"; break;
1747 case 0x5E: mnem = "divsd"; break;
1751 get_modrm(*data, &mod, ®op, &rm);
1753 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1754 data += PrintRightOperand(data);
1755 } else if (b2 == 0x2C || b2 == 0x2D) {
1756 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1757 data += PrintRightXMMOperand(data);
1758 } else if (b2 == 0xC2) {
1759 // Intel manual 2A, Table 3-18.
1760 const char* const pseudo_op[] = {
1770 AppendToBuffer("%s %s,%s",
1772 NameOfXMMRegister(regop),
1773 NameOfXMMRegister(rm));
1776 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1777 data += PrintRightXMMOperand(data);
1781 UnimplementedInstruction();
1786 if (*(data+1) == 0x0F) {
1787 byte b2 = *(data+2);
1789 AppendToBuffer("movss ");
1792 get_modrm(*data, &mod, ®op, &rm);
1793 data += PrintRightXMMOperand(data);
1794 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1795 } else if (b2 == 0x10) {
1798 get_modrm(*data, &mod, ®op, &rm);
1799 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1800 data += PrintRightXMMOperand(data);
1801 } else if (b2 == 0x2C) {
1804 get_modrm(*data, &mod, ®op, &rm);
1805 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1806 data += PrintRightXMMOperand(data);
1807 } else if (b2 == 0x58) {
1810 get_modrm(*data, &mod, ®op, &rm);
1811 AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
1812 data += PrintRightXMMOperand(data);
1813 } else if (b2 == 0x59) {
1816 get_modrm(*data, &mod, ®op, &rm);
1817 AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
1818 data += PrintRightXMMOperand(data);
1819 } else if (b2 == 0x5A) {
1822 get_modrm(*data, &mod, ®op, &rm);
1823 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1824 data += PrintRightXMMOperand(data);
1825 } else if (b2 == 0x5c) {
1828 get_modrm(*data, &mod, ®op, &rm);
1829 AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
1830 data += PrintRightXMMOperand(data);
1831 } else if (b2 == 0x5e) {
1834 get_modrm(*data, &mod, ®op, &rm);
1835 AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
1836 data += PrintRightXMMOperand(data);
1837 } else if (b2 == 0x6F) {
1840 get_modrm(*data, &mod, ®op, &rm);
1841 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1842 data += PrintRightXMMOperand(data);
1843 } else if (b2 == 0x7F) {
1844 AppendToBuffer("movdqu ");
1847 get_modrm(*data, &mod, ®op, &rm);
1848 data += PrintRightXMMOperand(data);
1849 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1851 UnimplementedInstruction();
1853 } else if (*(data+1) == 0xA5) {
1855 AppendToBuffer("rep_movs");
1856 } else if (*(data+1) == 0xAB) {
1858 AppendToBuffer("rep_stos");
1860 UnimplementedInstruction();
1865 data += F7Instruction(data);
1869 UnimplementedInstruction();
1873 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1874 tmp_buffer_[tmp_buffer_pos_] = '\0';
1877 int instr_len = data - instr;
1878 if (instr_len == 0) {
1879 printf("%02x", *data);
1881 DCHECK(instr_len > 0); // Ensure progress.
1884 // Instruction bytes.
1885 for (byte* bp = instr; bp < data; bp++) {
1886 outp += v8::internal::SNPrintF(out_buffer + outp,
1890 for (int i = 6 - instr_len; i >= 0; i--) {
1891 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
1894 outp += v8::internal::SNPrintF(out_buffer + outp,
1896 tmp_buffer_.start());
1898 } // NOLINT (function is too long)
1901 //------------------------------------------------------------------------------
1904 static const char* const cpu_regs[8] = {
1905 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1909 static const char* const byte_cpu_regs[8] = {
1910 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1914 static const char* const xmm_regs[8] = {
1915 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1919 const char* NameConverter::NameOfAddress(byte* addr) const {
1920 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1921 return tmp_buffer_.start();
1925 const char* NameConverter::NameOfConstant(byte* addr) const {
1926 return NameOfAddress(addr);
1930 const char* NameConverter::NameOfCPURegister(int reg) const {
1931 if (0 <= reg && reg < 8) return cpu_regs[reg];
1936 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1937 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1942 const char* NameConverter::NameOfXMMRegister(int reg) const {
1943 if (0 <= reg && reg < 8) return xmm_regs[reg];
1948 const char* NameConverter::NameInCode(byte* addr) const {
1949 // IA32 does not embed debug strings at the moment.
1955 //------------------------------------------------------------------------------
1957 Disassembler::Disassembler(const NameConverter& converter)
1958 : converter_(converter) {}
1961 Disassembler::~Disassembler() {}
1964 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1965 byte* instruction) {
1966 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1967 return d.InstructionDecode(buffer, instruction);
1971 // The IA-32 assembler does not currently use constant pools.
1972 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1975 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1976 NameConverter converter;
1977 Disassembler d(converter);
1978 for (byte* pc = begin; pc < end;) {
1979 v8::internal::EmbeddedVector<char, 128> buffer;
1982 pc += d.InstructionDecode(buffer, pc);
1983 fprintf(f, "%p", prev_pc);
1986 for (byte* bp = prev_pc; bp < pc; bp++) {
1987 fprintf(f, "%02x", *bp);
1989 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1992 fprintf(f, " %s\n", buffer.start());
1997 } // namespace disasm
1999 #endif // V8_TARGET_ARCH_IA32