blob: d6798986a1622efe4118cb4e0704a6de14ac9b09 [file] [log] [blame]
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001// 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_X64
Leon Clarkef7060e22010-06-03 12:02:55 +010010
Ben Murdochc5610432016-08-08 18:44:38 +010011#include "src/base/compiler-specific.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/base/lazy-instance.h"
13#include "src/disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000014
15namespace disasm {
16
17enum OperandType {
18 UNSET_OP_ORDER = 0,
19 // Operand size decides between 16, 32 and 64 bit operands.
20 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
21 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
22 // Fixed 8-bit operands.
23 BYTE_SIZE_OPERAND_FLAG = 4,
24 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
25 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
26};
27
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028
Steve Blocka7e24c12009-10-30 11:49:00 +000029//------------------------------------------------------------------
30// Tables
31//------------------------------------------------------------------
32struct ByteMnemonic {
33 int b; // -1 terminates, otherwise must be in range (0..255)
34 OperandType op_order_;
35 const char* mnem;
36};
37
38
Ben Murdoch69a99ed2011-11-30 16:03:39 +000039static const ByteMnemonic two_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000040 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
41 { 0x01, OPER_REG_OP_ORDER, "add" },
42 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
43 { 0x03, REG_OPER_OP_ORDER, "add" },
44 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
45 { 0x09, OPER_REG_OP_ORDER, "or" },
46 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
47 { 0x0B, REG_OPER_OP_ORDER, "or" },
48 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
49 { 0x11, OPER_REG_OP_ORDER, "adc" },
50 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
51 { 0x13, REG_OPER_OP_ORDER, "adc" },
52 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
53 { 0x19, OPER_REG_OP_ORDER, "sbb" },
54 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
55 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
56 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
57 { 0x21, OPER_REG_OP_ORDER, "and" },
58 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
59 { 0x23, REG_OPER_OP_ORDER, "and" },
60 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
61 { 0x29, OPER_REG_OP_ORDER, "sub" },
62 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
63 { 0x2B, REG_OPER_OP_ORDER, "sub" },
64 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
65 { 0x31, OPER_REG_OP_ORDER, "xor" },
66 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
67 { 0x33, REG_OPER_OP_ORDER, "xor" },
68 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
69 { 0x39, OPER_REG_OP_ORDER, "cmp" },
70 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
71 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072 { 0x63, REG_OPER_OP_ORDER, "movsxl" },
Steve Blocka7e24c12009-10-30 11:49:00 +000073 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
74 { 0x85, REG_OPER_OP_ORDER, "test" },
75 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
76 { 0x87, REG_OPER_OP_ORDER, "xchg" },
77 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
78 { 0x89, OPER_REG_OP_ORDER, "mov" },
79 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
80 { 0x8B, REG_OPER_OP_ORDER, "mov" },
81 { 0x8D, REG_OPER_OP_ORDER, "lea" },
82 { -1, UNSET_OP_ORDER, "" }
83};
84
85
Ben Murdoch69a99ed2011-11-30 16:03:39 +000086static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000087 { 0xC3, UNSET_OP_ORDER, "ret" },
88 { 0xC9, UNSET_OP_ORDER, "leave" },
89 { 0xF4, UNSET_OP_ORDER, "hlt" },
Ben Murdoch3ef787d2012-04-12 10:51:47 +010090 { 0xFC, UNSET_OP_ORDER, "cld" },
Steve Blocka7e24c12009-10-30 11:49:00 +000091 { 0xCC, UNSET_OP_ORDER, "int3" },
92 { 0x60, UNSET_OP_ORDER, "pushad" },
93 { 0x61, UNSET_OP_ORDER, "popad" },
94 { 0x9C, UNSET_OP_ORDER, "pushfd" },
95 { 0x9D, UNSET_OP_ORDER, "popfd" },
96 { 0x9E, UNSET_OP_ORDER, "sahf" },
97 { 0x99, UNSET_OP_ORDER, "cdq" },
98 { 0x9B, UNSET_OP_ORDER, "fwait" },
Leon Clarked91b9f72010-01-27 17:25:45 +000099 { 0xA4, UNSET_OP_ORDER, "movs" },
100 { 0xA5, UNSET_OP_ORDER, "movs" },
101 { 0xA6, UNSET_OP_ORDER, "cmps" },
102 { 0xA7, UNSET_OP_ORDER, "cmps" },
Steve Blocka7e24c12009-10-30 11:49:00 +0000103 { -1, UNSET_OP_ORDER, "" }
104};
105
106
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000107static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 { 0xE8, UNSET_OP_ORDER, "call" },
109 { 0xE9, UNSET_OP_ORDER, "jmp" },
110 { -1, UNSET_OP_ORDER, "" }
111};
112
113
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000114static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 { 0x05, UNSET_OP_ORDER, "add" },
116 { 0x0D, UNSET_OP_ORDER, "or" },
117 { 0x15, UNSET_OP_ORDER, "adc" },
118 { 0x1D, UNSET_OP_ORDER, "sbb" },
119 { 0x25, UNSET_OP_ORDER, "and" },
120 { 0x2D, UNSET_OP_ORDER, "sub" },
121 { 0x35, UNSET_OP_ORDER, "xor" },
122 { 0x3D, UNSET_OP_ORDER, "cmp" },
123 { -1, UNSET_OP_ORDER, "" }
124};
125
126
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000127static const char* const conditional_code_suffix[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 "o", "no", "c", "nc", "z", "nz", "na", "a",
129 "s", "ns", "pe", "po", "l", "ge", "le", "g"
130};
131
132
133enum InstructionType {
134 NO_INSTR,
135 ZERO_OPERANDS_INSTR,
136 TWO_OPERANDS_INSTR,
137 JUMP_CONDITIONAL_SHORT_INSTR,
138 REGISTER_INSTR,
139 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
140 MOVE_REG_INSTR,
141 CALL_JUMP_INSTR,
142 SHORT_IMMEDIATE_INSTR
143};
144
Leon Clarked91b9f72010-01-27 17:25:45 +0000145enum Prefixes {
146 ESCAPE_PREFIX = 0x0F,
147 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
148 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400149 VEX3_PREFIX = 0xC4,
150 VEX2_PREFIX = 0xC5,
Ben Murdoch61f157c2016-09-16 13:49:30 +0100151 LOCK_PREFIX = 0xF0,
Leon Clarked91b9f72010-01-27 17:25:45 +0000152 REPNE_PREFIX = 0xF2,
153 REP_PREFIX = 0xF3,
154 REPEQ_PREFIX = REP_PREFIX
155};
156
Steve Blocka7e24c12009-10-30 11:49:00 +0000157struct InstructionDesc {
158 const char* mnem;
159 InstructionType type;
160 OperandType op_order_;
161 bool byte_size_operation; // Fixed 8-bit operation.
162};
163
164
165class InstructionTable {
166 public:
167 InstructionTable();
168 const InstructionDesc& Get(byte x) const {
169 return instructions_[x];
170 }
171
172 private:
173 InstructionDesc instructions_[256];
174 void Clear();
175 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000176 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
178 const char* mnem);
179 void AddJumpConditionalShort();
180};
181
182
183InstructionTable::InstructionTable() {
184 Clear();
185 Init();
186}
187
188
189void InstructionTable::Clear() {
190 for (int i = 0; i < 256; i++) {
191 instructions_[i].mnem = "(bad)";
192 instructions_[i].type = NO_INSTR;
193 instructions_[i].op_order_ = UNSET_OP_ORDER;
194 instructions_[i].byte_size_operation = false;
195 }
196}
197
198
199void InstructionTable::Init() {
200 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
201 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
202 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
203 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
204 AddJumpConditionalShort();
205 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
206 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
207 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
208}
209
210
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000211void InstructionTable::CopyTable(const ByteMnemonic bm[],
212 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 for (int i = 0; bm[i].b >= 0; i++) {
214 InstructionDesc* id = &instructions_[bm[i].b];
215 id->mnem = bm[i].mnem;
216 OperandType op_order = bm[i].op_order_;
217 id->op_order_ =
218 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000220 id->type = type;
221 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
222 }
223}
224
225
226void InstructionTable::SetTableRange(InstructionType type,
227 byte start,
228 byte end,
229 bool byte_size,
230 const char* mnem) {
231 for (byte b = start; b <= end; b++) {
232 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 id->mnem = mnem;
235 id->type = type;
236 id->byte_size_operation = byte_size;
237 }
238}
239
240
241void InstructionTable::AddJumpConditionalShort() {
242 for (byte b = 0x70; b <= 0x7F; b++) {
243 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 id->mnem = NULL; // Computed depending on condition code.
246 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
247 }
248}
249
250
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251static v8::base::LazyInstance<InstructionTable>::type instruction_table =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252 LAZY_INSTANCE_INITIALIZER;
Steve Blocka7e24c12009-10-30 11:49:00 +0000253
Steve Block44f0eee2011-05-26 01:26:41 +0100254
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400255static const InstructionDesc cmov_instructions[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
257 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
272};
273
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274
Steve Blocka7e24c12009-10-30 11:49:00 +0000275//------------------------------------------------------------------------------
276// DisassemblerX64 implementation.
277
278enum UnimplementedOpcodeAction {
279 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
280 ABORT_ON_UNIMPLEMENTED_OPCODE
281};
282
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283
Steve Blocka7e24c12009-10-30 11:49:00 +0000284// A new DisassemblerX64 object is created to disassemble each instruction.
285// The object can only disassemble a single instruction.
286class DisassemblerX64 {
287 public:
288 DisassemblerX64(const NameConverter& converter,
289 UnimplementedOpcodeAction unimplemented_action =
290 ABORT_ON_UNIMPLEMENTED_OPCODE)
291 : converter_(converter),
292 tmp_buffer_pos_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400293 abort_on_unimplemented_(unimplemented_action ==
294 ABORT_ON_UNIMPLEMENTED_OPCODE),
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 rex_(0),
296 operand_size_(0),
297 group_1_prefix_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400298 vex_byte0_(0),
299 vex_byte1_(0),
300 vex_byte2_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 byte_size_operand_(false),
302 instruction_table_(instruction_table.Pointer()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 tmp_buffer_[0] = '\0';
304 }
305
306 virtual ~DisassemblerX64() {
307 }
308
309 // Writes one disassembled instruction into 'buffer' (0-terminated).
310 // Returns the length of the disassembled machine instruction in bytes.
311 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
312
313 private:
314 enum OperandSize {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 OPERAND_BYTE_SIZE = 0,
316 OPERAND_WORD_SIZE = 1,
317 OPERAND_DOUBLEWORD_SIZE = 2,
318 OPERAND_QUADWORD_SIZE = 3
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 };
320
321 const NameConverter& converter_;
322 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
323 unsigned int tmp_buffer_pos_;
324 bool abort_on_unimplemented_;
325 // Prefixes parsed
326 byte rex_;
327 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
328 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400329 byte vex_byte0_; // 0xc4 or 0xc5
330 byte vex_byte1_;
331 byte vex_byte2_; // only for 3 bytes vex prefix
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 // Byte size operand override.
333 bool byte_size_operand_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 const InstructionTable* const instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000335
336 void setRex(byte rex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 DCHECK_EQ(0x40, rex & 0xF0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 rex_ = rex;
339 }
340
341 bool rex() { return rex_ != 0; }
342
343 bool rex_b() { return (rex_ & 0x01) != 0; }
344
345 // Actual number of base register given the low bits and the rex.b state.
346 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
347
348 bool rex_x() { return (rex_ & 0x02) != 0; }
349
350 bool rex_r() { return (rex_ & 0x04) != 0; }
351
352 bool rex_w() { return (rex_ & 0x08) != 0; }
353
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000354 bool vex_w() {
355 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
356 return vex_byte0_ == VEX3_PREFIX ? (vex_byte2_ & 0x80) != 0 : false;
357 }
358
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400359 bool vex_128() {
360 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
361 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
Ben Murdochc5610432016-08-08 18:44:38 +0100362 return (checked & 4) == 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400363 }
364
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 bool vex_none() {
366 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
367 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
368 return (checked & 3) == 0;
369 }
370
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 bool vex_66() {
372 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
373 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
374 return (checked & 3) == 1;
375 }
376
377 bool vex_f3() {
378 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
379 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
380 return (checked & 3) == 2;
381 }
382
383 bool vex_f2() {
384 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
385 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
386 return (checked & 3) == 3;
387 }
388
389 bool vex_0f() {
390 if (vex_byte0_ == VEX2_PREFIX) return true;
391 return (vex_byte1_ & 3) == 1;
392 }
393
394 bool vex_0f38() {
395 if (vex_byte0_ == VEX2_PREFIX) return false;
396 return (vex_byte1_ & 3) == 2;
397 }
398
399 bool vex_0f3a() {
400 if (vex_byte0_ == VEX2_PREFIX) return false;
401 return (vex_byte1_ & 3) == 3;
402 }
403
404 int vex_vreg() {
405 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
406 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
407 return ~(checked >> 3) & 0xf;
408 }
409
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 OperandSize operand_size() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000411 if (byte_size_operand_) return OPERAND_BYTE_SIZE;
412 if (rex_w()) return OPERAND_QUADWORD_SIZE;
413 if (operand_size_ != 0) return OPERAND_WORD_SIZE;
414 return OPERAND_DOUBLEWORD_SIZE;
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 }
416
417 char operand_size_code() {
418 return "bwlq"[operand_size()];
419 }
420
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400421 char float_size_code() { return "sd"[rex_w()]; }
422
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 const char* NameOfCPURegister(int reg) const {
424 return converter_.NameOfCPURegister(reg);
425 }
426
427 const char* NameOfByteCPURegister(int reg) const {
428 return converter_.NameOfByteCPURegister(reg);
429 }
430
431 const char* NameOfXMMRegister(int reg) const {
432 return converter_.NameOfXMMRegister(reg);
433 }
434
435 const char* NameOfAddress(byte* addr) const {
436 return converter_.NameOfAddress(addr);
437 }
438
439 // Disassembler helper functions.
440 void get_modrm(byte data,
441 int* mod,
442 int* regop,
443 int* rm) {
444 *mod = (data >> 6) & 3;
445 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
446 *rm = (data & 7) | (rex_b() ? 8 : 0);
447 }
448
449 void get_sib(byte data,
450 int* scale,
451 int* index,
452 int* base) {
453 *scale = (data >> 6) & 3;
454 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
455 *base = (data & 7) | (rex_b() ? 8 : 0);
456 }
457
458 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
459
460 int PrintRightOperandHelper(byte* modrmp,
461 RegisterNameMapping register_name);
462 int PrintRightOperand(byte* modrmp);
463 int PrintRightByteOperand(byte* modrmp);
Steve Blockd0582a62009-12-15 09:54:21 +0000464 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 int PrintOperands(const char* mnem,
466 OperandType op_order,
467 byte* data);
468 int PrintImmediate(byte* data, OperandSize size);
469 int PrintImmediateOp(byte* data);
470 const char* TwoByteMnemonic(byte opcode);
471 int TwoByteOpcodeInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000472 int F6F7Instruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 int ShiftInstruction(byte* data);
474 int JumpShort(byte* data);
475 int JumpConditional(byte* data);
476 int JumpConditionalShort(byte* data);
477 int SetCC(byte* data);
478 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000479 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
480 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400481 int AVXInstruction(byte* data);
Ben Murdochc5610432016-08-08 18:44:38 +0100482 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
Steve Blocka7e24c12009-10-30 11:49:00 +0000483
484 void UnimplementedInstruction() {
485 if (abort_on_unimplemented_) {
486 CHECK(false);
487 } else {
488 AppendToBuffer("'Unimplemented Instruction'");
489 }
490 }
491};
492
493
494void DisassemblerX64::AppendToBuffer(const char* format, ...) {
495 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
496 va_list args;
497 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 va_end(args);
500 tmp_buffer_pos_ += result;
501}
502
503
504int DisassemblerX64::PrintRightOperandHelper(
505 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100506 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000507 int mod, regop, rm;
508 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100509 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
510 &DisassemblerX64::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000511 switch (mod) {
512 case 0:
513 if ((rm & 7) == 5) {
514 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 AppendToBuffer("[rip+0x%x]", disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000516 return 5;
517 } else if ((rm & 7) == 4) {
518 // Codes for SIB byte.
519 byte sib = *(modrmp + 1);
520 int scale, index, base;
521 get_sib(sib, &scale, &index, &base);
522 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
523 // index == rsp means no index. Only use sib byte with no index for
524 // rsp and r12 base.
Steve Block8defd9f2010-07-08 12:39:36 +0100525 AppendToBuffer("[%s]", NameOfCPURegister(base));
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 return 2;
527 } else if (base == 5) {
528 // base == rbp means no base register (when mod == 0).
529 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000530 AppendToBuffer("[%s*%d%s0x%x]",
Steve Block8defd9f2010-07-08 12:39:36 +0100531 NameOfCPURegister(index),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 1 << scale,
533 disp < 0 ? "-" : "+",
534 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000535 return 6;
536 } else if (index != 4 && base != 5) {
537 // [base+index*scale]
538 AppendToBuffer("[%s+%s*%d]",
Steve Block8defd9f2010-07-08 12:39:36 +0100539 NameOfCPURegister(base),
540 NameOfCPURegister(index),
Steve Blocka7e24c12009-10-30 11:49:00 +0000541 1 << scale);
542 return 2;
543 } else {
544 UnimplementedInstruction();
545 return 1;
546 }
547 } else {
Steve Block8defd9f2010-07-08 12:39:36 +0100548 AppendToBuffer("[%s]", NameOfCPURegister(rm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 return 1;
550 }
551 break;
552 case 1: // fall through
553 case 2:
554 if ((rm & 7) == 4) {
555 byte sib = *(modrmp + 1);
556 int scale, index, base;
557 get_sib(sib, &scale, &index, &base);
558 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 AppendToBuffer("[%s%s0x%x]",
562 NameOfCPURegister(base),
563 disp < 0 ? "-" : "+",
564 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000565 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 AppendToBuffer("[%s+%s*%d%s0x%x]",
567 NameOfCPURegister(base),
568 NameOfCPURegister(index),
569 1 << scale,
570 disp < 0 ? "-" : "+",
571 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000572 }
573 return mod == 2 ? 6 : 3;
574 } else {
575 // No sib.
576 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 : *reinterpret_cast<int8_t*>(modrmp + 1);
578 AppendToBuffer("[%s%s0x%x]",
579 NameOfCPURegister(rm),
580 disp < 0 ? "-" : "+",
581 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 return (mod == 2) ? 5 : 2;
583 }
584 break;
585 case 3:
586 AppendToBuffer("%s", (this->*register_name)(rm));
587 return 1;
588 default:
589 UnimplementedInstruction();
590 return 1;
591 }
592 UNREACHABLE();
593}
594
595
596int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
597 int64_t value;
598 int count;
599 switch (size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 case OPERAND_BYTE_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 value = *data;
602 count = 1;
603 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000605 value = *reinterpret_cast<int16_t*>(data);
606 count = 2;
607 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 value = *reinterpret_cast<uint32_t*>(data);
610 count = 4;
611 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 value = *reinterpret_cast<int32_t*>(data);
614 count = 4;
615 break;
616 default:
617 UNREACHABLE();
618 value = 0; // Initialize variables on all paths to satisfy the compiler.
619 count = 0;
620 }
Ben Murdochc5610432016-08-08 18:44:38 +0100621 AppendToBuffer("%" PRIx64, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 return count;
623}
624
625
626int DisassemblerX64::PrintRightOperand(byte* modrmp) {
627 return PrintRightOperandHelper(modrmp,
628 &DisassemblerX64::NameOfCPURegister);
629}
630
631
632int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
633 return PrintRightOperandHelper(modrmp,
634 &DisassemblerX64::NameOfByteCPURegister);
635}
636
637
Steve Blockd0582a62009-12-15 09:54:21 +0000638int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
639 return PrintRightOperandHelper(modrmp,
640 &DisassemblerX64::NameOfXMMRegister);
641}
642
643
Steve Blocka7e24c12009-10-30 11:49:00 +0000644// Returns number of bytes used including the current *data.
645// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
646int DisassemblerX64::PrintOperands(const char* mnem,
647 OperandType op_order,
648 byte* data) {
649 byte modrm = *data;
650 int mod, regop, rm;
651 get_modrm(modrm, &mod, &regop, &rm);
652 int advance = 0;
653 const char* register_name =
654 byte_size_operand_ ? NameOfByteCPURegister(regop)
655 : NameOfCPURegister(regop);
656 switch (op_order) {
657 case REG_OPER_OP_ORDER: {
658 AppendToBuffer("%s%c %s,",
659 mnem,
660 operand_size_code(),
661 register_name);
662 advance = byte_size_operand_ ? PrintRightByteOperand(data)
663 : PrintRightOperand(data);
664 break;
665 }
666 case OPER_REG_OP_ORDER: {
667 AppendToBuffer("%s%c ", mnem, operand_size_code());
668 advance = byte_size_operand_ ? PrintRightByteOperand(data)
669 : PrintRightOperand(data);
670 AppendToBuffer(",%s", register_name);
671 break;
672 }
673 default:
674 UNREACHABLE();
675 break;
676 }
677 return advance;
678}
679
680
681// Returns number of bytes used by machine instruction, including *data byte.
682// Writes immediate instructions to 'tmp_buffer_'.
683int DisassemblerX64::PrintImmediateOp(byte* data) {
684 bool byte_size_immediate = (*data & 0x02) != 0;
685 byte modrm = *(data + 1);
686 int mod, regop, rm;
687 get_modrm(modrm, &mod, &regop, &rm);
688 const char* mnem = "Imm???";
689 switch (regop) {
690 case 0:
691 mnem = "add";
692 break;
693 case 1:
694 mnem = "or";
695 break;
696 case 2:
697 mnem = "adc";
698 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100699 case 3:
700 mnem = "sbb";
701 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000702 case 4:
703 mnem = "and";
704 break;
705 case 5:
706 mnem = "sub";
707 break;
708 case 6:
709 mnem = "xor";
710 break;
711 case 7:
712 mnem = "cmp";
713 break;
714 default:
715 UnimplementedInstruction();
716 }
717 AppendToBuffer("%s%c ", mnem, operand_size_code());
718 int count = PrintRightOperand(data + 1);
719 AppendToBuffer(",0x");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000720 OperandSize immediate_size =
721 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 count += PrintImmediate(data + 1 + count, immediate_size);
723 return 1 + count;
724}
725
726
727// Returns number of bytes used, including *data.
Steve Blockd0582a62009-12-15 09:54:21 +0000728int DisassemblerX64::F6F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000729 DCHECK(*data == 0xF7 || *data == 0xF6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000730 byte modrm = *(data + 1);
731 int mod, regop, rm;
732 get_modrm(modrm, &mod, &regop, &rm);
733 if (mod == 3 && regop != 0) {
734 const char* mnem = NULL;
735 switch (regop) {
736 case 2:
737 mnem = "not";
738 break;
739 case 3:
740 mnem = "neg";
741 break;
742 case 4:
743 mnem = "mul";
744 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745 case 5:
746 mnem = "imul";
747 break;
748 case 6:
749 mnem = "div";
750 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 case 7:
752 mnem = "idiv";
753 break;
754 default:
755 UnimplementedInstruction();
756 }
757 AppendToBuffer("%s%c %s",
758 mnem,
759 operand_size_code(),
760 NameOfCPURegister(rm));
761 return 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 } else if (regop == 0) {
763 AppendToBuffer("test%c ", operand_size_code());
Steve Blockd0582a62009-12-15 09:54:21 +0000764 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
765 AppendToBuffer(",0x");
766 count += PrintImmediate(data + 1 + count, operand_size());
767 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 } else {
769 UnimplementedInstruction();
770 return 2;
771 }
772}
773
774
775int DisassemblerX64::ShiftInstruction(byte* data) {
776 byte op = *data & (~1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400777 int count = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000778 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
779 UnimplementedInstruction();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400780 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400782 // Print mneumonic.
783 {
784 byte modrm = *(data + count);
785 int mod, regop, rm;
786 get_modrm(modrm, &mod, &regop, &rm);
787 regop &= 0x7; // The REX.R bit does not affect the operation.
788 const char* mnem = NULL;
789 switch (regop) {
790 case 0:
791 mnem = "rol";
792 break;
793 case 1:
794 mnem = "ror";
795 break;
796 case 2:
797 mnem = "rcl";
798 break;
799 case 3:
800 mnem = "rcr";
801 break;
802 case 4:
803 mnem = "shl";
804 break;
805 case 5:
806 mnem = "shr";
807 break;
808 case 7:
809 mnem = "sar";
810 break;
811 default:
812 UnimplementedInstruction();
813 return count + 1;
814 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 DCHECK_NOT_NULL(mnem);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400816 AppendToBuffer("%s%c ", mnem, operand_size_code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000817 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400818 count += PrintRightOperand(data + count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 if (op == 0xD2) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400820 AppendToBuffer(", cl");
Steve Blocka7e24c12009-10-30 11:49:00 +0000821 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400822 int imm8 = -1;
823 if (op == 0xD0) {
824 imm8 = 1;
825 } else {
826 DCHECK_EQ(0xC0, op);
827 imm8 = *(data + count);
828 count++;
829 }
830 AppendToBuffer(", %d", imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000831 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400832 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000833}
834
835
836// Returns number of bytes used, including *data.
837int DisassemblerX64::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 byte b = *(data + 1);
840 byte* dest = data + static_cast<int8_t>(b) + 2;
841 AppendToBuffer("jmp %s", NameOfAddress(dest));
842 return 2;
843}
844
845
846// Returns number of bytes used, including *data.
847int DisassemblerX64::JumpConditional(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 byte cond = *(data + 1) & 0x0F;
850 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
851 const char* mnem = conditional_code_suffix[cond];
852 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
853 return 6; // includes 0x0F
854}
855
856
857// Returns number of bytes used, including *data.
858int DisassemblerX64::JumpConditionalShort(byte* data) {
859 byte cond = *data & 0x0F;
860 byte b = *(data + 1);
861 byte* dest = data + static_cast<int8_t>(b) + 2;
862 const char* mnem = conditional_code_suffix[cond];
863 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
864 return 2;
865}
866
867
868// Returns number of bytes used, including *data.
869int DisassemblerX64::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000870 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000871 byte cond = *(data + 1) & 0x0F;
872 const char* mnem = conditional_code_suffix[cond];
873 AppendToBuffer("set%s%c ", mnem, operand_size_code());
874 PrintRightByteOperand(data + 2);
875 return 3; // includes 0x0F
876}
877
878
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400879int DisassemblerX64::AVXInstruction(byte* data) {
880 byte opcode = *data;
881 byte* current = data + 1;
882 if (vex_66() && vex_0f38()) {
883 int mod, regop, rm, vvvv = vex_vreg();
884 get_modrm(*current, &mod, &regop, &rm);
885 switch (opcode) {
886 case 0x99:
887 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
888 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
889 current += PrintRightXMMOperand(current);
890 break;
891 case 0xa9:
892 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
893 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
894 current += PrintRightXMMOperand(current);
895 break;
896 case 0xb9:
897 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
898 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
899 current += PrintRightXMMOperand(current);
900 break;
901 case 0x9b:
902 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
903 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
904 current += PrintRightXMMOperand(current);
905 break;
906 case 0xab:
907 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
908 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
909 current += PrintRightXMMOperand(current);
910 break;
911 case 0xbb:
912 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
913 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
914 current += PrintRightXMMOperand(current);
915 break;
916 case 0x9d:
917 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
918 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
919 current += PrintRightXMMOperand(current);
920 break;
921 case 0xad:
922 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
923 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
924 current += PrintRightXMMOperand(current);
925 break;
926 case 0xbd:
927 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
928 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
929 current += PrintRightXMMOperand(current);
930 break;
931 case 0x9f:
932 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
933 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
934 current += PrintRightXMMOperand(current);
935 break;
936 case 0xaf:
937 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
938 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
939 current += PrintRightXMMOperand(current);
940 break;
941 case 0xbf:
942 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
943 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
944 current += PrintRightXMMOperand(current);
945 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946 case 0xf7:
947 AppendToBuffer("shlx%c %s,", operand_size_code(),
948 NameOfCPURegister(regop));
949 current += PrintRightOperand(current);
950 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
951 break;
952 default:
953 UnimplementedInstruction();
954 }
955 } else if (vex_66() && vex_0f3a()) {
956 int mod, regop, rm, vvvv = vex_vreg();
957 get_modrm(*current, &mod, &regop, &rm);
958 switch (opcode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100959 case 0x0a:
960 AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
961 NameOfXMMRegister(vvvv));
962 current += PrintRightXMMOperand(current);
963 AppendToBuffer(",0x%x", *current++);
964 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000965 case 0x0b:
966 AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
967 NameOfXMMRegister(vvvv));
968 current += PrintRightXMMOperand(current);
969 AppendToBuffer(",0x%x", *current++);
970 break;
971 default:
972 UnimplementedInstruction();
973 }
974 } else if (vex_f3() && vex_0f()) {
975 int mod, regop, rm, vvvv = vex_vreg();
976 get_modrm(*current, &mod, &regop, &rm);
977 switch (opcode) {
978 case 0x10:
979 AppendToBuffer("vmovss %s,", NameOfXMMRegister(regop));
980 if (mod == 3) {
981 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
982 }
983 current += PrintRightXMMOperand(current);
984 break;
985 case 0x11:
986 AppendToBuffer("vmovss ");
987 current += PrintRightXMMOperand(current);
988 if (mod == 3) {
989 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
990 }
991 AppendToBuffer(",%s", NameOfXMMRegister(regop));
992 break;
993 case 0x2a:
994 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2ss" : "vcvtlsi2ss",
995 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
996 current += PrintRightOperand(current);
997 break;
998 case 0x2c:
999 AppendToBuffer("vcvttss2si%s %s,", vex_w() ? "q" : "",
1000 NameOfCPURegister(regop));
1001 current += PrintRightXMMOperand(current);
1002 break;
1003 case 0x58:
1004 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
1005 NameOfXMMRegister(vvvv));
1006 current += PrintRightXMMOperand(current);
1007 break;
1008 case 0x59:
1009 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
1010 NameOfXMMRegister(vvvv));
1011 current += PrintRightXMMOperand(current);
1012 break;
1013 case 0x5a:
1014 AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
1015 NameOfXMMRegister(vvvv));
1016 current += PrintRightXMMOperand(current);
1017 break;
1018 case 0x5c:
1019 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
1020 NameOfXMMRegister(vvvv));
1021 current += PrintRightXMMOperand(current);
1022 break;
1023 case 0x5d:
1024 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
1025 NameOfXMMRegister(vvvv));
1026 current += PrintRightXMMOperand(current);
1027 break;
1028 case 0x5e:
1029 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
1030 NameOfXMMRegister(vvvv));
1031 current += PrintRightXMMOperand(current);
1032 break;
1033 case 0x5f:
1034 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
1035 NameOfXMMRegister(vvvv));
1036 current += PrintRightXMMOperand(current);
1037 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001038 default:
1039 UnimplementedInstruction();
1040 }
1041 } else if (vex_f2() && vex_0f()) {
1042 int mod, regop, rm, vvvv = vex_vreg();
1043 get_modrm(*current, &mod, &regop, &rm);
1044 switch (opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001045 case 0x10:
1046 AppendToBuffer("vmovsd %s,", NameOfXMMRegister(regop));
1047 if (mod == 3) {
1048 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1049 }
1050 current += PrintRightXMMOperand(current);
1051 break;
1052 case 0x11:
1053 AppendToBuffer("vmovsd ");
1054 current += PrintRightXMMOperand(current);
1055 if (mod == 3) {
1056 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1057 }
1058 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1059 break;
1060 case 0x2a:
1061 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd",
1062 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1063 current += PrintRightOperand(current);
1064 break;
1065 case 0x2c:
1066 AppendToBuffer("vcvttsd2si%s %s,", vex_w() ? "q" : "",
1067 NameOfCPURegister(regop));
1068 current += PrintRightXMMOperand(current);
1069 break;
1070 case 0x2d:
1071 AppendToBuffer("vcvtsd2si%s %s,", vex_w() ? "q" : "",
1072 NameOfCPURegister(regop));
1073 current += PrintRightXMMOperand(current);
1074 break;
1075 case 0x51:
1076 AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
1077 NameOfXMMRegister(vvvv));
1078 current += PrintRightXMMOperand(current);
1079 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001080 case 0x58:
1081 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
1082 NameOfXMMRegister(vvvv));
1083 current += PrintRightXMMOperand(current);
1084 break;
1085 case 0x59:
1086 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
1087 NameOfXMMRegister(vvvv));
1088 current += PrintRightXMMOperand(current);
1089 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001090 case 0x5a:
1091 AppendToBuffer("vcvtsd2ss %s,%s,", NameOfXMMRegister(regop),
1092 NameOfXMMRegister(vvvv));
1093 current += PrintRightXMMOperand(current);
1094 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001095 case 0x5c:
1096 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
1097 NameOfXMMRegister(vvvv));
1098 current += PrintRightXMMOperand(current);
1099 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001100 case 0x5d:
1101 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
1102 NameOfXMMRegister(vvvv));
1103 current += PrintRightXMMOperand(current);
1104 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001105 case 0x5e:
1106 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
1107 NameOfXMMRegister(vvvv));
1108 current += PrintRightXMMOperand(current);
1109 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110 case 0x5f:
1111 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
1112 NameOfXMMRegister(vvvv));
1113 current += PrintRightXMMOperand(current);
1114 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001115 default:
1116 UnimplementedInstruction();
1117 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001118 } else if (vex_none() && vex_0f38()) {
1119 int mod, regop, rm, vvvv = vex_vreg();
1120 get_modrm(*current, &mod, &regop, &rm);
1121 const char* mnem = "?";
1122 switch (opcode) {
1123 case 0xf2:
1124 AppendToBuffer("andn%c %s,%s,", operand_size_code(),
1125 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1126 current += PrintRightOperand(current);
1127 break;
1128 case 0xf5:
1129 AppendToBuffer("bzhi%c %s,", operand_size_code(),
1130 NameOfCPURegister(regop));
1131 current += PrintRightOperand(current);
1132 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1133 break;
1134 case 0xf7:
1135 AppendToBuffer("bextr%c %s,", operand_size_code(),
1136 NameOfCPURegister(regop));
1137 current += PrintRightOperand(current);
1138 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1139 break;
1140 case 0xf3:
1141 switch (regop) {
1142 case 1:
1143 mnem = "blsr";
1144 break;
1145 case 2:
1146 mnem = "blsmsk";
1147 break;
1148 case 3:
1149 mnem = "blsi";
1150 break;
1151 default:
1152 UnimplementedInstruction();
1153 }
1154 AppendToBuffer("%s%c %s,", mnem, operand_size_code(),
1155 NameOfCPURegister(vvvv));
1156 current += PrintRightOperand(current);
1157 mnem = "?";
1158 break;
1159 default:
1160 UnimplementedInstruction();
1161 }
1162 } else if (vex_f2() && vex_0f38()) {
1163 int mod, regop, rm, vvvv = vex_vreg();
1164 get_modrm(*current, &mod, &regop, &rm);
1165 switch (opcode) {
1166 case 0xf5:
1167 AppendToBuffer("pdep%c %s,%s,", operand_size_code(),
1168 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1169 current += PrintRightOperand(current);
1170 break;
1171 case 0xf6:
1172 AppendToBuffer("mulx%c %s,%s,", operand_size_code(),
1173 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1174 current += PrintRightOperand(current);
1175 break;
1176 case 0xf7:
1177 AppendToBuffer("shrx%c %s,", operand_size_code(),
1178 NameOfCPURegister(regop));
1179 current += PrintRightOperand(current);
1180 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1181 break;
1182 default:
1183 UnimplementedInstruction();
1184 }
1185 } else if (vex_f3() && vex_0f38()) {
1186 int mod, regop, rm, vvvv = vex_vreg();
1187 get_modrm(*current, &mod, &regop, &rm);
1188 switch (opcode) {
1189 case 0xf5:
1190 AppendToBuffer("pext%c %s,%s,", operand_size_code(),
1191 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1192 current += PrintRightOperand(current);
1193 break;
1194 case 0xf7:
1195 AppendToBuffer("sarx%c %s,", operand_size_code(),
1196 NameOfCPURegister(regop));
1197 current += PrintRightOperand(current);
1198 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1199 break;
1200 default:
1201 UnimplementedInstruction();
1202 }
1203 } else if (vex_f2() && vex_0f3a()) {
1204 int mod, regop, rm;
1205 get_modrm(*current, &mod, &regop, &rm);
1206 switch (opcode) {
1207 case 0xf0:
1208 AppendToBuffer("rorx%c %s,", operand_size_code(),
1209 NameOfCPURegister(regop));
1210 current += PrintRightOperand(current);
1211 switch (operand_size()) {
1212 case OPERAND_DOUBLEWORD_SIZE:
1213 AppendToBuffer(",%d", *current & 0x1f);
1214 break;
1215 case OPERAND_QUADWORD_SIZE:
1216 AppendToBuffer(",%d", *current & 0x3f);
1217 break;
1218 default:
1219 UnimplementedInstruction();
1220 }
1221 current += 1;
1222 break;
1223 default:
1224 UnimplementedInstruction();
1225 }
1226 } else if (vex_none() && vex_0f()) {
1227 int mod, regop, rm, vvvv = vex_vreg();
1228 get_modrm(*current, &mod, &regop, &rm);
1229 switch (opcode) {
1230 case 0x28:
1231 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1232 current += PrintRightXMMOperand(current);
1233 break;
1234 case 0x29:
1235 AppendToBuffer("vmovaps ");
1236 current += PrintRightXMMOperand(current);
1237 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1238 break;
1239 case 0x2e:
1240 AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1241 current += PrintRightXMMOperand(current);
1242 break;
1243 case 0x54:
1244 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1245 NameOfXMMRegister(vvvv));
1246 current += PrintRightXMMOperand(current);
1247 break;
1248 case 0x57:
1249 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1250 NameOfXMMRegister(vvvv));
1251 current += PrintRightXMMOperand(current);
1252 break;
1253 default:
1254 UnimplementedInstruction();
1255 }
1256 } else if (vex_66() && vex_0f()) {
1257 int mod, regop, rm, vvvv = vex_vreg();
1258 get_modrm(*current, &mod, &regop, &rm);
1259 switch (opcode) {
1260 case 0x28:
1261 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1262 current += PrintRightXMMOperand(current);
1263 break;
1264 case 0x29:
1265 AppendToBuffer("vmovapd ");
1266 current += PrintRightXMMOperand(current);
1267 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1268 break;
1269 case 0x2e:
1270 AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1271 current += PrintRightXMMOperand(current);
1272 break;
1273 case 0x50:
1274 AppendToBuffer("vmovmskpd %s,", NameOfCPURegister(regop));
1275 current += PrintRightXMMOperand(current);
1276 break;
1277 case 0x54:
1278 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1279 NameOfXMMRegister(vvvv));
1280 current += PrintRightXMMOperand(current);
1281 break;
1282 case 0x56:
1283 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1284 NameOfXMMRegister(vvvv));
1285 current += PrintRightXMMOperand(current);
1286 break;
1287 case 0x57:
1288 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1289 NameOfXMMRegister(vvvv));
1290 current += PrintRightXMMOperand(current);
1291 break;
1292 case 0x6e:
1293 AppendToBuffer("vmov%c %s,", vex_w() ? 'q' : 'd',
1294 NameOfXMMRegister(regop));
1295 current += PrintRightOperand(current);
1296 break;
1297 case 0x73:
1298 AppendToBuffer("%s %s,", regop == 6 ? "vpsllq" : "vpsrlq",
1299 NameOfXMMRegister(vvvv));
1300 current += PrintRightXMMOperand(current);
1301 AppendToBuffer(",%u", *current++);
1302 break;
1303 case 0x76:
1304 AppendToBuffer("vpcmpeqd %s,%s,", NameOfXMMRegister(regop),
1305 NameOfXMMRegister(vvvv));
1306 current += PrintRightXMMOperand(current);
1307 break;
1308 case 0x7e:
1309 AppendToBuffer("vmov%c ", vex_w() ? 'q' : 'd');
1310 current += PrintRightOperand(current);
1311 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1312 break;
1313 default:
1314 UnimplementedInstruction();
1315 }
1316
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001317 } else {
1318 UnimplementedInstruction();
1319 }
1320
1321 return static_cast<int>(current - data);
1322}
1323
1324
Steve Blocka7e24c12009-10-30 11:49:00 +00001325// Returns number of bytes used, including *data.
1326int DisassemblerX64::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001327 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001329 byte modrm_byte = *(data+1);
1330
1331 if (modrm_byte >= 0xC0) {
1332 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1333 } else {
1334 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 }
Steve Blockd0582a62009-12-15 09:54:21 +00001336}
1337
1338int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
1339 int modrm_byte,
1340 byte* modrm_start) {
1341 const char* mnem = "?";
1342 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1343 switch (escape_opcode) {
1344 case 0xD9: switch (regop) {
1345 case 0: mnem = "fld_s"; break;
1346 case 3: mnem = "fstp_s"; break;
1347 case 7: mnem = "fstcw"; break;
1348 default: UnimplementedInstruction();
1349 }
1350 break;
1351
1352 case 0xDB: switch (regop) {
1353 case 0: mnem = "fild_s"; break;
1354 case 1: mnem = "fisttp_s"; break;
1355 case 2: mnem = "fist_s"; break;
1356 case 3: mnem = "fistp_s"; break;
1357 default: UnimplementedInstruction();
1358 }
1359 break;
1360
1361 case 0xDD: switch (regop) {
1362 case 0: mnem = "fld_d"; break;
1363 case 3: mnem = "fstp_d"; break;
1364 default: UnimplementedInstruction();
1365 }
1366 break;
1367
1368 case 0xDF: switch (regop) {
1369 case 5: mnem = "fild_d"; break;
1370 case 7: mnem = "fistp_d"; break;
1371 default: UnimplementedInstruction();
1372 }
1373 break;
1374
1375 default: UnimplementedInstruction();
1376 }
1377 AppendToBuffer("%s ", mnem);
1378 int count = PrintRightOperand(modrm_start);
1379 return count + 1;
1380}
1381
1382int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1383 byte modrm_byte) {
1384 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1385 const char* mnem = "?";
1386
1387 switch (escape_opcode) {
1388 case 0xD8:
1389 UnimplementedInstruction();
1390 break;
1391
1392 case 0xD9:
1393 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001394 case 0xC0:
1395 mnem = "fld";
1396 has_register = true;
1397 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001398 case 0xC8:
1399 mnem = "fxch";
1400 has_register = true;
1401 break;
1402 default:
1403 switch (modrm_byte) {
1404 case 0xE0: mnem = "fchs"; break;
1405 case 0xE1: mnem = "fabs"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001406 case 0xE3: mnem = "fninit"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001407 case 0xE4: mnem = "ftst"; break;
1408 case 0xE8: mnem = "fld1"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001409 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001410 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001411 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001412 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001413 case 0xF1: mnem = "fyl2x"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001414 case 0xF2: mnem = "fptan"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001415 case 0xF5: mnem = "fprem1"; break;
1416 case 0xF7: mnem = "fincstp"; break;
1417 case 0xF8: mnem = "fprem"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418 case 0xFC: mnem = "frndint"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001419 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001420 case 0xFE: mnem = "fsin"; break;
1421 case 0xFF: mnem = "fcos"; break;
1422 default: UnimplementedInstruction();
1423 }
1424 }
1425 break;
1426
1427 case 0xDA:
1428 if (modrm_byte == 0xE9) {
1429 mnem = "fucompp";
1430 } else {
1431 UnimplementedInstruction();
1432 }
1433 break;
1434
1435 case 0xDB:
1436 if ((modrm_byte & 0xF8) == 0xE8) {
1437 mnem = "fucomi";
1438 has_register = true;
1439 } else if (modrm_byte == 0xE2) {
1440 mnem = "fclex";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441 } else if (modrm_byte == 0xE3) {
1442 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001443 } else {
1444 UnimplementedInstruction();
1445 }
1446 break;
1447
1448 case 0xDC:
1449 has_register = true;
1450 switch (modrm_byte & 0xF8) {
1451 case 0xC0: mnem = "fadd"; break;
1452 case 0xE8: mnem = "fsub"; break;
1453 case 0xC8: mnem = "fmul"; break;
1454 case 0xF8: mnem = "fdiv"; break;
1455 default: UnimplementedInstruction();
1456 }
1457 break;
1458
1459 case 0xDD:
1460 has_register = true;
1461 switch (modrm_byte & 0xF8) {
1462 case 0xC0: mnem = "ffree"; break;
1463 case 0xD8: mnem = "fstp"; break;
1464 default: UnimplementedInstruction();
1465 }
1466 break;
1467
1468 case 0xDE:
1469 if (modrm_byte == 0xD9) {
1470 mnem = "fcompp";
1471 } else {
1472 has_register = true;
1473 switch (modrm_byte & 0xF8) {
1474 case 0xC0: mnem = "faddp"; break;
1475 case 0xE8: mnem = "fsubp"; break;
1476 case 0xC8: mnem = "fmulp"; break;
1477 case 0xF8: mnem = "fdivp"; break;
1478 default: UnimplementedInstruction();
1479 }
1480 }
1481 break;
1482
1483 case 0xDF:
1484 if (modrm_byte == 0xE0) {
1485 mnem = "fnstsw_ax";
1486 } else if ((modrm_byte & 0xF8) == 0xE8) {
1487 mnem = "fucomip";
1488 has_register = true;
1489 }
1490 break;
1491
1492 default: UnimplementedInstruction();
1493 }
1494
1495 if (has_register) {
1496 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1497 } else {
1498 AppendToBuffer("%s", mnem);
1499 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 return 2;
1501}
1502
1503
Steve Blockd0582a62009-12-15 09:54:21 +00001504
Steve Blocka7e24c12009-10-30 11:49:00 +00001505// Handle all two-byte opcodes, which start with 0x0F.
1506// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1507// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1508int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1509 byte opcode = *(data + 1);
1510 byte* current = data + 2;
1511 // At return, "current" points to the start of the next instruction.
1512 const char* mnemonic = TwoByteMnemonic(opcode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001513 if (operand_size_ == 0x66) {
1514 // 0x66 0x0F prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 int mod, regop, rm;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001516 if (opcode == 0x38) {
1517 byte third_byte = *current;
1518 current = data + 3;
1519 if (third_byte == 0x40) {
1520 // pmulld xmm, xmm/m128
1521 get_modrm(*current, &mod, &regop, &rm);
1522 AppendToBuffer("pmulld %s,", NameOfXMMRegister(regop));
1523 current += PrintRightXMMOperand(current);
1524 }
1525 } else if (opcode == 0x3A) {
Steve Block6ded16b2010-05-10 14:33:55 +01001526 byte third_byte = *current;
1527 current = data + 3;
1528 if (third_byte == 0x17) {
1529 get_modrm(*current, &mod, &regop, &rm);
1530 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1531 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
Steve Block6ded16b2010-05-10 14:33:55 +01001533 current += 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001534 } else if (third_byte == 0x0a) {
1535 get_modrm(*current, &mod, &regop, &rm);
1536 AppendToBuffer("roundss %s,", NameOfXMMRegister(regop));
1537 current += PrintRightXMMOperand(current);
1538 AppendToBuffer(",0x%x", (*current) & 3);
1539 current += 1;
Ben Murdoch257744e2011-11-30 15:57:28 +00001540 } else if (third_byte == 0x0b) {
1541 get_modrm(*current, &mod, &regop, &rm);
1542 // roundsd xmm, xmm/m64, imm8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001543 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1544 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 AppendToBuffer(",0x%x", (*current) & 3);
1546 current += 1;
1547 } else if (third_byte == 0x16) {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001548 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001549 AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
1550 current += PrintRightOperand(current);
1551 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1552 current += 1;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001553 } else if (third_byte == 0x21) {
1554 get_modrm(*current, &mod, &regop, &rm);
1555 // insertps xmm, xmm/m32, imm8
1556 AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
1557 current += PrintRightXMMOperand(current);
1558 AppendToBuffer(",0x%x", (*current) & 3);
1559 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001560 } else if (third_byte == 0x22) {
1561 get_modrm(*current, &mod, &regop, &rm);
1562 AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
1563 AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1564 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001565 AppendToBuffer(",%d", (*current) & 3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001566 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001567 } else {
1568 UnimplementedInstruction();
1569 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001571 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001572 if (opcode == 0x1f) {
1573 current++;
1574 if (rm == 4) { // SIB byte present.
1575 current++;
1576 }
1577 if (mod == 1) { // Byte displacement.
1578 current += 1;
1579 } else if (mod == 2) { // 32-bit displacement.
1580 current += 4;
1581 } // else no immediate displacement.
1582 AppendToBuffer("nop");
1583 } else if (opcode == 0x28) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001585 current += PrintRightXMMOperand(current);
1586 } else if (opcode == 0x29) {
1587 AppendToBuffer("movapd ");
1588 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001590 } else if (opcode == 0x6E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001591 AppendToBuffer("mov%c %s,",
1592 rex_w() ? 'q' : 'd',
1593 NameOfXMMRegister(regop));
1594 current += PrintRightOperand(current);
Steve Block1e0659c2011-05-24 12:43:12 +01001595 } else if (opcode == 0x6F) {
1596 AppendToBuffer("movdqa %s,",
1597 NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001598 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001599 } else if (opcode == 0x7E) {
Ben Murdochbb769b22010-08-11 14:56:33 +01001600 AppendToBuffer("mov%c ",
1601 rex_w() ? 'q' : 'd');
1602 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001603 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block1e0659c2011-05-24 12:43:12 +01001604 } else if (opcode == 0x7F) {
1605 AppendToBuffer("movdqa ");
Steve Block44f0eee2011-05-26 01:26:41 +01001606 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001608 } else if (opcode == 0xD6) {
1609 AppendToBuffer("movq ");
1610 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001611 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001612 } else if (opcode == 0x50) {
1613 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1614 current += PrintRightXMMOperand(current);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001615 } else if (opcode == 0x70) {
1616 AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
1617 current += PrintRightXMMOperand(current);
1618 AppendToBuffer(",0x%x", *current);
1619 current += 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001620 } else if (opcode == 0x72) {
1621 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001622 AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001623 NameOfXMMRegister(rm), *current & 0x7f);
1624 current += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001625 } else if (opcode == 0x73) {
1626 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001627 AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001628 NameOfXMMRegister(rm), *current & 0x7f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001629 current += 1;
Ben Murdoch61f157c2016-09-16 13:49:30 +01001630 } else if (opcode == 0xB1) {
1631 current += PrintOperands("cmpxchg", OPER_REG_OP_ORDER, current);
Steve Block6ded16b2010-05-10 14:33:55 +01001632 } else {
1633 const char* mnemonic = "?";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001634 if (opcode == 0x54) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001635 mnemonic = "andpd";
1636 } else if (opcode == 0x56) {
1637 mnemonic = "orpd";
1638 } else if (opcode == 0x57) {
Steve Block6ded16b2010-05-10 14:33:55 +01001639 mnemonic = "xorpd";
Ben Murdoch61f157c2016-09-16 13:49:30 +01001640 } else if (opcode == 0x5B) {
1641 mnemonic = "cvtps2dq";
Steve Block6ded16b2010-05-10 14:33:55 +01001642 } else if (opcode == 0x2E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001643 mnemonic = "ucomisd";
Steve Block8defd9f2010-07-08 12:39:36 +01001644 } else if (opcode == 0x2F) {
1645 mnemonic = "comisd";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001646 } else if (opcode == 0x76) {
1647 mnemonic = "pcmpeqd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001648 } else if (opcode == 0x62) {
1649 mnemonic = "punpckldq";
1650 } else if (opcode == 0x6A) {
1651 mnemonic = "punpckhdq";
Ben Murdoch61f157c2016-09-16 13:49:30 +01001652 } else if (opcode == 0xF4) {
1653 mnemonic = "pmuludq";
1654 } else if (opcode == 0xFA) {
1655 mnemonic = "psubd";
1656 } else if (opcode == 0xFE) {
1657 mnemonic = "paddd";
Steve Block6ded16b2010-05-10 14:33:55 +01001658 } else {
1659 UnimplementedInstruction();
1660 }
1661 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1662 current += PrintRightXMMOperand(current);
1663 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001664 }
1665 } else if (group_1_prefix_ == 0xF2) {
1666 // Beginning of instructions with prefix 0xF2.
1667
1668 if (opcode == 0x11 || opcode == 0x10) {
1669 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1670 AppendToBuffer("movsd ");
1671 int mod, regop, rm;
1672 get_modrm(*current, &mod, &regop, &rm);
1673 if (opcode == 0x11) {
Steve Block44f0eee2011-05-26 01:26:41 +01001674 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1676 } else {
1677 AppendToBuffer("%s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001678 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001679 }
1680 } else if (opcode == 0x2A) {
1681 // CVTSI2SD: integer to XMM double conversion.
1682 int mod, regop, rm;
1683 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Blockd0582a62009-12-15 09:54:21 +00001685 current += PrintRightOperand(current);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001686 } else if (opcode == 0x2C) {
1687 // CVTTSD2SI:
1688 // Convert with truncation scalar double-precision FP to integer.
1689 int mod, regop, rm;
1690 get_modrm(*current, &mod, &regop, &rm);
1691 AppendToBuffer("cvttsd2si%c %s,",
1692 operand_size_code(), NameOfCPURegister(regop));
1693 current += PrintRightXMMOperand(current);
1694 } else if (opcode == 0x2D) {
1695 // CVTSD2SI: Convert scalar double-precision FP to integer.
1696 int mod, regop, rm;
1697 get_modrm(*current, &mod, &regop, &rm);
1698 AppendToBuffer("cvtsd2si%c %s,",
1699 operand_size_code(), NameOfCPURegister(regop));
1700 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001701 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001702 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1703 int mod, regop, rm;
1704 get_modrm(*current, &mod, &regop, &rm);
Steve Blockd0582a62009-12-15 09:54:21 +00001705 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1706 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001707 } else if (opcode == 0xC2) {
1708 // Intel manual 2A, Table 3-18.
1709 int mod, regop, rm;
1710 get_modrm(*current, &mod, &regop, &rm);
1711 const char* const pseudo_op[] = {
1712 "cmpeqsd",
1713 "cmpltsd",
1714 "cmplesd",
1715 "cmpunordsd",
1716 "cmpneqsd",
1717 "cmpnltsd",
1718 "cmpnlesd",
1719 "cmpordsd"
1720 };
1721 AppendToBuffer("%s %s,%s",
1722 pseudo_op[current[1]],
1723 NameOfXMMRegister(regop),
1724 NameOfXMMRegister(rm));
1725 current += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001726 } else {
1727 UnimplementedInstruction();
1728 }
Steve Block6ded16b2010-05-10 14:33:55 +01001729 } else if (group_1_prefix_ == 0xF3) {
1730 // Instructions with prefix 0xF3.
Steve Block8defd9f2010-07-08 12:39:36 +01001731 if (opcode == 0x11 || opcode == 0x10) {
1732 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1733 AppendToBuffer("movss ");
1734 int mod, regop, rm;
1735 get_modrm(*current, &mod, &regop, &rm);
1736 if (opcode == 0x11) {
1737 current += PrintRightOperand(current);
1738 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1739 } else {
1740 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1741 current += PrintRightOperand(current);
1742 }
1743 } else if (opcode == 0x2A) {
1744 // CVTSI2SS: integer to XMM single conversion.
1745 int mod, regop, rm;
1746 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001747 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Block8defd9f2010-07-08 12:39:36 +01001748 current += PrintRightOperand(current);
1749 } else if (opcode == 0x2C) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001750 // CVTTSS2SI:
1751 // Convert with truncation scalar single-precision FP to dword integer.
Steve Block1e0659c2011-05-24 12:43:12 +01001752 int mod, regop, rm;
1753 get_modrm(*current, &mod, &regop, &rm);
1754 AppendToBuffer("cvttss2si%c %s,",
1755 operand_size_code(), NameOfCPURegister(regop));
1756 current += PrintRightXMMOperand(current);
Ben Murdoch257744e2011-11-30 15:57:28 +00001757 } else if (opcode == 0x7E) {
1758 int mod, regop, rm;
1759 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001760 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001761 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001762 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1763 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1764 int mod, regop, rm;
1765 get_modrm(*current, &mod, &regop, &rm);
1766 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1767 current += PrintRightXMMOperand(current);
1768 } else if (opcode == 0xB8) {
1769 int mod, regop, rm;
1770 get_modrm(*current, &mod, &regop, &rm);
1771 AppendToBuffer("popcnt%c %s,", operand_size_code(),
1772 NameOfCPURegister(regop));
1773 current += PrintRightOperand(current);
1774 } else if (opcode == 0xBC) {
1775 int mod, regop, rm;
1776 get_modrm(*current, &mod, &regop, &rm);
1777 AppendToBuffer("tzcnt%c %s,", operand_size_code(),
1778 NameOfCPURegister(regop));
1779 current += PrintRightOperand(current);
1780 } else if (opcode == 0xBD) {
1781 int mod, regop, rm;
1782 get_modrm(*current, &mod, &regop, &rm);
1783 AppendToBuffer("lzcnt%c %s,", operand_size_code(),
1784 NameOfCPURegister(regop));
1785 current += PrintRightOperand(current);
1786 } else if (opcode == 0xC2) {
1787 // Intel manual 2A, Table 3-18.
1788 int mod, regop, rm;
1789 get_modrm(*current, &mod, &regop, &rm);
1790 const char* const pseudo_op[] = {"cmpeqss", "cmpltss", "cmpless",
1791 "cmpunordss", "cmpneqss", "cmpnltss",
1792 "cmpnless", "cmpordss"};
1793 AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
1794 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
1795 current += 2;
Steve Block6ded16b2010-05-10 14:33:55 +01001796 } else {
1797 UnimplementedInstruction();
1798 }
Ben Murdoch61f157c2016-09-16 13:49:30 +01001799 } else if (opcode == 0x10 || opcode == 0x11) {
1800 // movups xmm, xmm/m128
1801 // movups xmm/m128, xmm
1802 int mod, regop, rm;
1803 get_modrm(*current, &mod, &regop, &rm);
1804 AppendToBuffer("movups ");
1805 if (opcode == 0x11) {
1806 current += PrintRightXMMOperand(current);
1807 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1808 } else {
1809 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1810 current += PrintRightXMMOperand(current);
1811 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001812 } else if (opcode == 0x1F) {
1813 // NOP
1814 int mod, regop, rm;
1815 get_modrm(*current, &mod, &regop, &rm);
1816 current++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001817 if (rm == 4) { // SIB byte present.
Andrei Popescu402d9372010-02-26 13:31:12 +00001818 current++;
1819 }
1820 if (mod == 1) { // Byte displacement.
1821 current += 1;
1822 } else if (mod == 2) { // 32-bit displacement.
1823 current += 4;
1824 } // else no immediate displacement.
1825 AppendToBuffer("nop");
Ben Murdoch257744e2011-11-30 15:57:28 +00001826
1827 } else if (opcode == 0x28) {
1828 // movaps xmm, xmm/m128
1829 int mod, regop, rm;
1830 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001831 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001832 current += PrintRightXMMOperand(current);
1833
1834 } else if (opcode == 0x29) {
1835 // movaps xmm/m128, xmm
1836 int mod, regop, rm;
1837 get_modrm(*current, &mod, &regop, &rm);
1838 AppendToBuffer("movaps ");
1839 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001840 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001841
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001842 } else if (opcode == 0x2e) {
1843 int mod, regop, rm;
1844 get_modrm(*current, &mod, &regop, &rm);
1845 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1846 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001847 } else if (opcode == 0xA2) {
1848 // CPUID
Andrei Popescu402d9372010-02-26 13:31:12 +00001849 AppendToBuffer("%s", mnemonic);
1850
1851 } else if ((opcode & 0xF0) == 0x40) {
1852 // CMOVcc: conditional move.
1853 int condition = opcode & 0x0F;
1854 const InstructionDesc& idesc = cmov_instructions[condition];
1855 byte_size_operand_ = idesc.byte_size_operation;
1856 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1857
Ben Murdoch61f157c2016-09-16 13:49:30 +01001858 } else if (opcode >= 0x51 && opcode <= 0x5F) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001859 const char* const pseudo_op[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001860 "sqrtps", "rsqrtps", "rcpps", "andps", "andnps",
1861 "orps", "xorps", "addps", "mulps", "cvtps2pd",
1862 "cvtdq2ps", "subps", "minps", "divps", "maxps",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001863 };
Ben Murdoch257744e2011-11-30 15:57:28 +00001864 int mod, regop, rm;
1865 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch61f157c2016-09-16 13:49:30 +01001866 AppendToBuffer("%s %s,", pseudo_op[opcode - 0x51],
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 NameOfXMMRegister(regop));
1868 current += PrintRightXMMOperand(current);
1869
Ben Murdoch61f157c2016-09-16 13:49:30 +01001870 } else if (opcode == 0xC2) {
1871 // cmpps xmm, xmm/m128, imm8
1872 int mod, regop, rm;
1873 get_modrm(*current, &mod, &regop, &rm);
1874 const char* const pseudo_op[] = {"cmpeqps", "cmpltps", "cmpleps",
1875 "cmpunordps", "cmpneqps", "cmpnltps",
1876 "cmpnleps", "cmpordps"};
1877 AppendToBuffer("%s %s,%s", pseudo_op[current[1]], NameOfXMMRegister(regop),
1878 NameOfXMMRegister(rm));
1879 current += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001880 } else if (opcode == 0xC6) {
1881 // shufps xmm, xmm/m128, imm8
1882 int mod, regop, rm;
1883 get_modrm(*current, &mod, &regop, &rm);
1884 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1885 current += PrintRightXMMOperand(current);
1886 AppendToBuffer(", %d", (*current) & 3);
1887 current += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001888 } else if (opcode == 0x50) {
1889 // movmskps reg, xmm
1890 int mod, regop, rm;
1891 get_modrm(*current, &mod, &regop, &rm);
1892 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001893 current += PrintRightXMMOperand(current);
1894
Andrei Popescu402d9372010-02-26 13:31:12 +00001895 } else if ((opcode & 0xF0) == 0x80) {
1896 // Jcc: Conditional jump (branch).
1897 current = data + JumpConditional(data);
1898
1899 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1900 opcode == 0xB7 || opcode == 0xAF) {
1901 // Size-extending moves, IMUL.
1902 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1903
1904 } else if ((opcode & 0xF0) == 0x90) {
1905 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1906 current = data + SetCC(data);
1907
1908 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1909 // SHLD, SHRD (double-precision shift), BTS (bit set).
1910 AppendToBuffer("%s ", mnemonic);
1911 int mod, regop, rm;
1912 get_modrm(*current, &mod, &regop, &rm);
1913 current += PrintRightOperand(current);
1914 if (opcode == 0xAB) {
1915 AppendToBuffer(",%s", NameOfCPURegister(regop));
1916 } else {
1917 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1918 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001919 } else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
1920 // POPCNT, CTZ, CLZ.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001921 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1922 int mod, regop, rm;
1923 get_modrm(*current, &mod, &regop, &rm);
1924 AppendToBuffer("%s,", NameOfCPURegister(regop));
1925 current += PrintRightOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001926 } else if (opcode == 0x0B) {
1927 AppendToBuffer("ud2");
Ben Murdoch61f157c2016-09-16 13:49:30 +01001928 } else if (opcode == 0xB0 || opcode == 0xB1) {
1929 // CMPXCHG.
1930 if (opcode == 0xB0) {
1931 byte_size_operand_ = true;
1932 }
1933 current += PrintOperands(mnemonic, OPER_REG_OP_ORDER, current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001934 } else {
1935 UnimplementedInstruction();
1936 }
Steve Blockd0582a62009-12-15 09:54:21 +00001937 return static_cast<int>(current - data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001938}
1939
1940
1941// Mnemonics for two-byte opcode instructions starting with 0x0F.
1942// The argument is the second byte of the two-byte opcode.
1943// Returns NULL if the instruction is not handled here.
1944const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1945 switch (opcode) {
1946 case 0x1F:
1947 return "nop";
Steve Block8defd9f2010-07-08 12:39:36 +01001948 case 0x2A: // F2/F3 prefix.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001949 return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
1950 case 0x51: // F2/F3 prefix.
1951 return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
1952 case 0x58: // F2/F3 prefix.
1953 return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
1954 case 0x59: // F2/F3 prefix.
1955 return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
1956 case 0x5A: // F2/F3 prefix.
1957 return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
1958 case 0x5D: // F2/F3 prefix.
1959 return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
1960 case 0x5C: // F2/F3 prefix.
1961 return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
1962 case 0x5E: // F2/F3 prefix.
1963 return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
1964 case 0x5F: // F2/F3 prefix.
1965 return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 case 0xA2:
1967 return "cpuid";
1968 case 0xA5:
1969 return "shld";
1970 case 0xAB:
1971 return "bts";
1972 case 0xAD:
1973 return "shrd";
1974 case 0xAF:
1975 return "imul";
Ben Murdoch61f157c2016-09-16 13:49:30 +01001976 case 0xB0:
1977 case 0xB1:
1978 return "cmpxchg";
Steve Blocka7e24c12009-10-30 11:49:00 +00001979 case 0xB6:
1980 return "movzxb";
1981 case 0xB7:
1982 return "movzxw";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001983 case 0xBC:
1984 return "bsf";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001985 case 0xBD:
1986 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001987 case 0xBE:
1988 return "movsxb";
1989 case 0xBF:
1990 return "movsxw";
1991 default:
1992 return NULL;
1993 }
1994}
1995
1996
1997// Disassembles the instruction at instr, and writes it into out_buffer.
1998int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1999 byte* instr) {
2000 tmp_buffer_pos_ = 0; // starting to write as position 0
2001 byte* data = instr;
2002 bool processed = true; // Will be set to false if the current instruction
2003 // is not in 'instructions' table.
2004 byte current;
2005
2006 // Scan for prefixes.
2007 while (true) {
2008 current = *data;
Leon Clarked91b9f72010-01-27 17:25:45 +00002009 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00002010 operand_size_ = current;
2011 } else if ((current & 0xF0) == 0x40) { // REX prefix.
2012 setRex(current);
2013 if (rex_w()) AppendToBuffer("REX.W ");
Leon Clarked91b9f72010-01-27 17:25:45 +00002014 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
Steve Blocka7e24c12009-10-30 11:49:00 +00002015 group_1_prefix_ = current;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002016 } else if (current == LOCK_PREFIX) {
2017 AppendToBuffer("lock ");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002018 } else if (current == VEX3_PREFIX) {
2019 vex_byte0_ = current;
2020 vex_byte1_ = *(data + 1);
2021 vex_byte2_ = *(data + 2);
2022 setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002023 data += 3;
2024 break; // Vex is the last prefix.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002025 } else if (current == VEX2_PREFIX) {
2026 vex_byte0_ = current;
2027 vex_byte1_ = *(data + 1);
2028 setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002029 data += 2;
2030 break; // Vex is the last prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00002031 } else { // Not a prefix - an opcode.
2032 break;
2033 }
2034 data++;
2035 }
2036
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002037 // Decode AVX instructions.
2038 if (vex_byte0_ != 0) {
2039 processed = true;
2040 data += AVXInstruction(data);
2041 } else {
2042 const InstructionDesc& idesc = instruction_table_->Get(current);
2043 byte_size_operand_ = idesc.byte_size_operation;
2044 switch (idesc.type) {
2045 case ZERO_OPERANDS_INSTR:
2046 if (current >= 0xA4 && current <= 0xA7) {
2047 // String move or compare operations.
2048 if (group_1_prefix_ == REP_PREFIX) {
2049 // REP.
2050 AppendToBuffer("rep ");
2051 }
2052 if (rex_w()) AppendToBuffer("REX.W ");
2053 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2054 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002055 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
Leon Clarked91b9f72010-01-27 17:25:45 +00002056 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002057 data++;
2058 break;
2059
2060 case TWO_OPERANDS_INSTR:
2061 data++;
2062 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
2063 break;
2064
2065 case JUMP_CONDITIONAL_SHORT_INSTR:
2066 data += JumpConditionalShort(data);
2067 break;
2068
2069 case REGISTER_INSTR:
2070 AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
2071 NameOfCPURegister(base_reg(current & 0x07)));
2072 data++;
2073 break;
2074 case PUSHPOP_INSTR:
2075 AppendToBuffer("%s %s", idesc.mnem,
2076 NameOfCPURegister(base_reg(current & 0x07)));
2077 data++;
2078 break;
2079 case MOVE_REG_INSTR: {
2080 byte* addr = NULL;
2081 switch (operand_size()) {
2082 case OPERAND_WORD_SIZE:
2083 addr =
2084 reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
2085 data += 3;
2086 break;
2087 case OPERAND_DOUBLEWORD_SIZE:
2088 addr =
2089 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
2090 data += 5;
2091 break;
2092 case OPERAND_QUADWORD_SIZE:
2093 addr =
2094 reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
2095 data += 9;
2096 break;
2097 default:
2098 UNREACHABLE();
2099 }
2100 AppendToBuffer("mov%c %s,%s", operand_size_code(),
2101 NameOfCPURegister(base_reg(current & 0x07)),
2102 NameOfAddress(addr));
2103 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00002104 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002105
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002106 case CALL_JUMP_INSTR: {
2107 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
2108 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
2109 data += 5;
2110 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002111 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002112
2113 case SHORT_IMMEDIATE_INSTR: {
2114 byte* addr =
2115 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
2116 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
2117 data += 5;
2118 break;
2119 }
2120
2121 case NO_INSTR:
2122 processed = false;
2123 break;
2124
2125 default:
2126 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00002127 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002128 }
2129
2130 // The first byte didn't match any of the simple opcodes, so we
2131 // need to do special processing on it.
2132 if (!processed) {
2133 switch (*data) {
2134 case 0xC2:
2135 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
2136 data += 3;
2137 break;
2138
2139 case 0x69: // fall through
2140 case 0x6B: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002141 int count = 1;
2142 count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
2143 AppendToBuffer(",0x");
2144 if (*data == 0x69) {
2145 count += PrintImmediate(data + count, operand_size());
2146 } else {
2147 count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
2148 }
2149 data += count;
Steve Blocka7e24c12009-10-30 11:49:00 +00002150 break;
2151 }
2152
Steve Blocka7e24c12009-10-30 11:49:00 +00002153 case 0x81: // fall through
2154 case 0x83: // 0x81 with sign extension bit set
2155 data += PrintImmediateOp(data);
2156 break;
2157
2158 case 0x0F:
2159 data += TwoByteOpcodeInstruction(data);
2160 break;
2161
2162 case 0x8F: {
2163 data++;
2164 int mod, regop, rm;
2165 get_modrm(*data, &mod, &regop, &rm);
2166 if (regop == 0) {
2167 AppendToBuffer("pop ");
2168 data += PrintRightOperand(data);
2169 }
2170 }
2171 break;
2172
2173 case 0xFF: {
2174 data++;
2175 int mod, regop, rm;
2176 get_modrm(*data, &mod, &regop, &rm);
2177 const char* mnem = NULL;
2178 switch (regop) {
2179 case 0:
2180 mnem = "inc";
2181 break;
2182 case 1:
2183 mnem = "dec";
2184 break;
2185 case 2:
2186 mnem = "call";
2187 break;
2188 case 4:
2189 mnem = "jmp";
2190 break;
2191 case 6:
2192 mnem = "push";
2193 break;
2194 default:
2195 mnem = "???";
2196 }
Ben Murdochc5610432016-08-08 18:44:38 +01002197 if (regop <= 1) {
2198 AppendToBuffer("%s%c ", mnem, operand_size_code());
2199 } else {
2200 AppendToBuffer("%s ", mnem);
2201 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002202 data += PrintRightOperand(data);
2203 }
2204 break;
2205
2206 case 0xC7: // imm32, fall through
2207 case 0xC6: // imm8
2208 {
2209 bool is_byte = *data == 0xC6;
2210 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01002211 if (is_byte) {
2212 AppendToBuffer("movb ");
2213 data += PrintRightByteOperand(data);
2214 int32_t imm = *data;
2215 AppendToBuffer(",0x%x", imm);
2216 data++;
2217 } else {
2218 AppendToBuffer("mov%c ", operand_size_code());
2219 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002220 if (operand_size() == OPERAND_WORD_SIZE) {
2221 int16_t imm = *reinterpret_cast<int16_t*>(data);
2222 AppendToBuffer(",0x%x", imm);
2223 data += 2;
2224 } else {
2225 int32_t imm = *reinterpret_cast<int32_t*>(data);
2226 AppendToBuffer(",0x%x", imm);
2227 data += 4;
2228 }
Steve Block44f0eee2011-05-26 01:26:41 +01002229 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002230 }
2231 break;
2232
2233 case 0x80: {
2234 data++;
2235 AppendToBuffer("cmpb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002236 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002237 int32_t imm = *data;
2238 AppendToBuffer(",0x%x", imm);
2239 data++;
2240 }
2241 break;
2242
2243 case 0x88: // 8bit, fall through
2244 case 0x89: // 32bit
2245 {
2246 bool is_byte = *data == 0x88;
2247 int mod, regop, rm;
2248 data++;
2249 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002250 if (is_byte) {
2251 AppendToBuffer("movb ");
2252 data += PrintRightByteOperand(data);
2253 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2254 } else {
2255 AppendToBuffer("mov%c ", operand_size_code());
2256 data += PrintRightOperand(data);
2257 AppendToBuffer(",%s", NameOfCPURegister(regop));
2258 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002259 }
2260 break;
2261
2262 case 0x90:
2263 case 0x91:
2264 case 0x92:
2265 case 0x93:
2266 case 0x94:
2267 case 0x95:
2268 case 0x96:
2269 case 0x97: {
Steve Blockd0582a62009-12-15 09:54:21 +00002270 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002271 if (reg == 0) {
2272 AppendToBuffer("nop"); // Common name for xchg rax,rax.
2273 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002274 AppendToBuffer("xchg%c rax,%s",
Steve Blocka7e24c12009-10-30 11:49:00 +00002275 operand_size_code(),
2276 NameOfCPURegister(reg));
2277 }
Steve Blockd0582a62009-12-15 09:54:21 +00002278 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00002279 }
Steve Blockd0582a62009-12-15 09:54:21 +00002280 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002281 case 0xB0:
2282 case 0xB1:
2283 case 0xB2:
2284 case 0xB3:
2285 case 0xB4:
2286 case 0xB5:
2287 case 0xB6:
2288 case 0xB7:
2289 case 0xB8:
2290 case 0xB9:
2291 case 0xBA:
2292 case 0xBB:
2293 case 0xBC:
2294 case 0xBD:
2295 case 0xBE:
2296 case 0xBF: {
2297 // mov reg8,imm8 or mov reg32,imm32
2298 byte opcode = *data;
2299 data++;
2300 bool is_32bit = (opcode >= 0xB8);
2301 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
2302 if (is_32bit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002303 AppendToBuffer("mov%c %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002304 operand_size_code(),
2305 NameOfCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002306 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002307 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002308 AppendToBuffer("movb %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002309 NameOfByteCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002310 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002311 }
2312 break;
2313 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002314 case 0xFE: {
2315 data++;
2316 int mod, regop, rm;
2317 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002318 if (regop == 1) {
2319 AppendToBuffer("decb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002320 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002321 } else {
2322 UnimplementedInstruction();
2323 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002324 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002325 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002326 case 0x68:
2327 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
2328 data += 5;
2329 break;
2330
2331 case 0x6A:
2332 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
2333 data += 2;
2334 break;
2335
2336 case 0xA1: // Fall through.
2337 case 0xA3:
2338 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002339 case OPERAND_DOUBLEWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002340 const char* memory_location = NameOfAddress(
2341 reinterpret_cast<byte*>(
2342 *reinterpret_cast<int32_t*>(data + 1)));
2343 if (*data == 0xA1) { // Opcode 0xA1
2344 AppendToBuffer("movzxlq rax,(%s)", memory_location);
2345 } else { // Opcode 0xA3
2346 AppendToBuffer("movzxlq (%s),rax", memory_location);
2347 }
2348 data += 5;
2349 break;
2350 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002351 case OPERAND_QUADWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002352 // New x64 instruction mov rax,(imm_64).
2353 const char* memory_location = NameOfAddress(
2354 *reinterpret_cast<byte**>(data + 1));
2355 if (*data == 0xA1) { // Opcode 0xA1
2356 AppendToBuffer("movq rax,(%s)", memory_location);
2357 } else { // Opcode 0xA3
2358 AppendToBuffer("movq (%s),rax", memory_location);
2359 }
2360 data += 9;
2361 break;
2362 }
2363 default:
2364 UnimplementedInstruction();
2365 data += 2;
2366 }
2367 break;
2368
2369 case 0xA8:
2370 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
2371 data += 2;
2372 break;
2373
2374 case 0xA9: {
2375 int64_t value = 0;
2376 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002377 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002378 value = *reinterpret_cast<uint16_t*>(data + 1);
2379 data += 3;
2380 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002381 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002382 value = *reinterpret_cast<uint32_t*>(data + 1);
2383 data += 5;
2384 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002385 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002386 value = *reinterpret_cast<int32_t*>(data + 1);
2387 data += 5;
2388 break;
2389 default:
2390 UNREACHABLE();
2391 }
Ben Murdochc5610432016-08-08 18:44:38 +01002392 AppendToBuffer("test%c rax,0x%" PRIx64, operand_size_code(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002393 break;
2394 }
2395 case 0xD1: // fall through
2396 case 0xD3: // fall through
2397 case 0xC1:
2398 data += ShiftInstruction(data);
2399 break;
2400 case 0xD0: // fall through
2401 case 0xD2: // fall through
2402 case 0xC0:
2403 byte_size_operand_ = true;
2404 data += ShiftInstruction(data);
2405 break;
2406
2407 case 0xD9: // fall through
2408 case 0xDA: // fall through
2409 case 0xDB: // fall through
2410 case 0xDC: // fall through
2411 case 0xDD: // fall through
2412 case 0xDE: // fall through
2413 case 0xDF:
2414 data += FPUInstruction(data);
2415 break;
2416
2417 case 0xEB:
2418 data += JumpShort(data);
2419 break;
2420
Steve Blockd0582a62009-12-15 09:54:21 +00002421 case 0xF6:
2422 byte_size_operand_ = true; // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00002423 case 0xF7:
Steve Blockd0582a62009-12-15 09:54:21 +00002424 data += F6F7Instruction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002425 break;
2426
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002427 case 0x3C:
2428 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2429 data +=2;
2430 break;
2431
Steve Blocka7e24c12009-10-30 11:49:00 +00002432 default:
2433 UnimplementedInstruction();
2434 data += 1;
2435 }
2436 } // !processed
2437
2438 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2439 tmp_buffer_[tmp_buffer_pos_] = '\0';
2440 }
2441
Steve Blockd0582a62009-12-15 09:54:21 +00002442 int instr_len = static_cast<int>(data - instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002443 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002444
2445 int outp = 0;
2446 // Instruction bytes.
2447 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002448 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002449 }
2450 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002451 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002452 }
2453
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002454 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2455 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002456 return instr_len;
2457}
2458
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002459
Steve Blocka7e24c12009-10-30 11:49:00 +00002460//------------------------------------------------------------------------------
2461
2462
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002463static const char* const cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002464 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2465 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2466};
2467
2468
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002469static const char* const byte_cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002470 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2471 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2472};
2473
2474
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002475static const char* const xmm_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002476 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2477 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2478};
2479
2480
2481const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdoch61f157c2016-09-16 13:49:30 +01002482 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
Steve Block44f0eee2011-05-26 01:26:41 +01002483 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002484}
2485
2486
2487const char* NameConverter::NameOfConstant(byte* addr) const {
2488 return NameOfAddress(addr);
2489}
2490
2491
2492const char* NameConverter::NameOfCPURegister(int reg) const {
2493 if (0 <= reg && reg < 16)
2494 return cpu_regs[reg];
2495 return "noreg";
2496}
2497
2498
2499const char* NameConverter::NameOfByteCPURegister(int reg) const {
2500 if (0 <= reg && reg < 16)
2501 return byte_cpu_regs[reg];
2502 return "noreg";
2503}
2504
2505
2506const char* NameConverter::NameOfXMMRegister(int reg) const {
2507 if (0 <= reg && reg < 16)
2508 return xmm_regs[reg];
2509 return "noxmmreg";
2510}
2511
2512
2513const char* NameConverter::NameInCode(byte* addr) const {
2514 // X64 does not embed debug strings at the moment.
2515 UNREACHABLE();
2516 return "";
2517}
2518
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002519
Steve Blocka7e24c12009-10-30 11:49:00 +00002520//------------------------------------------------------------------------------
2521
2522Disassembler::Disassembler(const NameConverter& converter)
2523 : converter_(converter) { }
2524
2525Disassembler::~Disassembler() { }
2526
2527
2528int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2529 byte* instruction) {
2530 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2531 return d.InstructionDecode(buffer, instruction);
2532}
2533
2534
2535// The X64 assembler does not use constant pools.
2536int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2537 return -1;
2538}
2539
2540
2541void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2542 NameConverter converter;
2543 Disassembler d(converter);
2544 for (byte* pc = begin; pc < end;) {
2545 v8::internal::EmbeddedVector<char, 128> buffer;
2546 buffer[0] = '\0';
2547 byte* prev_pc = pc;
2548 pc += d.InstructionDecode(buffer, pc);
Ben Murdoch61f157c2016-09-16 13:49:30 +01002549 fprintf(f, "%p", static_cast<void*>(prev_pc));
Steve Blocka7e24c12009-10-30 11:49:00 +00002550 fprintf(f, " ");
2551
2552 for (byte* bp = prev_pc; bp < pc; bp++) {
2553 fprintf(f, "%02x", *bp);
2554 }
Steve Blockd0582a62009-12-15 09:54:21 +00002555 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002556 fprintf(f, " ");
2557 }
2558 fprintf(f, " %s\n", buffer.start());
2559 }
2560}
2561
2562} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002563
2564#endif // V8_TARGET_ARCH_X64