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