blob: b11ff97752bef4e18117001eb6c1f1d9c22e9d0f [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 Murdoch097c5b22016-05-18 11:27:45 +010032 {0x01, "add", OPER_REG_OP_ORDER},
33 {0x03, "add", REG_OPER_OP_ORDER},
34 {0x09, "or", OPER_REG_OP_ORDER},
35 {0x0B, "or", REG_OPER_OP_ORDER},
36 {0x1B, "sbb", REG_OPER_OP_ORDER},
37 {0x21, "and", OPER_REG_OP_ORDER},
38 {0x23, "and", REG_OPER_OP_ORDER},
39 {0x29, "sub", OPER_REG_OP_ORDER},
40 {0x2A, "subb", REG_OPER_OP_ORDER},
41 {0x2B, "sub", REG_OPER_OP_ORDER},
42 {0x31, "xor", OPER_REG_OP_ORDER},
43 {0x33, "xor", REG_OPER_OP_ORDER},
44 {0x38, "cmpb", OPER_REG_OP_ORDER},
45 {0x39, "cmp", OPER_REG_OP_ORDER},
46 {0x3A, "cmpb", REG_OPER_OP_ORDER},
47 {0x3B, "cmp", REG_OPER_OP_ORDER},
48 {0x84, "test_b", REG_OPER_OP_ORDER},
49 {0x85, "test", REG_OPER_OP_ORDER},
50 {0x87, "xchg", REG_OPER_OP_ORDER},
51 {0x8A, "mov_b", REG_OPER_OP_ORDER},
52 {0x8B, "mov", REG_OPER_OP_ORDER},
53 {0x8D, "lea", REG_OPER_OP_ORDER},
54 {-1, "", UNSET_OP_ORDER}};
Steve Blocka7e24c12009-10-30 11:49:00 +000055
Ben Murdoch69a99ed2011-11-30 16:03:39 +000056static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000057 {0xC3, "ret", UNSET_OP_ORDER},
58 {0xC9, "leave", UNSET_OP_ORDER},
59 {0x90, "nop", UNSET_OP_ORDER},
60 {0xF4, "hlt", UNSET_OP_ORDER},
61 {0xCC, "int3", UNSET_OP_ORDER},
62 {0x60, "pushad", UNSET_OP_ORDER},
63 {0x61, "popad", UNSET_OP_ORDER},
64 {0x9C, "pushfd", UNSET_OP_ORDER},
65 {0x9D, "popfd", UNSET_OP_ORDER},
66 {0x9E, "sahf", UNSET_OP_ORDER},
67 {0x99, "cdq", UNSET_OP_ORDER},
68 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010069 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010070 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000071 {-1, "", UNSET_OP_ORDER}
72};
73
74
Ben Murdoch69a99ed2011-11-30 16:03:39 +000075static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000076 {0xE8, "call", UNSET_OP_ORDER},
77 {0xE9, "jmp", UNSET_OP_ORDER},
78 {-1, "", UNSET_OP_ORDER}
79};
80
81
Ben Murdoch69a99ed2011-11-30 16:03:39 +000082static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000083 {0x05, "add", UNSET_OP_ORDER},
84 {0x0D, "or", UNSET_OP_ORDER},
85 {0x15, "adc", UNSET_OP_ORDER},
86 {0x25, "and", UNSET_OP_ORDER},
87 {0x2D, "sub", UNSET_OP_ORDER},
88 {0x35, "xor", UNSET_OP_ORDER},
89 {0x3D, "cmp", UNSET_OP_ORDER},
90 {-1, "", UNSET_OP_ORDER}
91};
92
93
Ben Murdoch3ef787d2012-04-12 10:51:47 +010094// Generally we don't want to generate these because they are subject to partial
95// register stalls. They are included for completeness and because the cmp
96// variant is used by the RecordWrite stub. Because it does not update the
97// register it is not subject to partial register stalls.
98static ByteMnemonic byte_immediate_instr[] = {
99 {0x0c, "or", UNSET_OP_ORDER},
100 {0x24, "and", UNSET_OP_ORDER},
101 {0x34, "xor", UNSET_OP_ORDER},
102 {0x3c, "cmp", UNSET_OP_ORDER},
103 {-1, "", UNSET_OP_ORDER}
104};
105
106
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000107static const char* const jump_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 /*0*/ "jo", "jno", "jc", "jnc",
109 /*4*/ "jz", "jnz", "jna", "ja",
110 /*8*/ "js", "jns", "jpe", "jpo",
111 /*12*/ "jl", "jnl", "jng", "jg"
112};
113
114
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000115static const char* const set_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000116 /*0*/ "seto", "setno", "setc", "setnc",
117 /*4*/ "setz", "setnz", "setna", "seta",
118 /*8*/ "sets", "setns", "setpe", "setpo",
119 /*12*/ "setl", "setnl", "setng", "setg"
120};
121
122
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000123static const char* const conditional_move_mnem[] = {
Steve Block3ce2e202009-11-05 08:53:23 +0000124 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
125 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
126 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
127 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
128};
129
130
Steve Blocka7e24c12009-10-30 11:49:00 +0000131enum InstructionType {
132 NO_INSTR,
133 ZERO_OPERANDS_INSTR,
134 TWO_OPERANDS_INSTR,
135 JUMP_CONDITIONAL_SHORT_INSTR,
136 REGISTER_INSTR,
137 MOVE_REG_INSTR,
138 CALL_JUMP_INSTR,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100139 SHORT_IMMEDIATE_INSTR,
140 BYTE_IMMEDIATE_INSTR
Steve Blocka7e24c12009-10-30 11:49:00 +0000141};
142
143
144struct InstructionDesc {
145 const char* mnem;
146 InstructionType type;
147 OperandOrder op_order_;
148};
149
150
151class InstructionTable {
152 public:
153 InstructionTable();
154 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100155 static InstructionTable* get_instance() {
156 static InstructionTable table;
157 return &table;
158 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000159
160 private:
161 InstructionDesc instructions_[256];
162 void Clear();
163 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000164 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 void SetTableRange(InstructionType type,
166 byte start,
167 byte end,
168 const char* mnem);
169 void AddJumpConditionalShort();
170};
171
172
173InstructionTable::InstructionTable() {
174 Clear();
175 Init();
176}
177
178
179void InstructionTable::Clear() {
180 for (int i = 0; i < 256; i++) {
181 instructions_[i].mnem = "";
182 instructions_[i].type = NO_INSTR;
183 instructions_[i].op_order_ = UNSET_OP_ORDER;
184 }
185}
186
187
188void InstructionTable::Init() {
189 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
190 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
191 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
192 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100193 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 AddJumpConditionalShort();
195 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
196 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
197 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
198 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
199 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
200 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
201}
202
203
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000204void InstructionTable::CopyTable(const ByteMnemonic bm[],
205 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000206 for (int i = 0; bm[i].b >= 0; i++) {
207 InstructionDesc* id = &instructions_[bm[i].b];
208 id->mnem = bm[i].mnem;
209 id->op_order_ = bm[i].op_order_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000210 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000211 id->type = type;
212 }
213}
214
215
216void InstructionTable::SetTableRange(InstructionType type,
217 byte start,
218 byte end,
219 const char* mnem) {
220 for (byte b = start; b <= end; b++) {
221 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000223 id->mnem = mnem;
224 id->type = type;
225 }
226}
227
228
229void InstructionTable::AddJumpConditionalShort() {
230 for (byte b = 0x70; b <= 0x7F; b++) {
231 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 id->mnem = jump_conditional_mnem[b & 0x0F];
234 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
235 }
236}
237
238
Steve Blocka7e24c12009-10-30 11:49:00 +0000239// The IA32 disassembler implementation.
240class DisassemblerIA32 {
241 public:
242 DisassemblerIA32(const NameConverter& converter,
243 bool abort_on_unimplemented = true)
244 : converter_(converter),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245 vex_byte0_(0),
246 vex_byte1_(0),
247 vex_byte2_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100248 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000249 tmp_buffer_pos_(0),
250 abort_on_unimplemented_(abort_on_unimplemented) {
251 tmp_buffer_[0] = '\0';
252 }
253
254 virtual ~DisassemblerIA32() {}
255
256 // Writes one disassembled instruction into 'buffer' (0-terminated).
257 // Returns the length of the disassembled machine instruction in bytes.
258 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
259
260 private:
261 const NameConverter& converter_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262 byte vex_byte0_; // 0xc4 or 0xc5
263 byte vex_byte1_;
264 byte vex_byte2_; // only for 3 bytes vex prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100265 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000266 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
267 unsigned int tmp_buffer_pos_;
268 bool abort_on_unimplemented_;
269
Steve Blocka7e24c12009-10-30 11:49:00 +0000270 enum {
271 eax = 0,
272 ecx = 1,
273 edx = 2,
274 ebx = 3,
275 esp = 4,
276 ebp = 5,
277 esi = 6,
278 edi = 7
279 };
280
281
Steve Blockd0582a62009-12-15 09:54:21 +0000282 enum ShiftOpcodeExtension {
283 kROL = 0,
284 kROR = 1,
285 kRCL = 2,
286 kRCR = 3,
287 kSHL = 4,
288 KSHR = 5,
289 kSAR = 7
290 };
291
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400292 bool vex_128() {
293 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
294 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
295 return (checked & 4) != 1;
296 }
297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 bool vex_none() {
299 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
300 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
301 return (checked & 3) == 0;
302 }
303
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400304 bool vex_66() {
305 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
306 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
307 return (checked & 3) == 1;
308 }
309
310 bool vex_f3() {
311 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
312 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
313 return (checked & 3) == 2;
314 }
315
316 bool vex_f2() {
317 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
318 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
319 return (checked & 3) == 3;
320 }
321
322 bool vex_w() {
323 if (vex_byte0_ == 0xc5) return false;
324 return (vex_byte2_ & 0x80) != 0;
325 }
326
327 bool vex_0f() {
328 if (vex_byte0_ == 0xc5) return true;
329 return (vex_byte1_ & 3) == 1;
330 }
331
332 bool vex_0f38() {
333 if (vex_byte0_ == 0xc5) return false;
334 return (vex_byte1_ & 3) == 2;
335 }
336
337 bool vex_0f3a() {
338 if (vex_byte0_ == 0xc5) return false;
339 return (vex_byte1_ & 3) == 3;
340 }
341
342 int vex_vreg() {
343 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
344 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
345 return ~(checked >> 3) & 0xf;
346 }
347
348 char float_size_code() { return "sd"[vex_w()]; }
Steve Blockd0582a62009-12-15 09:54:21 +0000349
Steve Blocka7e24c12009-10-30 11:49:00 +0000350 const char* NameOfCPURegister(int reg) const {
351 return converter_.NameOfCPURegister(reg);
352 }
353
354
355 const char* NameOfByteCPURegister(int reg) const {
356 return converter_.NameOfByteCPURegister(reg);
357 }
358
359
360 const char* NameOfXMMRegister(int reg) const {
361 return converter_.NameOfXMMRegister(reg);
362 }
363
364
365 const char* NameOfAddress(byte* addr) const {
366 return converter_.NameOfAddress(addr);
367 }
368
369
370 // Disassembler helper functions.
371 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
372 *mod = (data >> 6) & 3;
373 *regop = (data & 0x38) >> 3;
374 *rm = data & 7;
375 }
376
377
378 static void get_sib(byte data, int* scale, int* index, int* base) {
379 *scale = (data >> 6) & 3;
380 *index = (data >> 3) & 7;
381 *base = data & 7;
382 }
383
384 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
385
386 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
387 int PrintRightOperand(byte* modrmp);
388 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100389 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000390 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
391 int PrintImmediateOp(byte* data);
392 int F7Instruction(byte* data);
393 int D1D3C1Instruction(byte* data);
394 int JumpShort(byte* data);
395 int JumpConditional(byte* data, const char* comment);
396 int JumpConditionalShort(byte* data, const char* comment);
397 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000398 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000400 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
401 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400402 int AVXInstruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 void AppendToBuffer(const char* format, ...);
404
405
406 void UnimplementedInstruction() {
407 if (abort_on_unimplemented_) {
408 UNIMPLEMENTED();
409 } else {
410 AppendToBuffer("'Unimplemented Instruction'");
411 }
412 }
413};
414
415
416void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
417 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
418 va_list args;
419 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000420 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 va_end(args);
422 tmp_buffer_pos_ += result;
423}
424
425int DisassemblerIA32::PrintRightOperandHelper(
426 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100427 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000428 int mod, regop, rm;
429 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100430 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
431 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 switch (mod) {
433 case 0:
434 if (rm == ebp) {
435 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
436 AppendToBuffer("[0x%x]", disp);
437 return 5;
438 } else if (rm == esp) {
439 byte sib = *(modrmp + 1);
440 int scale, index, base;
441 get_sib(sib, &scale, &index, &base);
442 if (index == esp && base == esp && scale == 0 /*times_1*/) {
443 AppendToBuffer("[%s]", (this->*register_name)(rm));
444 return 2;
445 } else if (base == ebp) {
446 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 AppendToBuffer("[%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 (this->*register_name)(index),
449 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000450 disp < 0 ? "-" : "+",
451 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 return 6;
453 } else if (index != esp && base != ebp) {
454 // [base+index*scale]
455 AppendToBuffer("[%s+%s*%d]",
456 (this->*register_name)(base),
457 (this->*register_name)(index),
458 1 << scale);
459 return 2;
460 } else {
461 UnimplementedInstruction();
462 return 1;
463 }
464 } else {
465 AppendToBuffer("[%s]", (this->*register_name)(rm));
466 return 1;
467 }
468 break;
469 case 1: // fall through
470 case 2:
471 if (rm == esp) {
472 byte sib = *(modrmp + 1);
473 int scale, index, base;
474 get_sib(sib, &scale, &index, &base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
476 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478 AppendToBuffer("[%s%s0x%x]",
479 (this->*register_name)(rm),
480 disp < 0 ? "-" : "+",
481 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000482 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 AppendToBuffer("[%s+%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 (this->*register_name)(base),
485 (this->*register_name)(index),
486 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000487 disp < 0 ? "-" : "+",
488 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 }
490 return mod == 2 ? 6 : 3;
491 } else {
492 // No sib.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000493 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
494 : *reinterpret_cast<int8_t*>(modrmp + 1);
495 AppendToBuffer("[%s%s0x%x]",
496 (this->*register_name)(rm),
497 disp < 0 ? "-" : "+",
498 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 return mod == 2 ? 5 : 2;
500 }
501 break;
502 case 3:
503 AppendToBuffer("%s", (this->*register_name)(rm));
504 return 1;
505 default:
506 UnimplementedInstruction();
507 return 1;
508 }
509 UNREACHABLE();
510}
511
512
513int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
514 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
515}
516
517
518int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
519 return PrintRightOperandHelper(modrmp,
520 &DisassemblerIA32::NameOfByteCPURegister);
521}
522
523
Steve Block44f0eee2011-05-26 01:26:41 +0100524int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
525 return PrintRightOperandHelper(modrmp,
526 &DisassemblerIA32::NameOfXMMRegister);
527}
528
529
Steve Blocka7e24c12009-10-30 11:49:00 +0000530// Returns number of bytes used including the current *data.
531// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
532int DisassemblerIA32::PrintOperands(const char* mnem,
533 OperandOrder op_order,
534 byte* data) {
535 byte modrm = *data;
536 int mod, regop, rm;
537 get_modrm(modrm, &mod, &regop, &rm);
538 int advance = 0;
539 switch (op_order) {
540 case REG_OPER_OP_ORDER: {
541 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
542 advance = PrintRightOperand(data);
543 break;
544 }
545 case OPER_REG_OP_ORDER: {
546 AppendToBuffer("%s ", mnem);
547 advance = PrintRightOperand(data);
548 AppendToBuffer(",%s", NameOfCPURegister(regop));
549 break;
550 }
551 default:
552 UNREACHABLE();
553 break;
554 }
555 return advance;
556}
557
558
559// Returns number of bytes used by machine instruction, including *data byte.
560// Writes immediate instructions to 'tmp_buffer_'.
561int DisassemblerIA32::PrintImmediateOp(byte* data) {
562 bool sign_extension_bit = (*data & 0x02) != 0;
563 byte modrm = *(data+1);
564 int mod, regop, rm;
565 get_modrm(modrm, &mod, &regop, &rm);
566 const char* mnem = "Imm???";
567 switch (regop) {
568 case 0: mnem = "add"; break;
569 case 1: mnem = "or"; break;
570 case 2: mnem = "adc"; break;
571 case 4: mnem = "and"; break;
572 case 5: mnem = "sub"; break;
573 case 6: mnem = "xor"; break;
574 case 7: mnem = "cmp"; break;
575 default: UnimplementedInstruction();
576 }
577 AppendToBuffer("%s ", mnem);
578 int count = PrintRightOperand(data+1);
579 if (sign_extension_bit) {
580 AppendToBuffer(",0x%x", *(data + 1 + count));
581 return 1 + count + 1 /*int8*/;
582 } else {
583 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
584 return 1 + count + 4 /*int32_t*/;
585 }
586}
587
588
589// Returns number of bytes used, including *data.
590int DisassemblerIA32::F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 DCHECK_EQ(0xF7, *data);
592 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 int mod, regop, rm;
594 get_modrm(modrm, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 const char* mnem = NULL;
596 switch (regop) {
597 case 0:
598 mnem = "test";
599 break;
600 case 2:
601 mnem = "not";
602 break;
603 case 3:
604 mnem = "neg";
605 break;
606 case 4:
607 mnem = "mul";
608 break;
609 case 5:
610 mnem = "imul";
611 break;
612 case 6:
613 mnem = "div";
614 break;
615 case 7:
616 mnem = "idiv";
617 break;
618 default:
619 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000621 AppendToBuffer("%s ", mnem);
622 int count = PrintRightOperand(data);
623 if (regop == 0) {
624 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
625 count += 4;
626 }
627 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000628}
629
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000630
Steve Blocka7e24c12009-10-30 11:49:00 +0000631int DisassemblerIA32::D1D3C1Instruction(byte* data) {
632 byte op = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
634 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000635 int mod, regop, rm;
636 get_modrm(modrm, &mod, &regop, &rm);
637 int imm8 = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000638 const char* mnem = NULL;
639 switch (regop) {
640 case kROL:
641 mnem = "rol";
642 break;
643 case kROR:
644 mnem = "ror";
645 break;
646 case kRCL:
647 mnem = "rcl";
648 break;
649 case kRCR:
650 mnem = "rcr";
651 break;
652 case kSHL:
653 mnem = "shl";
654 break;
655 case KSHR:
656 mnem = "shr";
657 break;
658 case kSAR:
659 mnem = "sar";
660 break;
661 default:
662 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000663 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000664 AppendToBuffer("%s ", mnem);
665 int count = PrintRightOperand(data);
666 if (op == 0xD1) {
667 imm8 = 1;
668 } else if (op == 0xC1) {
669 imm8 = *(data + 1);
670 count++;
671 } else if (op == 0xD3) {
672 // Shift/rotate by cl.
673 }
674 if (imm8 >= 0) {
675 AppendToBuffer(",%d", imm8);
676 } else {
677 AppendToBuffer(",cl");
678 }
679 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000680}
681
682
683// Returns number of bytes used, including *data.
684int DisassemblerIA32::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 byte b = *(data+1);
687 byte* dest = data + static_cast<int8_t>(b) + 2;
688 AppendToBuffer("jmp %s", NameOfAddress(dest));
689 return 2;
690}
691
692
693// Returns number of bytes used, including *data.
694int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000695 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000696 byte cond = *(data+1) & 0x0F;
697 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
698 const char* mnem = jump_conditional_mnem[cond];
699 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
700 if (comment != NULL) {
701 AppendToBuffer(", %s", comment);
702 }
703 return 6; // includes 0x0F
704}
705
706
707// Returns number of bytes used, including *data.
708int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
709 byte cond = *data & 0x0F;
710 byte b = *(data+1);
711 byte* dest = data + static_cast<int8_t>(b) + 2;
712 const char* mnem = jump_conditional_mnem[cond];
713 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
714 if (comment != NULL) {
715 AppendToBuffer(", %s", comment);
716 }
717 return 2;
718}
719
720
721// Returns number of bytes used, including *data.
722int DisassemblerIA32::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000724 byte cond = *(data+1) & 0x0F;
725 const char* mnem = set_conditional_mnem[cond];
726 AppendToBuffer("%s ", mnem);
727 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000728 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000729}
730
731
732// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000733int DisassemblerIA32::CMov(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734 DCHECK_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000735 byte cond = *(data + 1) & 0x0F;
736 const char* mnem = conditional_move_mnem[cond];
737 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
738 return 2 + op_size; // includes 0x0F
739}
740
741
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400742int DisassemblerIA32::AVXInstruction(byte* data) {
743 byte opcode = *data;
744 byte* current = data + 1;
745 if (vex_66() && vex_0f38()) {
746 int mod, regop, rm, vvvv = vex_vreg();
747 get_modrm(*current, &mod, &regop, &rm);
748 switch (opcode) {
749 case 0x99:
750 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
751 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
752 current += PrintRightXMMOperand(current);
753 break;
754 case 0xa9:
755 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
756 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
757 current += PrintRightXMMOperand(current);
758 break;
759 case 0xb9:
760 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
761 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
762 current += PrintRightXMMOperand(current);
763 break;
764 case 0x9b:
765 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
766 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
767 current += PrintRightXMMOperand(current);
768 break;
769 case 0xab:
770 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
771 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
772 current += PrintRightXMMOperand(current);
773 break;
774 case 0xbb:
775 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
776 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
777 current += PrintRightXMMOperand(current);
778 break;
779 case 0x9d:
780 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
781 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
782 current += PrintRightXMMOperand(current);
783 break;
784 case 0xad:
785 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
786 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
787 current += PrintRightXMMOperand(current);
788 break;
789 case 0xbd:
790 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
791 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
792 current += PrintRightXMMOperand(current);
793 break;
794 case 0x9f:
795 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
796 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
797 current += PrintRightXMMOperand(current);
798 break;
799 case 0xaf:
800 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
801 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
802 current += PrintRightXMMOperand(current);
803 break;
804 case 0xbf:
805 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
806 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
807 current += PrintRightXMMOperand(current);
808 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000809 case 0xf7:
810 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
811 current += PrintRightOperand(current);
812 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
813 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400814 default:
815 UnimplementedInstruction();
816 }
817 } else if (vex_f2() && vex_0f()) {
818 int mod, regop, rm, vvvv = vex_vreg();
819 get_modrm(*current, &mod, &regop, &rm);
820 switch (opcode) {
821 case 0x58:
822 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
823 NameOfXMMRegister(vvvv));
824 current += PrintRightXMMOperand(current);
825 break;
826 case 0x59:
827 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
828 NameOfXMMRegister(vvvv));
829 current += PrintRightXMMOperand(current);
830 break;
831 case 0x5c:
832 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
833 NameOfXMMRegister(vvvv));
834 current += PrintRightXMMOperand(current);
835 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000836 case 0x5d:
837 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
838 NameOfXMMRegister(vvvv));
839 current += PrintRightXMMOperand(current);
840 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400841 case 0x5e:
842 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
843 NameOfXMMRegister(vvvv));
844 current += PrintRightXMMOperand(current);
845 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000846 case 0x5f:
847 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
848 NameOfXMMRegister(vvvv));
849 current += PrintRightXMMOperand(current);
850 break;
851 default:
852 UnimplementedInstruction();
853 }
854 } else if (vex_f3() && vex_0f()) {
855 int mod, regop, rm, vvvv = vex_vreg();
856 get_modrm(*current, &mod, &regop, &rm);
857 switch (opcode) {
858 case 0x58:
859 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
860 NameOfXMMRegister(vvvv));
861 current += PrintRightXMMOperand(current);
862 break;
863 case 0x59:
864 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
865 NameOfXMMRegister(vvvv));
866 current += PrintRightXMMOperand(current);
867 break;
868 case 0x5c:
869 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
870 NameOfXMMRegister(vvvv));
871 current += PrintRightXMMOperand(current);
872 break;
873 case 0x5d:
874 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
875 NameOfXMMRegister(vvvv));
876 current += PrintRightXMMOperand(current);
877 break;
878 case 0x5e:
879 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
880 NameOfXMMRegister(vvvv));
881 current += PrintRightXMMOperand(current);
882 break;
883 case 0x5f:
884 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
885 NameOfXMMRegister(vvvv));
886 current += PrintRightXMMOperand(current);
887 break;
888 default:
889 UnimplementedInstruction();
890 }
891 } else if (vex_none() && vex_0f38()) {
892 int mod, regop, rm, vvvv = vex_vreg();
893 get_modrm(*current, &mod, &regop, &rm);
894 const char* mnem = "?";
895 switch (opcode) {
896 case 0xf2:
897 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
898 NameOfCPURegister(vvvv));
899 current += PrintRightOperand(current);
900 break;
901 case 0xf5:
902 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
903 current += PrintRightOperand(current);
904 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
905 break;
906 case 0xf7:
907 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
908 current += PrintRightOperand(current);
909 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
910 break;
911 case 0xf3:
912 switch (regop) {
913 case 1:
914 mnem = "blsr";
915 break;
916 case 2:
917 mnem = "blsmsk";
918 break;
919 case 3:
920 mnem = "blsi";
921 break;
922 default:
923 UnimplementedInstruction();
924 }
925 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
926 current += PrintRightOperand(current);
927 mnem = "?";
928 break;
929 default:
930 UnimplementedInstruction();
931 }
932 } else if (vex_f2() && vex_0f38()) {
933 int mod, regop, rm, vvvv = vex_vreg();
934 get_modrm(*current, &mod, &regop, &rm);
935 switch (opcode) {
936 case 0xf5:
937 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
938 NameOfCPURegister(vvvv));
939 current += PrintRightOperand(current);
940 break;
941 case 0xf6:
942 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
943 NameOfCPURegister(vvvv));
944 current += PrintRightOperand(current);
945 break;
946 case 0xf7:
947 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
948 current += PrintRightOperand(current);
949 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
950 break;
951 default:
952 UnimplementedInstruction();
953 }
954 } else if (vex_f3() && vex_0f38()) {
955 int mod, regop, rm, vvvv = vex_vreg();
956 get_modrm(*current, &mod, &regop, &rm);
957 switch (opcode) {
958 case 0xf5:
959 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
960 NameOfCPURegister(vvvv));
961 current += PrintRightOperand(current);
962 break;
963 case 0xf7:
964 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
965 current += PrintRightOperand(current);
966 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
967 break;
968 default:
969 UnimplementedInstruction();
970 }
971 } else if (vex_f2() && vex_0f3a()) {
972 int mod, regop, rm;
973 get_modrm(*current, &mod, &regop, &rm);
974 switch (opcode) {
975 case 0xf0:
976 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
977 current += PrintRightOperand(current);
978 AppendToBuffer(",%d", *current & 0x1f);
979 current += 1;
980 break;
981 default:
982 UnimplementedInstruction();
983 }
984 } else if (vex_none() && vex_0f()) {
985 int mod, regop, rm, vvvv = vex_vreg();
986 get_modrm(*current, &mod, &regop, &rm);
987 switch (opcode) {
988 case 0x54:
989 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
990 NameOfXMMRegister(vvvv));
991 current += PrintRightXMMOperand(current);
992 break;
993 case 0x57:
994 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
995 NameOfXMMRegister(vvvv));
996 current += PrintRightXMMOperand(current);
997 break;
998 default:
999 UnimplementedInstruction();
1000 }
1001 } else if (vex_66() && vex_0f()) {
1002 int mod, regop, rm, vvvv = vex_vreg();
1003 get_modrm(*current, &mod, &regop, &rm);
1004 switch (opcode) {
1005 case 0x54:
1006 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1007 NameOfXMMRegister(vvvv));
1008 current += PrintRightXMMOperand(current);
1009 break;
1010 case 0x57:
1011 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1012 NameOfXMMRegister(vvvv));
1013 current += PrintRightXMMOperand(current);
1014 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001015 default:
1016 UnimplementedInstruction();
1017 }
1018 } else {
1019 UnimplementedInstruction();
1020 }
1021
1022 return static_cast<int>(current - data);
1023}
1024
1025
Steve Block3ce2e202009-11-05 08:53:23 +00001026// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +00001027int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001028 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001029 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001030 byte modrm_byte = *(data+1);
1031
1032 if (modrm_byte >= 0xC0) {
1033 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1034 } else {
1035 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 }
Steve Blockd0582a62009-12-15 09:54:21 +00001037}
1038
1039int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
1040 int modrm_byte,
1041 byte* modrm_start) {
1042 const char* mnem = "?";
1043 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1044 switch (escape_opcode) {
1045 case 0xD9: switch (regop) {
1046 case 0: mnem = "fld_s"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001047 case 2: mnem = "fst_s"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001048 case 3: mnem = "fstp_s"; break;
1049 case 7: mnem = "fstcw"; break;
1050 default: UnimplementedInstruction();
1051 }
1052 break;
1053
1054 case 0xDB: switch (regop) {
1055 case 0: mnem = "fild_s"; break;
1056 case 1: mnem = "fisttp_s"; break;
1057 case 2: mnem = "fist_s"; break;
1058 case 3: mnem = "fistp_s"; break;
1059 default: UnimplementedInstruction();
1060 }
1061 break;
1062
1063 case 0xDD: switch (regop) {
1064 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001065 case 1: mnem = "fisttp_d"; break;
1066 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001067 case 3: mnem = "fstp_d"; break;
1068 default: UnimplementedInstruction();
1069 }
1070 break;
1071
1072 case 0xDF: switch (regop) {
1073 case 5: mnem = "fild_d"; break;
1074 case 7: mnem = "fistp_d"; break;
1075 default: UnimplementedInstruction();
1076 }
1077 break;
1078
1079 default: UnimplementedInstruction();
1080 }
1081 AppendToBuffer("%s ", mnem);
1082 int count = PrintRightOperand(modrm_start);
1083 return count + 1;
1084}
1085
1086int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1087 byte modrm_byte) {
1088 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1089 const char* mnem = "?";
1090
1091 switch (escape_opcode) {
1092 case 0xD8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001093 has_register = true;
1094 switch (modrm_byte & 0xF8) {
1095 case 0xC0: mnem = "fadd_i"; break;
1096 case 0xE0: mnem = "fsub_i"; break;
1097 case 0xC8: mnem = "fmul_i"; break;
1098 case 0xF0: mnem = "fdiv_i"; break;
1099 default: UnimplementedInstruction();
1100 }
Steve Blockd0582a62009-12-15 09:54:21 +00001101 break;
1102
1103 case 0xD9:
1104 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001105 case 0xC0:
1106 mnem = "fld";
1107 has_register = true;
1108 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001109 case 0xC8:
1110 mnem = "fxch";
1111 has_register = true;
1112 break;
1113 default:
1114 switch (modrm_byte) {
1115 case 0xE0: mnem = "fchs"; break;
1116 case 0xE1: mnem = "fabs"; break;
1117 case 0xE4: mnem = "ftst"; break;
1118 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001119 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001120 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001121 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001122 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001123 case 0xF1: mnem = "fyl2x"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001124 case 0xF4: mnem = "fxtract"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001125 case 0xF5: mnem = "fprem1"; break;
1126 case 0xF7: mnem = "fincstp"; break;
1127 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001128 case 0xFC: mnem = "frndint"; break;
1129 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001130 case 0xFE: mnem = "fsin"; break;
1131 case 0xFF: mnem = "fcos"; break;
1132 default: UnimplementedInstruction();
1133 }
1134 }
1135 break;
1136
1137 case 0xDA:
1138 if (modrm_byte == 0xE9) {
1139 mnem = "fucompp";
1140 } else {
1141 UnimplementedInstruction();
1142 }
1143 break;
1144
1145 case 0xDB:
1146 if ((modrm_byte & 0xF8) == 0xE8) {
1147 mnem = "fucomi";
1148 has_register = true;
1149 } else if (modrm_byte == 0xE2) {
1150 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001151 } else if (modrm_byte == 0xE3) {
1152 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001153 } else {
1154 UnimplementedInstruction();
1155 }
1156 break;
1157
1158 case 0xDC:
1159 has_register = true;
1160 switch (modrm_byte & 0xF8) {
1161 case 0xC0: mnem = "fadd"; break;
1162 case 0xE8: mnem = "fsub"; break;
1163 case 0xC8: mnem = "fmul"; break;
1164 case 0xF8: mnem = "fdiv"; break;
1165 default: UnimplementedInstruction();
1166 }
1167 break;
1168
1169 case 0xDD:
1170 has_register = true;
1171 switch (modrm_byte & 0xF8) {
1172 case 0xC0: mnem = "ffree"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001173 case 0xD0: mnem = "fst"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001174 case 0xD8: mnem = "fstp"; break;
1175 default: UnimplementedInstruction();
1176 }
1177 break;
1178
1179 case 0xDE:
1180 if (modrm_byte == 0xD9) {
1181 mnem = "fcompp";
1182 } else {
1183 has_register = true;
1184 switch (modrm_byte & 0xF8) {
1185 case 0xC0: mnem = "faddp"; break;
1186 case 0xE8: mnem = "fsubp"; break;
1187 case 0xC8: mnem = "fmulp"; break;
1188 case 0xF8: mnem = "fdivp"; break;
1189 default: UnimplementedInstruction();
1190 }
1191 }
1192 break;
1193
1194 case 0xDF:
1195 if (modrm_byte == 0xE0) {
1196 mnem = "fnstsw_ax";
1197 } else if ((modrm_byte & 0xF8) == 0xE8) {
1198 mnem = "fucomip";
1199 has_register = true;
1200 }
1201 break;
1202
1203 default: UnimplementedInstruction();
1204 }
1205
1206 if (has_register) {
1207 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1208 } else {
1209 AppendToBuffer("%s", mnem);
1210 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001211 return 2;
1212}
1213
1214
1215// Mnemonics for instructions 0xF0 byte.
1216// Returns NULL if the instruction is not handled here.
1217static const char* F0Mnem(byte f0byte) {
1218 switch (f0byte) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001219 case 0x0B:
1220 return "ud2";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001221 case 0x18: return "prefetch";
Steve Blocka7e24c12009-10-30 11:49:00 +00001222 case 0xA2: return "cpuid";
Steve Blocka7e24c12009-10-30 11:49:00 +00001223 case 0xBE: return "movsx_b";
1224 case 0xBF: return "movsx_w";
1225 case 0xB6: return "movzx_b";
1226 case 0xB7: return "movzx_w";
1227 case 0xAF: return "imul";
1228 case 0xA5: return "shld";
1229 case 0xAD: return "shrd";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230 case 0xAC: return "shrd"; // 3-operand version.
Steve Blocka7e24c12009-10-30 11:49:00 +00001231 case 0xAB: return "bts";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 case 0xBC:
1233 return "bsf";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001234 case 0xBD: return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001235 default: return NULL;
1236 }
1237}
1238
1239
1240// Disassembled instruction '*instr' and writes it into 'out_buffer'.
1241int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1242 byte* instr) {
1243 tmp_buffer_pos_ = 0; // starting to write as position 0
1244 byte* data = instr;
1245 // Check for hints.
1246 const char* branch_hint = NULL;
1247 // We use these two prefixes only with branch prediction
1248 if (*data == 0x3E /*ds*/) {
1249 branch_hint = "predicted taken";
1250 data++;
1251 } else if (*data == 0x2E /*cs*/) {
1252 branch_hint = "predicted not taken";
1253 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001254 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1255 vex_byte0_ = *data;
1256 vex_byte1_ = *(data + 1);
1257 vex_byte2_ = *(data + 2);
1258 data += 3;
1259 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1260 vex_byte0_ = *data;
1261 vex_byte1_ = *(data + 1);
1262 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001264
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 bool processed = true; // Will be set to false if the current instruction
1266 // is not in 'instructions' table.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001267 // Decode AVX instructions.
1268 if (vex_byte0_ != 0) {
1269 data += AVXInstruction(data);
1270 } else {
1271 const InstructionDesc& idesc = instruction_table_->Get(*data);
1272 switch (idesc.type) {
1273 case ZERO_OPERANDS_INSTR:
1274 AppendToBuffer(idesc.mnem);
1275 data++;
1276 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001277
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001278 case TWO_OPERANDS_INSTR:
1279 data++;
1280 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1281 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001282
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001283 case JUMP_CONDITIONAL_SHORT_INSTR:
1284 data += JumpConditionalShort(data, branch_hint);
1285 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001286
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001287 case REGISTER_INSTR:
1288 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1289 data++;
1290 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001291
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001292 case MOVE_REG_INSTR: {
1293 byte* addr =
1294 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1295 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1296 NameOfAddress(addr));
1297 data += 5;
1298 break;
1299 }
1300
1301 case CALL_JUMP_INSTR: {
1302 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1303 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1304 data += 5;
1305 break;
1306 }
1307
1308 case SHORT_IMMEDIATE_INSTR: {
1309 byte* addr =
1310 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1311 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1312 data += 5;
1313 break;
1314 }
1315
1316 case BYTE_IMMEDIATE_INSTR: {
1317 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1318 data += 2;
1319 break;
1320 }
1321
1322 case NO_INSTR:
1323 processed = false;
1324 break;
1325
1326 default:
1327 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001329 }
1330 //----------------------------
1331 if (!processed) {
1332 switch (*data) {
1333 case 0xC2:
1334 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1335 data += 3;
1336 break;
1337
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338 case 0x6B: {
1339 data++;
1340 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1341 AppendToBuffer(",%d", *data);
1342 data++;
1343 } break;
1344
1345 case 0x69: {
1346 data++;
1347 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1348 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1349 data += 4;
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 }
1351 break;
1352
1353 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001354 { data++;
1355 int mod, regop, rm;
1356 get_modrm(*data, &mod, &regop, &rm);
1357 if (regop == eax) {
1358 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +01001359 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001360 int32_t imm = *data;
1361 AppendToBuffer(",0x%x", imm);
1362 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 } else {
1364 UnimplementedInstruction();
1365 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001366 }
1367 break;
1368
1369 case 0x81: // fall through
1370 case 0x83: // 0x81 with sign extension bit set
1371 data += PrintImmediateOp(data);
1372 break;
1373
1374 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001375 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001377 if (f0byte == 0x18) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001378 data += 2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001379 int mod, regop, rm;
1380 get_modrm(*data, &mod, &regop, &rm);
1381 const char* suffix[] = {"nta", "1", "2", "3"};
1382 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1383 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001384 } else if (f0byte == 0x1F && data[2] == 0) {
1385 AppendToBuffer("nop"); // 3 byte nop.
1386 data += 3;
1387 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1388 AppendToBuffer("nop"); // 4 byte nop.
1389 data += 4;
1390 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1391 data[4] == 0) {
1392 AppendToBuffer("nop"); // 5 byte nop.
1393 data += 5;
1394 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1395 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1396 AppendToBuffer("nop"); // 7 byte nop.
1397 data += 7;
1398 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1399 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1400 data[7] == 0) {
1401 AppendToBuffer("nop"); // 8 byte nop.
1402 data += 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 AppendToBuffer("%s", f0mnem);
1405 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001406 } else if (f0byte == 0x28) {
1407 data += 2;
1408 int mod, regop, rm;
1409 get_modrm(*data, &mod, &regop, &rm);
1410 AppendToBuffer("movaps %s,%s",
1411 NameOfXMMRegister(regop),
1412 NameOfXMMRegister(rm));
1413 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001414 } else if (f0byte == 0x2e) {
1415 data += 2;
1416 int mod, regop, rm;
1417 get_modrm(*data, &mod, &regop, &rm);
1418 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1419 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001420 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1421 const char* const pseudo_op[] = {
1422 "rcpps",
1423 "andps",
1424 "andnps",
1425 "orps",
1426 "xorps",
1427 "addps",
1428 "mulps",
1429 "cvtps2pd",
1430 "cvtdq2ps",
1431 "subps",
1432 "minps",
1433 "divps",
1434 "maxps",
1435 };
1436
Ben Murdoch257744e2011-11-30 15:57:28 +00001437 data += 2;
1438 int mod, regop, rm;
1439 get_modrm(*data, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440 AppendToBuffer("%s %s,",
1441 pseudo_op[f0byte - 0x53],
1442 NameOfXMMRegister(regop));
1443 data += PrintRightXMMOperand(data);
1444 } else if (f0byte == 0x50) {
1445 data += 2;
1446 int mod, regop, rm;
1447 get_modrm(*data, &mod, &regop, &rm);
1448 AppendToBuffer("movmskps %s,%s",
1449 NameOfCPURegister(regop),
Ben Murdoch257744e2011-11-30 15:57:28 +00001450 NameOfXMMRegister(rm));
1451 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001452 } else if (f0byte== 0xC6) {
1453 // shufps xmm, xmm/m128, imm8
1454 data += 2;
1455 int mod, regop, rm;
1456 get_modrm(*data, &mod, &regop, &rm);
1457 int8_t imm8 = static_cast<int8_t>(data[1]);
1458 AppendToBuffer("shufps %s,%s,%d",
1459 NameOfXMMRegister(rm),
1460 NameOfXMMRegister(regop),
1461 static_cast<int>(imm8));
1462 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001463 } else if ((f0byte & 0xF0) == 0x80) {
1464 data += JumpConditional(data, branch_hint);
1465 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1466 f0byte == 0xB7 || f0byte == 0xAF) {
1467 data += 2;
1468 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1469 } else if ((f0byte & 0xF0) == 0x90) {
1470 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001471 } else if ((f0byte & 0xF0) == 0x40) {
1472 data += CMov(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001473 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1474 // shrd, shld, bts
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 AppendToBuffer("%s ", f0mnem);
1477 int mod, regop, rm;
1478 get_modrm(*data, &mod, &regop, &rm);
1479 data += PrintRightOperand(data);
1480 if (f0byte == 0xAB) {
1481 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001483 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 } else if (f0byte == 0xBC) {
1486 data += 2;
1487 int mod, regop, rm;
1488 get_modrm(*data, &mod, &regop, &rm);
1489 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1490 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001491 } else if (f0byte == 0xBD) {
1492 data += 2;
1493 int mod, regop, rm;
1494 get_modrm(*data, &mod, &regop, &rm);
1495 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1496 data += PrintRightOperand(data);
1497 } else {
1498 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +00001499 }
1500 }
1501 break;
1502
1503 case 0x8F:
1504 { data++;
1505 int mod, regop, rm;
1506 get_modrm(*data, &mod, &regop, &rm);
1507 if (regop == eax) {
1508 AppendToBuffer("pop ");
1509 data += PrintRightOperand(data);
1510 }
1511 }
1512 break;
1513
1514 case 0xFF:
1515 { data++;
1516 int mod, regop, rm;
1517 get_modrm(*data, &mod, &regop, &rm);
1518 const char* mnem = NULL;
1519 switch (regop) {
1520 case esi: mnem = "push"; break;
1521 case eax: mnem = "inc"; break;
1522 case ecx: mnem = "dec"; break;
1523 case edx: mnem = "call"; break;
1524 case esp: mnem = "jmp"; break;
1525 default: mnem = "???";
1526 }
1527 AppendToBuffer("%s ", mnem);
1528 data += PrintRightOperand(data);
1529 }
1530 break;
1531
1532 case 0xC7: // imm32, fall through
1533 case 0xC6: // imm8
1534 { bool is_byte = *data == 0xC6;
1535 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001536 if (is_byte) {
1537 AppendToBuffer("%s ", "mov_b");
1538 data += PrintRightByteOperand(data);
1539 int32_t imm = *data;
1540 AppendToBuffer(",0x%x", imm);
1541 data++;
1542 } else {
1543 AppendToBuffer("%s ", "mov");
1544 data += PrintRightOperand(data);
1545 int32_t imm = *reinterpret_cast<int32_t*>(data);
1546 AppendToBuffer(",0x%x", imm);
1547 data += 4;
1548 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001549 }
1550 break;
1551
1552 case 0x80:
1553 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001554 int mod, regop, rm;
1555 get_modrm(*data, &mod, &regop, &rm);
1556 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001557 switch (regop) {
1558 case 5: mnem = "subb"; break;
1559 case 7: mnem = "cmpb"; break;
1560 default: UnimplementedInstruction();
1561 }
1562 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001563 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001564 int32_t imm = *data;
1565 AppendToBuffer(",0x%x", imm);
1566 data++;
1567 }
1568 break;
1569
1570 case 0x88: // 8bit, fall through
1571 case 0x89: // 32bit
1572 { bool is_byte = *data == 0x88;
1573 int mod, regop, rm;
1574 data++;
1575 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001576 if (is_byte) {
1577 AppendToBuffer("%s ", "mov_b");
1578 data += PrintRightByteOperand(data);
1579 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1580 } else {
1581 AppendToBuffer("%s ", "mov");
1582 data += PrintRightOperand(data);
1583 AppendToBuffer(",%s", NameOfCPURegister(regop));
1584 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001585 }
1586 break;
1587
1588 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001589 while (*data == 0x66) data++;
1590 if (*data == 0xf && data[1] == 0x1f) {
1591 AppendToBuffer("nop"); // 0x66 prefix
1592 } else if (*data == 0x90) {
1593 AppendToBuffer("nop"); // 0x66 prefix
1594 } else if (*data == 0x8B) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001595 data++;
1596 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1597 } else if (*data == 0x89) {
1598 data++;
1599 int mod, regop, rm;
1600 get_modrm(*data, &mod, &regop, &rm);
1601 AppendToBuffer("mov_w ");
1602 data += PrintRightOperand(data);
1603 AppendToBuffer(",%s", NameOfCPURegister(regop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001604 } else if (*data == 0xC7) {
1605 data++;
1606 AppendToBuffer("%s ", "mov_w");
1607 data += PrintRightOperand(data);
1608 int imm = *reinterpret_cast<int16_t*>(data);
1609 AppendToBuffer(",0x%x", imm);
1610 data += 2;
Steve Block3ce2e202009-11-05 08:53:23 +00001611 } else if (*data == 0x0F) {
1612 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001613 if (*data == 0x38) {
1614 data++;
1615 if (*data == 0x17) {
1616 data++;
1617 int mod, regop, rm;
1618 get_modrm(*data, &mod, &regop, &rm);
1619 AppendToBuffer("ptest %s,%s",
1620 NameOfXMMRegister(regop),
1621 NameOfXMMRegister(rm));
1622 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001623 } else if (*data == 0x2A) {
1624 // movntdqa
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001625 UnimplementedInstruction();
Steve Block6ded16b2010-05-10 14:33:55 +01001626 } else {
1627 UnimplementedInstruction();
1628 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001629 } else if (*data == 0x3A) {
1630 data++;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001631 if (*data == 0x0A) {
1632 data++;
1633 int mod, regop, rm;
1634 get_modrm(*data, &mod, &regop, &rm);
1635 int8_t imm8 = static_cast<int8_t>(data[1]);
1636 AppendToBuffer("roundss %s,%s,%d", NameOfXMMRegister(regop),
1637 NameOfXMMRegister(rm), static_cast<int>(imm8));
1638 data += 2;
1639 } else if (*data == 0x0B) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001640 data++;
1641 int mod, regop, rm;
1642 get_modrm(*data, &mod, &regop, &rm);
1643 int8_t imm8 = static_cast<int8_t>(data[1]);
1644 AppendToBuffer("roundsd %s,%s,%d",
1645 NameOfXMMRegister(regop),
1646 NameOfXMMRegister(rm),
1647 static_cast<int>(imm8));
1648 data += 2;
1649 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001650 data++;
1651 int mod, regop, rm;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001652 get_modrm(*data, &mod, &rm, &regop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001653 int8_t imm8 = static_cast<int8_t>(data[1]);
1654 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001655 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001656 NameOfXMMRegister(rm),
1657 static_cast<int>(imm8));
1658 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001659 } else if (*data == 0x17) {
1660 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("extractps %s,%s,%d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001665 NameOfCPURegister(rm),
1666 NameOfXMMRegister(regop),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001667 static_cast<int>(imm8));
1668 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001669 } else if (*data == 0x22) {
1670 data++;
1671 int mod, regop, rm;
1672 get_modrm(*data, &mod, &regop, &rm);
1673 int8_t imm8 = static_cast<int8_t>(data[1]);
1674 AppendToBuffer("pinsrd %s,%s,%d",
1675 NameOfXMMRegister(regop),
1676 NameOfCPURegister(rm),
1677 static_cast<int>(imm8));
1678 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001679 } else {
1680 UnimplementedInstruction();
1681 }
Steve Block6ded16b2010-05-10 14:33:55 +01001682 } else if (*data == 0x2E || *data == 0x2F) {
1683 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001684 data++;
1685 int mod, regop, rm;
1686 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001687 if (mod == 0x3) {
1688 AppendToBuffer("%s %s,%s", mnem,
1689 NameOfXMMRegister(regop),
1690 NameOfXMMRegister(rm));
1691 data++;
1692 } else {
1693 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1694 data += PrintRightOperand(data);
1695 }
1696 } else if (*data == 0x50) {
1697 data++;
1698 int mod, regop, rm;
1699 get_modrm(*data, &mod, &regop, &rm);
1700 AppendToBuffer("movmskpd %s,%s",
1701 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001702 NameOfXMMRegister(rm));
1703 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001704 } else if (*data == 0x54) {
1705 data++;
1706 int mod, regop, rm;
1707 get_modrm(*data, &mod, &regop, &rm);
1708 AppendToBuffer("andpd %s,%s",
1709 NameOfXMMRegister(regop),
1710 NameOfXMMRegister(rm));
1711 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001712 } else if (*data == 0x56) {
1713 data++;
1714 int mod, regop, rm;
1715 get_modrm(*data, &mod, &regop, &rm);
1716 AppendToBuffer("orpd %s,%s",
1717 NameOfXMMRegister(regop),
1718 NameOfXMMRegister(rm));
1719 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001720 } else if (*data == 0x57) {
1721 data++;
1722 int mod, regop, rm;
1723 get_modrm(*data, &mod, &regop, &rm);
1724 AppendToBuffer("xorpd %s,%s",
1725 NameOfXMMRegister(regop),
1726 NameOfXMMRegister(rm));
1727 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001728 } else if (*data == 0x6E) {
1729 data++;
1730 int mod, regop, rm;
1731 get_modrm(*data, &mod, &regop, &rm);
1732 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1733 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001734 } else if (*data == 0x6F) {
1735 data++;
1736 int mod, regop, rm;
1737 get_modrm(*data, &mod, &regop, &rm);
1738 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001739 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001740 } else if (*data == 0x70) {
1741 data++;
1742 int mod, regop, rm;
1743 get_modrm(*data, &mod, &regop, &rm);
1744 int8_t imm8 = static_cast<int8_t>(data[1]);
1745 AppendToBuffer("pshufd %s,%s,%d",
1746 NameOfXMMRegister(regop),
1747 NameOfXMMRegister(rm),
1748 static_cast<int>(imm8));
1749 data += 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001750 } else if (*data == 0x62) {
1751 data++;
1752 int mod, regop, rm;
1753 get_modrm(*data, &mod, &regop, &rm);
1754 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
1755 NameOfXMMRegister(rm));
1756 data++;
1757 } else if (*data == 0x6A) {
1758 data++;
1759 int mod, regop, rm;
1760 get_modrm(*data, &mod, &regop, &rm);
1761 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
1762 NameOfXMMRegister(rm));
1763 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001764 } else if (*data == 0x76) {
1765 data++;
1766 int mod, regop, rm;
1767 get_modrm(*data, &mod, &regop, &rm);
1768 AppendToBuffer("pcmpeqd %s,%s",
1769 NameOfXMMRegister(regop),
1770 NameOfXMMRegister(rm));
1771 data++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001772 } else if (*data == 0x90) {
1773 data++;
1774 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001775 } else if (*data == 0xF3) {
1776 data++;
1777 int mod, regop, rm;
1778 get_modrm(*data, &mod, &regop, &rm);
1779 AppendToBuffer("psllq %s,%s",
1780 NameOfXMMRegister(regop),
1781 NameOfXMMRegister(rm));
1782 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001783 } else if (*data == 0x72) {
1784 data++;
1785 int mod, regop, rm;
1786 get_modrm(*data, &mod, &regop, &rm);
1787 int8_t imm8 = static_cast<int8_t>(data[1]);
1788 DCHECK(regop == esi || regop == edx);
1789 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1790 NameOfXMMRegister(rm), static_cast<int>(imm8));
1791 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001792 } else if (*data == 0x73) {
1793 data++;
1794 int mod, regop, rm;
1795 get_modrm(*data, &mod, &regop, &rm);
1796 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001797 DCHECK(regop == esi || regop == edx);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001798 AppendToBuffer("%s %s,%d",
1799 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001800 NameOfXMMRegister(rm),
1801 static_cast<int>(imm8));
1802 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001803 } else if (*data == 0xD3) {
1804 data++;
1805 int mod, regop, rm;
1806 get_modrm(*data, &mod, &regop, &rm);
1807 AppendToBuffer("psrlq %s,%s",
1808 NameOfXMMRegister(regop),
1809 NameOfXMMRegister(rm));
1810 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001811 } else if (*data == 0x7F) {
1812 AppendToBuffer("movdqa ");
1813 data++;
1814 int mod, regop, rm;
1815 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001816 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001817 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001818 } else if (*data == 0x7E) {
1819 data++;
1820 int mod, regop, rm;
1821 get_modrm(*data, &mod, &regop, &rm);
1822 AppendToBuffer("movd ");
1823 data += PrintRightOperand(data);
1824 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1825 } else if (*data == 0xDB) {
1826 data++;
1827 int mod, regop, rm;
1828 get_modrm(*data, &mod, &regop, &rm);
1829 AppendToBuffer("pand %s,%s",
1830 NameOfXMMRegister(regop),
1831 NameOfXMMRegister(rm));
1832 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001833 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001834 data++;
1835 int mod, regop, rm;
1836 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001837 if (mod == 3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001838 // movntdq
1839 UnimplementedInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +01001840 } else {
1841 UnimplementedInstruction();
1842 }
Steve Block6ded16b2010-05-10 14:33:55 +01001843 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001844 data++;
1845 int mod, regop, rm;
1846 get_modrm(*data, &mod, &regop, &rm);
1847 AppendToBuffer("pxor %s,%s",
1848 NameOfXMMRegister(regop),
1849 NameOfXMMRegister(rm));
1850 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001851 } else if (*data == 0xEB) {
1852 data++;
1853 int mod, regop, rm;
1854 get_modrm(*data, &mod, &regop, &rm);
1855 AppendToBuffer("por %s,%s",
1856 NameOfXMMRegister(regop),
1857 NameOfXMMRegister(rm));
1858 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001859 } else {
1860 UnimplementedInstruction();
1861 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001862 } else {
1863 UnimplementedInstruction();
1864 }
1865 break;
1866
1867 case 0xFE:
1868 { data++;
1869 int mod, regop, rm;
1870 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001871 if (regop == ecx) {
1872 AppendToBuffer("dec_b ");
1873 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001874 } else {
1875 UnimplementedInstruction();
1876 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 }
1878 break;
1879
1880 case 0x68:
1881 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1882 data += 5;
1883 break;
1884
1885 case 0x6A:
1886 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1887 data += 2;
1888 break;
1889
1890 case 0xA8:
1891 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1892 data += 2;
1893 break;
1894
1895 case 0xA9:
1896 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1897 data += 5;
1898 break;
1899
1900 case 0xD1: // fall through
1901 case 0xD3: // fall through
1902 case 0xC1:
1903 data += D1D3C1Instruction(data);
1904 break;
1905
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001906 case 0xD8: // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001907 case 0xD9: // fall through
1908 case 0xDA: // fall through
1909 case 0xDB: // fall through
1910 case 0xDC: // fall through
1911 case 0xDD: // fall through
1912 case 0xDE: // fall through
1913 case 0xDF:
1914 data += FPUInstruction(data);
1915 break;
1916
1917 case 0xEB:
1918 data += JumpShort(data);
1919 break;
1920
1921 case 0xF2:
1922 if (*(data+1) == 0x0F) {
1923 byte b2 = *(data+2);
1924 if (b2 == 0x11) {
1925 AppendToBuffer("movsd ");
1926 data += 3;
1927 int mod, regop, rm;
1928 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001929 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001930 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1931 } else if (b2 == 0x10) {
1932 data += 3;
1933 int mod, regop, rm;
1934 get_modrm(*data, &mod, &regop, &rm);
1935 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001936 data += PrintRightXMMOperand(data);
1937 } else if (b2 == 0x5A) {
1938 data += 3;
1939 int mod, regop, rm;
1940 get_modrm(*data, &mod, &regop, &rm);
1941 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1942 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001943 } else {
1944 const char* mnem = "?";
1945 switch (b2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001946 case 0x2A:
1947 mnem = "cvtsi2sd";
1948 break;
1949 case 0x2C:
1950 mnem = "cvttsd2si";
1951 break;
1952 case 0x2D:
1953 mnem = "cvtsd2si";
1954 break;
1955 case 0x51:
1956 mnem = "sqrtsd";
1957 break;
1958 case 0x58:
1959 mnem = "addsd";
1960 break;
1961 case 0x59:
1962 mnem = "mulsd";
1963 break;
1964 case 0x5C:
1965 mnem = "subsd";
1966 break;
1967 case 0x5D:
1968 mnem = "minsd";
1969 break;
1970 case 0x5E:
1971 mnem = "divsd";
1972 break;
1973 case 0x5F:
1974 mnem = "maxsd";
1975 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001976 }
1977 data += 3;
1978 int mod, regop, rm;
1979 get_modrm(*data, &mod, &regop, &rm);
1980 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01001981 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1982 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001983 } else if (b2 == 0x2C || b2 == 0x2D) {
Steve Block44f0eee2011-05-26 01:26:41 +01001984 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1985 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001986 } else if (b2 == 0xC2) {
1987 // Intel manual 2A, Table 3-18.
1988 const char* const pseudo_op[] = {
1989 "cmpeqsd",
1990 "cmpltsd",
1991 "cmplesd",
1992 "cmpunordsd",
1993 "cmpneqsd",
1994 "cmpnltsd",
1995 "cmpnlesd",
1996 "cmpordsd"
1997 };
1998 AppendToBuffer("%s %s,%s",
1999 pseudo_op[data[1]],
2000 NameOfXMMRegister(regop),
2001 NameOfXMMRegister(rm));
2002 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00002003 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002004 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2005 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002006 }
2007 }
2008 } else {
2009 UnimplementedInstruction();
2010 }
2011 break;
2012
2013 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00002014 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01002015 byte b2 = *(data+2);
2016 if (b2 == 0x11) {
2017 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01002018 data += 3;
2019 int mod, regop, rm;
2020 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002021 data += PrintRightXMMOperand(data);
2022 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2023 } else if (b2 == 0x10) {
2024 data += 3;
2025 int mod, regop, rm;
2026 get_modrm(*data, &mod, &regop, &rm);
2027 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2028 data += PrintRightXMMOperand(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002029 } else if (b2 == 0x5A) {
2030 data += 3;
2031 int mod, regop, rm;
2032 get_modrm(*data, &mod, &regop, &rm);
2033 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2034 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002035 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002036 data += 3;
2037 int mod, regop, rm;
2038 get_modrm(*data, &mod, &regop, &rm);
2039 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01002040 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002041 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002042 AppendToBuffer("movdqu ");
2043 data += 3;
2044 int mod, regop, rm;
2045 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002046 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002047 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002048 } else if (b2 == 0xB8) {
2049 data += 3;
2050 int mod, regop, rm;
2051 get_modrm(*data, &mod, &regop, &rm);
2052 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2053 data += PrintRightOperand(data);
2054 } else if (b2 == 0xBC) {
2055 data += 3;
2056 int mod, regop, rm;
2057 get_modrm(*data, &mod, &regop, &rm);
2058 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2059 data += PrintRightOperand(data);
2060 } else if (b2 == 0xBD) {
2061 data += 3;
2062 int mod, regop, rm;
2063 get_modrm(*data, &mod, &regop, &rm);
2064 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2065 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002066 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002067 const char* mnem = "?";
2068 switch (b2) {
2069 case 0x2A:
2070 mnem = "cvtsi2ss";
2071 break;
2072 case 0x2C:
2073 mnem = "cvttss2si";
2074 break;
2075 case 0x2D:
2076 mnem = "cvtss2si";
2077 break;
2078 case 0x51:
2079 mnem = "sqrtss";
2080 break;
2081 case 0x58:
2082 mnem = "addss";
2083 break;
2084 case 0x59:
2085 mnem = "mulss";
2086 break;
2087 case 0x5C:
2088 mnem = "subss";
2089 break;
2090 case 0x5D:
2091 mnem = "minss";
2092 break;
2093 case 0x5E:
2094 mnem = "divss";
2095 break;
2096 case 0x5F:
2097 mnem = "maxss";
2098 break;
2099 }
2100 data += 3;
2101 int mod, regop, rm;
2102 get_modrm(*data, &mod, &regop, &rm);
2103 if (b2 == 0x2A) {
2104 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2105 data += PrintRightOperand(data);
2106 } else if (b2 == 0x2C || b2 == 0x2D) {
2107 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2108 data += PrintRightXMMOperand(data);
2109 } else if (b2 == 0xC2) {
2110 // Intel manual 2A, Table 3-18.
2111 const char* const pseudo_op[] = {
2112 "cmpeqss", "cmpltss", "cmpless", "cmpunordss",
2113 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2114 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2115 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2116 data += 2;
2117 } else {
2118 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2119 data += PrintRightXMMOperand(data);
2120 }
Leon Clarkee46be812010-01-19 14:06:41 +00002121 }
2122 } else if (*(data+1) == 0xA5) {
2123 data += 2;
2124 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01002125 } else if (*(data+1) == 0xAB) {
2126 data += 2;
2127 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00002128 } else {
2129 UnimplementedInstruction();
2130 }
2131 break;
2132
2133 case 0xF7:
2134 data += F7Instruction(data);
2135 break;
2136
2137 default:
2138 UnimplementedInstruction();
2139 }
2140 }
2141
2142 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2143 tmp_buffer_[tmp_buffer_pos_] = '\0';
2144 }
2145
2146 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00002147 if (instr_len == 0) {
2148 printf("%02x", *data);
2149 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002150 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002151
2152 int outp = 0;
2153 // Instruction bytes.
2154 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002155 outp += v8::internal::SNPrintF(out_buffer + outp,
2156 "%02x",
2157 *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002158 }
2159 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002160 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002161 }
2162
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002163 outp += v8::internal::SNPrintF(out_buffer + outp,
2164 " %s",
2165 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002166 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002167} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00002168
2169
2170//------------------------------------------------------------------------------
2171
2172
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002173static const char* const cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002174 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
2175};
2176
2177
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002178static const char* const byte_cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002179 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
2180};
2181
2182
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002183static const char* const xmm_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002184 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
2185};
2186
2187
2188const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002189 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002190 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002191}
2192
2193
2194const char* NameConverter::NameOfConstant(byte* addr) const {
2195 return NameOfAddress(addr);
2196}
2197
2198
2199const char* NameConverter::NameOfCPURegister(int reg) const {
2200 if (0 <= reg && reg < 8) return cpu_regs[reg];
2201 return "noreg";
2202}
2203
2204
2205const char* NameConverter::NameOfByteCPURegister(int reg) const {
2206 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2207 return "noreg";
2208}
2209
2210
2211const char* NameConverter::NameOfXMMRegister(int reg) const {
2212 if (0 <= reg && reg < 8) return xmm_regs[reg];
2213 return "noxmmreg";
2214}
2215
2216
2217const char* NameConverter::NameInCode(byte* addr) const {
2218 // IA32 does not embed debug strings at the moment.
2219 UNREACHABLE();
2220 return "";
2221}
2222
2223
2224//------------------------------------------------------------------------------
2225
2226Disassembler::Disassembler(const NameConverter& converter)
2227 : converter_(converter) {}
2228
2229
2230Disassembler::~Disassembler() {}
2231
2232
2233int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2234 byte* instruction) {
2235 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
2236 return d.InstructionDecode(buffer, instruction);
2237}
2238
2239
2240// The IA-32 assembler does not currently use constant pools.
2241int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2242
2243
2244/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2245 NameConverter converter;
2246 Disassembler d(converter);
2247 for (byte* pc = begin; pc < end;) {
2248 v8::internal::EmbeddedVector<char, 128> buffer;
2249 buffer[0] = '\0';
2250 byte* prev_pc = pc;
2251 pc += d.InstructionDecode(buffer, pc);
2252 fprintf(f, "%p", prev_pc);
2253 fprintf(f, " ");
2254
2255 for (byte* bp = prev_pc; bp < pc; bp++) {
2256 fprintf(f, "%02x", *bp);
2257 }
2258 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2259 fprintf(f, " ");
2260 }
2261 fprintf(f, " %s\n", buffer.start());
2262 }
2263}
2264
2265
2266} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002267
2268#endif // V8_TARGET_ARCH_IA32