blob: 5a432806592f7c03903e66c99e629d8f87ab70f7 [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
31
Ben Murdoch69a99ed2011-11-30 16:03:39 +000032static const ByteMnemonic two_operands_instr[] = {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010033 {0x01, "add", OPER_REG_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000034 {0x03, "add", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000035 {0x09, "or", OPER_REG_OP_ORDER},
36 {0x0B, "or", REG_OPER_OP_ORDER},
37 {0x1B, "sbb", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000038 {0x21, "and", OPER_REG_OP_ORDER},
39 {0x23, "and", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000040 {0x29, "sub", OPER_REG_OP_ORDER},
Leon Clarkee46be812010-01-19 14:06:41 +000041 {0x2A, "subb", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000042 {0x2B, "sub", REG_OPER_OP_ORDER},
Leon Clarkeeab96aa2010-01-27 16:31:12 +000043 {0x31, "xor", OPER_REG_OP_ORDER},
44 {0x33, "xor", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000045 {0x38, "cmpb", 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},
Steve Blocka7e24c12009-10-30 11:49:00 +000050 {0x87, "xchg", REG_OPER_OP_ORDER},
51 {0x8A, "mov_b", REG_OPER_OP_ORDER},
52 {0x8B, "mov", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000053 {0x8D, "lea", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000054 {-1, "", UNSET_OP_ORDER}
55};
56
57
Ben Murdoch69a99ed2011-11-30 16:03:39 +000058static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000059 {0xC3, "ret", UNSET_OP_ORDER},
60 {0xC9, "leave", UNSET_OP_ORDER},
61 {0x90, "nop", UNSET_OP_ORDER},
62 {0xF4, "hlt", UNSET_OP_ORDER},
63 {0xCC, "int3", UNSET_OP_ORDER},
64 {0x60, "pushad", UNSET_OP_ORDER},
65 {0x61, "popad", UNSET_OP_ORDER},
66 {0x9C, "pushfd", UNSET_OP_ORDER},
67 {0x9D, "popfd", UNSET_OP_ORDER},
68 {0x9E, "sahf", UNSET_OP_ORDER},
69 {0x99, "cdq", UNSET_OP_ORDER},
70 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010071 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010072 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000073 {-1, "", UNSET_OP_ORDER}
74};
75
76
Ben Murdoch69a99ed2011-11-30 16:03:39 +000077static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000078 {0xE8, "call", UNSET_OP_ORDER},
79 {0xE9, "jmp", UNSET_OP_ORDER},
80 {-1, "", UNSET_OP_ORDER}
81};
82
83
Ben Murdoch69a99ed2011-11-30 16:03:39 +000084static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000085 {0x05, "add", UNSET_OP_ORDER},
86 {0x0D, "or", UNSET_OP_ORDER},
87 {0x15, "adc", UNSET_OP_ORDER},
88 {0x25, "and", UNSET_OP_ORDER},
89 {0x2D, "sub", UNSET_OP_ORDER},
90 {0x35, "xor", UNSET_OP_ORDER},
91 {0x3D, "cmp", UNSET_OP_ORDER},
92 {-1, "", UNSET_OP_ORDER}
93};
94
95
Ben Murdoch3ef787d2012-04-12 10:51:47 +010096// Generally we don't want to generate these because they are subject to partial
97// register stalls. They are included for completeness and because the cmp
98// variant is used by the RecordWrite stub. Because it does not update the
99// register it is not subject to partial register stalls.
100static ByteMnemonic byte_immediate_instr[] = {
101 {0x0c, "or", UNSET_OP_ORDER},
102 {0x24, "and", UNSET_OP_ORDER},
103 {0x34, "xor", UNSET_OP_ORDER},
104 {0x3c, "cmp", UNSET_OP_ORDER},
105 {-1, "", UNSET_OP_ORDER}
106};
107
108
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000109static const char* const jump_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 /*0*/ "jo", "jno", "jc", "jnc",
111 /*4*/ "jz", "jnz", "jna", "ja",
112 /*8*/ "js", "jns", "jpe", "jpo",
113 /*12*/ "jl", "jnl", "jng", "jg"
114};
115
116
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000117static const char* const set_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 /*0*/ "seto", "setno", "setc", "setnc",
119 /*4*/ "setz", "setnz", "setna", "seta",
120 /*8*/ "sets", "setns", "setpe", "setpo",
121 /*12*/ "setl", "setnl", "setng", "setg"
122};
123
124
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000125static const char* const conditional_move_mnem[] = {
Steve Block3ce2e202009-11-05 08:53:23 +0000126 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
127 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
128 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
129 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
130};
131
132
Steve Blocka7e24c12009-10-30 11:49:00 +0000133enum InstructionType {
134 NO_INSTR,
135 ZERO_OPERANDS_INSTR,
136 TWO_OPERANDS_INSTR,
137 JUMP_CONDITIONAL_SHORT_INSTR,
138 REGISTER_INSTR,
139 MOVE_REG_INSTR,
140 CALL_JUMP_INSTR,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100141 SHORT_IMMEDIATE_INSTR,
142 BYTE_IMMEDIATE_INSTR
Steve Blocka7e24c12009-10-30 11:49:00 +0000143};
144
145
146struct InstructionDesc {
147 const char* mnem;
148 InstructionType type;
149 OperandOrder op_order_;
150};
151
152
153class InstructionTable {
154 public:
155 InstructionTable();
156 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100157 static InstructionTable* get_instance() {
158 static InstructionTable table;
159 return &table;
160 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000161
162 private:
163 InstructionDesc instructions_[256];
164 void Clear();
165 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000166 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000167 void SetTableRange(InstructionType type,
168 byte start,
169 byte end,
170 const char* mnem);
171 void AddJumpConditionalShort();
172};
173
174
175InstructionTable::InstructionTable() {
176 Clear();
177 Init();
178}
179
180
181void InstructionTable::Clear() {
182 for (int i = 0; i < 256; i++) {
183 instructions_[i].mnem = "";
184 instructions_[i].type = NO_INSTR;
185 instructions_[i].op_order_ = UNSET_OP_ORDER;
186 }
187}
188
189
190void InstructionTable::Init() {
191 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
192 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
193 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
194 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100195 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
Steve Blocka7e24c12009-10-30 11:49:00 +0000196 AddJumpConditionalShort();
197 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
198 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
199 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
200 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
201 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
202 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
203}
204
205
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000206void InstructionTable::CopyTable(const ByteMnemonic bm[],
207 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000208 for (int i = 0; bm[i].b >= 0; i++) {
209 InstructionDesc* id = &instructions_[bm[i].b];
210 id->mnem = bm[i].mnem;
211 id->op_order_ = bm[i].op_order_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 id->type = type;
214 }
215}
216
217
218void InstructionTable::SetTableRange(InstructionType type,
219 byte start,
220 byte end,
221 const char* mnem) {
222 for (byte b = start; b <= end; b++) {
223 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000224 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000225 id->mnem = mnem;
226 id->type = type;
227 }
228}
229
230
231void InstructionTable::AddJumpConditionalShort() {
232 for (byte b = 0x70; b <= 0x7F; b++) {
233 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 id->mnem = jump_conditional_mnem[b & 0x0F];
236 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
237 }
238}
239
240
Steve Blocka7e24c12009-10-30 11:49:00 +0000241// The IA32 disassembler implementation.
242class DisassemblerIA32 {
243 public:
244 DisassemblerIA32(const NameConverter& converter,
245 bool abort_on_unimplemented = true)
246 : converter_(converter),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400247 vex_byte0_(0),
248 vex_byte1_(0),
249 vex_byte2_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100250 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000251 tmp_buffer_pos_(0),
252 abort_on_unimplemented_(abort_on_unimplemented) {
253 tmp_buffer_[0] = '\0';
254 }
255
256 virtual ~DisassemblerIA32() {}
257
258 // Writes one disassembled instruction into 'buffer' (0-terminated).
259 // Returns the length of the disassembled machine instruction in bytes.
260 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
261
262 private:
263 const NameConverter& converter_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 byte vex_byte0_; // 0xc4 or 0xc5
265 byte vex_byte1_;
266 byte vex_byte2_; // only for 3 bytes vex prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100267 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
269 unsigned int tmp_buffer_pos_;
270 bool abort_on_unimplemented_;
271
Steve Blocka7e24c12009-10-30 11:49:00 +0000272 enum {
273 eax = 0,
274 ecx = 1,
275 edx = 2,
276 ebx = 3,
277 esp = 4,
278 ebp = 5,
279 esi = 6,
280 edi = 7
281 };
282
283
Steve Blockd0582a62009-12-15 09:54:21 +0000284 enum ShiftOpcodeExtension {
285 kROL = 0,
286 kROR = 1,
287 kRCL = 2,
288 kRCR = 3,
289 kSHL = 4,
290 KSHR = 5,
291 kSAR = 7
292 };
293
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 bool vex_128() {
295 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
296 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
297 return (checked & 4) != 1;
298 }
299
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 bool vex_none() {
301 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
302 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
303 return (checked & 3) == 0;
304 }
305
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400306 bool vex_66() {
307 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
308 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
309 return (checked & 3) == 1;
310 }
311
312 bool vex_f3() {
313 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
314 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
315 return (checked & 3) == 2;
316 }
317
318 bool vex_f2() {
319 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
320 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
321 return (checked & 3) == 3;
322 }
323
324 bool vex_w() {
325 if (vex_byte0_ == 0xc5) return false;
326 return (vex_byte2_ & 0x80) != 0;
327 }
328
329 bool vex_0f() {
330 if (vex_byte0_ == 0xc5) return true;
331 return (vex_byte1_ & 3) == 1;
332 }
333
334 bool vex_0f38() {
335 if (vex_byte0_ == 0xc5) return false;
336 return (vex_byte1_ & 3) == 2;
337 }
338
339 bool vex_0f3a() {
340 if (vex_byte0_ == 0xc5) return false;
341 return (vex_byte1_ & 3) == 3;
342 }
343
344 int vex_vreg() {
345 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
346 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
347 return ~(checked >> 3) & 0xf;
348 }
349
350 char float_size_code() { return "sd"[vex_w()]; }
Steve Blockd0582a62009-12-15 09:54:21 +0000351
Steve Blocka7e24c12009-10-30 11:49:00 +0000352 const char* NameOfCPURegister(int reg) const {
353 return converter_.NameOfCPURegister(reg);
354 }
355
356
357 const char* NameOfByteCPURegister(int reg) const {
358 return converter_.NameOfByteCPURegister(reg);
359 }
360
361
362 const char* NameOfXMMRegister(int reg) const {
363 return converter_.NameOfXMMRegister(reg);
364 }
365
366
367 const char* NameOfAddress(byte* addr) const {
368 return converter_.NameOfAddress(addr);
369 }
370
371
372 // Disassembler helper functions.
373 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
374 *mod = (data >> 6) & 3;
375 *regop = (data & 0x38) >> 3;
376 *rm = data & 7;
377 }
378
379
380 static void get_sib(byte data, int* scale, int* index, int* base) {
381 *scale = (data >> 6) & 3;
382 *index = (data >> 3) & 7;
383 *base = data & 7;
384 }
385
386 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
387
388 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
389 int PrintRightOperand(byte* modrmp);
390 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100391 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
393 int PrintImmediateOp(byte* data);
394 int F7Instruction(byte* data);
395 int D1D3C1Instruction(byte* data);
396 int JumpShort(byte* data);
397 int JumpConditional(byte* data, const char* comment);
398 int JumpConditionalShort(byte* data, const char* comment);
399 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000400 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000402 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
403 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400404 int AVXInstruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000405 void AppendToBuffer(const char* format, ...);
406
407
408 void UnimplementedInstruction() {
409 if (abort_on_unimplemented_) {
410 UNIMPLEMENTED();
411 } else {
412 AppendToBuffer("'Unimplemented Instruction'");
413 }
414 }
415};
416
417
418void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
419 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
420 va_list args;
421 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 va_end(args);
424 tmp_buffer_pos_ += result;
425}
426
427int DisassemblerIA32::PrintRightOperandHelper(
428 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100429 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000430 int mod, regop, rm;
431 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100432 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
433 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000434 switch (mod) {
435 case 0:
436 if (rm == ebp) {
437 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
438 AppendToBuffer("[0x%x]", disp);
439 return 5;
440 } else if (rm == esp) {
441 byte sib = *(modrmp + 1);
442 int scale, index, base;
443 get_sib(sib, &scale, &index, &base);
444 if (index == esp && base == esp && scale == 0 /*times_1*/) {
445 AppendToBuffer("[%s]", (this->*register_name)(rm));
446 return 2;
447 } else if (base == ebp) {
448 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 AppendToBuffer("[%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000450 (this->*register_name)(index),
451 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452 disp < 0 ? "-" : "+",
453 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 return 6;
455 } else if (index != esp && base != ebp) {
456 // [base+index*scale]
457 AppendToBuffer("[%s+%s*%d]",
458 (this->*register_name)(base),
459 (this->*register_name)(index),
460 1 << scale);
461 return 2;
462 } else {
463 UnimplementedInstruction();
464 return 1;
465 }
466 } else {
467 AppendToBuffer("[%s]", (this->*register_name)(rm));
468 return 1;
469 }
470 break;
471 case 1: // fall through
472 case 2:
473 if (rm == esp) {
474 byte sib = *(modrmp + 1);
475 int scale, index, base;
476 get_sib(sib, &scale, &index, &base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
478 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000480 AppendToBuffer("[%s%s0x%x]",
481 (this->*register_name)(rm),
482 disp < 0 ? "-" : "+",
483 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000485 AppendToBuffer("[%s+%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000486 (this->*register_name)(base),
487 (this->*register_name)(index),
488 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489 disp < 0 ? "-" : "+",
490 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000491 }
492 return mod == 2 ? 6 : 3;
493 } else {
494 // No sib.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
496 : *reinterpret_cast<int8_t*>(modrmp + 1);
497 AppendToBuffer("[%s%s0x%x]",
498 (this->*register_name)(rm),
499 disp < 0 ? "-" : "+",
500 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000501 return mod == 2 ? 5 : 2;
502 }
503 break;
504 case 3:
505 AppendToBuffer("%s", (this->*register_name)(rm));
506 return 1;
507 default:
508 UnimplementedInstruction();
509 return 1;
510 }
511 UNREACHABLE();
512}
513
514
515int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
516 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
517}
518
519
520int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
521 return PrintRightOperandHelper(modrmp,
522 &DisassemblerIA32::NameOfByteCPURegister);
523}
524
525
Steve Block44f0eee2011-05-26 01:26:41 +0100526int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
527 return PrintRightOperandHelper(modrmp,
528 &DisassemblerIA32::NameOfXMMRegister);
529}
530
531
Steve Blocka7e24c12009-10-30 11:49:00 +0000532// Returns number of bytes used including the current *data.
533// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
534int DisassemblerIA32::PrintOperands(const char* mnem,
535 OperandOrder op_order,
536 byte* data) {
537 byte modrm = *data;
538 int mod, regop, rm;
539 get_modrm(modrm, &mod, &regop, &rm);
540 int advance = 0;
541 switch (op_order) {
542 case REG_OPER_OP_ORDER: {
543 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
544 advance = PrintRightOperand(data);
545 break;
546 }
547 case OPER_REG_OP_ORDER: {
548 AppendToBuffer("%s ", mnem);
549 advance = PrintRightOperand(data);
550 AppendToBuffer(",%s", NameOfCPURegister(regop));
551 break;
552 }
553 default:
554 UNREACHABLE();
555 break;
556 }
557 return advance;
558}
559
560
561// Returns number of bytes used by machine instruction, including *data byte.
562// Writes immediate instructions to 'tmp_buffer_'.
563int DisassemblerIA32::PrintImmediateOp(byte* data) {
564 bool sign_extension_bit = (*data & 0x02) != 0;
565 byte modrm = *(data+1);
566 int mod, regop, rm;
567 get_modrm(modrm, &mod, &regop, &rm);
568 const char* mnem = "Imm???";
569 switch (regop) {
570 case 0: mnem = "add"; break;
571 case 1: mnem = "or"; break;
572 case 2: mnem = "adc"; break;
573 case 4: mnem = "and"; break;
574 case 5: mnem = "sub"; break;
575 case 6: mnem = "xor"; break;
576 case 7: mnem = "cmp"; break;
577 default: UnimplementedInstruction();
578 }
579 AppendToBuffer("%s ", mnem);
580 int count = PrintRightOperand(data+1);
581 if (sign_extension_bit) {
582 AppendToBuffer(",0x%x", *(data + 1 + count));
583 return 1 + count + 1 /*int8*/;
584 } else {
585 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
586 return 1 + count + 4 /*int32_t*/;
587 }
588}
589
590
591// Returns number of bytes used, including *data.
592int DisassemblerIA32::F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 DCHECK_EQ(0xF7, *data);
594 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000595 int mod, regop, rm;
596 get_modrm(modrm, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000597 const char* mnem = NULL;
598 switch (regop) {
599 case 0:
600 mnem = "test";
601 break;
602 case 2:
603 mnem = "not";
604 break;
605 case 3:
606 mnem = "neg";
607 break;
608 case 4:
609 mnem = "mul";
610 break;
611 case 5:
612 mnem = "imul";
613 break;
614 case 6:
615 mnem = "div";
616 break;
617 case 7:
618 mnem = "idiv";
619 break;
620 default:
621 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 AppendToBuffer("%s ", mnem);
624 int count = PrintRightOperand(data);
625 if (regop == 0) {
626 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
627 count += 4;
628 }
629 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000630}
631
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000632
Steve Blocka7e24c12009-10-30 11:49:00 +0000633int DisassemblerIA32::D1D3C1Instruction(byte* data) {
634 byte op = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
636 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000637 int mod, regop, rm;
638 get_modrm(modrm, &mod, &regop, &rm);
639 int imm8 = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640 const char* mnem = NULL;
641 switch (regop) {
642 case kROL:
643 mnem = "rol";
644 break;
645 case kROR:
646 mnem = "ror";
647 break;
648 case kRCL:
649 mnem = "rcl";
650 break;
651 case kRCR:
652 mnem = "rcr";
653 break;
654 case kSHL:
655 mnem = "shl";
656 break;
657 case KSHR:
658 mnem = "shr";
659 break;
660 case kSAR:
661 mnem = "sar";
662 break;
663 default:
664 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000665 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666 AppendToBuffer("%s ", mnem);
667 int count = PrintRightOperand(data);
668 if (op == 0xD1) {
669 imm8 = 1;
670 } else if (op == 0xC1) {
671 imm8 = *(data + 1);
672 count++;
673 } else if (op == 0xD3) {
674 // Shift/rotate by cl.
675 }
676 if (imm8 >= 0) {
677 AppendToBuffer(",%d", imm8);
678 } else {
679 AppendToBuffer(",cl");
680 }
681 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000682}
683
684
685// Returns number of bytes used, including *data.
686int DisassemblerIA32::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000687 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 byte b = *(data+1);
689 byte* dest = data + static_cast<int8_t>(b) + 2;
690 AppendToBuffer("jmp %s", NameOfAddress(dest));
691 return 2;
692}
693
694
695// Returns number of bytes used, including *data.
696int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000698 byte cond = *(data+1) & 0x0F;
699 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
700 const char* mnem = jump_conditional_mnem[cond];
701 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
702 if (comment != NULL) {
703 AppendToBuffer(", %s", comment);
704 }
705 return 6; // includes 0x0F
706}
707
708
709// Returns number of bytes used, including *data.
710int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
711 byte cond = *data & 0x0F;
712 byte b = *(data+1);
713 byte* dest = data + static_cast<int8_t>(b) + 2;
714 const char* mnem = jump_conditional_mnem[cond];
715 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
716 if (comment != NULL) {
717 AppendToBuffer(", %s", comment);
718 }
719 return 2;
720}
721
722
723// Returns number of bytes used, including *data.
724int DisassemblerIA32::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000725 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 byte cond = *(data+1) & 0x0F;
727 const char* mnem = set_conditional_mnem[cond];
728 AppendToBuffer("%s ", mnem);
729 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000730 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000731}
732
733
734// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000735int DisassemblerIA32::CMov(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 DCHECK_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000737 byte cond = *(data + 1) & 0x0F;
738 const char* mnem = conditional_move_mnem[cond];
739 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
740 return 2 + op_size; // includes 0x0F
741}
742
743
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400744int DisassemblerIA32::AVXInstruction(byte* data) {
745 byte opcode = *data;
746 byte* current = data + 1;
747 if (vex_66() && vex_0f38()) {
748 int mod, regop, rm, vvvv = vex_vreg();
749 get_modrm(*current, &mod, &regop, &rm);
750 switch (opcode) {
751 case 0x99:
752 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
753 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
754 current += PrintRightXMMOperand(current);
755 break;
756 case 0xa9:
757 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
758 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
759 current += PrintRightXMMOperand(current);
760 break;
761 case 0xb9:
762 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
763 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
764 current += PrintRightXMMOperand(current);
765 break;
766 case 0x9b:
767 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
768 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
769 current += PrintRightXMMOperand(current);
770 break;
771 case 0xab:
772 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
773 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
774 current += PrintRightXMMOperand(current);
775 break;
776 case 0xbb:
777 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
778 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
779 current += PrintRightXMMOperand(current);
780 break;
781 case 0x9d:
782 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
783 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
784 current += PrintRightXMMOperand(current);
785 break;
786 case 0xad:
787 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
788 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
789 current += PrintRightXMMOperand(current);
790 break;
791 case 0xbd:
792 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
793 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
794 current += PrintRightXMMOperand(current);
795 break;
796 case 0x9f:
797 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
798 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
799 current += PrintRightXMMOperand(current);
800 break;
801 case 0xaf:
802 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
803 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
804 current += PrintRightXMMOperand(current);
805 break;
806 case 0xbf:
807 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
808 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
809 current += PrintRightXMMOperand(current);
810 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 case 0xf7:
812 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
813 current += PrintRightOperand(current);
814 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
815 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400816 default:
817 UnimplementedInstruction();
818 }
819 } else if (vex_f2() && vex_0f()) {
820 int mod, regop, rm, vvvv = vex_vreg();
821 get_modrm(*current, &mod, &regop, &rm);
822 switch (opcode) {
823 case 0x58:
824 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
825 NameOfXMMRegister(vvvv));
826 current += PrintRightXMMOperand(current);
827 break;
828 case 0x59:
829 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
830 NameOfXMMRegister(vvvv));
831 current += PrintRightXMMOperand(current);
832 break;
833 case 0x5c:
834 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
835 NameOfXMMRegister(vvvv));
836 current += PrintRightXMMOperand(current);
837 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000838 case 0x5d:
839 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
840 NameOfXMMRegister(vvvv));
841 current += PrintRightXMMOperand(current);
842 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400843 case 0x5e:
844 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
845 NameOfXMMRegister(vvvv));
846 current += PrintRightXMMOperand(current);
847 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 case 0x5f:
849 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
850 NameOfXMMRegister(vvvv));
851 current += PrintRightXMMOperand(current);
852 break;
853 default:
854 UnimplementedInstruction();
855 }
856 } else if (vex_f3() && vex_0f()) {
857 int mod, regop, rm, vvvv = vex_vreg();
858 get_modrm(*current, &mod, &regop, &rm);
859 switch (opcode) {
860 case 0x58:
861 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
862 NameOfXMMRegister(vvvv));
863 current += PrintRightXMMOperand(current);
864 break;
865 case 0x59:
866 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
867 NameOfXMMRegister(vvvv));
868 current += PrintRightXMMOperand(current);
869 break;
870 case 0x5c:
871 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
872 NameOfXMMRegister(vvvv));
873 current += PrintRightXMMOperand(current);
874 break;
875 case 0x5d:
876 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
877 NameOfXMMRegister(vvvv));
878 current += PrintRightXMMOperand(current);
879 break;
880 case 0x5e:
881 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
882 NameOfXMMRegister(vvvv));
883 current += PrintRightXMMOperand(current);
884 break;
885 case 0x5f:
886 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
887 NameOfXMMRegister(vvvv));
888 current += PrintRightXMMOperand(current);
889 break;
890 default:
891 UnimplementedInstruction();
892 }
893 } else if (vex_none() && vex_0f38()) {
894 int mod, regop, rm, vvvv = vex_vreg();
895 get_modrm(*current, &mod, &regop, &rm);
896 const char* mnem = "?";
897 switch (opcode) {
898 case 0xf2:
899 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
900 NameOfCPURegister(vvvv));
901 current += PrintRightOperand(current);
902 break;
903 case 0xf5:
904 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
905 current += PrintRightOperand(current);
906 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
907 break;
908 case 0xf7:
909 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
910 current += PrintRightOperand(current);
911 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
912 break;
913 case 0xf3:
914 switch (regop) {
915 case 1:
916 mnem = "blsr";
917 break;
918 case 2:
919 mnem = "blsmsk";
920 break;
921 case 3:
922 mnem = "blsi";
923 break;
924 default:
925 UnimplementedInstruction();
926 }
927 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
928 current += PrintRightOperand(current);
929 mnem = "?";
930 break;
931 default:
932 UnimplementedInstruction();
933 }
934 } else if (vex_f2() && vex_0f38()) {
935 int mod, regop, rm, vvvv = vex_vreg();
936 get_modrm(*current, &mod, &regop, &rm);
937 switch (opcode) {
938 case 0xf5:
939 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
940 NameOfCPURegister(vvvv));
941 current += PrintRightOperand(current);
942 break;
943 case 0xf6:
944 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
945 NameOfCPURegister(vvvv));
946 current += PrintRightOperand(current);
947 break;
948 case 0xf7:
949 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
950 current += PrintRightOperand(current);
951 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
952 break;
953 default:
954 UnimplementedInstruction();
955 }
956 } else if (vex_f3() && vex_0f38()) {
957 int mod, regop, rm, vvvv = vex_vreg();
958 get_modrm(*current, &mod, &regop, &rm);
959 switch (opcode) {
960 case 0xf5:
961 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
962 NameOfCPURegister(vvvv));
963 current += PrintRightOperand(current);
964 break;
965 case 0xf7:
966 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
967 current += PrintRightOperand(current);
968 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
969 break;
970 default:
971 UnimplementedInstruction();
972 }
973 } else if (vex_f2() && vex_0f3a()) {
974 int mod, regop, rm;
975 get_modrm(*current, &mod, &regop, &rm);
976 switch (opcode) {
977 case 0xf0:
978 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
979 current += PrintRightOperand(current);
980 AppendToBuffer(",%d", *current & 0x1f);
981 current += 1;
982 break;
983 default:
984 UnimplementedInstruction();
985 }
986 } else if (vex_none() && vex_0f()) {
987 int mod, regop, rm, vvvv = vex_vreg();
988 get_modrm(*current, &mod, &regop, &rm);
989 switch (opcode) {
990 case 0x54:
991 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
992 NameOfXMMRegister(vvvv));
993 current += PrintRightXMMOperand(current);
994 break;
995 case 0x57:
996 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
997 NameOfXMMRegister(vvvv));
998 current += PrintRightXMMOperand(current);
999 break;
1000 default:
1001 UnimplementedInstruction();
1002 }
1003 } else if (vex_66() && vex_0f()) {
1004 int mod, regop, rm, vvvv = vex_vreg();
1005 get_modrm(*current, &mod, &regop, &rm);
1006 switch (opcode) {
1007 case 0x54:
1008 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1009 NameOfXMMRegister(vvvv));
1010 current += PrintRightXMMOperand(current);
1011 break;
1012 case 0x57:
1013 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1014 NameOfXMMRegister(vvvv));
1015 current += PrintRightXMMOperand(current);
1016 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001017 default:
1018 UnimplementedInstruction();
1019 }
1020 } else {
1021 UnimplementedInstruction();
1022 }
1023
1024 return static_cast<int>(current - data);
1025}
1026
1027
Steve Block3ce2e202009-11-05 08:53:23 +00001028// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +00001029int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001030 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001031 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001032 byte modrm_byte = *(data+1);
1033
1034 if (modrm_byte >= 0xC0) {
1035 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1036 } else {
1037 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001038 }
Steve Blockd0582a62009-12-15 09:54:21 +00001039}
1040
1041int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
1042 int modrm_byte,
1043 byte* modrm_start) {
1044 const char* mnem = "?";
1045 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1046 switch (escape_opcode) {
1047 case 0xD9: switch (regop) {
1048 case 0: mnem = "fld_s"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001049 case 2: mnem = "fst_s"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001050 case 3: mnem = "fstp_s"; break;
1051 case 7: mnem = "fstcw"; break;
1052 default: UnimplementedInstruction();
1053 }
1054 break;
1055
1056 case 0xDB: switch (regop) {
1057 case 0: mnem = "fild_s"; break;
1058 case 1: mnem = "fisttp_s"; break;
1059 case 2: mnem = "fist_s"; break;
1060 case 3: mnem = "fistp_s"; break;
1061 default: UnimplementedInstruction();
1062 }
1063 break;
1064
1065 case 0xDD: switch (regop) {
1066 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001067 case 1: mnem = "fisttp_d"; break;
1068 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001069 case 3: mnem = "fstp_d"; break;
1070 default: UnimplementedInstruction();
1071 }
1072 break;
1073
1074 case 0xDF: switch (regop) {
1075 case 5: mnem = "fild_d"; break;
1076 case 7: mnem = "fistp_d"; break;
1077 default: UnimplementedInstruction();
1078 }
1079 break;
1080
1081 default: UnimplementedInstruction();
1082 }
1083 AppendToBuffer("%s ", mnem);
1084 int count = PrintRightOperand(modrm_start);
1085 return count + 1;
1086}
1087
1088int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1089 byte modrm_byte) {
1090 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1091 const char* mnem = "?";
1092
1093 switch (escape_opcode) {
1094 case 0xD8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001095 has_register = true;
1096 switch (modrm_byte & 0xF8) {
1097 case 0xC0: mnem = "fadd_i"; break;
1098 case 0xE0: mnem = "fsub_i"; break;
1099 case 0xC8: mnem = "fmul_i"; break;
1100 case 0xF0: mnem = "fdiv_i"; break;
1101 default: UnimplementedInstruction();
1102 }
Steve Blockd0582a62009-12-15 09:54:21 +00001103 break;
1104
1105 case 0xD9:
1106 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001107 case 0xC0:
1108 mnem = "fld";
1109 has_register = true;
1110 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001111 case 0xC8:
1112 mnem = "fxch";
1113 has_register = true;
1114 break;
1115 default:
1116 switch (modrm_byte) {
1117 case 0xE0: mnem = "fchs"; break;
1118 case 0xE1: mnem = "fabs"; break;
1119 case 0xE4: mnem = "ftst"; break;
1120 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +00001121 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001122 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001123 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001124 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001125 case 0xF1: mnem = "fyl2x"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001126 case 0xF4: mnem = "fxtract"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001127 case 0xF5: mnem = "fprem1"; break;
1128 case 0xF7: mnem = "fincstp"; break;
1129 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001130 case 0xFC: mnem = "frndint"; break;
1131 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001132 case 0xFE: mnem = "fsin"; break;
1133 case 0xFF: mnem = "fcos"; break;
1134 default: UnimplementedInstruction();
1135 }
1136 }
1137 break;
1138
1139 case 0xDA:
1140 if (modrm_byte == 0xE9) {
1141 mnem = "fucompp";
1142 } else {
1143 UnimplementedInstruction();
1144 }
1145 break;
1146
1147 case 0xDB:
1148 if ((modrm_byte & 0xF8) == 0xE8) {
1149 mnem = "fucomi";
1150 has_register = true;
1151 } else if (modrm_byte == 0xE2) {
1152 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001153 } else if (modrm_byte == 0xE3) {
1154 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001155 } else {
1156 UnimplementedInstruction();
1157 }
1158 break;
1159
1160 case 0xDC:
1161 has_register = true;
1162 switch (modrm_byte & 0xF8) {
1163 case 0xC0: mnem = "fadd"; break;
1164 case 0xE8: mnem = "fsub"; break;
1165 case 0xC8: mnem = "fmul"; break;
1166 case 0xF8: mnem = "fdiv"; break;
1167 default: UnimplementedInstruction();
1168 }
1169 break;
1170
1171 case 0xDD:
1172 has_register = true;
1173 switch (modrm_byte & 0xF8) {
1174 case 0xC0: mnem = "ffree"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001175 case 0xD0: mnem = "fst"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001176 case 0xD8: mnem = "fstp"; break;
1177 default: UnimplementedInstruction();
1178 }
1179 break;
1180
1181 case 0xDE:
1182 if (modrm_byte == 0xD9) {
1183 mnem = "fcompp";
1184 } else {
1185 has_register = true;
1186 switch (modrm_byte & 0xF8) {
1187 case 0xC0: mnem = "faddp"; break;
1188 case 0xE8: mnem = "fsubp"; break;
1189 case 0xC8: mnem = "fmulp"; break;
1190 case 0xF8: mnem = "fdivp"; break;
1191 default: UnimplementedInstruction();
1192 }
1193 }
1194 break;
1195
1196 case 0xDF:
1197 if (modrm_byte == 0xE0) {
1198 mnem = "fnstsw_ax";
1199 } else if ((modrm_byte & 0xF8) == 0xE8) {
1200 mnem = "fucomip";
1201 has_register = true;
1202 }
1203 break;
1204
1205 default: UnimplementedInstruction();
1206 }
1207
1208 if (has_register) {
1209 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1210 } else {
1211 AppendToBuffer("%s", mnem);
1212 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001213 return 2;
1214}
1215
1216
1217// Mnemonics for instructions 0xF0 byte.
1218// Returns NULL if the instruction is not handled here.
1219static const char* F0Mnem(byte f0byte) {
1220 switch (f0byte) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001221 case 0x0B:
1222 return "ud2";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001223 case 0x18: return "prefetch";
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 case 0xA2: return "cpuid";
Steve Blocka7e24c12009-10-30 11:49:00 +00001225 case 0xBE: return "movsx_b";
1226 case 0xBF: return "movsx_w";
1227 case 0xB6: return "movzx_b";
1228 case 0xB7: return "movzx_w";
1229 case 0xAF: return "imul";
1230 case 0xA5: return "shld";
1231 case 0xAD: return "shrd";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001232 case 0xAC: return "shrd"; // 3-operand version.
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 case 0xAB: return "bts";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001234 case 0xBC:
1235 return "bsf";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236 case 0xBD: return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 default: return NULL;
1238 }
1239}
1240
1241
1242// Disassembled instruction '*instr' and writes it into 'out_buffer'.
1243int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1244 byte* instr) {
1245 tmp_buffer_pos_ = 0; // starting to write as position 0
1246 byte* data = instr;
1247 // Check for hints.
1248 const char* branch_hint = NULL;
1249 // We use these two prefixes only with branch prediction
1250 if (*data == 0x3E /*ds*/) {
1251 branch_hint = "predicted taken";
1252 data++;
1253 } else if (*data == 0x2E /*cs*/) {
1254 branch_hint = "predicted not taken";
1255 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001256 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1257 vex_byte0_ = *data;
1258 vex_byte1_ = *(data + 1);
1259 vex_byte2_ = *(data + 2);
1260 data += 3;
1261 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1262 vex_byte0_ = *data;
1263 vex_byte1_ = *(data + 1);
1264 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001266
Steve Blocka7e24c12009-10-30 11:49:00 +00001267 bool processed = true; // Will be set to false if the current instruction
1268 // is not in 'instructions' table.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001269 // Decode AVX instructions.
1270 if (vex_byte0_ != 0) {
1271 data += AVXInstruction(data);
1272 } else {
1273 const InstructionDesc& idesc = instruction_table_->Get(*data);
1274 switch (idesc.type) {
1275 case ZERO_OPERANDS_INSTR:
1276 AppendToBuffer(idesc.mnem);
1277 data++;
1278 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001279
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001280 case TWO_OPERANDS_INSTR:
1281 data++;
1282 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1283 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001284
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001285 case JUMP_CONDITIONAL_SHORT_INSTR:
1286 data += JumpConditionalShort(data, branch_hint);
1287 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001288
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001289 case REGISTER_INSTR:
1290 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1291 data++;
1292 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001293
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001294 case MOVE_REG_INSTR: {
1295 byte* addr =
1296 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1297 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1298 NameOfAddress(addr));
1299 data += 5;
1300 break;
1301 }
1302
1303 case CALL_JUMP_INSTR: {
1304 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1305 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1306 data += 5;
1307 break;
1308 }
1309
1310 case SHORT_IMMEDIATE_INSTR: {
1311 byte* addr =
1312 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1313 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1314 data += 5;
1315 break;
1316 }
1317
1318 case BYTE_IMMEDIATE_INSTR: {
1319 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1320 data += 2;
1321 break;
1322 }
1323
1324 case NO_INSTR:
1325 processed = false;
1326 break;
1327
1328 default:
1329 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 }
1332 //----------------------------
1333 if (!processed) {
1334 switch (*data) {
1335 case 0xC2:
1336 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1337 data += 3;
1338 break;
1339
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001340 case 0x6B: {
1341 data++;
1342 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1343 AppendToBuffer(",%d", *data);
1344 data++;
1345 } break;
1346
1347 case 0x69: {
1348 data++;
1349 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1350 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1351 data += 4;
Steve Blocka7e24c12009-10-30 11:49:00 +00001352 }
1353 break;
1354
1355 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001356 { data++;
1357 int mod, regop, rm;
1358 get_modrm(*data, &mod, &regop, &rm);
1359 if (regop == eax) {
1360 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +01001361 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001362 int32_t imm = *data;
1363 AppendToBuffer(",0x%x", imm);
1364 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 } else {
1366 UnimplementedInstruction();
1367 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001368 }
1369 break;
1370
1371 case 0x81: // fall through
1372 case 0x83: // 0x81 with sign extension bit set
1373 data += PrintImmediateOp(data);
1374 break;
1375
1376 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001377 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001379 if (f0byte == 0x18) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380 data += 2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001381 int mod, regop, rm;
1382 get_modrm(*data, &mod, &regop, &rm);
1383 const char* suffix[] = {"nta", "1", "2", "3"};
1384 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1385 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001386 } else if (f0byte == 0x1F && data[2] == 0) {
1387 AppendToBuffer("nop"); // 3 byte nop.
1388 data += 3;
1389 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1390 AppendToBuffer("nop"); // 4 byte nop.
1391 data += 4;
1392 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1393 data[4] == 0) {
1394 AppendToBuffer("nop"); // 5 byte nop.
1395 data += 5;
1396 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1397 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1398 AppendToBuffer("nop"); // 7 byte nop.
1399 data += 7;
1400 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1401 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1402 data[7] == 0) {
1403 AppendToBuffer("nop"); // 8 byte nop.
1404 data += 8;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001405 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001406 AppendToBuffer("%s", f0mnem);
1407 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001408 } else if (f0byte == 0x28) {
1409 data += 2;
1410 int mod, regop, rm;
1411 get_modrm(*data, &mod, &regop, &rm);
1412 AppendToBuffer("movaps %s,%s",
1413 NameOfXMMRegister(regop),
1414 NameOfXMMRegister(rm));
1415 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001416 } else if (f0byte == 0x2e) {
1417 data += 2;
1418 int mod, regop, rm;
1419 get_modrm(*data, &mod, &regop, &rm);
1420 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1421 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001422 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1423 const char* const pseudo_op[] = {
1424 "rcpps",
1425 "andps",
1426 "andnps",
1427 "orps",
1428 "xorps",
1429 "addps",
1430 "mulps",
1431 "cvtps2pd",
1432 "cvtdq2ps",
1433 "subps",
1434 "minps",
1435 "divps",
1436 "maxps",
1437 };
1438
Ben Murdoch257744e2011-11-30 15:57:28 +00001439 data += 2;
1440 int mod, regop, rm;
1441 get_modrm(*data, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 AppendToBuffer("%s %s,",
1443 pseudo_op[f0byte - 0x53],
1444 NameOfXMMRegister(regop));
1445 data += PrintRightXMMOperand(data);
1446 } else if (f0byte == 0x50) {
1447 data += 2;
1448 int mod, regop, rm;
1449 get_modrm(*data, &mod, &regop, &rm);
1450 AppendToBuffer("movmskps %s,%s",
1451 NameOfCPURegister(regop),
Ben Murdoch257744e2011-11-30 15:57:28 +00001452 NameOfXMMRegister(rm));
1453 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454 } else if (f0byte== 0xC6) {
1455 // shufps xmm, xmm/m128, imm8
1456 data += 2;
1457 int mod, regop, rm;
1458 get_modrm(*data, &mod, &regop, &rm);
1459 int8_t imm8 = static_cast<int8_t>(data[1]);
1460 AppendToBuffer("shufps %s,%s,%d",
1461 NameOfXMMRegister(rm),
1462 NameOfXMMRegister(regop),
1463 static_cast<int>(imm8));
1464 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 } else if ((f0byte & 0xF0) == 0x80) {
1466 data += JumpConditional(data, branch_hint);
1467 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1468 f0byte == 0xB7 || f0byte == 0xAF) {
1469 data += 2;
1470 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1471 } else if ((f0byte & 0xF0) == 0x90) {
1472 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001473 } else if ((f0byte & 0xF0) == 0x40) {
1474 data += CMov(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001475 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1476 // shrd, shld, bts
Steve Blocka7e24c12009-10-30 11:49:00 +00001477 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 AppendToBuffer("%s ", f0mnem);
1479 int mod, regop, rm;
1480 get_modrm(*data, &mod, &regop, &rm);
1481 data += PrintRightOperand(data);
1482 if (f0byte == 0xAB) {
1483 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001485 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001487 } else if (f0byte == 0xBC) {
1488 data += 2;
1489 int mod, regop, rm;
1490 get_modrm(*data, &mod, &regop, &rm);
1491 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1492 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001493 } else if (f0byte == 0xBD) {
1494 data += 2;
1495 int mod, regop, rm;
1496 get_modrm(*data, &mod, &regop, &rm);
1497 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1498 data += PrintRightOperand(data);
1499 } else {
1500 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 }
1502 }
1503 break;
1504
1505 case 0x8F:
1506 { data++;
1507 int mod, regop, rm;
1508 get_modrm(*data, &mod, &regop, &rm);
1509 if (regop == eax) {
1510 AppendToBuffer("pop ");
1511 data += PrintRightOperand(data);
1512 }
1513 }
1514 break;
1515
1516 case 0xFF:
1517 { data++;
1518 int mod, regop, rm;
1519 get_modrm(*data, &mod, &regop, &rm);
1520 const char* mnem = NULL;
1521 switch (regop) {
1522 case esi: mnem = "push"; break;
1523 case eax: mnem = "inc"; break;
1524 case ecx: mnem = "dec"; break;
1525 case edx: mnem = "call"; break;
1526 case esp: mnem = "jmp"; break;
1527 default: mnem = "???";
1528 }
1529 AppendToBuffer("%s ", mnem);
1530 data += PrintRightOperand(data);
1531 }
1532 break;
1533
1534 case 0xC7: // imm32, fall through
1535 case 0xC6: // imm8
1536 { bool is_byte = *data == 0xC6;
1537 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001538 if (is_byte) {
1539 AppendToBuffer("%s ", "mov_b");
1540 data += PrintRightByteOperand(data);
1541 int32_t imm = *data;
1542 AppendToBuffer(",0x%x", imm);
1543 data++;
1544 } else {
1545 AppendToBuffer("%s ", "mov");
1546 data += PrintRightOperand(data);
1547 int32_t imm = *reinterpret_cast<int32_t*>(data);
1548 AppendToBuffer(",0x%x", imm);
1549 data += 4;
1550 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 }
1552 break;
1553
1554 case 0x80:
1555 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001556 int mod, regop, rm;
1557 get_modrm(*data, &mod, &regop, &rm);
1558 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001559 switch (regop) {
1560 case 5: mnem = "subb"; break;
1561 case 7: mnem = "cmpb"; break;
1562 default: UnimplementedInstruction();
1563 }
1564 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001565 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001566 int32_t imm = *data;
1567 AppendToBuffer(",0x%x", imm);
1568 data++;
1569 }
1570 break;
1571
1572 case 0x88: // 8bit, fall through
1573 case 0x89: // 32bit
1574 { bool is_byte = *data == 0x88;
1575 int mod, regop, rm;
1576 data++;
1577 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001578 if (is_byte) {
1579 AppendToBuffer("%s ", "mov_b");
1580 data += PrintRightByteOperand(data);
1581 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1582 } else {
1583 AppendToBuffer("%s ", "mov");
1584 data += PrintRightOperand(data);
1585 AppendToBuffer(",%s", NameOfCPURegister(regop));
1586 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 }
1588 break;
1589
1590 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001591 while (*data == 0x66) data++;
1592 if (*data == 0xf && data[1] == 0x1f) {
1593 AppendToBuffer("nop"); // 0x66 prefix
1594 } else if (*data == 0x90) {
1595 AppendToBuffer("nop"); // 0x66 prefix
1596 } else if (*data == 0x8B) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001597 data++;
1598 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1599 } else if (*data == 0x89) {
1600 data++;
1601 int mod, regop, rm;
1602 get_modrm(*data, &mod, &regop, &rm);
1603 AppendToBuffer("mov_w ");
1604 data += PrintRightOperand(data);
1605 AppendToBuffer(",%s", NameOfCPURegister(regop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606 } else if (*data == 0xC7) {
1607 data++;
1608 AppendToBuffer("%s ", "mov_w");
1609 data += PrintRightOperand(data);
1610 int imm = *reinterpret_cast<int16_t*>(data);
1611 AppendToBuffer(",0x%x", imm);
1612 data += 2;
Steve Block3ce2e202009-11-05 08:53:23 +00001613 } else if (*data == 0x0F) {
1614 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001615 if (*data == 0x38) {
1616 data++;
1617 if (*data == 0x17) {
1618 data++;
1619 int mod, regop, rm;
1620 get_modrm(*data, &mod, &regop, &rm);
1621 AppendToBuffer("ptest %s,%s",
1622 NameOfXMMRegister(regop),
1623 NameOfXMMRegister(rm));
1624 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001625 } else if (*data == 0x2A) {
1626 // movntdqa
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001627 UnimplementedInstruction();
Steve Block6ded16b2010-05-10 14:33:55 +01001628 } else {
1629 UnimplementedInstruction();
1630 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001631 } else if (*data == 0x3A) {
1632 data++;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001633 if (*data == 0x0B) {
1634 data++;
1635 int mod, regop, rm;
1636 get_modrm(*data, &mod, &regop, &rm);
1637 int8_t imm8 = static_cast<int8_t>(data[1]);
1638 AppendToBuffer("roundsd %s,%s,%d",
1639 NameOfXMMRegister(regop),
1640 NameOfXMMRegister(rm),
1641 static_cast<int>(imm8));
1642 data += 2;
1643 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001644 data++;
1645 int mod, regop, rm;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001646 get_modrm(*data, &mod, &rm, &regop);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001647 int8_t imm8 = static_cast<int8_t>(data[1]);
1648 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001649 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001650 NameOfXMMRegister(rm),
1651 static_cast<int>(imm8));
1652 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001653 } else if (*data == 0x17) {
1654 data++;
1655 int mod, regop, rm;
1656 get_modrm(*data, &mod, &regop, &rm);
1657 int8_t imm8 = static_cast<int8_t>(data[1]);
1658 AppendToBuffer("extractps %s,%s,%d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001659 NameOfCPURegister(rm),
1660 NameOfXMMRegister(regop),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001661 static_cast<int>(imm8));
1662 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001663 } else if (*data == 0x22) {
1664 data++;
1665 int mod, regop, rm;
1666 get_modrm(*data, &mod, &regop, &rm);
1667 int8_t imm8 = static_cast<int8_t>(data[1]);
1668 AppendToBuffer("pinsrd %s,%s,%d",
1669 NameOfXMMRegister(regop),
1670 NameOfCPURegister(rm),
1671 static_cast<int>(imm8));
1672 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001673 } else {
1674 UnimplementedInstruction();
1675 }
Steve Block6ded16b2010-05-10 14:33:55 +01001676 } else if (*data == 0x2E || *data == 0x2F) {
1677 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001678 data++;
1679 int mod, regop, rm;
1680 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001681 if (mod == 0x3) {
1682 AppendToBuffer("%s %s,%s", mnem,
1683 NameOfXMMRegister(regop),
1684 NameOfXMMRegister(rm));
1685 data++;
1686 } else {
1687 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1688 data += PrintRightOperand(data);
1689 }
1690 } else if (*data == 0x50) {
1691 data++;
1692 int mod, regop, rm;
1693 get_modrm(*data, &mod, &regop, &rm);
1694 AppendToBuffer("movmskpd %s,%s",
1695 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001696 NameOfXMMRegister(rm));
1697 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001698 } else if (*data == 0x54) {
1699 data++;
1700 int mod, regop, rm;
1701 get_modrm(*data, &mod, &regop, &rm);
1702 AppendToBuffer("andpd %s,%s",
1703 NameOfXMMRegister(regop),
1704 NameOfXMMRegister(rm));
1705 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001706 } else if (*data == 0x56) {
1707 data++;
1708 int mod, regop, rm;
1709 get_modrm(*data, &mod, &regop, &rm);
1710 AppendToBuffer("orpd %s,%s",
1711 NameOfXMMRegister(regop),
1712 NameOfXMMRegister(rm));
1713 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001714 } else if (*data == 0x57) {
1715 data++;
1716 int mod, regop, rm;
1717 get_modrm(*data, &mod, &regop, &rm);
1718 AppendToBuffer("xorpd %s,%s",
1719 NameOfXMMRegister(regop),
1720 NameOfXMMRegister(rm));
1721 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001722 } else if (*data == 0x6E) {
1723 data++;
1724 int mod, regop, rm;
1725 get_modrm(*data, &mod, &regop, &rm);
1726 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1727 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001728 } else if (*data == 0x6F) {
1729 data++;
1730 int mod, regop, rm;
1731 get_modrm(*data, &mod, &regop, &rm);
1732 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001733 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001734 } else if (*data == 0x70) {
1735 data++;
1736 int mod, regop, rm;
1737 get_modrm(*data, &mod, &regop, &rm);
1738 int8_t imm8 = static_cast<int8_t>(data[1]);
1739 AppendToBuffer("pshufd %s,%s,%d",
1740 NameOfXMMRegister(regop),
1741 NameOfXMMRegister(rm),
1742 static_cast<int>(imm8));
1743 data += 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001744 } else if (*data == 0x62) {
1745 data++;
1746 int mod, regop, rm;
1747 get_modrm(*data, &mod, &regop, &rm);
1748 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop),
1749 NameOfXMMRegister(rm));
1750 data++;
1751 } else if (*data == 0x6A) {
1752 data++;
1753 int mod, regop, rm;
1754 get_modrm(*data, &mod, &regop, &rm);
1755 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop),
1756 NameOfXMMRegister(rm));
1757 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001758 } else if (*data == 0x76) {
1759 data++;
1760 int mod, regop, rm;
1761 get_modrm(*data, &mod, &regop, &rm);
1762 AppendToBuffer("pcmpeqd %s,%s",
1763 NameOfXMMRegister(regop),
1764 NameOfXMMRegister(rm));
1765 data++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001766 } else if (*data == 0x90) {
1767 data++;
1768 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001769 } else if (*data == 0xF3) {
1770 data++;
1771 int mod, regop, rm;
1772 get_modrm(*data, &mod, &regop, &rm);
1773 AppendToBuffer("psllq %s,%s",
1774 NameOfXMMRegister(regop),
1775 NameOfXMMRegister(rm));
1776 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001777 } else if (*data == 0x72) {
1778 data++;
1779 int mod, regop, rm;
1780 get_modrm(*data, &mod, &regop, &rm);
1781 int8_t imm8 = static_cast<int8_t>(data[1]);
1782 DCHECK(regop == esi || regop == edx);
1783 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1784 NameOfXMMRegister(rm), static_cast<int>(imm8));
1785 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001786 } else if (*data == 0x73) {
1787 data++;
1788 int mod, regop, rm;
1789 get_modrm(*data, &mod, &regop, &rm);
1790 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001791 DCHECK(regop == esi || regop == edx);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001792 AppendToBuffer("%s %s,%d",
1793 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001794 NameOfXMMRegister(rm),
1795 static_cast<int>(imm8));
1796 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001797 } else if (*data == 0xD3) {
1798 data++;
1799 int mod, regop, rm;
1800 get_modrm(*data, &mod, &regop, &rm);
1801 AppendToBuffer("psrlq %s,%s",
1802 NameOfXMMRegister(regop),
1803 NameOfXMMRegister(rm));
1804 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001805 } else if (*data == 0x7F) {
1806 AppendToBuffer("movdqa ");
1807 data++;
1808 int mod, regop, rm;
1809 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001810 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001811 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001812 } else if (*data == 0x7E) {
1813 data++;
1814 int mod, regop, rm;
1815 get_modrm(*data, &mod, &regop, &rm);
1816 AppendToBuffer("movd ");
1817 data += PrintRightOperand(data);
1818 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1819 } else if (*data == 0xDB) {
1820 data++;
1821 int mod, regop, rm;
1822 get_modrm(*data, &mod, &regop, &rm);
1823 AppendToBuffer("pand %s,%s",
1824 NameOfXMMRegister(regop),
1825 NameOfXMMRegister(rm));
1826 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001827 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001828 data++;
1829 int mod, regop, rm;
1830 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001831 if (mod == 3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001832 // movntdq
1833 UnimplementedInstruction();
Steve Block44f0eee2011-05-26 01:26:41 +01001834 } else {
1835 UnimplementedInstruction();
1836 }
Steve Block6ded16b2010-05-10 14:33:55 +01001837 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001838 data++;
1839 int mod, regop, rm;
1840 get_modrm(*data, &mod, &regop, &rm);
1841 AppendToBuffer("pxor %s,%s",
1842 NameOfXMMRegister(regop),
1843 NameOfXMMRegister(rm));
1844 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001845 } else if (*data == 0xEB) {
1846 data++;
1847 int mod, regop, rm;
1848 get_modrm(*data, &mod, &regop, &rm);
1849 AppendToBuffer("por %s,%s",
1850 NameOfXMMRegister(regop),
1851 NameOfXMMRegister(rm));
1852 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001853 } else {
1854 UnimplementedInstruction();
1855 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001856 } else {
1857 UnimplementedInstruction();
1858 }
1859 break;
1860
1861 case 0xFE:
1862 { data++;
1863 int mod, regop, rm;
1864 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001865 if (regop == ecx) {
1866 AppendToBuffer("dec_b ");
1867 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 } else {
1869 UnimplementedInstruction();
1870 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001871 }
1872 break;
1873
1874 case 0x68:
1875 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1876 data += 5;
1877 break;
1878
1879 case 0x6A:
1880 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1881 data += 2;
1882 break;
1883
1884 case 0xA8:
1885 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1886 data += 2;
1887 break;
1888
1889 case 0xA9:
1890 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1891 data += 5;
1892 break;
1893
1894 case 0xD1: // fall through
1895 case 0xD3: // fall through
1896 case 0xC1:
1897 data += D1D3C1Instruction(data);
1898 break;
1899
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900 case 0xD8: // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001901 case 0xD9: // fall through
1902 case 0xDA: // fall through
1903 case 0xDB: // fall through
1904 case 0xDC: // fall through
1905 case 0xDD: // fall through
1906 case 0xDE: // fall through
1907 case 0xDF:
1908 data += FPUInstruction(data);
1909 break;
1910
1911 case 0xEB:
1912 data += JumpShort(data);
1913 break;
1914
1915 case 0xF2:
1916 if (*(data+1) == 0x0F) {
1917 byte b2 = *(data+2);
1918 if (b2 == 0x11) {
1919 AppendToBuffer("movsd ");
1920 data += 3;
1921 int mod, regop, rm;
1922 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001923 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001924 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1925 } else if (b2 == 0x10) {
1926 data += 3;
1927 int mod, regop, rm;
1928 get_modrm(*data, &mod, &regop, &rm);
1929 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001930 data += PrintRightXMMOperand(data);
1931 } else if (b2 == 0x5A) {
1932 data += 3;
1933 int mod, regop, rm;
1934 get_modrm(*data, &mod, &regop, &rm);
1935 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1936 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001937 } else {
1938 const char* mnem = "?";
1939 switch (b2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001940 case 0x2A:
1941 mnem = "cvtsi2sd";
1942 break;
1943 case 0x2C:
1944 mnem = "cvttsd2si";
1945 break;
1946 case 0x2D:
1947 mnem = "cvtsd2si";
1948 break;
1949 case 0x51:
1950 mnem = "sqrtsd";
1951 break;
1952 case 0x58:
1953 mnem = "addsd";
1954 break;
1955 case 0x59:
1956 mnem = "mulsd";
1957 break;
1958 case 0x5C:
1959 mnem = "subsd";
1960 break;
1961 case 0x5D:
1962 mnem = "minsd";
1963 break;
1964 case 0x5E:
1965 mnem = "divsd";
1966 break;
1967 case 0x5F:
1968 mnem = "maxsd";
1969 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001970 }
1971 data += 3;
1972 int mod, regop, rm;
1973 get_modrm(*data, &mod, &regop, &rm);
1974 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01001975 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1976 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001977 } else if (b2 == 0x2C || b2 == 0x2D) {
Steve Block44f0eee2011-05-26 01:26:41 +01001978 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1979 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001980 } else if (b2 == 0xC2) {
1981 // Intel manual 2A, Table 3-18.
1982 const char* const pseudo_op[] = {
1983 "cmpeqsd",
1984 "cmpltsd",
1985 "cmplesd",
1986 "cmpunordsd",
1987 "cmpneqsd",
1988 "cmpnltsd",
1989 "cmpnlesd",
1990 "cmpordsd"
1991 };
1992 AppendToBuffer("%s %s,%s",
1993 pseudo_op[data[1]],
1994 NameOfXMMRegister(regop),
1995 NameOfXMMRegister(rm));
1996 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001997 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001998 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1999 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002000 }
2001 }
2002 } else {
2003 UnimplementedInstruction();
2004 }
2005 break;
2006
2007 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00002008 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01002009 byte b2 = *(data+2);
2010 if (b2 == 0x11) {
2011 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01002012 data += 3;
2013 int mod, regop, rm;
2014 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002015 data += PrintRightXMMOperand(data);
2016 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2017 } else if (b2 == 0x10) {
2018 data += 3;
2019 int mod, regop, rm;
2020 get_modrm(*data, &mod, &regop, &rm);
2021 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2022 data += PrintRightXMMOperand(data);
Steve Block44f0eee2011-05-26 01:26:41 +01002023 } else if (b2 == 0x5A) {
2024 data += 3;
2025 int mod, regop, rm;
2026 get_modrm(*data, &mod, &regop, &rm);
2027 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2028 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002029 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002030 data += 3;
2031 int mod, regop, rm;
2032 get_modrm(*data, &mod, &regop, &rm);
2033 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01002034 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002035 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00002036 AppendToBuffer("movdqu ");
2037 data += 3;
2038 int mod, regop, rm;
2039 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002040 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002041 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002042 } else if (b2 == 0xB8) {
2043 data += 3;
2044 int mod, regop, rm;
2045 get_modrm(*data, &mod, &regop, &rm);
2046 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2047 data += PrintRightOperand(data);
2048 } else if (b2 == 0xBC) {
2049 data += 3;
2050 int mod, regop, rm;
2051 get_modrm(*data, &mod, &regop, &rm);
2052 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2053 data += PrintRightOperand(data);
2054 } else if (b2 == 0xBD) {
2055 data += 3;
2056 int mod, regop, rm;
2057 get_modrm(*data, &mod, &regop, &rm);
2058 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2059 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00002060 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002061 const char* mnem = "?";
2062 switch (b2) {
2063 case 0x2A:
2064 mnem = "cvtsi2ss";
2065 break;
2066 case 0x2C:
2067 mnem = "cvttss2si";
2068 break;
2069 case 0x2D:
2070 mnem = "cvtss2si";
2071 break;
2072 case 0x51:
2073 mnem = "sqrtss";
2074 break;
2075 case 0x58:
2076 mnem = "addss";
2077 break;
2078 case 0x59:
2079 mnem = "mulss";
2080 break;
2081 case 0x5C:
2082 mnem = "subss";
2083 break;
2084 case 0x5D:
2085 mnem = "minss";
2086 break;
2087 case 0x5E:
2088 mnem = "divss";
2089 break;
2090 case 0x5F:
2091 mnem = "maxss";
2092 break;
2093 }
2094 data += 3;
2095 int mod, regop, rm;
2096 get_modrm(*data, &mod, &regop, &rm);
2097 if (b2 == 0x2A) {
2098 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2099 data += PrintRightOperand(data);
2100 } else if (b2 == 0x2C || b2 == 0x2D) {
2101 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2102 data += PrintRightXMMOperand(data);
2103 } else if (b2 == 0xC2) {
2104 // Intel manual 2A, Table 3-18.
2105 const char* const pseudo_op[] = {
2106 "cmpeqss", "cmpltss", "cmpless", "cmpunordss",
2107 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2108 AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2109 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2110 data += 2;
2111 } else {
2112 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2113 data += PrintRightXMMOperand(data);
2114 }
Leon Clarkee46be812010-01-19 14:06:41 +00002115 }
2116 } else if (*(data+1) == 0xA5) {
2117 data += 2;
2118 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01002119 } else if (*(data+1) == 0xAB) {
2120 data += 2;
2121 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00002122 } else {
2123 UnimplementedInstruction();
2124 }
2125 break;
2126
2127 case 0xF7:
2128 data += F7Instruction(data);
2129 break;
2130
2131 default:
2132 UnimplementedInstruction();
2133 }
2134 }
2135
2136 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2137 tmp_buffer_[tmp_buffer_pos_] = '\0';
2138 }
2139
2140 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00002141 if (instr_len == 0) {
2142 printf("%02x", *data);
2143 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002144 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002145
2146 int outp = 0;
2147 // Instruction bytes.
2148 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002149 outp += v8::internal::SNPrintF(out_buffer + outp,
2150 "%02x",
2151 *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002152 }
2153 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002154 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002155 }
2156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002157 outp += v8::internal::SNPrintF(out_buffer + outp,
2158 " %s",
2159 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002160 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002161} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00002162
2163
2164//------------------------------------------------------------------------------
2165
2166
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002167static const char* const cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002168 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
2169};
2170
2171
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002172static const char* const byte_cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002173 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
2174};
2175
2176
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002177static const char* const xmm_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002178 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
2179};
2180
2181
2182const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002183 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002184 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002185}
2186
2187
2188const char* NameConverter::NameOfConstant(byte* addr) const {
2189 return NameOfAddress(addr);
2190}
2191
2192
2193const char* NameConverter::NameOfCPURegister(int reg) const {
2194 if (0 <= reg && reg < 8) return cpu_regs[reg];
2195 return "noreg";
2196}
2197
2198
2199const char* NameConverter::NameOfByteCPURegister(int reg) const {
2200 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2201 return "noreg";
2202}
2203
2204
2205const char* NameConverter::NameOfXMMRegister(int reg) const {
2206 if (0 <= reg && reg < 8) return xmm_regs[reg];
2207 return "noxmmreg";
2208}
2209
2210
2211const char* NameConverter::NameInCode(byte* addr) const {
2212 // IA32 does not embed debug strings at the moment.
2213 UNREACHABLE();
2214 return "";
2215}
2216
2217
2218//------------------------------------------------------------------------------
2219
2220Disassembler::Disassembler(const NameConverter& converter)
2221 : converter_(converter) {}
2222
2223
2224Disassembler::~Disassembler() {}
2225
2226
2227int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2228 byte* instruction) {
2229 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
2230 return d.InstructionDecode(buffer, instruction);
2231}
2232
2233
2234// The IA-32 assembler does not currently use constant pools.
2235int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2236
2237
2238/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2239 NameConverter converter;
2240 Disassembler d(converter);
2241 for (byte* pc = begin; pc < end;) {
2242 v8::internal::EmbeddedVector<char, 128> buffer;
2243 buffer[0] = '\0';
2244 byte* prev_pc = pc;
2245 pc += d.InstructionDecode(buffer, pc);
2246 fprintf(f, "%p", prev_pc);
2247 fprintf(f, " ");
2248
2249 for (byte* bp = prev_pc; bp < pc; bp++) {
2250 fprintf(f, "%02x", *bp);
2251 }
2252 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2253 fprintf(f, " ");
2254 }
2255 fprintf(f, " %s\n", buffer.start());
2256 }
2257}
2258
2259
2260} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002261
2262#endif // V8_TARGET_ARCH_IA32