34 #if defined(V8_TARGET_ARCH_IA32)
53 OperandOrder op_order_;
57 static 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}
83 static 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}
102 static const ByteMnemonic call_jump_instr[] = {
103 {0xE8,
"call", UNSET_OP_ORDER},
104 {0xE9,
"jmp", UNSET_OP_ORDER},
105 {-1,
"", UNSET_OP_ORDER}
109 static 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}
125 static 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}
134 static const char*
const jump_conditional_mnem[] = {
135 "jo",
"jno",
"jc",
"jnc",
136 "jz",
"jnz",
"jna",
"ja",
137 "js",
"jns",
"jpe",
"jpo",
138 "jl",
"jnl",
"jng",
"jg"
142 static const char*
const set_conditional_mnem[] = {
143 "seto",
"setno",
"setc",
"setnc",
144 "setz",
"setnz",
"setna",
"seta",
145 "sets",
"setns",
"setpe",
"setpo",
146 "setl",
"setnl",
"setng",
"setg"
150 static const char*
const conditional_move_mnem[] = {
151 "cmovo",
"cmovno",
"cmovc",
"cmovnc",
152 "cmovz",
"cmovnz",
"cmovna",
"cmova",
153 "cmovs",
"cmovns",
"cmovpe",
"cmovpo",
154 "cmovl",
"cmovnl",
"cmovng",
"cmovg"
158 enum InstructionType {
162 JUMP_CONDITIONAL_SHORT_INSTR,
166 SHORT_IMMEDIATE_INSTR,
171 struct InstructionDesc {
173 InstructionType
type;
174 OperandOrder op_order_;
178 class InstructionTable {
181 const InstructionDesc& Get(
byte x)
const {
return instructions_[x]; }
182 static InstructionTable* get_instance() {
183 static InstructionTable table;
188 InstructionDesc instructions_[256];
191 void CopyTable(
const ByteMnemonic bm[], InstructionType
type);
192 void SetTableRange(InstructionType
type,
196 void AddJumpConditionalShort();
200 InstructionTable::InstructionTable() {
206 void 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;
215 void 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,");
227 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF,
"mov");
231 void 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_;
243 void InstructionTable::SetTableRange(InstructionType type,
247 for (
byte b = start; b <= end; b++) {
248 InstructionDesc*
id = &instructions_[b];
256 void InstructionTable::AddJumpConditionalShort() {
257 for (
byte b = 0x70; b <= 0x7F; b++) {
258 InstructionDesc*
id = &instructions_[b];
260 id->mnem = jump_conditional_mnem[b & 0x0F];
261 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
267 class DisassemblerIA32 {
269 DisassemblerIA32(
const NameConverter& converter,
270 bool abort_on_unimplemented =
true)
271 : converter_(converter),
272 instruction_table_(InstructionTable::get_instance()),
274 abort_on_unimplemented_(abort_on_unimplemented) {
275 tmp_buffer_[0] =
'\0';
278 virtual ~DisassemblerIA32() {}
285 const NameConverter& converter_;
286 InstructionTable* instruction_table_;
288 unsigned int tmp_buffer_pos_;
289 bool abort_on_unimplemented_;
303 enum ShiftOpcodeExtension {
314 const char* NameOfCPURegister(
int reg)
const {
315 return converter_.NameOfCPURegister(reg);
319 const char* NameOfByteCPURegister(
int reg)
const {
320 return converter_.NameOfByteCPURegister(reg);
324 const char* NameOfXMMRegister(
int reg)
const {
325 return converter_.NameOfXMMRegister(reg);
329 const char* NameOfAddress(
byte* addr)
const {
330 return converter_.NameOfAddress(addr);
335 static void get_modrm(
byte data,
int* mod,
int* regop,
int* rm) {
336 *mod = (data >> 6) & 3;
337 *regop = (data & 0x38) >> 3;
342 static void get_sib(
byte data,
int* scale,
int* index,
int* base) {
343 *scale = (data >> 6) & 3;
344 *index = (data >> 3) & 7;
348 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(
int reg)
const;
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);
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, ...);
369 void UnimplementedInstruction() {
370 if (abort_on_unimplemented_) {
373 AppendToBuffer(
"'Unimplemented Instruction'");
379 void DisassemblerIA32::AppendToBuffer(
const char* format, ...) {
382 va_start(args, format);
385 tmp_buffer_pos_ += result;
388 int DisassemblerIA32::PrintRightOperandHelper(
390 RegisterNameMapping direct_register_name) {
392 get_modrm(*modrmp, &mod, ®op, &rm);
393 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
394 &DisassemblerIA32::NameOfCPURegister;
399 AppendToBuffer(
"[0x%x]", disp);
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 ) {
406 AppendToBuffer(
"[%s]", (this->*register_name)(rm));
408 }
else if (base ==
ebp) {
410 AppendToBuffer(
"[%s*%d+0x%x]",
411 (this->*register_name)(index),
415 }
else if (index !=
esp && base !=
ebp) {
417 AppendToBuffer(
"[%s+%s*%d]",
418 (this->*register_name)(base),
419 (this->*register_name)(index),
423 UnimplementedInstruction();
427 AppendToBuffer(
"[%s]", (this->*register_name)(rm));
434 byte sib = *(modrmp + 1);
435 int scale, index, base;
436 get_sib(sib, &scale, &index, &base);
438 mod == 2 ? *
reinterpret_cast<int32_t*
>(modrmp + 2) : *(modrmp + 2);
439 if (index == base && index == rm && scale == 0 ) {
440 AppendToBuffer(
"[%s+0x%x]", (this->*register_name)(rm), disp);
442 AppendToBuffer(
"[%s+%s*%d+0x%x]",
443 (this->*register_name)(base),
444 (this->*register_name)(index),
448 return mod == 2 ? 6 : 3;
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;
458 AppendToBuffer(
"%s", (this->*register_name)(rm));
461 UnimplementedInstruction();
468 int DisassemblerIA32::PrintRightOperand(
byte* modrmp) {
469 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
473 int DisassemblerIA32::PrintRightByteOperand(
byte* modrmp) {
474 return PrintRightOperandHelper(modrmp,
475 &DisassemblerIA32::NameOfByteCPURegister);
479 int DisassemblerIA32::PrintRightXMMOperand(
byte* modrmp) {
480 return PrintRightOperandHelper(modrmp,
481 &DisassemblerIA32::NameOfXMMRegister);
487 int DisassemblerIA32::PrintOperands(
const char* mnem,
488 OperandOrder op_order,
492 get_modrm(modrm, &mod, ®op, &rm);
495 case REG_OPER_OP_ORDER: {
496 AppendToBuffer(
"%s %s,", mnem, NameOfCPURegister(regop));
497 advance = PrintRightOperand(data);
500 case OPER_REG_OP_ORDER: {
501 AppendToBuffer(
"%s ", mnem);
502 advance = PrintRightOperand(data);
503 AppendToBuffer(
",%s", NameOfCPURegister(regop));
516 int DisassemblerIA32::PrintImmediateOp(
byte* data) {
517 bool sign_extension_bit = (*data & 0x02) != 0;
518 byte modrm = *(data+1);
520 get_modrm(modrm, &mod, ®op, &rm);
521 const char* mnem =
"Imm???";
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();
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 ;
538 AppendToBuffer(
",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
539 return 1 + count + 4 ;
545 int DisassemblerIA32::F7Instruction(
byte* data) {
547 byte modrm = *(data+1);
549 get_modrm(modrm, &mod, ®op, &rm);
550 if (mod == 3 && regop != 0) {
551 const char* mnem =
NULL;
553 case 2: mnem =
"not";
break;
554 case 3: mnem =
"neg";
break;
555 case 4: mnem =
"mul";
break;
556 case 7: mnem =
"idiv";
break;
557 default: UnimplementedInstruction();
559 AppendToBuffer(
"%s %s", mnem, NameOfCPURegister(rm));
561 }
else if (mod == 3 && regop ==
eax) {
563 AppendToBuffer(
"test %s,0x%x", NameOfCPURegister(rm), imm);
565 }
else if (regop ==
eax) {
566 AppendToBuffer(
"test ");
567 int count = PrintRightOperand(data+1);
569 AppendToBuffer(
",0x%x", imm);
572 UnimplementedInstruction();
577 int DisassemblerIA32::D1D3C1Instruction(
byte* data) {
579 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
580 byte modrm = *(data+1);
582 get_modrm(modrm, &mod, ®op, &rm);
586 const char* mnem =
NULL;
588 case kROL: mnem =
"rol";
break;
589 case kROR: mnem =
"ror";
break;
590 case kRCL: mnem =
"rcl";
break;
591 case kRCR: mnem =
"rcr";
break;
592 case kSHL: mnem =
"shl";
break;
593 case KSHR: mnem =
"shr";
break;
594 case kSAR: mnem =
"sar";
break;
595 default: UnimplementedInstruction();
599 }
else if (op == 0xC1) {
602 }
else if (op == 0xD3) {
606 AppendToBuffer(
"%s %s,", mnem, NameOfCPURegister(rm));
608 AppendToBuffer(
"%d", imm8);
610 AppendToBuffer(
"cl");
613 UnimplementedInstruction();
620 int DisassemblerIA32::JumpShort(
byte* data) {
623 byte* dest = data +
static_cast<int8_t
>(b) + 2;
624 AppendToBuffer(
"jmp %s", NameOfAddress(dest));
630 int DisassemblerIA32::JumpConditional(
byte* data,
const char*
comment) {
632 byte cond = *(data+1) & 0x0F;
633 byte* dest = data + *
reinterpret_cast<int32_t*
>(data+2) + 6;
634 const char* mnem = jump_conditional_mnem[cond];
635 AppendToBuffer(
"%s %s", mnem, NameOfAddress(dest));
636 if (comment !=
NULL) {
637 AppendToBuffer(
", %s", comment);
644 int DisassemblerIA32::JumpConditionalShort(
byte* data,
const char* comment) {
645 byte cond = *data & 0x0F;
647 byte* dest = data +
static_cast<int8_t
>(b) + 2;
648 const char* mnem = jump_conditional_mnem[cond];
649 AppendToBuffer(
"%s %s", mnem, NameOfAddress(dest));
650 if (comment !=
NULL) {
651 AppendToBuffer(
", %s", comment);
660 byte cond = *(data+1) & 0x0F;
661 const char* mnem = set_conditional_mnem[cond];
662 AppendToBuffer(
"%s ", mnem);
663 PrintRightByteOperand(data+2);
669 int DisassemblerIA32::CMov(
byte* data) {
671 byte cond = *(data + 1) & 0x0F;
672 const char* mnem = conditional_move_mnem[cond];
673 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
679 int DisassemblerIA32::FPUInstruction(
byte* data) {
680 byte escape_opcode = *data;
682 byte modrm_byte = *(data+1);
684 if (modrm_byte >= 0xC0) {
685 return RegisterFPUInstruction(escape_opcode, modrm_byte);
687 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
691 int DisassemblerIA32::MemoryFPUInstruction(
int escape_opcode,
694 const char* mnem =
"?";
695 int regop = (modrm_byte >> 3) & 0x7;
696 switch (escape_opcode) {
697 case 0xD9:
switch (regop) {
698 case 0: mnem =
"fld_s";
break;
699 case 3: mnem =
"fstp_s";
break;
700 case 7: mnem =
"fstcw";
break;
701 default: UnimplementedInstruction();
705 case 0xDB:
switch (regop) {
706 case 0: mnem =
"fild_s";
break;
707 case 1: mnem =
"fisttp_s";
break;
708 case 2: mnem =
"fist_s";
break;
709 case 3: mnem =
"fistp_s";
break;
710 default: UnimplementedInstruction();
714 case 0xDD:
switch (regop) {
715 case 0: mnem =
"fld_d";
break;
716 case 1: mnem =
"fisttp_d";
break;
717 case 2: mnem =
"fst_d";
break;
718 case 3: mnem =
"fstp_d";
break;
719 default: UnimplementedInstruction();
723 case 0xDF:
switch (regop) {
724 case 5: mnem =
"fild_d";
break;
725 case 7: mnem =
"fistp_d";
break;
726 default: UnimplementedInstruction();
730 default: UnimplementedInstruction();
732 AppendToBuffer(
"%s ", mnem);
733 int count = PrintRightOperand(modrm_start);
737 int DisassemblerIA32::RegisterFPUInstruction(
int escape_opcode,
739 bool has_register =
false;
740 const char* mnem =
"?";
742 switch (escape_opcode) {
744 UnimplementedInstruction();
748 switch (modrm_byte & 0xF8) {
758 switch (modrm_byte) {
759 case 0xE0: mnem =
"fchs";
break;
760 case 0xE1: mnem =
"fabs";
break;
761 case 0xE4: mnem =
"ftst";
break;
762 case 0xE8: mnem =
"fld1";
break;
763 case 0xEB: mnem =
"fldpi";
break;
764 case 0xED: mnem =
"fldln2";
break;
765 case 0xEE: mnem =
"fldz";
break;
766 case 0xF0: mnem =
"f2xm1";
break;
767 case 0xF1: mnem =
"fyl2x";
break;
768 case 0xF5: mnem =
"fprem1";
break;
769 case 0xF7: mnem =
"fincstp";
break;
770 case 0xF8: mnem =
"fprem";
break;
771 case 0xFC: mnem =
"frndint";
break;
772 case 0xFD: mnem =
"fscale";
break;
773 case 0xFE: mnem =
"fsin";
break;
774 case 0xFF: mnem =
"fcos";
break;
775 default: UnimplementedInstruction();
781 if (modrm_byte == 0xE9) {
784 UnimplementedInstruction();
789 if ((modrm_byte & 0xF8) == 0xE8) {
792 }
else if (modrm_byte == 0xE2) {
794 }
else if (modrm_byte == 0xE3) {
797 UnimplementedInstruction();
803 switch (modrm_byte & 0xF8) {
804 case 0xC0: mnem =
"fadd";
break;
805 case 0xE8: mnem =
"fsub";
break;
806 case 0xC8: mnem =
"fmul";
break;
807 case 0xF8: mnem =
"fdiv";
break;
808 default: UnimplementedInstruction();
814 switch (modrm_byte & 0xF8) {
815 case 0xC0: mnem =
"ffree";
break;
816 case 0xD8: mnem =
"fstp";
break;
817 default: UnimplementedInstruction();
822 if (modrm_byte == 0xD9) {
826 switch (modrm_byte & 0xF8) {
827 case 0xC0: mnem =
"faddp";
break;
828 case 0xE8: mnem =
"fsubp";
break;
829 case 0xC8: mnem =
"fmulp";
break;
830 case 0xF8: mnem =
"fdivp";
break;
831 default: UnimplementedInstruction();
837 if (modrm_byte == 0xE0) {
839 }
else if ((modrm_byte & 0xF8) == 0xE8) {
845 default: UnimplementedInstruction();
849 AppendToBuffer(
"%s st%d", mnem, modrm_byte & 0x7);
851 AppendToBuffer(
"%s", mnem);
859 static const char* F0Mnem(
byte f0byte) {
861 case 0x18:
return "prefetch";
862 case 0xA2:
return "cpuid";
863 case 0x31:
return "rdtsc";
864 case 0xBE:
return "movsx_b";
865 case 0xBF:
return "movsx_w";
866 case 0xB6:
return "movzx_b";
867 case 0xB7:
return "movzx_w";
868 case 0xAF:
return "imul";
869 case 0xA5:
return "shld";
870 case 0xAD:
return "shrd";
871 case 0xAB:
return "bts";
872 default:
return NULL;
883 const char* branch_hint =
NULL;
885 if (*data == 0x3E ) {
886 branch_hint =
"predicted taken";
888 }
else if (*data == 0x2E ) {
889 branch_hint =
"predicted not taken";
892 bool processed =
true;
894 const InstructionDesc& idesc = instruction_table_->Get(*data);
895 switch (idesc.type) {
896 case ZERO_OPERANDS_INSTR:
897 AppendToBuffer(idesc.mnem);
901 case TWO_OPERANDS_INSTR:
903 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
906 case JUMP_CONDITIONAL_SHORT_INSTR:
907 data += JumpConditionalShort(data, branch_hint);
911 AppendToBuffer(
"%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
915 case MOVE_REG_INSTR: {
916 byte* addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data+1));
917 AppendToBuffer(
"mov %s,%s",
918 NameOfCPURegister(*data & 0x07),
919 NameOfAddress(addr));
924 case CALL_JUMP_INSTR: {
925 byte* addr = data + *
reinterpret_cast<int32_t*
>(data+1) + 5;
926 AppendToBuffer(
"%s %s", idesc.mnem, NameOfAddress(addr));
931 case SHORT_IMMEDIATE_INSTR: {
932 byte* addr =
reinterpret_cast<byte*
>(*
reinterpret_cast<int32_t*
>(data+1));
933 AppendToBuffer(
"%s eax, %s", idesc.mnem, NameOfAddress(addr));
938 case BYTE_IMMEDIATE_INSTR: {
939 AppendToBuffer(
"%s al, 0x%x", idesc.mnem, data[1]);
955 AppendToBuffer(
"ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
961 {
int mod, regop, rm;
962 get_modrm(*(data+1), &mod, ®op, &rm);
964 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
965 AppendToBuffer(
"imul %s,%s,0x%x",
966 NameOfCPURegister(regop),
967 NameOfCPURegister(rm),
969 data += 2 + (*data == 0x6B ? 1 : 4);
976 get_modrm(*data, &mod, ®op, &rm);
978 AppendToBuffer(
"test_b ");
979 data += PrintRightByteOperand(data);
981 AppendToBuffer(
",0x%x", imm);
984 UnimplementedInstruction();
991 data += PrintImmediateOp(data);
995 {
byte f0byte = data[1];
996 const char* f0mnem = F0Mnem(f0byte);
997 if (f0byte == 0x18) {
999 get_modrm(*data, &mod, ®op, &rm);
1000 const char* suffix[] = {
"nta",
"1",
"2",
"3"};
1001 AppendToBuffer(
"%s%s ", f0mnem, suffix[regop & 0x03]);
1002 data += PrintRightOperand(data);
1003 }
else if (f0byte == 0x1F && data[2] == 0) {
1004 AppendToBuffer(
"nop");
1006 }
else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1007 AppendToBuffer(
"nop");
1009 }
else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1011 AppendToBuffer(
"nop");
1013 }
else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1014 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1015 AppendToBuffer(
"nop");
1017 }
else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1018 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1020 AppendToBuffer(
"nop");
1022 }
else if (f0byte == 0xA2 || f0byte == 0x31) {
1023 AppendToBuffer(
"%s", f0mnem);
1025 }
else if (f0byte == 0x28) {
1028 get_modrm(*data, &mod, ®op, &rm);
1029 AppendToBuffer(
"movaps %s,%s",
1030 NameOfXMMRegister(regop),
1031 NameOfXMMRegister(rm));
1033 }
else if (f0byte == 0x57) {
1036 get_modrm(*data, &mod, ®op, &rm);
1037 AppendToBuffer(
"xorps %s,%s",
1038 NameOfXMMRegister(regop),
1039 NameOfXMMRegister(rm));
1041 }
else if ((f0byte & 0xF0) == 0x80) {
1042 data += JumpConditional(data, branch_hint);
1043 }
else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1044 f0byte == 0xB7 || f0byte == 0xAF) {
1046 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1047 }
else if ((f0byte & 0xF0) == 0x90) {
1048 data +=
SetCC(data);
1049 }
else if ((f0byte & 0xF0) == 0x40) {
1053 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1055 AppendToBuffer(
"%s ", f0mnem);
1057 get_modrm(*data, &mod, ®op, &rm);
1058 data += PrintRightOperand(data);
1059 if (f0byte == 0xAB) {
1060 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1062 AppendToBuffer(
",%s,cl", NameOfCPURegister(regop));
1065 UnimplementedInstruction();
1074 get_modrm(*data, &mod, ®op, &rm);
1076 AppendToBuffer(
"pop ");
1077 data += PrintRightOperand(data);
1085 get_modrm(*data, &mod, ®op, &rm);
1086 const char* mnem =
NULL;
1088 case esi: mnem =
"push";
break;
1089 case eax: mnem =
"inc";
break;
1090 case ecx: mnem =
"dec";
break;
1091 case edx: mnem =
"call";
break;
1092 case esp: mnem =
"jmp";
break;
1093 default: mnem =
"???";
1095 AppendToBuffer(
"%s ", mnem);
1096 data += PrintRightOperand(data);
1102 {
bool is_byte = *data == 0xC6;
1105 AppendToBuffer(
"%s ",
"mov_b");
1106 data += PrintRightByteOperand(data);
1108 AppendToBuffer(
",0x%x", imm);
1111 AppendToBuffer(
"%s ",
"mov");
1112 data += PrintRightOperand(data);
1114 AppendToBuffer(
",0x%x", imm);
1123 get_modrm(*data, &mod, ®op, &rm);
1124 const char* mnem =
NULL;
1126 case 5: mnem =
"subb";
break;
1127 case 7: mnem =
"cmpb";
break;
1128 default: UnimplementedInstruction();
1130 AppendToBuffer(
"%s ", mnem);
1131 data += PrintRightByteOperand(data);
1133 AppendToBuffer(
",0x%x", imm);
1140 {
bool is_byte = *data == 0x88;
1143 get_modrm(*data, &mod, ®op, &rm);
1145 AppendToBuffer(
"%s ",
"mov_b");
1146 data += PrintRightByteOperand(data);
1147 AppendToBuffer(
",%s", NameOfByteCPURegister(regop));
1149 AppendToBuffer(
"%s ",
"mov");
1150 data += PrintRightOperand(data);
1151 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1157 while (*data == 0x66) data++;
1158 if (*data == 0xf && data[1] == 0x1f) {
1159 AppendToBuffer(
"nop");
1160 }
else if (*data == 0x90) {
1161 AppendToBuffer(
"nop");
1162 }
else if (*data == 0x8B) {
1164 data += PrintOperands(
"mov_w", REG_OPER_OP_ORDER, data);
1165 }
else if (*data == 0x89) {
1168 get_modrm(*data, &mod, ®op, &rm);
1169 AppendToBuffer(
"mov_w ");
1170 data += PrintRightOperand(data);
1171 AppendToBuffer(
",%s", NameOfCPURegister(regop));
1172 }
else if (*data == 0x0F) {
1174 if (*data == 0x38) {
1176 if (*data == 0x17) {
1179 get_modrm(*data, &mod, ®op, &rm);
1180 AppendToBuffer(
"ptest %s,%s",
1181 NameOfXMMRegister(regop),
1182 NameOfXMMRegister(rm));
1184 }
else if (*data == 0x2A) {
1188 get_modrm(*data, &mod, ®op, &rm);
1189 AppendToBuffer(
"movntdqa %s,", NameOfXMMRegister(regop));
1190 data += PrintRightOperand(data);
1192 UnimplementedInstruction();
1194 }
else if (*data == 0x3A) {
1196 if (*data == 0x0B) {
1199 get_modrm(*data, &mod, ®op, &rm);
1200 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1201 AppendToBuffer(
"roundsd %s,%s,%d",
1202 NameOfXMMRegister(regop),
1203 NameOfXMMRegister(rm),
1204 static_cast<int>(imm8));
1206 }
else if (*data == 0x16) {
1209 get_modrm(*data, &mod, ®op, &rm);
1210 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1211 AppendToBuffer(
"pextrd %s,%s,%d",
1212 NameOfCPURegister(regop),
1213 NameOfXMMRegister(rm),
1214 static_cast<int>(imm8));
1216 }
else if (*data == 0x17) {
1219 get_modrm(*data, &mod, ®op, &rm);
1220 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1221 AppendToBuffer(
"extractps %s,%s,%d",
1222 NameOfCPURegister(regop),
1223 NameOfXMMRegister(rm),
1224 static_cast<int>(imm8));
1226 }
else if (*data == 0x22) {
1229 get_modrm(*data, &mod, ®op, &rm);
1230 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1231 AppendToBuffer(
"pinsrd %s,%s,%d",
1232 NameOfXMMRegister(regop),
1233 NameOfCPURegister(rm),
1234 static_cast<int>(imm8));
1237 UnimplementedInstruction();
1239 }
else if (*data == 0x2E || *data == 0x2F) {
1240 const char* mnem = (*data == 0x2E) ?
"ucomisd" :
"comisd";
1243 get_modrm(*data, &mod, ®op, &rm);
1245 AppendToBuffer(
"%s %s,%s", mnem,
1246 NameOfXMMRegister(regop),
1247 NameOfXMMRegister(rm));
1250 AppendToBuffer(
"%s %s,", mnem, NameOfXMMRegister(regop));
1251 data += PrintRightOperand(data);
1253 }
else if (*data == 0x50) {
1256 get_modrm(*data, &mod, ®op, &rm);
1257 AppendToBuffer(
"movmskpd %s,%s",
1258 NameOfCPURegister(regop),
1259 NameOfXMMRegister(rm));
1261 }
else if (*data == 0x54) {
1264 get_modrm(*data, &mod, ®op, &rm);
1265 AppendToBuffer(
"andpd %s,%s",
1266 NameOfXMMRegister(regop),
1267 NameOfXMMRegister(rm));
1269 }
else if (*data == 0x57) {
1272 get_modrm(*data, &mod, ®op, &rm);
1273 AppendToBuffer(
"xorpd %s,%s",
1274 NameOfXMMRegister(regop),
1275 NameOfXMMRegister(rm));
1277 }
else if (*data == 0x6E) {
1280 get_modrm(*data, &mod, ®op, &rm);
1281 AppendToBuffer(
"movd %s,", NameOfXMMRegister(regop));
1282 data += PrintRightOperand(data);
1283 }
else if (*data == 0x6F) {
1286 get_modrm(*data, &mod, ®op, &rm);
1287 AppendToBuffer(
"movdqa %s,", NameOfXMMRegister(regop));
1288 data += PrintRightXMMOperand(data);
1289 }
else if (*data == 0x70) {
1292 get_modrm(*data, &mod, ®op, &rm);
1293 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1294 AppendToBuffer(
"pshufd %s,%s,%d",
1295 NameOfXMMRegister(regop),
1296 NameOfXMMRegister(rm),
1297 static_cast<int>(imm8));
1299 }
else if (*data == 0x90) {
1301 AppendToBuffer(
"nop");
1302 }
else if (*data == 0xF3) {
1305 get_modrm(*data, &mod, ®op, &rm);
1306 AppendToBuffer(
"psllq %s,%s",
1307 NameOfXMMRegister(regop),
1308 NameOfXMMRegister(rm));
1310 }
else if (*data == 0x73) {
1313 get_modrm(*data, &mod, ®op, &rm);
1314 int8_t imm8 =
static_cast<int8_t
>(data[1]);
1316 AppendToBuffer(
"%s %s,%d",
1317 (regop ==
esi) ?
"psllq" :
"psrlq",
1318 NameOfXMMRegister(rm),
1319 static_cast<int>(imm8));
1321 }
else if (*data == 0xD3) {
1324 get_modrm(*data, &mod, ®op, &rm);
1325 AppendToBuffer(
"psrlq %s,%s",
1326 NameOfXMMRegister(regop),
1327 NameOfXMMRegister(rm));
1329 }
else if (*data == 0x7F) {
1330 AppendToBuffer(
"movdqa ");
1333 get_modrm(*data, &mod, ®op, &rm);
1334 data += PrintRightXMMOperand(data);
1335 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1336 }
else if (*data == 0x7E) {
1339 get_modrm(*data, &mod, ®op, &rm);
1340 AppendToBuffer(
"movd ");
1341 data += PrintRightOperand(data);
1342 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1343 }
else if (*data == 0xDB) {
1346 get_modrm(*data, &mod, ®op, &rm);
1347 AppendToBuffer(
"pand %s,%s",
1348 NameOfXMMRegister(regop),
1349 NameOfXMMRegister(rm));
1351 }
else if (*data == 0xE7) {
1354 get_modrm(*data, &mod, ®op, &rm);
1356 AppendToBuffer(
"movntdq ");
1357 data += PrintRightOperand(data);
1358 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1360 UnimplementedInstruction();
1362 }
else if (*data == 0xEF) {
1365 get_modrm(*data, &mod, ®op, &rm);
1366 AppendToBuffer(
"pxor %s,%s",
1367 NameOfXMMRegister(regop),
1368 NameOfXMMRegister(rm));
1370 }
else if (*data == 0xEB) {
1373 get_modrm(*data, &mod, ®op, &rm);
1374 AppendToBuffer(
"por %s,%s",
1375 NameOfXMMRegister(regop),
1376 NameOfXMMRegister(rm));
1379 UnimplementedInstruction();
1382 UnimplementedInstruction();
1389 get_modrm(*data, &mod, ®op, &rm);
1391 AppendToBuffer(
"dec_b ");
1392 data += PrintRightOperand(data);
1394 UnimplementedInstruction();
1400 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1405 AppendToBuffer(
"push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1410 AppendToBuffer(
"test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1415 AppendToBuffer(
"test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1422 data += D1D3C1Instruction(data);
1432 data += FPUInstruction(data);
1436 data += JumpShort(data);
1440 if (*(data+1) == 0x0F) {
1441 byte b2 = *(data+2);
1443 AppendToBuffer(
"movsd ");
1446 get_modrm(*data, &mod, ®op, &rm);
1447 data += PrintRightXMMOperand(data);
1448 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1449 }
else if (b2 == 0x10) {
1452 get_modrm(*data, &mod, ®op, &rm);
1453 AppendToBuffer(
"movsd %s,", NameOfXMMRegister(regop));
1454 data += PrintRightXMMOperand(data);
1455 }
else if (b2 == 0x5A) {
1458 get_modrm(*data, &mod, ®op, &rm);
1459 AppendToBuffer(
"cvtsd2ss %s,", NameOfXMMRegister(regop));
1460 data += PrintRightXMMOperand(data);
1462 const char* mnem =
"?";
1464 case 0x2A: mnem =
"cvtsi2sd";
break;
1465 case 0x2C: mnem =
"cvttsd2si";
break;
1466 case 0x51: mnem =
"sqrtsd";
break;
1467 case 0x58: mnem =
"addsd";
break;
1468 case 0x59: mnem =
"mulsd";
break;
1469 case 0x5C: mnem =
"subsd";
break;
1470 case 0x5E: mnem =
"divsd";
break;
1474 get_modrm(*data, &mod, ®op, &rm);
1476 AppendToBuffer(
"%s %s,", mnem, NameOfXMMRegister(regop));
1477 data += PrintRightOperand(data);
1478 }
else if (b2 == 0x2C) {
1479 AppendToBuffer(
"%s %s,", mnem, NameOfCPURegister(regop));
1480 data += PrintRightXMMOperand(data);
1481 }
else if (b2 == 0xC2) {
1483 const char*
const pseudo_op[] = {
1493 AppendToBuffer(
"%s %s,%s",
1495 NameOfXMMRegister(regop),
1496 NameOfXMMRegister(rm));
1499 AppendToBuffer(
"%s %s,", mnem, NameOfXMMRegister(regop));
1500 data += PrintRightXMMOperand(data);
1504 UnimplementedInstruction();
1509 if (*(data+1) == 0x0F) {
1510 byte b2 = *(data+2);
1512 AppendToBuffer(
"movss ");
1515 get_modrm(*data, &mod, ®op, &rm);
1516 data += PrintRightXMMOperand(data);
1517 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1518 }
else if (b2 == 0x10) {
1521 get_modrm(*data, &mod, ®op, &rm);
1522 AppendToBuffer(
"movss %s,", NameOfXMMRegister(regop));
1523 data += PrintRightXMMOperand(data);
1524 }
else if (b2 == 0x2C) {
1527 get_modrm(*data, &mod, ®op, &rm);
1528 AppendToBuffer(
"cvttss2si %s,", NameOfCPURegister(regop));
1529 data += PrintRightXMMOperand(data);
1530 }
else if (b2 == 0x5A) {
1533 get_modrm(*data, &mod, ®op, &rm);
1534 AppendToBuffer(
"cvtss2sd %s,", NameOfXMMRegister(regop));
1535 data += PrintRightXMMOperand(data);
1536 }
else if (b2 == 0x6F) {
1539 get_modrm(*data, &mod, ®op, &rm);
1540 AppendToBuffer(
"movdqu %s,", NameOfXMMRegister(regop));
1541 data += PrintRightXMMOperand(data);
1542 }
else if (b2 == 0x7F) {
1543 AppendToBuffer(
"movdqu ");
1546 get_modrm(*data, &mod, ®op, &rm);
1547 data += PrintRightXMMOperand(data);
1548 AppendToBuffer(
",%s", NameOfXMMRegister(regop));
1550 UnimplementedInstruction();
1552 }
else if (*(data+1) == 0xA5) {
1554 AppendToBuffer(
"rep_movs");
1555 }
else if (*(data+1) == 0xAB) {
1557 AppendToBuffer(
"rep_stos");
1559 UnimplementedInstruction();
1564 data += F7Instruction(data);
1568 UnimplementedInstruction();
1572 if (tmp_buffer_pos_ <
sizeof tmp_buffer_) {
1573 tmp_buffer_[tmp_buffer_pos_] =
'\0';
1576 int instr_len = data - instr;
1577 if (instr_len == 0) {
1578 printf(
"%02x", *data);
1584 for (
byte* bp = instr; bp < data; bp++) {
1589 for (
int i = 6 - instr_len; i >= 0; i--) {
1596 tmp_buffer_.
start());
1604 static const char* cpu_regs[8] = {
1605 "eax",
"ecx",
"edx",
"ebx",
"esp",
"ebp",
"esi",
"edi"
1609 static const char* byte_cpu_regs[8] = {
1610 "al",
"cl",
"dl",
"bl",
"ah",
"ch",
"dh",
"bh"
1614 static const char* xmm_regs[8] = {
1615 "xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7"
1631 if (0 <= reg && reg < 8)
return cpu_regs[reg];
1637 if (0 <= reg && reg < 8)
return byte_cpu_regs[reg];
1643 if (0 <= reg && reg < 8)
return xmm_regs[reg];
1658 : converter_(converter) {}
1661 Disassembler::~Disassembler() {}
1665 byte* instruction) {
1666 DisassemblerIA32 d(converter_,
false );
1667 return d.InstructionDecode(buffer, instruction);
1672 int Disassembler::ConstantPoolSizeAt(
byte* instruction) {
return -1; }
1675 void Disassembler::Disassemble(FILE* f,
byte* begin,
byte* end) {
1676 NameConverter converter;
1677 Disassembler d(converter);
1678 for (
byte*
pc = begin;
pc < end;) {
1682 pc += d.InstructionDecode(buffer,
pc);
1683 fprintf(f,
"%p", prev_pc);
1686 for (
byte* bp = prev_pc; bp <
pc; bp++) {
1687 fprintf(f,
"%02x", *bp);
1689 for (
int i = 6 - (pc - prev_pc); i >= 0; i--) {
1692 fprintf(f,
" %s\n", buffer.
start());
1699 #endif // V8_TARGET_ARCH_IA32
Disassembler(const NameConverter &converter)
static int VSNPrintF(Vector< char > str, const char *format, va_list args)
virtual const char * NameOfXMMRegister(int reg) const
v8::internal::EmbeddedVector< char, 128 > tmp_buffer_
virtual const char * NameOfConstant(byte *addr) const
#define ASSERT(condition)
const char * comment() const
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfCPURegister(int reg) const
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
virtual const char * NameOfAddress(byte *addr) const
static int SNPrintF(Vector< char > str, const char *format,...)
#define ASSERT_EQ(v1, v2)
#define ASSERT_NE(v1, v2)