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