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