blob: 7126b89b9956a94febcc2c6e24cb2fb2f1cec6e7 [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
145
Leon Clarked91b9f72010-01-27 17:25:45 +0000146enum Prefixes {
147 ESCAPE_PREFIX = 0x0F,
148 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
149 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150 VEX3_PREFIX = 0xC4,
151 VEX2_PREFIX = 0xC5,
Leon Clarked91b9f72010-01-27 17:25:45 +0000152 REPNE_PREFIX = 0xF2,
153 REP_PREFIX = 0xF3,
154 REPEQ_PREFIX = REP_PREFIX
155};
156
157
Steve Blocka7e24c12009-10-30 11:49:00 +0000158struct InstructionDesc {
159 const char* mnem;
160 InstructionType type;
161 OperandType op_order_;
162 bool byte_size_operation; // Fixed 8-bit operation.
163};
164
165
166class InstructionTable {
167 public:
168 InstructionTable();
169 const InstructionDesc& Get(byte x) const {
170 return instructions_[x];
171 }
172
173 private:
174 InstructionDesc instructions_[256];
175 void Clear();
176 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000177 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
179 const char* mnem);
180 void AddJumpConditionalShort();
181};
182
183
184InstructionTable::InstructionTable() {
185 Clear();
186 Init();
187}
188
189
190void InstructionTable::Clear() {
191 for (int i = 0; i < 256; i++) {
192 instructions_[i].mnem = "(bad)";
193 instructions_[i].type = NO_INSTR;
194 instructions_[i].op_order_ = UNSET_OP_ORDER;
195 instructions_[i].byte_size_operation = false;
196 }
197}
198
199
200void InstructionTable::Init() {
201 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
202 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
203 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
204 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
205 AddJumpConditionalShort();
206 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
207 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
208 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
209}
210
211
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000212void InstructionTable::CopyTable(const ByteMnemonic bm[],
213 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 for (int i = 0; bm[i].b >= 0; i++) {
215 InstructionDesc* id = &instructions_[bm[i].b];
216 id->mnem = bm[i].mnem;
217 OperandType op_order = bm[i].op_order_;
218 id->op_order_ =
219 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 id->type = type;
222 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
223 }
224}
225
226
227void InstructionTable::SetTableRange(InstructionType type,
228 byte start,
229 byte end,
230 bool byte_size,
231 const char* mnem) {
232 for (byte b = start; b <= end; b++) {
233 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000235 id->mnem = mnem;
236 id->type = type;
237 id->byte_size_operation = byte_size;
238 }
239}
240
241
242void InstructionTable::AddJumpConditionalShort() {
243 for (byte b = 0x70; b <= 0x7F; b++) {
244 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 id->mnem = NULL; // Computed depending on condition code.
247 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
248 }
249}
250
251
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252static v8::base::LazyInstance<InstructionTable>::type instruction_table =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100253 LAZY_INSTANCE_INITIALIZER;
Steve Blocka7e24c12009-10-30 11:49:00 +0000254
Steve Block44f0eee2011-05-26 01:26:41 +0100255
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400256static const InstructionDesc cmov_instructions[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
272 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
273};
274
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275
Steve Blocka7e24c12009-10-30 11:49:00 +0000276//------------------------------------------------------------------------------
277// DisassemblerX64 implementation.
278
279enum UnimplementedOpcodeAction {
280 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
281 ABORT_ON_UNIMPLEMENTED_OPCODE
282};
283
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000284
Steve Blocka7e24c12009-10-30 11:49:00 +0000285// A new DisassemblerX64 object is created to disassemble each instruction.
286// The object can only disassemble a single instruction.
287class DisassemblerX64 {
288 public:
289 DisassemblerX64(const NameConverter& converter,
290 UnimplementedOpcodeAction unimplemented_action =
291 ABORT_ON_UNIMPLEMENTED_OPCODE)
292 : converter_(converter),
293 tmp_buffer_pos_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 abort_on_unimplemented_(unimplemented_action ==
295 ABORT_ON_UNIMPLEMENTED_OPCODE),
Steve Blocka7e24c12009-10-30 11:49:00 +0000296 rex_(0),
297 operand_size_(0),
298 group_1_prefix_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400299 vex_byte0_(0),
300 vex_byte1_(0),
301 vex_byte2_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000302 byte_size_operand_(false),
303 instruction_table_(instruction_table.Pointer()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 tmp_buffer_[0] = '\0';
305 }
306
307 virtual ~DisassemblerX64() {
308 }
309
310 // Writes one disassembled instruction into 'buffer' (0-terminated).
311 // Returns the length of the disassembled machine instruction in bytes.
312 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
313
314 private:
315 enum OperandSize {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 OPERAND_BYTE_SIZE = 0,
317 OPERAND_WORD_SIZE = 1,
318 OPERAND_DOUBLEWORD_SIZE = 2,
319 OPERAND_QUADWORD_SIZE = 3
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 };
321
322 const NameConverter& converter_;
323 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
324 unsigned int tmp_buffer_pos_;
325 bool abort_on_unimplemented_;
326 // Prefixes parsed
327 byte rex_;
328 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
329 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400330 byte vex_byte0_; // 0xc4 or 0xc5
331 byte vex_byte1_;
332 byte vex_byte2_; // only for 3 bytes vex prefix
Steve Blocka7e24c12009-10-30 11:49:00 +0000333 // Byte size operand override.
334 bool byte_size_operand_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 const InstructionTable* const instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000336
337 void setRex(byte rex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338 DCHECK_EQ(0x40, rex & 0xF0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 rex_ = rex;
340 }
341
342 bool rex() { return rex_ != 0; }
343
344 bool rex_b() { return (rex_ & 0x01) != 0; }
345
346 // Actual number of base register given the low bits and the rex.b state.
347 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
348
349 bool rex_x() { return (rex_ & 0x02) != 0; }
350
351 bool rex_r() { return (rex_ & 0x04) != 0; }
352
353 bool rex_w() { return (rex_ & 0x08) != 0; }
354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 bool vex_w() {
356 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
357 return vex_byte0_ == VEX3_PREFIX ? (vex_byte2_ & 0x80) != 0 : false;
358 }
359
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360 bool vex_128() {
361 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
362 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
Ben Murdochc5610432016-08-08 18:44:38 +0100363 return (checked & 4) == 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400364 }
365
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 bool vex_none() {
367 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
368 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
369 return (checked & 3) == 0;
370 }
371
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372 bool vex_66() {
373 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
374 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
375 return (checked & 3) == 1;
376 }
377
378 bool vex_f3() {
379 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
380 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
381 return (checked & 3) == 2;
382 }
383
384 bool vex_f2() {
385 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
386 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
387 return (checked & 3) == 3;
388 }
389
390 bool vex_0f() {
391 if (vex_byte0_ == VEX2_PREFIX) return true;
392 return (vex_byte1_ & 3) == 1;
393 }
394
395 bool vex_0f38() {
396 if (vex_byte0_ == VEX2_PREFIX) return false;
397 return (vex_byte1_ & 3) == 2;
398 }
399
400 bool vex_0f3a() {
401 if (vex_byte0_ == VEX2_PREFIX) return false;
402 return (vex_byte1_ & 3) == 3;
403 }
404
405 int vex_vreg() {
406 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
407 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
408 return ~(checked >> 3) & 0xf;
409 }
410
Steve Blocka7e24c12009-10-30 11:49:00 +0000411 OperandSize operand_size() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000412 if (byte_size_operand_) return OPERAND_BYTE_SIZE;
413 if (rex_w()) return OPERAND_QUADWORD_SIZE;
414 if (operand_size_ != 0) return OPERAND_WORD_SIZE;
415 return OPERAND_DOUBLEWORD_SIZE;
Steve Blocka7e24c12009-10-30 11:49:00 +0000416 }
417
418 char operand_size_code() {
419 return "bwlq"[operand_size()];
420 }
421
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400422 char float_size_code() { return "sd"[rex_w()]; }
423
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 const char* NameOfCPURegister(int reg) const {
425 return converter_.NameOfCPURegister(reg);
426 }
427
428 const char* NameOfByteCPURegister(int reg) const {
429 return converter_.NameOfByteCPURegister(reg);
430 }
431
432 const char* NameOfXMMRegister(int reg) const {
433 return converter_.NameOfXMMRegister(reg);
434 }
435
436 const char* NameOfAddress(byte* addr) const {
437 return converter_.NameOfAddress(addr);
438 }
439
440 // Disassembler helper functions.
441 void get_modrm(byte data,
442 int* mod,
443 int* regop,
444 int* rm) {
445 *mod = (data >> 6) & 3;
446 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
447 *rm = (data & 7) | (rex_b() ? 8 : 0);
448 }
449
450 void get_sib(byte data,
451 int* scale,
452 int* index,
453 int* base) {
454 *scale = (data >> 6) & 3;
455 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
456 *base = (data & 7) | (rex_b() ? 8 : 0);
457 }
458
459 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
460
461 int PrintRightOperandHelper(byte* modrmp,
462 RegisterNameMapping register_name);
463 int PrintRightOperand(byte* modrmp);
464 int PrintRightByteOperand(byte* modrmp);
Steve Blockd0582a62009-12-15 09:54:21 +0000465 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 int PrintOperands(const char* mnem,
467 OperandType op_order,
468 byte* data);
469 int PrintImmediate(byte* data, OperandSize size);
470 int PrintImmediateOp(byte* data);
471 const char* TwoByteMnemonic(byte opcode);
472 int TwoByteOpcodeInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000473 int F6F7Instruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000474 int ShiftInstruction(byte* data);
475 int JumpShort(byte* data);
476 int JumpConditional(byte* data);
477 int JumpConditionalShort(byte* data);
478 int SetCC(byte* data);
479 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000480 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
481 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400482 int AVXInstruction(byte* data);
Ben Murdochc5610432016-08-08 18:44:38 +0100483 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
Steve Blocka7e24c12009-10-30 11:49:00 +0000484
485 void UnimplementedInstruction() {
486 if (abort_on_unimplemented_) {
487 CHECK(false);
488 } else {
489 AppendToBuffer("'Unimplemented Instruction'");
490 }
491 }
492};
493
494
495void DisassemblerX64::AppendToBuffer(const char* format, ...) {
496 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
497 va_list args;
498 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000499 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000500 va_end(args);
501 tmp_buffer_pos_ += result;
502}
503
504
505int DisassemblerX64::PrintRightOperandHelper(
506 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100507 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000508 int mod, regop, rm;
509 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100510 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
511 &DisassemblerX64::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 switch (mod) {
513 case 0:
514 if ((rm & 7) == 5) {
515 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000516 AppendToBuffer("[rip+0x%x]", disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000517 return 5;
518 } else if ((rm & 7) == 4) {
519 // Codes for SIB byte.
520 byte sib = *(modrmp + 1);
521 int scale, index, base;
522 get_sib(sib, &scale, &index, &base);
523 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
524 // index == rsp means no index. Only use sib byte with no index for
525 // rsp and r12 base.
Steve Block8defd9f2010-07-08 12:39:36 +0100526 AppendToBuffer("[%s]", NameOfCPURegister(base));
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 return 2;
528 } else if (base == 5) {
529 // base == rbp means no base register (when mod == 0).
530 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 AppendToBuffer("[%s*%d%s0x%x]",
Steve Block8defd9f2010-07-08 12:39:36 +0100532 NameOfCPURegister(index),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 1 << scale,
534 disp < 0 ? "-" : "+",
535 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000536 return 6;
537 } else if (index != 4 && base != 5) {
538 // [base+index*scale]
539 AppendToBuffer("[%s+%s*%d]",
Steve Block8defd9f2010-07-08 12:39:36 +0100540 NameOfCPURegister(base),
541 NameOfCPURegister(index),
Steve Blocka7e24c12009-10-30 11:49:00 +0000542 1 << scale);
543 return 2;
544 } else {
545 UnimplementedInstruction();
546 return 1;
547 }
548 } else {
Steve Block8defd9f2010-07-08 12:39:36 +0100549 AppendToBuffer("[%s]", NameOfCPURegister(rm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000550 return 1;
551 }
552 break;
553 case 1: // fall through
554 case 2:
555 if ((rm & 7) == 4) {
556 byte sib = *(modrmp + 1);
557 int scale, index, base;
558 get_sib(sib, &scale, &index, &base);
559 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000561 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000562 AppendToBuffer("[%s%s0x%x]",
563 NameOfCPURegister(base),
564 disp < 0 ? "-" : "+",
565 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567 AppendToBuffer("[%s+%s*%d%s0x%x]",
568 NameOfCPURegister(base),
569 NameOfCPURegister(index),
570 1 << scale,
571 disp < 0 ? "-" : "+",
572 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 }
574 return mod == 2 ? 6 : 3;
575 } else {
576 // No sib.
577 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 : *reinterpret_cast<int8_t*>(modrmp + 1);
579 AppendToBuffer("[%s%s0x%x]",
580 NameOfCPURegister(rm),
581 disp < 0 ? "-" : "+",
582 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 return (mod == 2) ? 5 : 2;
584 }
585 break;
586 case 3:
587 AppendToBuffer("%s", (this->*register_name)(rm));
588 return 1;
589 default:
590 UnimplementedInstruction();
591 return 1;
592 }
593 UNREACHABLE();
594}
595
596
597int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
598 int64_t value;
599 int count;
600 switch (size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 case OPERAND_BYTE_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 value = *data;
603 count = 1;
604 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000605 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 value = *reinterpret_cast<int16_t*>(data);
607 count = 2;
608 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000610 value = *reinterpret_cast<uint32_t*>(data);
611 count = 4;
612 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000614 value = *reinterpret_cast<int32_t*>(data);
615 count = 4;
616 break;
617 default:
618 UNREACHABLE();
619 value = 0; // Initialize variables on all paths to satisfy the compiler.
620 count = 0;
621 }
Ben Murdochc5610432016-08-08 18:44:38 +0100622 AppendToBuffer("%" PRIx64, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000623 return count;
624}
625
626
627int DisassemblerX64::PrintRightOperand(byte* modrmp) {
628 return PrintRightOperandHelper(modrmp,
629 &DisassemblerX64::NameOfCPURegister);
630}
631
632
633int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
634 return PrintRightOperandHelper(modrmp,
635 &DisassemblerX64::NameOfByteCPURegister);
636}
637
638
Steve Blockd0582a62009-12-15 09:54:21 +0000639int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
640 return PrintRightOperandHelper(modrmp,
641 &DisassemblerX64::NameOfXMMRegister);
642}
643
644
Steve Blocka7e24c12009-10-30 11:49:00 +0000645// Returns number of bytes used including the current *data.
646// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
647int DisassemblerX64::PrintOperands(const char* mnem,
648 OperandType op_order,
649 byte* data) {
650 byte modrm = *data;
651 int mod, regop, rm;
652 get_modrm(modrm, &mod, &regop, &rm);
653 int advance = 0;
654 const char* register_name =
655 byte_size_operand_ ? NameOfByteCPURegister(regop)
656 : NameOfCPURegister(regop);
657 switch (op_order) {
658 case REG_OPER_OP_ORDER: {
659 AppendToBuffer("%s%c %s,",
660 mnem,
661 operand_size_code(),
662 register_name);
663 advance = byte_size_operand_ ? PrintRightByteOperand(data)
664 : PrintRightOperand(data);
665 break;
666 }
667 case OPER_REG_OP_ORDER: {
668 AppendToBuffer("%s%c ", mnem, operand_size_code());
669 advance = byte_size_operand_ ? PrintRightByteOperand(data)
670 : PrintRightOperand(data);
671 AppendToBuffer(",%s", register_name);
672 break;
673 }
674 default:
675 UNREACHABLE();
676 break;
677 }
678 return advance;
679}
680
681
682// Returns number of bytes used by machine instruction, including *data byte.
683// Writes immediate instructions to 'tmp_buffer_'.
684int DisassemblerX64::PrintImmediateOp(byte* data) {
685 bool byte_size_immediate = (*data & 0x02) != 0;
686 byte modrm = *(data + 1);
687 int mod, regop, rm;
688 get_modrm(modrm, &mod, &regop, &rm);
689 const char* mnem = "Imm???";
690 switch (regop) {
691 case 0:
692 mnem = "add";
693 break;
694 case 1:
695 mnem = "or";
696 break;
697 case 2:
698 mnem = "adc";
699 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100700 case 3:
701 mnem = "sbb";
702 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000703 case 4:
704 mnem = "and";
705 break;
706 case 5:
707 mnem = "sub";
708 break;
709 case 6:
710 mnem = "xor";
711 break;
712 case 7:
713 mnem = "cmp";
714 break;
715 default:
716 UnimplementedInstruction();
717 }
718 AppendToBuffer("%s%c ", mnem, operand_size_code());
719 int count = PrintRightOperand(data + 1);
720 AppendToBuffer(",0x");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 OperandSize immediate_size =
722 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 count += PrintImmediate(data + 1 + count, immediate_size);
724 return 1 + count;
725}
726
727
728// Returns number of bytes used, including *data.
Steve Blockd0582a62009-12-15 09:54:21 +0000729int DisassemblerX64::F6F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 DCHECK(*data == 0xF7 || *data == 0xF6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000731 byte modrm = *(data + 1);
732 int mod, regop, rm;
733 get_modrm(modrm, &mod, &regop, &rm);
734 if (mod == 3 && regop != 0) {
735 const char* mnem = NULL;
736 switch (regop) {
737 case 2:
738 mnem = "not";
739 break;
740 case 3:
741 mnem = "neg";
742 break;
743 case 4:
744 mnem = "mul";
745 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746 case 5:
747 mnem = "imul";
748 break;
749 case 6:
750 mnem = "div";
751 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 case 7:
753 mnem = "idiv";
754 break;
755 default:
756 UnimplementedInstruction();
757 }
758 AppendToBuffer("%s%c %s",
759 mnem,
760 operand_size_code(),
761 NameOfCPURegister(rm));
762 return 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 } else if (regop == 0) {
764 AppendToBuffer("test%c ", operand_size_code());
Steve Blockd0582a62009-12-15 09:54:21 +0000765 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
766 AppendToBuffer(",0x");
767 count += PrintImmediate(data + 1 + count, operand_size());
768 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 } else {
770 UnimplementedInstruction();
771 return 2;
772 }
773}
774
775
776int DisassemblerX64::ShiftInstruction(byte* data) {
777 byte op = *data & (~1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400778 int count = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
780 UnimplementedInstruction();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400781 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000782 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400783 // Print mneumonic.
784 {
785 byte modrm = *(data + count);
786 int mod, regop, rm;
787 get_modrm(modrm, &mod, &regop, &rm);
788 regop &= 0x7; // The REX.R bit does not affect the operation.
789 const char* mnem = NULL;
790 switch (regop) {
791 case 0:
792 mnem = "rol";
793 break;
794 case 1:
795 mnem = "ror";
796 break;
797 case 2:
798 mnem = "rcl";
799 break;
800 case 3:
801 mnem = "rcr";
802 break;
803 case 4:
804 mnem = "shl";
805 break;
806 case 5:
807 mnem = "shr";
808 break;
809 case 7:
810 mnem = "sar";
811 break;
812 default:
813 UnimplementedInstruction();
814 return count + 1;
815 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816 DCHECK_NOT_NULL(mnem);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400817 AppendToBuffer("%s%c ", mnem, operand_size_code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000818 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400819 count += PrintRightOperand(data + count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 if (op == 0xD2) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400821 AppendToBuffer(", cl");
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400823 int imm8 = -1;
824 if (op == 0xD0) {
825 imm8 = 1;
826 } else {
827 DCHECK_EQ(0xC0, op);
828 imm8 = *(data + count);
829 count++;
830 }
831 AppendToBuffer(", %d", imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000832 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400833 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000834}
835
836
837// Returns number of bytes used, including *data.
838int DisassemblerX64::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 byte b = *(data + 1);
841 byte* dest = data + static_cast<int8_t>(b) + 2;
842 AppendToBuffer("jmp %s", NameOfAddress(dest));
843 return 2;
844}
845
846
847// Returns number of bytes used, including *data.
848int DisassemblerX64::JumpConditional(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 byte cond = *(data + 1) & 0x0F;
851 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
852 const char* mnem = conditional_code_suffix[cond];
853 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
854 return 6; // includes 0x0F
855}
856
857
858// Returns number of bytes used, including *data.
859int DisassemblerX64::JumpConditionalShort(byte* data) {
860 byte cond = *data & 0x0F;
861 byte b = *(data + 1);
862 byte* dest = data + static_cast<int8_t>(b) + 2;
863 const char* mnem = conditional_code_suffix[cond];
864 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
865 return 2;
866}
867
868
869// Returns number of bytes used, including *data.
870int DisassemblerX64::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000871 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000872 byte cond = *(data + 1) & 0x0F;
873 const char* mnem = conditional_code_suffix[cond];
874 AppendToBuffer("set%s%c ", mnem, operand_size_code());
875 PrintRightByteOperand(data + 2);
876 return 3; // includes 0x0F
877}
878
879
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400880int DisassemblerX64::AVXInstruction(byte* data) {
881 byte opcode = *data;
882 byte* current = data + 1;
883 if (vex_66() && vex_0f38()) {
884 int mod, regop, rm, vvvv = vex_vreg();
885 get_modrm(*current, &mod, &regop, &rm);
886 switch (opcode) {
887 case 0x99:
888 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
889 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
890 current += PrintRightXMMOperand(current);
891 break;
892 case 0xa9:
893 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
894 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
895 current += PrintRightXMMOperand(current);
896 break;
897 case 0xb9:
898 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
899 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
900 current += PrintRightXMMOperand(current);
901 break;
902 case 0x9b:
903 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
904 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
905 current += PrintRightXMMOperand(current);
906 break;
907 case 0xab:
908 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
909 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
910 current += PrintRightXMMOperand(current);
911 break;
912 case 0xbb:
913 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
914 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
915 current += PrintRightXMMOperand(current);
916 break;
917 case 0x9d:
918 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
919 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
920 current += PrintRightXMMOperand(current);
921 break;
922 case 0xad:
923 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
924 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
925 current += PrintRightXMMOperand(current);
926 break;
927 case 0xbd:
928 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
929 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
930 current += PrintRightXMMOperand(current);
931 break;
932 case 0x9f:
933 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
934 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
935 current += PrintRightXMMOperand(current);
936 break;
937 case 0xaf:
938 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
939 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
940 current += PrintRightXMMOperand(current);
941 break;
942 case 0xbf:
943 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
944 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
945 current += PrintRightXMMOperand(current);
946 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 case 0xf7:
948 AppendToBuffer("shlx%c %s,", operand_size_code(),
949 NameOfCPURegister(regop));
950 current += PrintRightOperand(current);
951 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
952 break;
953 default:
954 UnimplementedInstruction();
955 }
956 } else if (vex_66() && vex_0f3a()) {
957 int mod, regop, rm, vvvv = vex_vreg();
958 get_modrm(*current, &mod, &regop, &rm);
959 switch (opcode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100960 case 0x0a:
961 AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
962 NameOfXMMRegister(vvvv));
963 current += PrintRightXMMOperand(current);
964 AppendToBuffer(",0x%x", *current++);
965 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000966 case 0x0b:
967 AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
968 NameOfXMMRegister(vvvv));
969 current += PrintRightXMMOperand(current);
970 AppendToBuffer(",0x%x", *current++);
971 break;
972 default:
973 UnimplementedInstruction();
974 }
975 } else if (vex_f3() && vex_0f()) {
976 int mod, regop, rm, vvvv = vex_vreg();
977 get_modrm(*current, &mod, &regop, &rm);
978 switch (opcode) {
979 case 0x10:
980 AppendToBuffer("vmovss %s,", NameOfXMMRegister(regop));
981 if (mod == 3) {
982 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
983 }
984 current += PrintRightXMMOperand(current);
985 break;
986 case 0x11:
987 AppendToBuffer("vmovss ");
988 current += PrintRightXMMOperand(current);
989 if (mod == 3) {
990 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
991 }
992 AppendToBuffer(",%s", NameOfXMMRegister(regop));
993 break;
994 case 0x2a:
995 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2ss" : "vcvtlsi2ss",
996 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
997 current += PrintRightOperand(current);
998 break;
999 case 0x2c:
1000 AppendToBuffer("vcvttss2si%s %s,", vex_w() ? "q" : "",
1001 NameOfCPURegister(regop));
1002 current += PrintRightXMMOperand(current);
1003 break;
1004 case 0x58:
1005 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
1006 NameOfXMMRegister(vvvv));
1007 current += PrintRightXMMOperand(current);
1008 break;
1009 case 0x59:
1010 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
1011 NameOfXMMRegister(vvvv));
1012 current += PrintRightXMMOperand(current);
1013 break;
1014 case 0x5a:
1015 AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
1016 NameOfXMMRegister(vvvv));
1017 current += PrintRightXMMOperand(current);
1018 break;
1019 case 0x5c:
1020 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
1021 NameOfXMMRegister(vvvv));
1022 current += PrintRightXMMOperand(current);
1023 break;
1024 case 0x5d:
1025 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
1026 NameOfXMMRegister(vvvv));
1027 current += PrintRightXMMOperand(current);
1028 break;
1029 case 0x5e:
1030 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
1031 NameOfXMMRegister(vvvv));
1032 current += PrintRightXMMOperand(current);
1033 break;
1034 case 0x5f:
1035 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
1036 NameOfXMMRegister(vvvv));
1037 current += PrintRightXMMOperand(current);
1038 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001039 default:
1040 UnimplementedInstruction();
1041 }
1042 } else if (vex_f2() && vex_0f()) {
1043 int mod, regop, rm, vvvv = vex_vreg();
1044 get_modrm(*current, &mod, &regop, &rm);
1045 switch (opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001046 case 0x10:
1047 AppendToBuffer("vmovsd %s,", NameOfXMMRegister(regop));
1048 if (mod == 3) {
1049 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1050 }
1051 current += PrintRightXMMOperand(current);
1052 break;
1053 case 0x11:
1054 AppendToBuffer("vmovsd ");
1055 current += PrintRightXMMOperand(current);
1056 if (mod == 3) {
1057 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1058 }
1059 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1060 break;
1061 case 0x2a:
1062 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd",
1063 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1064 current += PrintRightOperand(current);
1065 break;
1066 case 0x2c:
1067 AppendToBuffer("vcvttsd2si%s %s,", vex_w() ? "q" : "",
1068 NameOfCPURegister(regop));
1069 current += PrintRightXMMOperand(current);
1070 break;
1071 case 0x2d:
1072 AppendToBuffer("vcvtsd2si%s %s,", vex_w() ? "q" : "",
1073 NameOfCPURegister(regop));
1074 current += PrintRightXMMOperand(current);
1075 break;
1076 case 0x51:
1077 AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
1078 NameOfXMMRegister(vvvv));
1079 current += PrintRightXMMOperand(current);
1080 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001081 case 0x58:
1082 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
1083 NameOfXMMRegister(vvvv));
1084 current += PrintRightXMMOperand(current);
1085 break;
1086 case 0x59:
1087 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
1088 NameOfXMMRegister(vvvv));
1089 current += PrintRightXMMOperand(current);
1090 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001091 case 0x5a:
1092 AppendToBuffer("vcvtsd2ss %s,%s,", NameOfXMMRegister(regop),
1093 NameOfXMMRegister(vvvv));
1094 current += PrintRightXMMOperand(current);
1095 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001096 case 0x5c:
1097 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
1098 NameOfXMMRegister(vvvv));
1099 current += PrintRightXMMOperand(current);
1100 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001101 case 0x5d:
1102 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
1103 NameOfXMMRegister(vvvv));
1104 current += PrintRightXMMOperand(current);
1105 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001106 case 0x5e:
1107 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
1108 NameOfXMMRegister(vvvv));
1109 current += PrintRightXMMOperand(current);
1110 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001111 case 0x5f:
1112 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
1113 NameOfXMMRegister(vvvv));
1114 current += PrintRightXMMOperand(current);
1115 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001116 default:
1117 UnimplementedInstruction();
1118 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001119 } else if (vex_none() && vex_0f38()) {
1120 int mod, regop, rm, vvvv = vex_vreg();
1121 get_modrm(*current, &mod, &regop, &rm);
1122 const char* mnem = "?";
1123 switch (opcode) {
1124 case 0xf2:
1125 AppendToBuffer("andn%c %s,%s,", operand_size_code(),
1126 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1127 current += PrintRightOperand(current);
1128 break;
1129 case 0xf5:
1130 AppendToBuffer("bzhi%c %s,", operand_size_code(),
1131 NameOfCPURegister(regop));
1132 current += PrintRightOperand(current);
1133 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1134 break;
1135 case 0xf7:
1136 AppendToBuffer("bextr%c %s,", operand_size_code(),
1137 NameOfCPURegister(regop));
1138 current += PrintRightOperand(current);
1139 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1140 break;
1141 case 0xf3:
1142 switch (regop) {
1143 case 1:
1144 mnem = "blsr";
1145 break;
1146 case 2:
1147 mnem = "blsmsk";
1148 break;
1149 case 3:
1150 mnem = "blsi";
1151 break;
1152 default:
1153 UnimplementedInstruction();
1154 }
1155 AppendToBuffer("%s%c %s,", mnem, operand_size_code(),
1156 NameOfCPURegister(vvvv));
1157 current += PrintRightOperand(current);
1158 mnem = "?";
1159 break;
1160 default:
1161 UnimplementedInstruction();
1162 }
1163 } else if (vex_f2() && vex_0f38()) {
1164 int mod, regop, rm, vvvv = vex_vreg();
1165 get_modrm(*current, &mod, &regop, &rm);
1166 switch (opcode) {
1167 case 0xf5:
1168 AppendToBuffer("pdep%c %s,%s,", operand_size_code(),
1169 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1170 current += PrintRightOperand(current);
1171 break;
1172 case 0xf6:
1173 AppendToBuffer("mulx%c %s,%s,", operand_size_code(),
1174 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1175 current += PrintRightOperand(current);
1176 break;
1177 case 0xf7:
1178 AppendToBuffer("shrx%c %s,", operand_size_code(),
1179 NameOfCPURegister(regop));
1180 current += PrintRightOperand(current);
1181 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1182 break;
1183 default:
1184 UnimplementedInstruction();
1185 }
1186 } else if (vex_f3() && vex_0f38()) {
1187 int mod, regop, rm, vvvv = vex_vreg();
1188 get_modrm(*current, &mod, &regop, &rm);
1189 switch (opcode) {
1190 case 0xf5:
1191 AppendToBuffer("pext%c %s,%s,", operand_size_code(),
1192 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1193 current += PrintRightOperand(current);
1194 break;
1195 case 0xf7:
1196 AppendToBuffer("sarx%c %s,", operand_size_code(),
1197 NameOfCPURegister(regop));
1198 current += PrintRightOperand(current);
1199 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1200 break;
1201 default:
1202 UnimplementedInstruction();
1203 }
1204 } else if (vex_f2() && vex_0f3a()) {
1205 int mod, regop, rm;
1206 get_modrm(*current, &mod, &regop, &rm);
1207 switch (opcode) {
1208 case 0xf0:
1209 AppendToBuffer("rorx%c %s,", operand_size_code(),
1210 NameOfCPURegister(regop));
1211 current += PrintRightOperand(current);
1212 switch (operand_size()) {
1213 case OPERAND_DOUBLEWORD_SIZE:
1214 AppendToBuffer(",%d", *current & 0x1f);
1215 break;
1216 case OPERAND_QUADWORD_SIZE:
1217 AppendToBuffer(",%d", *current & 0x3f);
1218 break;
1219 default:
1220 UnimplementedInstruction();
1221 }
1222 current += 1;
1223 break;
1224 default:
1225 UnimplementedInstruction();
1226 }
1227 } else if (vex_none() && vex_0f()) {
1228 int mod, regop, rm, vvvv = vex_vreg();
1229 get_modrm(*current, &mod, &regop, &rm);
1230 switch (opcode) {
1231 case 0x28:
1232 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1233 current += PrintRightXMMOperand(current);
1234 break;
1235 case 0x29:
1236 AppendToBuffer("vmovaps ");
1237 current += PrintRightXMMOperand(current);
1238 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1239 break;
1240 case 0x2e:
1241 AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1242 current += PrintRightXMMOperand(current);
1243 break;
1244 case 0x54:
1245 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1246 NameOfXMMRegister(vvvv));
1247 current += PrintRightXMMOperand(current);
1248 break;
1249 case 0x57:
1250 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1251 NameOfXMMRegister(vvvv));
1252 current += PrintRightXMMOperand(current);
1253 break;
1254 default:
1255 UnimplementedInstruction();
1256 }
1257 } else if (vex_66() && vex_0f()) {
1258 int mod, regop, rm, vvvv = vex_vreg();
1259 get_modrm(*current, &mod, &regop, &rm);
1260 switch (opcode) {
1261 case 0x28:
1262 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1263 current += PrintRightXMMOperand(current);
1264 break;
1265 case 0x29:
1266 AppendToBuffer("vmovapd ");
1267 current += PrintRightXMMOperand(current);
1268 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1269 break;
1270 case 0x2e:
1271 AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1272 current += PrintRightXMMOperand(current);
1273 break;
1274 case 0x50:
1275 AppendToBuffer("vmovmskpd %s,", NameOfCPURegister(regop));
1276 current += PrintRightXMMOperand(current);
1277 break;
1278 case 0x54:
1279 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1280 NameOfXMMRegister(vvvv));
1281 current += PrintRightXMMOperand(current);
1282 break;
1283 case 0x56:
1284 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1285 NameOfXMMRegister(vvvv));
1286 current += PrintRightXMMOperand(current);
1287 break;
1288 case 0x57:
1289 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1290 NameOfXMMRegister(vvvv));
1291 current += PrintRightXMMOperand(current);
1292 break;
1293 case 0x6e:
1294 AppendToBuffer("vmov%c %s,", vex_w() ? 'q' : 'd',
1295 NameOfXMMRegister(regop));
1296 current += PrintRightOperand(current);
1297 break;
1298 case 0x73:
1299 AppendToBuffer("%s %s,", regop == 6 ? "vpsllq" : "vpsrlq",
1300 NameOfXMMRegister(vvvv));
1301 current += PrintRightXMMOperand(current);
1302 AppendToBuffer(",%u", *current++);
1303 break;
1304 case 0x76:
1305 AppendToBuffer("vpcmpeqd %s,%s,", NameOfXMMRegister(regop),
1306 NameOfXMMRegister(vvvv));
1307 current += PrintRightXMMOperand(current);
1308 break;
1309 case 0x7e:
1310 AppendToBuffer("vmov%c ", vex_w() ? 'q' : 'd');
1311 current += PrintRightOperand(current);
1312 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1313 break;
1314 default:
1315 UnimplementedInstruction();
1316 }
1317
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001318 } else {
1319 UnimplementedInstruction();
1320 }
1321
1322 return static_cast<int>(current - data);
1323}
1324
1325
Steve Blocka7e24c12009-10-30 11:49:00 +00001326// Returns number of bytes used, including *data.
1327int DisassemblerX64::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001328 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001329 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001330 byte modrm_byte = *(data+1);
1331
1332 if (modrm_byte >= 0xC0) {
1333 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1334 } else {
1335 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 }
Steve Blockd0582a62009-12-15 09:54:21 +00001337}
1338
1339int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
1340 int modrm_byte,
1341 byte* modrm_start) {
1342 const char* mnem = "?";
1343 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1344 switch (escape_opcode) {
1345 case 0xD9: switch (regop) {
1346 case 0: mnem = "fld_s"; break;
1347 case 3: mnem = "fstp_s"; break;
1348 case 7: mnem = "fstcw"; break;
1349 default: UnimplementedInstruction();
1350 }
1351 break;
1352
1353 case 0xDB: switch (regop) {
1354 case 0: mnem = "fild_s"; break;
1355 case 1: mnem = "fisttp_s"; break;
1356 case 2: mnem = "fist_s"; break;
1357 case 3: mnem = "fistp_s"; break;
1358 default: UnimplementedInstruction();
1359 }
1360 break;
1361
1362 case 0xDD: switch (regop) {
1363 case 0: mnem = "fld_d"; break;
1364 case 3: mnem = "fstp_d"; break;
1365 default: UnimplementedInstruction();
1366 }
1367 break;
1368
1369 case 0xDF: switch (regop) {
1370 case 5: mnem = "fild_d"; break;
1371 case 7: mnem = "fistp_d"; break;
1372 default: UnimplementedInstruction();
1373 }
1374 break;
1375
1376 default: UnimplementedInstruction();
1377 }
1378 AppendToBuffer("%s ", mnem);
1379 int count = PrintRightOperand(modrm_start);
1380 return count + 1;
1381}
1382
1383int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1384 byte modrm_byte) {
1385 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1386 const char* mnem = "?";
1387
1388 switch (escape_opcode) {
1389 case 0xD8:
1390 UnimplementedInstruction();
1391 break;
1392
1393 case 0xD9:
1394 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001395 case 0xC0:
1396 mnem = "fld";
1397 has_register = true;
1398 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001399 case 0xC8:
1400 mnem = "fxch";
1401 has_register = true;
1402 break;
1403 default:
1404 switch (modrm_byte) {
1405 case 0xE0: mnem = "fchs"; break;
1406 case 0xE1: mnem = "fabs"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001407 case 0xE3: mnem = "fninit"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001408 case 0xE4: mnem = "ftst"; break;
1409 case 0xE8: mnem = "fld1"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001410 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001411 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001412 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001413 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001414 case 0xF1: mnem = "fyl2x"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001415 case 0xF2: mnem = "fptan"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001416 case 0xF5: mnem = "fprem1"; break;
1417 case 0xF7: mnem = "fincstp"; break;
1418 case 0xF8: mnem = "fprem"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 case 0xFC: mnem = "frndint"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001420 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001421 case 0xFE: mnem = "fsin"; break;
1422 case 0xFF: mnem = "fcos"; break;
1423 default: UnimplementedInstruction();
1424 }
1425 }
1426 break;
1427
1428 case 0xDA:
1429 if (modrm_byte == 0xE9) {
1430 mnem = "fucompp";
1431 } else {
1432 UnimplementedInstruction();
1433 }
1434 break;
1435
1436 case 0xDB:
1437 if ((modrm_byte & 0xF8) == 0xE8) {
1438 mnem = "fucomi";
1439 has_register = true;
1440 } else if (modrm_byte == 0xE2) {
1441 mnem = "fclex";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 } else if (modrm_byte == 0xE3) {
1443 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001444 } else {
1445 UnimplementedInstruction();
1446 }
1447 break;
1448
1449 case 0xDC:
1450 has_register = true;
1451 switch (modrm_byte & 0xF8) {
1452 case 0xC0: mnem = "fadd"; break;
1453 case 0xE8: mnem = "fsub"; break;
1454 case 0xC8: mnem = "fmul"; break;
1455 case 0xF8: mnem = "fdiv"; break;
1456 default: UnimplementedInstruction();
1457 }
1458 break;
1459
1460 case 0xDD:
1461 has_register = true;
1462 switch (modrm_byte & 0xF8) {
1463 case 0xC0: mnem = "ffree"; break;
1464 case 0xD8: mnem = "fstp"; break;
1465 default: UnimplementedInstruction();
1466 }
1467 break;
1468
1469 case 0xDE:
1470 if (modrm_byte == 0xD9) {
1471 mnem = "fcompp";
1472 } else {
1473 has_register = true;
1474 switch (modrm_byte & 0xF8) {
1475 case 0xC0: mnem = "faddp"; break;
1476 case 0xE8: mnem = "fsubp"; break;
1477 case 0xC8: mnem = "fmulp"; break;
1478 case 0xF8: mnem = "fdivp"; break;
1479 default: UnimplementedInstruction();
1480 }
1481 }
1482 break;
1483
1484 case 0xDF:
1485 if (modrm_byte == 0xE0) {
1486 mnem = "fnstsw_ax";
1487 } else if ((modrm_byte & 0xF8) == 0xE8) {
1488 mnem = "fucomip";
1489 has_register = true;
1490 }
1491 break;
1492
1493 default: UnimplementedInstruction();
1494 }
1495
1496 if (has_register) {
1497 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1498 } else {
1499 AppendToBuffer("%s", mnem);
1500 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 return 2;
1502}
1503
1504
Steve Blockd0582a62009-12-15 09:54:21 +00001505
Steve Blocka7e24c12009-10-30 11:49:00 +00001506// Handle all two-byte opcodes, which start with 0x0F.
1507// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1508// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1509int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1510 byte opcode = *(data + 1);
1511 byte* current = data + 2;
1512 // At return, "current" points to the start of the next instruction.
1513 const char* mnemonic = TwoByteMnemonic(opcode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001514 if (operand_size_ == 0x66) {
1515 // 0x66 0x0F prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001516 int mod, regop, rm;
Steve Block6ded16b2010-05-10 14:33:55 +01001517 if (opcode == 0x3A) {
1518 byte third_byte = *current;
1519 current = data + 3;
1520 if (third_byte == 0x17) {
1521 get_modrm(*current, &mod, &regop, &rm);
1522 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1523 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001524 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
Steve Block6ded16b2010-05-10 14:33:55 +01001525 current += 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001526 } else if (third_byte == 0x0a) {
1527 get_modrm(*current, &mod, &regop, &rm);
1528 AppendToBuffer("roundss %s,", NameOfXMMRegister(regop));
1529 current += PrintRightXMMOperand(current);
1530 AppendToBuffer(",0x%x", (*current) & 3);
1531 current += 1;
Ben Murdoch257744e2011-11-30 15:57:28 +00001532 } else if (third_byte == 0x0b) {
1533 get_modrm(*current, &mod, &regop, &rm);
1534 // roundsd xmm, xmm/m64, imm8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001535 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1536 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001537 AppendToBuffer(",0x%x", (*current) & 3);
1538 current += 1;
1539 } else if (third_byte == 0x16) {
1540 get_modrm(*current, &mod, &rm, &regop);
1541 AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
1542 current += PrintRightOperand(current);
1543 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1544 current += 1;
1545 } else if (third_byte == 0x22) {
1546 get_modrm(*current, &mod, &regop, &rm);
1547 AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
1548 AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1549 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001550 AppendToBuffer(",%d", (*current) & 3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001551 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001552 } else {
1553 UnimplementedInstruction();
1554 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001556 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001557 if (opcode == 0x1f) {
1558 current++;
1559 if (rm == 4) { // SIB byte present.
1560 current++;
1561 }
1562 if (mod == 1) { // Byte displacement.
1563 current += 1;
1564 } else if (mod == 2) { // 32-bit displacement.
1565 current += 4;
1566 } // else no immediate displacement.
1567 AppendToBuffer("nop");
1568 } else if (opcode == 0x28) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001569 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001570 current += PrintRightXMMOperand(current);
1571 } else if (opcode == 0x29) {
1572 AppendToBuffer("movapd ");
1573 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001574 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001575 } else if (opcode == 0x6E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001576 AppendToBuffer("mov%c %s,",
1577 rex_w() ? 'q' : 'd',
1578 NameOfXMMRegister(regop));
1579 current += PrintRightOperand(current);
Steve Block1e0659c2011-05-24 12:43:12 +01001580 } else if (opcode == 0x6F) {
1581 AppendToBuffer("movdqa %s,",
1582 NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001583 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001584 } else if (opcode == 0x7E) {
Ben Murdochbb769b22010-08-11 14:56:33 +01001585 AppendToBuffer("mov%c ",
1586 rex_w() ? 'q' : 'd');
1587 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block1e0659c2011-05-24 12:43:12 +01001589 } else if (opcode == 0x7F) {
1590 AppendToBuffer("movdqa ");
Steve Block44f0eee2011-05-26 01:26:41 +01001591 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001592 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001593 } else if (opcode == 0xD6) {
1594 AppendToBuffer("movq ");
1595 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001596 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001597 } else if (opcode == 0x50) {
1598 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1599 current += PrintRightXMMOperand(current);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001600 } else if (opcode == 0x72) {
1601 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001602 AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001603 NameOfXMMRegister(rm), *current & 0x7f);
1604 current += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001605 } else if (opcode == 0x73) {
1606 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001607 AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001608 NameOfXMMRegister(rm), *current & 0x7f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001609 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001610 } else {
1611 const char* mnemonic = "?";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001612 if (opcode == 0x54) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001613 mnemonic = "andpd";
1614 } else if (opcode == 0x56) {
1615 mnemonic = "orpd";
1616 } else if (opcode == 0x57) {
Steve Block6ded16b2010-05-10 14:33:55 +01001617 mnemonic = "xorpd";
1618 } else if (opcode == 0x2E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001619 mnemonic = "ucomisd";
Steve Block8defd9f2010-07-08 12:39:36 +01001620 } else if (opcode == 0x2F) {
1621 mnemonic = "comisd";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001622 } else if (opcode == 0x76) {
1623 mnemonic = "pcmpeqd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001624 } else if (opcode == 0x62) {
1625 mnemonic = "punpckldq";
1626 } else if (opcode == 0x6A) {
1627 mnemonic = "punpckhdq";
Steve Block6ded16b2010-05-10 14:33:55 +01001628 } else {
1629 UnimplementedInstruction();
1630 }
1631 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1632 current += PrintRightXMMOperand(current);
1633 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001634 }
1635 } else if (group_1_prefix_ == 0xF2) {
1636 // Beginning of instructions with prefix 0xF2.
1637
1638 if (opcode == 0x11 || opcode == 0x10) {
1639 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1640 AppendToBuffer("movsd ");
1641 int mod, regop, rm;
1642 get_modrm(*current, &mod, &regop, &rm);
1643 if (opcode == 0x11) {
Steve Block44f0eee2011-05-26 01:26:41 +01001644 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001645 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1646 } else {
1647 AppendToBuffer("%s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001648 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001649 }
1650 } else if (opcode == 0x2A) {
1651 // CVTSI2SD: integer to XMM double conversion.
1652 int mod, regop, rm;
1653 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001654 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Blockd0582a62009-12-15 09:54:21 +00001655 current += PrintRightOperand(current);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001656 } else if (opcode == 0x2C) {
1657 // CVTTSD2SI:
1658 // Convert with truncation scalar double-precision FP to integer.
1659 int mod, regop, rm;
1660 get_modrm(*current, &mod, &regop, &rm);
1661 AppendToBuffer("cvttsd2si%c %s,",
1662 operand_size_code(), NameOfCPURegister(regop));
1663 current += PrintRightXMMOperand(current);
1664 } else if (opcode == 0x2D) {
1665 // CVTSD2SI: Convert scalar double-precision FP to integer.
1666 int mod, regop, rm;
1667 get_modrm(*current, &mod, &regop, &rm);
1668 AppendToBuffer("cvtsd2si%c %s,",
1669 operand_size_code(), NameOfCPURegister(regop));
1670 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001671 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001672 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1673 int mod, regop, rm;
1674 get_modrm(*current, &mod, &regop, &rm);
Steve Blockd0582a62009-12-15 09:54:21 +00001675 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1676 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001677 } else if (opcode == 0xC2) {
1678 // Intel manual 2A, Table 3-18.
1679 int mod, regop, rm;
1680 get_modrm(*current, &mod, &regop, &rm);
1681 const char* const pseudo_op[] = {
1682 "cmpeqsd",
1683 "cmpltsd",
1684 "cmplesd",
1685 "cmpunordsd",
1686 "cmpneqsd",
1687 "cmpnltsd",
1688 "cmpnlesd",
1689 "cmpordsd"
1690 };
1691 AppendToBuffer("%s %s,%s",
1692 pseudo_op[current[1]],
1693 NameOfXMMRegister(regop),
1694 NameOfXMMRegister(rm));
1695 current += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001696 } else {
1697 UnimplementedInstruction();
1698 }
Steve Block6ded16b2010-05-10 14:33:55 +01001699 } else if (group_1_prefix_ == 0xF3) {
1700 // Instructions with prefix 0xF3.
Steve Block8defd9f2010-07-08 12:39:36 +01001701 if (opcode == 0x11 || opcode == 0x10) {
1702 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1703 AppendToBuffer("movss ");
1704 int mod, regop, rm;
1705 get_modrm(*current, &mod, &regop, &rm);
1706 if (opcode == 0x11) {
1707 current += PrintRightOperand(current);
1708 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1709 } else {
1710 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1711 current += PrintRightOperand(current);
1712 }
1713 } else if (opcode == 0x2A) {
1714 // CVTSI2SS: integer to XMM single conversion.
1715 int mod, regop, rm;
1716 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001717 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Block8defd9f2010-07-08 12:39:36 +01001718 current += PrintRightOperand(current);
1719 } else if (opcode == 0x2C) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001720 // CVTTSS2SI:
1721 // Convert with truncation scalar single-precision FP to dword integer.
Steve Block1e0659c2011-05-24 12:43:12 +01001722 int mod, regop, rm;
1723 get_modrm(*current, &mod, &regop, &rm);
1724 AppendToBuffer("cvttss2si%c %s,",
1725 operand_size_code(), NameOfCPURegister(regop));
1726 current += PrintRightXMMOperand(current);
Ben Murdoch257744e2011-11-30 15:57:28 +00001727 } else if (opcode == 0x7E) {
1728 int mod, regop, rm;
1729 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001730 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001731 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001732 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1733 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1734 int mod, regop, rm;
1735 get_modrm(*current, &mod, &regop, &rm);
1736 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1737 current += PrintRightXMMOperand(current);
1738 } else if (opcode == 0xB8) {
1739 int mod, regop, rm;
1740 get_modrm(*current, &mod, &regop, &rm);
1741 AppendToBuffer("popcnt%c %s,", operand_size_code(),
1742 NameOfCPURegister(regop));
1743 current += PrintRightOperand(current);
1744 } else if (opcode == 0xBC) {
1745 int mod, regop, rm;
1746 get_modrm(*current, &mod, &regop, &rm);
1747 AppendToBuffer("tzcnt%c %s,", operand_size_code(),
1748 NameOfCPURegister(regop));
1749 current += PrintRightOperand(current);
1750 } else if (opcode == 0xBD) {
1751 int mod, regop, rm;
1752 get_modrm(*current, &mod, &regop, &rm);
1753 AppendToBuffer("lzcnt%c %s,", operand_size_code(),
1754 NameOfCPURegister(regop));
1755 current += PrintRightOperand(current);
1756 } else if (opcode == 0xC2) {
1757 // Intel manual 2A, Table 3-18.
1758 int mod, regop, rm;
1759 get_modrm(*current, &mod, &regop, &rm);
1760 const char* const pseudo_op[] = {"cmpeqss", "cmpltss", "cmpless",
1761 "cmpunordss", "cmpneqss", "cmpnltss",
1762 "cmpnless", "cmpordss"};
1763 AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
1764 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
1765 current += 2;
Steve Block6ded16b2010-05-10 14:33:55 +01001766 } else {
1767 UnimplementedInstruction();
1768 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001769 } else if (opcode == 0x1F) {
1770 // NOP
1771 int mod, regop, rm;
1772 get_modrm(*current, &mod, &regop, &rm);
1773 current++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001774 if (rm == 4) { // SIB byte present.
Andrei Popescu402d9372010-02-26 13:31:12 +00001775 current++;
1776 }
1777 if (mod == 1) { // Byte displacement.
1778 current += 1;
1779 } else if (mod == 2) { // 32-bit displacement.
1780 current += 4;
1781 } // else no immediate displacement.
1782 AppendToBuffer("nop");
Ben Murdoch257744e2011-11-30 15:57:28 +00001783
1784 } else if (opcode == 0x28) {
1785 // movaps xmm, xmm/m128
1786 int mod, regop, rm;
1787 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001788 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001789 current += PrintRightXMMOperand(current);
1790
1791 } else if (opcode == 0x29) {
1792 // movaps xmm/m128, xmm
1793 int mod, regop, rm;
1794 get_modrm(*current, &mod, &regop, &rm);
1795 AppendToBuffer("movaps ");
1796 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001797 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001798
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001799 } else if (opcode == 0x2e) {
1800 int mod, regop, rm;
1801 get_modrm(*current, &mod, &regop, &rm);
1802 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1803 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001804 } else if (opcode == 0xA2) {
1805 // CPUID
Andrei Popescu402d9372010-02-26 13:31:12 +00001806 AppendToBuffer("%s", mnemonic);
1807
1808 } else if ((opcode & 0xF0) == 0x40) {
1809 // CMOVcc: conditional move.
1810 int condition = opcode & 0x0F;
1811 const InstructionDesc& idesc = cmov_instructions[condition];
1812 byte_size_operand_ = idesc.byte_size_operation;
1813 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1814
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001815 } else if (opcode >= 0x53 && opcode <= 0x5F) {
1816 const char* const pseudo_op[] = {
1817 "rcpps",
1818 "andps",
1819 "andnps",
1820 "orps",
1821 "xorps",
1822 "addps",
1823 "mulps",
1824 "cvtps2pd",
1825 "cvtdq2ps",
1826 "subps",
1827 "minps",
1828 "divps",
1829 "maxps",
1830 };
Ben Murdoch257744e2011-11-30 15:57:28 +00001831 int mod, regop, rm;
1832 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001833 AppendToBuffer("%s %s,",
1834 pseudo_op[opcode - 0x53],
1835 NameOfXMMRegister(regop));
1836 current += PrintRightXMMOperand(current);
1837
1838 } else if (opcode == 0xC6) {
1839 // shufps xmm, xmm/m128, imm8
1840 int mod, regop, rm;
1841 get_modrm(*current, &mod, &regop, &rm);
1842 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1843 current += PrintRightXMMOperand(current);
1844 AppendToBuffer(", %d", (*current) & 3);
1845 current += 1;
1846
1847 } else if (opcode == 0x50) {
1848 // movmskps reg, xmm
1849 int mod, regop, rm;
1850 get_modrm(*current, &mod, &regop, &rm);
1851 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001852 current += PrintRightXMMOperand(current);
1853
Andrei Popescu402d9372010-02-26 13:31:12 +00001854 } else if ((opcode & 0xF0) == 0x80) {
1855 // Jcc: Conditional jump (branch).
1856 current = data + JumpConditional(data);
1857
1858 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1859 opcode == 0xB7 || opcode == 0xAF) {
1860 // Size-extending moves, IMUL.
1861 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1862
1863 } else if ((opcode & 0xF0) == 0x90) {
1864 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1865 current = data + SetCC(data);
1866
1867 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1868 // SHLD, SHRD (double-precision shift), BTS (bit set).
1869 AppendToBuffer("%s ", mnemonic);
1870 int mod, regop, rm;
1871 get_modrm(*current, &mod, &regop, &rm);
1872 current += PrintRightOperand(current);
1873 if (opcode == 0xAB) {
1874 AppendToBuffer(",%s", NameOfCPURegister(regop));
1875 } else {
1876 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1877 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001878 } else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
1879 // POPCNT, CTZ, CLZ.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001880 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1881 int mod, regop, rm;
1882 get_modrm(*current, &mod, &regop, &rm);
1883 AppendToBuffer("%s,", NameOfCPURegister(regop));
1884 current += PrintRightOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001885 } else if (opcode == 0x0B) {
1886 AppendToBuffer("ud2");
Steve Blocka7e24c12009-10-30 11:49:00 +00001887 } else {
1888 UnimplementedInstruction();
1889 }
Steve Blockd0582a62009-12-15 09:54:21 +00001890 return static_cast<int>(current - data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001891}
1892
1893
1894// Mnemonics for two-byte opcode instructions starting with 0x0F.
1895// The argument is the second byte of the two-byte opcode.
1896// Returns NULL if the instruction is not handled here.
1897const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1898 switch (opcode) {
1899 case 0x1F:
1900 return "nop";
Steve Block8defd9f2010-07-08 12:39:36 +01001901 case 0x2A: // F2/F3 prefix.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001902 return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
1903 case 0x51: // F2/F3 prefix.
1904 return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
1905 case 0x58: // F2/F3 prefix.
1906 return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
1907 case 0x59: // F2/F3 prefix.
1908 return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
1909 case 0x5A: // F2/F3 prefix.
1910 return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
1911 case 0x5D: // F2/F3 prefix.
1912 return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
1913 case 0x5C: // F2/F3 prefix.
1914 return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
1915 case 0x5E: // F2/F3 prefix.
1916 return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
1917 case 0x5F: // F2/F3 prefix.
1918 return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
Steve Blocka7e24c12009-10-30 11:49:00 +00001919 case 0xA2:
1920 return "cpuid";
1921 case 0xA5:
1922 return "shld";
1923 case 0xAB:
1924 return "bts";
1925 case 0xAD:
1926 return "shrd";
1927 case 0xAF:
1928 return "imul";
1929 case 0xB6:
1930 return "movzxb";
1931 case 0xB7:
1932 return "movzxw";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001933 case 0xBC:
1934 return "bsf";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935 case 0xBD:
1936 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001937 case 0xBE:
1938 return "movsxb";
1939 case 0xBF:
1940 return "movsxw";
1941 default:
1942 return NULL;
1943 }
1944}
1945
1946
1947// Disassembles the instruction at instr, and writes it into out_buffer.
1948int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1949 byte* instr) {
1950 tmp_buffer_pos_ = 0; // starting to write as position 0
1951 byte* data = instr;
1952 bool processed = true; // Will be set to false if the current instruction
1953 // is not in 'instructions' table.
1954 byte current;
1955
1956 // Scan for prefixes.
1957 while (true) {
1958 current = *data;
Leon Clarked91b9f72010-01-27 17:25:45 +00001959 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001960 operand_size_ = current;
1961 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1962 setRex(current);
1963 if (rex_w()) AppendToBuffer("REX.W ");
Leon Clarked91b9f72010-01-27 17:25:45 +00001964 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
Steve Blocka7e24c12009-10-30 11:49:00 +00001965 group_1_prefix_ = current;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001966 } else if (current == VEX3_PREFIX) {
1967 vex_byte0_ = current;
1968 vex_byte1_ = *(data + 1);
1969 vex_byte2_ = *(data + 2);
1970 setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001971 data += 3;
1972 break; // Vex is the last prefix.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001973 } else if (current == VEX2_PREFIX) {
1974 vex_byte0_ = current;
1975 vex_byte1_ = *(data + 1);
1976 setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001977 data += 2;
1978 break; // Vex is the last prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001979 } else { // Not a prefix - an opcode.
1980 break;
1981 }
1982 data++;
1983 }
1984
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001985 // Decode AVX instructions.
1986 if (vex_byte0_ != 0) {
1987 processed = true;
1988 data += AVXInstruction(data);
1989 } else {
1990 const InstructionDesc& idesc = instruction_table_->Get(current);
1991 byte_size_operand_ = idesc.byte_size_operation;
1992 switch (idesc.type) {
1993 case ZERO_OPERANDS_INSTR:
1994 if (current >= 0xA4 && current <= 0xA7) {
1995 // String move or compare operations.
1996 if (group_1_prefix_ == REP_PREFIX) {
1997 // REP.
1998 AppendToBuffer("rep ");
1999 }
2000 if (rex_w()) AppendToBuffer("REX.W ");
2001 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2002 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01002003 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
Leon Clarked91b9f72010-01-27 17:25:45 +00002004 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002005 data++;
2006 break;
2007
2008 case TWO_OPERANDS_INSTR:
2009 data++;
2010 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
2011 break;
2012
2013 case JUMP_CONDITIONAL_SHORT_INSTR:
2014 data += JumpConditionalShort(data);
2015 break;
2016
2017 case REGISTER_INSTR:
2018 AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
2019 NameOfCPURegister(base_reg(current & 0x07)));
2020 data++;
2021 break;
2022 case PUSHPOP_INSTR:
2023 AppendToBuffer("%s %s", idesc.mnem,
2024 NameOfCPURegister(base_reg(current & 0x07)));
2025 data++;
2026 break;
2027 case MOVE_REG_INSTR: {
2028 byte* addr = NULL;
2029 switch (operand_size()) {
2030 case OPERAND_WORD_SIZE:
2031 addr =
2032 reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
2033 data += 3;
2034 break;
2035 case OPERAND_DOUBLEWORD_SIZE:
2036 addr =
2037 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
2038 data += 5;
2039 break;
2040 case OPERAND_QUADWORD_SIZE:
2041 addr =
2042 reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
2043 data += 9;
2044 break;
2045 default:
2046 UNREACHABLE();
2047 }
2048 AppendToBuffer("mov%c %s,%s", operand_size_code(),
2049 NameOfCPURegister(base_reg(current & 0x07)),
2050 NameOfAddress(addr));
2051 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00002052 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002053
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002054 case CALL_JUMP_INSTR: {
2055 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
2056 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
2057 data += 5;
2058 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002059 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002060
2061 case SHORT_IMMEDIATE_INSTR: {
2062 byte* addr =
2063 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
2064 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
2065 data += 5;
2066 break;
2067 }
2068
2069 case NO_INSTR:
2070 processed = false;
2071 break;
2072
2073 default:
2074 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00002075 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002076 }
2077
2078 // The first byte didn't match any of the simple opcodes, so we
2079 // need to do special processing on it.
2080 if (!processed) {
2081 switch (*data) {
2082 case 0xC2:
2083 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
2084 data += 3;
2085 break;
2086
2087 case 0x69: // fall through
2088 case 0x6B: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002089 int count = 1;
2090 count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
2091 AppendToBuffer(",0x");
2092 if (*data == 0x69) {
2093 count += PrintImmediate(data + count, operand_size());
2094 } else {
2095 count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
2096 }
2097 data += count;
Steve Blocka7e24c12009-10-30 11:49:00 +00002098 break;
2099 }
2100
Steve Blocka7e24c12009-10-30 11:49:00 +00002101 case 0x81: // fall through
2102 case 0x83: // 0x81 with sign extension bit set
2103 data += PrintImmediateOp(data);
2104 break;
2105
2106 case 0x0F:
2107 data += TwoByteOpcodeInstruction(data);
2108 break;
2109
2110 case 0x8F: {
2111 data++;
2112 int mod, regop, rm;
2113 get_modrm(*data, &mod, &regop, &rm);
2114 if (regop == 0) {
2115 AppendToBuffer("pop ");
2116 data += PrintRightOperand(data);
2117 }
2118 }
2119 break;
2120
2121 case 0xFF: {
2122 data++;
2123 int mod, regop, rm;
2124 get_modrm(*data, &mod, &regop, &rm);
2125 const char* mnem = NULL;
2126 switch (regop) {
2127 case 0:
2128 mnem = "inc";
2129 break;
2130 case 1:
2131 mnem = "dec";
2132 break;
2133 case 2:
2134 mnem = "call";
2135 break;
2136 case 4:
2137 mnem = "jmp";
2138 break;
2139 case 6:
2140 mnem = "push";
2141 break;
2142 default:
2143 mnem = "???";
2144 }
Ben Murdochc5610432016-08-08 18:44:38 +01002145 if (regop <= 1) {
2146 AppendToBuffer("%s%c ", mnem, operand_size_code());
2147 } else {
2148 AppendToBuffer("%s ", mnem);
2149 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002150 data += PrintRightOperand(data);
2151 }
2152 break;
2153
2154 case 0xC7: // imm32, fall through
2155 case 0xC6: // imm8
2156 {
2157 bool is_byte = *data == 0xC6;
2158 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01002159 if (is_byte) {
2160 AppendToBuffer("movb ");
2161 data += PrintRightByteOperand(data);
2162 int32_t imm = *data;
2163 AppendToBuffer(",0x%x", imm);
2164 data++;
2165 } else {
2166 AppendToBuffer("mov%c ", operand_size_code());
2167 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002168 if (operand_size() == OPERAND_WORD_SIZE) {
2169 int16_t imm = *reinterpret_cast<int16_t*>(data);
2170 AppendToBuffer(",0x%x", imm);
2171 data += 2;
2172 } else {
2173 int32_t imm = *reinterpret_cast<int32_t*>(data);
2174 AppendToBuffer(",0x%x", imm);
2175 data += 4;
2176 }
Steve Block44f0eee2011-05-26 01:26:41 +01002177 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002178 }
2179 break;
2180
2181 case 0x80: {
2182 data++;
2183 AppendToBuffer("cmpb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002184 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002185 int32_t imm = *data;
2186 AppendToBuffer(",0x%x", imm);
2187 data++;
2188 }
2189 break;
2190
2191 case 0x88: // 8bit, fall through
2192 case 0x89: // 32bit
2193 {
2194 bool is_byte = *data == 0x88;
2195 int mod, regop, rm;
2196 data++;
2197 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002198 if (is_byte) {
2199 AppendToBuffer("movb ");
2200 data += PrintRightByteOperand(data);
2201 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2202 } else {
2203 AppendToBuffer("mov%c ", operand_size_code());
2204 data += PrintRightOperand(data);
2205 AppendToBuffer(",%s", NameOfCPURegister(regop));
2206 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002207 }
2208 break;
2209
2210 case 0x90:
2211 case 0x91:
2212 case 0x92:
2213 case 0x93:
2214 case 0x94:
2215 case 0x95:
2216 case 0x96:
2217 case 0x97: {
Steve Blockd0582a62009-12-15 09:54:21 +00002218 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002219 if (reg == 0) {
2220 AppendToBuffer("nop"); // Common name for xchg rax,rax.
2221 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002222 AppendToBuffer("xchg%c rax,%s",
Steve Blocka7e24c12009-10-30 11:49:00 +00002223 operand_size_code(),
2224 NameOfCPURegister(reg));
2225 }
Steve Blockd0582a62009-12-15 09:54:21 +00002226 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00002227 }
Steve Blockd0582a62009-12-15 09:54:21 +00002228 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002229 case 0xB0:
2230 case 0xB1:
2231 case 0xB2:
2232 case 0xB3:
2233 case 0xB4:
2234 case 0xB5:
2235 case 0xB6:
2236 case 0xB7:
2237 case 0xB8:
2238 case 0xB9:
2239 case 0xBA:
2240 case 0xBB:
2241 case 0xBC:
2242 case 0xBD:
2243 case 0xBE:
2244 case 0xBF: {
2245 // mov reg8,imm8 or mov reg32,imm32
2246 byte opcode = *data;
2247 data++;
2248 bool is_32bit = (opcode >= 0xB8);
2249 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
2250 if (is_32bit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002251 AppendToBuffer("mov%c %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002252 operand_size_code(),
2253 NameOfCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002254 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002255 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 AppendToBuffer("movb %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002257 NameOfByteCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002258 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002259 }
2260 break;
2261 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002262 case 0xFE: {
2263 data++;
2264 int mod, regop, rm;
2265 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002266 if (regop == 1) {
2267 AppendToBuffer("decb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002268 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002269 } else {
2270 UnimplementedInstruction();
2271 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002272 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002273 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002274 case 0x68:
2275 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
2276 data += 5;
2277 break;
2278
2279 case 0x6A:
2280 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
2281 data += 2;
2282 break;
2283
2284 case 0xA1: // Fall through.
2285 case 0xA3:
2286 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002287 case OPERAND_DOUBLEWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002288 const char* memory_location = NameOfAddress(
2289 reinterpret_cast<byte*>(
2290 *reinterpret_cast<int32_t*>(data + 1)));
2291 if (*data == 0xA1) { // Opcode 0xA1
2292 AppendToBuffer("movzxlq rax,(%s)", memory_location);
2293 } else { // Opcode 0xA3
2294 AppendToBuffer("movzxlq (%s),rax", memory_location);
2295 }
2296 data += 5;
2297 break;
2298 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002299 case OPERAND_QUADWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002300 // New x64 instruction mov rax,(imm_64).
2301 const char* memory_location = NameOfAddress(
2302 *reinterpret_cast<byte**>(data + 1));
2303 if (*data == 0xA1) { // Opcode 0xA1
2304 AppendToBuffer("movq rax,(%s)", memory_location);
2305 } else { // Opcode 0xA3
2306 AppendToBuffer("movq (%s),rax", memory_location);
2307 }
2308 data += 9;
2309 break;
2310 }
2311 default:
2312 UnimplementedInstruction();
2313 data += 2;
2314 }
2315 break;
2316
2317 case 0xA8:
2318 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
2319 data += 2;
2320 break;
2321
2322 case 0xA9: {
2323 int64_t value = 0;
2324 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002325 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002326 value = *reinterpret_cast<uint16_t*>(data + 1);
2327 data += 3;
2328 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002329 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002330 value = *reinterpret_cast<uint32_t*>(data + 1);
2331 data += 5;
2332 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002333 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002334 value = *reinterpret_cast<int32_t*>(data + 1);
2335 data += 5;
2336 break;
2337 default:
2338 UNREACHABLE();
2339 }
Ben Murdochc5610432016-08-08 18:44:38 +01002340 AppendToBuffer("test%c rax,0x%" PRIx64, operand_size_code(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002341 break;
2342 }
2343 case 0xD1: // fall through
2344 case 0xD3: // fall through
2345 case 0xC1:
2346 data += ShiftInstruction(data);
2347 break;
2348 case 0xD0: // fall through
2349 case 0xD2: // fall through
2350 case 0xC0:
2351 byte_size_operand_ = true;
2352 data += ShiftInstruction(data);
2353 break;
2354
2355 case 0xD9: // fall through
2356 case 0xDA: // fall through
2357 case 0xDB: // fall through
2358 case 0xDC: // fall through
2359 case 0xDD: // fall through
2360 case 0xDE: // fall through
2361 case 0xDF:
2362 data += FPUInstruction(data);
2363 break;
2364
2365 case 0xEB:
2366 data += JumpShort(data);
2367 break;
2368
Steve Blockd0582a62009-12-15 09:54:21 +00002369 case 0xF6:
2370 byte_size_operand_ = true; // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00002371 case 0xF7:
Steve Blockd0582a62009-12-15 09:54:21 +00002372 data += F6F7Instruction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002373 break;
2374
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002375 case 0x3C:
2376 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2377 data +=2;
2378 break;
2379
Steve Blocka7e24c12009-10-30 11:49:00 +00002380 default:
2381 UnimplementedInstruction();
2382 data += 1;
2383 }
2384 } // !processed
2385
2386 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2387 tmp_buffer_[tmp_buffer_pos_] = '\0';
2388 }
2389
Steve Blockd0582a62009-12-15 09:54:21 +00002390 int instr_len = static_cast<int>(data - instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002391 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002392
2393 int outp = 0;
2394 // Instruction bytes.
2395 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002396 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002397 }
2398 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002399 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002400 }
2401
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002402 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2403 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002404 return instr_len;
2405}
2406
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002407
Steve Blocka7e24c12009-10-30 11:49:00 +00002408//------------------------------------------------------------------------------
2409
2410
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002411static const char* const cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002412 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2413 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2414};
2415
2416
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002417static const char* const byte_cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002418 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2419 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2420};
2421
2422
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002423static const char* const xmm_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002424 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2425 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2426};
2427
2428
2429const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002431 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002432}
2433
2434
2435const char* NameConverter::NameOfConstant(byte* addr) const {
2436 return NameOfAddress(addr);
2437}
2438
2439
2440const char* NameConverter::NameOfCPURegister(int reg) const {
2441 if (0 <= reg && reg < 16)
2442 return cpu_regs[reg];
2443 return "noreg";
2444}
2445
2446
2447const char* NameConverter::NameOfByteCPURegister(int reg) const {
2448 if (0 <= reg && reg < 16)
2449 return byte_cpu_regs[reg];
2450 return "noreg";
2451}
2452
2453
2454const char* NameConverter::NameOfXMMRegister(int reg) const {
2455 if (0 <= reg && reg < 16)
2456 return xmm_regs[reg];
2457 return "noxmmreg";
2458}
2459
2460
2461const char* NameConverter::NameInCode(byte* addr) const {
2462 // X64 does not embed debug strings at the moment.
2463 UNREACHABLE();
2464 return "";
2465}
2466
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002467
Steve Blocka7e24c12009-10-30 11:49:00 +00002468//------------------------------------------------------------------------------
2469
2470Disassembler::Disassembler(const NameConverter& converter)
2471 : converter_(converter) { }
2472
2473Disassembler::~Disassembler() { }
2474
2475
2476int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2477 byte* instruction) {
2478 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2479 return d.InstructionDecode(buffer, instruction);
2480}
2481
2482
2483// The X64 assembler does not use constant pools.
2484int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2485 return -1;
2486}
2487
2488
2489void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2490 NameConverter converter;
2491 Disassembler d(converter);
2492 for (byte* pc = begin; pc < end;) {
2493 v8::internal::EmbeddedVector<char, 128> buffer;
2494 buffer[0] = '\0';
2495 byte* prev_pc = pc;
2496 pc += d.InstructionDecode(buffer, pc);
2497 fprintf(f, "%p", prev_pc);
2498 fprintf(f, " ");
2499
2500 for (byte* bp = prev_pc; bp < pc; bp++) {
2501 fprintf(f, "%02x", *bp);
2502 }
Steve Blockd0582a62009-12-15 09:54:21 +00002503 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002504 fprintf(f, " ");
2505 }
2506 fprintf(f, " %s\n", buffer.start());
2507 }
2508}
2509
2510} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002511
2512#endif // V8_TARGET_ARCH_X64