1 // 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 #if V8_TARGET_ARCH_IA32
10
11 #include "src/base/compiler-specific.h"
12 #include "src/codegen/ia32/sse-instr.h"
13 #include "src/diagnostics/disasm.h"
14 #include "src/utils/utils.h"
15
16 namespace disasm {
17
18 enum OperandOrder { UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER };
19
20 //------------------------------------------------------------------
21 // Tables
22 //------------------------------------------------------------------
23 struct ByteMnemonic {
24 int b; // -1 terminates, otherwise must be in range (0..255)
25 const char* mnem;
26 OperandOrder op_order_;
27 };
28
29 static const ByteMnemonic two_operands_instr[] = {
30 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
31 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER},
32 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER},
33 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER},
34 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER},
35 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
36 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
37 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
38 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
39 {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER},
40 {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER},
41 {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER},
42 {-1, "", UNSET_OP_ORDER}};
43
44 static const ByteMnemonic zero_operands_instr[] = {
45 {0xC3, "ret", UNSET_OP_ORDER}, {0xC9, "leave", UNSET_OP_ORDER},
46 {0x90, "nop", UNSET_OP_ORDER}, {0xF4, "hlt", UNSET_OP_ORDER},
47 {0xCC, "int3", UNSET_OP_ORDER}, {0x60, "pushad", UNSET_OP_ORDER},
48 {0x61, "popad", UNSET_OP_ORDER}, {0x9C, "pushfd", UNSET_OP_ORDER},
49 {0x9D, "popfd", UNSET_OP_ORDER}, {0x9E, "sahf", UNSET_OP_ORDER},
50 {0x99, "cdq", UNSET_OP_ORDER}, {0x9B, "fwait", UNSET_OP_ORDER},
51 {0xFC, "cld", UNSET_OP_ORDER}, {0xAB, "stos", UNSET_OP_ORDER},
52 {-1, "", UNSET_OP_ORDER}};
53
54 static const ByteMnemonic call_jump_instr[] = {{0xE8, "call", UNSET_OP_ORDER},
55 {0xE9, "jmp", UNSET_OP_ORDER},
56 {-1, "", UNSET_OP_ORDER}};
57
58 static const ByteMnemonic short_immediate_instr[] = {
59 {0x05, "add", UNSET_OP_ORDER}, {0x0D, "or", UNSET_OP_ORDER},
60 {0x15, "adc", UNSET_OP_ORDER}, {0x25, "and", UNSET_OP_ORDER},
61 {0x2D, "sub", UNSET_OP_ORDER}, {0x35, "xor", UNSET_OP_ORDER},
62 {0x3D, "cmp", UNSET_OP_ORDER}, {-1, "", UNSET_OP_ORDER}};
63
64 // Generally we don't want to generate these because they are subject to partial
65 // register stalls. They are included for completeness and because the cmp
66 // variant is used by the RecordWrite stub. Because it does not update the
67 // register it is not subject to partial register stalls.
68 static ByteMnemonic byte_immediate_instr[] = {{0x0C, "or", UNSET_OP_ORDER},
69 {0x24, "and", UNSET_OP_ORDER},
70 {0x34, "xor", UNSET_OP_ORDER},
71 {0x3C, "cmp", UNSET_OP_ORDER},
72 {-1, "", UNSET_OP_ORDER}};
73
74 static const char* const jump_conditional_mnem[] = {
75 /*0*/ "jo", "jno", "jc", "jnc",
76 /*4*/ "jz", "jnz", "jna", "ja",
77 /*8*/ "js", "jns", "jpe", "jpo",
78 /*12*/ "jl", "jnl", "jng", "jg"};
79
80 static const char* const set_conditional_mnem[] = {
81 /*0*/ "seto", "setno", "setc", "setnc",
82 /*4*/ "setz", "setnz", "setna", "seta",
83 /*8*/ "sets", "setns", "setpe", "setpo",
84 /*12*/ "setl", "setnl", "setng", "setg"};
85
86 static const char* const conditional_move_mnem[] = {
87 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
88 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
89 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
90 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"};
91
92 enum InstructionType {
93 NO_INSTR,
94 ZERO_OPERANDS_INSTR,
95 TWO_OPERANDS_INSTR,
96 JUMP_CONDITIONAL_SHORT_INSTR,
97 REGISTER_INSTR,
98 MOVE_REG_INSTR,
99 CALL_JUMP_INSTR,
100 SHORT_IMMEDIATE_INSTR,
101 BYTE_IMMEDIATE_INSTR
102 };
103
104 struct InstructionDesc {
105 const char* mnem;
106 InstructionType type;
107 OperandOrder op_order_;
108 };
109
110 class InstructionTable {
111 public:
112 InstructionTable();
Get(byte x) const113 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
get_instance()114 static InstructionTable* get_instance() {
115 static InstructionTable table;
116 return &table;
117 }
118
119 private:
120 InstructionDesc instructions_[256];
121 void Clear();
122 void Init();
123 void CopyTable(const ByteMnemonic bm[], InstructionType type);
124 void SetTableRange(InstructionType type, byte start, byte end,
125 const char* mnem);
126 void AddJumpConditionalShort();
127 };
128
InstructionTable()129 InstructionTable::InstructionTable() {
130 Clear();
131 Init();
132 }
133
Clear()134 void InstructionTable::Clear() {
135 for (int i = 0; i < 256; i++) {
136 instructions_[i].mnem = "";
137 instructions_[i].type = NO_INSTR;
138 instructions_[i].op_order_ = UNSET_OP_ORDER;
139 }
140 }
141
Init()142 void InstructionTable::Init() {
143 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
144 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
145 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
146 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
147 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
148 AddJumpConditionalShort();
149 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
150 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
151 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
152 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
153 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
154 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
155 }
156
CopyTable(const ByteMnemonic bm[],InstructionType type)157 void InstructionTable::CopyTable(const ByteMnemonic bm[],
158 InstructionType type) {
159 for (int i = 0; bm[i].b >= 0; i++) {
160 InstructionDesc* id = &instructions_[bm[i].b];
161 id->mnem = bm[i].mnem;
162 id->op_order_ = bm[i].op_order_;
163 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
164 id->type = type;
165 }
166 }
167
SetTableRange(InstructionType type,byte start,byte end,const char * mnem)168 void InstructionTable::SetTableRange(InstructionType type, byte start, byte end,
169 const char* mnem) {
170 for (byte b = start; b <= end; b++) {
171 InstructionDesc* id = &instructions_[b];
172 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
173 id->mnem = mnem;
174 id->type = type;
175 }
176 }
177
AddJumpConditionalShort()178 void InstructionTable::AddJumpConditionalShort() {
179 for (byte b = 0x70; b <= 0x7F; b++) {
180 InstructionDesc* id = &instructions_[b];
181 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
182 id->mnem = jump_conditional_mnem[b & 0x0F];
183 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
184 }
185 }
186
187 namespace {
Imm8(const uint8_t * data)188 int8_t Imm8(const uint8_t* data) {
189 return *reinterpret_cast<const int8_t*>(data);
190 }
Imm8_U(const uint8_t * data)191 uint8_t Imm8_U(const uint8_t* data) {
192 return *reinterpret_cast<const uint8_t*>(data);
193 }
Imm16(const uint8_t * data)194 int16_t Imm16(const uint8_t* data) {
195 return *reinterpret_cast<const int16_t*>(data);
196 }
Imm16_U(const uint8_t * data)197 uint16_t Imm16_U(const uint8_t* data) {
198 return *reinterpret_cast<const uint16_t*>(data);
199 }
Imm32(const uint8_t * data)200 int32_t Imm32(const uint8_t* data) {
201 return *reinterpret_cast<const int32_t*>(data);
202 }
203 } // namespace
204
205 // The IA32 disassembler implementation.
206 class DisassemblerIA32 {
207 public:
DisassemblerIA32(const NameConverter & converter,Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action)208 DisassemblerIA32(
209 const NameConverter& converter,
210 Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action)
211 : converter_(converter),
212 vex_byte0_(0),
213 vex_byte1_(0),
214 vex_byte2_(0),
215 instruction_table_(InstructionTable::get_instance()),
216 tmp_buffer_pos_(0),
217 unimplemented_opcode_action_(unimplemented_opcode_action) {
218 tmp_buffer_[0] = '\0';
219 }
220
~DisassemblerIA32()221 virtual ~DisassemblerIA32() {}
222
223 // Writes one disassembled instruction into 'buffer' (0-terminated).
224 // Returns the length of the disassembled machine instruction in bytes.
225 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
226
227 private:
228 const NameConverter& converter_;
229 byte vex_byte0_; // 0xC4 or 0xC5
230 byte vex_byte1_;
231 byte vex_byte2_; // only for 3 bytes vex prefix
232 InstructionTable* instruction_table_;
233 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
234 unsigned int tmp_buffer_pos_;
235 Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action_;
236
237 enum {
238 eax = 0,
239 ecx = 1,
240 edx = 2,
241 ebx = 3,
242 esp = 4,
243 ebp = 5,
244 esi = 6,
245 edi = 7
246 };
247
248 enum ShiftOpcodeExtension {
249 kROL = 0,
250 kROR = 1,
251 kRCL = 2,
252 kRCR = 3,
253 kSHL = 4,
254 KSHR = 5,
255 kSAR = 7
256 };
257
vex_128()258 bool vex_128() {
259 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
260 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
261 return (checked & 4) == 0;
262 }
263
vex_none()264 bool vex_none() {
265 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
266 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
267 return (checked & 3) == 0;
268 }
269
vex_66()270 bool vex_66() {
271 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
272 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
273 return (checked & 3) == 1;
274 }
275
vex_f3()276 bool vex_f3() {
277 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
278 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
279 return (checked & 3) == 2;
280 }
281
vex_f2()282 bool vex_f2() {
283 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
284 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
285 return (checked & 3) == 3;
286 }
287
vex_w()288 bool vex_w() {
289 if (vex_byte0_ == 0xC5) return false;
290 return (vex_byte2_ & 0x80) != 0;
291 }
292
vex_0f()293 bool vex_0f() {
294 if (vex_byte0_ == 0xC5) return true;
295 return (vex_byte1_ & 3) == 1;
296 }
297
vex_0f38()298 bool vex_0f38() {
299 if (vex_byte0_ == 0xC5) return false;
300 return (vex_byte1_ & 3) == 2;
301 }
302
vex_0f3a()303 bool vex_0f3a() {
304 if (vex_byte0_ == 0xC5) return false;
305 return (vex_byte1_ & 3) == 3;
306 }
307
vex_vreg()308 int vex_vreg() {
309 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
310 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
311 return ~(checked >> 3) & 0xF;
312 }
313
float_size_code()314 char float_size_code() { return "sd"[vex_w()]; }
315
NameOfCPURegister(int reg) const316 const char* NameOfCPURegister(int reg) const {
317 return converter_.NameOfCPURegister(reg);
318 }
319
NameOfByteCPURegister(int reg) const320 const char* NameOfByteCPURegister(int reg) const {
321 return converter_.NameOfByteCPURegister(reg);
322 }
323
NameOfXMMRegister(int reg) const324 const char* NameOfXMMRegister(int reg) const {
325 return converter_.NameOfXMMRegister(reg);
326 }
327
NameOfAddress(byte * addr) const328 const char* NameOfAddress(byte* addr) const {
329 return converter_.NameOfAddress(addr);
330 }
331
332 // Disassembler helper functions.
get_modrm(byte data,int * mod,int * regop,int * rm)333 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
334 *mod = (data >> 6) & 3;
335 *regop = (data & 0x38) >> 3;
336 *rm = data & 7;
337 }
338
get_sib(byte data,int * scale,int * index,int * base)339 static void get_sib(byte data, int* scale, int* index, int* base) {
340 *scale = (data >> 6) & 3;
341 *index = (data >> 3) & 7;
342 *base = data & 7;
343 }
344
345 using RegisterNameMapping = const char* (DisassemblerIA32::*)(int reg) const;
346
347 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
348 int PrintRightOperand(byte* modrmp);
349 int PrintRightByteOperand(byte* modrmp);
350 int PrintRightXMMOperand(byte* modrmp);
351 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
352 int PrintImmediateOp(byte* data);
353 int F7Instruction(byte* data);
354 int D1D3C1Instruction(byte* data);
355 int JumpShort(byte* data);
356 int JumpConditional(byte* data, const char* comment);
357 int JumpConditionalShort(byte* data, const char* comment);
358 int SetCC(byte* data);
359 int CMov(byte* data);
360 int FPUInstruction(byte* data);
361 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
362 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
363 int AVXInstruction(byte* data);
364 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
365
UnimplementedInstruction()366 void UnimplementedInstruction() {
367 if (unimplemented_opcode_action_ ==
368 Disassembler::kAbortOnUnimplementedOpcode) {
369 FATAL("Unimplemented instruction in disassembler");
370 } else {
371 AppendToBuffer("'Unimplemented Instruction'");
372 }
373 }
374 };
375
AppendToBuffer(const char * format,...)376 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
377 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
378 va_list args;
379 va_start(args, format);
380 int result = v8::internal::VSNPrintF(buf, format, args);
381 va_end(args);
382 tmp_buffer_pos_ += result;
383 }
384
PrintRightOperandHelper(byte * modrmp,RegisterNameMapping direct_register_name)385 int DisassemblerIA32::PrintRightOperandHelper(
386 byte* modrmp, RegisterNameMapping direct_register_name) {
387 int mod, regop, rm;
388 get_modrm(*modrmp, &mod, ®op, &rm);
389 RegisterNameMapping register_name =
390 (mod == 3) ? direct_register_name : &DisassemblerIA32::NameOfCPURegister;
391 switch (mod) {
392 case 0:
393 if (rm == ebp) {
394 AppendToBuffer("[0x%x]", Imm32(modrmp + 1));
395 return 5;
396 } else if (rm == esp) {
397 byte sib = *(modrmp + 1);
398 int scale, index, base;
399 get_sib(sib, &scale, &index, &base);
400 if (index == esp && base == esp && scale == 0 /*times_1*/) {
401 AppendToBuffer("[%s]", (this->*register_name)(rm));
402 return 2;
403 } else if (base == ebp) {
404 int32_t disp = Imm32(modrmp + 2);
405 AppendToBuffer("[%s*%d%s0x%x]", (this->*register_name)(index),
406 1 << scale, disp < 0 ? "-" : "+",
407 disp < 0 ? -disp : disp);
408 return 6;
409 } else if (index != esp && base != ebp) {
410 // [base+index*scale]
411 AppendToBuffer("[%s+%s*%d]", (this->*register_name)(base),
412 (this->*register_name)(index), 1 << scale);
413 return 2;
414 } else {
415 UnimplementedInstruction();
416 return 1;
417 }
418 } else {
419 AppendToBuffer("[%s]", (this->*register_name)(rm));
420 return 1;
421 }
422 break;
423 case 1: // fall through
424 case 2:
425 if (rm == esp) {
426 byte sib = *(modrmp + 1);
427 int scale, index, base;
428 get_sib(sib, &scale, &index, &base);
429 int disp = mod == 2 ? Imm32(modrmp + 2) : Imm8(modrmp + 2);
430 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
431 AppendToBuffer("[%s%s0x%x]", (this->*register_name)(rm),
432 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
433 } else {
434 AppendToBuffer("[%s+%s*%d%s0x%x]", (this->*register_name)(base),
435 (this->*register_name)(index), 1 << scale,
436 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
437 }
438 return mod == 2 ? 6 : 3;
439 } else {
440 // No sib.
441 int disp = mod == 2 ? Imm32(modrmp + 1) : Imm8(modrmp + 1);
442 AppendToBuffer("[%s%s0x%x]", (this->*register_name)(rm),
443 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
444 return mod == 2 ? 5 : 2;
445 }
446 break;
447 case 3:
448 AppendToBuffer("%s", (this->*register_name)(rm));
449 return 1;
450 default:
451 UnimplementedInstruction();
452 return 1;
453 }
454 UNREACHABLE();
455 }
456
PrintRightOperand(byte * modrmp)457 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
458 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
459 }
460
PrintRightByteOperand(byte * modrmp)461 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
462 return PrintRightOperandHelper(modrmp,
463 &DisassemblerIA32::NameOfByteCPURegister);
464 }
465
PrintRightXMMOperand(byte * modrmp)466 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
467 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfXMMRegister);
468 }
469
470 // Returns number of bytes used including the current *data.
471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
PrintOperands(const char * mnem,OperandOrder op_order,byte * data)472 int DisassemblerIA32::PrintOperands(const char* mnem, OperandOrder op_order,
473 byte* data) {
474 byte modrm = *data;
475 int mod, regop, rm;
476 get_modrm(modrm, &mod, ®op, &rm);
477 int advance = 0;
478 switch (op_order) {
479 case REG_OPER_OP_ORDER: {
480 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
481 advance = PrintRightOperand(data);
482 break;
483 }
484 case OPER_REG_OP_ORDER: {
485 AppendToBuffer("%s ", mnem);
486 advance = PrintRightOperand(data);
487 AppendToBuffer(",%s", NameOfCPURegister(regop));
488 break;
489 }
490 default:
491 UNREACHABLE();
492 }
493 return advance;
494 }
495
496 // Returns number of bytes used by machine instruction, including *data byte.
497 // Writes immediate instructions to 'tmp_buffer_'.
PrintImmediateOp(byte * data)498 int DisassemblerIA32::PrintImmediateOp(byte* data) {
499 bool sign_extension_bit = (*data & 0x02) != 0;
500 byte modrm = *(data + 1);
501 int mod, regop, rm;
502 get_modrm(modrm, &mod, ®op, &rm);
503 const char* mnem = "Imm???";
504 switch (regop) {
505 case 0:
506 mnem = "add";
507 break;
508 case 1:
509 mnem = "or";
510 break;
511 case 2:
512 mnem = "adc";
513 break;
514 case 4:
515 mnem = "and";
516 break;
517 case 5:
518 mnem = "sub";
519 break;
520 case 6:
521 mnem = "xor";
522 break;
523 case 7:
524 mnem = "cmp";
525 break;
526 default:
527 UnimplementedInstruction();
528 }
529 AppendToBuffer("%s ", mnem);
530 int count = PrintRightOperand(data + 1);
531 if (sign_extension_bit) {
532 AppendToBuffer(",0x%x", *(data + 1 + count));
533 return 1 + count + 1 /*int8*/;
534 } else {
535 AppendToBuffer(",0x%x", Imm32(data + 1 + count));
536 return 1 + count + 4 /*int32_t*/;
537 }
538 }
539
540 // Returns number of bytes used, including *data.
F7Instruction(byte * data)541 int DisassemblerIA32::F7Instruction(byte* data) {
542 DCHECK_EQ(0xF7, *data);
543 byte modrm = *++data;
544 int mod, regop, rm;
545 get_modrm(modrm, &mod, ®op, &rm);
546 const char* mnem = nullptr;
547 switch (regop) {
548 case 0:
549 mnem = "test";
550 break;
551 case 2:
552 mnem = "not";
553 break;
554 case 3:
555 mnem = "neg";
556 break;
557 case 4:
558 mnem = "mul";
559 break;
560 case 5:
561 mnem = "imul";
562 break;
563 case 6:
564 mnem = "div";
565 break;
566 case 7:
567 mnem = "idiv";
568 break;
569 default:
570 UnimplementedInstruction();
571 }
572 AppendToBuffer("%s ", mnem);
573 int count = PrintRightOperand(data);
574 if (regop == 0) {
575 AppendToBuffer(",0x%x", Imm32(data + count));
576 count += 4;
577 }
578 return 1 + count;
579 }
580
D1D3C1Instruction(byte * data)581 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
582 byte op = *data;
583 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
584 byte modrm = *++data;
585 int mod, regop, rm;
586 get_modrm(modrm, &mod, ®op, &rm);
587 int imm8 = -1;
588 const char* mnem = nullptr;
589 switch (regop) {
590 case kROL:
591 mnem = "rol";
592 break;
593 case kROR:
594 mnem = "ror";
595 break;
596 case kRCL:
597 mnem = "rcl";
598 break;
599 case kRCR:
600 mnem = "rcr";
601 break;
602 case kSHL:
603 mnem = "shl";
604 break;
605 case KSHR:
606 mnem = "shr";
607 break;
608 case kSAR:
609 mnem = "sar";
610 break;
611 default:
612 UnimplementedInstruction();
613 }
614 AppendToBuffer("%s ", mnem);
615 int count = PrintRightOperand(data);
616 if (op == 0xD1) {
617 imm8 = 1;
618 } else if (op == 0xC1) {
619 imm8 = *(data + 1);
620 count++;
621 } else if (op == 0xD3) {
622 // Shift/rotate by cl.
623 }
624 if (imm8 >= 0) {
625 AppendToBuffer(",%d", imm8);
626 } else {
627 AppendToBuffer(",cl");
628 }
629 return 1 + count;
630 }
631
632 // Returns number of bytes used, including *data.
JumpShort(byte * data)633 int DisassemblerIA32::JumpShort(byte* data) {
634 DCHECK_EQ(0xEB, *data);
635 byte b = *(data + 1);
636 byte* dest = data + static_cast<int8_t>(b) + 2;
637 AppendToBuffer("jmp %s", NameOfAddress(dest));
638 return 2;
639 }
640
641 // Returns number of bytes used, including *data.
JumpConditional(byte * data,const char * comment)642 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
643 DCHECK_EQ(0x0F, *data);
644 byte cond = *(data + 1) & 0x0F;
645 byte* dest = data + Imm32(data + 2) + 6;
646 const char* mnem = jump_conditional_mnem[cond];
647 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
648 if (comment != nullptr) {
649 AppendToBuffer(", %s", comment);
650 }
651 return 6; // includes 0x0F
652 }
653
654 // Returns number of bytes used, including *data.
JumpConditionalShort(byte * data,const char * comment)655 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
656 byte cond = *data & 0x0F;
657 byte b = *(data + 1);
658 byte* dest = data + static_cast<int8_t>(b) + 2;
659 const char* mnem = jump_conditional_mnem[cond];
660 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
661 if (comment != nullptr) {
662 AppendToBuffer(", %s", comment);
663 }
664 return 2;
665 }
666
667 // Returns number of bytes used, including *data.
SetCC(byte * data)668 int DisassemblerIA32::SetCC(byte* data) {
669 DCHECK_EQ(0x0F, *data);
670 byte cond = *(data + 1) & 0x0F;
671 const char* mnem = set_conditional_mnem[cond];
672 AppendToBuffer("%s ", mnem);
673 PrintRightByteOperand(data + 2);
674 return 3; // Includes 0x0F.
675 }
676
677 // Returns number of bytes used, including *data.
CMov(byte * data)678 int DisassemblerIA32::CMov(byte* data) {
679 DCHECK_EQ(0x0F, *data);
680 byte cond = *(data + 1) & 0x0F;
681 const char* mnem = conditional_move_mnem[cond];
682 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
683 return 2 + op_size; // includes 0x0F
684 }
685
686 const char* sf_str[4] = {"", "rl", "ra", "ll"};
687
AVXInstruction(byte * data)688 int DisassemblerIA32::AVXInstruction(byte* data) {
689 byte opcode = *data;
690 byte* current = data + 1;
691 if (vex_66() && vex_0f38()) {
692 int mod, regop, rm, vvvv = vex_vreg();
693 get_modrm(*current, &mod, ®op, &rm);
694 switch (opcode) {
695 case 0x18:
696 AppendToBuffer("vbroadcastss %s,", NameOfXMMRegister(regop));
697 current += PrintRightXMMOperand(current);
698 break;
699 case 0x99:
700 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
701 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
702 current += PrintRightXMMOperand(current);
703 break;
704 case 0xA9:
705 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
706 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
707 current += PrintRightXMMOperand(current);
708 break;
709 case 0xB9:
710 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
711 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
712 current += PrintRightXMMOperand(current);
713 break;
714 case 0x9B:
715 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
716 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
717 current += PrintRightXMMOperand(current);
718 break;
719 case 0xAB:
720 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
721 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
722 current += PrintRightXMMOperand(current);
723 break;
724 case 0xBB:
725 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
726 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
727 current += PrintRightXMMOperand(current);
728 break;
729 case 0x9D:
730 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
731 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
732 current += PrintRightXMMOperand(current);
733 break;
734 case 0xAD:
735 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
736 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
737 current += PrintRightXMMOperand(current);
738 break;
739 case 0xBD:
740 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
741 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
742 current += PrintRightXMMOperand(current);
743 break;
744 case 0x9F:
745 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
746 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
747 current += PrintRightXMMOperand(current);
748 break;
749 case 0xAF:
750 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
751 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
752 current += PrintRightXMMOperand(current);
753 break;
754 case 0xBF:
755 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
756 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
757 current += PrintRightXMMOperand(current);
758 break;
759 case 0xF7:
760 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
761 current += PrintRightOperand(current);
762 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
763 break;
764 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
765 opcode) \
766 case 0x##opcode: { \
767 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
768 NameOfXMMRegister(vvvv)); \
769 current += PrintRightXMMOperand(current); \
770 break; \
771 }
772
773 SSSE3_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
774 SSE4_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
775 #undef DECLARE_SSE_AVX_DIS_CASE
776 #define DECLARE_SSE_AVX_RM_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
777 opcode) \
778 case 0x##opcode: { \
779 AppendToBuffer("v" #instruction " %s,", NameOfXMMRegister(regop)); \
780 current += PrintRightXMMOperand(current); \
781 break; \
782 }
783
784 SSSE3_UNOP_INSTRUCTION_LIST(DECLARE_SSE_AVX_RM_DIS_CASE)
785 SSE4_RM_INSTRUCTION_LIST(DECLARE_SSE_AVX_RM_DIS_CASE)
786 #undef DECLARE_SSE_AVX_RM_DIS_CASE
787 default:
788 UnimplementedInstruction();
789 }
790 } else if (vex_66() && vex_0f3a()) {
791 int mod, regop, rm, vvvv = vex_vreg();
792 get_modrm(*current, &mod, ®op, &rm);
793 switch (opcode) {
794 case 0x0E:
795 AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop),
796 NameOfXMMRegister(vvvv));
797 current += PrintRightXMMOperand(current);
798 AppendToBuffer(",%d", Imm8_U(current));
799 current++;
800 break;
801 case 0x0F:
802 AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop),
803 NameOfXMMRegister(vvvv));
804 current += PrintRightXMMOperand(current);
805 AppendToBuffer(",%d", Imm8_U(current));
806 current++;
807 break;
808 case 0x14:
809 AppendToBuffer("vpextrb ");
810 current += PrintRightOperand(current);
811 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
812 current++;
813 break;
814 case 0x15:
815 AppendToBuffer("vpextrw ");
816 current += PrintRightOperand(current);
817 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
818 current++;
819 break;
820 case 0x16:
821 AppendToBuffer("vpextrd ");
822 current += PrintRightOperand(current);
823 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
824 current++;
825 break;
826 case 0x20:
827 AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
828 NameOfXMMRegister(vvvv));
829 current += PrintRightOperand(current);
830 AppendToBuffer(",%d", Imm8(current));
831 current++;
832 break;
833 case 0x21:
834 AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop),
835 NameOfXMMRegister(vvvv));
836 current += PrintRightXMMOperand(current);
837 AppendToBuffer(",%d", Imm8(current));
838 current++;
839 break;
840 case 0x22:
841 AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop),
842 NameOfXMMRegister(vvvv));
843 current += PrintRightOperand(current);
844 AppendToBuffer(",%d", Imm8(current));
845 current++;
846 break;
847 default:
848 UnimplementedInstruction();
849 }
850 } else if (vex_f2() && vex_0f()) {
851 int mod, regop, rm, vvvv = vex_vreg();
852 get_modrm(*current, &mod, ®op, &rm);
853 switch (opcode) {
854 case 0x12:
855 AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop));
856 current += PrintRightXMMOperand(current);
857 break;
858 case 0x51:
859 AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
860 NameOfXMMRegister(vvvv));
861 current += PrintRightXMMOperand(current);
862 break;
863 case 0x58:
864 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
865 NameOfXMMRegister(vvvv));
866 current += PrintRightXMMOperand(current);
867 break;
868 case 0x59:
869 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
870 NameOfXMMRegister(vvvv));
871 current += PrintRightXMMOperand(current);
872 break;
873 case 0x5C:
874 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
875 NameOfXMMRegister(vvvv));
876 current += PrintRightXMMOperand(current);
877 break;
878 case 0x5D:
879 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
880 NameOfXMMRegister(vvvv));
881 current += PrintRightXMMOperand(current);
882 break;
883 case 0x5E:
884 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
885 NameOfXMMRegister(vvvv));
886 current += PrintRightXMMOperand(current);
887 break;
888 case 0x5F:
889 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
890 NameOfXMMRegister(vvvv));
891 current += PrintRightXMMOperand(current);
892 break;
893 case 0x70:
894 AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop));
895 current += PrintRightXMMOperand(current);
896 AppendToBuffer(",%d", Imm8(current));
897 current++;
898 break;
899 case 0x7C:
900 AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop),
901 NameOfXMMRegister(vvvv));
902 current += PrintRightXMMOperand(current);
903 break;
904 default:
905 UnimplementedInstruction();
906 }
907 } else if (vex_f3() && vex_0f()) {
908 int mod, regop, rm, vvvv = vex_vreg();
909 get_modrm(*current, &mod, ®op, &rm);
910 switch (opcode) {
911 case 0x51:
912 AppendToBuffer("vsqrtss %s,%s,", NameOfXMMRegister(regop),
913 NameOfXMMRegister(vvvv));
914 current += PrintRightXMMOperand(current);
915 break;
916 case 0x58:
917 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
918 NameOfXMMRegister(vvvv));
919 current += PrintRightXMMOperand(current);
920 break;
921 case 0x59:
922 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
923 NameOfXMMRegister(vvvv));
924 current += PrintRightXMMOperand(current);
925 break;
926 case 0x5B:
927 AppendToBuffer("vcvttps2dq %s,", NameOfXMMRegister(regop));
928 current += PrintRightXMMOperand(current);
929 break;
930 case 0x5C:
931 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
932 NameOfXMMRegister(vvvv));
933 current += PrintRightXMMOperand(current);
934 break;
935 case 0x5D:
936 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
937 NameOfXMMRegister(vvvv));
938 current += PrintRightXMMOperand(current);
939 break;
940 case 0x5E:
941 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
942 NameOfXMMRegister(vvvv));
943 current += PrintRightXMMOperand(current);
944 break;
945 case 0x5F:
946 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
947 NameOfXMMRegister(vvvv));
948 current += PrintRightXMMOperand(current);
949 break;
950 case 0x6f:
951 AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop));
952 current += PrintRightOperand(current);
953 break;
954 case 0x70:
955 AppendToBuffer("vpshufhw %s,", NameOfXMMRegister(regop));
956 current += PrintRightXMMOperand(current);
957 AppendToBuffer(",%d", Imm8(current));
958 current++;
959 break;
960 case 0x7f:
961 AppendToBuffer("vmovdqu ");
962 current += PrintRightOperand(current);
963 AppendToBuffer(",%s", NameOfXMMRegister(regop));
964 break;
965 default:
966 UnimplementedInstruction();
967 }
968 } else if (vex_none() && vex_0f38()) {
969 int mod, regop, rm, vvvv = vex_vreg();
970 get_modrm(*current, &mod, ®op, &rm);
971 const char* mnem = "?";
972 switch (opcode) {
973 case 0xF2:
974 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
975 NameOfCPURegister(vvvv));
976 current += PrintRightOperand(current);
977 break;
978 case 0xF5:
979 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
980 current += PrintRightOperand(current);
981 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
982 break;
983 case 0xF7:
984 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
985 current += PrintRightOperand(current);
986 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
987 break;
988 case 0xF3:
989 switch (regop) {
990 case 1:
991 mnem = "blsr";
992 break;
993 case 2:
994 mnem = "blsmsk";
995 break;
996 case 3:
997 mnem = "blsi";
998 break;
999 default:
1000 UnimplementedInstruction();
1001 }
1002 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
1003 current += PrintRightOperand(current);
1004 mnem = "?";
1005 break;
1006 default:
1007 UnimplementedInstruction();
1008 }
1009 } else if (vex_f2() && vex_0f38()) {
1010 int mod, regop, rm, vvvv = vex_vreg();
1011 get_modrm(*current, &mod, ®op, &rm);
1012 switch (opcode) {
1013 case 0xF5:
1014 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
1015 NameOfCPURegister(vvvv));
1016 current += PrintRightOperand(current);
1017 break;
1018 case 0xF6:
1019 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
1020 NameOfCPURegister(vvvv));
1021 current += PrintRightOperand(current);
1022 break;
1023 case 0xF7:
1024 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
1025 current += PrintRightOperand(current);
1026 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1027 break;
1028 default:
1029 UnimplementedInstruction();
1030 }
1031 } else if (vex_f3() && vex_0f38()) {
1032 int mod, regop, rm, vvvv = vex_vreg();
1033 get_modrm(*current, &mod, ®op, &rm);
1034 switch (opcode) {
1035 case 0xF5:
1036 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
1037 NameOfCPURegister(vvvv));
1038 current += PrintRightOperand(current);
1039 break;
1040 case 0xF7:
1041 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
1042 current += PrintRightOperand(current);
1043 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1044 break;
1045 default:
1046 UnimplementedInstruction();
1047 }
1048 } else if (vex_f2() && vex_0f3a()) {
1049 int mod, regop, rm;
1050 get_modrm(*current, &mod, ®op, &rm);
1051 switch (opcode) {
1052 case 0xF0:
1053 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
1054 current += PrintRightOperand(current);
1055 AppendToBuffer(",%d", *current & 0x1F);
1056 current += 1;
1057 break;
1058 default:
1059 UnimplementedInstruction();
1060 }
1061 } else if (vex_none() && vex_0f()) {
1062 int mod, regop, rm, vvvv = vex_vreg();
1063 get_modrm(*current, &mod, ®op, &rm);
1064 switch (opcode) {
1065 case 0x28:
1066 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1067 current += PrintRightXMMOperand(current);
1068 break;
1069 case 0x51:
1070 AppendToBuffer("vsqrtps %s,", NameOfXMMRegister(regop));
1071 current += PrintRightXMMOperand(current);
1072 break;
1073 case 0x52:
1074 AppendToBuffer("vrsqrtps %s,", NameOfXMMRegister(regop));
1075 current += PrintRightXMMOperand(current);
1076 break;
1077 case 0x53:
1078 AppendToBuffer("vrcpps %s,", NameOfXMMRegister(regop));
1079 current += PrintRightXMMOperand(current);
1080 break;
1081 case 0x54:
1082 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1083 NameOfXMMRegister(vvvv));
1084 current += PrintRightXMMOperand(current);
1085 break;
1086 case 0x55:
1087 AppendToBuffer("vandnps %s,%s,", NameOfXMMRegister(regop),
1088 NameOfXMMRegister(vvvv));
1089 current += PrintRightXMMOperand(current);
1090 break;
1091 case 0x56:
1092 AppendToBuffer("vorps %s,%s,", NameOfXMMRegister(regop),
1093 NameOfXMMRegister(vvvv));
1094 current += PrintRightXMMOperand(current);
1095 break;
1096 case 0x57:
1097 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1098 NameOfXMMRegister(vvvv));
1099 current += PrintRightXMMOperand(current);
1100 break;
1101 case 0x58:
1102 AppendToBuffer("vaddps %s,%s,", NameOfXMMRegister(regop),
1103 NameOfXMMRegister(vvvv));
1104 current += PrintRightXMMOperand(current);
1105 break;
1106 case 0x59:
1107 AppendToBuffer("vmulps %s,%s,", NameOfXMMRegister(regop),
1108 NameOfXMMRegister(vvvv));
1109 current += PrintRightXMMOperand(current);
1110 break;
1111 case 0x5B:
1112 AppendToBuffer("vcvtdq2ps %s,", NameOfXMMRegister(regop));
1113 current += PrintRightXMMOperand(current);
1114 break;
1115 case 0x5C:
1116 AppendToBuffer("vsubps %s,%s,", NameOfXMMRegister(regop),
1117 NameOfXMMRegister(vvvv));
1118 current += PrintRightXMMOperand(current);
1119 break;
1120 case 0x5D:
1121 AppendToBuffer("vminps %s,%s,", NameOfXMMRegister(regop),
1122 NameOfXMMRegister(vvvv));
1123 current += PrintRightXMMOperand(current);
1124 break;
1125 case 0x5E:
1126 AppendToBuffer("vdivps %s,%s,", NameOfXMMRegister(regop),
1127 NameOfXMMRegister(vvvv));
1128 current += PrintRightXMMOperand(current);
1129 break;
1130 case 0x5F:
1131 AppendToBuffer("vmaxps %s,%s,", NameOfXMMRegister(regop),
1132 NameOfXMMRegister(vvvv));
1133 current += PrintRightXMMOperand(current);
1134 break;
1135 case 0xC2: {
1136 const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1137 "neq", "nlt", "nle", "ord"};
1138 AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1139 NameOfXMMRegister(vvvv));
1140 current += PrintRightXMMOperand(current);
1141 AppendToBuffer(", (%s)", pseudo_op[*current]);
1142 current++;
1143 break;
1144 }
1145 case 0xC6:
1146 AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop),
1147 NameOfXMMRegister(vvvv));
1148 current += PrintRightXMMOperand(current);
1149 AppendToBuffer(", %d", (*current) & 3);
1150 current += 1;
1151 break;
1152 default:
1153 UnimplementedInstruction();
1154 }
1155 } else if (vex_66() && vex_0f()) {
1156 int mod, regop, rm, vvvv = vex_vreg();
1157 get_modrm(*current, &mod, ®op, &rm);
1158 switch (opcode) {
1159 case 0x28:
1160 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1161 current += PrintRightXMMOperand(current);
1162 break;
1163 case 0x54:
1164 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1165 NameOfXMMRegister(vvvv));
1166 current += PrintRightXMMOperand(current);
1167 break;
1168 case 0x55:
1169 AppendToBuffer("vandnpd %s,%s,", NameOfXMMRegister(regop),
1170 NameOfXMMRegister(vvvv));
1171 current += PrintRightXMMOperand(current);
1172 break;
1173 case 0x56:
1174 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1175 NameOfXMMRegister(vvvv));
1176 current += PrintRightXMMOperand(current);
1177 break;
1178 case 0x57:
1179 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1180 NameOfXMMRegister(vvvv));
1181 current += PrintRightXMMOperand(current);
1182 break;
1183 case 0x58:
1184 AppendToBuffer("vaddpd %s,%s,", NameOfXMMRegister(regop),
1185 NameOfXMMRegister(vvvv));
1186 current += PrintRightXMMOperand(current);
1187 break;
1188 case 0x59:
1189 AppendToBuffer("vmulpd %s,%s,", NameOfXMMRegister(regop),
1190 NameOfXMMRegister(vvvv));
1191 current += PrintRightXMMOperand(current);
1192 break;
1193 case 0x5C:
1194 AppendToBuffer("vsubpd %s,%s,", NameOfXMMRegister(regop),
1195 NameOfXMMRegister(vvvv));
1196 current += PrintRightXMMOperand(current);
1197 break;
1198 case 0x5D:
1199 AppendToBuffer("vminpd %s,%s,", NameOfXMMRegister(regop),
1200 NameOfXMMRegister(vvvv));
1201 current += PrintRightXMMOperand(current);
1202 break;
1203 case 0x5E:
1204 AppendToBuffer("vdivpd %s,%s,", NameOfXMMRegister(regop),
1205 NameOfXMMRegister(vvvv));
1206 current += PrintRightXMMOperand(current);
1207 break;
1208 case 0x5F:
1209 AppendToBuffer("vmaxpd %s,%s,", NameOfXMMRegister(regop),
1210 NameOfXMMRegister(vvvv));
1211 current += PrintRightXMMOperand(current);
1212 break;
1213 case 0x6E:
1214 AppendToBuffer("vmovd %s,", NameOfXMMRegister(regop));
1215 current += PrintRightOperand(current);
1216 break;
1217 case 0x70:
1218 AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1219 current += PrintRightXMMOperand(current);
1220 AppendToBuffer(",%d", Imm8(current));
1221 current++;
1222 break;
1223 case 0x71:
1224 AppendToBuffer("vps%sw %s,%s", sf_str[regop / 2],
1225 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1226 current++;
1227 AppendToBuffer(",%u", *current++);
1228 break;
1229 case 0x72:
1230 AppendToBuffer("vps%sd %s,%s", sf_str[regop / 2],
1231 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1232 current++;
1233 AppendToBuffer(",%u", *current++);
1234 break;
1235 case 0x73:
1236 AppendToBuffer("vps%sq %s,%s", sf_str[regop / 2],
1237 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1238 current++;
1239 AppendToBuffer(",%u", *current++);
1240 break;
1241 case 0x7E:
1242 AppendToBuffer("vmovd ");
1243 current += PrintRightOperand(current);
1244 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1245 break;
1246 case 0xC2: {
1247 const char* const pseudo_op[] = {"eq", "lt", "le", "unord", "neq"};
1248 AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1249 NameOfXMMRegister(vvvv));
1250 current += PrintRightXMMOperand(current);
1251 AppendToBuffer(", (%s)", pseudo_op[*current]);
1252 current++;
1253 break;
1254 }
1255 case 0xC4:
1256 AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1257 NameOfXMMRegister(vvvv));
1258 current += PrintRightOperand(current);
1259 AppendToBuffer(",%d", Imm8(current));
1260 current++;
1261 break;
1262 case 0xC6:
1263 AppendToBuffer("vshufpd %s,%s,", NameOfXMMRegister(regop),
1264 NameOfXMMRegister(vvvv));
1265 current += PrintRightXMMOperand(current);
1266 AppendToBuffer(",%d", Imm8(current));
1267 current++;
1268 break;
1269 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1270 case 0x##opcode: { \
1271 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
1272 NameOfXMMRegister(vvvv)); \
1273 current += PrintRightXMMOperand(current); \
1274 break; \
1275 }
1276
1277 SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1278 #undef DECLARE_SSE_AVX_DIS_CASE
1279 default:
1280 UnimplementedInstruction();
1281 }
1282 } else {
1283 UnimplementedInstruction();
1284 }
1285
1286 return static_cast<int>(current - data);
1287 }
1288
1289 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)1290 int DisassemblerIA32::FPUInstruction(byte* data) {
1291 byte escape_opcode = *data;
1292 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1293 byte modrm_byte = *(data + 1);
1294
1295 if (modrm_byte >= 0xC0) {
1296 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1297 } else {
1298 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
1299 }
1300 }
1301
MemoryFPUInstruction(int escape_opcode,int modrm_byte,byte * modrm_start)1302 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, int modrm_byte,
1303 byte* modrm_start) {
1304 const char* mnem = "?";
1305 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1306 switch (escape_opcode) {
1307 case 0xD9:
1308 switch (regop) {
1309 case 0:
1310 mnem = "fld_s";
1311 break;
1312 case 2:
1313 mnem = "fst_s";
1314 break;
1315 case 3:
1316 mnem = "fstp_s";
1317 break;
1318 case 7:
1319 mnem = "fstcw";
1320 break;
1321 default:
1322 UnimplementedInstruction();
1323 }
1324 break;
1325
1326 case 0xDB:
1327 switch (regop) {
1328 case 0:
1329 mnem = "fild_s";
1330 break;
1331 case 1:
1332 mnem = "fisttp_s";
1333 break;
1334 case 2:
1335 mnem = "fist_s";
1336 break;
1337 case 3:
1338 mnem = "fistp_s";
1339 break;
1340 default:
1341 UnimplementedInstruction();
1342 }
1343 break;
1344
1345 case 0xDD:
1346 switch (regop) {
1347 case 0:
1348 mnem = "fld_d";
1349 break;
1350 case 1:
1351 mnem = "fisttp_d";
1352 break;
1353 case 2:
1354 mnem = "fst_d";
1355 break;
1356 case 3:
1357 mnem = "fstp_d";
1358 break;
1359 default:
1360 UnimplementedInstruction();
1361 }
1362 break;
1363
1364 case 0xDF:
1365 switch (regop) {
1366 case 5:
1367 mnem = "fild_d";
1368 break;
1369 case 7:
1370 mnem = "fistp_d";
1371 break;
1372 default:
1373 UnimplementedInstruction();
1374 }
1375 break;
1376
1377 default:
1378 UnimplementedInstruction();
1379 }
1380 AppendToBuffer("%s ", mnem);
1381 int count = PrintRightOperand(modrm_start);
1382 return count + 1;
1383 }
1384
RegisterFPUInstruction(int escape_opcode,byte modrm_byte)1385 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1386 byte modrm_byte) {
1387 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1388 const char* mnem = "?";
1389
1390 switch (escape_opcode) {
1391 case 0xD8:
1392 has_register = true;
1393 switch (modrm_byte & 0xF8) {
1394 case 0xC0:
1395 mnem = "fadd_i";
1396 break;
1397 case 0xE0:
1398 mnem = "fsub_i";
1399 break;
1400 case 0xC8:
1401 mnem = "fmul_i";
1402 break;
1403 case 0xF0:
1404 mnem = "fdiv_i";
1405 break;
1406 default:
1407 UnimplementedInstruction();
1408 }
1409 break;
1410
1411 case 0xD9:
1412 switch (modrm_byte & 0xF8) {
1413 case 0xC0:
1414 mnem = "fld";
1415 has_register = true;
1416 break;
1417 case 0xC8:
1418 mnem = "fxch";
1419 has_register = true;
1420 break;
1421 default:
1422 switch (modrm_byte) {
1423 case 0xE0:
1424 mnem = "fchs";
1425 break;
1426 case 0xE1:
1427 mnem = "fabs";
1428 break;
1429 case 0xE4:
1430 mnem = "ftst";
1431 break;
1432 case 0xE8:
1433 mnem = "fld1";
1434 break;
1435 case 0xEB:
1436 mnem = "fldpi";
1437 break;
1438 case 0xED:
1439 mnem = "fldln2";
1440 break;
1441 case 0xEE:
1442 mnem = "fldz";
1443 break;
1444 case 0xF0:
1445 mnem = "f2xm1";
1446 break;
1447 case 0xF1:
1448 mnem = "fyl2x";
1449 break;
1450 case 0xF4:
1451 mnem = "fxtract";
1452 break;
1453 case 0xF5:
1454 mnem = "fprem1";
1455 break;
1456 case 0xF7:
1457 mnem = "fincstp";
1458 break;
1459 case 0xF8:
1460 mnem = "fprem";
1461 break;
1462 case 0xFC:
1463 mnem = "frndint";
1464 break;
1465 case 0xFD:
1466 mnem = "fscale";
1467 break;
1468 case 0xFE:
1469 mnem = "fsin";
1470 break;
1471 case 0xFF:
1472 mnem = "fcos";
1473 break;
1474 default:
1475 UnimplementedInstruction();
1476 }
1477 }
1478 break;
1479
1480 case 0xDA:
1481 if (modrm_byte == 0xE9) {
1482 mnem = "fucompp";
1483 } else {
1484 UnimplementedInstruction();
1485 }
1486 break;
1487
1488 case 0xDB:
1489 if ((modrm_byte & 0xF8) == 0xE8) {
1490 mnem = "fucomi";
1491 has_register = true;
1492 } else if (modrm_byte == 0xE2) {
1493 mnem = "fclex";
1494 } else if (modrm_byte == 0xE3) {
1495 mnem = "fninit";
1496 } else {
1497 UnimplementedInstruction();
1498 }
1499 break;
1500
1501 case 0xDC:
1502 has_register = true;
1503 switch (modrm_byte & 0xF8) {
1504 case 0xC0:
1505 mnem = "fadd";
1506 break;
1507 case 0xE8:
1508 mnem = "fsub";
1509 break;
1510 case 0xC8:
1511 mnem = "fmul";
1512 break;
1513 case 0xF8:
1514 mnem = "fdiv";
1515 break;
1516 default:
1517 UnimplementedInstruction();
1518 }
1519 break;
1520
1521 case 0xDD:
1522 has_register = true;
1523 switch (modrm_byte & 0xF8) {
1524 case 0xC0:
1525 mnem = "ffree";
1526 break;
1527 case 0xD0:
1528 mnem = "fst";
1529 break;
1530 case 0xD8:
1531 mnem = "fstp";
1532 break;
1533 default:
1534 UnimplementedInstruction();
1535 }
1536 break;
1537
1538 case 0xDE:
1539 if (modrm_byte == 0xD9) {
1540 mnem = "fcompp";
1541 } else {
1542 has_register = true;
1543 switch (modrm_byte & 0xF8) {
1544 case 0xC0:
1545 mnem = "faddp";
1546 break;
1547 case 0xE8:
1548 mnem = "fsubp";
1549 break;
1550 case 0xC8:
1551 mnem = "fmulp";
1552 break;
1553 case 0xF8:
1554 mnem = "fdivp";
1555 break;
1556 default:
1557 UnimplementedInstruction();
1558 }
1559 }
1560 break;
1561
1562 case 0xDF:
1563 if (modrm_byte == 0xE0) {
1564 mnem = "fnstsw_ax";
1565 } else if ((modrm_byte & 0xF8) == 0xE8) {
1566 mnem = "fucomip";
1567 has_register = true;
1568 }
1569 break;
1570
1571 default:
1572 UnimplementedInstruction();
1573 }
1574
1575 if (has_register) {
1576 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1577 } else {
1578 AppendToBuffer("%s", mnem);
1579 }
1580 return 2;
1581 }
1582
1583 // Mnemonics for instructions 0xF0 byte.
1584 // Returns nullptr if the instruction is not handled here.
F0Mnem(byte f0byte)1585 static const char* F0Mnem(byte f0byte) {
1586 switch (f0byte) {
1587 case 0x0B:
1588 return "ud2";
1589 case 0x18:
1590 return "prefetch";
1591 case 0xA2:
1592 return "cpuid";
1593 case 0xBE:
1594 return "movsx_b";
1595 case 0xBF:
1596 return "movsx_w";
1597 case 0xB6:
1598 return "movzx_b";
1599 case 0xB7:
1600 return "movzx_w";
1601 case 0xAF:
1602 return "imul";
1603 case 0xA4:
1604 return "shld";
1605 case 0xA5:
1606 return "shld";
1607 case 0xAD:
1608 return "shrd";
1609 case 0xAC:
1610 return "shrd"; // 3-operand version.
1611 case 0xAB:
1612 return "bts";
1613 case 0xB0:
1614 return "cmpxchg_b";
1615 case 0xB1:
1616 return "cmpxchg";
1617 case 0xBC:
1618 return "bsf";
1619 case 0xBD:
1620 return "bsr";
1621 case 0xC7:
1622 return "cmpxchg8b";
1623 default:
1624 return nullptr;
1625 }
1626 }
1627
1628 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
InstructionDecode(v8::internal::Vector<char> out_buffer,byte * instr)1629 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1630 byte* instr) {
1631 tmp_buffer_pos_ = 0; // starting to write as position 0
1632 byte* data = instr;
1633 // Check for hints.
1634 const char* branch_hint = nullptr;
1635 // We use these two prefixes only with branch prediction
1636 if (*data == 0x3E /*ds*/) {
1637 branch_hint = "predicted taken";
1638 data++;
1639 } else if (*data == 0x2E /*cs*/) {
1640 branch_hint = "predicted not taken";
1641 data++;
1642 } else if (*data == 0xC4 && *(data + 1) >= 0xC0) {
1643 vex_byte0_ = *data;
1644 vex_byte1_ = *(data + 1);
1645 vex_byte2_ = *(data + 2);
1646 data += 3;
1647 } else if (*data == 0xC5 && *(data + 1) >= 0xC0) {
1648 vex_byte0_ = *data;
1649 vex_byte1_ = *(data + 1);
1650 data += 2;
1651 } else if (*data == 0xF0 /*lock*/) {
1652 AppendToBuffer("lock ");
1653 data++;
1654 }
1655
1656 bool processed = true; // Will be set to false if the current instruction
1657 // is not in 'instructions' table.
1658 // Decode AVX instructions.
1659 if (vex_byte0_ != 0) {
1660 data += AVXInstruction(data);
1661 } else {
1662 const InstructionDesc& idesc = instruction_table_->Get(*data);
1663 switch (idesc.type) {
1664 case ZERO_OPERANDS_INSTR:
1665 AppendToBuffer("%s", idesc.mnem);
1666 data++;
1667 break;
1668
1669 case TWO_OPERANDS_INSTR:
1670 data++;
1671 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1672 break;
1673
1674 case JUMP_CONDITIONAL_SHORT_INSTR:
1675 data += JumpConditionalShort(data, branch_hint);
1676 break;
1677
1678 case REGISTER_INSTR:
1679 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1680 data++;
1681 break;
1682
1683 case MOVE_REG_INSTR: {
1684 byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1685 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1686 NameOfAddress(addr));
1687 data += 5;
1688 break;
1689 }
1690
1691 case CALL_JUMP_INSTR: {
1692 byte* addr = data + Imm32(data + 1) + 5;
1693 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1694 data += 5;
1695 break;
1696 }
1697
1698 case SHORT_IMMEDIATE_INSTR: {
1699 byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1700 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1701 data += 5;
1702 break;
1703 }
1704
1705 case BYTE_IMMEDIATE_INSTR: {
1706 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1707 data += 2;
1708 break;
1709 }
1710
1711 case NO_INSTR:
1712 processed = false;
1713 break;
1714
1715 default:
1716 UNIMPLEMENTED(); // This type is not implemented.
1717 }
1718 }
1719 //----------------------------
1720 if (!processed) {
1721 switch (*data) {
1722 case 0xC2:
1723 AppendToBuffer("ret 0x%x", Imm16_U(data + 1));
1724 data += 3;
1725 break;
1726
1727 case 0x6B: {
1728 data++;
1729 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1730 AppendToBuffer(",%d", *data);
1731 data++;
1732 } break;
1733
1734 case 0x69: {
1735 data++;
1736 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1737 AppendToBuffer(",%d", Imm32(data));
1738 data += 4;
1739 } break;
1740
1741 case 0xF6: {
1742 data++;
1743 int mod, regop, rm;
1744 get_modrm(*data, &mod, ®op, &rm);
1745 if (regop == eax) {
1746 AppendToBuffer("test_b ");
1747 data += PrintRightByteOperand(data);
1748 int32_t imm = *data;
1749 AppendToBuffer(",0x%x", imm);
1750 data++;
1751 } else {
1752 UnimplementedInstruction();
1753 }
1754 } break;
1755
1756 case 0x81: // fall through
1757 case 0x83: // 0x81 with sign extension bit set
1758 data += PrintImmediateOp(data);
1759 break;
1760
1761 case 0x0F: {
1762 byte f0byte = data[1];
1763 const char* f0mnem = F0Mnem(f0byte);
1764 if (f0byte == 0x18) {
1765 data += 2;
1766 int mod, regop, rm;
1767 get_modrm(*data, &mod, ®op, &rm);
1768 const char* suffix[] = {"nta", "1", "2", "3"};
1769 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1770 data += PrintRightOperand(data);
1771 } else if (f0byte == 0x1F && data[2] == 0) {
1772 AppendToBuffer("nop"); // 3 byte nop.
1773 data += 3;
1774 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1775 AppendToBuffer("nop"); // 4 byte nop.
1776 data += 4;
1777 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1778 data[4] == 0) {
1779 AppendToBuffer("nop"); // 5 byte nop.
1780 data += 5;
1781 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1782 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1783 AppendToBuffer("nop"); // 7 byte nop.
1784 data += 7;
1785 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1786 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1787 data[7] == 0) {
1788 AppendToBuffer("nop"); // 8 byte nop.
1789 data += 8;
1790 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1791 AppendToBuffer("%s", f0mnem);
1792 data += 2;
1793 } else if (f0byte == 0x28) {
1794 data += 2;
1795 int mod, regop, rm;
1796 get_modrm(*data, &mod, ®op, &rm);
1797 AppendToBuffer("movaps %s,%s", NameOfXMMRegister(regop),
1798 NameOfXMMRegister(rm));
1799 data++;
1800 } else if (f0byte == 0x10 || f0byte == 0x11) {
1801 data += 2;
1802 // movups xmm, xmm/m128
1803 // movups xmm/m128, xmm
1804 int mod, regop, rm;
1805 get_modrm(*data, &mod, ®op, &rm);
1806 AppendToBuffer("movups ");
1807 if (f0byte == 0x11) {
1808 data += PrintRightXMMOperand(data);
1809 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1810 } else {
1811 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1812 data += PrintRightXMMOperand(data);
1813 }
1814 } else if (f0byte == 0x2E) {
1815 data += 2;
1816 int mod, regop, rm;
1817 get_modrm(*data, &mod, ®op, &rm);
1818 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1819 data += PrintRightXMMOperand(data);
1820 } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1821 const char* const pseudo_op[] = {
1822 "sqrtps", "rsqrtps", "rcpps", "andps", "andnps",
1823 "orps", "xorps", "addps", "mulps", "cvtps2pd",
1824 "cvtdq2ps", "subps", "minps", "divps", "maxps",
1825 };
1826
1827 data += 2;
1828 int mod, regop, rm;
1829 get_modrm(*data, &mod, ®op, &rm);
1830 AppendToBuffer("%s %s,", pseudo_op[f0byte - 0x51],
1831 NameOfXMMRegister(regop));
1832 data += PrintRightXMMOperand(data);
1833 } else if (f0byte == 0x50) {
1834 data += 2;
1835 int mod, regop, rm;
1836 get_modrm(*data, &mod, ®op, &rm);
1837 AppendToBuffer("movmskps %s,%s", NameOfCPURegister(regop),
1838 NameOfXMMRegister(rm));
1839 data++;
1840 } else if (f0byte == 0xC2) {
1841 data += 2;
1842 int mod, regop, rm;
1843 get_modrm(*data, &mod, ®op, &rm);
1844 const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1845 "neq", "nlt", "nle", "ord"};
1846 AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
1847 data += PrintRightXMMOperand(data);
1848 AppendToBuffer(", (%s)", pseudo_op[*data]);
1849 data++;
1850 } else if (f0byte == 0xC6) {
1851 // shufps xmm, xmm/m128, imm8
1852 data += 2;
1853 int mod, regop, rm;
1854 get_modrm(*data, &mod, ®op, &rm);
1855 int8_t imm8 = static_cast<int8_t>(data[1]);
1856 AppendToBuffer("shufps %s,%s,%d", NameOfXMMRegister(rm),
1857 NameOfXMMRegister(regop), static_cast<int>(imm8));
1858 data += 2;
1859 } else if (f0byte >= 0xC8 && f0byte <= 0xCF) {
1860 // bswap
1861 data += 2;
1862 int reg = f0byte - 0xC8;
1863 AppendToBuffer("bswap %s", NameOfCPURegister(reg));
1864 } else if ((f0byte & 0xF0) == 0x80) {
1865 data += JumpConditional(data, branch_hint);
1866 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1867 f0byte == 0xB7 || f0byte == 0xAF) {
1868 data += 2;
1869 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1870 } else if ((f0byte & 0xF0) == 0x90) {
1871 data += SetCC(data);
1872 } else if ((f0byte & 0xF0) == 0x40) {
1873 data += CMov(data);
1874 } else if (f0byte == 0xA4 || f0byte == 0xAC) {
1875 // shld, shrd
1876 data += 2;
1877 AppendToBuffer("%s ", f0mnem);
1878 int mod, regop, rm;
1879 get_modrm(*data, &mod, ®op, &rm);
1880 int8_t imm8 = static_cast<int8_t>(data[1]);
1881 data += 2;
1882 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
1883 NameOfCPURegister(regop), static_cast<int>(imm8));
1884 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1885 // shrd_cl, shld_cl, bts
1886 data += 2;
1887 AppendToBuffer("%s ", f0mnem);
1888 int mod, regop, rm;
1889 get_modrm(*data, &mod, ®op, &rm);
1890 data += PrintRightOperand(data);
1891 if (f0byte == 0xAB) {
1892 AppendToBuffer(",%s", NameOfCPURegister(regop));
1893 } else {
1894 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1895 }
1896 } else if (f0byte == 0xB0) {
1897 // cmpxchg_b
1898 data += 2;
1899 AppendToBuffer("%s ", f0mnem);
1900 int mod, regop, rm;
1901 get_modrm(*data, &mod, ®op, &rm);
1902 data += PrintRightOperand(data);
1903 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1904 } else if (f0byte == 0xB1) {
1905 // cmpxchg
1906 data += 2;
1907 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
1908 } else if (f0byte == 0xBC) {
1909 data += 2;
1910 int mod, regop, rm;
1911 get_modrm(*data, &mod, ®op, &rm);
1912 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1913 data += PrintRightOperand(data);
1914 } else if (f0byte == 0xBD) {
1915 data += 2;
1916 int mod, regop, rm;
1917 get_modrm(*data, &mod, ®op, &rm);
1918 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1919 data += PrintRightOperand(data);
1920 } else if (f0byte == 0xC7) {
1921 // cmpxchg8b
1922 data += 2;
1923 AppendToBuffer("%s ", f0mnem);
1924 int mod, regop, rm;
1925 get_modrm(*data, &mod, ®op, &rm);
1926 data += PrintRightOperand(data);
1927 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xF0) {
1928 AppendToBuffer("mfence");
1929 data += 3;
1930 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xE8) {
1931 AppendToBuffer("lfence");
1932 data += 3;
1933 } else {
1934 UnimplementedInstruction();
1935 }
1936 } break;
1937
1938 case 0x8F: {
1939 data++;
1940 int mod, regop, rm;
1941 get_modrm(*data, &mod, ®op, &rm);
1942 if (regop == eax) {
1943 AppendToBuffer("pop ");
1944 data += PrintRightOperand(data);
1945 }
1946 } break;
1947
1948 case 0xFF: {
1949 data++;
1950 int mod, regop, rm;
1951 get_modrm(*data, &mod, ®op, &rm);
1952 const char* mnem = nullptr;
1953 switch (regop) {
1954 case esi:
1955 mnem = "push";
1956 break;
1957 case eax:
1958 mnem = "inc";
1959 break;
1960 case ecx:
1961 mnem = "dec";
1962 break;
1963 case edx:
1964 mnem = "call";
1965 break;
1966 case esp:
1967 mnem = "jmp";
1968 break;
1969 default:
1970 mnem = "???";
1971 }
1972 AppendToBuffer("%s ", mnem);
1973 data += PrintRightOperand(data);
1974 } break;
1975
1976 case 0xC7: // imm32, fall through
1977 case 0xC6: // imm8
1978 {
1979 bool is_byte = *data == 0xC6;
1980 data++;
1981 if (is_byte) {
1982 AppendToBuffer("%s ", "mov_b");
1983 data += PrintRightByteOperand(data);
1984 int32_t imm = *data;
1985 AppendToBuffer(",0x%x", imm);
1986 data++;
1987 } else {
1988 AppendToBuffer("%s ", "mov");
1989 data += PrintRightOperand(data);
1990 AppendToBuffer(",0x%x", Imm32(data));
1991 data += 4;
1992 }
1993 } break;
1994
1995 case 0x80: {
1996 data++;
1997 int mod, regop, rm;
1998 get_modrm(*data, &mod, ®op, &rm);
1999 const char* mnem = nullptr;
2000 switch (regop) {
2001 case 5:
2002 mnem = "subb";
2003 break;
2004 case 7:
2005 mnem = "cmpb";
2006 break;
2007 default:
2008 UnimplementedInstruction();
2009 }
2010 AppendToBuffer("%s ", mnem);
2011 data += PrintRightByteOperand(data);
2012 int32_t imm = *data;
2013 AppendToBuffer(",0x%x", imm);
2014 data++;
2015 } break;
2016
2017 case 0x88: // 8bit, fall through
2018 case 0x89: // 32bit
2019 {
2020 bool is_byte = *data == 0x88;
2021 int mod, regop, rm;
2022 data++;
2023 get_modrm(*data, &mod, ®op, &rm);
2024 if (is_byte) {
2025 AppendToBuffer("%s ", "mov_b");
2026 data += PrintRightByteOperand(data);
2027 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2028 } else {
2029 AppendToBuffer("%s ", "mov");
2030 data += PrintRightOperand(data);
2031 AppendToBuffer(",%s", NameOfCPURegister(regop));
2032 }
2033 } break;
2034
2035 case 0x66: // prefix
2036 while (*data == 0x66) data++;
2037 if (*data == 0xF && data[1] == 0x1F) {
2038 AppendToBuffer("nop"); // 0x66 prefix
2039 } else if (*data == 0x39) {
2040 data++;
2041 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data);
2042 } else if (*data == 0x3B) {
2043 data++;
2044 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data);
2045 } else if (*data == 0x81) {
2046 data++;
2047 AppendToBuffer("cmpw ");
2048 data += PrintRightOperand(data);
2049 AppendToBuffer(",0x%x", Imm16(data));
2050 data += 2;
2051 } else if (*data == 0x87) {
2052 data++;
2053 int mod, regop, rm;
2054 get_modrm(*data, &mod, ®op, &rm);
2055 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
2056 data += PrintRightOperand(data);
2057 } else if (*data == 0x89) {
2058 data++;
2059 int mod, regop, rm;
2060 get_modrm(*data, &mod, ®op, &rm);
2061 AppendToBuffer("mov_w ");
2062 data += PrintRightOperand(data);
2063 AppendToBuffer(",%s", NameOfCPURegister(regop));
2064 } else if (*data == 0x8B) {
2065 data++;
2066 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
2067 } else if (*data == 0x90) {
2068 AppendToBuffer("nop"); // 0x66 prefix
2069 } else if (*data == 0xC7) {
2070 data++;
2071 AppendToBuffer("%s ", "mov_w");
2072 data += PrintRightOperand(data);
2073 AppendToBuffer(",0x%x", Imm16(data));
2074 data += 2;
2075 } else if (*data == 0xF7) {
2076 data++;
2077 AppendToBuffer("%s ", "test_w");
2078 data += PrintRightOperand(data);
2079 AppendToBuffer(",0x%x", Imm16(data));
2080 data += 2;
2081 } else if (*data == 0x0F) {
2082 data++;
2083 if (*data == 0x28) {
2084 data++;
2085 int mod, regop, rm;
2086 get_modrm(*data, &mod, ®op, &rm);
2087 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
2088 data += PrintRightXMMOperand(data);
2089 } else if (*data == 0x38) {
2090 data++;
2091 byte op = *data;
2092 data++;
2093 int mod, regop, rm;
2094 get_modrm(*data, &mod, ®op, &rm);
2095 switch (op) {
2096 #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
2097 case 0x##opcode: { \
2098 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2099 data += PrintRightXMMOperand(data); \
2100 break; \
2101 }
2102
2103 SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
2104 SSSE3_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
2105 SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
2106 SSE4_RM_INSTRUCTION_LIST(SSE34_DIS_CASE)
2107 #undef SSE34_DIS_CASE
2108 default:
2109 UnimplementedInstruction();
2110 }
2111 } else if (*data == 0x3A) {
2112 data++;
2113 if (*data == 0x0A) {
2114 data++;
2115 int mod, regop, rm;
2116 get_modrm(*data, &mod, ®op, &rm);
2117 int8_t imm8 = static_cast<int8_t>(data[1]);
2118 AppendToBuffer("roundss %s,%s,%d", NameOfXMMRegister(regop),
2119 NameOfXMMRegister(rm), static_cast<int>(imm8));
2120 data += 2;
2121 } else if (*data == 0x0B) {
2122 data++;
2123 int mod, regop, rm;
2124 get_modrm(*data, &mod, ®op, &rm);
2125 int8_t imm8 = static_cast<int8_t>(data[1]);
2126 AppendToBuffer("roundsd %s,%s,%d", NameOfXMMRegister(regop),
2127 NameOfXMMRegister(rm), static_cast<int>(imm8));
2128 data += 2;
2129 } else if (*data == 0x0E) {
2130 data++;
2131 int mod, regop, rm;
2132 get_modrm(*data, &mod, ®op, &rm);
2133 AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop));
2134 data += PrintRightXMMOperand(data);
2135 AppendToBuffer(",%d", Imm8_U(data));
2136 data++;
2137 } else if (*data == 0x0F) {
2138 data++;
2139 int mod, regop, rm;
2140 get_modrm(*data, &mod, ®op, &rm);
2141 AppendToBuffer("palignr %s,", NameOfXMMRegister(regop));
2142 data += PrintRightXMMOperand(data);
2143 AppendToBuffer(",%d", Imm8_U(data));
2144 data++;
2145 } else if (*data == 0x14) {
2146 data++;
2147 int mod, regop, rm;
2148 get_modrm(*data, &mod, ®op, &rm);
2149 AppendToBuffer("pextrb ");
2150 data += PrintRightOperand(data);
2151 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2152 data++;
2153 } else if (*data == 0x15) {
2154 data++;
2155 int mod, regop, rm;
2156 get_modrm(*data, &mod, ®op, &rm);
2157 AppendToBuffer("pextrw ");
2158 data += PrintRightOperand(data);
2159 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2160 data++;
2161 } else if (*data == 0x16) {
2162 data++;
2163 int mod, regop, rm;
2164 get_modrm(*data, &mod, ®op, &rm);
2165 AppendToBuffer("pextrd ");
2166 data += PrintRightOperand(data);
2167 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2168 data++;
2169 } else if (*data == 0x17) {
2170 data++;
2171 int mod, regop, rm;
2172 get_modrm(*data, &mod, ®op, &rm);
2173 int8_t imm8 = static_cast<int8_t>(data[1]);
2174 AppendToBuffer("extractps %s,%s,%d", NameOfCPURegister(rm),
2175 NameOfXMMRegister(regop), static_cast<int>(imm8));
2176 data += 2;
2177 } else if (*data == 0x20) {
2178 data++;
2179 int mod, regop, rm;
2180 get_modrm(*data, &mod, ®op, &rm);
2181 AppendToBuffer("pinsrb %s,", NameOfXMMRegister(regop));
2182 data += PrintRightOperand(data);
2183 AppendToBuffer(",%d", Imm8(data));
2184 data++;
2185 } else if (*data == 0x21) {
2186 data++;
2187 int mod, regop, rm;
2188 get_modrm(*data, &mod, ®op, &rm);
2189 AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
2190 data += PrintRightXMMOperand(data);
2191 AppendToBuffer(",%d", Imm8(data));
2192 data++;
2193 } else if (*data == 0x22) {
2194 data++;
2195 int mod, regop, rm;
2196 get_modrm(*data, &mod, ®op, &rm);
2197 AppendToBuffer("pinsrd %s,", NameOfXMMRegister(regop));
2198 data += PrintRightOperand(data);
2199 AppendToBuffer(",%d", Imm8(data));
2200 data++;
2201 } else {
2202 UnimplementedInstruction();
2203 }
2204 } else if (*data == 0x2E || *data == 0x2F) {
2205 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
2206 data++;
2207 int mod, regop, rm;
2208 get_modrm(*data, &mod, ®op, &rm);
2209 if (mod == 0x3) {
2210 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
2211 NameOfXMMRegister(rm));
2212 data++;
2213 } else {
2214 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2215 data += PrintRightOperand(data);
2216 }
2217 } else if (*data == 0x50) {
2218 data++;
2219 int mod, regop, rm;
2220 get_modrm(*data, &mod, ®op, &rm);
2221 AppendToBuffer("movmskpd %s,%s", NameOfCPURegister(regop),
2222 NameOfXMMRegister(rm));
2223 data++;
2224 } else if (*data >= 0x54 && *data <= 0x59) {
2225 const char* const pseudo_op[] = {
2226 "andpd", "andnpd", "orpd", "xorpd", "addpd", "mulpd",
2227 };
2228 byte op = *data;
2229 data++;
2230 int mod, regop, rm;
2231 get_modrm(*data, &mod, ®op, &rm);
2232 AppendToBuffer("%s %s,", pseudo_op[op - 0x54],
2233 NameOfXMMRegister(regop));
2234 data += PrintRightXMMOperand(data);
2235 } else if (*data >= 0x5c && *data <= 0x5f) {
2236 const char* const pseudo_op[] = {
2237 "subpd",
2238 "minpd",
2239 "divpd",
2240 "maxpd",
2241 };
2242 byte op = *data;
2243 data++;
2244 int mod, regop, rm;
2245 get_modrm(*data, &mod, ®op, &rm);
2246 AppendToBuffer("%s %s,", pseudo_op[op - 0x5c],
2247 NameOfXMMRegister(regop));
2248 data += PrintRightXMMOperand(data);
2249 } else if (*data == 0x6E) {
2250 data++;
2251 int mod, regop, rm;
2252 get_modrm(*data, &mod, ®op, &rm);
2253 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
2254 data += PrintRightOperand(data);
2255 } else if (*data == 0x6F) {
2256 data++;
2257 int mod, regop, rm;
2258 get_modrm(*data, &mod, ®op, &rm);
2259 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
2260 data += PrintRightXMMOperand(data);
2261 } else if (*data == 0x70) {
2262 data++;
2263 int mod, regop, rm;
2264 get_modrm(*data, &mod, ®op, &rm);
2265 AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
2266 data += PrintRightXMMOperand(data);
2267 AppendToBuffer(",%d", Imm8(data));
2268 data++;
2269 } else if (*data == 0x90) {
2270 data++;
2271 AppendToBuffer("nop"); // 2 byte nop.
2272 } else if (*data == 0x71) {
2273 data++;
2274 int mod, regop, rm;
2275 get_modrm(*data, &mod, ®op, &rm);
2276 int8_t imm8 = static_cast<int8_t>(data[1]);
2277 AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2],
2278 NameOfXMMRegister(rm), static_cast<int>(imm8));
2279 data += 2;
2280 } else if (*data == 0x72) {
2281 data++;
2282 int mod, regop, rm;
2283 get_modrm(*data, &mod, ®op, &rm);
2284 int8_t imm8 = static_cast<int8_t>(data[1]);
2285 AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2],
2286 NameOfXMMRegister(rm), static_cast<int>(imm8));
2287 data += 2;
2288 } else if (*data == 0x73) {
2289 data++;
2290 int mod, regop, rm;
2291 get_modrm(*data, &mod, ®op, &rm);
2292 int8_t imm8 = static_cast<int8_t>(data[1]);
2293 DCHECK(regop == esi || regop == edx);
2294 AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2],
2295 NameOfXMMRegister(rm), static_cast<int>(imm8));
2296 data += 2;
2297 } else if (*data == 0x7F) {
2298 AppendToBuffer("movdqa ");
2299 data++;
2300 int mod, regop, rm;
2301 get_modrm(*data, &mod, ®op, &rm);
2302 data += PrintRightXMMOperand(data);
2303 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2304 } else if (*data == 0x7E) {
2305 data++;
2306 int mod, regop, rm;
2307 get_modrm(*data, &mod, ®op, &rm);
2308 AppendToBuffer("movd ");
2309 data += PrintRightOperand(data);
2310 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2311 } else if (*data == 0xC2) {
2312 data++;
2313 int mod, regop, rm;
2314 get_modrm(*data, &mod, ®op, &rm);
2315 const char* const pseudo_op[] = {"eq", "lt", "le", "unord", "neq"};
2316 AppendToBuffer("cmppd %s, ", NameOfXMMRegister(regop));
2317 data += PrintRightXMMOperand(data);
2318 AppendToBuffer(", (%s)", pseudo_op[*data]);
2319 data++;
2320 } else if (*data == 0xC4) {
2321 data++;
2322 int mod, regop, rm;
2323 get_modrm(*data, &mod, ®op, &rm);
2324 AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
2325 data += PrintRightOperand(data);
2326 AppendToBuffer(",%d", Imm8(data));
2327 data++;
2328 } else if (*data == 0xC6) {
2329 // shufpd xmm, xmm/m128, imm8
2330 data++;
2331 int mod, regop, rm;
2332 get_modrm(*data, &mod, ®op, &rm);
2333 AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
2334 data += PrintRightXMMOperand(data);
2335 AppendToBuffer(",%d", Imm8(data));
2336 data++;
2337 } else if (*data == 0xE7) {
2338 data++;
2339 int mod, regop, rm;
2340 get_modrm(*data, &mod, ®op, &rm);
2341 if (mod == 3) {
2342 // movntdq
2343 UnimplementedInstruction();
2344 } else {
2345 UnimplementedInstruction();
2346 }
2347 } else if (*data == 0xB1) {
2348 data++;
2349 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
2350 } else {
2351 byte op = *data;
2352 data++;
2353 int mod, regop, rm;
2354 get_modrm(*data, &mod, ®op, &rm);
2355 switch (op) {
2356 #define SSE2_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
2357 case 0x##opcode: { \
2358 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2359 data += PrintRightXMMOperand(data); \
2360 break; \
2361 }
2362
2363 SSE2_INSTRUCTION_LIST(SSE2_DIS_CASE)
2364 #undef SSE2_DIS_CASE
2365 default:
2366 UnimplementedInstruction();
2367 }
2368 }
2369 } else {
2370 UnimplementedInstruction();
2371 }
2372 break;
2373
2374 case 0xFE: {
2375 data++;
2376 int mod, regop, rm;
2377 get_modrm(*data, &mod, ®op, &rm);
2378 if (regop == ecx) {
2379 AppendToBuffer("dec_b ");
2380 data += PrintRightOperand(data);
2381 } else {
2382 UnimplementedInstruction();
2383 }
2384 } break;
2385
2386 case 0x68:
2387 AppendToBuffer("push 0x%x", Imm32(data + 1));
2388 data += 5;
2389 break;
2390
2391 case 0x6A:
2392 AppendToBuffer("push 0x%x", Imm8(data + 1));
2393 data += 2;
2394 break;
2395
2396 case 0xA8:
2397 AppendToBuffer("test al,0x%x", Imm8_U(data + 1));
2398 data += 2;
2399 break;
2400
2401 case 0xA9:
2402 AppendToBuffer("test eax,0x%x", Imm32(data + 1));
2403 data += 5;
2404 break;
2405
2406 case 0xD1: // fall through
2407 case 0xD3: // fall through
2408 case 0xC1:
2409 data += D1D3C1Instruction(data);
2410 break;
2411
2412 case 0xD8: // fall through
2413 case 0xD9: // fall through
2414 case 0xDA: // fall through
2415 case 0xDB: // fall through
2416 case 0xDC: // fall through
2417 case 0xDD: // fall through
2418 case 0xDE: // fall through
2419 case 0xDF:
2420 data += FPUInstruction(data);
2421 break;
2422
2423 case 0xEB:
2424 data += JumpShort(data);
2425 break;
2426
2427 case 0xF2:
2428 if (*(data + 1) == 0x0F) {
2429 byte b2 = *(data + 2);
2430 if (b2 == 0x11) {
2431 AppendToBuffer("movsd ");
2432 data += 3;
2433 int mod, regop, rm;
2434 get_modrm(*data, &mod, ®op, &rm);
2435 data += PrintRightXMMOperand(data);
2436 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2437 } else if (b2 == 0x10) {
2438 data += 3;
2439 int mod, regop, rm;
2440 get_modrm(*data, &mod, ®op, &rm);
2441 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
2442 data += PrintRightXMMOperand(data);
2443 } else if (b2 == 0x12) {
2444 data += 3;
2445 int mod, regop, rm;
2446 get_modrm(*data, &mod, ®op, &rm);
2447 AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
2448 data += PrintRightXMMOperand(data);
2449 } else if (b2 == 0x5A) {
2450 data += 3;
2451 int mod, regop, rm;
2452 get_modrm(*data, &mod, ®op, &rm);
2453 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
2454 data += PrintRightXMMOperand(data);
2455 } else if (b2 == 0x70) {
2456 data += 3;
2457 int mod, regop, rm;
2458 get_modrm(*data, &mod, ®op, &rm);
2459 AppendToBuffer("pshuflw %s,", NameOfXMMRegister(regop));
2460 data += PrintRightXMMOperand(data);
2461 AppendToBuffer(",%d", Imm8(data));
2462 data++;
2463 } else {
2464 const char* mnem = "?";
2465 switch (b2) {
2466 case 0x2A:
2467 mnem = "cvtsi2sd";
2468 break;
2469 case 0x2C:
2470 mnem = "cvttsd2si";
2471 break;
2472 case 0x2D:
2473 mnem = "cvtsd2si";
2474 break;
2475 case 0x51:
2476 mnem = "sqrtsd";
2477 break;
2478 case 0x58:
2479 mnem = "addsd";
2480 break;
2481 case 0x59:
2482 mnem = "mulsd";
2483 break;
2484 case 0x5C:
2485 mnem = "subsd";
2486 break;
2487 case 0x5D:
2488 mnem = "minsd";
2489 break;
2490 case 0x5E:
2491 mnem = "divsd";
2492 break;
2493 case 0x5F:
2494 mnem = "maxsd";
2495 break;
2496 case 0x7C:
2497 mnem = "haddps";
2498 break;
2499 }
2500 data += 3;
2501 int mod, regop, rm;
2502 get_modrm(*data, &mod, ®op, &rm);
2503 if (b2 == 0x2A) {
2504 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2505 data += PrintRightOperand(data);
2506 } else if (b2 == 0x2C || b2 == 0x2D) {
2507 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2508 data += PrintRightXMMOperand(data);
2509 } else if (b2 == 0xC2) {
2510 // Intel manual 2A, Table 3-18.
2511 const char* const pseudo_op[] = {
2512 "cmpeqsd", "cmpltsd", "cmplesd", "cmpunordsd",
2513 "cmpneqsd", "cmpnltsd", "cmpnlesd", "cmpordsd"};
2514 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2515 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2516 data += 2;
2517 } else {
2518 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2519 data += PrintRightXMMOperand(data);
2520 }
2521 }
2522 } else {
2523 UnimplementedInstruction();
2524 }
2525 break;
2526
2527 case 0xF3:
2528 if (*(data + 1) == 0x0F) {
2529 byte b2 = *(data + 2);
2530 if (b2 == 0x11) {
2531 AppendToBuffer("movss ");
2532 data += 3;
2533 int mod, regop, rm;
2534 get_modrm(*data, &mod, ®op, &rm);
2535 data += PrintRightXMMOperand(data);
2536 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2537 } else if (b2 == 0x10) {
2538 data += 3;
2539 int mod, regop, rm;
2540 get_modrm(*data, &mod, ®op, &rm);
2541 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2542 data += PrintRightXMMOperand(data);
2543 } else if (b2 == 0x5A) {
2544 data += 3;
2545 int mod, regop, rm;
2546 get_modrm(*data, &mod, ®op, &rm);
2547 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2548 data += PrintRightXMMOperand(data);
2549 } else if (b2 == 0x6F) {
2550 data += 3;
2551 int mod, regop, rm;
2552 get_modrm(*data, &mod, ®op, &rm);
2553 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
2554 data += PrintRightXMMOperand(data);
2555 } else if (b2 == 0x70) {
2556 data += 3;
2557 int mod, regop, rm;
2558 get_modrm(*data, &mod, ®op, &rm);
2559 AppendToBuffer("pshufhw %s,", NameOfXMMRegister(regop));
2560 data += PrintRightXMMOperand(data);
2561 AppendToBuffer(",%d", Imm8(data));
2562 data++;
2563 } else if (b2 == 0x7F) {
2564 AppendToBuffer("movdqu ");
2565 data += 3;
2566 int mod, regop, rm;
2567 get_modrm(*data, &mod, ®op, &rm);
2568 data += PrintRightXMMOperand(data);
2569 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2570 } else if (b2 == 0xB8) {
2571 data += 3;
2572 int mod, regop, rm;
2573 get_modrm(*data, &mod, ®op, &rm);
2574 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2575 data += PrintRightOperand(data);
2576 } else if (b2 == 0xBC) {
2577 data += 3;
2578 int mod, regop, rm;
2579 get_modrm(*data, &mod, ®op, &rm);
2580 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2581 data += PrintRightOperand(data);
2582 } else if (b2 == 0xBD) {
2583 data += 3;
2584 int mod, regop, rm;
2585 get_modrm(*data, &mod, ®op, &rm);
2586 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2587 data += PrintRightOperand(data);
2588 } else {
2589 const char* mnem = "?";
2590 switch (b2) {
2591 case 0x2A:
2592 mnem = "cvtsi2ss";
2593 break;
2594 case 0x2C:
2595 mnem = "cvttss2si";
2596 break;
2597 case 0x2D:
2598 mnem = "cvtss2si";
2599 break;
2600 case 0x51:
2601 mnem = "sqrtss";
2602 break;
2603 case 0x58:
2604 mnem = "addss";
2605 break;
2606 case 0x59:
2607 mnem = "mulss";
2608 break;
2609 case 0x5B:
2610 mnem = "cvttps2dq";
2611 break;
2612 case 0x5C:
2613 mnem = "subss";
2614 break;
2615 case 0x5D:
2616 mnem = "minss";
2617 break;
2618 case 0x5E:
2619 mnem = "divss";
2620 break;
2621 case 0x5F:
2622 mnem = "maxss";
2623 break;
2624 case 0x7E:
2625 mnem = "movq";
2626 break;
2627 }
2628 data += 3;
2629 int mod, regop, rm;
2630 get_modrm(*data, &mod, ®op, &rm);
2631 if (b2 == 0x2A) {
2632 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2633 data += PrintRightOperand(data);
2634 } else if (b2 == 0x2C || b2 == 0x2D) {
2635 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2636 data += PrintRightXMMOperand(data);
2637 } else if (b2 == 0xC2) {
2638 // Intel manual 2A, Table 3-18.
2639 const char* const pseudo_op[] = {
2640 "cmpeqss", "cmpltss", "cmpless", "cmpunordss",
2641 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2642 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2643 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2644 data += 2;
2645 } else {
2646 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2647 data += PrintRightXMMOperand(data);
2648 }
2649 }
2650 } else if (*(data + 1) == 0xA5) {
2651 data += 2;
2652 AppendToBuffer("rep_movs");
2653 } else if (*(data + 1) == 0xAB) {
2654 data += 2;
2655 AppendToBuffer("rep_stos");
2656 } else if (*(data + 1) == 0x90) {
2657 data += 2;
2658 AppendToBuffer("pause");
2659 } else {
2660 UnimplementedInstruction();
2661 }
2662 break;
2663
2664 case 0xF7:
2665 data += F7Instruction(data);
2666 break;
2667
2668 default:
2669 UnimplementedInstruction();
2670 }
2671 }
2672
2673 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2674 tmp_buffer_[tmp_buffer_pos_] = '\0';
2675 }
2676
2677 int instr_len = data - instr;
2678 if (instr_len == 0) {
2679 printf("%02x", *data);
2680 }
2681 DCHECK_GT(instr_len, 0); // Ensure progress.
2682
2683 int outp = 0;
2684 // Instruction bytes.
2685 for (byte* bp = instr; bp < data; bp++) {
2686 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2687 }
2688 for (int i = 6 - instr_len; i >= 0; i--) {
2689 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
2690 }
2691
2692 outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin());
2693 return instr_len;
2694 } // NOLINT (function is too long)
2695
2696 //------------------------------------------------------------------------------
2697
2698 static const char* const cpu_regs[8] = {"eax", "ecx", "edx", "ebx",
2699 "esp", "ebp", "esi", "edi"};
2700
2701 static const char* const byte_cpu_regs[8] = {"al", "cl", "dl", "bl",
2702 "ah", "ch", "dh", "bh"};
2703
2704 static const char* const xmm_regs[8] = {"xmm0", "xmm1", "xmm2", "xmm3",
2705 "xmm4", "xmm5", "xmm6", "xmm7"};
2706
NameOfAddress(byte * addr) const2707 const char* NameConverter::NameOfAddress(byte* addr) const {
2708 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
2709 return tmp_buffer_.begin();
2710 }
2711
NameOfConstant(byte * addr) const2712 const char* NameConverter::NameOfConstant(byte* addr) const {
2713 return NameOfAddress(addr);
2714 }
2715
NameOfCPURegister(int reg) const2716 const char* NameConverter::NameOfCPURegister(int reg) const {
2717 if (0 <= reg && reg < 8) return cpu_regs[reg];
2718 return "noreg";
2719 }
2720
NameOfByteCPURegister(int reg) const2721 const char* NameConverter::NameOfByteCPURegister(int reg) const {
2722 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2723 return "noreg";
2724 }
2725
NameOfXMMRegister(int reg) const2726 const char* NameConverter::NameOfXMMRegister(int reg) const {
2727 if (0 <= reg && reg < 8) return xmm_regs[reg];
2728 return "noxmmreg";
2729 }
2730
NameInCode(byte * addr) const2731 const char* NameConverter::NameInCode(byte* addr) const {
2732 // IA32 does not embed debug strings at the moment.
2733 UNREACHABLE();
2734 }
2735
2736 //------------------------------------------------------------------------------
2737
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)2738 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2739 byte* instruction) {
2740 DisassemblerIA32 d(converter_, unimplemented_opcode_action());
2741 return d.InstructionDecode(buffer, instruction);
2742 }
2743
2744 // The IA-32 assembler does not currently use constant pools.
ConstantPoolSizeAt(byte * instruction)2745 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2746
2747 // static
Disassemble(FILE * f,byte * begin,byte * end,UnimplementedOpcodeAction unimplemented_action)2748 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end,
2749 UnimplementedOpcodeAction unimplemented_action) {
2750 NameConverter converter;
2751 Disassembler d(converter, unimplemented_action);
2752 for (byte* pc = begin; pc < end;) {
2753 v8::internal::EmbeddedVector<char, 128> buffer;
2754 buffer[0] = '\0';
2755 byte* prev_pc = pc;
2756 pc += d.InstructionDecode(buffer, pc);
2757 fprintf(f, "%p", static_cast<void*>(prev_pc));
2758 fprintf(f, " ");
2759
2760 for (byte* bp = prev_pc; bp < pc; bp++) {
2761 fprintf(f, "%02x", *bp);
2762 }
2763 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2764 fprintf(f, " ");
2765 }
2766 fprintf(f, " %s\n", buffer.begin());
2767 }
2768 }
2769
2770 } // namespace disasm
2771
2772 #endif // V8_TARGET_ARCH_IA32
2773