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 0x08:
795 AppendToBuffer("vroundps %s,", NameOfXMMRegister(regop));
796 current += PrintRightXMMOperand(current);
797 AppendToBuffer(",%d", Imm8_U(current));
798 current++;
799 break;
800 case 0x09:
801 AppendToBuffer("vroundpd %s,", NameOfXMMRegister(regop));
802 current += PrintRightXMMOperand(current);
803 AppendToBuffer(",%d", Imm8_U(current));
804 current++;
805 break;
806 case 0x0E:
807 AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop),
808 NameOfXMMRegister(vvvv));
809 current += PrintRightXMMOperand(current);
810 AppendToBuffer(",%d", Imm8_U(current));
811 current++;
812 break;
813 case 0x0F:
814 AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop),
815 NameOfXMMRegister(vvvv));
816 current += PrintRightXMMOperand(current);
817 AppendToBuffer(",%d", Imm8_U(current));
818 current++;
819 break;
820 case 0x14:
821 AppendToBuffer("vpextrb ");
822 current += PrintRightOperand(current);
823 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
824 current++;
825 break;
826 case 0x15:
827 AppendToBuffer("vpextrw ");
828 current += PrintRightOperand(current);
829 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
830 current++;
831 break;
832 case 0x16:
833 AppendToBuffer("vpextrd ");
834 current += PrintRightOperand(current);
835 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
836 current++;
837 break;
838 case 0x20:
839 AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
840 NameOfXMMRegister(vvvv));
841 current += PrintRightOperand(current);
842 AppendToBuffer(",%d", Imm8(current));
843 current++;
844 break;
845 case 0x21:
846 AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop),
847 NameOfXMMRegister(vvvv));
848 current += PrintRightXMMOperand(current);
849 AppendToBuffer(",%d", Imm8(current));
850 current++;
851 break;
852 case 0x22:
853 AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop),
854 NameOfXMMRegister(vvvv));
855 current += PrintRightOperand(current);
856 AppendToBuffer(",%d", Imm8(current));
857 current++;
858 break;
859 default:
860 UnimplementedInstruction();
861 }
862 } else if (vex_f2() && vex_0f()) {
863 int mod, regop, rm, vvvv = vex_vreg();
864 get_modrm(*current, &mod, ®op, &rm);
865 switch (opcode) {
866 case 0x12:
867 AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop));
868 current += PrintRightXMMOperand(current);
869 break;
870 case 0x51:
871 AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
872 NameOfXMMRegister(vvvv));
873 current += PrintRightXMMOperand(current);
874 break;
875 case 0x58:
876 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
877 NameOfXMMRegister(vvvv));
878 current += PrintRightXMMOperand(current);
879 break;
880 case 0x59:
881 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
882 NameOfXMMRegister(vvvv));
883 current += PrintRightXMMOperand(current);
884 break;
885 case 0x5C:
886 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
887 NameOfXMMRegister(vvvv));
888 current += PrintRightXMMOperand(current);
889 break;
890 case 0x5D:
891 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
892 NameOfXMMRegister(vvvv));
893 current += PrintRightXMMOperand(current);
894 break;
895 case 0x5E:
896 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
897 NameOfXMMRegister(vvvv));
898 current += PrintRightXMMOperand(current);
899 break;
900 case 0x5F:
901 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
902 NameOfXMMRegister(vvvv));
903 current += PrintRightXMMOperand(current);
904 break;
905 case 0x70:
906 AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop));
907 current += PrintRightXMMOperand(current);
908 AppendToBuffer(",%d", Imm8(current));
909 current++;
910 break;
911 case 0x7C:
912 AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop),
913 NameOfXMMRegister(vvvv));
914 current += PrintRightXMMOperand(current);
915 break;
916 default:
917 UnimplementedInstruction();
918 }
919 } else if (vex_f3() && vex_0f()) {
920 int mod, regop, rm, vvvv = vex_vreg();
921 get_modrm(*current, &mod, ®op, &rm);
922 switch (opcode) {
923 case 0x51:
924 AppendToBuffer("vsqrtss %s,%s,", NameOfXMMRegister(regop),
925 NameOfXMMRegister(vvvv));
926 current += PrintRightXMMOperand(current);
927 break;
928 case 0x58:
929 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
930 NameOfXMMRegister(vvvv));
931 current += PrintRightXMMOperand(current);
932 break;
933 case 0x59:
934 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
935 NameOfXMMRegister(vvvv));
936 current += PrintRightXMMOperand(current);
937 break;
938 case 0x5B:
939 AppendToBuffer("vcvttps2dq %s,", NameOfXMMRegister(regop));
940 current += PrintRightXMMOperand(current);
941 break;
942 case 0x5C:
943 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
944 NameOfXMMRegister(vvvv));
945 current += PrintRightXMMOperand(current);
946 break;
947 case 0x5D:
948 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
949 NameOfXMMRegister(vvvv));
950 current += PrintRightXMMOperand(current);
951 break;
952 case 0x5E:
953 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
954 NameOfXMMRegister(vvvv));
955 current += PrintRightXMMOperand(current);
956 break;
957 case 0x5F:
958 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
959 NameOfXMMRegister(vvvv));
960 current += PrintRightXMMOperand(current);
961 break;
962 case 0x6f:
963 AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop));
964 current += PrintRightOperand(current);
965 break;
966 case 0x70:
967 AppendToBuffer("vpshufhw %s,", NameOfXMMRegister(regop));
968 current += PrintRightXMMOperand(current);
969 AppendToBuffer(",%d", Imm8(current));
970 current++;
971 break;
972 case 0x7f:
973 AppendToBuffer("vmovdqu ");
974 current += PrintRightOperand(current);
975 AppendToBuffer(",%s", NameOfXMMRegister(regop));
976 break;
977 default:
978 UnimplementedInstruction();
979 }
980 } else if (vex_none() && vex_0f38()) {
981 int mod, regop, rm, vvvv = vex_vreg();
982 get_modrm(*current, &mod, ®op, &rm);
983 const char* mnem = "?";
984 switch (opcode) {
985 case 0xF2:
986 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
987 NameOfCPURegister(vvvv));
988 current += PrintRightOperand(current);
989 break;
990 case 0xF5:
991 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
992 current += PrintRightOperand(current);
993 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
994 break;
995 case 0xF7:
996 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
997 current += PrintRightOperand(current);
998 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
999 break;
1000 case 0xF3:
1001 switch (regop) {
1002 case 1:
1003 mnem = "blsr";
1004 break;
1005 case 2:
1006 mnem = "blsmsk";
1007 break;
1008 case 3:
1009 mnem = "blsi";
1010 break;
1011 default:
1012 UnimplementedInstruction();
1013 }
1014 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
1015 current += PrintRightOperand(current);
1016 mnem = "?";
1017 break;
1018 default:
1019 UnimplementedInstruction();
1020 }
1021 } else if (vex_f2() && vex_0f38()) {
1022 int mod, regop, rm, vvvv = vex_vreg();
1023 get_modrm(*current, &mod, ®op, &rm);
1024 switch (opcode) {
1025 case 0xF5:
1026 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
1027 NameOfCPURegister(vvvv));
1028 current += PrintRightOperand(current);
1029 break;
1030 case 0xF6:
1031 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
1032 NameOfCPURegister(vvvv));
1033 current += PrintRightOperand(current);
1034 break;
1035 case 0xF7:
1036 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
1037 current += PrintRightOperand(current);
1038 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1039 break;
1040 default:
1041 UnimplementedInstruction();
1042 }
1043 } else if (vex_f3() && vex_0f38()) {
1044 int mod, regop, rm, vvvv = vex_vreg();
1045 get_modrm(*current, &mod, ®op, &rm);
1046 switch (opcode) {
1047 case 0xF5:
1048 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
1049 NameOfCPURegister(vvvv));
1050 current += PrintRightOperand(current);
1051 break;
1052 case 0xF7:
1053 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
1054 current += PrintRightOperand(current);
1055 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1056 break;
1057 default:
1058 UnimplementedInstruction();
1059 }
1060 } else if (vex_f2() && vex_0f3a()) {
1061 int mod, regop, rm;
1062 get_modrm(*current, &mod, ®op, &rm);
1063 switch (opcode) {
1064 case 0xF0:
1065 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
1066 current += PrintRightOperand(current);
1067 AppendToBuffer(",%d", *current & 0x1F);
1068 current += 1;
1069 break;
1070 default:
1071 UnimplementedInstruction();
1072 }
1073 } else if (vex_none() && vex_0f()) {
1074 int mod, regop, rm, vvvv = vex_vreg();
1075 get_modrm(*current, &mod, ®op, &rm);
1076 switch (opcode) {
1077 case 0x10:
1078 AppendToBuffer("vmovups %s,", NameOfXMMRegister(regop));
1079 current += PrintRightXMMOperand(current);
1080 break;
1081 case 0x28:
1082 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1083 current += PrintRightXMMOperand(current);
1084 break;
1085 case 0x50:
1086 AppendToBuffer("vmovmskps %s,%s", NameOfCPURegister(regop),
1087 NameOfXMMRegister(rm));
1088 current++;
1089 break;
1090 case 0x51:
1091 AppendToBuffer("vsqrtps %s,", NameOfXMMRegister(regop));
1092 current += PrintRightXMMOperand(current);
1093 break;
1094 case 0x52:
1095 AppendToBuffer("vrsqrtps %s,", NameOfXMMRegister(regop));
1096 current += PrintRightXMMOperand(current);
1097 break;
1098 case 0x53:
1099 AppendToBuffer("vrcpps %s,", NameOfXMMRegister(regop));
1100 current += PrintRightXMMOperand(current);
1101 break;
1102 case 0x54:
1103 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1104 NameOfXMMRegister(vvvv));
1105 current += PrintRightXMMOperand(current);
1106 break;
1107 case 0x55:
1108 AppendToBuffer("vandnps %s,%s,", NameOfXMMRegister(regop),
1109 NameOfXMMRegister(vvvv));
1110 current += PrintRightXMMOperand(current);
1111 break;
1112 case 0x56:
1113 AppendToBuffer("vorps %s,%s,", NameOfXMMRegister(regop),
1114 NameOfXMMRegister(vvvv));
1115 current += PrintRightXMMOperand(current);
1116 break;
1117 case 0x57:
1118 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1119 NameOfXMMRegister(vvvv));
1120 current += PrintRightXMMOperand(current);
1121 break;
1122 case 0x58:
1123 AppendToBuffer("vaddps %s,%s,", NameOfXMMRegister(regop),
1124 NameOfXMMRegister(vvvv));
1125 current += PrintRightXMMOperand(current);
1126 break;
1127 case 0x59:
1128 AppendToBuffer("vmulps %s,%s,", NameOfXMMRegister(regop),
1129 NameOfXMMRegister(vvvv));
1130 current += PrintRightXMMOperand(current);
1131 break;
1132 case 0x5B:
1133 AppendToBuffer("vcvtdq2ps %s,", NameOfXMMRegister(regop));
1134 current += PrintRightXMMOperand(current);
1135 break;
1136 case 0x5C:
1137 AppendToBuffer("vsubps %s,%s,", NameOfXMMRegister(regop),
1138 NameOfXMMRegister(vvvv));
1139 current += PrintRightXMMOperand(current);
1140 break;
1141 case 0x5D:
1142 AppendToBuffer("vminps %s,%s,", NameOfXMMRegister(regop),
1143 NameOfXMMRegister(vvvv));
1144 current += PrintRightXMMOperand(current);
1145 break;
1146 case 0x5E:
1147 AppendToBuffer("vdivps %s,%s,", NameOfXMMRegister(regop),
1148 NameOfXMMRegister(vvvv));
1149 current += PrintRightXMMOperand(current);
1150 break;
1151 case 0x5F:
1152 AppendToBuffer("vmaxps %s,%s,", NameOfXMMRegister(regop),
1153 NameOfXMMRegister(vvvv));
1154 current += PrintRightXMMOperand(current);
1155 break;
1156 case 0xC2: {
1157 const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1158 "neq", "nlt", "nle", "ord"};
1159 AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1160 NameOfXMMRegister(vvvv));
1161 current += PrintRightXMMOperand(current);
1162 AppendToBuffer(", (%s)", pseudo_op[*current]);
1163 current++;
1164 break;
1165 }
1166 case 0xC6:
1167 AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop),
1168 NameOfXMMRegister(vvvv));
1169 current += PrintRightXMMOperand(current);
1170 AppendToBuffer(", %d", (*current) & 3);
1171 current += 1;
1172 break;
1173 default:
1174 UnimplementedInstruction();
1175 }
1176 } else if (vex_66() && vex_0f()) {
1177 int mod, regop, rm, vvvv = vex_vreg();
1178 get_modrm(*current, &mod, ®op, &rm);
1179 switch (opcode) {
1180 case 0x10:
1181 AppendToBuffer("vmovupd %s,", NameOfXMMRegister(regop));
1182 current += PrintRightXMMOperand(current);
1183 break;
1184 case 0x28:
1185 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1186 current += PrintRightXMMOperand(current);
1187 break;
1188 case 0x54:
1189 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1190 NameOfXMMRegister(vvvv));
1191 current += PrintRightXMMOperand(current);
1192 break;
1193 case 0x55:
1194 AppendToBuffer("vandnpd %s,%s,", NameOfXMMRegister(regop),
1195 NameOfXMMRegister(vvvv));
1196 current += PrintRightXMMOperand(current);
1197 break;
1198 case 0x56:
1199 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1200 NameOfXMMRegister(vvvv));
1201 current += PrintRightXMMOperand(current);
1202 break;
1203 case 0x57:
1204 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1205 NameOfXMMRegister(vvvv));
1206 current += PrintRightXMMOperand(current);
1207 break;
1208 case 0x58:
1209 AppendToBuffer("vaddpd %s,%s,", NameOfXMMRegister(regop),
1210 NameOfXMMRegister(vvvv));
1211 current += PrintRightXMMOperand(current);
1212 break;
1213 case 0x59:
1214 AppendToBuffer("vmulpd %s,%s,", NameOfXMMRegister(regop),
1215 NameOfXMMRegister(vvvv));
1216 current += PrintRightXMMOperand(current);
1217 break;
1218 case 0x5C:
1219 AppendToBuffer("vsubpd %s,%s,", NameOfXMMRegister(regop),
1220 NameOfXMMRegister(vvvv));
1221 current += PrintRightXMMOperand(current);
1222 break;
1223 case 0x5D:
1224 AppendToBuffer("vminpd %s,%s,", NameOfXMMRegister(regop),
1225 NameOfXMMRegister(vvvv));
1226 current += PrintRightXMMOperand(current);
1227 break;
1228 case 0x5E:
1229 AppendToBuffer("vdivpd %s,%s,", NameOfXMMRegister(regop),
1230 NameOfXMMRegister(vvvv));
1231 current += PrintRightXMMOperand(current);
1232 break;
1233 case 0x5F:
1234 AppendToBuffer("vmaxpd %s,%s,", NameOfXMMRegister(regop),
1235 NameOfXMMRegister(vvvv));
1236 current += PrintRightXMMOperand(current);
1237 break;
1238 case 0x6E:
1239 AppendToBuffer("vmovd %s,", NameOfXMMRegister(regop));
1240 current += PrintRightOperand(current);
1241 break;
1242 case 0x70:
1243 AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1244 current += PrintRightXMMOperand(current);
1245 AppendToBuffer(",%d", Imm8(current));
1246 current++;
1247 break;
1248 case 0x71:
1249 AppendToBuffer("vps%sw %s,%s", sf_str[regop / 2],
1250 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1251 current++;
1252 AppendToBuffer(",%u", *current++);
1253 break;
1254 case 0x72:
1255 AppendToBuffer("vps%sd %s,%s", sf_str[regop / 2],
1256 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1257 current++;
1258 AppendToBuffer(",%u", *current++);
1259 break;
1260 case 0x73:
1261 AppendToBuffer("vps%sq %s,%s", sf_str[regop / 2],
1262 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1263 current++;
1264 AppendToBuffer(",%u", *current++);
1265 break;
1266 case 0x7E:
1267 AppendToBuffer("vmovd ");
1268 current += PrintRightOperand(current);
1269 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1270 break;
1271 case 0xC2: {
1272 const char* const pseudo_op[] = {"eq", "lt", "le", "unord", "neq"};
1273 AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1274 NameOfXMMRegister(vvvv));
1275 current += PrintRightXMMOperand(current);
1276 AppendToBuffer(", (%s)", pseudo_op[*current]);
1277 current++;
1278 break;
1279 }
1280 case 0xC4:
1281 AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1282 NameOfXMMRegister(vvvv));
1283 current += PrintRightOperand(current);
1284 AppendToBuffer(",%d", Imm8(current));
1285 current++;
1286 break;
1287 case 0xC6:
1288 AppendToBuffer("vshufpd %s,%s,", NameOfXMMRegister(regop),
1289 NameOfXMMRegister(vvvv));
1290 current += PrintRightXMMOperand(current);
1291 AppendToBuffer(",%d", Imm8(current));
1292 current++;
1293 break;
1294 case 0xD7:
1295 AppendToBuffer("vpmovmskb %s,%s", NameOfCPURegister(regop),
1296 NameOfXMMRegister(rm));
1297 current++;
1298 break;
1299 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1300 case 0x##opcode: { \
1301 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
1302 NameOfXMMRegister(vvvv)); \
1303 current += PrintRightXMMOperand(current); \
1304 break; \
1305 }
1306
1307 SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1308 #undef DECLARE_SSE_AVX_DIS_CASE
1309 default:
1310 UnimplementedInstruction();
1311 }
1312 } else {
1313 UnimplementedInstruction();
1314 }
1315
1316 return static_cast<int>(current - data);
1317 }
1318
1319 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)1320 int DisassemblerIA32::FPUInstruction(byte* data) {
1321 byte escape_opcode = *data;
1322 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1323 byte modrm_byte = *(data + 1);
1324
1325 if (modrm_byte >= 0xC0) {
1326 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1327 } else {
1328 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
1329 }
1330 }
1331
MemoryFPUInstruction(int escape_opcode,int modrm_byte,byte * modrm_start)1332 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, int modrm_byte,
1333 byte* modrm_start) {
1334 const char* mnem = "?";
1335 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1336 switch (escape_opcode) {
1337 case 0xD9:
1338 switch (regop) {
1339 case 0:
1340 mnem = "fld_s";
1341 break;
1342 case 2:
1343 mnem = "fst_s";
1344 break;
1345 case 3:
1346 mnem = "fstp_s";
1347 break;
1348 case 7:
1349 mnem = "fstcw";
1350 break;
1351 default:
1352 UnimplementedInstruction();
1353 }
1354 break;
1355
1356 case 0xDB:
1357 switch (regop) {
1358 case 0:
1359 mnem = "fild_s";
1360 break;
1361 case 1:
1362 mnem = "fisttp_s";
1363 break;
1364 case 2:
1365 mnem = "fist_s";
1366 break;
1367 case 3:
1368 mnem = "fistp_s";
1369 break;
1370 default:
1371 UnimplementedInstruction();
1372 }
1373 break;
1374
1375 case 0xDD:
1376 switch (regop) {
1377 case 0:
1378 mnem = "fld_d";
1379 break;
1380 case 1:
1381 mnem = "fisttp_d";
1382 break;
1383 case 2:
1384 mnem = "fst_d";
1385 break;
1386 case 3:
1387 mnem = "fstp_d";
1388 break;
1389 default:
1390 UnimplementedInstruction();
1391 }
1392 break;
1393
1394 case 0xDF:
1395 switch (regop) {
1396 case 5:
1397 mnem = "fild_d";
1398 break;
1399 case 7:
1400 mnem = "fistp_d";
1401 break;
1402 default:
1403 UnimplementedInstruction();
1404 }
1405 break;
1406
1407 default:
1408 UnimplementedInstruction();
1409 }
1410 AppendToBuffer("%s ", mnem);
1411 int count = PrintRightOperand(modrm_start);
1412 return count + 1;
1413 }
1414
RegisterFPUInstruction(int escape_opcode,byte modrm_byte)1415 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1416 byte modrm_byte) {
1417 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1418 const char* mnem = "?";
1419
1420 switch (escape_opcode) {
1421 case 0xD8:
1422 has_register = true;
1423 switch (modrm_byte & 0xF8) {
1424 case 0xC0:
1425 mnem = "fadd_i";
1426 break;
1427 case 0xE0:
1428 mnem = "fsub_i";
1429 break;
1430 case 0xC8:
1431 mnem = "fmul_i";
1432 break;
1433 case 0xF0:
1434 mnem = "fdiv_i";
1435 break;
1436 default:
1437 UnimplementedInstruction();
1438 }
1439 break;
1440
1441 case 0xD9:
1442 switch (modrm_byte & 0xF8) {
1443 case 0xC0:
1444 mnem = "fld";
1445 has_register = true;
1446 break;
1447 case 0xC8:
1448 mnem = "fxch";
1449 has_register = true;
1450 break;
1451 default:
1452 switch (modrm_byte) {
1453 case 0xE0:
1454 mnem = "fchs";
1455 break;
1456 case 0xE1:
1457 mnem = "fabs";
1458 break;
1459 case 0xE4:
1460 mnem = "ftst";
1461 break;
1462 case 0xE8:
1463 mnem = "fld1";
1464 break;
1465 case 0xEB:
1466 mnem = "fldpi";
1467 break;
1468 case 0xED:
1469 mnem = "fldln2";
1470 break;
1471 case 0xEE:
1472 mnem = "fldz";
1473 break;
1474 case 0xF0:
1475 mnem = "f2xm1";
1476 break;
1477 case 0xF1:
1478 mnem = "fyl2x";
1479 break;
1480 case 0xF4:
1481 mnem = "fxtract";
1482 break;
1483 case 0xF5:
1484 mnem = "fprem1";
1485 break;
1486 case 0xF7:
1487 mnem = "fincstp";
1488 break;
1489 case 0xF8:
1490 mnem = "fprem";
1491 break;
1492 case 0xFC:
1493 mnem = "frndint";
1494 break;
1495 case 0xFD:
1496 mnem = "fscale";
1497 break;
1498 case 0xFE:
1499 mnem = "fsin";
1500 break;
1501 case 0xFF:
1502 mnem = "fcos";
1503 break;
1504 default:
1505 UnimplementedInstruction();
1506 }
1507 }
1508 break;
1509
1510 case 0xDA:
1511 if (modrm_byte == 0xE9) {
1512 mnem = "fucompp";
1513 } else {
1514 UnimplementedInstruction();
1515 }
1516 break;
1517
1518 case 0xDB:
1519 if ((modrm_byte & 0xF8) == 0xE8) {
1520 mnem = "fucomi";
1521 has_register = true;
1522 } else if (modrm_byte == 0xE2) {
1523 mnem = "fclex";
1524 } else if (modrm_byte == 0xE3) {
1525 mnem = "fninit";
1526 } else {
1527 UnimplementedInstruction();
1528 }
1529 break;
1530
1531 case 0xDC:
1532 has_register = true;
1533 switch (modrm_byte & 0xF8) {
1534 case 0xC0:
1535 mnem = "fadd";
1536 break;
1537 case 0xE8:
1538 mnem = "fsub";
1539 break;
1540 case 0xC8:
1541 mnem = "fmul";
1542 break;
1543 case 0xF8:
1544 mnem = "fdiv";
1545 break;
1546 default:
1547 UnimplementedInstruction();
1548 }
1549 break;
1550
1551 case 0xDD:
1552 has_register = true;
1553 switch (modrm_byte & 0xF8) {
1554 case 0xC0:
1555 mnem = "ffree";
1556 break;
1557 case 0xD0:
1558 mnem = "fst";
1559 break;
1560 case 0xD8:
1561 mnem = "fstp";
1562 break;
1563 default:
1564 UnimplementedInstruction();
1565 }
1566 break;
1567
1568 case 0xDE:
1569 if (modrm_byte == 0xD9) {
1570 mnem = "fcompp";
1571 } else {
1572 has_register = true;
1573 switch (modrm_byte & 0xF8) {
1574 case 0xC0:
1575 mnem = "faddp";
1576 break;
1577 case 0xE8:
1578 mnem = "fsubp";
1579 break;
1580 case 0xC8:
1581 mnem = "fmulp";
1582 break;
1583 case 0xF8:
1584 mnem = "fdivp";
1585 break;
1586 default:
1587 UnimplementedInstruction();
1588 }
1589 }
1590 break;
1591
1592 case 0xDF:
1593 if (modrm_byte == 0xE0) {
1594 mnem = "fnstsw_ax";
1595 } else if ((modrm_byte & 0xF8) == 0xE8) {
1596 mnem = "fucomip";
1597 has_register = true;
1598 }
1599 break;
1600
1601 default:
1602 UnimplementedInstruction();
1603 }
1604
1605 if (has_register) {
1606 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1607 } else {
1608 AppendToBuffer("%s", mnem);
1609 }
1610 return 2;
1611 }
1612
1613 // Mnemonics for instructions 0xF0 byte.
1614 // Returns nullptr if the instruction is not handled here.
F0Mnem(byte f0byte)1615 static const char* F0Mnem(byte f0byte) {
1616 switch (f0byte) {
1617 case 0x0B:
1618 return "ud2";
1619 case 0x18:
1620 return "prefetch";
1621 case 0xA2:
1622 return "cpuid";
1623 case 0xBE:
1624 return "movsx_b";
1625 case 0xBF:
1626 return "movsx_w";
1627 case 0xB6:
1628 return "movzx_b";
1629 case 0xB7:
1630 return "movzx_w";
1631 case 0xAF:
1632 return "imul";
1633 case 0xA4:
1634 return "shld";
1635 case 0xA5:
1636 return "shld";
1637 case 0xAD:
1638 return "shrd";
1639 case 0xAC:
1640 return "shrd"; // 3-operand version.
1641 case 0xAB:
1642 return "bts";
1643 case 0xB0:
1644 return "cmpxchg_b";
1645 case 0xB1:
1646 return "cmpxchg";
1647 case 0xBC:
1648 return "bsf";
1649 case 0xBD:
1650 return "bsr";
1651 case 0xC7:
1652 return "cmpxchg8b";
1653 default:
1654 return nullptr;
1655 }
1656 }
1657
1658 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
InstructionDecode(v8::internal::Vector<char> out_buffer,byte * instr)1659 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1660 byte* instr) {
1661 tmp_buffer_pos_ = 0; // starting to write as position 0
1662 byte* data = instr;
1663 // Check for hints.
1664 const char* branch_hint = nullptr;
1665 // We use these two prefixes only with branch prediction
1666 if (*data == 0x3E /*ds*/) {
1667 branch_hint = "predicted taken";
1668 data++;
1669 } else if (*data == 0x2E /*cs*/) {
1670 branch_hint = "predicted not taken";
1671 data++;
1672 } else if (*data == 0xC4 && *(data + 1) >= 0xC0) {
1673 vex_byte0_ = *data;
1674 vex_byte1_ = *(data + 1);
1675 vex_byte2_ = *(data + 2);
1676 data += 3;
1677 } else if (*data == 0xC5 && *(data + 1) >= 0xC0) {
1678 vex_byte0_ = *data;
1679 vex_byte1_ = *(data + 1);
1680 data += 2;
1681 } else if (*data == 0xF0 /*lock*/) {
1682 AppendToBuffer("lock ");
1683 data++;
1684 }
1685
1686 bool processed = true; // Will be set to false if the current instruction
1687 // is not in 'instructions' table.
1688 // Decode AVX instructions.
1689 if (vex_byte0_ != 0) {
1690 data += AVXInstruction(data);
1691 } else {
1692 const InstructionDesc& idesc = instruction_table_->Get(*data);
1693 switch (idesc.type) {
1694 case ZERO_OPERANDS_INSTR:
1695 AppendToBuffer("%s", idesc.mnem);
1696 data++;
1697 break;
1698
1699 case TWO_OPERANDS_INSTR:
1700 data++;
1701 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1702 break;
1703
1704 case JUMP_CONDITIONAL_SHORT_INSTR:
1705 data += JumpConditionalShort(data, branch_hint);
1706 break;
1707
1708 case REGISTER_INSTR:
1709 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1710 data++;
1711 break;
1712
1713 case MOVE_REG_INSTR: {
1714 byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1715 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1716 NameOfAddress(addr));
1717 data += 5;
1718 break;
1719 }
1720
1721 case CALL_JUMP_INSTR: {
1722 byte* addr = data + Imm32(data + 1) + 5;
1723 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1724 data += 5;
1725 break;
1726 }
1727
1728 case SHORT_IMMEDIATE_INSTR: {
1729 byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1730 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1731 data += 5;
1732 break;
1733 }
1734
1735 case BYTE_IMMEDIATE_INSTR: {
1736 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1737 data += 2;
1738 break;
1739 }
1740
1741 case NO_INSTR:
1742 processed = false;
1743 break;
1744
1745 default:
1746 UNIMPLEMENTED(); // This type is not implemented.
1747 }
1748 }
1749 //----------------------------
1750 if (!processed) {
1751 switch (*data) {
1752 case 0xC2:
1753 AppendToBuffer("ret 0x%x", Imm16_U(data + 1));
1754 data += 3;
1755 break;
1756
1757 case 0x6B: {
1758 data++;
1759 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1760 AppendToBuffer(",%d", *data);
1761 data++;
1762 } break;
1763
1764 case 0x69: {
1765 data++;
1766 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1767 AppendToBuffer(",%d", Imm32(data));
1768 data += 4;
1769 } break;
1770
1771 case 0xF6: {
1772 data++;
1773 int mod, regop, rm;
1774 get_modrm(*data, &mod, ®op, &rm);
1775 if (regop == eax) {
1776 AppendToBuffer("test_b ");
1777 data += PrintRightByteOperand(data);
1778 int32_t imm = *data;
1779 AppendToBuffer(",0x%x", imm);
1780 data++;
1781 } else {
1782 UnimplementedInstruction();
1783 }
1784 } break;
1785
1786 case 0x81: // fall through
1787 case 0x83: // 0x81 with sign extension bit set
1788 data += PrintImmediateOp(data);
1789 break;
1790
1791 case 0x0F: {
1792 byte f0byte = data[1];
1793 const char* f0mnem = F0Mnem(f0byte);
1794 if (f0byte == 0x18) {
1795 data += 2;
1796 int mod, regop, rm;
1797 get_modrm(*data, &mod, ®op, &rm);
1798 const char* suffix[] = {"nta", "1", "2", "3"};
1799 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1800 data += PrintRightOperand(data);
1801 } else if (f0byte == 0x1F && data[2] == 0) {
1802 AppendToBuffer("nop"); // 3 byte nop.
1803 data += 3;
1804 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1805 AppendToBuffer("nop"); // 4 byte nop.
1806 data += 4;
1807 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1808 data[4] == 0) {
1809 AppendToBuffer("nop"); // 5 byte nop.
1810 data += 5;
1811 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1812 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1813 AppendToBuffer("nop"); // 7 byte nop.
1814 data += 7;
1815 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1816 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1817 data[7] == 0) {
1818 AppendToBuffer("nop"); // 8 byte nop.
1819 data += 8;
1820 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1821 AppendToBuffer("%s", f0mnem);
1822 data += 2;
1823 } else if (f0byte == 0x28) {
1824 data += 2;
1825 int mod, regop, rm;
1826 get_modrm(*data, &mod, ®op, &rm);
1827 AppendToBuffer("movaps %s,%s", NameOfXMMRegister(regop),
1828 NameOfXMMRegister(rm));
1829 data++;
1830 } else if (f0byte == 0x10 || f0byte == 0x11) {
1831 data += 2;
1832 // movups xmm, xmm/m128
1833 // movups xmm/m128, xmm
1834 int mod, regop, rm;
1835 get_modrm(*data, &mod, ®op, &rm);
1836 AppendToBuffer("movups ");
1837 if (f0byte == 0x11) {
1838 data += PrintRightXMMOperand(data);
1839 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1840 } else {
1841 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1842 data += PrintRightXMMOperand(data);
1843 }
1844 } else if (f0byte == 0x2E) {
1845 data += 2;
1846 int mod, regop, rm;
1847 get_modrm(*data, &mod, ®op, &rm);
1848 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1849 data += PrintRightXMMOperand(data);
1850 } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1851 const char* const pseudo_op[] = {
1852 "sqrtps", "rsqrtps", "rcpps", "andps", "andnps",
1853 "orps", "xorps", "addps", "mulps", "cvtps2pd",
1854 "cvtdq2ps", "subps", "minps", "divps", "maxps",
1855 };
1856
1857 data += 2;
1858 int mod, regop, rm;
1859 get_modrm(*data, &mod, ®op, &rm);
1860 AppendToBuffer("%s %s,", pseudo_op[f0byte - 0x51],
1861 NameOfXMMRegister(regop));
1862 data += PrintRightXMMOperand(data);
1863 } else if (f0byte == 0x50) {
1864 data += 2;
1865 int mod, regop, rm;
1866 get_modrm(*data, &mod, ®op, &rm);
1867 AppendToBuffer("movmskps %s,%s", NameOfCPURegister(regop),
1868 NameOfXMMRegister(rm));
1869 data++;
1870 } else if (f0byte == 0xC0) {
1871 data += 2;
1872 data += PrintOperands("xadd_b", OPER_REG_OP_ORDER, data);
1873 } else if (f0byte == 0xC1) {
1874 data += 2;
1875 data += PrintOperands("xadd", OPER_REG_OP_ORDER, data);
1876 } else if (f0byte == 0xC2) {
1877 data += 2;
1878 int mod, regop, rm;
1879 get_modrm(*data, &mod, ®op, &rm);
1880 const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1881 "neq", "nlt", "nle", "ord"};
1882 AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
1883 data += PrintRightXMMOperand(data);
1884 AppendToBuffer(", (%s)", pseudo_op[*data]);
1885 data++;
1886 } else if (f0byte == 0xC6) {
1887 // shufps xmm, xmm/m128, imm8
1888 data += 2;
1889 int mod, regop, rm;
1890 get_modrm(*data, &mod, ®op, &rm);
1891 int8_t imm8 = static_cast<int8_t>(data[1]);
1892 AppendToBuffer("shufps %s,%s,%d", NameOfXMMRegister(rm),
1893 NameOfXMMRegister(regop), static_cast<int>(imm8));
1894 data += 2;
1895 } else if (f0byte >= 0xC8 && f0byte <= 0xCF) {
1896 // bswap
1897 data += 2;
1898 int reg = f0byte - 0xC8;
1899 AppendToBuffer("bswap %s", NameOfCPURegister(reg));
1900 } else if ((f0byte & 0xF0) == 0x80) {
1901 data += JumpConditional(data, branch_hint);
1902 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1903 f0byte == 0xB7 || f0byte == 0xAF) {
1904 data += 2;
1905 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1906 } else if ((f0byte & 0xF0) == 0x90) {
1907 data += SetCC(data);
1908 } else if ((f0byte & 0xF0) == 0x40) {
1909 data += CMov(data);
1910 } else if (f0byte == 0xA4 || f0byte == 0xAC) {
1911 // shld, shrd
1912 data += 2;
1913 AppendToBuffer("%s ", f0mnem);
1914 int mod, regop, rm;
1915 get_modrm(*data, &mod, ®op, &rm);
1916 int8_t imm8 = static_cast<int8_t>(data[1]);
1917 data += 2;
1918 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
1919 NameOfCPURegister(regop), static_cast<int>(imm8));
1920 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1921 // shrd_cl, shld_cl, bts
1922 data += 2;
1923 AppendToBuffer("%s ", f0mnem);
1924 int mod, regop, rm;
1925 get_modrm(*data, &mod, ®op, &rm);
1926 data += PrintRightOperand(data);
1927 if (f0byte == 0xAB) {
1928 AppendToBuffer(",%s", NameOfCPURegister(regop));
1929 } else {
1930 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1931 }
1932 } else if (f0byte == 0xB0) {
1933 // cmpxchg_b
1934 data += 2;
1935 AppendToBuffer("%s ", f0mnem);
1936 int mod, regop, rm;
1937 get_modrm(*data, &mod, ®op, &rm);
1938 data += PrintRightOperand(data);
1939 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1940 } else if (f0byte == 0xB1) {
1941 // cmpxchg
1942 data += 2;
1943 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
1944 } else if (f0byte == 0xBC) {
1945 data += 2;
1946 int mod, regop, rm;
1947 get_modrm(*data, &mod, ®op, &rm);
1948 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1949 data += PrintRightOperand(data);
1950 } else if (f0byte == 0xBD) {
1951 data += 2;
1952 int mod, regop, rm;
1953 get_modrm(*data, &mod, ®op, &rm);
1954 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1955 data += PrintRightOperand(data);
1956 } else if (f0byte == 0xC7) {
1957 // cmpxchg8b
1958 data += 2;
1959 AppendToBuffer("%s ", f0mnem);
1960 int mod, regop, rm;
1961 get_modrm(*data, &mod, ®op, &rm);
1962 data += PrintRightOperand(data);
1963 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xF0) {
1964 AppendToBuffer("mfence");
1965 data += 3;
1966 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xE8) {
1967 AppendToBuffer("lfence");
1968 data += 3;
1969 } else {
1970 UnimplementedInstruction();
1971 }
1972 } break;
1973
1974 case 0x8F: {
1975 data++;
1976 int mod, regop, rm;
1977 get_modrm(*data, &mod, ®op, &rm);
1978 if (regop == eax) {
1979 AppendToBuffer("pop ");
1980 data += PrintRightOperand(data);
1981 }
1982 } break;
1983
1984 case 0xFF: {
1985 data++;
1986 int mod, regop, rm;
1987 get_modrm(*data, &mod, ®op, &rm);
1988 const char* mnem = nullptr;
1989 switch (regop) {
1990 case esi:
1991 mnem = "push";
1992 break;
1993 case eax:
1994 mnem = "inc";
1995 break;
1996 case ecx:
1997 mnem = "dec";
1998 break;
1999 case edx:
2000 mnem = "call";
2001 break;
2002 case esp:
2003 mnem = "jmp";
2004 break;
2005 default:
2006 mnem = "???";
2007 }
2008 AppendToBuffer("%s ", mnem);
2009 data += PrintRightOperand(data);
2010 } break;
2011
2012 case 0xC7: // imm32, fall through
2013 case 0xC6: // imm8
2014 {
2015 bool is_byte = *data == 0xC6;
2016 data++;
2017 if (is_byte) {
2018 AppendToBuffer("%s ", "mov_b");
2019 data += PrintRightByteOperand(data);
2020 int32_t imm = *data;
2021 AppendToBuffer(",0x%x", imm);
2022 data++;
2023 } else {
2024 AppendToBuffer("%s ", "mov");
2025 data += PrintRightOperand(data);
2026 AppendToBuffer(",0x%x", Imm32(data));
2027 data += 4;
2028 }
2029 } break;
2030
2031 case 0x80: {
2032 data++;
2033 int mod, regop, rm;
2034 get_modrm(*data, &mod, ®op, &rm);
2035 const char* mnem = nullptr;
2036 switch (regop) {
2037 case 5:
2038 mnem = "subb";
2039 break;
2040 case 7:
2041 mnem = "cmpb";
2042 break;
2043 default:
2044 UnimplementedInstruction();
2045 }
2046 AppendToBuffer("%s ", mnem);
2047 data += PrintRightByteOperand(data);
2048 int32_t imm = *data;
2049 AppendToBuffer(",0x%x", imm);
2050 data++;
2051 } break;
2052
2053 case 0x88: // 8bit, fall through
2054 case 0x89: // 32bit
2055 {
2056 bool is_byte = *data == 0x88;
2057 int mod, regop, rm;
2058 data++;
2059 get_modrm(*data, &mod, ®op, &rm);
2060 if (is_byte) {
2061 AppendToBuffer("%s ", "mov_b");
2062 data += PrintRightByteOperand(data);
2063 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2064 } else {
2065 AppendToBuffer("%s ", "mov");
2066 data += PrintRightOperand(data);
2067 AppendToBuffer(",%s", NameOfCPURegister(regop));
2068 }
2069 } break;
2070
2071 case 0x66: // prefix
2072 while (*data == 0x66) data++;
2073 if (*data == 0xF && data[1] == 0x1F) {
2074 AppendToBuffer("nop"); // 0x66 prefix
2075 } else if (*data == 0x39) {
2076 data++;
2077 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data);
2078 } else if (*data == 0x3B) {
2079 data++;
2080 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data);
2081 } else if (*data == 0x81) {
2082 data++;
2083 AppendToBuffer("cmpw ");
2084 data += PrintRightOperand(data);
2085 AppendToBuffer(",0x%x", Imm16(data));
2086 data += 2;
2087 } else if (*data == 0x87) {
2088 data++;
2089 int mod, regop, rm;
2090 get_modrm(*data, &mod, ®op, &rm);
2091 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
2092 data += PrintRightOperand(data);
2093 } else if (*data == 0x89) {
2094 data++;
2095 int mod, regop, rm;
2096 get_modrm(*data, &mod, ®op, &rm);
2097 AppendToBuffer("mov_w ");
2098 data += PrintRightOperand(data);
2099 AppendToBuffer(",%s", NameOfCPURegister(regop));
2100 } else if (*data == 0x8B) {
2101 data++;
2102 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
2103 } else if (*data == 0x90) {
2104 AppendToBuffer("nop"); // 0x66 prefix
2105 } else if (*data == 0xC7) {
2106 data++;
2107 AppendToBuffer("%s ", "mov_w");
2108 data += PrintRightOperand(data);
2109 AppendToBuffer(",0x%x", Imm16(data));
2110 data += 2;
2111 } else if (*data == 0xF7) {
2112 data++;
2113 AppendToBuffer("%s ", "test_w");
2114 data += PrintRightOperand(data);
2115 AppendToBuffer(",0x%x", Imm16(data));
2116 data += 2;
2117 } else if (*data == 0x0F) {
2118 data++;
2119 if (*data == 0x10) {
2120 data++;
2121 int mod, regop, rm;
2122 get_modrm(*data, &mod, ®op, &rm);
2123 AppendToBuffer("movupd %s,", NameOfXMMRegister(regop));
2124 data += PrintRightXMMOperand(data);
2125 } else if (*data == 0x28) {
2126 data++;
2127 int mod, regop, rm;
2128 get_modrm(*data, &mod, ®op, &rm);
2129 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
2130 data += PrintRightXMMOperand(data);
2131 } else if (*data == 0x38) {
2132 data++;
2133 byte op = *data;
2134 data++;
2135 int mod, regop, rm;
2136 get_modrm(*data, &mod, ®op, &rm);
2137 switch (op) {
2138 #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
2139 case 0x##opcode: { \
2140 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2141 data += PrintRightXMMOperand(data); \
2142 break; \
2143 }
2144
2145 SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
2146 SSSE3_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
2147 SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
2148 SSE4_RM_INSTRUCTION_LIST(SSE34_DIS_CASE)
2149 #undef SSE34_DIS_CASE
2150 default:
2151 UnimplementedInstruction();
2152 }
2153 } else if (*data == 0x3A) {
2154 data++;
2155 if (*data >= 0x08 && *data <= 0x0B) {
2156 const char* const pseudo_op[] = {
2157 "roundps",
2158 "roundpd",
2159 "roundss",
2160 "roundsd",
2161 };
2162 byte op = *data;
2163 data++;
2164 int mod, regop, rm;
2165 get_modrm(*data, &mod, ®op, &rm);
2166 int8_t imm8 = static_cast<int8_t>(data[1]);
2167 AppendToBuffer("%s %s,%s,%d", pseudo_op[op - 0x08],
2168 NameOfXMMRegister(regop), NameOfXMMRegister(rm),
2169 static_cast<int>(imm8));
2170 data += 2;
2171 } else if (*data == 0x0E) {
2172 data++;
2173 int mod, regop, rm;
2174 get_modrm(*data, &mod, ®op, &rm);
2175 AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop));
2176 data += PrintRightXMMOperand(data);
2177 AppendToBuffer(",%d", Imm8_U(data));
2178 data++;
2179 } else if (*data == 0x0F) {
2180 data++;
2181 int mod, regop, rm;
2182 get_modrm(*data, &mod, ®op, &rm);
2183 AppendToBuffer("palignr %s,", NameOfXMMRegister(regop));
2184 data += PrintRightXMMOperand(data);
2185 AppendToBuffer(",%d", Imm8_U(data));
2186 data++;
2187 } else if (*data == 0x14) {
2188 data++;
2189 int mod, regop, rm;
2190 get_modrm(*data, &mod, ®op, &rm);
2191 AppendToBuffer("pextrb ");
2192 data += PrintRightOperand(data);
2193 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2194 data++;
2195 } else if (*data == 0x15) {
2196 data++;
2197 int mod, regop, rm;
2198 get_modrm(*data, &mod, ®op, &rm);
2199 AppendToBuffer("pextrw ");
2200 data += PrintRightOperand(data);
2201 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2202 data++;
2203 } else if (*data == 0x16) {
2204 data++;
2205 int mod, regop, rm;
2206 get_modrm(*data, &mod, ®op, &rm);
2207 AppendToBuffer("pextrd ");
2208 data += PrintRightOperand(data);
2209 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2210 data++;
2211 } else if (*data == 0x17) {
2212 data++;
2213 int mod, regop, rm;
2214 get_modrm(*data, &mod, ®op, &rm);
2215 int8_t imm8 = static_cast<int8_t>(data[1]);
2216 AppendToBuffer("extractps %s,%s,%d", NameOfCPURegister(rm),
2217 NameOfXMMRegister(regop), static_cast<int>(imm8));
2218 data += 2;
2219 } else if (*data == 0x20) {
2220 data++;
2221 int mod, regop, rm;
2222 get_modrm(*data, &mod, ®op, &rm);
2223 AppendToBuffer("pinsrb %s,", NameOfXMMRegister(regop));
2224 data += PrintRightOperand(data);
2225 AppendToBuffer(",%d", Imm8(data));
2226 data++;
2227 } else if (*data == 0x21) {
2228 data++;
2229 int mod, regop, rm;
2230 get_modrm(*data, &mod, ®op, &rm);
2231 AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
2232 data += PrintRightXMMOperand(data);
2233 AppendToBuffer(",%d", Imm8(data));
2234 data++;
2235 } else if (*data == 0x22) {
2236 data++;
2237 int mod, regop, rm;
2238 get_modrm(*data, &mod, ®op, &rm);
2239 AppendToBuffer("pinsrd %s,", NameOfXMMRegister(regop));
2240 data += PrintRightOperand(data);
2241 AppendToBuffer(",%d", Imm8(data));
2242 data++;
2243 } else {
2244 UnimplementedInstruction();
2245 }
2246 } else if (*data == 0x2E || *data == 0x2F) {
2247 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
2248 data++;
2249 int mod, regop, rm;
2250 get_modrm(*data, &mod, ®op, &rm);
2251 if (mod == 0x3) {
2252 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
2253 NameOfXMMRegister(rm));
2254 data++;
2255 } else {
2256 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2257 data += PrintRightOperand(data);
2258 }
2259 } else if (*data == 0x50) {
2260 data++;
2261 int mod, regop, rm;
2262 get_modrm(*data, &mod, ®op, &rm);
2263 AppendToBuffer("movmskpd %s,%s", NameOfCPURegister(regop),
2264 NameOfXMMRegister(rm));
2265 data++;
2266 } else if (*data >= 0x54 && *data <= 0x59) {
2267 const char* const pseudo_op[] = {
2268 "andpd", "andnpd", "orpd", "xorpd", "addpd", "mulpd",
2269 };
2270 byte op = *data;
2271 data++;
2272 int mod, regop, rm;
2273 get_modrm(*data, &mod, ®op, &rm);
2274 AppendToBuffer("%s %s,", pseudo_op[op - 0x54],
2275 NameOfXMMRegister(regop));
2276 data += PrintRightXMMOperand(data);
2277 } else if (*data >= 0x5c && *data <= 0x5f) {
2278 const char* const pseudo_op[] = {
2279 "subpd",
2280 "minpd",
2281 "divpd",
2282 "maxpd",
2283 };
2284 byte op = *data;
2285 data++;
2286 int mod, regop, rm;
2287 get_modrm(*data, &mod, ®op, &rm);
2288 AppendToBuffer("%s %s,", pseudo_op[op - 0x5c],
2289 NameOfXMMRegister(regop));
2290 data += PrintRightXMMOperand(data);
2291 } else if (*data == 0x6E) {
2292 data++;
2293 int mod, regop, rm;
2294 get_modrm(*data, &mod, ®op, &rm);
2295 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
2296 data += PrintRightOperand(data);
2297 } else if (*data == 0x6F) {
2298 data++;
2299 int mod, regop, rm;
2300 get_modrm(*data, &mod, ®op, &rm);
2301 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
2302 data += PrintRightXMMOperand(data);
2303 } else if (*data == 0x70) {
2304 data++;
2305 int mod, regop, rm;
2306 get_modrm(*data, &mod, ®op, &rm);
2307 AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
2308 data += PrintRightXMMOperand(data);
2309 AppendToBuffer(",%d", Imm8(data));
2310 data++;
2311 } else if (*data == 0x90) {
2312 data++;
2313 AppendToBuffer("nop"); // 2 byte nop.
2314 } else if (*data == 0x71) {
2315 data++;
2316 int mod, regop, rm;
2317 get_modrm(*data, &mod, ®op, &rm);
2318 int8_t imm8 = static_cast<int8_t>(data[1]);
2319 AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2],
2320 NameOfXMMRegister(rm), static_cast<int>(imm8));
2321 data += 2;
2322 } else if (*data == 0x72) {
2323 data++;
2324 int mod, regop, rm;
2325 get_modrm(*data, &mod, ®op, &rm);
2326 int8_t imm8 = static_cast<int8_t>(data[1]);
2327 AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2],
2328 NameOfXMMRegister(rm), static_cast<int>(imm8));
2329 data += 2;
2330 } else if (*data == 0x73) {
2331 data++;
2332 int mod, regop, rm;
2333 get_modrm(*data, &mod, ®op, &rm);
2334 int8_t imm8 = static_cast<int8_t>(data[1]);
2335 DCHECK(regop == esi || regop == edx);
2336 AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2],
2337 NameOfXMMRegister(rm), static_cast<int>(imm8));
2338 data += 2;
2339 } else if (*data == 0x7F) {
2340 AppendToBuffer("movdqa ");
2341 data++;
2342 int mod, regop, rm;
2343 get_modrm(*data, &mod, ®op, &rm);
2344 data += PrintRightXMMOperand(data);
2345 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2346 } else if (*data == 0x7E) {
2347 data++;
2348 int mod, regop, rm;
2349 get_modrm(*data, &mod, ®op, &rm);
2350 AppendToBuffer("movd ");
2351 data += PrintRightOperand(data);
2352 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2353 } else if (*data == 0xC1) {
2354 data += 2;
2355 data += PrintOperands("xadd_w", OPER_REG_OP_ORDER, data);
2356 } else if (*data == 0xC2) {
2357 data++;
2358 int mod, regop, rm;
2359 get_modrm(*data, &mod, ®op, &rm);
2360 const char* const pseudo_op[] = {"eq", "lt", "le", "unord", "neq"};
2361 AppendToBuffer("cmppd %s, ", NameOfXMMRegister(regop));
2362 data += PrintRightXMMOperand(data);
2363 AppendToBuffer(", (%s)", pseudo_op[*data]);
2364 data++;
2365 } else if (*data == 0xC4) {
2366 data++;
2367 int mod, regop, rm;
2368 get_modrm(*data, &mod, ®op, &rm);
2369 AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
2370 data += PrintRightOperand(data);
2371 AppendToBuffer(",%d", Imm8(data));
2372 data++;
2373 } else if (*data == 0xC6) {
2374 // shufpd xmm, xmm/m128, imm8
2375 data++;
2376 int mod, regop, rm;
2377 get_modrm(*data, &mod, ®op, &rm);
2378 AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
2379 data += PrintRightXMMOperand(data);
2380 AppendToBuffer(",%d", Imm8(data));
2381 data++;
2382 } else if (*data == 0xE7) {
2383 data++;
2384 int mod, regop, rm;
2385 get_modrm(*data, &mod, ®op, &rm);
2386 if (mod == 3) {
2387 // movntdq
2388 UnimplementedInstruction();
2389 } else {
2390 UnimplementedInstruction();
2391 }
2392 } else if (*data == 0xB1) {
2393 data++;
2394 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
2395 } else if (*data == 0xD7) {
2396 data++;
2397 int mod, regop, rm;
2398 get_modrm(*data, &mod, ®op, &rm);
2399 AppendToBuffer("pmovmskb %s,%s", NameOfCPURegister(regop),
2400 NameOfXMMRegister(rm));
2401 data++;
2402 } else {
2403 byte op = *data;
2404 data++;
2405 int mod, regop, rm;
2406 get_modrm(*data, &mod, ®op, &rm);
2407 switch (op) {
2408 #define SSE2_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
2409 case 0x##opcode: { \
2410 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2411 data += PrintRightXMMOperand(data); \
2412 break; \
2413 }
2414
2415 SSE2_INSTRUCTION_LIST(SSE2_DIS_CASE)
2416 #undef SSE2_DIS_CASE
2417 default:
2418 UnimplementedInstruction();
2419 }
2420 }
2421 } else {
2422 UnimplementedInstruction();
2423 }
2424 break;
2425
2426 case 0xFE: {
2427 data++;
2428 int mod, regop, rm;
2429 get_modrm(*data, &mod, ®op, &rm);
2430 if (regop == ecx) {
2431 AppendToBuffer("dec_b ");
2432 data += PrintRightOperand(data);
2433 } else {
2434 UnimplementedInstruction();
2435 }
2436 } break;
2437
2438 case 0x68:
2439 AppendToBuffer("push 0x%x", Imm32(data + 1));
2440 data += 5;
2441 break;
2442
2443 case 0x6A:
2444 AppendToBuffer("push 0x%x", Imm8(data + 1));
2445 data += 2;
2446 break;
2447
2448 case 0xA8:
2449 AppendToBuffer("test al,0x%x", Imm8_U(data + 1));
2450 data += 2;
2451 break;
2452
2453 case 0xA9:
2454 AppendToBuffer("test eax,0x%x", Imm32(data + 1));
2455 data += 5;
2456 break;
2457
2458 case 0xD1: // fall through
2459 case 0xD3: // fall through
2460 case 0xC1:
2461 data += D1D3C1Instruction(data);
2462 break;
2463
2464 case 0xD8: // fall through
2465 case 0xD9: // fall through
2466 case 0xDA: // fall through
2467 case 0xDB: // fall through
2468 case 0xDC: // fall through
2469 case 0xDD: // fall through
2470 case 0xDE: // fall through
2471 case 0xDF:
2472 data += FPUInstruction(data);
2473 break;
2474
2475 case 0xEB:
2476 data += JumpShort(data);
2477 break;
2478
2479 case 0xF2:
2480 if (*(data + 1) == 0x0F) {
2481 byte b2 = *(data + 2);
2482 if (b2 == 0x11) {
2483 AppendToBuffer("movsd ");
2484 data += 3;
2485 int mod, regop, rm;
2486 get_modrm(*data, &mod, ®op, &rm);
2487 data += PrintRightXMMOperand(data);
2488 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2489 } else if (b2 == 0x10) {
2490 data += 3;
2491 int mod, regop, rm;
2492 get_modrm(*data, &mod, ®op, &rm);
2493 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
2494 data += PrintRightXMMOperand(data);
2495 } else if (b2 == 0x12) {
2496 data += 3;
2497 int mod, regop, rm;
2498 get_modrm(*data, &mod, ®op, &rm);
2499 AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
2500 data += PrintRightXMMOperand(data);
2501 } else if (b2 == 0x5A) {
2502 data += 3;
2503 int mod, regop, rm;
2504 get_modrm(*data, &mod, ®op, &rm);
2505 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
2506 data += PrintRightXMMOperand(data);
2507 } else if (b2 == 0x70) {
2508 data += 3;
2509 int mod, regop, rm;
2510 get_modrm(*data, &mod, ®op, &rm);
2511 AppendToBuffer("pshuflw %s,", NameOfXMMRegister(regop));
2512 data += PrintRightXMMOperand(data);
2513 AppendToBuffer(",%d", Imm8(data));
2514 data++;
2515 } else {
2516 const char* mnem = "?";
2517 switch (b2) {
2518 case 0x2A:
2519 mnem = "cvtsi2sd";
2520 break;
2521 case 0x2C:
2522 mnem = "cvttsd2si";
2523 break;
2524 case 0x2D:
2525 mnem = "cvtsd2si";
2526 break;
2527 case 0x51:
2528 mnem = "sqrtsd";
2529 break;
2530 case 0x58:
2531 mnem = "addsd";
2532 break;
2533 case 0x59:
2534 mnem = "mulsd";
2535 break;
2536 case 0x5C:
2537 mnem = "subsd";
2538 break;
2539 case 0x5D:
2540 mnem = "minsd";
2541 break;
2542 case 0x5E:
2543 mnem = "divsd";
2544 break;
2545 case 0x5F:
2546 mnem = "maxsd";
2547 break;
2548 case 0x7C:
2549 mnem = "haddps";
2550 break;
2551 }
2552 data += 3;
2553 int mod, regop, rm;
2554 get_modrm(*data, &mod, ®op, &rm);
2555 if (b2 == 0x2A) {
2556 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2557 data += PrintRightOperand(data);
2558 } else if (b2 == 0x2C || b2 == 0x2D) {
2559 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2560 data += PrintRightXMMOperand(data);
2561 } else if (b2 == 0xC2) {
2562 // Intel manual 2A, Table 3-18.
2563 const char* const pseudo_op[] = {
2564 "cmpeqsd", "cmpltsd", "cmplesd", "cmpunordsd",
2565 "cmpneqsd", "cmpnltsd", "cmpnlesd", "cmpordsd"};
2566 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2567 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2568 data += 2;
2569 } else {
2570 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2571 data += PrintRightXMMOperand(data);
2572 }
2573 }
2574 } else {
2575 UnimplementedInstruction();
2576 }
2577 break;
2578
2579 case 0xF3:
2580 if (*(data + 1) == 0x0F) {
2581 byte b2 = *(data + 2);
2582 if (b2 == 0x11) {
2583 AppendToBuffer("movss ");
2584 data += 3;
2585 int mod, regop, rm;
2586 get_modrm(*data, &mod, ®op, &rm);
2587 data += PrintRightXMMOperand(data);
2588 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2589 } else if (b2 == 0x10) {
2590 data += 3;
2591 int mod, regop, rm;
2592 get_modrm(*data, &mod, ®op, &rm);
2593 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2594 data += PrintRightXMMOperand(data);
2595 } else if (b2 == 0x5A) {
2596 data += 3;
2597 int mod, regop, rm;
2598 get_modrm(*data, &mod, ®op, &rm);
2599 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2600 data += PrintRightXMMOperand(data);
2601 } else if (b2 == 0x6F) {
2602 data += 3;
2603 int mod, regop, rm;
2604 get_modrm(*data, &mod, ®op, &rm);
2605 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
2606 data += PrintRightXMMOperand(data);
2607 } else if (b2 == 0x70) {
2608 data += 3;
2609 int mod, regop, rm;
2610 get_modrm(*data, &mod, ®op, &rm);
2611 AppendToBuffer("pshufhw %s,", NameOfXMMRegister(regop));
2612 data += PrintRightXMMOperand(data);
2613 AppendToBuffer(",%d", Imm8(data));
2614 data++;
2615 } else if (b2 == 0x7F) {
2616 AppendToBuffer("movdqu ");
2617 data += 3;
2618 int mod, regop, rm;
2619 get_modrm(*data, &mod, ®op, &rm);
2620 data += PrintRightXMMOperand(data);
2621 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2622 } else if (b2 == 0xB8) {
2623 data += 3;
2624 int mod, regop, rm;
2625 get_modrm(*data, &mod, ®op, &rm);
2626 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2627 data += PrintRightOperand(data);
2628 } else if (b2 == 0xBC) {
2629 data += 3;
2630 int mod, regop, rm;
2631 get_modrm(*data, &mod, ®op, &rm);
2632 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2633 data += PrintRightOperand(data);
2634 } else if (b2 == 0xBD) {
2635 data += 3;
2636 int mod, regop, rm;
2637 get_modrm(*data, &mod, ®op, &rm);
2638 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2639 data += PrintRightOperand(data);
2640 } else {
2641 const char* mnem = "?";
2642 switch (b2) {
2643 case 0x2A:
2644 mnem = "cvtsi2ss";
2645 break;
2646 case 0x2C:
2647 mnem = "cvttss2si";
2648 break;
2649 case 0x2D:
2650 mnem = "cvtss2si";
2651 break;
2652 case 0x51:
2653 mnem = "sqrtss";
2654 break;
2655 case 0x58:
2656 mnem = "addss";
2657 break;
2658 case 0x59:
2659 mnem = "mulss";
2660 break;
2661 case 0x5B:
2662 mnem = "cvttps2dq";
2663 break;
2664 case 0x5C:
2665 mnem = "subss";
2666 break;
2667 case 0x5D:
2668 mnem = "minss";
2669 break;
2670 case 0x5E:
2671 mnem = "divss";
2672 break;
2673 case 0x5F:
2674 mnem = "maxss";
2675 break;
2676 case 0x7E:
2677 mnem = "movq";
2678 break;
2679 }
2680 data += 3;
2681 int mod, regop, rm;
2682 get_modrm(*data, &mod, ®op, &rm);
2683 if (b2 == 0x2A) {
2684 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2685 data += PrintRightOperand(data);
2686 } else if (b2 == 0x2C || b2 == 0x2D) {
2687 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2688 data += PrintRightXMMOperand(data);
2689 } else if (b2 == 0xC2) {
2690 // Intel manual 2A, Table 3-18.
2691 const char* const pseudo_op[] = {
2692 "cmpeqss", "cmpltss", "cmpless", "cmpunordss",
2693 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2694 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2695 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2696 data += 2;
2697 } else {
2698 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2699 data += PrintRightXMMOperand(data);
2700 }
2701 }
2702 } else if (*(data + 1) == 0xA5) {
2703 data += 2;
2704 AppendToBuffer("rep_movs");
2705 } else if (*(data + 1) == 0xAB) {
2706 data += 2;
2707 AppendToBuffer("rep_stos");
2708 } else if (*(data + 1) == 0x90) {
2709 data += 2;
2710 AppendToBuffer("pause");
2711 } else {
2712 UnimplementedInstruction();
2713 }
2714 break;
2715
2716 case 0xF7:
2717 data += F7Instruction(data);
2718 break;
2719
2720 default:
2721 UnimplementedInstruction();
2722 }
2723 }
2724
2725 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2726 tmp_buffer_[tmp_buffer_pos_] = '\0';
2727 }
2728
2729 int instr_len = data - instr;
2730 if (instr_len == 0) {
2731 printf("%02x", *data);
2732 }
2733 DCHECK_GT(instr_len, 0); // Ensure progress.
2734
2735 int outp = 0;
2736 // Instruction bytes.
2737 for (byte* bp = instr; bp < data; bp++) {
2738 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2739 }
2740 for (int i = 6 - instr_len; i >= 0; i--) {
2741 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
2742 }
2743
2744 outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin());
2745 return instr_len;
2746 } // NOLINT (function is too long)
2747
2748 //------------------------------------------------------------------------------
2749
2750 static const char* const cpu_regs[8] = {"eax", "ecx", "edx", "ebx",
2751 "esp", "ebp", "esi", "edi"};
2752
2753 static const char* const byte_cpu_regs[8] = {"al", "cl", "dl", "bl",
2754 "ah", "ch", "dh", "bh"};
2755
2756 static const char* const xmm_regs[8] = {"xmm0", "xmm1", "xmm2", "xmm3",
2757 "xmm4", "xmm5", "xmm6", "xmm7"};
2758
NameOfAddress(byte * addr) const2759 const char* NameConverter::NameOfAddress(byte* addr) const {
2760 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
2761 return tmp_buffer_.begin();
2762 }
2763
NameOfConstant(byte * addr) const2764 const char* NameConverter::NameOfConstant(byte* addr) const {
2765 return NameOfAddress(addr);
2766 }
2767
NameOfCPURegister(int reg) const2768 const char* NameConverter::NameOfCPURegister(int reg) const {
2769 if (0 <= reg && reg < 8) return cpu_regs[reg];
2770 return "noreg";
2771 }
2772
NameOfByteCPURegister(int reg) const2773 const char* NameConverter::NameOfByteCPURegister(int reg) const {
2774 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2775 return "noreg";
2776 }
2777
NameOfXMMRegister(int reg) const2778 const char* NameConverter::NameOfXMMRegister(int reg) const {
2779 if (0 <= reg && reg < 8) return xmm_regs[reg];
2780 return "noxmmreg";
2781 }
2782
NameInCode(byte * addr) const2783 const char* NameConverter::NameInCode(byte* addr) const {
2784 // IA32 does not embed debug strings at the moment.
2785 UNREACHABLE();
2786 }
2787
2788 //------------------------------------------------------------------------------
2789
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)2790 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2791 byte* instruction) {
2792 DisassemblerIA32 d(converter_, unimplemented_opcode_action());
2793 return d.InstructionDecode(buffer, instruction);
2794 }
2795
2796 // The IA-32 assembler does not currently use constant pools.
ConstantPoolSizeAt(byte * instruction)2797 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2798
2799 // static
Disassemble(FILE * f,byte * begin,byte * end,UnimplementedOpcodeAction unimplemented_action)2800 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end,
2801 UnimplementedOpcodeAction unimplemented_action) {
2802 NameConverter converter;
2803 Disassembler d(converter, unimplemented_action);
2804 for (byte* pc = begin; pc < end;) {
2805 v8::internal::EmbeddedVector<char, 128> buffer;
2806 buffer[0] = '\0';
2807 byte* prev_pc = pc;
2808 pc += d.InstructionDecode(buffer, pc);
2809 fprintf(f, "%p", static_cast<void*>(prev_pc));
2810 fprintf(f, " ");
2811
2812 for (byte* bp = prev_pc; bp < pc; bp++) {
2813 fprintf(f, "%02x", *bp);
2814 }
2815 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2816 fprintf(f, " ");
2817 }
2818 fprintf(f, " %s\n", buffer.begin());
2819 }
2820 }
2821
2822 } // namespace disasm
2823
2824 #endif // V8_TARGET_ARCH_IA32
2825