blob: 3cd0ac6e52fbe9d20e85faf60311971b80b18488 [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 Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000012
13namespace disasm {
14
15enum OperandOrder {
16 UNSET_OP_ORDER = 0,
17 REG_OPER_OP_ORDER,
18 OPER_REG_OP_ORDER
19};
20
21
22//------------------------------------------------------------------
23// Tables
24//------------------------------------------------------------------
25struct ByteMnemonic {
26 int b; // -1 terminates, otherwise must be in range (0..255)
27 const char* mnem;
28 OperandOrder op_order_;
29};
30
Ben Murdoch69a99ed2011-11-30 16:03:39 +000031static const ByteMnemonic two_operands_instr[] = {
Ben Murdochda12d292016-06-02 14:46:10 +010032 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
33 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER},
34 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER},
35 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER},
36 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER},
37 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
38 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
39 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
40 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
41 {0x85, "test", REG_OPER_OP_ORDER}, {0x87, "xchg", REG_OPER_OP_ORDER},
42 {0x8A, "mov_b", REG_OPER_OP_ORDER}, {0x8B, "mov", REG_OPER_OP_ORDER},
43 {0x8D, "lea", REG_OPER_OP_ORDER}, {-1, "", UNSET_OP_ORDER}};
Steve Blocka7e24c12009-10-30 11:49:00 +000044
Ben Murdoch69a99ed2011-11-30 16:03:39 +000045static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000046 {0xC3, "ret", UNSET_OP_ORDER},
47 {0xC9, "leave", UNSET_OP_ORDER},
48 {0x90, "nop", UNSET_OP_ORDER},
49 {0xF4, "hlt", UNSET_OP_ORDER},
50 {0xCC, "int3", UNSET_OP_ORDER},
51 {0x60, "pushad", UNSET_OP_ORDER},
52 {0x61, "popad", UNSET_OP_ORDER},
53 {0x9C, "pushfd", UNSET_OP_ORDER},
54 {0x9D, "popfd", UNSET_OP_ORDER},
55 {0x9E, "sahf", UNSET_OP_ORDER},
56 {0x99, "cdq", UNSET_OP_ORDER},
57 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010058 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010059 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000060 {-1, "", UNSET_OP_ORDER}
61};
62
63
Ben Murdoch69a99ed2011-11-30 16:03:39 +000064static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000065 {0xE8, "call", UNSET_OP_ORDER},
66 {0xE9, "jmp", UNSET_OP_ORDER},
67 {-1, "", UNSET_OP_ORDER}
68};
69
70
Ben Murdoch69a99ed2011-11-30 16:03:39 +000071static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000072 {0x05, "add", UNSET_OP_ORDER},
73 {0x0D, "or", UNSET_OP_ORDER},
74 {0x15, "adc", UNSET_OP_ORDER},
75 {0x25, "and", UNSET_OP_ORDER},
76 {0x2D, "sub", UNSET_OP_ORDER},
77 {0x35, "xor", UNSET_OP_ORDER},
78 {0x3D, "cmp", UNSET_OP_ORDER},
79 {-1, "", UNSET_OP_ORDER}
80};
81
82
Ben Murdoch3ef787d2012-04-12 10:51:47 +010083// Generally we don't want to generate these because they are subject to partial
84// register stalls. They are included for completeness and because the cmp
85// variant is used by the RecordWrite stub. Because it does not update the
86// register it is not subject to partial register stalls.
87static ByteMnemonic byte_immediate_instr[] = {
88 {0x0c, "or", UNSET_OP_ORDER},
89 {0x24, "and", UNSET_OP_ORDER},
90 {0x34, "xor", UNSET_OP_ORDER},
91 {0x3c, "cmp", UNSET_OP_ORDER},
92 {-1, "", UNSET_OP_ORDER}
93};
94
95
Ben Murdoch69a99ed2011-11-30 16:03:39 +000096static const char* const jump_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000097 /*0*/ "jo", "jno", "jc", "jnc",
98 /*4*/ "jz", "jnz", "jna", "ja",
99 /*8*/ "js", "jns", "jpe", "jpo",
100 /*12*/ "jl", "jnl", "jng", "jg"
101};
102
103
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000104static const char* const set_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000105 /*0*/ "seto", "setno", "setc", "setnc",
106 /*4*/ "setz", "setnz", "setna", "seta",
107 /*8*/ "sets", "setns", "setpe", "setpo",
108 /*12*/ "setl", "setnl", "setng", "setg"
109};
110
111
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000112static const char* const conditional_move_mnem[] = {
Steve Block3ce2e202009-11-05 08:53:23 +0000113 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
114 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
115 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
116 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
117};
118
119
Steve Blocka7e24c12009-10-30 11:49:00 +0000120enum InstructionType {
121 NO_INSTR,
122 ZERO_OPERANDS_INSTR,
123 TWO_OPERANDS_INSTR,
124 JUMP_CONDITIONAL_SHORT_INSTR,
125 REGISTER_INSTR,
126 MOVE_REG_INSTR,
127 CALL_JUMP_INSTR,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100128 SHORT_IMMEDIATE_INSTR,
129 BYTE_IMMEDIATE_INSTR
Steve Blocka7e24c12009-10-30 11:49:00 +0000130};
131
132
133struct InstructionDesc {
134 const char* mnem;
135 InstructionType type;
136 OperandOrder op_order_;
137};
138
139
140class InstructionTable {
141 public:
142 InstructionTable();
143 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100144 static InstructionTable* get_instance() {
145 static InstructionTable table;
146 return &table;
147 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000148
149 private:
150 InstructionDesc instructions_[256];
151 void Clear();
152 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000153 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 void SetTableRange(InstructionType type,
155 byte start,
156 byte end,
157 const char* mnem);
158 void AddJumpConditionalShort();
159};
160
161
162InstructionTable::InstructionTable() {
163 Clear();
164 Init();
165}
166
167
168void InstructionTable::Clear() {
169 for (int i = 0; i < 256; i++) {
170 instructions_[i].mnem = "";
171 instructions_[i].type = NO_INSTR;
172 instructions_[i].op_order_ = UNSET_OP_ORDER;
173 }
174}
175
176
177void InstructionTable::Init() {
178 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
179 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
180 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
181 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100182 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 AddJumpConditionalShort();
184 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
185 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
186 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
187 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
188 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
189 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
190}
191
192
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000193void InstructionTable::CopyTable(const ByteMnemonic bm[],
194 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 for (int i = 0; bm[i].b >= 0; i++) {
196 InstructionDesc* id = &instructions_[bm[i].b];
197 id->mnem = bm[i].mnem;
198 id->op_order_ = bm[i].op_order_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000200 id->type = type;
201 }
202}
203
204
205void InstructionTable::SetTableRange(InstructionType type,
206 byte start,
207 byte end,
208 const char* mnem) {
209 for (byte b = start; b <= end; b++) {
210 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 id->mnem = mnem;
213 id->type = type;
214 }
215}
216
217
218void InstructionTable::AddJumpConditionalShort() {
219 for (byte b = 0x70; b <= 0x7F; b++) {
220 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 id->mnem = jump_conditional_mnem[b & 0x0F];
223 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
224 }
225}
226
227
Steve Blocka7e24c12009-10-30 11:49:00 +0000228// The IA32 disassembler implementation.
229class DisassemblerIA32 {
230 public:
231 DisassemblerIA32(const NameConverter& converter,
232 bool abort_on_unimplemented = true)
233 : converter_(converter),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400234 vex_byte0_(0),
235 vex_byte1_(0),
236 vex_byte2_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100237 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 tmp_buffer_pos_(0),
239 abort_on_unimplemented_(abort_on_unimplemented) {
240 tmp_buffer_[0] = '\0';
241 }
242
243 virtual ~DisassemblerIA32() {}
244
245 // Writes one disassembled instruction into 'buffer' (0-terminated).
246 // Returns the length of the disassembled machine instruction in bytes.
247 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
248
249 private:
250 const NameConverter& converter_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400251 byte vex_byte0_; // 0xc4 or 0xc5
252 byte vex_byte1_;
253 byte vex_byte2_; // only for 3 bytes vex prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100254 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000255 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
256 unsigned int tmp_buffer_pos_;
257 bool abort_on_unimplemented_;
258
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 enum {
260 eax = 0,
261 ecx = 1,
262 edx = 2,
263 ebx = 3,
264 esp = 4,
265 ebp = 5,
266 esi = 6,
267 edi = 7
268 };
269
270
Steve Blockd0582a62009-12-15 09:54:21 +0000271 enum ShiftOpcodeExtension {
272 kROL = 0,
273 kROR = 1,
274 kRCL = 2,
275 kRCR = 3,
276 kSHL = 4,
277 KSHR = 5,
278 kSAR = 7
279 };
280
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281 bool vex_128() {
282 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
283 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
284 return (checked & 4) != 1;
285 }
286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 bool vex_none() {
288 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
289 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
290 return (checked & 3) == 0;
291 }
292
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400293 bool vex_66() {
294 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
295 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
296 return (checked & 3) == 1;
297 }
298
299 bool vex_f3() {
300 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
301 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
302 return (checked & 3) == 2;
303 }
304
305 bool vex_f2() {
306 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
307 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
308 return (checked & 3) == 3;
309 }
310
311 bool vex_w() {
312 if (vex_byte0_ == 0xc5) return false;
313 return (vex_byte2_ & 0x80) != 0;
314 }
315
316 bool vex_0f() {
317 if (vex_byte0_ == 0xc5) return true;
318 return (vex_byte1_ & 3) == 1;
319 }
320
321 bool vex_0f38() {
322 if (vex_byte0_ == 0xc5) return false;
323 return (vex_byte1_ & 3) == 2;
324 }
325
326 bool vex_0f3a() {
327 if (vex_byte0_ == 0xc5) return false;
328 return (vex_byte1_ & 3) == 3;
329 }
330
331 int vex_vreg() {
332 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
333 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
334 return ~(checked >> 3) & 0xf;
335 }
336
337 char float_size_code() { return "sd"[vex_w()]; }
Steve Blockd0582a62009-12-15 09:54:21 +0000338
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 const char* NameOfCPURegister(int reg) const {
340 return converter_.NameOfCPURegister(reg);
341 }
342
343
344 const char* NameOfByteCPURegister(int reg) const {
345 return converter_.NameOfByteCPURegister(reg);
346 }
347
348
349 const char* NameOfXMMRegister(int reg) const {
350 return converter_.NameOfXMMRegister(reg);
351 }
352
353
354 const char* NameOfAddress(byte* addr) const {
355 return converter_.NameOfAddress(addr);
356 }
357
358
359 // Disassembler helper functions.
360 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
361 *mod = (data >> 6) & 3;
362 *regop = (data & 0x38) >> 3;
363 *rm = data & 7;
364 }
365
366
367 static void get_sib(byte data, int* scale, int* index, int* base) {
368 *scale = (data >> 6) & 3;
369 *index = (data >> 3) & 7;
370 *base = data & 7;
371 }
372
373 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
374
375 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
376 int PrintRightOperand(byte* modrmp);
377 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100378 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000379 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
380 int PrintImmediateOp(byte* data);
381 int F7Instruction(byte* data);
382 int D1D3C1Instruction(byte* data);
383 int JumpShort(byte* data);
384 int JumpConditional(byte* data, const char* comment);
385 int JumpConditionalShort(byte* data, const char* comment);
386 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000387 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000389 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
390 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400391 int AVXInstruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 void AppendToBuffer(const char* format, ...);
393
394
395 void UnimplementedInstruction() {
396 if (abort_on_unimplemented_) {
397 UNIMPLEMENTED();
398 } else {
399 AppendToBuffer("'Unimplemented Instruction'");
400 }
401 }
402};
403
404
405void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
406 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
407 va_list args;
408 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 va_end(args);
411 tmp_buffer_pos_ += result;
412}
413
414int DisassemblerIA32::PrintRightOperandHelper(
415 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100416 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 int mod, regop, rm;
418 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100419 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
420 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 switch (mod) {
422 case 0:
423 if (rm == ebp) {
424 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
425 AppendToBuffer("[0x%x]", disp);
426 return 5;
427 } else if (rm == esp) {
428 byte sib = *(modrmp + 1);
429 int scale, index, base;
430 get_sib(sib, &scale, &index, &base);
431 if (index == esp && base == esp && scale == 0 /*times_1*/) {
432 AppendToBuffer("[%s]", (this->*register_name)(rm));
433 return 2;
434 } else if (base == ebp) {
435 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 AppendToBuffer("[%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 (this->*register_name)(index),
438 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 disp < 0 ? "-" : "+",
440 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 return 6;
442 } else if (index != esp && base != ebp) {
443 // [base+index*scale]
444 AppendToBuffer("[%s+%s*%d]",
445 (this->*register_name)(base),
446 (this->*register_name)(index),
447 1 << scale);
448 return 2;
449 } else {
450 UnimplementedInstruction();
451 return 1;
452 }
453 } else {
454 AppendToBuffer("[%s]", (this->*register_name)(rm));
455 return 1;
456 }
457 break;
458 case 1: // fall through
459 case 2:
460 if (rm == esp) {
461 byte sib = *(modrmp + 1);
462 int scale, index, base;
463 get_sib(sib, &scale, &index, &base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
465 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000467 AppendToBuffer("[%s%s0x%x]",
468 (this->*register_name)(rm),
469 disp < 0 ? "-" : "+",
470 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000471 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000472 AppendToBuffer("[%s+%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 (this->*register_name)(base),
474 (this->*register_name)(index),
475 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 disp < 0 ? "-" : "+",
477 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478 }
479 return mod == 2 ? 6 : 3;
480 } else {
481 // No sib.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000482 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
483 : *reinterpret_cast<int8_t*>(modrmp + 1);
484 AppendToBuffer("[%s%s0x%x]",
485 (this->*register_name)(rm),
486 disp < 0 ? "-" : "+",
487 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000488 return mod == 2 ? 5 : 2;
489 }
490 break;
491 case 3:
492 AppendToBuffer("%s", (this->*register_name)(rm));
493 return 1;
494 default:
495 UnimplementedInstruction();
496 return 1;
497 }
498 UNREACHABLE();
499}
500
501
502int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
503 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
504}
505
506
507int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
508 return PrintRightOperandHelper(modrmp,
509 &DisassemblerIA32::NameOfByteCPURegister);
510}
511
512
Steve Block44f0eee2011-05-26 01:26:41 +0100513int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
514 return PrintRightOperandHelper(modrmp,
515 &DisassemblerIA32::NameOfXMMRegister);
516}
517
518
Steve Blocka7e24c12009-10-30 11:49:00 +0000519// Returns number of bytes used including the current *data.
520// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
521int DisassemblerIA32::PrintOperands(const char* mnem,
522 OperandOrder op_order,
523 byte* data) {
524 byte modrm = *data;
525 int mod, regop, rm;
526 get_modrm(modrm, &mod, &regop, &rm);
527 int advance = 0;
528 switch (op_order) {
529 case REG_OPER_OP_ORDER: {
530 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
531 advance = PrintRightOperand(data);
532 break;
533 }
534 case OPER_REG_OP_ORDER: {
535 AppendToBuffer("%s ", mnem);
536 advance = PrintRightOperand(data);
537 AppendToBuffer(",%s", NameOfCPURegister(regop));
538 break;
539 }
540 default:
541 UNREACHABLE();
542 break;
543 }
544 return advance;
545}
546
547
548// Returns number of bytes used by machine instruction, including *data byte.
549// Writes immediate instructions to 'tmp_buffer_'.
550int DisassemblerIA32::PrintImmediateOp(byte* data) {
551 bool sign_extension_bit = (*data & 0x02) != 0;
552 byte modrm = *(data+1);
553 int mod, regop, rm;
554 get_modrm(modrm, &mod, &regop, &rm);
555 const char* mnem = "Imm???";
556 switch (regop) {
557 case 0: mnem = "add"; break;
558 case 1: mnem = "or"; break;
559 case 2: mnem = "adc"; break;
560 case 4: mnem = "and"; break;
561 case 5: mnem = "sub"; break;
562 case 6: mnem = "xor"; break;
563 case 7: mnem = "cmp"; break;
564 default: UnimplementedInstruction();
565 }
566 AppendToBuffer("%s ", mnem);
567 int count = PrintRightOperand(data+1);
568 if (sign_extension_bit) {
569 AppendToBuffer(",0x%x", *(data + 1 + count));
570 return 1 + count + 1 /*int8*/;
571 } else {
572 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
573 return 1 + count + 4 /*int32_t*/;
574 }
575}
576
577
578// Returns number of bytes used, including *data.
579int DisassemblerIA32::F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 DCHECK_EQ(0xF7, *data);
581 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 int mod, regop, rm;
583 get_modrm(modrm, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000584 const char* mnem = NULL;
585 switch (regop) {
586 case 0:
587 mnem = "test";
588 break;
589 case 2:
590 mnem = "not";
591 break;
592 case 3:
593 mnem = "neg";
594 break;
595 case 4:
596 mnem = "mul";
597 break;
598 case 5:
599 mnem = "imul";
600 break;
601 case 6:
602 mnem = "div";
603 break;
604 case 7:
605 mnem = "idiv";
606 break;
607 default:
608 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610 AppendToBuffer("%s ", mnem);
611 int count = PrintRightOperand(data);
612 if (regop == 0) {
613 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
614 count += 4;
615 }
616 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000617}
618
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619
Steve Blocka7e24c12009-10-30 11:49:00 +0000620int DisassemblerIA32::D1D3C1Instruction(byte* data) {
621 byte op = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000622 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
623 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000624 int mod, regop, rm;
625 get_modrm(modrm, &mod, &regop, &rm);
626 int imm8 = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000627 const char* mnem = NULL;
628 switch (regop) {
629 case kROL:
630 mnem = "rol";
631 break;
632 case kROR:
633 mnem = "ror";
634 break;
635 case kRCL:
636 mnem = "rcl";
637 break;
638 case kRCR:
639 mnem = "rcr";
640 break;
641 case kSHL:
642 mnem = "shl";
643 break;
644 case KSHR:
645 mnem = "shr";
646 break;
647 case kSAR:
648 mnem = "sar";
649 break;
650 default:
651 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000653 AppendToBuffer("%s ", mnem);
654 int count = PrintRightOperand(data);
655 if (op == 0xD1) {
656 imm8 = 1;
657 } else if (op == 0xC1) {
658 imm8 = *(data + 1);
659 count++;
660 } else if (op == 0xD3) {
661 // Shift/rotate by cl.
662 }
663 if (imm8 >= 0) {
664 AppendToBuffer(",%d", imm8);
665 } else {
666 AppendToBuffer(",cl");
667 }
668 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000669}
670
671
672// Returns number of bytes used, including *data.
673int DisassemblerIA32::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 byte b = *(data+1);
676 byte* dest = data + static_cast<int8_t>(b) + 2;
677 AppendToBuffer("jmp %s", NameOfAddress(dest));
678 return 2;
679}
680
681
682// Returns number of bytes used, including *data.
683int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000685 byte cond = *(data+1) & 0x0F;
686 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
687 const char* mnem = jump_conditional_mnem[cond];
688 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
689 if (comment != NULL) {
690 AppendToBuffer(", %s", comment);
691 }
692 return 6; // includes 0x0F
693}
694
695
696// Returns number of bytes used, including *data.
697int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
698 byte cond = *data & 0x0F;
699 byte b = *(data+1);
700 byte* dest = data + static_cast<int8_t>(b) + 2;
701 const char* mnem = jump_conditional_mnem[cond];
702 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
703 if (comment != NULL) {
704 AppendToBuffer(", %s", comment);
705 }
706 return 2;
707}
708
709
710// Returns number of bytes used, including *data.
711int DisassemblerIA32::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000713 byte cond = *(data+1) & 0x0F;
714 const char* mnem = set_conditional_mnem[cond];
715 AppendToBuffer("%s ", mnem);
716 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000717 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000718}
719
720
721// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000722int DisassemblerIA32::CMov(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 DCHECK_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000724 byte cond = *(data + 1) & 0x0F;
725 const char* mnem = conditional_move_mnem[cond];
726 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
727 return 2 + op_size; // includes 0x0F
728}
729
730
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400731int DisassemblerIA32::AVXInstruction(byte* data) {
732 byte opcode = *data;
733 byte* current = data + 1;
734 if (vex_66() && vex_0f38()) {
735 int mod, regop, rm, vvvv = vex_vreg();
736 get_modrm(*current, &mod, &regop, &rm);
737 switch (opcode) {
738 case 0x99:
739 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
740 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
741 current += PrintRightXMMOperand(current);
742 break;
743 case 0xa9:
744 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
745 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
746 current += PrintRightXMMOperand(current);
747 break;
748 case 0xb9:
749 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
750 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
751 current += PrintRightXMMOperand(current);
752 break;
753 case 0x9b:
754 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
755 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
756 current += PrintRightXMMOperand(current);
757 break;
758 case 0xab:
759 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
760 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
761 current += PrintRightXMMOperand(current);
762 break;
763 case 0xbb:
764 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
765 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
766 current += PrintRightXMMOperand(current);
767 break;
768 case 0x9d:
769 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
770 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
771 current += PrintRightXMMOperand(current);
772 break;
773 case 0xad:
774 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
775 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
776 current += PrintRightXMMOperand(current);
777 break;
778 case 0xbd:
779 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
780 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
781 current += PrintRightXMMOperand(current);
782 break;
783 case 0x9f:
784 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
785 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
786 current += PrintRightXMMOperand(current);
787 break;
788 case 0xaf:
789 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
790 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
791 current += PrintRightXMMOperand(current);
792 break;
793 case 0xbf:
794 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
795 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
796 current += PrintRightXMMOperand(current);
797 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000798 case 0xf7:
799 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
800 current += PrintRightOperand(current);
801 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
802 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400803 default:
804 UnimplementedInstruction();
805 }
806 } else if (vex_f2() && vex_0f()) {
807 int mod, regop, rm, vvvv = vex_vreg();
808 get_modrm(*current, &mod, &regop, &rm);
809 switch (opcode) {
810 case 0x58:
811 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
812 NameOfXMMRegister(vvvv));
813 current += PrintRightXMMOperand(current);
814 break;
815 case 0x59:
816 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
817 NameOfXMMRegister(vvvv));
818 current += PrintRightXMMOperand(current);
819 break;
820 case 0x5c:
821 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
822 NameOfXMMRegister(vvvv));
823 current += PrintRightXMMOperand(current);
824 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 case 0x5d:
826 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
827 NameOfXMMRegister(vvvv));
828 current += PrintRightXMMOperand(current);
829 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400830 case 0x5e:
831 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
832 NameOfXMMRegister(vvvv));
833 current += PrintRightXMMOperand(current);
834 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000835 case 0x5f:
836 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
837 NameOfXMMRegister(vvvv));
838 current += PrintRightXMMOperand(current);
839 break;
840 default:
841 UnimplementedInstruction();
842 }
843 } else if (vex_f3() && vex_0f()) {
844 int mod, regop, rm, vvvv = vex_vreg();
845 get_modrm(*current, &mod, &regop, &rm);
846 switch (opcode) {
847 case 0x58:
848 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
849 NameOfXMMRegister(vvvv));
850 current += PrintRightXMMOperand(current);
851 break;
852 case 0x59:
853 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
854 NameOfXMMRegister(vvvv));
855 current += PrintRightXMMOperand(current);
856 break;
857 case 0x5c:
858 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
859 NameOfXMMRegister(vvvv));
860 current += PrintRightXMMOperand(current);
861 break;
862 case 0x5d:
863 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
864 NameOfXMMRegister(vvvv));
865 current += PrintRightXMMOperand(current);
866 break;
867 case 0x5e:
868 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
869 NameOfXMMRegister(vvvv));
870 current += PrintRightXMMOperand(current);
871 break;
872 case 0x5f:
873 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
874 NameOfXMMRegister(vvvv));
875 current += PrintRightXMMOperand(current);
876 break;
877 default:
878 UnimplementedInstruction();
879 }
880 } else if (vex_none() && vex_0f38()) {
881 int mod, regop, rm, vvvv = vex_vreg();
882 get_modrm(*current, &mod, &regop, &rm);
883 const char* mnem = "?";
884 switch (opcode) {
885 case 0xf2:
886 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
887 NameOfCPURegister(vvvv));
888 current += PrintRightOperand(current);
889 break;
890 case 0xf5:
891 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
892 current += PrintRightOperand(current);
893 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
894 break;
895 case 0xf7:
896 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
897 current += PrintRightOperand(current);
898 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
899 break;
900 case 0xf3:
901 switch (regop) {
902 case 1:
903 mnem = "blsr";
904 break;
905 case 2:
906 mnem = "blsmsk";
907 break;
908 case 3:
909 mnem = "blsi";
910 break;
911 default:
912 UnimplementedInstruction();
913 }
914 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
915 current += PrintRightOperand(current);
916 mnem = "?";
917 break;
918 default:
919 UnimplementedInstruction();
920 }
921 } else if (vex_f2() && vex_0f38()) {
922 int mod, regop, rm, vvvv = vex_vreg();
923 get_modrm(*current, &mod, &regop, &rm);
924 switch (opcode) {
925 case 0xf5:
926 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
927 NameOfCPURegister(vvvv));
928 current += PrintRightOperand(current);
929 break;
930 case 0xf6:
931 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
932 NameOfCPURegister(vvvv));
933 current += PrintRightOperand(current);
934 break;
935 case 0xf7:
936 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
937 current += PrintRightOperand(current);
938 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
939 break;
940 default:
941 UnimplementedInstruction();
942 }
943 } else if (vex_f3() && vex_0f38()) {
944 int mod, regop, rm, vvvv = vex_vreg();
945 get_modrm(*current, &mod, &regop, &rm);
946 switch (opcode) {
947 case 0xf5:
948 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
949 NameOfCPURegister(vvvv));
950 current += PrintRightOperand(current);
951 break;
952 case 0xf7:
953 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
954 current += PrintRightOperand(current);
955 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
956 break;
957 default:
958 UnimplementedInstruction();
959 }
960 } else if (vex_f2() && vex_0f3a()) {
961 int mod, regop, rm;
962 get_modrm(*current, &mod, &regop, &rm);
963 switch (opcode) {
964 case 0xf0:
965 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
966 current += PrintRightOperand(current);
967 AppendToBuffer(",%d", *current & 0x1f);
968 current += 1;
969 break;
970 default:
971 UnimplementedInstruction();
972 }
973 } else if (vex_none() && vex_0f()) {
974 int mod, regop, rm, vvvv = vex_vreg();
975 get_modrm(*current, &mod, &regop, &rm);
976 switch (opcode) {
977 case 0x54:
978 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
979 NameOfXMMRegister(vvvv));
980 current += PrintRightXMMOperand(current);
981 break;
982 case 0x57:
983 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
984 NameOfXMMRegister(vvvv));
985 current += PrintRightXMMOperand(current);
986 break;
987 default:
988 UnimplementedInstruction();
989 }
990 } else if (vex_66() && vex_0f()) {
991 int mod, regop, rm, vvvv = vex_vreg();
992 get_modrm(*current, &mod, &regop, &rm);
993 switch (opcode) {
994 case 0x54:
995 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
996 NameOfXMMRegister(vvvv));
997 current += PrintRightXMMOperand(current);
998 break;
999 case 0x57:
1000 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1001 NameOfXMMRegister(vvvv));
1002 current += PrintRightXMMOperand(current);
1003 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001004 default:
1005 UnimplementedInstruction();
1006 }
1007 } else {
1008 UnimplementedInstruction();
1009 }
1010
1011 return static_cast<int>(current - data);
1012}
1013
1014
Steve Block3ce2e202009-11-05 08:53:23 +00001015// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +00001016int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001017 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001018 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001019 byte modrm_byte = *(data+1);
1020
1021 if (modrm_byte >= 0xC0) {
1022 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1023 } else {
1024 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 }
Steve Blockd0582a62009-12-15 09:54:21 +00001026}
1027
1028int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
1029 int modrm_byte,
1030 byte* modrm_start) {
1031 const char* mnem = "?";
1032 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1033 switch (escape_opcode) {
1034 case 0xD9: switch (regop) {
1035 case 0: mnem = "fld_s"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001036 case 2: mnem = "fst_s"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001037 case 3: mnem = "fstp_s"; break;
1038 case 7: mnem = "fstcw"; break;
1039 default: UnimplementedInstruction();
1040 }
1041 break;
1042
1043 case 0xDB: switch (regop) {
1044 case 0: mnem = "fild_s"; break;
1045 case 1: mnem = "fisttp_s"; break;
1046 case 2: mnem = "fist_s"; break;
1047 case 3: mnem = "fistp_s"; break;
1048 default: UnimplementedInstruction();
1049 }
1050 break;
1051
1052 case 0xDD: switch (regop) {
1053 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001054 case 1: mnem = "fisttp_d"; break;
1055 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001056 case 3: mnem = "fstp_d"; break;
1057 default: UnimplementedInstruction();
1058 }
1059 break;
1060
1061 case 0xDF: switch (regop) {
1062 case 5: mnem = "fild_d"; break;
1063 case 7: mnem = "fistp_d"; break;
1064 default: UnimplementedInstruction();
1065 }
1066 break;
1067
1068 default: UnimplementedInstruction();
1069 }
1070 AppendToBuffer("%s ", mnem);
1071 int count = PrintRightOperand(modrm_start);
1072 return count + 1;
1073}
1074
1075int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1076 byte modrm_byte) {
1077 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1078 const char* mnem = "?";
1079
1080 switch (escape_opcode) {
1081 case 0xD8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082 has_register = true;
1083 switch (modrm_byte & 0xF8) {
1084 case 0xC0: mnem = "fadd_i"; break;
1085 case 0xE0: mnem = "fsub_i"; break;
1086 case 0xC8: mnem = "fmul_i"; break;
1087 case 0xF0: mnem = "fdiv_i"; break;
1088 default: UnimplementedInstruction();
1089 }
Steve Blockd0582a62009-12-15 09:54:21 +00001090 break;
1091
1092 case 0xD9:
1093 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001094 case 0xC0:
1095 mnem = "fld";
1096 has_register = true;
1097 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001098 case 0xC8:
1099 mnem = "fxch";
1100 has_register = true;
1101 break;
1102 default:
1103 switch (modrm_byte) {
1104 case 0xE0: mnem = "fchs"; break;
1105 case 0xE1: mnem = "fabs"; break;
1106 case 0xE4: mnem = "ftst"; break;
1107 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001108 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001109 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001110 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001111 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001112 case 0xF1: mnem = "fyl2x"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001113 case 0xF4: mnem = "fxtract"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001114 case 0xF5: mnem = "fprem1"; break;
1115 case 0xF7: mnem = "fincstp"; break;
1116 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001117 case 0xFC: mnem = "frndint"; break;
1118 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001119 case 0xFE: mnem = "fsin"; break;
1120 case 0xFF: mnem = "fcos"; break;
1121 default: UnimplementedInstruction();
1122 }
1123 }
1124 break;
1125
1126 case 0xDA:
1127 if (modrm_byte == 0xE9) {
1128 mnem = "fucompp";
1129 } else {
1130 UnimplementedInstruction();
1131 }
1132 break;
1133
1134 case 0xDB:
1135 if ((modrm_byte & 0xF8) == 0xE8) {
1136 mnem = "fucomi";
1137 has_register = true;
1138 } else if (modrm_byte == 0xE2) {
1139 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001140 } else if (modrm_byte == 0xE3) {
1141 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001142 } else {
1143 UnimplementedInstruction();
1144 }
1145 break;
1146
1147 case 0xDC:
1148 has_register = true;
1149 switch (modrm_byte & 0xF8) {
1150 case 0xC0: mnem = "fadd"; break;
1151 case 0xE8: mnem = "fsub"; break;
1152 case 0xC8: mnem = "fmul"; break;
1153 case 0xF8: mnem = "fdiv"; break;
1154 default: UnimplementedInstruction();
1155 }
1156 break;
1157
1158 case 0xDD:
1159 has_register = true;
1160 switch (modrm_byte & 0xF8) {
1161 case 0xC0: mnem = "ffree"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001162 case 0xD0: mnem = "fst"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001163 case 0xD8: mnem = "fstp"; break;
1164 default: UnimplementedInstruction();
1165 }
1166 break;
1167
1168 case 0xDE:
1169 if (modrm_byte == 0xD9) {
1170 mnem = "fcompp";
1171 } else {
1172 has_register = true;
1173 switch (modrm_byte & 0xF8) {
1174 case 0xC0: mnem = "faddp"; break;
1175 case 0xE8: mnem = "fsubp"; break;
1176 case 0xC8: mnem = "fmulp"; break;
1177 case 0xF8: mnem = "fdivp"; break;
1178 default: UnimplementedInstruction();
1179 }
1180 }
1181 break;
1182
1183 case 0xDF:
1184 if (modrm_byte == 0xE0) {
1185 mnem = "fnstsw_ax";
1186 } else if ((modrm_byte & 0xF8) == 0xE8) {
1187 mnem = "fucomip";
1188 has_register = true;
1189 }
1190 break;
1191
1192 default: UnimplementedInstruction();
1193 }
1194
1195 if (has_register) {
1196 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1197 } else {
1198 AppendToBuffer("%s", mnem);
1199 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 return 2;
1201}
1202
1203
1204// Mnemonics for instructions 0xF0 byte.
1205// Returns NULL if the instruction is not handled here.
1206static const char* F0Mnem(byte f0byte) {
1207 switch (f0byte) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001208 case 0x0B:
1209 return "ud2";
Ben Murdochda12d292016-06-02 14:46:10 +01001210 case 0x18:
1211 return "prefetch";
1212 case 0xA2:
1213 return "cpuid";
1214 case 0xBE:
1215 return "movsx_b";
1216 case 0xBF:
1217 return "movsx_w";
1218 case 0xB6:
1219 return "movzx_b";
1220 case 0xB7:
1221 return "movzx_w";
1222 case 0xAF:
1223 return "imul";
1224 case 0xA4:
1225 return "shld";
1226 case 0xA5:
1227 return "shld";
1228 case 0xAD:
1229 return "shrd";
1230 case 0xAC:
1231 return "shrd"; // 3-operand version.
1232 case 0xAB:
1233 return "bts";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 case 0xBC:
1235 return "bsf";
Ben Murdochda12d292016-06-02 14:46:10 +01001236 case 0xBD:
1237 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 default: return NULL;
1239 }
1240}
1241
1242
1243// Disassembled instruction '*instr' and writes it into 'out_buffer'.
1244int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1245 byte* instr) {
1246 tmp_buffer_pos_ = 0; // starting to write as position 0
1247 byte* data = instr;
1248 // Check for hints.
1249 const char* branch_hint = NULL;
1250 // We use these two prefixes only with branch prediction
1251 if (*data == 0x3E /*ds*/) {
1252 branch_hint = "predicted taken";
1253 data++;
1254 } else if (*data == 0x2E /*cs*/) {
1255 branch_hint = "predicted not taken";
1256 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001257 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1258 vex_byte0_ = *data;
1259 vex_byte1_ = *(data + 1);
1260 vex_byte2_ = *(data + 2);
1261 data += 3;
1262 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1263 vex_byte0_ = *data;
1264 vex_byte1_ = *(data + 1);
1265 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001267
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 bool processed = true; // Will be set to false if the current instruction
1269 // is not in 'instructions' table.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001270 // Decode AVX instructions.
1271 if (vex_byte0_ != 0) {
1272 data += AVXInstruction(data);
1273 } else {
1274 const InstructionDesc& idesc = instruction_table_->Get(*data);
1275 switch (idesc.type) {
1276 case ZERO_OPERANDS_INSTR:
1277 AppendToBuffer(idesc.mnem);
1278 data++;
1279 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001280
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001281 case TWO_OPERANDS_INSTR:
1282 data++;
1283 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1284 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001285
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001286 case JUMP_CONDITIONAL_SHORT_INSTR:
1287 data += JumpConditionalShort(data, branch_hint);
1288 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001289
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001290 case REGISTER_INSTR:
1291 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1292 data++;
1293 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001294
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001295 case MOVE_REG_INSTR: {
1296 byte* addr =
1297 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1298 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1299 NameOfAddress(addr));
1300 data += 5;
1301 break;
1302 }
1303
1304 case CALL_JUMP_INSTR: {
1305 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1306 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1307 data += 5;
1308 break;
1309 }
1310
1311 case SHORT_IMMEDIATE_INSTR: {
1312 byte* addr =
1313 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1314 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1315 data += 5;
1316 break;
1317 }
1318
1319 case BYTE_IMMEDIATE_INSTR: {
1320 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1321 data += 2;
1322 break;
1323 }
1324
1325 case NO_INSTR:
1326 processed = false;
1327 break;
1328
1329 default:
1330 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001332 }
1333 //----------------------------
1334 if (!processed) {
1335 switch (*data) {
1336 case 0xC2:
1337 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1338 data += 3;
1339 break;
1340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001341 case 0x6B: {
1342 data++;
1343 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1344 AppendToBuffer(",%d", *data);
1345 data++;
1346 } break;
1347
1348 case 0x69: {
1349 data++;
1350 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1351 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1352 data += 4;
Steve Blocka7e24c12009-10-30 11:49:00 +00001353 }
1354 break;
1355
1356 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001357 { data++;
1358 int mod, regop, rm;
1359 get_modrm(*data, &mod, &regop, &rm);
1360 if (regop == eax) {
1361 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +01001362 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001363 int32_t imm = *data;
1364 AppendToBuffer(",0x%x", imm);
1365 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001366 } else {
1367 UnimplementedInstruction();
1368 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 }
1370 break;
1371
1372 case 0x81: // fall through
1373 case 0x83: // 0x81 with sign extension bit set
1374 data += PrintImmediateOp(data);
1375 break;
1376
1377 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001378 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +00001379 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001380 if (f0byte == 0x18) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001381 data += 2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001382 int mod, regop, rm;
1383 get_modrm(*data, &mod, &regop, &rm);
1384 const char* suffix[] = {"nta", "1", "2", "3"};
1385 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1386 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001387 } else if (f0byte == 0x1F && data[2] == 0) {
1388 AppendToBuffer("nop"); // 3 byte nop.
1389 data += 3;
1390 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1391 AppendToBuffer("nop"); // 4 byte nop.
1392 data += 4;
1393 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1394 data[4] == 0) {
1395 AppendToBuffer("nop"); // 5 byte nop.
1396 data += 5;
1397 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1398 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1399 AppendToBuffer("nop"); // 7 byte nop.
1400 data += 7;
1401 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1402 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1403 data[7] == 0) {
1404 AppendToBuffer("nop"); // 8 byte nop.
1405 data += 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001406 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001407 AppendToBuffer("%s", f0mnem);
1408 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001409 } else if (f0byte == 0x28) {
1410 data += 2;
1411 int mod, regop, rm;
1412 get_modrm(*data, &mod, &regop, &rm);
1413 AppendToBuffer("movaps %s,%s",
1414 NameOfXMMRegister(regop),
1415 NameOfXMMRegister(rm));
1416 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001417 } else if (f0byte == 0x2e) {
1418 data += 2;
1419 int mod, regop, rm;
1420 get_modrm(*data, &mod, &regop, &rm);
1421 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1422 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1424 const char* const pseudo_op[] = {
1425 "rcpps",
1426 "andps",
1427 "andnps",
1428 "orps",
1429 "xorps",
1430 "addps",
1431 "mulps",
1432 "cvtps2pd",
1433 "cvtdq2ps",
1434 "subps",
1435 "minps",
1436 "divps",
1437 "maxps",
1438 };
1439
Ben Murdoch257744e2011-11-30 15:57:28 +00001440 data += 2;
1441 int mod, regop, rm;
1442 get_modrm(*data, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 AppendToBuffer("%s %s,",
1444 pseudo_op[f0byte - 0x53],
1445 NameOfXMMRegister(regop));
1446 data += PrintRightXMMOperand(data);
1447 } else if (f0byte == 0x50) {
1448 data += 2;
1449 int mod, regop, rm;
1450 get_modrm(*data, &mod, &regop, &rm);
1451 AppendToBuffer("movmskps %s,%s",
1452 NameOfCPURegister(regop),
Ben Murdoch257744e2011-11-30 15:57:28 +00001453 NameOfXMMRegister(rm));
1454 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001455 } else if (f0byte== 0xC6) {
1456 // shufps xmm, xmm/m128, imm8
1457 data += 2;
1458 int mod, regop, rm;
1459 get_modrm(*data, &mod, &regop, &rm);
1460 int8_t imm8 = static_cast<int8_t>(data[1]);
1461 AppendToBuffer("shufps %s,%s,%d",
1462 NameOfXMMRegister(rm),
1463 NameOfXMMRegister(regop),
1464 static_cast<int>(imm8));
1465 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001466 } else if ((f0byte & 0xF0) == 0x80) {
1467 data += JumpConditional(data, branch_hint);
1468 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1469 f0byte == 0xB7 || f0byte == 0xAF) {
1470 data += 2;
1471 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1472 } else if ((f0byte & 0xF0) == 0x90) {
1473 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001474 } else if ((f0byte & 0xF0) == 0x40) {
1475 data += CMov(data);
Ben Murdochda12d292016-06-02 14:46:10 +01001476 } else if (f0byte == 0xA4 || f0byte == 0xAC) {
1477 // shld, shrd
1478 data += 2;
1479 AppendToBuffer("%s ", f0mnem);
1480 int mod, regop, rm;
1481 get_modrm(*data, &mod, &regop, &rm);
1482 int8_t imm8 = static_cast<int8_t>(data[1]);
1483 data += 2;
1484 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
1485 NameOfCPURegister(regop), static_cast<int>(imm8));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
Ben Murdochda12d292016-06-02 14:46:10 +01001487 // shrd_cl, shld_cl, bts
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001489 AppendToBuffer("%s ", f0mnem);
1490 int mod, regop, rm;
1491 get_modrm(*data, &mod, &regop, &rm);
1492 data += PrintRightOperand(data);
1493 if (f0byte == 0xAB) {
1494 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001495 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001497 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001498 } else if (f0byte == 0xBC) {
1499 data += 2;
1500 int mod, regop, rm;
1501 get_modrm(*data, &mod, &regop, &rm);
1502 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1503 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504 } else if (f0byte == 0xBD) {
1505 data += 2;
1506 int mod, regop, rm;
1507 get_modrm(*data, &mod, &regop, &rm);
1508 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1509 data += PrintRightOperand(data);
1510 } else {
1511 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +00001512 }
1513 }
1514 break;
1515
1516 case 0x8F:
1517 { data++;
1518 int mod, regop, rm;
1519 get_modrm(*data, &mod, &regop, &rm);
1520 if (regop == eax) {
1521 AppendToBuffer("pop ");
1522 data += PrintRightOperand(data);
1523 }
1524 }
1525 break;
1526
1527 case 0xFF:
1528 { data++;
1529 int mod, regop, rm;
1530 get_modrm(*data, &mod, &regop, &rm);
1531 const char* mnem = NULL;
1532 switch (regop) {
1533 case esi: mnem = "push"; break;
1534 case eax: mnem = "inc"; break;
1535 case ecx: mnem = "dec"; break;
1536 case edx: mnem = "call"; break;
1537 case esp: mnem = "jmp"; break;
1538 default: mnem = "???";
1539 }
1540 AppendToBuffer("%s ", mnem);
1541 data += PrintRightOperand(data);
1542 }
1543 break;
1544
1545 case 0xC7: // imm32, fall through
1546 case 0xC6: // imm8
1547 { bool is_byte = *data == 0xC6;
1548 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001549 if (is_byte) {
1550 AppendToBuffer("%s ", "mov_b");
1551 data += PrintRightByteOperand(data);
1552 int32_t imm = *data;
1553 AppendToBuffer(",0x%x", imm);
1554 data++;
1555 } else {
1556 AppendToBuffer("%s ", "mov");
1557 data += PrintRightOperand(data);
1558 int32_t imm = *reinterpret_cast<int32_t*>(data);
1559 AppendToBuffer(",0x%x", imm);
1560 data += 4;
1561 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 }
1563 break;
1564
1565 case 0x80:
1566 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001567 int mod, regop, rm;
1568 get_modrm(*data, &mod, &regop, &rm);
1569 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001570 switch (regop) {
1571 case 5: mnem = "subb"; break;
1572 case 7: mnem = "cmpb"; break;
1573 default: UnimplementedInstruction();
1574 }
1575 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001576 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001577 int32_t imm = *data;
1578 AppendToBuffer(",0x%x", imm);
1579 data++;
1580 }
1581 break;
1582
1583 case 0x88: // 8bit, fall through
1584 case 0x89: // 32bit
1585 { bool is_byte = *data == 0x88;
1586 int mod, regop, rm;
1587 data++;
1588 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001589 if (is_byte) {
1590 AppendToBuffer("%s ", "mov_b");
1591 data += PrintRightByteOperand(data);
1592 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1593 } else {
1594 AppendToBuffer("%s ", "mov");
1595 data += PrintRightOperand(data);
1596 AppendToBuffer(",%s", NameOfCPURegister(regop));
1597 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001598 }
1599 break;
1600
1601 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001602 while (*data == 0x66) data++;
1603 if (*data == 0xf && data[1] == 0x1f) {
1604 AppendToBuffer("nop"); // 0x66 prefix
1605 } else if (*data == 0x90) {
1606 AppendToBuffer("nop"); // 0x66 prefix
1607 } else if (*data == 0x8B) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001608 data++;
1609 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1610 } else if (*data == 0x89) {
1611 data++;
1612 int mod, regop, rm;
1613 get_modrm(*data, &mod, &regop, &rm);
1614 AppendToBuffer("mov_w ");
1615 data += PrintRightOperand(data);
1616 AppendToBuffer(",%s", NameOfCPURegister(regop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001617 } else if (*data == 0xC7) {
1618 data++;
1619 AppendToBuffer("%s ", "mov_w");
1620 data += PrintRightOperand(data);
1621 int imm = *reinterpret_cast<int16_t*>(data);
1622 AppendToBuffer(",0x%x", imm);
1623 data += 2;
Ben Murdochda12d292016-06-02 14:46:10 +01001624 } else if (*data == 0xF7) {
1625 data++;
1626 AppendToBuffer("%s ", "test_w");
1627 data += PrintRightOperand(data);
1628 int imm = *reinterpret_cast<int16_t*>(data);
1629 AppendToBuffer(",0x%x", imm);
1630 data += 2;
Steve Block3ce2e202009-11-05 08:53:23 +00001631 } else if (*data == 0x0F) {
1632 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001633 if (*data == 0x38) {
1634 data++;
1635 if (*data == 0x17) {
1636 data++;
1637 int mod, regop, rm;
1638 get_modrm(*data, &mod, &regop, &rm);
1639 AppendToBuffer("ptest %s,%s",
1640 NameOfXMMRegister(regop),
1641 NameOfXMMRegister(rm));
1642 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001643 } else if (*data == 0x2A) {
1644 // movntdqa
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001645 UnimplementedInstruction();
Steve Block6ded16b2010-05-10 14:33:55 +01001646 } else {
1647 UnimplementedInstruction();
1648 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001649 } else if (*data == 0x3A) {
1650 data++;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001651 if (*data == 0x0A) {
1652 data++;
1653 int mod, regop, rm;
1654 get_modrm(*data, &mod, &regop, &rm);
1655 int8_t imm8 = static_cast<int8_t>(data[1]);
1656 AppendToBuffer("roundss %s,%s,%d", NameOfXMMRegister(regop),
1657 NameOfXMMRegister(rm), static_cast<int>(imm8));
1658 data += 2;
1659 } else if (*data == 0x0B) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001660 data++;
1661 int mod, regop, rm;
1662 get_modrm(*data, &mod, &regop, &rm);
1663 int8_t imm8 = static_cast<int8_t>(data[1]);
1664 AppendToBuffer("roundsd %s,%s,%d",
1665 NameOfXMMRegister(regop),
1666 NameOfXMMRegister(rm),
1667 static_cast<int>(imm8));
1668 data += 2;
1669 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001670 data++;
1671 int mod, regop, rm;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001672 get_modrm(*data, &mod, &rm, &regop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001673 int8_t imm8 = static_cast<int8_t>(data[1]);
1674 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001675 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001676 NameOfXMMRegister(rm),
1677 static_cast<int>(imm8));
1678 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001679 } else if (*data == 0x17) {
1680 data++;
1681 int mod, regop, rm;
1682 get_modrm(*data, &mod, &regop, &rm);
1683 int8_t imm8 = static_cast<int8_t>(data[1]);
1684 AppendToBuffer("extractps %s,%s,%d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 NameOfCPURegister(rm),
1686 NameOfXMMRegister(regop),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001687 static_cast<int>(imm8));
1688 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001689 } else if (*data == 0x22) {
1690 data++;
1691 int mod, regop, rm;
1692 get_modrm(*data, &mod, &regop, &rm);
1693 int8_t imm8 = static_cast<int8_t>(data[1]);
1694 AppendToBuffer("pinsrd %s,%s,%d",
1695 NameOfXMMRegister(regop),
1696 NameOfCPURegister(rm),
1697 static_cast<int>(imm8));
1698 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001699 } else {
1700 UnimplementedInstruction();
1701 }
Steve Block6ded16b2010-05-10 14:33:55 +01001702 } else if (*data == 0x2E || *data == 0x2F) {
1703 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001704 data++;
1705 int mod, regop, rm;
1706 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001707 if (mod == 0x3) {
1708 AppendToBuffer("%s %s,%s", mnem,
1709 NameOfXMMRegister(regop),
1710 NameOfXMMRegister(rm));
1711 data++;
1712 } else {
1713 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1714 data += PrintRightOperand(data);
1715 }
1716 } else if (*data == 0x50) {
1717 data++;
1718 int mod, regop, rm;
1719 get_modrm(*data, &mod, &regop, &rm);
1720 AppendToBuffer("movmskpd %s,%s",
1721 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001722 NameOfXMMRegister(rm));
1723 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001724 } else if (*data == 0x54) {
1725 data++;
1726 int mod, regop, rm;
1727 get_modrm(*data, &mod, &regop, &rm);
1728 AppendToBuffer("andpd %s,%s",
1729 NameOfXMMRegister(regop),
1730 NameOfXMMRegister(rm));
1731 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001732 } else if (*data == 0x56) {
1733 data++;
1734 int mod, regop, rm;
1735 get_modrm(*data, &mod, &regop, &rm);
1736 AppendToBuffer("orpd %s,%s",
1737 NameOfXMMRegister(regop),
1738 NameOfXMMRegister(rm));
1739 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001740 } else if (*data == 0x57) {
1741 data++;
1742 int mod, regop, rm;
1743 get_modrm(*data, &mod, &regop, &rm);
1744 AppendToBuffer("xorpd %s,%s",
1745 NameOfXMMRegister(regop),
1746 NameOfXMMRegister(rm));
1747 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001748 } else if (*data == 0x6E) {
1749 data++;
1750 int mod, regop, rm;
1751 get_modrm(*data, &mod, &regop, &rm);
1752 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1753 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001754 } else if (*data == 0x6F) {
1755 data++;
1756 int mod, regop, rm;
1757 get_modrm(*data, &mod, &regop, &rm);
1758 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001759 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001760 } else if (*data == 0x70) {
1761 data++;
1762 int mod, regop, rm;
1763 get_modrm(*data, &mod, &regop, &rm);
1764 int8_t imm8 = static_cast<int8_t>(data[1]);
1765 AppendToBuffer("pshufd %s,%s,%d",
1766 NameOfXMMRegister(regop),
1767 NameOfXMMRegister(rm),
1768 static_cast<int>(imm8));
1769 data += 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001770 } else if (*data == 0x62) {
1771 data++;
1772 int mod, regop, rm;
1773 get_modrm(*data, &mod, &regop, &rm);
1774 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
1775 NameOfXMMRegister(rm));
1776 data++;
1777 } else if (*data == 0x6A) {
1778 data++;
1779 int mod, regop, rm;
1780 get_modrm(*data, &mod, &regop, &rm);
1781 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
1782 NameOfXMMRegister(rm));
1783 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001784 } else if (*data == 0x76) {
1785 data++;
1786 int mod, regop, rm;
1787 get_modrm(*data, &mod, &regop, &rm);
1788 AppendToBuffer("pcmpeqd %s,%s",
1789 NameOfXMMRegister(regop),
1790 NameOfXMMRegister(rm));
1791 data++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001792 } else if (*data == 0x90) {
1793 data++;
1794 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001795 } else if (*data == 0xF3) {
1796 data++;
1797 int mod, regop, rm;
1798 get_modrm(*data, &mod, &regop, &rm);
1799 AppendToBuffer("psllq %s,%s",
1800 NameOfXMMRegister(regop),
1801 NameOfXMMRegister(rm));
1802 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001803 } else if (*data == 0x72) {
1804 data++;
1805 int mod, regop, rm;
1806 get_modrm(*data, &mod, &regop, &rm);
1807 int8_t imm8 = static_cast<int8_t>(data[1]);
1808 DCHECK(regop == esi || regop == edx);
1809 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1810 NameOfXMMRegister(rm), static_cast<int>(imm8));
1811 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001812 } else if (*data == 0x73) {
1813 data++;
1814 int mod, regop, rm;
1815 get_modrm(*data, &mod, &regop, &rm);
1816 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001817 DCHECK(regop == esi || regop == edx);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001818 AppendToBuffer("%s %s,%d",
1819 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001820 NameOfXMMRegister(rm),
1821 static_cast<int>(imm8));
1822 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001823 } else if (*data == 0xD3) {
1824 data++;
1825 int mod, regop, rm;
1826 get_modrm(*data, &mod, &regop, &rm);
1827 AppendToBuffer("psrlq %s,%s",
1828 NameOfXMMRegister(regop),
1829 NameOfXMMRegister(rm));
1830 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001831 } else if (*data == 0x7F) {
1832 AppendToBuffer("movdqa ");
1833 data++;
1834 int mod, regop, rm;
1835 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001836 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001837 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001838 } else if (*data == 0x7E) {
1839 data++;
1840 int mod, regop, rm;
1841 get_modrm(*data, &mod, &regop, &rm);
1842 AppendToBuffer("movd ");
1843 data += PrintRightOperand(data);
1844 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1845 } else if (*data == 0xDB) {
1846 data++;
1847 int mod, regop, rm;
1848 get_modrm(*data, &mod, &regop, &rm);
1849 AppendToBuffer("pand %s,%s",
1850 NameOfXMMRegister(regop),
1851 NameOfXMMRegister(rm));
1852 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001853 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001854 data++;
1855 int mod, regop, rm;
1856 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001857 if (mod == 3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001858 // movntdq
1859 UnimplementedInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +01001860 } else {
1861 UnimplementedInstruction();
1862 }
Steve Block6ded16b2010-05-10 14:33:55 +01001863 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001864 data++;
1865 int mod, regop, rm;
1866 get_modrm(*data, &mod, &regop, &rm);
1867 AppendToBuffer("pxor %s,%s",
1868 NameOfXMMRegister(regop),
1869 NameOfXMMRegister(rm));
1870 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001871 } else if (*data == 0xEB) {
1872 data++;
1873 int mod, regop, rm;
1874 get_modrm(*data, &mod, &regop, &rm);
1875 AppendToBuffer("por %s,%s",
1876 NameOfXMMRegister(regop),
1877 NameOfXMMRegister(rm));
1878 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001879 } else {
1880 UnimplementedInstruction();
1881 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001882 } else {
1883 UnimplementedInstruction();
1884 }
1885 break;
1886
1887 case 0xFE:
1888 { data++;
1889 int mod, regop, rm;
1890 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001891 if (regop == ecx) {
1892 AppendToBuffer("dec_b ");
1893 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001894 } else {
1895 UnimplementedInstruction();
1896 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001897 }
1898 break;
1899
1900 case 0x68:
1901 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1902 data += 5;
1903 break;
1904
1905 case 0x6A:
1906 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1907 data += 2;
1908 break;
1909
1910 case 0xA8:
1911 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1912 data += 2;
1913 break;
1914
1915 case 0xA9:
1916 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1917 data += 5;
1918 break;
1919
1920 case 0xD1: // fall through
1921 case 0xD3: // fall through
1922 case 0xC1:
1923 data += D1D3C1Instruction(data);
1924 break;
1925
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 case 0xD8: // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001927 case 0xD9: // fall through
1928 case 0xDA: // fall through
1929 case 0xDB: // fall through
1930 case 0xDC: // fall through
1931 case 0xDD: // fall through
1932 case 0xDE: // fall through
1933 case 0xDF:
1934 data += FPUInstruction(data);
1935 break;
1936
1937 case 0xEB:
1938 data += JumpShort(data);
1939 break;
1940
1941 case 0xF2:
1942 if (*(data+1) == 0x0F) {
1943 byte b2 = *(data+2);
1944 if (b2 == 0x11) {
1945 AppendToBuffer("movsd ");
1946 data += 3;
1947 int mod, regop, rm;
1948 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001949 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1951 } else if (b2 == 0x10) {
1952 data += 3;
1953 int mod, regop, rm;
1954 get_modrm(*data, &mod, &regop, &rm);
1955 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001956 data += PrintRightXMMOperand(data);
1957 } else if (b2 == 0x5A) {
1958 data += 3;
1959 int mod, regop, rm;
1960 get_modrm(*data, &mod, &regop, &rm);
1961 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1962 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001963 } else {
1964 const char* mnem = "?";
1965 switch (b2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001966 case 0x2A:
1967 mnem = "cvtsi2sd";
1968 break;
1969 case 0x2C:
1970 mnem = "cvttsd2si";
1971 break;
1972 case 0x2D:
1973 mnem = "cvtsd2si";
1974 break;
1975 case 0x51:
1976 mnem = "sqrtsd";
1977 break;
1978 case 0x58:
1979 mnem = "addsd";
1980 break;
1981 case 0x59:
1982 mnem = "mulsd";
1983 break;
1984 case 0x5C:
1985 mnem = "subsd";
1986 break;
1987 case 0x5D:
1988 mnem = "minsd";
1989 break;
1990 case 0x5E:
1991 mnem = "divsd";
1992 break;
1993 case 0x5F:
1994 mnem = "maxsd";
1995 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001996 }
1997 data += 3;
1998 int mod, regop, rm;
1999 get_modrm(*data, &mod, &regop, &rm);
2000 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01002001 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2002 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003 } else if (b2 == 0x2C || b2 == 0x2D) {
Steve Block44f0eee2011-05-26 01:26:41 +01002004 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2005 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002006 } else if (b2 == 0xC2) {
2007 // Intel manual 2A, Table 3-18.
2008 const char* const pseudo_op[] = {
2009 "cmpeqsd",
2010 "cmpltsd",
2011 "cmplesd",
2012 "cmpunordsd",
2013 "cmpneqsd",
2014 "cmpnltsd",
2015 "cmpnlesd",
2016 "cmpordsd"
2017 };
2018 AppendToBuffer("%s %s,%s",
2019 pseudo_op[data[1]],
2020 NameOfXMMRegister(regop),
2021 NameOfXMMRegister(rm));
2022 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00002023 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002024 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2025 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002026 }
2027 }
2028 } else {
2029 UnimplementedInstruction();
2030 }
2031 break;
2032
2033 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00002034 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01002035 byte b2 = *(data+2);
2036 if (b2 == 0x11) {
2037 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01002038 data += 3;
2039 int mod, regop, rm;
2040 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002041 data += PrintRightXMMOperand(data);
2042 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2043 } else if (b2 == 0x10) {
2044 data += 3;
2045 int mod, regop, rm;
2046 get_modrm(*data, &mod, &regop, &rm);
2047 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2048 data += PrintRightXMMOperand(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002049 } else if (b2 == 0x5A) {
2050 data += 3;
2051 int mod, regop, rm;
2052 get_modrm(*data, &mod, &regop, &rm);
2053 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2054 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002055 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002056 data += 3;
2057 int mod, regop, rm;
2058 get_modrm(*data, &mod, &regop, &rm);
2059 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01002060 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002061 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002062 AppendToBuffer("movdqu ");
2063 data += 3;
2064 int mod, regop, rm;
2065 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002066 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002067 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002068 } else if (b2 == 0xB8) {
2069 data += 3;
2070 int mod, regop, rm;
2071 get_modrm(*data, &mod, &regop, &rm);
2072 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2073 data += PrintRightOperand(data);
2074 } else if (b2 == 0xBC) {
2075 data += 3;
2076 int mod, regop, rm;
2077 get_modrm(*data, &mod, &regop, &rm);
2078 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2079 data += PrintRightOperand(data);
2080 } else if (b2 == 0xBD) {
2081 data += 3;
2082 int mod, regop, rm;
2083 get_modrm(*data, &mod, &regop, &rm);
2084 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2085 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002086 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002087 const char* mnem = "?";
2088 switch (b2) {
2089 case 0x2A:
2090 mnem = "cvtsi2ss";
2091 break;
2092 case 0x2C:
2093 mnem = "cvttss2si";
2094 break;
2095 case 0x2D:
2096 mnem = "cvtss2si";
2097 break;
2098 case 0x51:
2099 mnem = "sqrtss";
2100 break;
2101 case 0x58:
2102 mnem = "addss";
2103 break;
2104 case 0x59:
2105 mnem = "mulss";
2106 break;
2107 case 0x5C:
2108 mnem = "subss";
2109 break;
2110 case 0x5D:
2111 mnem = "minss";
2112 break;
2113 case 0x5E:
2114 mnem = "divss";
2115 break;
2116 case 0x5F:
2117 mnem = "maxss";
2118 break;
2119 }
2120 data += 3;
2121 int mod, regop, rm;
2122 get_modrm(*data, &mod, &regop, &rm);
2123 if (b2 == 0x2A) {
2124 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2125 data += PrintRightOperand(data);
2126 } else if (b2 == 0x2C || b2 == 0x2D) {
2127 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2128 data += PrintRightXMMOperand(data);
2129 } else if (b2 == 0xC2) {
2130 // Intel manual 2A, Table 3-18.
2131 const char* const pseudo_op[] = {
2132 "cmpeqss", "cmpltss", "cmpless", "cmpunordss",
2133 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2134 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2135 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2136 data += 2;
2137 } else {
2138 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2139 data += PrintRightXMMOperand(data);
2140 }
Leon Clarkee46be812010-01-19 14:06:41 +00002141 }
2142 } else if (*(data+1) == 0xA5) {
2143 data += 2;
2144 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01002145 } else if (*(data+1) == 0xAB) {
2146 data += 2;
2147 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00002148 } else {
2149 UnimplementedInstruction();
2150 }
2151 break;
2152
2153 case 0xF7:
2154 data += F7Instruction(data);
2155 break;
2156
2157 default:
2158 UnimplementedInstruction();
2159 }
2160 }
2161
2162 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2163 tmp_buffer_[tmp_buffer_pos_] = '\0';
2164 }
2165
2166 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00002167 if (instr_len == 0) {
2168 printf("%02x", *data);
2169 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002170 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002171
2172 int outp = 0;
2173 // Instruction bytes.
2174 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002175 outp += v8::internal::SNPrintF(out_buffer + outp,
2176 "%02x",
2177 *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002178 }
2179 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002180 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002181 }
2182
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002183 outp += v8::internal::SNPrintF(out_buffer + outp,
2184 " %s",
2185 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002186 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002187} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00002188
2189
2190//------------------------------------------------------------------------------
2191
2192
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002193static const char* const cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002194 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
2195};
2196
2197
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002198static const char* const byte_cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002199 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
2200};
2201
2202
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002203static const char* const xmm_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002204 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
2205};
2206
2207
2208const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002209 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002210 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002211}
2212
2213
2214const char* NameConverter::NameOfConstant(byte* addr) const {
2215 return NameOfAddress(addr);
2216}
2217
2218
2219const char* NameConverter::NameOfCPURegister(int reg) const {
2220 if (0 <= reg && reg < 8) return cpu_regs[reg];
2221 return "noreg";
2222}
2223
2224
2225const char* NameConverter::NameOfByteCPURegister(int reg) const {
2226 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2227 return "noreg";
2228}
2229
2230
2231const char* NameConverter::NameOfXMMRegister(int reg) const {
2232 if (0 <= reg && reg < 8) return xmm_regs[reg];
2233 return "noxmmreg";
2234}
2235
2236
2237const char* NameConverter::NameInCode(byte* addr) const {
2238 // IA32 does not embed debug strings at the moment.
2239 UNREACHABLE();
2240 return "";
2241}
2242
2243
2244//------------------------------------------------------------------------------
2245
2246Disassembler::Disassembler(const NameConverter& converter)
2247 : converter_(converter) {}
2248
2249
2250Disassembler::~Disassembler() {}
2251
2252
2253int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2254 byte* instruction) {
2255 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
2256 return d.InstructionDecode(buffer, instruction);
2257}
2258
2259
2260// The IA-32 assembler does not currently use constant pools.
2261int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2262
2263
2264/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2265 NameConverter converter;
2266 Disassembler d(converter);
2267 for (byte* pc = begin; pc < end;) {
2268 v8::internal::EmbeddedVector<char, 128> buffer;
2269 buffer[0] = '\0';
2270 byte* prev_pc = pc;
2271 pc += d.InstructionDecode(buffer, pc);
2272 fprintf(f, "%p", prev_pc);
2273 fprintf(f, " ");
2274
2275 for (byte* bp = prev_pc; bp < pc; bp++) {
2276 fprintf(f, "%02x", *bp);
2277 }
2278 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2279 fprintf(f, " ");
2280 }
2281 fprintf(f, " %s\n", buffer.start());
2282 }
2283}
2284
2285
2286} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002287
2288#endif // V8_TARGET_ARCH_IA32