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