• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 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 #include "disasm.h"
34 
35 namespace disasm {
36 
37 enum OperandType {
38   UNSET_OP_ORDER = 0,
39   // Operand size decides between 16, 32 and 64 bit operands.
40   REG_OPER_OP_ORDER = 1,  // Register destination, operand source.
41   OPER_REG_OP_ORDER = 2,  // Operand destination, register source.
42   // Fixed 8-bit operands.
43   BYTE_SIZE_OPERAND_FLAG = 4,
44   BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
45   BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
46 };
47 
48 //------------------------------------------------------------------
49 // Tables
50 //------------------------------------------------------------------
51 struct ByteMnemonic {
52   int b;  // -1 terminates, otherwise must be in range (0..255)
53   OperandType op_order_;
54   const char* mnem;
55 };
56 
57 
58 static ByteMnemonic two_operands_instr[] = {
59   { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
60   { 0x01, OPER_REG_OP_ORDER,      "add" },
61   { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
62   { 0x03, REG_OPER_OP_ORDER,      "add" },
63   { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
64   { 0x09, OPER_REG_OP_ORDER,      "or" },
65   { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
66   { 0x0B, REG_OPER_OP_ORDER,      "or" },
67   { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
68   { 0x11, OPER_REG_OP_ORDER,      "adc" },
69   { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
70   { 0x13, REG_OPER_OP_ORDER,      "adc" },
71   { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
72   { 0x19, OPER_REG_OP_ORDER,      "sbb" },
73   { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
74   { 0x1B, REG_OPER_OP_ORDER,      "sbb" },
75   { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
76   { 0x21, OPER_REG_OP_ORDER,      "and" },
77   { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
78   { 0x23, REG_OPER_OP_ORDER,      "and" },
79   { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
80   { 0x29, OPER_REG_OP_ORDER,      "sub" },
81   { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
82   { 0x2B, REG_OPER_OP_ORDER,      "sub" },
83   { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
84   { 0x31, OPER_REG_OP_ORDER,      "xor" },
85   { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
86   { 0x33, REG_OPER_OP_ORDER,      "xor" },
87   { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
88   { 0x39, OPER_REG_OP_ORDER,      "cmp" },
89   { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
90   { 0x3B, REG_OPER_OP_ORDER,      "cmp" },
91   { 0x63, REG_OPER_OP_ORDER,      "movsxlq" },
92   { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
93   { 0x85, REG_OPER_OP_ORDER,      "test" },
94   { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
95   { 0x87, REG_OPER_OP_ORDER,      "xchg" },
96   { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
97   { 0x89, OPER_REG_OP_ORDER,      "mov" },
98   { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
99   { 0x8B, REG_OPER_OP_ORDER,      "mov" },
100   { 0x8D, REG_OPER_OP_ORDER,      "lea" },
101   { -1, UNSET_OP_ORDER, "" }
102 };
103 
104 
105 static ByteMnemonic zero_operands_instr[] = {
106   { 0xC3, UNSET_OP_ORDER, "ret" },
107   { 0xC9, UNSET_OP_ORDER, "leave" },
108   { 0xF4, UNSET_OP_ORDER, "hlt" },
109   { 0xCC, UNSET_OP_ORDER, "int3" },
110   { 0x60, UNSET_OP_ORDER, "pushad" },
111   { 0x61, UNSET_OP_ORDER, "popad" },
112   { 0x9C, UNSET_OP_ORDER, "pushfd" },
113   { 0x9D, UNSET_OP_ORDER, "popfd" },
114   { 0x9E, UNSET_OP_ORDER, "sahf" },
115   { 0x99, UNSET_OP_ORDER, "cdq" },
116   { 0x9B, UNSET_OP_ORDER, "fwait" },
117   { -1, UNSET_OP_ORDER, "" }
118 };
119 
120 
121 static ByteMnemonic call_jump_instr[] = {
122   { 0xE8, UNSET_OP_ORDER, "call" },
123   { 0xE9, UNSET_OP_ORDER, "jmp" },
124   { -1, UNSET_OP_ORDER, "" }
125 };
126 
127 
128 static ByteMnemonic short_immediate_instr[] = {
129   { 0x05, UNSET_OP_ORDER, "add" },
130   { 0x0D, UNSET_OP_ORDER, "or" },
131   { 0x15, UNSET_OP_ORDER, "adc" },
132   { 0x1D, UNSET_OP_ORDER, "sbb" },
133   { 0x25, UNSET_OP_ORDER, "and" },
134   { 0x2D, UNSET_OP_ORDER, "sub" },
135   { 0x35, UNSET_OP_ORDER, "xor" },
136   { 0x3D, UNSET_OP_ORDER, "cmp" },
137   { -1, UNSET_OP_ORDER, "" }
138 };
139 
140 
141 static const char* conditional_code_suffix[] = {
142   "o", "no", "c", "nc", "z", "nz", "na", "a",
143   "s", "ns", "pe", "po", "l", "ge", "le", "g"
144 };
145 
146 
147 enum InstructionType {
148   NO_INSTR,
149   ZERO_OPERANDS_INSTR,
150   TWO_OPERANDS_INSTR,
151   JUMP_CONDITIONAL_SHORT_INSTR,
152   REGISTER_INSTR,
153   PUSHPOP_INSTR,  // Has implicit 64-bit operand size.
154   MOVE_REG_INSTR,
155   CALL_JUMP_INSTR,
156   SHORT_IMMEDIATE_INSTR
157 };
158 
159 
160 struct InstructionDesc {
161   const char* mnem;
162   InstructionType type;
163   OperandType op_order_;
164   bool byte_size_operation;  // Fixed 8-bit operation.
165 };
166 
167 
168 class InstructionTable {
169  public:
170   InstructionTable();
Get(byte x) const171   const InstructionDesc& Get(byte x) const {
172     return instructions_[x];
173   }
174 
175  private:
176   InstructionDesc instructions_[256];
177   void Clear();
178   void Init();
179   void CopyTable(ByteMnemonic bm[], InstructionType type);
180   void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
181                      const char* mnem);
182   void AddJumpConditionalShort();
183 };
184 
185 
InstructionTable()186 InstructionTable::InstructionTable() {
187   Clear();
188   Init();
189 }
190 
191 
Clear()192 void InstructionTable::Clear() {
193   for (int i = 0; i < 256; i++) {
194     instructions_[i].mnem = "(bad)";
195     instructions_[i].type = NO_INSTR;
196     instructions_[i].op_order_ = UNSET_OP_ORDER;
197     instructions_[i].byte_size_operation = false;
198   }
199 }
200 
201 
Init()202 void InstructionTable::Init() {
203   CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
204   CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
205   CopyTable(call_jump_instr, CALL_JUMP_INSTR);
206   CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
207   AddJumpConditionalShort();
208   SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
209   SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
210   SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
211 }
212 
213 
CopyTable(ByteMnemonic bm[],InstructionType type)214 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
215   for (int i = 0; bm[i].b >= 0; i++) {
216     InstructionDesc* id = &instructions_[bm[i].b];
217     id->mnem = bm[i].mnem;
218     OperandType op_order = bm[i].op_order_;
219     id->op_order_ =
220         static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
221     assert(id->type == NO_INSTR);  // Information not already entered
222     id->type = type;
223     id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
224   }
225 }
226 
227 
SetTableRange(InstructionType type,byte start,byte end,bool byte_size,const char * mnem)228 void InstructionTable::SetTableRange(InstructionType type,
229                                      byte start,
230                                      byte end,
231                                      bool byte_size,
232                                      const char* mnem) {
233   for (byte b = start; b <= end; b++) {
234     InstructionDesc* id = &instructions_[b];
235     assert(id->type == NO_INSTR);  // Information already entered
236     id->mnem = mnem;
237     id->type = type;
238     id->byte_size_operation = byte_size;
239   }
240 }
241 
242 
AddJumpConditionalShort()243 void InstructionTable::AddJumpConditionalShort() {
244   for (byte b = 0x70; b <= 0x7F; b++) {
245     InstructionDesc* id = &instructions_[b];
246     assert(id->type == NO_INSTR);  // Information already entered
247     id->mnem = NULL;  // Computed depending on condition code.
248     id->type = JUMP_CONDITIONAL_SHORT_INSTR;
249   }
250 }
251 
252 
253 static InstructionTable instruction_table;
254 
255 static InstructionDesc cmov_instructions[16] = {
256   {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
257   {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258   {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259   {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260   {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261   {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262   {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263   {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264   {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265   {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266   {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267   {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268   {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269   {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270   {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271   {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
272 };
273 
274 //------------------------------------------------------------------------------
275 // DisassemblerX64 implementation.
276 
277 enum UnimplementedOpcodeAction {
278   CONTINUE_ON_UNIMPLEMENTED_OPCODE,
279   ABORT_ON_UNIMPLEMENTED_OPCODE
280 };
281 
282 // A new DisassemblerX64 object is created to disassemble each instruction.
283 // The object can only disassemble a single instruction.
284 class DisassemblerX64 {
285  public:
DisassemblerX64(const NameConverter & converter,UnimplementedOpcodeAction unimplemented_action=ABORT_ON_UNIMPLEMENTED_OPCODE)286   DisassemblerX64(const NameConverter& converter,
287                   UnimplementedOpcodeAction unimplemented_action =
288                       ABORT_ON_UNIMPLEMENTED_OPCODE)
289       : converter_(converter),
290         tmp_buffer_pos_(0),
291         abort_on_unimplemented_(
292             unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
293         rex_(0),
294         operand_size_(0),
295         group_1_prefix_(0),
296         byte_size_operand_(false) {
297     tmp_buffer_[0] = '\0';
298   }
299 
~DisassemblerX64()300   virtual ~DisassemblerX64() {
301   }
302 
303   // Writes one disassembled instruction into 'buffer' (0-terminated).
304   // Returns the length of the disassembled machine instruction in bytes.
305   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
306 
307  private:
308   enum OperandSize {
309     BYTE_SIZE = 0,
310     WORD_SIZE = 1,
311     DOUBLEWORD_SIZE = 2,
312     QUADWORD_SIZE = 3
313   };
314 
315   const NameConverter& converter_;
316   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
317   unsigned int tmp_buffer_pos_;
318   bool abort_on_unimplemented_;
319   // Prefixes parsed
320   byte rex_;
321   byte operand_size_;  // 0x66 or (if no group 3 prefix is present) 0x0.
322   byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
323   // Byte size operand override.
324   bool byte_size_operand_;
325 
setRex(byte rex)326   void setRex(byte rex) {
327     ASSERT_EQ(0x40, rex & 0xF0);
328     rex_ = rex;
329   }
330 
rex()331   bool rex() { return rex_ != 0; }
332 
rex_b()333   bool rex_b() { return (rex_ & 0x01) != 0; }
334 
335   // Actual number of base register given the low bits and the rex.b state.
base_reg(int low_bits)336   int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
337 
rex_x()338   bool rex_x() { return (rex_ & 0x02) != 0; }
339 
rex_r()340   bool rex_r() { return (rex_ & 0x04) != 0; }
341 
rex_w()342   bool rex_w() { return (rex_ & 0x08) != 0; }
343 
operand_size()344   OperandSize operand_size() {
345     if (byte_size_operand_) return BYTE_SIZE;
346     if (rex_w()) return QUADWORD_SIZE;
347     if (operand_size_ != 0) return WORD_SIZE;
348     return DOUBLEWORD_SIZE;
349   }
350 
operand_size_code()351   char operand_size_code() {
352     return "bwlq"[operand_size()];
353   }
354 
NameOfCPURegister(int reg) const355   const char* NameOfCPURegister(int reg) const {
356     return converter_.NameOfCPURegister(reg);
357   }
358 
NameOfByteCPURegister(int reg) const359   const char* NameOfByteCPURegister(int reg) const {
360     return converter_.NameOfByteCPURegister(reg);
361   }
362 
NameOfXMMRegister(int reg) const363   const char* NameOfXMMRegister(int reg) const {
364     return converter_.NameOfXMMRegister(reg);
365   }
366 
NameOfAddress(byte * addr) const367   const char* NameOfAddress(byte* addr) const {
368     return converter_.NameOfAddress(addr);
369   }
370 
371   // Disassembler helper functions.
get_modrm(byte data,int * mod,int * regop,int * rm)372   void get_modrm(byte data,
373                  int* mod,
374                  int* regop,
375                  int* rm) {
376     *mod = (data >> 6) & 3;
377     *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
378     *rm = (data & 7) | (rex_b() ? 8 : 0);
379   }
380 
get_sib(byte data,int * scale,int * index,int * base)381   void get_sib(byte data,
382                int* scale,
383                int* index,
384                int* base) {
385     *scale = (data >> 6) & 3;
386     *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
387     *base = (data & 7) | (rex_b() ? 8 : 0);
388   }
389 
390   typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
391 
392   int PrintRightOperandHelper(byte* modrmp,
393                               RegisterNameMapping register_name);
394   int PrintRightOperand(byte* modrmp);
395   int PrintRightByteOperand(byte* modrmp);
396   int PrintOperands(const char* mnem,
397                     OperandType op_order,
398                     byte* data);
399   int PrintImmediate(byte* data, OperandSize size);
400   int PrintImmediateOp(byte* data);
401   const char* TwoByteMnemonic(byte opcode);
402   int TwoByteOpcodeInstruction(byte* data);
403   int F7Instruction(byte* data);
404   int ShiftInstruction(byte* data);
405   int JumpShort(byte* data);
406   int JumpConditional(byte* data);
407   int JumpConditionalShort(byte* data);
408   int SetCC(byte* data);
409   int FPUInstruction(byte* data);
410   void AppendToBuffer(const char* format, ...);
411 
UnimplementedInstruction()412   void UnimplementedInstruction() {
413     if (abort_on_unimplemented_) {
414       CHECK(false);
415     } else {
416       AppendToBuffer("'Unimplemented Instruction'");
417     }
418   }
419 };
420 
421 
AppendToBuffer(const char * format,...)422 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
423   v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
424   va_list args;
425   va_start(args, format);
426   int result = v8::internal::OS::VSNPrintF(buf, format, args);
427   va_end(args);
428   tmp_buffer_pos_ += result;
429 }
430 
431 
PrintRightOperandHelper(byte * modrmp,RegisterNameMapping register_name)432 int DisassemblerX64::PrintRightOperandHelper(
433     byte* modrmp,
434     RegisterNameMapping register_name) {
435   int mod, regop, rm;
436   get_modrm(*modrmp, &mod, &regop, &rm);
437   switch (mod) {
438     case 0:
439       if ((rm & 7) == 5) {
440         int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
441         AppendToBuffer("[0x%x]", disp);
442         return 5;
443       } else if ((rm & 7) == 4) {
444         // Codes for SIB byte.
445         byte sib = *(modrmp + 1);
446         int scale, index, base;
447         get_sib(sib, &scale, &index, &base);
448         if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
449           // index == rsp means no index. Only use sib byte with no index for
450           // rsp and r12 base.
451           AppendToBuffer("[%s]", (this->*register_name)(base));
452           return 2;
453         } else if (base == 5) {
454           // base == rbp means no base register (when mod == 0).
455           int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
456           AppendToBuffer("[%s*%d+0x%x]",
457                          (this->*register_name)(index),
458                          1 << scale, disp);
459           return 6;
460         } else if (index != 4 && base != 5) {
461           // [base+index*scale]
462           AppendToBuffer("[%s+%s*%d]",
463                          (this->*register_name)(base),
464                          (this->*register_name)(index),
465                          1 << scale);
466           return 2;
467         } else {
468           UnimplementedInstruction();
469           return 1;
470         }
471       } else {
472         AppendToBuffer("[%s]", (this->*register_name)(rm));
473         return 1;
474       }
475       break;
476     case 1:  // fall through
477     case 2:
478       if ((rm & 7) == 4) {
479         byte sib = *(modrmp + 1);
480         int scale, index, base;
481         get_sib(sib, &scale, &index, &base);
482         int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
483                               : *reinterpret_cast<char*>(modrmp + 2);
484         if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
485           if (-disp > 0) {
486             AppendToBuffer("[%s-0x%x]", (this->*register_name)(base), -disp);
487           } else {
488             AppendToBuffer("[%s+0x%x]", (this->*register_name)(base), disp);
489           }
490         } else {
491           if (-disp > 0) {
492             AppendToBuffer("[%s+%s*%d-0x%x]",
493                            (this->*register_name)(base),
494                            (this->*register_name)(index),
495                            1 << scale,
496                            -disp);
497           } else {
498             AppendToBuffer("[%s+%s*%d+0x%x]",
499                            (this->*register_name)(base),
500                            (this->*register_name)(index),
501                            1 << scale,
502                            disp);
503           }
504         }
505         return mod == 2 ? 6 : 3;
506       } else {
507         // No sib.
508         int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
509                               : *reinterpret_cast<char*>(modrmp + 1);
510         if (-disp > 0) {
511         AppendToBuffer("[%s-0x%x]", (this->*register_name)(rm), -disp);
512         } else {
513         AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
514         }
515         return (mod == 2) ? 5 : 2;
516       }
517       break;
518     case 3:
519       AppendToBuffer("%s", (this->*register_name)(rm));
520       return 1;
521     default:
522       UnimplementedInstruction();
523       return 1;
524   }
525   UNREACHABLE();
526 }
527 
528 
PrintImmediate(byte * data,OperandSize size)529 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
530   int64_t value;
531   int count;
532   switch (size) {
533     case BYTE_SIZE:
534       value = *data;
535       count = 1;
536       break;
537     case WORD_SIZE:
538       value = *reinterpret_cast<int16_t*>(data);
539       count = 2;
540       break;
541     case DOUBLEWORD_SIZE:
542       value = *reinterpret_cast<uint32_t*>(data);
543       count = 4;
544       break;
545     case QUADWORD_SIZE:
546       value = *reinterpret_cast<int32_t*>(data);
547       count = 4;
548       break;
549     default:
550       UNREACHABLE();
551       value = 0;  // Initialize variables on all paths to satisfy the compiler.
552       count = 0;
553   }
554   AppendToBuffer("%" V8_PTR_PREFIX "x", value);
555   return count;
556 }
557 
558 
PrintRightOperand(byte * modrmp)559 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
560   return PrintRightOperandHelper(modrmp,
561                                  &DisassemblerX64::NameOfCPURegister);
562 }
563 
564 
PrintRightByteOperand(byte * modrmp)565 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
566   return PrintRightOperandHelper(modrmp,
567                                  &DisassemblerX64::NameOfByteCPURegister);
568 }
569 
570 
571 // Returns number of bytes used including the current *data.
572 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
PrintOperands(const char * mnem,OperandType op_order,byte * data)573 int DisassemblerX64::PrintOperands(const char* mnem,
574                                    OperandType op_order,
575                                    byte* data) {
576   byte modrm = *data;
577   int mod, regop, rm;
578   get_modrm(modrm, &mod, &regop, &rm);
579   int advance = 0;
580   const char* register_name =
581       byte_size_operand_ ? NameOfByteCPURegister(regop)
582                          : NameOfCPURegister(regop);
583   switch (op_order) {
584     case REG_OPER_OP_ORDER: {
585       AppendToBuffer("%s%c %s,",
586                      mnem,
587                      operand_size_code(),
588                      register_name);
589       advance = byte_size_operand_ ? PrintRightByteOperand(data)
590                                    : PrintRightOperand(data);
591       break;
592     }
593     case OPER_REG_OP_ORDER: {
594       AppendToBuffer("%s%c ", mnem, operand_size_code());
595       advance = byte_size_operand_ ? PrintRightByteOperand(data)
596                                    : PrintRightOperand(data);
597       AppendToBuffer(",%s", register_name);
598       break;
599     }
600     default:
601       UNREACHABLE();
602       break;
603   }
604   return advance;
605 }
606 
607 
608 // Returns number of bytes used by machine instruction, including *data byte.
609 // Writes immediate instructions to 'tmp_buffer_'.
PrintImmediateOp(byte * data)610 int DisassemblerX64::PrintImmediateOp(byte* data) {
611   bool byte_size_immediate = (*data & 0x02) != 0;
612   byte modrm = *(data + 1);
613   int mod, regop, rm;
614   get_modrm(modrm, &mod, &regop, &rm);
615   const char* mnem = "Imm???";
616   switch (regop) {
617     case 0:
618       mnem = "add";
619       break;
620     case 1:
621       mnem = "or";
622       break;
623     case 2:
624       mnem = "adc";
625       break;
626     case 4:
627       mnem = "and";
628       break;
629     case 5:
630       mnem = "sub";
631       break;
632     case 6:
633       mnem = "xor";
634       break;
635     case 7:
636       mnem = "cmp";
637       break;
638     default:
639       UnimplementedInstruction();
640   }
641   AppendToBuffer("%s%c ", mnem, operand_size_code());
642   int count = PrintRightOperand(data + 1);
643   AppendToBuffer(",0x");
644   OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
645   count += PrintImmediate(data + 1 + count, immediate_size);
646   return 1 + count;
647 }
648 
649 
650 // Returns number of bytes used, including *data.
F7Instruction(byte * data)651 int DisassemblerX64::F7Instruction(byte* data) {
652   assert(*data == 0xF7);
653   byte modrm = *(data + 1);
654   int mod, regop, rm;
655   get_modrm(modrm, &mod, &regop, &rm);
656   if (mod == 3 && regop != 0) {
657     const char* mnem = NULL;
658     switch (regop) {
659       case 2:
660         mnem = "not";
661         break;
662       case 3:
663         mnem = "neg";
664         break;
665       case 4:
666         mnem = "mul";
667         break;
668       case 7:
669         mnem = "idiv";
670         break;
671       default:
672         UnimplementedInstruction();
673     }
674     AppendToBuffer("%s%c %s",
675                    mnem,
676                    operand_size_code(),
677                    NameOfCPURegister(rm));
678     return 2;
679   } else if (mod == 3 && regop == 0) {
680     int32_t imm = *reinterpret_cast<int32_t*>(data + 2);
681     AppendToBuffer("test%c %s,0x%x",
682                    operand_size_code(),
683                    NameOfCPURegister(rm),
684                    imm);
685     return 6;
686   } else if (regop == 0) {
687     AppendToBuffer("test%c ", operand_size_code());
688     int count = PrintRightOperand(data + 1);
689     int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count);
690     AppendToBuffer(",0x%x", imm);
691     return 1 + count + 4 /*int32_t*/;
692   } else {
693     UnimplementedInstruction();
694     return 2;
695   }
696 }
697 
698 
ShiftInstruction(byte * data)699 int DisassemblerX64::ShiftInstruction(byte* data) {
700   byte op = *data & (~1);
701   if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
702     UnimplementedInstruction();
703     return 1;
704   }
705   byte modrm = *(data + 1);
706   int mod, regop, rm;
707   get_modrm(modrm, &mod, &regop, &rm);
708   regop &= 0x7;  // The REX.R bit does not affect the operation.
709   int imm8 = -1;
710   int num_bytes = 2;
711   if (mod != 3) {
712     UnimplementedInstruction();
713     return num_bytes;
714   }
715   const char* mnem = NULL;
716   switch (regop) {
717     case 0:
718       mnem = "rol";
719       break;
720     case 1:
721       mnem = "ror";
722       break;
723     case 2:
724       mnem = "rcl";
725       break;
726     case 3:
727       mnem = "rcr";
728       break;
729     case 4:
730       mnem = "shl";
731       break;
732     case 5:
733       mnem = "shr";
734       break;
735     case 7:
736       mnem = "sar";
737       break;
738     default:
739       UnimplementedInstruction();
740       return num_bytes;
741   }
742   assert(mnem != NULL);
743   if (op == 0xD0) {
744     imm8 = 1;
745   } else if (op == 0xC0) {
746     imm8 = *(data + 2);
747     num_bytes = 3;
748   }
749   AppendToBuffer("%s%c %s,",
750                  mnem,
751                  operand_size_code(),
752                  byte_size_operand_ ? NameOfByteCPURegister(rm)
753                                     : NameOfCPURegister(rm));
754   if (op == 0xD2) {
755     AppendToBuffer("cl");
756   } else {
757     AppendToBuffer("%d", imm8);
758   }
759   return num_bytes;
760 }
761 
762 
763 // Returns number of bytes used, including *data.
JumpShort(byte * data)764 int DisassemblerX64::JumpShort(byte* data) {
765   assert(*data == 0xEB);
766   byte b = *(data + 1);
767   byte* dest = data + static_cast<int8_t>(b) + 2;
768   AppendToBuffer("jmp %s", NameOfAddress(dest));
769   return 2;
770 }
771 
772 
773 // Returns number of bytes used, including *data.
JumpConditional(byte * data)774 int DisassemblerX64::JumpConditional(byte* data) {
775   assert(*data == 0x0F);
776   byte cond = *(data + 1) & 0x0F;
777   byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
778   const char* mnem = conditional_code_suffix[cond];
779   AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
780   return 6;  // includes 0x0F
781 }
782 
783 
784 // Returns number of bytes used, including *data.
JumpConditionalShort(byte * data)785 int DisassemblerX64::JumpConditionalShort(byte* data) {
786   byte cond = *data & 0x0F;
787   byte b = *(data + 1);
788   byte* dest = data + static_cast<int8_t>(b) + 2;
789   const char* mnem = conditional_code_suffix[cond];
790   AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
791   return 2;
792 }
793 
794 
795 // Returns number of bytes used, including *data.
SetCC(byte * data)796 int DisassemblerX64::SetCC(byte* data) {
797   assert(*data == 0x0F);
798   byte cond = *(data + 1) & 0x0F;
799   const char* mnem = conditional_code_suffix[cond];
800   AppendToBuffer("set%s%c ", mnem, operand_size_code());
801   PrintRightByteOperand(data + 2);
802   return 3;  // includes 0x0F
803 }
804 
805 
806 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)807 int DisassemblerX64::FPUInstruction(byte* data) {
808   byte b1 = *data;
809   byte b2 = *(data + 1);
810   if (b1 == 0xD9) {
811     const char* mnem = NULL;
812     switch (b2) {
813       case 0xE0:
814         mnem = "fchs";
815         break;
816       case 0xE1:
817         mnem = "fabs";
818         break;
819       case 0xE4:
820         mnem = "ftst";
821         break;
822       case 0xF5:
823         mnem = "fprem1";
824         break;
825       case 0xF7:
826         mnem = "fincstp";
827         break;
828       case 0xE8:
829         mnem = "fld1";
830         break;
831       case 0xEE:
832         mnem = "fldz";
833         break;
834       case 0xF8:
835         mnem = "fprem";
836         break;
837     }
838     if (mnem != NULL) {
839       AppendToBuffer("%s", mnem);
840       return 2;
841     } else if ((b2 & 0xF8) == 0xC8) {
842       AppendToBuffer("fxch st%d", b2 & 0x7);
843       return 2;
844     } else {
845       int mod, regop, rm;
846       get_modrm(*(data + 1), &mod, &regop, &rm);
847       const char* mnem = "?";
848       switch (regop) {
849         case 0:
850           mnem = "fld_s";
851           break;
852         case 3:
853           mnem = "fstp_s";
854           break;
855         default:
856           UnimplementedInstruction();
857       }
858       AppendToBuffer("%s ", mnem);
859       int count = PrintRightOperand(data + 1);
860       return count + 1;
861     }
862   } else if (b1 == 0xDD) {
863     if ((b2 & 0xF8) == 0xC0) {
864       AppendToBuffer("ffree st%d", b2 & 0x7);
865       return 2;
866     } else {
867       int mod, regop, rm;
868       get_modrm(*(data + 1), &mod, &regop, &rm);
869       const char* mnem = "?";
870       switch (regop) {
871         case 0:
872           mnem = "fld_d";
873           break;
874         case 3:
875           mnem = "fstp_d";
876           break;
877         default:
878           UnimplementedInstruction();
879       }
880       AppendToBuffer("%s ", mnem);
881       int count = PrintRightOperand(data + 1);
882       return count + 1;
883     }
884   } else if (b1 == 0xDB) {
885     int mod, regop, rm;
886     get_modrm(*(data + 1), &mod, &regop, &rm);
887     const char* mnem = "?";
888     switch (regop) {
889       case 0:
890         mnem = "fild_s";
891         break;
892       case 2:
893         mnem = "fist_s";
894         break;
895       case 3:
896         mnem = "fistp_s";
897         break;
898       default:
899         UnimplementedInstruction();
900     }
901     AppendToBuffer("%s ", mnem);
902     int count = PrintRightOperand(data + 1);
903     return count + 1;
904   } else if (b1 == 0xDF) {
905     if (b2 == 0xE0) {
906       AppendToBuffer("fnstsw_ax");
907       return 2;
908     }
909     int mod, regop, rm;
910     get_modrm(*(data + 1), &mod, &regop, &rm);
911     const char* mnem = "?";
912     switch (regop) {
913       case 5:
914         mnem = "fild_d";
915         break;
916       case 7:
917         mnem = "fistp_d";
918         break;
919       default:
920         UnimplementedInstruction();
921     }
922     AppendToBuffer("%s ", mnem);
923     int count = PrintRightOperand(data + 1);
924     return count + 1;
925   } else if (b1 == 0xDC || b1 == 0xDE) {
926     bool is_pop = (b1 == 0xDE);
927     if (is_pop && b2 == 0xD9) {
928       AppendToBuffer("fcompp");
929       return 2;
930     }
931     const char* mnem = "FP0xDC";
932     switch (b2 & 0xF8) {
933       case 0xC0:
934         mnem = "fadd";
935         break;
936       case 0xE8:
937         mnem = "fsub";
938         break;
939       case 0xC8:
940         mnem = "fmul";
941         break;
942       case 0xF8:
943         mnem = "fdiv";
944         break;
945       default:
946         UnimplementedInstruction();
947     }
948     AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7);
949     return 2;
950   } else if (b1 == 0xDA && b2 == 0xE9) {
951     const char* mnem = "fucompp";
952     AppendToBuffer("%s", mnem);
953     return 2;
954   }
955   AppendToBuffer("Unknown FP instruction");
956   return 2;
957 }
958 
959 
960 // Handle all two-byte opcodes, which start with 0x0F.
961 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
962 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
TwoByteOpcodeInstruction(byte * data)963 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
964   byte opcode = *(data + 1);
965   byte* current = data + 2;
966   // At return, "current" points to the start of the next instruction.
967   const char* mnemonic = TwoByteMnemonic(opcode);
968   if (opcode == 0x1F) {
969     // NOP
970     int mod, regop, rm;
971     get_modrm(*current, &mod, &regop, &rm);
972     current++;
973     if (regop == 4) {  // SIB byte present.
974       current++;
975     }
976     if (mod == 1) {  // Byte displacement.
977       current += 1;
978     } else if (mod == 2) {  // 32-bit displacement.
979       current += 4;
980     }  // else no immediate displacement.
981     AppendToBuffer("nop");
982 
983   } else  if (opcode == 0xA2 || opcode == 0x31) {
984     // RDTSC or CPUID
985     AppendToBuffer("%s", mnemonic);
986 
987   } else if ((opcode & 0xF0) == 0x40) {
988     // CMOVcc: conditional move.
989     int condition = opcode & 0x0F;
990     const InstructionDesc& idesc = cmov_instructions[condition];
991     byte_size_operand_ = idesc.byte_size_operation;
992     current += PrintOperands(idesc.mnem, idesc.op_order_, current);
993 
994   } else if ((opcode & 0xF0) == 0x80) {
995     // Jcc: Conditional jump (branch).
996     current = data + JumpConditional(data);
997 
998   } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
999              opcode == 0xB7 || opcode == 0xAF) {
1000     // Size-extending moves, IMUL.
1001     current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1002 
1003   } else if ((opcode & 0xF0) == 0x90) {
1004     // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1005     current = data + SetCC(data);
1006 
1007   } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1008     // SHLD, SHRD (double-precision shift), BTS (bit set).
1009     AppendToBuffer("%s ", mnemonic);
1010     int mod, regop, rm;
1011     get_modrm(*current, &mod, &regop, &rm);
1012     current += PrintRightOperand(current);
1013     if (opcode == 0xAB) {
1014       AppendToBuffer(",%s", NameOfCPURegister(regop));
1015     } else {
1016       AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1017     }
1018   } else if (group_1_prefix_ == 0xF2) {
1019     // Beginning of instructions with prefix 0xF2.
1020 
1021     if (opcode == 0x11 || opcode == 0x10) {
1022       // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1023       AppendToBuffer("movsd ");
1024       int mod, regop, rm;
1025       get_modrm(*current, &mod, &regop, &rm);
1026       if (opcode == 0x11) {
1027         current += PrintRightOperand(current);
1028         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1029       } else {
1030         AppendToBuffer("%s,", NameOfXMMRegister(regop));
1031         current += PrintRightOperand(current);
1032       }
1033     } else if (opcode == 0x2A) {
1034       // CVTSI2SD: integer to XMM double conversion.
1035       int mod, regop, rm;
1036       get_modrm(*current, &mod, &regop, &rm);
1037       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1038       data += PrintRightOperand(data);
1039     } else if ((opcode & 0xF8) == 0x58) {
1040       // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1041       int mod, regop, rm;
1042       get_modrm(*current, &mod, &regop, &rm);
1043       AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop),
1044                      NameOfXMMRegister(rm));
1045     } else {
1046       UnimplementedInstruction();
1047     }
1048   } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
1049     // Instruction with prefix 0xF3.
1050 
1051     // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
1052     // Assert that mod is not 3, so source is memory, not an XMM register.
1053     ASSERT((*current & 0xC0) != 0xC0);
1054     current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
1055   } else {
1056     UnimplementedInstruction();
1057   }
1058   return current - data;
1059 }
1060 
1061 
1062 // Mnemonics for two-byte opcode instructions starting with 0x0F.
1063 // The argument is the second byte of the two-byte opcode.
1064 // Returns NULL if the instruction is not handled here.
TwoByteMnemonic(byte opcode)1065 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1066   switch (opcode) {
1067     case 0x1F:
1068       return "nop";
1069     case 0x2A:  // F2 prefix.
1070       return "cvtsi2sd";
1071     case 0x31:
1072       return "rdtsc";
1073     case 0x58:  // F2 prefix.
1074       return "addsd";
1075     case 0x59:  // F2 prefix.
1076       return "mulsd";
1077     case 0x5C:  // F2 prefix.
1078       return "subsd";
1079     case 0x5E:  // F2 prefix.
1080       return "divsd";
1081     case 0xA2:
1082       return "cpuid";
1083     case 0xA5:
1084       return "shld";
1085     case 0xAB:
1086       return "bts";
1087     case 0xAD:
1088       return "shrd";
1089     case 0xAF:
1090       return "imul";
1091     case 0xB6:
1092       return "movzxb";
1093     case 0xB7:
1094       return "movzxw";
1095     case 0xBE:
1096       return "movsxb";
1097     case 0xBF:
1098       return "movsxw";
1099     default:
1100       return NULL;
1101   }
1102 }
1103 
1104 
1105 // Disassembles the instruction at instr, and writes it into out_buffer.
InstructionDecode(v8::internal::Vector<char> out_buffer,byte * instr)1106 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1107                                        byte* instr) {
1108   tmp_buffer_pos_ = 0;  // starting to write as position 0
1109   byte* data = instr;
1110   bool processed = true;  // Will be set to false if the current instruction
1111                           // is not in 'instructions' table.
1112   byte current;
1113 
1114   // Scan for prefixes.
1115   while (true) {
1116     current = *data;
1117     if (current == 0x66) {  // Group 3 prefix.
1118       operand_size_ = current;
1119     } else if ((current & 0xF0) == 0x40) {  // REX prefix.
1120       setRex(current);
1121       if (rex_w()) AppendToBuffer("REX.W ");
1122     } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix.
1123       group_1_prefix_ = current;
1124     } else {  // Not a prefix - an opcode.
1125       break;
1126     }
1127     data++;
1128   }
1129 
1130   const InstructionDesc& idesc = instruction_table.Get(current);
1131   byte_size_operand_ = idesc.byte_size_operation;
1132   switch (idesc.type) {
1133     case ZERO_OPERANDS_INSTR:
1134       AppendToBuffer(idesc.mnem);
1135       data++;
1136       break;
1137 
1138     case TWO_OPERANDS_INSTR:
1139       data++;
1140       data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1141       break;
1142 
1143     case JUMP_CONDITIONAL_SHORT_INSTR:
1144       data += JumpConditionalShort(data);
1145       break;
1146 
1147     case REGISTER_INSTR:
1148       AppendToBuffer("%s%c %s",
1149                      idesc.mnem,
1150                      operand_size_code(),
1151                      NameOfCPURegister(base_reg(current & 0x07)));
1152       data++;
1153       break;
1154     case PUSHPOP_INSTR:
1155       AppendToBuffer("%s %s",
1156                      idesc.mnem,
1157                      NameOfCPURegister(base_reg(current & 0x07)));
1158       data++;
1159       break;
1160     case MOVE_REG_INSTR: {
1161       byte* addr = NULL;
1162       switch (operand_size()) {
1163         case WORD_SIZE:
1164           addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1165           data += 3;
1166           break;
1167         case DOUBLEWORD_SIZE:
1168           addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1169           data += 5;
1170           break;
1171         case QUADWORD_SIZE:
1172           addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1173           data += 9;
1174           break;
1175         default:
1176           UNREACHABLE();
1177       }
1178       AppendToBuffer("mov%c %s,%s",
1179                      operand_size_code(),
1180                      NameOfCPURegister(base_reg(current & 0x07)),
1181                      NameOfAddress(addr));
1182       break;
1183     }
1184 
1185     case CALL_JUMP_INSTR: {
1186       byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1187       AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1188       data += 5;
1189       break;
1190     }
1191 
1192     case SHORT_IMMEDIATE_INSTR: {
1193       byte* addr =
1194           reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1195       AppendToBuffer("%s rax, %s", idesc.mnem, NameOfAddress(addr));
1196       data += 5;
1197       break;
1198     }
1199 
1200     case NO_INSTR:
1201       processed = false;
1202       break;
1203 
1204     default:
1205       UNIMPLEMENTED();  // This type is not implemented.
1206   }
1207 
1208   // The first byte didn't match any of the simple opcodes, so we
1209   // need to do special processing on it.
1210   if (!processed) {
1211     switch (*data) {
1212       case 0xC2:
1213         AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1214         data += 3;
1215         break;
1216 
1217       case 0x69:  // fall through
1218       case 0x6B: {
1219         int mod, regop, rm;
1220         get_modrm(*(data + 1), &mod, &regop, &rm);
1221         int32_t imm = *data == 0x6B ? *(data + 2)
1222             : *reinterpret_cast<int32_t*>(data + 2);
1223         AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
1224                        NameOfCPURegister(rm), imm);
1225         data += 2 + (*data == 0x6B ? 1 : 4);
1226         break;
1227       }
1228 
1229       case 0xF6: {
1230         int mod, regop, rm;
1231         get_modrm(*(data + 1), &mod, &regop, &rm);
1232         if (mod == 3 && regop == 0) {
1233           AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2));
1234         } else {
1235           UnimplementedInstruction();
1236         }
1237         data += 3;
1238         break;
1239       }
1240 
1241       case 0x81:  // fall through
1242       case 0x83:  // 0x81 with sign extension bit set
1243         data += PrintImmediateOp(data);
1244         break;
1245 
1246       case 0x0F:
1247         data += TwoByteOpcodeInstruction(data);
1248         break;
1249 
1250       case 0x8F: {
1251         data++;
1252         int mod, regop, rm;
1253         get_modrm(*data, &mod, &regop, &rm);
1254         if (regop == 0) {
1255           AppendToBuffer("pop ");
1256           data += PrintRightOperand(data);
1257         }
1258       }
1259         break;
1260 
1261       case 0xFF: {
1262         data++;
1263         int mod, regop, rm;
1264         get_modrm(*data, &mod, &regop, &rm);
1265         const char* mnem = NULL;
1266         switch (regop) {
1267           case 0:
1268             mnem = "inc";
1269             break;
1270           case 1:
1271             mnem = "dec";
1272             break;
1273           case 2:
1274             mnem = "call";
1275             break;
1276           case 4:
1277             mnem = "jmp";
1278             break;
1279           case 6:
1280             mnem = "push";
1281             break;
1282           default:
1283             mnem = "???";
1284         }
1285         AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1286                        mnem,
1287                        operand_size_code());
1288         data += PrintRightOperand(data);
1289       }
1290         break;
1291 
1292       case 0xC7:  // imm32, fall through
1293       case 0xC6:  // imm8
1294       {
1295         bool is_byte = *data == 0xC6;
1296         data++;
1297 
1298         AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1299         data += PrintRightOperand(data);
1300         int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
1301         AppendToBuffer(",0x%x", imm);
1302         data += is_byte ? 1 : 4;
1303       }
1304         break;
1305 
1306       case 0x80: {
1307         data++;
1308         AppendToBuffer("cmpb ");
1309         data += PrintRightOperand(data);
1310         int32_t imm = *data;
1311         AppendToBuffer(",0x%x", imm);
1312         data++;
1313       }
1314         break;
1315 
1316       case 0x88:  // 8bit, fall through
1317       case 0x89:  // 32bit
1318       {
1319         bool is_byte = *data == 0x88;
1320         int mod, regop, rm;
1321         data++;
1322         get_modrm(*data, &mod, &regop, &rm);
1323         AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1324         data += PrintRightOperand(data);
1325         AppendToBuffer(",%s", NameOfCPURegister(regop));
1326       }
1327         break;
1328 
1329       case 0x90:
1330       case 0x91:
1331       case 0x92:
1332       case 0x93:
1333       case 0x94:
1334       case 0x95:
1335       case 0x96:
1336       case 0x97: {
1337         int reg = (current & 0x7) | (rex_b() ? 8 : 0);
1338         if (reg == 0) {
1339           AppendToBuffer("nop");  // Common name for xchg rax,rax.
1340         } else {
1341           AppendToBuffer("xchg%c rax, %s",
1342                          operand_size_code(),
1343                          NameOfCPURegister(reg));
1344         }
1345       }
1346 
1347 
1348       case 0xFE: {
1349         data++;
1350         int mod, regop, rm;
1351         get_modrm(*data, &mod, &regop, &rm);
1352         if (mod == 3 && regop == 1) {
1353           AppendToBuffer("decb %s", NameOfCPURegister(rm));
1354         } else {
1355           UnimplementedInstruction();
1356         }
1357         data++;
1358       }
1359         break;
1360 
1361       case 0x68:
1362         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1363         data += 5;
1364         break;
1365 
1366       case 0x6A:
1367         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1368         data += 2;
1369         break;
1370 
1371       case 0xA1:  // Fall through.
1372       case 0xA3:
1373         switch (operand_size()) {
1374           case DOUBLEWORD_SIZE: {
1375             const char* memory_location = NameOfAddress(
1376                 reinterpret_cast<byte*>(
1377                     *reinterpret_cast<int32_t*>(data + 1)));
1378             if (*data == 0xA1) {  // Opcode 0xA1
1379               AppendToBuffer("movzxlq rax,(%s)", memory_location);
1380             } else {  // Opcode 0xA3
1381               AppendToBuffer("movzxlq (%s),rax", memory_location);
1382             }
1383             data += 5;
1384             break;
1385           }
1386           case QUADWORD_SIZE: {
1387             // New x64 instruction mov rax,(imm_64).
1388             const char* memory_location = NameOfAddress(
1389                 *reinterpret_cast<byte**>(data + 1));
1390             if (*data == 0xA1) {  // Opcode 0xA1
1391               AppendToBuffer("movq rax,(%s)", memory_location);
1392             } else {  // Opcode 0xA3
1393               AppendToBuffer("movq (%s),rax", memory_location);
1394             }
1395             data += 9;
1396             break;
1397           }
1398           default:
1399             UnimplementedInstruction();
1400             data += 2;
1401         }
1402         break;
1403 
1404       case 0xA8:
1405         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1406         data += 2;
1407         break;
1408 
1409       case 0xA9: {
1410         int64_t value = 0;
1411         switch (operand_size()) {
1412           case WORD_SIZE:
1413             value = *reinterpret_cast<uint16_t*>(data + 1);
1414             data += 3;
1415             break;
1416           case DOUBLEWORD_SIZE:
1417             value = *reinterpret_cast<uint32_t*>(data + 1);
1418             data += 5;
1419             break;
1420           case QUADWORD_SIZE:
1421             value = *reinterpret_cast<int32_t*>(data + 1);
1422             data += 5;
1423             break;
1424           default:
1425             UNREACHABLE();
1426         }
1427         AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"x",
1428                        operand_size_code(),
1429                        value);
1430         break;
1431       }
1432       case 0xD1:  // fall through
1433       case 0xD3:  // fall through
1434       case 0xC1:
1435         data += ShiftInstruction(data);
1436         break;
1437       case 0xD0:  // fall through
1438       case 0xD2:  // fall through
1439       case 0xC0:
1440         byte_size_operand_ = true;
1441         data += ShiftInstruction(data);
1442         break;
1443 
1444       case 0xD9:  // fall through
1445       case 0xDA:  // fall through
1446       case 0xDB:  // fall through
1447       case 0xDC:  // fall through
1448       case 0xDD:  // fall through
1449       case 0xDE:  // fall through
1450       case 0xDF:
1451         data += FPUInstruction(data);
1452         break;
1453 
1454       case 0xEB:
1455         data += JumpShort(data);
1456         break;
1457 
1458       case 0xF7:
1459         data += F7Instruction(data);
1460         break;
1461 
1462       default:
1463         UnimplementedInstruction();
1464         data += 1;
1465     }
1466   }  // !processed
1467 
1468   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1469     tmp_buffer_[tmp_buffer_pos_] = '\0';
1470   }
1471 
1472   int instr_len = data - instr;
1473   ASSERT(instr_len > 0);  // Ensure progress.
1474 
1475   int outp = 0;
1476   // Instruction bytes.
1477   for (byte* bp = instr; bp < data; bp++) {
1478     outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
1479   }
1480   for (int i = 6 - instr_len; i >= 0; i--) {
1481     outp += v8::internal::OS::SNPrintF(out_buffer + outp, "  ");
1482   }
1483 
1484   outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
1485                                      tmp_buffer_.start());
1486   return instr_len;
1487 }
1488 
1489 //------------------------------------------------------------------------------
1490 
1491 
1492 static const char* cpu_regs[16] = {
1493   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1494   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1495 };
1496 
1497 
1498 static const char* byte_cpu_regs[16] = {
1499   "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1500   "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1501 };
1502 
1503 
1504 static const char* xmm_regs[16] = {
1505   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1506   "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1507 };
1508 
1509 
NameOfAddress(byte * addr) const1510 const char* NameConverter::NameOfAddress(byte* addr) const {
1511   static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
1512   v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
1513   return tmp_buffer.start();
1514 }
1515 
1516 
NameOfConstant(byte * addr) const1517 const char* NameConverter::NameOfConstant(byte* addr) const {
1518   return NameOfAddress(addr);
1519 }
1520 
1521 
NameOfCPURegister(int reg) const1522 const char* NameConverter::NameOfCPURegister(int reg) const {
1523   if (0 <= reg && reg < 16)
1524     return cpu_regs[reg];
1525   return "noreg";
1526 }
1527 
1528 
NameOfByteCPURegister(int reg) const1529 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1530   if (0 <= reg && reg < 16)
1531     return byte_cpu_regs[reg];
1532   return "noreg";
1533 }
1534 
1535 
NameOfXMMRegister(int reg) const1536 const char* NameConverter::NameOfXMMRegister(int reg) const {
1537   if (0 <= reg && reg < 16)
1538     return xmm_regs[reg];
1539   return "noxmmreg";
1540 }
1541 
1542 
NameInCode(byte * addr) const1543 const char* NameConverter::NameInCode(byte* addr) const {
1544   // X64 does not embed debug strings at the moment.
1545   UNREACHABLE();
1546   return "";
1547 }
1548 
1549 //------------------------------------------------------------------------------
1550 
Disassembler(const NameConverter & converter)1551 Disassembler::Disassembler(const NameConverter& converter)
1552     : converter_(converter) { }
1553 
~Disassembler()1554 Disassembler::~Disassembler() { }
1555 
1556 
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)1557 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1558                                     byte* instruction) {
1559   DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1560   return d.InstructionDecode(buffer, instruction);
1561 }
1562 
1563 
1564 // The X64 assembler does not use constant pools.
ConstantPoolSizeAt(byte * instruction)1565 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1566   return -1;
1567 }
1568 
1569 
Disassemble(FILE * f,byte * begin,byte * end)1570 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1571   NameConverter converter;
1572   Disassembler d(converter);
1573   for (byte* pc = begin; pc < end;) {
1574     v8::internal::EmbeddedVector<char, 128> buffer;
1575     buffer[0] = '\0';
1576     byte* prev_pc = pc;
1577     pc += d.InstructionDecode(buffer, pc);
1578     fprintf(f, "%p", prev_pc);
1579     fprintf(f, "    ");
1580 
1581     for (byte* bp = prev_pc; bp < pc; bp++) {
1582       fprintf(f, "%02x", *bp);
1583     }
1584     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1585       fprintf(f, "  ");
1586     }
1587     fprintf(f, "  %s\n", buffer.start());
1588   }
1589 }
1590 
1591 }  // namespace disasm
1592