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