blob: be3530cb3d01f9d4a5328ef2a3f13b9534812a13 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
5#include <assert.h>
Steve Blocka7e24c12009-10-30 11:49:00 +00006#include <stdarg.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include <stdio.h>
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#if V8_TARGET_ARCH_IA32
Leon Clarkef7060e22010-06-03 12:02:55 +010010
Ben Murdochc5610432016-08-08 18:44:38 +010011#include "src/base/compiler-specific.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000013
14namespace disasm {
15
16enum OperandOrder {
17 UNSET_OP_ORDER = 0,
18 REG_OPER_OP_ORDER,
19 OPER_REG_OP_ORDER
20};
21
22
23//------------------------------------------------------------------
24// Tables
25//------------------------------------------------------------------
26struct ByteMnemonic {
27 int b; // -1 terminates, otherwise must be in range (0..255)
28 const char* mnem;
29 OperandOrder op_order_;
30};
31
Ben Murdoch69a99ed2011-11-30 16:03:39 +000032static const ByteMnemonic two_operands_instr[] = {
Ben Murdochc5610432016-08-08 18:44:38 +010033 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
34 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER},
35 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER},
36 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER},
37 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER},
38 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
39 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
40 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
41 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
42 {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER},
43 {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER},
44 {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER},
45 {-1, "", UNSET_OP_ORDER}};
Steve Blocka7e24c12009-10-30 11:49:00 +000046
Ben Murdoch69a99ed2011-11-30 16:03:39 +000047static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000048 {0xC3, "ret", UNSET_OP_ORDER},
49 {0xC9, "leave", UNSET_OP_ORDER},
50 {0x90, "nop", UNSET_OP_ORDER},
51 {0xF4, "hlt", UNSET_OP_ORDER},
52 {0xCC, "int3", UNSET_OP_ORDER},
53 {0x60, "pushad", UNSET_OP_ORDER},
54 {0x61, "popad", UNSET_OP_ORDER},
55 {0x9C, "pushfd", UNSET_OP_ORDER},
56 {0x9D, "popfd", UNSET_OP_ORDER},
57 {0x9E, "sahf", UNSET_OP_ORDER},
58 {0x99, "cdq", UNSET_OP_ORDER},
59 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010060 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010061 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000062 {-1, "", UNSET_OP_ORDER}
63};
64
65
Ben Murdoch69a99ed2011-11-30 16:03:39 +000066static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000067 {0xE8, "call", UNSET_OP_ORDER},
68 {0xE9, "jmp", UNSET_OP_ORDER},
69 {-1, "", UNSET_OP_ORDER}
70};
71
72
Ben Murdoch69a99ed2011-11-30 16:03:39 +000073static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000074 {0x05, "add", UNSET_OP_ORDER},
75 {0x0D, "or", UNSET_OP_ORDER},
76 {0x15, "adc", UNSET_OP_ORDER},
77 {0x25, "and", UNSET_OP_ORDER},
78 {0x2D, "sub", UNSET_OP_ORDER},
79 {0x35, "xor", UNSET_OP_ORDER},
80 {0x3D, "cmp", UNSET_OP_ORDER},
81 {-1, "", UNSET_OP_ORDER}
82};
83
84
Ben Murdoch3ef787d2012-04-12 10:51:47 +010085// Generally we don't want to generate these because they are subject to partial
86// register stalls. They are included for completeness and because the cmp
87// variant is used by the RecordWrite stub. Because it does not update the
88// register it is not subject to partial register stalls.
89static ByteMnemonic byte_immediate_instr[] = {
90 {0x0c, "or", UNSET_OP_ORDER},
91 {0x24, "and", UNSET_OP_ORDER},
92 {0x34, "xor", UNSET_OP_ORDER},
93 {0x3c, "cmp", UNSET_OP_ORDER},
94 {-1, "", UNSET_OP_ORDER}
95};
96
97
Ben Murdoch69a99ed2011-11-30 16:03:39 +000098static const char* const jump_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000099 /*0*/ "jo", "jno", "jc", "jnc",
100 /*4*/ "jz", "jnz", "jna", "ja",
101 /*8*/ "js", "jns", "jpe", "jpo",
102 /*12*/ "jl", "jnl", "jng", "jg"
103};
104
105
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000106static const char* const set_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000107 /*0*/ "seto", "setno", "setc", "setnc",
108 /*4*/ "setz", "setnz", "setna", "seta",
109 /*8*/ "sets", "setns", "setpe", "setpo",
110 /*12*/ "setl", "setnl", "setng", "setg"
111};
112
113
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000114static const char* const conditional_move_mnem[] = {
Steve Block3ce2e202009-11-05 08:53:23 +0000115 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
116 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
117 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
118 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
119};
120
121
Steve Blocka7e24c12009-10-30 11:49:00 +0000122enum InstructionType {
123 NO_INSTR,
124 ZERO_OPERANDS_INSTR,
125 TWO_OPERANDS_INSTR,
126 JUMP_CONDITIONAL_SHORT_INSTR,
127 REGISTER_INSTR,
128 MOVE_REG_INSTR,
129 CALL_JUMP_INSTR,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100130 SHORT_IMMEDIATE_INSTR,
131 BYTE_IMMEDIATE_INSTR
Steve Blocka7e24c12009-10-30 11:49:00 +0000132};
133
134
135struct InstructionDesc {
136 const char* mnem;
137 InstructionType type;
138 OperandOrder op_order_;
139};
140
141
142class InstructionTable {
143 public:
144 InstructionTable();
145 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100146 static InstructionTable* get_instance() {
147 static InstructionTable table;
148 return &table;
149 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000150
151 private:
152 InstructionDesc instructions_[256];
153 void Clear();
154 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000155 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 void SetTableRange(InstructionType type,
157 byte start,
158 byte end,
159 const char* mnem);
160 void AddJumpConditionalShort();
161};
162
163
164InstructionTable::InstructionTable() {
165 Clear();
166 Init();
167}
168
169
170void InstructionTable::Clear() {
171 for (int i = 0; i < 256; i++) {
172 instructions_[i].mnem = "";
173 instructions_[i].type = NO_INSTR;
174 instructions_[i].op_order_ = UNSET_OP_ORDER;
175 }
176}
177
178
179void InstructionTable::Init() {
180 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
181 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
182 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
183 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100184 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
Steve Blocka7e24c12009-10-30 11:49:00 +0000185 AddJumpConditionalShort();
186 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
187 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
188 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
189 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
190 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
191 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
192}
193
194
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000195void InstructionTable::CopyTable(const ByteMnemonic bm[],
196 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000197 for (int i = 0; bm[i].b >= 0; i++) {
198 InstructionDesc* id = &instructions_[bm[i].b];
199 id->mnem = bm[i].mnem;
200 id->op_order_ = bm[i].op_order_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000202 id->type = type;
203 }
204}
205
206
207void InstructionTable::SetTableRange(InstructionType type,
208 byte start,
209 byte end,
210 const char* mnem) {
211 for (byte b = start; b <= end; b++) {
212 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 id->mnem = mnem;
215 id->type = type;
216 }
217}
218
219
220void InstructionTable::AddJumpConditionalShort() {
221 for (byte b = 0x70; b <= 0x7F; b++) {
222 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 id->mnem = jump_conditional_mnem[b & 0x0F];
225 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
226 }
227}
228
229
Steve Blocka7e24c12009-10-30 11:49:00 +0000230// The IA32 disassembler implementation.
231class DisassemblerIA32 {
232 public:
233 DisassemblerIA32(const NameConverter& converter,
234 bool abort_on_unimplemented = true)
235 : converter_(converter),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400236 vex_byte0_(0),
237 vex_byte1_(0),
238 vex_byte2_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100239 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 tmp_buffer_pos_(0),
241 abort_on_unimplemented_(abort_on_unimplemented) {
242 tmp_buffer_[0] = '\0';
243 }
244
245 virtual ~DisassemblerIA32() {}
246
247 // Writes one disassembled instruction into 'buffer' (0-terminated).
248 // Returns the length of the disassembled machine instruction in bytes.
249 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
250
251 private:
252 const NameConverter& converter_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400253 byte vex_byte0_; // 0xc4 or 0xc5
254 byte vex_byte1_;
255 byte vex_byte2_; // only for 3 bytes vex prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100256 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
258 unsigned int tmp_buffer_pos_;
259 bool abort_on_unimplemented_;
260
Steve Blocka7e24c12009-10-30 11:49:00 +0000261 enum {
262 eax = 0,
263 ecx = 1,
264 edx = 2,
265 ebx = 3,
266 esp = 4,
267 ebp = 5,
268 esi = 6,
269 edi = 7
270 };
271
272
Steve Blockd0582a62009-12-15 09:54:21 +0000273 enum ShiftOpcodeExtension {
274 kROL = 0,
275 kROR = 1,
276 kRCL = 2,
277 kRCR = 3,
278 kSHL = 4,
279 KSHR = 5,
280 kSAR = 7
281 };
282
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400283 bool vex_128() {
284 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
285 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
Ben Murdochc5610432016-08-08 18:44:38 +0100286 return (checked & 4) == 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400287 }
288
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 bool vex_none() {
290 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
291 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
292 return (checked & 3) == 0;
293 }
294
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400295 bool vex_66() {
296 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
297 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
298 return (checked & 3) == 1;
299 }
300
301 bool vex_f3() {
302 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
303 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
304 return (checked & 3) == 2;
305 }
306
307 bool vex_f2() {
308 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
309 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
310 return (checked & 3) == 3;
311 }
312
313 bool vex_w() {
314 if (vex_byte0_ == 0xc5) return false;
315 return (vex_byte2_ & 0x80) != 0;
316 }
317
318 bool vex_0f() {
319 if (vex_byte0_ == 0xc5) return true;
320 return (vex_byte1_ & 3) == 1;
321 }
322
323 bool vex_0f38() {
324 if (vex_byte0_ == 0xc5) return false;
325 return (vex_byte1_ & 3) == 2;
326 }
327
328 bool vex_0f3a() {
329 if (vex_byte0_ == 0xc5) return false;
330 return (vex_byte1_ & 3) == 3;
331 }
332
333 int vex_vreg() {
334 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
335 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
336 return ~(checked >> 3) & 0xf;
337 }
338
339 char float_size_code() { return "sd"[vex_w()]; }
Steve Blockd0582a62009-12-15 09:54:21 +0000340
Steve Blocka7e24c12009-10-30 11:49:00 +0000341 const char* NameOfCPURegister(int reg) const {
342 return converter_.NameOfCPURegister(reg);
343 }
344
345
346 const char* NameOfByteCPURegister(int reg) const {
347 return converter_.NameOfByteCPURegister(reg);
348 }
349
350
351 const char* NameOfXMMRegister(int reg) const {
352 return converter_.NameOfXMMRegister(reg);
353 }
354
355
356 const char* NameOfAddress(byte* addr) const {
357 return converter_.NameOfAddress(addr);
358 }
359
360
361 // Disassembler helper functions.
362 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
363 *mod = (data >> 6) & 3;
364 *regop = (data & 0x38) >> 3;
365 *rm = data & 7;
366 }
367
368
369 static void get_sib(byte data, int* scale, int* index, int* base) {
370 *scale = (data >> 6) & 3;
371 *index = (data >> 3) & 7;
372 *base = data & 7;
373 }
374
375 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
376
377 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
378 int PrintRightOperand(byte* modrmp);
379 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100380 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000381 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
382 int PrintImmediateOp(byte* data);
383 int F7Instruction(byte* data);
384 int D1D3C1Instruction(byte* data);
385 int JumpShort(byte* data);
386 int JumpConditional(byte* data, const char* comment);
387 int JumpConditionalShort(byte* data, const char* comment);
388 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000389 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000390 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000391 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
392 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400393 int AVXInstruction(byte* data);
Ben Murdochc5610432016-08-08 18:44:38 +0100394 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
Steve Blocka7e24c12009-10-30 11:49:00 +0000395
396 void UnimplementedInstruction() {
397 if (abort_on_unimplemented_) {
398 UNIMPLEMENTED();
399 } else {
400 AppendToBuffer("'Unimplemented Instruction'");
401 }
402 }
403};
404
405
406void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
407 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
408 va_list args;
409 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000411 va_end(args);
412 tmp_buffer_pos_ += result;
413}
414
415int DisassemblerIA32::PrintRightOperandHelper(
416 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100417 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000418 int mod, regop, rm;
419 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100420 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
421 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 switch (mod) {
423 case 0:
424 if (rm == ebp) {
425 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
426 AppendToBuffer("[0x%x]", disp);
427 return 5;
428 } else if (rm == esp) {
429 byte sib = *(modrmp + 1);
430 int scale, index, base;
431 get_sib(sib, &scale, &index, &base);
432 if (index == esp && base == esp && scale == 0 /*times_1*/) {
433 AppendToBuffer("[%s]", (this->*register_name)(rm));
434 return 2;
435 } else if (base == ebp) {
436 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 AppendToBuffer("[%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000438 (this->*register_name)(index),
439 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 disp < 0 ? "-" : "+",
441 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 return 6;
443 } else if (index != esp && base != ebp) {
444 // [base+index*scale]
445 AppendToBuffer("[%s+%s*%d]",
446 (this->*register_name)(base),
447 (this->*register_name)(index),
448 1 << scale);
449 return 2;
450 } else {
451 UnimplementedInstruction();
452 return 1;
453 }
454 } else {
455 AppendToBuffer("[%s]", (this->*register_name)(rm));
456 return 1;
457 }
458 break;
459 case 1: // fall through
460 case 2:
461 if (rm == esp) {
462 byte sib = *(modrmp + 1);
463 int scale, index, base;
464 get_sib(sib, &scale, &index, &base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
466 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000467 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000468 AppendToBuffer("[%s%s0x%x]",
469 (this->*register_name)(rm),
470 disp < 0 ? "-" : "+",
471 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000472 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 AppendToBuffer("[%s+%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000474 (this->*register_name)(base),
475 (this->*register_name)(index),
476 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 disp < 0 ? "-" : "+",
478 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 }
480 return mod == 2 ? 6 : 3;
481 } else {
482 // No sib.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
484 : *reinterpret_cast<int8_t*>(modrmp + 1);
485 AppendToBuffer("[%s%s0x%x]",
486 (this->*register_name)(rm),
487 disp < 0 ? "-" : "+",
488 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 return mod == 2 ? 5 : 2;
490 }
491 break;
492 case 3:
493 AppendToBuffer("%s", (this->*register_name)(rm));
494 return 1;
495 default:
496 UnimplementedInstruction();
497 return 1;
498 }
499 UNREACHABLE();
500}
501
502
503int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
504 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
505}
506
507
508int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
509 return PrintRightOperandHelper(modrmp,
510 &DisassemblerIA32::NameOfByteCPURegister);
511}
512
513
Steve Block44f0eee2011-05-26 01:26:41 +0100514int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
515 return PrintRightOperandHelper(modrmp,
516 &DisassemblerIA32::NameOfXMMRegister);
517}
518
519
Steve Blocka7e24c12009-10-30 11:49:00 +0000520// Returns number of bytes used including the current *data.
521// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
522int DisassemblerIA32::PrintOperands(const char* mnem,
523 OperandOrder op_order,
524 byte* data) {
525 byte modrm = *data;
526 int mod, regop, rm;
527 get_modrm(modrm, &mod, &regop, &rm);
528 int advance = 0;
529 switch (op_order) {
530 case REG_OPER_OP_ORDER: {
531 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
532 advance = PrintRightOperand(data);
533 break;
534 }
535 case OPER_REG_OP_ORDER: {
536 AppendToBuffer("%s ", mnem);
537 advance = PrintRightOperand(data);
538 AppendToBuffer(",%s", NameOfCPURegister(regop));
539 break;
540 }
541 default:
542 UNREACHABLE();
543 break;
544 }
545 return advance;
546}
547
548
549// Returns number of bytes used by machine instruction, including *data byte.
550// Writes immediate instructions to 'tmp_buffer_'.
551int DisassemblerIA32::PrintImmediateOp(byte* data) {
552 bool sign_extension_bit = (*data & 0x02) != 0;
553 byte modrm = *(data+1);
554 int mod, regop, rm;
555 get_modrm(modrm, &mod, &regop, &rm);
556 const char* mnem = "Imm???";
557 switch (regop) {
558 case 0: mnem = "add"; break;
559 case 1: mnem = "or"; break;
560 case 2: mnem = "adc"; break;
561 case 4: mnem = "and"; break;
562 case 5: mnem = "sub"; break;
563 case 6: mnem = "xor"; break;
564 case 7: mnem = "cmp"; break;
565 default: UnimplementedInstruction();
566 }
567 AppendToBuffer("%s ", mnem);
568 int count = PrintRightOperand(data+1);
569 if (sign_extension_bit) {
570 AppendToBuffer(",0x%x", *(data + 1 + count));
571 return 1 + count + 1 /*int8*/;
572 } else {
573 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
574 return 1 + count + 4 /*int32_t*/;
575 }
576}
577
578
579// Returns number of bytes used, including *data.
580int DisassemblerIA32::F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581 DCHECK_EQ(0xF7, *data);
582 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 int mod, regop, rm;
584 get_modrm(modrm, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000585 const char* mnem = NULL;
586 switch (regop) {
587 case 0:
588 mnem = "test";
589 break;
590 case 2:
591 mnem = "not";
592 break;
593 case 3:
594 mnem = "neg";
595 break;
596 case 4:
597 mnem = "mul";
598 break;
599 case 5:
600 mnem = "imul";
601 break;
602 case 6:
603 mnem = "div";
604 break;
605 case 7:
606 mnem = "idiv";
607 break;
608 default:
609 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 AppendToBuffer("%s ", mnem);
612 int count = PrintRightOperand(data);
613 if (regop == 0) {
614 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
615 count += 4;
616 }
617 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000618}
619
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620
Steve Blocka7e24c12009-10-30 11:49:00 +0000621int DisassemblerIA32::D1D3C1Instruction(byte* data) {
622 byte op = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
624 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000625 int mod, regop, rm;
626 get_modrm(modrm, &mod, &regop, &rm);
627 int imm8 = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628 const char* mnem = NULL;
629 switch (regop) {
630 case kROL:
631 mnem = "rol";
632 break;
633 case kROR:
634 mnem = "ror";
635 break;
636 case kRCL:
637 mnem = "rcl";
638 break;
639 case kRCR:
640 mnem = "rcr";
641 break;
642 case kSHL:
643 mnem = "shl";
644 break;
645 case KSHR:
646 mnem = "shr";
647 break;
648 case kSAR:
649 mnem = "sar";
650 break;
651 default:
652 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000653 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000654 AppendToBuffer("%s ", mnem);
655 int count = PrintRightOperand(data);
656 if (op == 0xD1) {
657 imm8 = 1;
658 } else if (op == 0xC1) {
659 imm8 = *(data + 1);
660 count++;
661 } else if (op == 0xD3) {
662 // Shift/rotate by cl.
663 }
664 if (imm8 >= 0) {
665 AppendToBuffer(",%d", imm8);
666 } else {
667 AppendToBuffer(",cl");
668 }
669 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000670}
671
672
673// Returns number of bytes used, including *data.
674int DisassemblerIA32::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000675 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000676 byte b = *(data+1);
677 byte* dest = data + static_cast<int8_t>(b) + 2;
678 AppendToBuffer("jmp %s", NameOfAddress(dest));
679 return 2;
680}
681
682
683// Returns number of bytes used, including *data.
684int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 byte cond = *(data+1) & 0x0F;
687 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
688 const char* mnem = jump_conditional_mnem[cond];
689 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
690 if (comment != NULL) {
691 AppendToBuffer(", %s", comment);
692 }
693 return 6; // includes 0x0F
694}
695
696
697// Returns number of bytes used, including *data.
698int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
699 byte cond = *data & 0x0F;
700 byte b = *(data+1);
701 byte* dest = data + static_cast<int8_t>(b) + 2;
702 const char* mnem = jump_conditional_mnem[cond];
703 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
704 if (comment != NULL) {
705 AppendToBuffer(", %s", comment);
706 }
707 return 2;
708}
709
710
711// Returns number of bytes used, including *data.
712int DisassemblerIA32::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000714 byte cond = *(data+1) & 0x0F;
715 const char* mnem = set_conditional_mnem[cond];
716 AppendToBuffer("%s ", mnem);
717 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000718 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000719}
720
721
722// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000723int DisassemblerIA32::CMov(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 DCHECK_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000725 byte cond = *(data + 1) & 0x0F;
726 const char* mnem = conditional_move_mnem[cond];
727 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
728 return 2 + op_size; // includes 0x0F
729}
730
731
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400732int DisassemblerIA32::AVXInstruction(byte* data) {
733 byte opcode = *data;
734 byte* current = data + 1;
735 if (vex_66() && vex_0f38()) {
736 int mod, regop, rm, vvvv = vex_vreg();
737 get_modrm(*current, &mod, &regop, &rm);
738 switch (opcode) {
739 case 0x99:
740 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
741 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
742 current += PrintRightXMMOperand(current);
743 break;
744 case 0xa9:
745 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
746 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
747 current += PrintRightXMMOperand(current);
748 break;
749 case 0xb9:
750 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
751 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
752 current += PrintRightXMMOperand(current);
753 break;
754 case 0x9b:
755 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
756 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
757 current += PrintRightXMMOperand(current);
758 break;
759 case 0xab:
760 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
761 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
762 current += PrintRightXMMOperand(current);
763 break;
764 case 0xbb:
765 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
766 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
767 current += PrintRightXMMOperand(current);
768 break;
769 case 0x9d:
770 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
771 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
772 current += PrintRightXMMOperand(current);
773 break;
774 case 0xad:
775 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
776 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
777 current += PrintRightXMMOperand(current);
778 break;
779 case 0xbd:
780 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
781 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
782 current += PrintRightXMMOperand(current);
783 break;
784 case 0x9f:
785 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
786 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
787 current += PrintRightXMMOperand(current);
788 break;
789 case 0xaf:
790 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
791 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
792 current += PrintRightXMMOperand(current);
793 break;
794 case 0xbf:
795 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
796 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
797 current += PrintRightXMMOperand(current);
798 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000799 case 0xf7:
800 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
801 current += PrintRightOperand(current);
802 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
803 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400804 default:
805 UnimplementedInstruction();
806 }
807 } else if (vex_f2() && vex_0f()) {
808 int mod, regop, rm, vvvv = vex_vreg();
809 get_modrm(*current, &mod, &regop, &rm);
810 switch (opcode) {
811 case 0x58:
812 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
813 NameOfXMMRegister(vvvv));
814 current += PrintRightXMMOperand(current);
815 break;
816 case 0x59:
817 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
818 NameOfXMMRegister(vvvv));
819 current += PrintRightXMMOperand(current);
820 break;
821 case 0x5c:
822 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
823 NameOfXMMRegister(vvvv));
824 current += PrintRightXMMOperand(current);
825 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000826 case 0x5d:
827 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
828 NameOfXMMRegister(vvvv));
829 current += PrintRightXMMOperand(current);
830 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400831 case 0x5e:
832 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
833 NameOfXMMRegister(vvvv));
834 current += PrintRightXMMOperand(current);
835 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 case 0x5f:
837 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
838 NameOfXMMRegister(vvvv));
839 current += PrintRightXMMOperand(current);
840 break;
841 default:
842 UnimplementedInstruction();
843 }
844 } else if (vex_f3() && vex_0f()) {
845 int mod, regop, rm, vvvv = vex_vreg();
846 get_modrm(*current, &mod, &regop, &rm);
847 switch (opcode) {
848 case 0x58:
849 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
850 NameOfXMMRegister(vvvv));
851 current += PrintRightXMMOperand(current);
852 break;
853 case 0x59:
854 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
855 NameOfXMMRegister(vvvv));
856 current += PrintRightXMMOperand(current);
857 break;
858 case 0x5c:
859 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
860 NameOfXMMRegister(vvvv));
861 current += PrintRightXMMOperand(current);
862 break;
863 case 0x5d:
864 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
865 NameOfXMMRegister(vvvv));
866 current += PrintRightXMMOperand(current);
867 break;
868 case 0x5e:
869 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
870 NameOfXMMRegister(vvvv));
871 current += PrintRightXMMOperand(current);
872 break;
873 case 0x5f:
874 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
875 NameOfXMMRegister(vvvv));
876 current += PrintRightXMMOperand(current);
877 break;
878 default:
879 UnimplementedInstruction();
880 }
881 } else if (vex_none() && vex_0f38()) {
882 int mod, regop, rm, vvvv = vex_vreg();
883 get_modrm(*current, &mod, &regop, &rm);
884 const char* mnem = "?";
885 switch (opcode) {
886 case 0xf2:
887 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
888 NameOfCPURegister(vvvv));
889 current += PrintRightOperand(current);
890 break;
891 case 0xf5:
892 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
893 current += PrintRightOperand(current);
894 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
895 break;
896 case 0xf7:
897 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
898 current += PrintRightOperand(current);
899 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
900 break;
901 case 0xf3:
902 switch (regop) {
903 case 1:
904 mnem = "blsr";
905 break;
906 case 2:
907 mnem = "blsmsk";
908 break;
909 case 3:
910 mnem = "blsi";
911 break;
912 default:
913 UnimplementedInstruction();
914 }
915 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
916 current += PrintRightOperand(current);
917 mnem = "?";
918 break;
919 default:
920 UnimplementedInstruction();
921 }
922 } else if (vex_f2() && vex_0f38()) {
923 int mod, regop, rm, vvvv = vex_vreg();
924 get_modrm(*current, &mod, &regop, &rm);
925 switch (opcode) {
926 case 0xf5:
927 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
928 NameOfCPURegister(vvvv));
929 current += PrintRightOperand(current);
930 break;
931 case 0xf6:
932 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
933 NameOfCPURegister(vvvv));
934 current += PrintRightOperand(current);
935 break;
936 case 0xf7:
937 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
938 current += PrintRightOperand(current);
939 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
940 break;
941 default:
942 UnimplementedInstruction();
943 }
944 } else if (vex_f3() && vex_0f38()) {
945 int mod, regop, rm, vvvv = vex_vreg();
946 get_modrm(*current, &mod, &regop, &rm);
947 switch (opcode) {
948 case 0xf5:
949 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
950 NameOfCPURegister(vvvv));
951 current += PrintRightOperand(current);
952 break;
953 case 0xf7:
954 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
955 current += PrintRightOperand(current);
956 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
957 break;
958 default:
959 UnimplementedInstruction();
960 }
961 } else if (vex_f2() && vex_0f3a()) {
962 int mod, regop, rm;
963 get_modrm(*current, &mod, &regop, &rm);
964 switch (opcode) {
965 case 0xf0:
966 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
967 current += PrintRightOperand(current);
968 AppendToBuffer(",%d", *current & 0x1f);
969 current += 1;
970 break;
971 default:
972 UnimplementedInstruction();
973 }
974 } else if (vex_none() && vex_0f()) {
975 int mod, regop, rm, vvvv = vex_vreg();
976 get_modrm(*current, &mod, &regop, &rm);
977 switch (opcode) {
978 case 0x54:
979 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
980 NameOfXMMRegister(vvvv));
981 current += PrintRightXMMOperand(current);
982 break;
983 case 0x57:
984 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
985 NameOfXMMRegister(vvvv));
986 current += PrintRightXMMOperand(current);
987 break;
988 default:
989 UnimplementedInstruction();
990 }
991 } else if (vex_66() && vex_0f()) {
992 int mod, regop, rm, vvvv = vex_vreg();
993 get_modrm(*current, &mod, &regop, &rm);
994 switch (opcode) {
995 case 0x54:
996 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
997 NameOfXMMRegister(vvvv));
998 current += PrintRightXMMOperand(current);
999 break;
1000 case 0x57:
1001 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1002 NameOfXMMRegister(vvvv));
1003 current += PrintRightXMMOperand(current);
1004 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001005 default:
1006 UnimplementedInstruction();
1007 }
1008 } else {
1009 UnimplementedInstruction();
1010 }
1011
1012 return static_cast<int>(current - data);
1013}
1014
1015
Steve Block3ce2e202009-11-05 08:53:23 +00001016// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +00001017int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001018 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001019 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001020 byte modrm_byte = *(data+1);
1021
1022 if (modrm_byte >= 0xC0) {
1023 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1024 } else {
1025 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001026 }
Steve Blockd0582a62009-12-15 09:54:21 +00001027}
1028
1029int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
1030 int modrm_byte,
1031 byte* modrm_start) {
1032 const char* mnem = "?";
1033 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1034 switch (escape_opcode) {
1035 case 0xD9: switch (regop) {
1036 case 0: mnem = "fld_s"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001037 case 2: mnem = "fst_s"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001038 case 3: mnem = "fstp_s"; break;
1039 case 7: mnem = "fstcw"; break;
1040 default: UnimplementedInstruction();
1041 }
1042 break;
1043
1044 case 0xDB: switch (regop) {
1045 case 0: mnem = "fild_s"; break;
1046 case 1: mnem = "fisttp_s"; break;
1047 case 2: mnem = "fist_s"; break;
1048 case 3: mnem = "fistp_s"; break;
1049 default: UnimplementedInstruction();
1050 }
1051 break;
1052
1053 case 0xDD: switch (regop) {
1054 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001055 case 1: mnem = "fisttp_d"; break;
1056 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001057 case 3: mnem = "fstp_d"; break;
1058 default: UnimplementedInstruction();
1059 }
1060 break;
1061
1062 case 0xDF: switch (regop) {
1063 case 5: mnem = "fild_d"; break;
1064 case 7: mnem = "fistp_d"; break;
1065 default: UnimplementedInstruction();
1066 }
1067 break;
1068
1069 default: UnimplementedInstruction();
1070 }
1071 AppendToBuffer("%s ", mnem);
1072 int count = PrintRightOperand(modrm_start);
1073 return count + 1;
1074}
1075
1076int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1077 byte modrm_byte) {
1078 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1079 const char* mnem = "?";
1080
1081 switch (escape_opcode) {
1082 case 0xD8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001083 has_register = true;
1084 switch (modrm_byte & 0xF8) {
1085 case 0xC0: mnem = "fadd_i"; break;
1086 case 0xE0: mnem = "fsub_i"; break;
1087 case 0xC8: mnem = "fmul_i"; break;
1088 case 0xF0: mnem = "fdiv_i"; break;
1089 default: UnimplementedInstruction();
1090 }
Steve Blockd0582a62009-12-15 09:54:21 +00001091 break;
1092
1093 case 0xD9:
1094 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001095 case 0xC0:
1096 mnem = "fld";
1097 has_register = true;
1098 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001099 case 0xC8:
1100 mnem = "fxch";
1101 has_register = true;
1102 break;
1103 default:
1104 switch (modrm_byte) {
1105 case 0xE0: mnem = "fchs"; break;
1106 case 0xE1: mnem = "fabs"; break;
1107 case 0xE4: mnem = "ftst"; break;
1108 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001109 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001110 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001111 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001112 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001113 case 0xF1: mnem = "fyl2x"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001114 case 0xF4: mnem = "fxtract"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001115 case 0xF5: mnem = "fprem1"; break;
1116 case 0xF7: mnem = "fincstp"; break;
1117 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001118 case 0xFC: mnem = "frndint"; break;
1119 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001120 case 0xFE: mnem = "fsin"; break;
1121 case 0xFF: mnem = "fcos"; break;
1122 default: UnimplementedInstruction();
1123 }
1124 }
1125 break;
1126
1127 case 0xDA:
1128 if (modrm_byte == 0xE9) {
1129 mnem = "fucompp";
1130 } else {
1131 UnimplementedInstruction();
1132 }
1133 break;
1134
1135 case 0xDB:
1136 if ((modrm_byte & 0xF8) == 0xE8) {
1137 mnem = "fucomi";
1138 has_register = true;
1139 } else if (modrm_byte == 0xE2) {
1140 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001141 } else if (modrm_byte == 0xE3) {
1142 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001143 } else {
1144 UnimplementedInstruction();
1145 }
1146 break;
1147
1148 case 0xDC:
1149 has_register = true;
1150 switch (modrm_byte & 0xF8) {
1151 case 0xC0: mnem = "fadd"; break;
1152 case 0xE8: mnem = "fsub"; break;
1153 case 0xC8: mnem = "fmul"; break;
1154 case 0xF8: mnem = "fdiv"; break;
1155 default: UnimplementedInstruction();
1156 }
1157 break;
1158
1159 case 0xDD:
1160 has_register = true;
1161 switch (modrm_byte & 0xF8) {
1162 case 0xC0: mnem = "ffree"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001163 case 0xD0: mnem = "fst"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001164 case 0xD8: mnem = "fstp"; break;
1165 default: UnimplementedInstruction();
1166 }
1167 break;
1168
1169 case 0xDE:
1170 if (modrm_byte == 0xD9) {
1171 mnem = "fcompp";
1172 } else {
1173 has_register = true;
1174 switch (modrm_byte & 0xF8) {
1175 case 0xC0: mnem = "faddp"; break;
1176 case 0xE8: mnem = "fsubp"; break;
1177 case 0xC8: mnem = "fmulp"; break;
1178 case 0xF8: mnem = "fdivp"; break;
1179 default: UnimplementedInstruction();
1180 }
1181 }
1182 break;
1183
1184 case 0xDF:
1185 if (modrm_byte == 0xE0) {
1186 mnem = "fnstsw_ax";
1187 } else if ((modrm_byte & 0xF8) == 0xE8) {
1188 mnem = "fucomip";
1189 has_register = true;
1190 }
1191 break;
1192
1193 default: UnimplementedInstruction();
1194 }
1195
1196 if (has_register) {
1197 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1198 } else {
1199 AppendToBuffer("%s", mnem);
1200 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001201 return 2;
1202}
1203
1204
1205// Mnemonics for instructions 0xF0 byte.
1206// Returns NULL if the instruction is not handled here.
1207static const char* F0Mnem(byte f0byte) {
1208 switch (f0byte) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001209 case 0x0B:
1210 return "ud2";
Ben Murdochda12d292016-06-02 14:46:10 +01001211 case 0x18:
1212 return "prefetch";
1213 case 0xA2:
1214 return "cpuid";
1215 case 0xBE:
1216 return "movsx_b";
1217 case 0xBF:
1218 return "movsx_w";
1219 case 0xB6:
1220 return "movzx_b";
1221 case 0xB7:
1222 return "movzx_w";
1223 case 0xAF:
1224 return "imul";
1225 case 0xA4:
1226 return "shld";
1227 case 0xA5:
1228 return "shld";
1229 case 0xAD:
1230 return "shrd";
1231 case 0xAC:
1232 return "shrd"; // 3-operand version.
1233 case 0xAB:
1234 return "bts";
Ben Murdoch61f157c2016-09-16 13:49:30 +01001235 case 0xB0:
1236 return "cmpxchg_b";
1237 case 0xB1:
1238 return "cmpxchg";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239 case 0xBC:
1240 return "bsf";
Ben Murdochda12d292016-06-02 14:46:10 +01001241 case 0xBD:
1242 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 default: return NULL;
1244 }
1245}
1246
1247
1248// Disassembled instruction '*instr' and writes it into 'out_buffer'.
1249int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1250 byte* instr) {
1251 tmp_buffer_pos_ = 0; // starting to write as position 0
1252 byte* data = instr;
1253 // Check for hints.
1254 const char* branch_hint = NULL;
1255 // We use these two prefixes only with branch prediction
1256 if (*data == 0x3E /*ds*/) {
1257 branch_hint = "predicted taken";
1258 data++;
1259 } else if (*data == 0x2E /*cs*/) {
1260 branch_hint = "predicted not taken";
1261 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001262 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1263 vex_byte0_ = *data;
1264 vex_byte1_ = *(data + 1);
1265 vex_byte2_ = *(data + 2);
1266 data += 3;
1267 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1268 vex_byte0_ = *data;
1269 vex_byte1_ = *(data + 1);
1270 data += 2;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001271 } else if (*data == 0xF0 /*lock*/) {
1272 AppendToBuffer("lock ");
1273 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001275
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 bool processed = true; // Will be set to false if the current instruction
1277 // is not in 'instructions' table.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278 // Decode AVX instructions.
1279 if (vex_byte0_ != 0) {
1280 data += AVXInstruction(data);
1281 } else {
1282 const InstructionDesc& idesc = instruction_table_->Get(*data);
1283 switch (idesc.type) {
1284 case ZERO_OPERANDS_INSTR:
Ben Murdochc5610432016-08-08 18:44:38 +01001285 AppendToBuffer("%s", idesc.mnem);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001286 data++;
1287 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001288
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001289 case TWO_OPERANDS_INSTR:
1290 data++;
1291 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1292 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001293
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001294 case JUMP_CONDITIONAL_SHORT_INSTR:
1295 data += JumpConditionalShort(data, branch_hint);
1296 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001297
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001298 case REGISTER_INSTR:
1299 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1300 data++;
1301 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001302
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001303 case MOVE_REG_INSTR: {
1304 byte* addr =
1305 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1306 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1307 NameOfAddress(addr));
1308 data += 5;
1309 break;
1310 }
1311
1312 case CALL_JUMP_INSTR: {
1313 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1314 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1315 data += 5;
1316 break;
1317 }
1318
1319 case SHORT_IMMEDIATE_INSTR: {
1320 byte* addr =
1321 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1322 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1323 data += 5;
1324 break;
1325 }
1326
1327 case BYTE_IMMEDIATE_INSTR: {
1328 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1329 data += 2;
1330 break;
1331 }
1332
1333 case NO_INSTR:
1334 processed = false;
1335 break;
1336
1337 default:
1338 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00001339 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001340 }
1341 //----------------------------
1342 if (!processed) {
1343 switch (*data) {
1344 case 0xC2:
1345 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1346 data += 3;
1347 break;
1348
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 case 0x6B: {
1350 data++;
1351 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1352 AppendToBuffer(",%d", *data);
1353 data++;
1354 } break;
1355
1356 case 0x69: {
1357 data++;
1358 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1359 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1360 data += 4;
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 }
1362 break;
1363
1364 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001365 { data++;
1366 int mod, regop, rm;
1367 get_modrm(*data, &mod, &regop, &rm);
1368 if (regop == eax) {
1369 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +01001370 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001371 int32_t imm = *data;
1372 AppendToBuffer(",0x%x", imm);
1373 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001374 } else {
1375 UnimplementedInstruction();
1376 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001377 }
1378 break;
1379
1380 case 0x81: // fall through
1381 case 0x83: // 0x81 with sign extension bit set
1382 data += PrintImmediateOp(data);
1383 break;
1384
1385 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001386 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +00001387 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001388 if (f0byte == 0x18) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389 data += 2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001390 int mod, regop, rm;
1391 get_modrm(*data, &mod, &regop, &rm);
1392 const char* suffix[] = {"nta", "1", "2", "3"};
1393 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1394 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001395 } else if (f0byte == 0x1F && data[2] == 0) {
1396 AppendToBuffer("nop"); // 3 byte nop.
1397 data += 3;
1398 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1399 AppendToBuffer("nop"); // 4 byte nop.
1400 data += 4;
1401 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1402 data[4] == 0) {
1403 AppendToBuffer("nop"); // 5 byte nop.
1404 data += 5;
1405 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1406 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1407 AppendToBuffer("nop"); // 7 byte nop.
1408 data += 7;
1409 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1410 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1411 data[7] == 0) {
1412 AppendToBuffer("nop"); // 8 byte nop.
1413 data += 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001414 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001415 AppendToBuffer("%s", f0mnem);
1416 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001417 } else if (f0byte == 0x28) {
1418 data += 2;
1419 int mod, regop, rm;
1420 get_modrm(*data, &mod, &regop, &rm);
1421 AppendToBuffer("movaps %s,%s",
1422 NameOfXMMRegister(regop),
1423 NameOfXMMRegister(rm));
1424 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001425 } else if (f0byte == 0x2e) {
1426 data += 2;
1427 int mod, regop, rm;
1428 get_modrm(*data, &mod, &regop, &rm);
1429 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1430 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001431 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1432 const char* const pseudo_op[] = {
1433 "rcpps",
1434 "andps",
1435 "andnps",
1436 "orps",
1437 "xorps",
1438 "addps",
1439 "mulps",
1440 "cvtps2pd",
1441 "cvtdq2ps",
1442 "subps",
1443 "minps",
1444 "divps",
1445 "maxps",
1446 };
1447
Ben Murdoch257744e2011-11-30 15:57:28 +00001448 data += 2;
1449 int mod, regop, rm;
1450 get_modrm(*data, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451 AppendToBuffer("%s %s,",
1452 pseudo_op[f0byte - 0x53],
1453 NameOfXMMRegister(regop));
1454 data += PrintRightXMMOperand(data);
1455 } else if (f0byte == 0x50) {
1456 data += 2;
1457 int mod, regop, rm;
1458 get_modrm(*data, &mod, &regop, &rm);
1459 AppendToBuffer("movmskps %s,%s",
1460 NameOfCPURegister(regop),
Ben Murdoch257744e2011-11-30 15:57:28 +00001461 NameOfXMMRegister(rm));
1462 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463 } else if (f0byte== 0xC6) {
1464 // shufps xmm, xmm/m128, imm8
1465 data += 2;
1466 int mod, regop, rm;
1467 get_modrm(*data, &mod, &regop, &rm);
1468 int8_t imm8 = static_cast<int8_t>(data[1]);
1469 AppendToBuffer("shufps %s,%s,%d",
1470 NameOfXMMRegister(rm),
1471 NameOfXMMRegister(regop),
1472 static_cast<int>(imm8));
1473 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001474 } else if ((f0byte & 0xF0) == 0x80) {
1475 data += JumpConditional(data, branch_hint);
1476 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1477 f0byte == 0xB7 || f0byte == 0xAF) {
1478 data += 2;
1479 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1480 } else if ((f0byte & 0xF0) == 0x90) {
1481 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001482 } else if ((f0byte & 0xF0) == 0x40) {
1483 data += CMov(data);
Ben Murdochda12d292016-06-02 14:46:10 +01001484 } else if (f0byte == 0xA4 || f0byte == 0xAC) {
1485 // shld, shrd
1486 data += 2;
1487 AppendToBuffer("%s ", f0mnem);
1488 int mod, regop, rm;
1489 get_modrm(*data, &mod, &regop, &rm);
1490 int8_t imm8 = static_cast<int8_t>(data[1]);
1491 data += 2;
1492 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
1493 NameOfCPURegister(regop), static_cast<int>(imm8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001494 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
Ben Murdochda12d292016-06-02 14:46:10 +01001495 // shrd_cl, shld_cl, bts
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001497 AppendToBuffer("%s ", f0mnem);
1498 int mod, regop, rm;
1499 get_modrm(*data, &mod, &regop, &rm);
1500 data += PrintRightOperand(data);
1501 if (f0byte == 0xAB) {
1502 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001505 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001506 } else if (f0byte == 0xB0) {
1507 // cmpxchg_b
1508 data += 2;
1509 AppendToBuffer("%s ", f0mnem);
1510 int mod, regop, rm;
1511 get_modrm(*data, &mod, &regop, &rm);
1512 data += PrintRightOperand(data);
1513 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1514 } else if (f0byte == 0xB1) {
1515 // cmpxchg
1516 data += 2;
1517 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 } else if (f0byte == 0xBC) {
1519 data += 2;
1520 int mod, regop, rm;
1521 get_modrm(*data, &mod, &regop, &rm);
1522 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1523 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001524 } else if (f0byte == 0xBD) {
1525 data += 2;
1526 int mod, regop, rm;
1527 get_modrm(*data, &mod, &regop, &rm);
1528 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1529 data += PrintRightOperand(data);
1530 } else {
1531 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +00001532 }
1533 }
1534 break;
1535
1536 case 0x8F:
1537 { data++;
1538 int mod, regop, rm;
1539 get_modrm(*data, &mod, &regop, &rm);
1540 if (regop == eax) {
1541 AppendToBuffer("pop ");
1542 data += PrintRightOperand(data);
1543 }
1544 }
1545 break;
1546
1547 case 0xFF:
1548 { data++;
1549 int mod, regop, rm;
1550 get_modrm(*data, &mod, &regop, &rm);
1551 const char* mnem = NULL;
1552 switch (regop) {
1553 case esi: mnem = "push"; break;
1554 case eax: mnem = "inc"; break;
1555 case ecx: mnem = "dec"; break;
1556 case edx: mnem = "call"; break;
1557 case esp: mnem = "jmp"; break;
1558 default: mnem = "???";
1559 }
1560 AppendToBuffer("%s ", mnem);
1561 data += PrintRightOperand(data);
1562 }
1563 break;
1564
1565 case 0xC7: // imm32, fall through
1566 case 0xC6: // imm8
1567 { bool is_byte = *data == 0xC6;
1568 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001569 if (is_byte) {
1570 AppendToBuffer("%s ", "mov_b");
1571 data += PrintRightByteOperand(data);
1572 int32_t imm = *data;
1573 AppendToBuffer(",0x%x", imm);
1574 data++;
1575 } else {
1576 AppendToBuffer("%s ", "mov");
1577 data += PrintRightOperand(data);
1578 int32_t imm = *reinterpret_cast<int32_t*>(data);
1579 AppendToBuffer(",0x%x", imm);
1580 data += 4;
1581 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001582 }
1583 break;
1584
1585 case 0x80:
1586 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001587 int mod, regop, rm;
1588 get_modrm(*data, &mod, &regop, &rm);
1589 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001590 switch (regop) {
1591 case 5: mnem = "subb"; break;
1592 case 7: mnem = "cmpb"; break;
1593 default: UnimplementedInstruction();
1594 }
1595 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001596 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001597 int32_t imm = *data;
1598 AppendToBuffer(",0x%x", imm);
1599 data++;
1600 }
1601 break;
1602
1603 case 0x88: // 8bit, fall through
1604 case 0x89: // 32bit
1605 { bool is_byte = *data == 0x88;
1606 int mod, regop, rm;
1607 data++;
1608 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001609 if (is_byte) {
1610 AppendToBuffer("%s ", "mov_b");
1611 data += PrintRightByteOperand(data);
1612 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1613 } else {
1614 AppendToBuffer("%s ", "mov");
1615 data += PrintRightOperand(data);
1616 AppendToBuffer(",%s", NameOfCPURegister(regop));
1617 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001618 }
1619 break;
1620
1621 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001622 while (*data == 0x66) data++;
1623 if (*data == 0xf && data[1] == 0x1f) {
1624 AppendToBuffer("nop"); // 0x66 prefix
Ben Murdochc5610432016-08-08 18:44:38 +01001625 } else if (*data == 0x39) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001626 data++;
Ben Murdochc5610432016-08-08 18:44:38 +01001627 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data);
1628 } else if (*data == 0x3B) {
1629 data++;
1630 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data);
1631 } else if (*data == 0x81) {
1632 data++;
1633 AppendToBuffer("cmpw ");
1634 data += PrintRightOperand(data);
1635 int imm = *reinterpret_cast<int16_t*>(data);
1636 AppendToBuffer(",0x%x", imm);
1637 data += 2;
1638 } else if (*data == 0x87) {
1639 data++;
1640 int mod, regop, rm;
1641 get_modrm(*data, &mod, &regop, &rm);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001642 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
Ben Murdochc5610432016-08-08 18:44:38 +01001643 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001644 } else if (*data == 0x89) {
1645 data++;
1646 int mod, regop, rm;
1647 get_modrm(*data, &mod, &regop, &rm);
1648 AppendToBuffer("mov_w ");
1649 data += PrintRightOperand(data);
1650 AppendToBuffer(",%s", NameOfCPURegister(regop));
Ben Murdochc5610432016-08-08 18:44:38 +01001651 } else if (*data == 0x8B) {
1652 data++;
1653 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1654 } else if (*data == 0x90) {
1655 AppendToBuffer("nop"); // 0x66 prefix
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001656 } else if (*data == 0xC7) {
1657 data++;
1658 AppendToBuffer("%s ", "mov_w");
1659 data += PrintRightOperand(data);
1660 int imm = *reinterpret_cast<int16_t*>(data);
1661 AppendToBuffer(",0x%x", imm);
1662 data += 2;
Ben Murdochda12d292016-06-02 14:46:10 +01001663 } else if (*data == 0xF7) {
1664 data++;
1665 AppendToBuffer("%s ", "test_w");
1666 data += PrintRightOperand(data);
1667 int imm = *reinterpret_cast<int16_t*>(data);
1668 AppendToBuffer(",0x%x", imm);
1669 data += 2;
Steve Block3ce2e202009-11-05 08:53:23 +00001670 } else if (*data == 0x0F) {
1671 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001672 if (*data == 0x38) {
1673 data++;
1674 if (*data == 0x17) {
1675 data++;
1676 int mod, regop, rm;
1677 get_modrm(*data, &mod, &regop, &rm);
1678 AppendToBuffer("ptest %s,%s",
1679 NameOfXMMRegister(regop),
1680 NameOfXMMRegister(rm));
1681 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001682 } else if (*data == 0x2A) {
1683 // movntdqa
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 UnimplementedInstruction();
Steve Block6ded16b2010-05-10 14:33:55 +01001685 } else {
1686 UnimplementedInstruction();
1687 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001688 } else if (*data == 0x3A) {
1689 data++;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001690 if (*data == 0x0A) {
1691 data++;
1692 int mod, regop, rm;
1693 get_modrm(*data, &mod, &regop, &rm);
1694 int8_t imm8 = static_cast<int8_t>(data[1]);
1695 AppendToBuffer("roundss %s,%s,%d", NameOfXMMRegister(regop),
1696 NameOfXMMRegister(rm), static_cast<int>(imm8));
1697 data += 2;
1698 } else if (*data == 0x0B) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001699 data++;
1700 int mod, regop, rm;
1701 get_modrm(*data, &mod, &regop, &rm);
1702 int8_t imm8 = static_cast<int8_t>(data[1]);
1703 AppendToBuffer("roundsd %s,%s,%d",
1704 NameOfXMMRegister(regop),
1705 NameOfXMMRegister(rm),
1706 static_cast<int>(imm8));
1707 data += 2;
1708 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001709 data++;
1710 int mod, regop, rm;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001711 get_modrm(*data, &mod, &rm, &regop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001712 int8_t imm8 = static_cast<int8_t>(data[1]);
1713 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001714 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001715 NameOfXMMRegister(rm),
1716 static_cast<int>(imm8));
1717 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001718 } else if (*data == 0x17) {
1719 data++;
1720 int mod, regop, rm;
1721 get_modrm(*data, &mod, &regop, &rm);
1722 int8_t imm8 = static_cast<int8_t>(data[1]);
1723 AppendToBuffer("extractps %s,%s,%d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001724 NameOfCPURegister(rm),
1725 NameOfXMMRegister(regop),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001726 static_cast<int>(imm8));
1727 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001728 } else if (*data == 0x22) {
1729 data++;
1730 int mod, regop, rm;
1731 get_modrm(*data, &mod, &regop, &rm);
1732 int8_t imm8 = static_cast<int8_t>(data[1]);
1733 AppendToBuffer("pinsrd %s,%s,%d",
1734 NameOfXMMRegister(regop),
1735 NameOfCPURegister(rm),
1736 static_cast<int>(imm8));
1737 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001738 } else {
1739 UnimplementedInstruction();
1740 }
Steve Block6ded16b2010-05-10 14:33:55 +01001741 } else if (*data == 0x2E || *data == 0x2F) {
1742 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001743 data++;
1744 int mod, regop, rm;
1745 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001746 if (mod == 0x3) {
1747 AppendToBuffer("%s %s,%s", mnem,
1748 NameOfXMMRegister(regop),
1749 NameOfXMMRegister(rm));
1750 data++;
1751 } else {
1752 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1753 data += PrintRightOperand(data);
1754 }
1755 } else if (*data == 0x50) {
1756 data++;
1757 int mod, regop, rm;
1758 get_modrm(*data, &mod, &regop, &rm);
1759 AppendToBuffer("movmskpd %s,%s",
1760 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001761 NameOfXMMRegister(rm));
1762 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001763 } else if (*data == 0x54) {
1764 data++;
1765 int mod, regop, rm;
1766 get_modrm(*data, &mod, &regop, &rm);
1767 AppendToBuffer("andpd %s,%s",
1768 NameOfXMMRegister(regop),
1769 NameOfXMMRegister(rm));
1770 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001771 } else if (*data == 0x56) {
1772 data++;
1773 int mod, regop, rm;
1774 get_modrm(*data, &mod, &regop, &rm);
1775 AppendToBuffer("orpd %s,%s",
1776 NameOfXMMRegister(regop),
1777 NameOfXMMRegister(rm));
1778 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001779 } else if (*data == 0x57) {
1780 data++;
1781 int mod, regop, rm;
1782 get_modrm(*data, &mod, &regop, &rm);
1783 AppendToBuffer("xorpd %s,%s",
1784 NameOfXMMRegister(regop),
1785 NameOfXMMRegister(rm));
1786 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001787 } else if (*data == 0x6E) {
1788 data++;
1789 int mod, regop, rm;
1790 get_modrm(*data, &mod, &regop, &rm);
1791 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1792 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001793 } else if (*data == 0x6F) {
1794 data++;
1795 int mod, regop, rm;
1796 get_modrm(*data, &mod, &regop, &rm);
1797 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001798 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001799 } else if (*data == 0x70) {
1800 data++;
1801 int mod, regop, rm;
1802 get_modrm(*data, &mod, &regop, &rm);
1803 int8_t imm8 = static_cast<int8_t>(data[1]);
1804 AppendToBuffer("pshufd %s,%s,%d",
1805 NameOfXMMRegister(regop),
1806 NameOfXMMRegister(rm),
1807 static_cast<int>(imm8));
1808 data += 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001809 } else if (*data == 0x62) {
1810 data++;
1811 int mod, regop, rm;
1812 get_modrm(*data, &mod, &regop, &rm);
1813 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
1814 NameOfXMMRegister(rm));
1815 data++;
1816 } else if (*data == 0x6A) {
1817 data++;
1818 int mod, regop, rm;
1819 get_modrm(*data, &mod, &regop, &rm);
1820 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
1821 NameOfXMMRegister(rm));
1822 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001823 } else if (*data == 0x76) {
1824 data++;
1825 int mod, regop, rm;
1826 get_modrm(*data, &mod, &regop, &rm);
1827 AppendToBuffer("pcmpeqd %s,%s",
1828 NameOfXMMRegister(regop),
1829 NameOfXMMRegister(rm));
1830 data++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001831 } else if (*data == 0x90) {
1832 data++;
1833 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001834 } else if (*data == 0xF3) {
1835 data++;
1836 int mod, regop, rm;
1837 get_modrm(*data, &mod, &regop, &rm);
1838 AppendToBuffer("psllq %s,%s",
1839 NameOfXMMRegister(regop),
1840 NameOfXMMRegister(rm));
1841 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001842 } else if (*data == 0x72) {
1843 data++;
1844 int mod, regop, rm;
1845 get_modrm(*data, &mod, &regop, &rm);
1846 int8_t imm8 = static_cast<int8_t>(data[1]);
1847 DCHECK(regop == esi || regop == edx);
1848 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1849 NameOfXMMRegister(rm), static_cast<int>(imm8));
1850 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001851 } else if (*data == 0x73) {
1852 data++;
1853 int mod, regop, rm;
1854 get_modrm(*data, &mod, &regop, &rm);
1855 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001856 DCHECK(regop == esi || regop == edx);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001857 AppendToBuffer("%s %s,%d",
1858 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001859 NameOfXMMRegister(rm),
1860 static_cast<int>(imm8));
1861 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001862 } else if (*data == 0xD3) {
1863 data++;
1864 int mod, regop, rm;
1865 get_modrm(*data, &mod, &regop, &rm);
1866 AppendToBuffer("psrlq %s,%s",
1867 NameOfXMMRegister(regop),
1868 NameOfXMMRegister(rm));
1869 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001870 } else if (*data == 0x7F) {
1871 AppendToBuffer("movdqa ");
1872 data++;
1873 int mod, regop, rm;
1874 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001875 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001876 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001877 } else if (*data == 0x7E) {
1878 data++;
1879 int mod, regop, rm;
1880 get_modrm(*data, &mod, &regop, &rm);
1881 AppendToBuffer("movd ");
1882 data += PrintRightOperand(data);
1883 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1884 } else if (*data == 0xDB) {
1885 data++;
1886 int mod, regop, rm;
1887 get_modrm(*data, &mod, &regop, &rm);
1888 AppendToBuffer("pand %s,%s",
1889 NameOfXMMRegister(regop),
1890 NameOfXMMRegister(rm));
1891 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001892 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001893 data++;
1894 int mod, regop, rm;
1895 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001896 if (mod == 3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001897 // movntdq
1898 UnimplementedInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +01001899 } else {
1900 UnimplementedInstruction();
1901 }
Steve Block6ded16b2010-05-10 14:33:55 +01001902 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001903 data++;
1904 int mod, regop, rm;
1905 get_modrm(*data, &mod, &regop, &rm);
1906 AppendToBuffer("pxor %s,%s",
1907 NameOfXMMRegister(regop),
1908 NameOfXMMRegister(rm));
1909 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001910 } else if (*data == 0xEB) {
1911 data++;
1912 int mod, regop, rm;
1913 get_modrm(*data, &mod, &regop, &rm);
1914 AppendToBuffer("por %s,%s",
1915 NameOfXMMRegister(regop),
1916 NameOfXMMRegister(rm));
1917 data++;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001918 } else if (*data == 0xB1) {
1919 data++;
1920 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
Steve Block3ce2e202009-11-05 08:53:23 +00001921 } else {
1922 UnimplementedInstruction();
1923 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001924 } else {
1925 UnimplementedInstruction();
1926 }
1927 break;
1928
1929 case 0xFE:
1930 { data++;
1931 int mod, regop, rm;
1932 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001933 if (regop == ecx) {
1934 AppendToBuffer("dec_b ");
1935 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 } else {
1937 UnimplementedInstruction();
1938 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001939 }
1940 break;
1941
1942 case 0x68:
1943 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1944 data += 5;
1945 break;
1946
1947 case 0x6A:
1948 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1949 data += 2;
1950 break;
1951
1952 case 0xA8:
1953 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1954 data += 2;
1955 break;
1956
1957 case 0xA9:
1958 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1959 data += 5;
1960 break;
1961
1962 case 0xD1: // fall through
1963 case 0xD3: // fall through
1964 case 0xC1:
1965 data += D1D3C1Instruction(data);
1966 break;
1967
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001968 case 0xD8: // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 case 0xD9: // fall through
1970 case 0xDA: // fall through
1971 case 0xDB: // fall through
1972 case 0xDC: // fall through
1973 case 0xDD: // fall through
1974 case 0xDE: // fall through
1975 case 0xDF:
1976 data += FPUInstruction(data);
1977 break;
1978
1979 case 0xEB:
1980 data += JumpShort(data);
1981 break;
1982
1983 case 0xF2:
1984 if (*(data+1) == 0x0F) {
1985 byte b2 = *(data+2);
1986 if (b2 == 0x11) {
1987 AppendToBuffer("movsd ");
1988 data += 3;
1989 int mod, regop, rm;
1990 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001991 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001992 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1993 } else if (b2 == 0x10) {
1994 data += 3;
1995 int mod, regop, rm;
1996 get_modrm(*data, &mod, &regop, &rm);
1997 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001998 data += PrintRightXMMOperand(data);
1999 } else if (b2 == 0x5A) {
2000 data += 3;
2001 int mod, regop, rm;
2002 get_modrm(*data, &mod, &regop, &rm);
2003 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
2004 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002005 } else {
2006 const char* mnem = "?";
2007 switch (b2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008 case 0x2A:
2009 mnem = "cvtsi2sd";
2010 break;
2011 case 0x2C:
2012 mnem = "cvttsd2si";
2013 break;
2014 case 0x2D:
2015 mnem = "cvtsd2si";
2016 break;
2017 case 0x51:
2018 mnem = "sqrtsd";
2019 break;
2020 case 0x58:
2021 mnem = "addsd";
2022 break;
2023 case 0x59:
2024 mnem = "mulsd";
2025 break;
2026 case 0x5C:
2027 mnem = "subsd";
2028 break;
2029 case 0x5D:
2030 mnem = "minsd";
2031 break;
2032 case 0x5E:
2033 mnem = "divsd";
2034 break;
2035 case 0x5F:
2036 mnem = "maxsd";
2037 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002038 }
2039 data += 3;
2040 int mod, regop, rm;
2041 get_modrm(*data, &mod, &regop, &rm);
2042 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01002043 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2044 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002045 } else if (b2 == 0x2C || b2 == 0x2D) {
Steve Block44f0eee2011-05-26 01:26:41 +01002046 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2047 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002048 } else if (b2 == 0xC2) {
2049 // Intel manual 2A, Table 3-18.
2050 const char* const pseudo_op[] = {
2051 "cmpeqsd",
2052 "cmpltsd",
2053 "cmplesd",
2054 "cmpunordsd",
2055 "cmpneqsd",
2056 "cmpnltsd",
2057 "cmpnlesd",
2058 "cmpordsd"
2059 };
2060 AppendToBuffer("%s %s,%s",
2061 pseudo_op[data[1]],
2062 NameOfXMMRegister(regop),
2063 NameOfXMMRegister(rm));
2064 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00002065 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002066 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2067 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002068 }
2069 }
2070 } else {
2071 UnimplementedInstruction();
2072 }
2073 break;
2074
2075 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00002076 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01002077 byte b2 = *(data+2);
2078 if (b2 == 0x11) {
2079 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01002080 data += 3;
2081 int mod, regop, rm;
2082 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002083 data += PrintRightXMMOperand(data);
2084 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2085 } else if (b2 == 0x10) {
2086 data += 3;
2087 int mod, regop, rm;
2088 get_modrm(*data, &mod, &regop, &rm);
2089 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2090 data += PrintRightXMMOperand(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002091 } else if (b2 == 0x5A) {
2092 data += 3;
2093 int mod, regop, rm;
2094 get_modrm(*data, &mod, &regop, &rm);
2095 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2096 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002097 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002098 data += 3;
2099 int mod, regop, rm;
2100 get_modrm(*data, &mod, &regop, &rm);
2101 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01002102 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002103 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002104 AppendToBuffer("movdqu ");
2105 data += 3;
2106 int mod, regop, rm;
2107 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002108 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002109 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002110 } else if (b2 == 0xB8) {
2111 data += 3;
2112 int mod, regop, rm;
2113 get_modrm(*data, &mod, &regop, &rm);
2114 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2115 data += PrintRightOperand(data);
2116 } else if (b2 == 0xBC) {
2117 data += 3;
2118 int mod, regop, rm;
2119 get_modrm(*data, &mod, &regop, &rm);
2120 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2121 data += PrintRightOperand(data);
2122 } else if (b2 == 0xBD) {
2123 data += 3;
2124 int mod, regop, rm;
2125 get_modrm(*data, &mod, &regop, &rm);
2126 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2127 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002128 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002129 const char* mnem = "?";
2130 switch (b2) {
2131 case 0x2A:
2132 mnem = "cvtsi2ss";
2133 break;
2134 case 0x2C:
2135 mnem = "cvttss2si";
2136 break;
2137 case 0x2D:
2138 mnem = "cvtss2si";
2139 break;
2140 case 0x51:
2141 mnem = "sqrtss";
2142 break;
2143 case 0x58:
2144 mnem = "addss";
2145 break;
2146 case 0x59:
2147 mnem = "mulss";
2148 break;
2149 case 0x5C:
2150 mnem = "subss";
2151 break;
2152 case 0x5D:
2153 mnem = "minss";
2154 break;
2155 case 0x5E:
2156 mnem = "divss";
2157 break;
2158 case 0x5F:
2159 mnem = "maxss";
2160 break;
2161 }
2162 data += 3;
2163 int mod, regop, rm;
2164 get_modrm(*data, &mod, &regop, &rm);
2165 if (b2 == 0x2A) {
2166 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2167 data += PrintRightOperand(data);
2168 } else if (b2 == 0x2C || b2 == 0x2D) {
2169 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2170 data += PrintRightXMMOperand(data);
2171 } else if (b2 == 0xC2) {
2172 // Intel manual 2A, Table 3-18.
2173 const char* const pseudo_op[] = {
2174 "cmpeqss", "cmpltss", "cmpless", "cmpunordss",
2175 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2176 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2177 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2178 data += 2;
2179 } else {
2180 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2181 data += PrintRightXMMOperand(data);
2182 }
Leon Clarkee46be812010-01-19 14:06:41 +00002183 }
2184 } else if (*(data+1) == 0xA5) {
2185 data += 2;
2186 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01002187 } else if (*(data+1) == 0xAB) {
2188 data += 2;
2189 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00002190 } else {
2191 UnimplementedInstruction();
2192 }
2193 break;
2194
2195 case 0xF7:
2196 data += F7Instruction(data);
2197 break;
2198
2199 default:
2200 UnimplementedInstruction();
2201 }
2202 }
2203
2204 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2205 tmp_buffer_[tmp_buffer_pos_] = '\0';
2206 }
2207
2208 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00002209 if (instr_len == 0) {
2210 printf("%02x", *data);
2211 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002212 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002213
2214 int outp = 0;
2215 // Instruction bytes.
2216 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002217 outp += v8::internal::SNPrintF(out_buffer + outp,
2218 "%02x",
2219 *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002220 }
2221 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002223 }
2224
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002225 outp += v8::internal::SNPrintF(out_buffer + outp,
2226 " %s",
2227 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002228 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002229} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00002230
2231
2232//------------------------------------------------------------------------------
2233
2234
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002235static const char* const cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002236 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
2237};
2238
2239
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002240static const char* const byte_cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002241 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
2242};
2243
2244
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002245static const char* const xmm_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002246 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
2247};
2248
2249
2250const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002251 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
Steve Block44f0eee2011-05-26 01:26:41 +01002252 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002253}
2254
2255
2256const char* NameConverter::NameOfConstant(byte* addr) const {
2257 return NameOfAddress(addr);
2258}
2259
2260
2261const char* NameConverter::NameOfCPURegister(int reg) const {
2262 if (0 <= reg && reg < 8) return cpu_regs[reg];
2263 return "noreg";
2264}
2265
2266
2267const char* NameConverter::NameOfByteCPURegister(int reg) const {
2268 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2269 return "noreg";
2270}
2271
2272
2273const char* NameConverter::NameOfXMMRegister(int reg) const {
2274 if (0 <= reg && reg < 8) return xmm_regs[reg];
2275 return "noxmmreg";
2276}
2277
2278
2279const char* NameConverter::NameInCode(byte* addr) const {
2280 // IA32 does not embed debug strings at the moment.
2281 UNREACHABLE();
2282 return "";
2283}
2284
2285
2286//------------------------------------------------------------------------------
2287
2288Disassembler::Disassembler(const NameConverter& converter)
2289 : converter_(converter) {}
2290
2291
2292Disassembler::~Disassembler() {}
2293
2294
2295int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2296 byte* instruction) {
2297 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
2298 return d.InstructionDecode(buffer, instruction);
2299}
2300
2301
2302// The IA-32 assembler does not currently use constant pools.
2303int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2304
2305
2306/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2307 NameConverter converter;
2308 Disassembler d(converter);
2309 for (byte* pc = begin; pc < end;) {
2310 v8::internal::EmbeddedVector<char, 128> buffer;
2311 buffer[0] = '\0';
2312 byte* prev_pc = pc;
2313 pc += d.InstructionDecode(buffer, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002314 fprintf(f, "%p", static_cast<void*>(prev_pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00002315 fprintf(f, " ");
2316
2317 for (byte* bp = prev_pc; bp < pc; bp++) {
2318 fprintf(f, "%02x", *bp);
2319 }
2320 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2321 fprintf(f, " ");
2322 }
2323 fprintf(f, " %s\n", buffer.start());
2324 }
2325}
2326
2327
2328} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002329
2330#endif // V8_TARGET_ARCH_IA32