• 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 == 0x90) {
1293           AppendToBuffer("nop");  // 0x66 prefix
1294         } else if (*data == 0x8B) {
1295           data++;
1296           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1297         } else if (*data == 0x87) {
1298           data++;
1299           int mod, regop, rm;
1300           get_modrm(*data, &mod, &regop, &rm);
1301           AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
1302           data += PrintRightOperand(data);
1303         } else if (*data == 0x89) {
1304           data++;
1305           int mod, regop, rm;
1306           get_modrm(*data, &mod, &regop, &rm);
1307           AppendToBuffer("mov_w ");
1308           data += PrintRightOperand(data);
1309           AppendToBuffer(",%s", NameOfCPURegister(regop));
1310         } else if (*data == 0xC7) {
1311           data++;
1312           AppendToBuffer("%s ", "mov_w");
1313           data += PrintRightOperand(data);
1314           int imm = *reinterpret_cast<int16_t*>(data);
1315           AppendToBuffer(",0x%x", imm);
1316           data += 2;
1317         } else if (*data == 0xF7) {
1318           data++;
1319           AppendToBuffer("%s ", "test_w");
1320           data += PrintRightOperand(data);
1321           int imm = *reinterpret_cast<int16_t*>(data);
1322           AppendToBuffer(",0x%x", imm);
1323           data += 2;
1324         } else if (*data == 0x0F) {
1325           data++;
1326           if (*data == 0x38) {
1327             data++;
1328             if (*data == 0x17) {
1329               data++;
1330               int mod, regop, rm;
1331               get_modrm(*data, &mod, &regop, &rm);
1332               AppendToBuffer("ptest %s,%s",
1333                              NameOfXMMRegister(regop),
1334                              NameOfXMMRegister(rm));
1335               data++;
1336             } else if (*data == 0x2A) {
1337               // movntdqa
1338               UnimplementedInstruction();
1339             } else {
1340               UnimplementedInstruction();
1341             }
1342           } else if (*data == 0x3A) {
1343             data++;
1344             if (*data == 0x0B) {
1345               data++;
1346               int mod, regop, rm;
1347               get_modrm(*data, &mod, &regop, &rm);
1348               int8_t imm8 = static_cast<int8_t>(data[1]);
1349               AppendToBuffer("roundsd %s,%s,%d",
1350                              NameOfXMMRegister(regop),
1351                              NameOfXMMRegister(rm),
1352                              static_cast<int>(imm8));
1353               data += 2;
1354             } else if (*data == 0x16) {
1355               data++;
1356               int mod, regop, rm;
1357               get_modrm(*data, &mod, &rm, &regop);
1358               int8_t imm8 = static_cast<int8_t>(data[1]);
1359               AppendToBuffer("pextrd %s,%s,%d",
1360                              NameOfCPURegister(regop),
1361                              NameOfXMMRegister(rm),
1362                              static_cast<int>(imm8));
1363               data += 2;
1364             } else if (*data == 0x17) {
1365               data++;
1366               int mod, regop, rm;
1367               get_modrm(*data, &mod, &regop, &rm);
1368               int8_t imm8 = static_cast<int8_t>(data[1]);
1369               AppendToBuffer("extractps %s,%s,%d",
1370                              NameOfCPURegister(rm),
1371                              NameOfXMMRegister(regop),
1372                              static_cast<int>(imm8));
1373               data += 2;
1374             } else if (*data == 0x22) {
1375               data++;
1376               int mod, regop, rm;
1377               get_modrm(*data, &mod, &regop, &rm);
1378               int8_t imm8 = static_cast<int8_t>(data[1]);
1379               AppendToBuffer("pinsrd %s,%s,%d",
1380                              NameOfXMMRegister(regop),
1381                              NameOfCPURegister(rm),
1382                              static_cast<int>(imm8));
1383               data += 2;
1384             } else {
1385               UnimplementedInstruction();
1386             }
1387           } else if (*data == 0x2E || *data == 0x2F) {
1388             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1389             data++;
1390             int mod, regop, rm;
1391             get_modrm(*data, &mod, &regop, &rm);
1392             if (mod == 0x3) {
1393               AppendToBuffer("%s %s,%s", mnem,
1394                              NameOfXMMRegister(regop),
1395                              NameOfXMMRegister(rm));
1396               data++;
1397             } else {
1398               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1399               data += PrintRightOperand(data);
1400             }
1401           } else if (*data == 0x50) {
1402             data++;
1403             int mod, regop, rm;
1404             get_modrm(*data, &mod, &regop, &rm);
1405             AppendToBuffer("movmskpd %s,%s",
1406                            NameOfCPURegister(regop),
1407                            NameOfXMMRegister(rm));
1408             data++;
1409           } else if (*data == 0x54) {
1410             data++;
1411             int mod, regop, rm;
1412             get_modrm(*data, &mod, &regop, &rm);
1413             AppendToBuffer("andpd %s,%s",
1414                            NameOfXMMRegister(regop),
1415                            NameOfXMMRegister(rm));
1416             data++;
1417           } else if (*data == 0x56) {
1418             data++;
1419             int mod, regop, rm;
1420             get_modrm(*data, &mod, &regop, &rm);
1421             AppendToBuffer("orpd %s,%s",
1422                            NameOfXMMRegister(regop),
1423                            NameOfXMMRegister(rm));
1424             data++;
1425           } else if (*data == 0x57) {
1426             data++;
1427             int mod, regop, rm;
1428             get_modrm(*data, &mod, &regop, &rm);
1429             AppendToBuffer("xorpd %s,%s",
1430                            NameOfXMMRegister(regop),
1431                            NameOfXMMRegister(rm));
1432             data++;
1433           } else if (*data == 0x6E) {
1434             data++;
1435             int mod, regop, rm;
1436             get_modrm(*data, &mod, &regop, &rm);
1437             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1438             data += PrintRightOperand(data);
1439           } else if (*data == 0x6F) {
1440             data++;
1441             int mod, regop, rm;
1442             get_modrm(*data, &mod, &regop, &rm);
1443             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1444             data += PrintRightXMMOperand(data);
1445           } else if (*data == 0x70) {
1446             data++;
1447             int mod, regop, rm;
1448             get_modrm(*data, &mod, &regop, &rm);
1449             int8_t imm8 = static_cast<int8_t>(data[1]);
1450             AppendToBuffer("pshufd %s,%s,%d",
1451                            NameOfXMMRegister(regop),
1452                            NameOfXMMRegister(rm),
1453                            static_cast<int>(imm8));
1454             data += 2;
1455           } else if (*data == 0x76) {
1456             data++;
1457             int mod, regop, rm;
1458             get_modrm(*data, &mod, &regop, &rm);
1459             AppendToBuffer("pcmpeqd %s,%s",
1460                            NameOfXMMRegister(regop),
1461                            NameOfXMMRegister(rm));
1462             data++;
1463           } else if (*data == 0x90) {
1464             data++;
1465             AppendToBuffer("nop");  // 2 byte nop.
1466           } else if (*data == 0xF3) {
1467             data++;
1468             int mod, regop, rm;
1469             get_modrm(*data, &mod, &regop, &rm);
1470             AppendToBuffer("psllq %s,%s",
1471                            NameOfXMMRegister(regop),
1472                            NameOfXMMRegister(rm));
1473             data++;
1474           } else if (*data == 0x73) {
1475             data++;
1476             int mod, regop, rm;
1477             get_modrm(*data, &mod, &regop, &rm);
1478             int8_t imm8 = static_cast<int8_t>(data[1]);
1479             DCHECK(regop == esi || regop == edx);
1480             AppendToBuffer("%s %s,%d",
1481                            (regop == esi) ? "psllq" : "psrlq",
1482                            NameOfXMMRegister(rm),
1483                            static_cast<int>(imm8));
1484             data += 2;
1485           } else if (*data == 0xD3) {
1486             data++;
1487             int mod, regop, rm;
1488             get_modrm(*data, &mod, &regop, &rm);
1489             AppendToBuffer("psrlq %s,%s",
1490                            NameOfXMMRegister(regop),
1491                            NameOfXMMRegister(rm));
1492             data++;
1493           } else if (*data == 0x7F) {
1494             AppendToBuffer("movdqa ");
1495             data++;
1496             int mod, regop, rm;
1497             get_modrm(*data, &mod, &regop, &rm);
1498             data += PrintRightXMMOperand(data);
1499             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1500           } else if (*data == 0x7E) {
1501             data++;
1502             int mod, regop, rm;
1503             get_modrm(*data, &mod, &regop, &rm);
1504             AppendToBuffer("movd ");
1505             data += PrintRightOperand(data);
1506             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1507           } else if (*data == 0xDB) {
1508             data++;
1509             int mod, regop, rm;
1510             get_modrm(*data, &mod, &regop, &rm);
1511             AppendToBuffer("pand %s,%s",
1512                            NameOfXMMRegister(regop),
1513                            NameOfXMMRegister(rm));
1514             data++;
1515           } else if (*data == 0xE7) {
1516             data++;
1517             int mod, regop, rm;
1518             get_modrm(*data, &mod, &regop, &rm);
1519             if (mod == 3) {
1520               // movntdq
1521               UnimplementedInstruction();
1522             } else {
1523               UnimplementedInstruction();
1524             }
1525           } else if (*data == 0xEF) {
1526             data++;
1527             int mod, regop, rm;
1528             get_modrm(*data, &mod, &regop, &rm);
1529             AppendToBuffer("pxor %s,%s",
1530                            NameOfXMMRegister(regop),
1531                            NameOfXMMRegister(rm));
1532             data++;
1533           } else if (*data == 0xEB) {
1534             data++;
1535             int mod, regop, rm;
1536             get_modrm(*data, &mod, &regop, &rm);
1537             AppendToBuffer("por %s,%s",
1538                            NameOfXMMRegister(regop),
1539                            NameOfXMMRegister(rm));
1540             data++;
1541           } else if (*data == 0xB1) {
1542             data++;
1543             data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
1544           } else {
1545             UnimplementedInstruction();
1546           }
1547         } else {
1548           UnimplementedInstruction();
1549         }
1550         break;
1551 
1552       case 0xFE:
1553         { data++;
1554           int mod, regop, rm;
1555           get_modrm(*data, &mod, &regop, &rm);
1556           if (regop == ecx) {
1557             AppendToBuffer("dec_b ");
1558             data += PrintRightOperand(data);
1559           } else {
1560             UnimplementedInstruction();
1561           }
1562         }
1563         break;
1564 
1565       case 0x68:
1566         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1567         data += 5;
1568         break;
1569 
1570       case 0x6A:
1571         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1572         data += 2;
1573         break;
1574 
1575       case 0xA8:
1576         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1577         data += 2;
1578         break;
1579 
1580       case 0xA9:
1581         AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1582         data += 5;
1583         break;
1584 
1585       case 0xD1:  // fall through
1586       case 0xD3:  // fall through
1587       case 0xC1:
1588         data += D1D3C1Instruction(data);
1589         break;
1590 
1591       case 0xD8:  // fall through
1592       case 0xD9:  // fall through
1593       case 0xDA:  // fall through
1594       case 0xDB:  // fall through
1595       case 0xDC:  // fall through
1596       case 0xDD:  // fall through
1597       case 0xDE:  // fall through
1598       case 0xDF:
1599         data += FPUInstruction(data);
1600         break;
1601 
1602       case 0xEB:
1603         data += JumpShort(data);
1604         break;
1605 
1606       case 0xF2:
1607         if (*(data+1) == 0x0F) {
1608           byte b2 = *(data+2);
1609           if (b2 == 0x11) {
1610             AppendToBuffer("movsd ");
1611             data += 3;
1612             int mod, regop, rm;
1613             get_modrm(*data, &mod, &regop, &rm);
1614             data += PrintRightXMMOperand(data);
1615             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1616           } else if (b2 == 0x10) {
1617             data += 3;
1618             int mod, regop, rm;
1619             get_modrm(*data, &mod, &regop, &rm);
1620             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1621             data += PrintRightXMMOperand(data);
1622           } else  if (b2 == 0x5A) {
1623             data += 3;
1624             int mod, regop, rm;
1625             get_modrm(*data, &mod, &regop, &rm);
1626             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1627             data += PrintRightXMMOperand(data);
1628           } else {
1629             const char* mnem = "?";
1630             switch (b2) {
1631               case 0x2A: mnem = "cvtsi2sd"; break;
1632               case 0x2C: mnem = "cvttsd2si"; break;
1633               case 0x2D: mnem = "cvtsd2si"; break;
1634               case 0x51: mnem = "sqrtsd"; break;
1635               case 0x58: mnem = "addsd"; break;
1636               case 0x59: mnem = "mulsd"; break;
1637               case 0x5C: mnem = "subsd"; break;
1638               case 0x5E: mnem = "divsd"; break;
1639             }
1640             data += 3;
1641             int mod, regop, rm;
1642             get_modrm(*data, &mod, &regop, &rm);
1643             if (b2 == 0x2A) {
1644               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1645               data += PrintRightOperand(data);
1646             } else if (b2 == 0x2C || b2 == 0x2D) {
1647               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1648               data += PrintRightXMMOperand(data);
1649             } else if (b2 == 0xC2) {
1650               // Intel manual 2A, Table 3-18.
1651               const char* const pseudo_op[] = {
1652                 "cmpeqsd",
1653                 "cmpltsd",
1654                 "cmplesd",
1655                 "cmpunordsd",
1656                 "cmpneqsd",
1657                 "cmpnltsd",
1658                 "cmpnlesd",
1659                 "cmpordsd"
1660               };
1661               AppendToBuffer("%s %s,%s",
1662                              pseudo_op[data[1]],
1663                              NameOfXMMRegister(regop),
1664                              NameOfXMMRegister(rm));
1665               data += 2;
1666             } else {
1667               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1668               data += PrintRightXMMOperand(data);
1669             }
1670           }
1671         } else {
1672           UnimplementedInstruction();
1673         }
1674         break;
1675 
1676       case 0xF3:
1677         if (*(data+1) == 0x0F) {
1678           byte b2 = *(data+2);
1679           if (b2 == 0x11) {
1680             AppendToBuffer("movss ");
1681             data += 3;
1682             int mod, regop, rm;
1683             get_modrm(*data, &mod, &regop, &rm);
1684             data += PrintRightXMMOperand(data);
1685             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1686           } else if (b2 == 0x10) {
1687             data += 3;
1688             int mod, regop, rm;
1689             get_modrm(*data, &mod, &regop, &rm);
1690             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1691             data += PrintRightXMMOperand(data);
1692           } else if (b2 == 0x2C) {
1693             data += 3;
1694             int mod, regop, rm;
1695             get_modrm(*data, &mod, &regop, &rm);
1696             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1697             data += PrintRightXMMOperand(data);
1698           } else if (b2 == 0x5A) {
1699             data += 3;
1700             int mod, regop, rm;
1701             get_modrm(*data, &mod, &regop, &rm);
1702             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1703             data += PrintRightXMMOperand(data);
1704           } else if (b2 == 0x6F) {
1705             data += 3;
1706             int mod, regop, rm;
1707             get_modrm(*data, &mod, &regop, &rm);
1708             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1709             data += PrintRightXMMOperand(data);
1710           } else if (b2 == 0x7F) {
1711             AppendToBuffer("movdqu ");
1712             data += 3;
1713             int mod, regop, rm;
1714             get_modrm(*data, &mod, &regop, &rm);
1715             data += PrintRightXMMOperand(data);
1716             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1717           } else {
1718             UnimplementedInstruction();
1719           }
1720         } else if (*(data+1) == 0xA5) {
1721           data += 2;
1722           AppendToBuffer("rep_movs");
1723         } else if (*(data+1) == 0xAB) {
1724           data += 2;
1725           AppendToBuffer("rep_stos");
1726         } else {
1727           UnimplementedInstruction();
1728         }
1729         break;
1730 
1731       case 0xF7:
1732         data += F7Instruction(data);
1733         break;
1734 
1735       default:
1736         UnimplementedInstruction();
1737     }
1738   }
1739 
1740   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1741     tmp_buffer_[tmp_buffer_pos_] = '\0';
1742   }
1743 
1744   int instr_len = data - instr;
1745   if (instr_len == 0) {
1746     printf("%02x", *data);
1747   }
1748   DCHECK(instr_len > 0);  // Ensure progress.
1749 
1750   int outp = 0;
1751   // Instruction bytes.
1752   for (byte* bp = instr; bp < data; bp++) {
1753     outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
1754   }
1755   for (int i = 6 - instr_len; i >= 0; i--) {
1756     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
1757   }
1758 
1759   outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.start());
1760   return instr_len;
1761 }  // NOLINT (function is too long)
1762 
1763 
1764 //------------------------------------------------------------------------------
1765 
1766 
1767 static const char* const cpu_regs[8] = {
1768   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1769 };
1770 
1771 
1772 static const char* const byte_cpu_regs[8] = {
1773   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1774 };
1775 
1776 
1777 static const char* const xmm_regs[8] = {
1778   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1779 };
1780 
1781 
NameOfAddress(byte * addr) const1782 const char* NameConverter::NameOfAddress(byte* addr) const {
1783   v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
1784   return tmp_buffer_.start();
1785 }
1786 
1787 
NameOfConstant(byte * addr) const1788 const char* NameConverter::NameOfConstant(byte* addr) const {
1789   return NameOfAddress(addr);
1790 }
1791 
1792 
NameOfCPURegister(int reg) const1793 const char* NameConverter::NameOfCPURegister(int reg) const {
1794   if (0 <= reg && reg < 8) return cpu_regs[reg];
1795   return "noreg";
1796 }
1797 
1798 
NameOfByteCPURegister(int reg) const1799 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1800   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1801   return "noreg";
1802 }
1803 
1804 
NameOfXMMRegister(int reg) const1805 const char* NameConverter::NameOfXMMRegister(int reg) const {
1806   if (0 <= reg && reg < 8) return xmm_regs[reg];
1807   return "noxmmreg";
1808 }
1809 
1810 
NameInCode(byte * addr) const1811 const char* NameConverter::NameInCode(byte* addr) const {
1812   // X87 does not embed debug strings at the moment.
1813   UNREACHABLE();
1814   return "";
1815 }
1816 
1817 
1818 //------------------------------------------------------------------------------
1819 
Disassembler(const NameConverter & converter)1820 Disassembler::Disassembler(const NameConverter& converter)
1821     : converter_(converter) {}
1822 
1823 
~Disassembler()1824 Disassembler::~Disassembler() {}
1825 
1826 
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)1827 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1828                                     byte* instruction) {
1829   DisassemblerX87 d(converter_, false /*do not crash if unimplemented*/);
1830   return d.InstructionDecode(buffer, instruction);
1831 }
1832 
1833 
1834 // The IA-32 assembler does not currently use constant pools.
ConstantPoolSizeAt(byte * instruction)1835 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1836 
1837 
Disassemble(FILE * f,byte * begin,byte * end)1838 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1839   NameConverter converter;
1840   Disassembler d(converter);
1841   for (byte* pc = begin; pc < end;) {
1842     v8::internal::EmbeddedVector<char, 128> buffer;
1843     buffer[0] = '\0';
1844     byte* prev_pc = pc;
1845     pc += d.InstructionDecode(buffer, pc);
1846     fprintf(f, "%p", static_cast<void*>(prev_pc));
1847     fprintf(f, "    ");
1848 
1849     for (byte* bp = prev_pc; bp < pc; bp++) {
1850       fprintf(f, "%02x",  *bp);
1851     }
1852     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1853       fprintf(f, "  ");
1854     }
1855     fprintf(f, "  %s\n", buffer.start());
1856   }
1857 }
1858 
1859 
1860 }  // namespace disasm
1861 
1862 #endif  // V8_TARGET_ARCH_X87
1863