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