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