blob: a9532dc3ad9b97f8f238cefa7450b26c002dbed4 [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 Murdochb8a8cc12014-11-26 15:28:44 +000011#include "src/base/lazy-instance.h"
12#include "src/disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000013
14namespace disasm {
15
16enum OperandType {
17 UNSET_OP_ORDER = 0,
18 // Operand size decides between 16, 32 and 64 bit operands.
19 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
20 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
21 // Fixed 8-bit operands.
22 BYTE_SIZE_OPERAND_FLAG = 4,
23 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
24 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
25};
26
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027
Steve Blocka7e24c12009-10-30 11:49:00 +000028//------------------------------------------------------------------
29// Tables
30//------------------------------------------------------------------
31struct ByteMnemonic {
32 int b; // -1 terminates, otherwise must be in range (0..255)
33 OperandType op_order_;
34 const char* mnem;
35};
36
37
Ben Murdoch69a99ed2011-11-30 16:03:39 +000038static const ByteMnemonic two_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000039 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
40 { 0x01, OPER_REG_OP_ORDER, "add" },
41 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
42 { 0x03, REG_OPER_OP_ORDER, "add" },
43 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
44 { 0x09, OPER_REG_OP_ORDER, "or" },
45 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
46 { 0x0B, REG_OPER_OP_ORDER, "or" },
47 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
48 { 0x11, OPER_REG_OP_ORDER, "adc" },
49 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
50 { 0x13, REG_OPER_OP_ORDER, "adc" },
51 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
52 { 0x19, OPER_REG_OP_ORDER, "sbb" },
53 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
54 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
55 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
56 { 0x21, OPER_REG_OP_ORDER, "and" },
57 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
58 { 0x23, REG_OPER_OP_ORDER, "and" },
59 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
60 { 0x29, OPER_REG_OP_ORDER, "sub" },
61 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
62 { 0x2B, REG_OPER_OP_ORDER, "sub" },
63 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
64 { 0x31, OPER_REG_OP_ORDER, "xor" },
65 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
66 { 0x33, REG_OPER_OP_ORDER, "xor" },
67 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
68 { 0x39, OPER_REG_OP_ORDER, "cmp" },
69 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
70 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
Ben Murdochb8a8cc12014-11-26 15:28:44 +000071 { 0x63, REG_OPER_OP_ORDER, "movsxl" },
Steve Blocka7e24c12009-10-30 11:49:00 +000072 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
73 { 0x85, REG_OPER_OP_ORDER, "test" },
74 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
75 { 0x87, REG_OPER_OP_ORDER, "xchg" },
76 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
77 { 0x89, OPER_REG_OP_ORDER, "mov" },
78 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
79 { 0x8B, REG_OPER_OP_ORDER, "mov" },
80 { 0x8D, REG_OPER_OP_ORDER, "lea" },
81 { -1, UNSET_OP_ORDER, "" }
82};
83
84
Ben Murdoch69a99ed2011-11-30 16:03:39 +000085static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000086 { 0xC3, UNSET_OP_ORDER, "ret" },
87 { 0xC9, UNSET_OP_ORDER, "leave" },
88 { 0xF4, UNSET_OP_ORDER, "hlt" },
Ben Murdoch3ef787d2012-04-12 10:51:47 +010089 { 0xFC, UNSET_OP_ORDER, "cld" },
Steve Blocka7e24c12009-10-30 11:49:00 +000090 { 0xCC, UNSET_OP_ORDER, "int3" },
91 { 0x60, UNSET_OP_ORDER, "pushad" },
92 { 0x61, UNSET_OP_ORDER, "popad" },
93 { 0x9C, UNSET_OP_ORDER, "pushfd" },
94 { 0x9D, UNSET_OP_ORDER, "popfd" },
95 { 0x9E, UNSET_OP_ORDER, "sahf" },
96 { 0x99, UNSET_OP_ORDER, "cdq" },
97 { 0x9B, UNSET_OP_ORDER, "fwait" },
Leon Clarked91b9f72010-01-27 17:25:45 +000098 { 0xA4, UNSET_OP_ORDER, "movs" },
99 { 0xA5, UNSET_OP_ORDER, "movs" },
100 { 0xA6, UNSET_OP_ORDER, "cmps" },
101 { 0xA7, UNSET_OP_ORDER, "cmps" },
Steve Blocka7e24c12009-10-30 11:49:00 +0000102 { -1, UNSET_OP_ORDER, "" }
103};
104
105
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000106static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000107 { 0xE8, UNSET_OP_ORDER, "call" },
108 { 0xE9, UNSET_OP_ORDER, "jmp" },
109 { -1, UNSET_OP_ORDER, "" }
110};
111
112
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000113static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 { 0x05, UNSET_OP_ORDER, "add" },
115 { 0x0D, UNSET_OP_ORDER, "or" },
116 { 0x15, UNSET_OP_ORDER, "adc" },
117 { 0x1D, UNSET_OP_ORDER, "sbb" },
118 { 0x25, UNSET_OP_ORDER, "and" },
119 { 0x2D, UNSET_OP_ORDER, "sub" },
120 { 0x35, UNSET_OP_ORDER, "xor" },
121 { 0x3D, UNSET_OP_ORDER, "cmp" },
122 { -1, UNSET_OP_ORDER, "" }
123};
124
125
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000126static const char* const conditional_code_suffix[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 "o", "no", "c", "nc", "z", "nz", "na", "a",
128 "s", "ns", "pe", "po", "l", "ge", "le", "g"
129};
130
131
132enum InstructionType {
133 NO_INSTR,
134 ZERO_OPERANDS_INSTR,
135 TWO_OPERANDS_INSTR,
136 JUMP_CONDITIONAL_SHORT_INSTR,
137 REGISTER_INSTR,
138 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
139 MOVE_REG_INSTR,
140 CALL_JUMP_INSTR,
141 SHORT_IMMEDIATE_INSTR
142};
143
144
Leon Clarked91b9f72010-01-27 17:25:45 +0000145enum Prefixes {
146 ESCAPE_PREFIX = 0x0F,
147 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
148 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400149 VEX3_PREFIX = 0xC4,
150 VEX2_PREFIX = 0xC5,
Leon Clarked91b9f72010-01-27 17:25:45 +0000151 REPNE_PREFIX = 0xF2,
152 REP_PREFIX = 0xF3,
153 REPEQ_PREFIX = REP_PREFIX
154};
155
156
Steve Blocka7e24c12009-10-30 11:49:00 +0000157struct InstructionDesc {
158 const char* mnem;
159 InstructionType type;
160 OperandType op_order_;
161 bool byte_size_operation; // Fixed 8-bit operation.
162};
163
164
165class InstructionTable {
166 public:
167 InstructionTable();
168 const InstructionDesc& Get(byte x) const {
169 return instructions_[x];
170 }
171
172 private:
173 InstructionDesc instructions_[256];
174 void Clear();
175 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000176 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
178 const char* mnem);
179 void AddJumpConditionalShort();
180};
181
182
183InstructionTable::InstructionTable() {
184 Clear();
185 Init();
186}
187
188
189void InstructionTable::Clear() {
190 for (int i = 0; i < 256; i++) {
191 instructions_[i].mnem = "(bad)";
192 instructions_[i].type = NO_INSTR;
193 instructions_[i].op_order_ = UNSET_OP_ORDER;
194 instructions_[i].byte_size_operation = false;
195 }
196}
197
198
199void InstructionTable::Init() {
200 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
201 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
202 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
203 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
204 AddJumpConditionalShort();
205 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
206 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
207 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
208}
209
210
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000211void InstructionTable::CopyTable(const ByteMnemonic bm[],
212 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000213 for (int i = 0; bm[i].b >= 0; i++) {
214 InstructionDesc* id = &instructions_[bm[i].b];
215 id->mnem = bm[i].mnem;
216 OperandType op_order = bm[i].op_order_;
217 id->op_order_ =
218 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000220 id->type = type;
221 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
222 }
223}
224
225
226void InstructionTable::SetTableRange(InstructionType type,
227 byte start,
228 byte end,
229 bool byte_size,
230 const char* mnem) {
231 for (byte b = start; b <= end; b++) {
232 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000233 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 id->mnem = mnem;
235 id->type = type;
236 id->byte_size_operation = byte_size;
237 }
238}
239
240
241void InstructionTable::AddJumpConditionalShort() {
242 for (byte b = 0x70; b <= 0x7F; b++) {
243 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 id->mnem = NULL; // Computed depending on condition code.
246 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
247 }
248}
249
250
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251static v8::base::LazyInstance<InstructionTable>::type instruction_table =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252 LAZY_INSTANCE_INITIALIZER;
Steve Blocka7e24c12009-10-30 11:49:00 +0000253
Steve Block44f0eee2011-05-26 01:26:41 +0100254
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400255static const InstructionDesc cmov_instructions[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
257 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
272};
273
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274
Steve Blocka7e24c12009-10-30 11:49:00 +0000275//------------------------------------------------------------------------------
276// DisassemblerX64 implementation.
277
278enum UnimplementedOpcodeAction {
279 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
280 ABORT_ON_UNIMPLEMENTED_OPCODE
281};
282
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283
Steve Blocka7e24c12009-10-30 11:49:00 +0000284// A new DisassemblerX64 object is created to disassemble each instruction.
285// The object can only disassemble a single instruction.
286class DisassemblerX64 {
287 public:
288 DisassemblerX64(const NameConverter& converter,
289 UnimplementedOpcodeAction unimplemented_action =
290 ABORT_ON_UNIMPLEMENTED_OPCODE)
291 : converter_(converter),
292 tmp_buffer_pos_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400293 abort_on_unimplemented_(unimplemented_action ==
294 ABORT_ON_UNIMPLEMENTED_OPCODE),
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 rex_(0),
296 operand_size_(0),
297 group_1_prefix_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400298 vex_byte0_(0),
299 vex_byte1_(0),
300 vex_byte2_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301 byte_size_operand_(false),
302 instruction_table_(instruction_table.Pointer()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 tmp_buffer_[0] = '\0';
304 }
305
306 virtual ~DisassemblerX64() {
307 }
308
309 // Writes one disassembled instruction into 'buffer' (0-terminated).
310 // Returns the length of the disassembled machine instruction in bytes.
311 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
312
313 private:
314 enum OperandSize {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 OPERAND_BYTE_SIZE = 0,
316 OPERAND_WORD_SIZE = 1,
317 OPERAND_DOUBLEWORD_SIZE = 2,
318 OPERAND_QUADWORD_SIZE = 3
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 };
320
321 const NameConverter& converter_;
322 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
323 unsigned int tmp_buffer_pos_;
324 bool abort_on_unimplemented_;
325 // Prefixes parsed
326 byte rex_;
327 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
328 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400329 byte vex_byte0_; // 0xc4 or 0xc5
330 byte vex_byte1_;
331 byte vex_byte2_; // only for 3 bytes vex prefix
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 // Byte size operand override.
333 bool byte_size_operand_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000334 const InstructionTable* const instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000335
336 void setRex(byte rex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 DCHECK_EQ(0x40, rex & 0xF0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 rex_ = rex;
339 }
340
341 bool rex() { return rex_ != 0; }
342
343 bool rex_b() { return (rex_ & 0x01) != 0; }
344
345 // Actual number of base register given the low bits and the rex.b state.
346 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
347
348 bool rex_x() { return (rex_ & 0x02) != 0; }
349
350 bool rex_r() { return (rex_ & 0x04) != 0; }
351
352 bool rex_w() { return (rex_ & 0x08) != 0; }
353
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000354 bool vex_w() {
355 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
356 return vex_byte0_ == VEX3_PREFIX ? (vex_byte2_ & 0x80) != 0 : false;
357 }
358
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400359 bool vex_128() {
360 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
361 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
362 return (checked & 4) != 1;
363 }
364
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000365 bool vex_none() {
366 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
367 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
368 return (checked & 3) == 0;
369 }
370
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 bool vex_66() {
372 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
373 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
374 return (checked & 3) == 1;
375 }
376
377 bool vex_f3() {
378 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
379 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
380 return (checked & 3) == 2;
381 }
382
383 bool vex_f2() {
384 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
385 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
386 return (checked & 3) == 3;
387 }
388
389 bool vex_0f() {
390 if (vex_byte0_ == VEX2_PREFIX) return true;
391 return (vex_byte1_ & 3) == 1;
392 }
393
394 bool vex_0f38() {
395 if (vex_byte0_ == VEX2_PREFIX) return false;
396 return (vex_byte1_ & 3) == 2;
397 }
398
399 bool vex_0f3a() {
400 if (vex_byte0_ == VEX2_PREFIX) return false;
401 return (vex_byte1_ & 3) == 3;
402 }
403
404 int vex_vreg() {
405 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
406 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
407 return ~(checked >> 3) & 0xf;
408 }
409
Steve Blocka7e24c12009-10-30 11:49:00 +0000410 OperandSize operand_size() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000411 if (byte_size_operand_) return OPERAND_BYTE_SIZE;
412 if (rex_w()) return OPERAND_QUADWORD_SIZE;
413 if (operand_size_ != 0) return OPERAND_WORD_SIZE;
414 return OPERAND_DOUBLEWORD_SIZE;
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 }
416
417 char operand_size_code() {
418 return "bwlq"[operand_size()];
419 }
420
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400421 char float_size_code() { return "sd"[rex_w()]; }
422
Steve Blocka7e24c12009-10-30 11:49:00 +0000423 const char* NameOfCPURegister(int reg) const {
424 return converter_.NameOfCPURegister(reg);
425 }
426
427 const char* NameOfByteCPURegister(int reg) const {
428 return converter_.NameOfByteCPURegister(reg);
429 }
430
431 const char* NameOfXMMRegister(int reg) const {
432 return converter_.NameOfXMMRegister(reg);
433 }
434
435 const char* NameOfAddress(byte* addr) const {
436 return converter_.NameOfAddress(addr);
437 }
438
439 // Disassembler helper functions.
440 void get_modrm(byte data,
441 int* mod,
442 int* regop,
443 int* rm) {
444 *mod = (data >> 6) & 3;
445 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
446 *rm = (data & 7) | (rex_b() ? 8 : 0);
447 }
448
449 void get_sib(byte data,
450 int* scale,
451 int* index,
452 int* base) {
453 *scale = (data >> 6) & 3;
454 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
455 *base = (data & 7) | (rex_b() ? 8 : 0);
456 }
457
458 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
459
460 int PrintRightOperandHelper(byte* modrmp,
461 RegisterNameMapping register_name);
462 int PrintRightOperand(byte* modrmp);
463 int PrintRightByteOperand(byte* modrmp);
Steve Blockd0582a62009-12-15 09:54:21 +0000464 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 int PrintOperands(const char* mnem,
466 OperandType op_order,
467 byte* data);
468 int PrintImmediate(byte* data, OperandSize size);
469 int PrintImmediateOp(byte* data);
470 const char* TwoByteMnemonic(byte opcode);
471 int TwoByteOpcodeInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000472 int F6F7Instruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 int ShiftInstruction(byte* data);
474 int JumpShort(byte* data);
475 int JumpConditional(byte* data);
476 int JumpConditionalShort(byte* data);
477 int SetCC(byte* data);
478 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000479 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
480 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400481 int AVXInstruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000482 void AppendToBuffer(const char* format, ...);
483
484 void UnimplementedInstruction() {
485 if (abort_on_unimplemented_) {
486 CHECK(false);
487 } else {
488 AppendToBuffer("'Unimplemented Instruction'");
489 }
490 }
491};
492
493
494void DisassemblerX64::AppendToBuffer(const char* format, ...) {
495 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
496 va_list args;
497 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 va_end(args);
500 tmp_buffer_pos_ += result;
501}
502
503
504int DisassemblerX64::PrintRightOperandHelper(
505 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100506 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000507 int mod, regop, rm;
508 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100509 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
510 &DisassemblerX64::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000511 switch (mod) {
512 case 0:
513 if ((rm & 7) == 5) {
514 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 AppendToBuffer("[rip+0x%x]", disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000516 return 5;
517 } else if ((rm & 7) == 4) {
518 // Codes for SIB byte.
519 byte sib = *(modrmp + 1);
520 int scale, index, base;
521 get_sib(sib, &scale, &index, &base);
522 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
523 // index == rsp means no index. Only use sib byte with no index for
524 // rsp and r12 base.
Steve Block8defd9f2010-07-08 12:39:36 +0100525 AppendToBuffer("[%s]", NameOfCPURegister(base));
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 return 2;
527 } else if (base == 5) {
528 // base == rbp means no base register (when mod == 0).
529 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000530 AppendToBuffer("[%s*%d%s0x%x]",
Steve Block8defd9f2010-07-08 12:39:36 +0100531 NameOfCPURegister(index),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 1 << scale,
533 disp < 0 ? "-" : "+",
534 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000535 return 6;
536 } else if (index != 4 && base != 5) {
537 // [base+index*scale]
538 AppendToBuffer("[%s+%s*%d]",
Steve Block8defd9f2010-07-08 12:39:36 +0100539 NameOfCPURegister(base),
540 NameOfCPURegister(index),
Steve Blocka7e24c12009-10-30 11:49:00 +0000541 1 << scale);
542 return 2;
543 } else {
544 UnimplementedInstruction();
545 return 1;
546 }
547 } else {
Steve Block8defd9f2010-07-08 12:39:36 +0100548 AppendToBuffer("[%s]", NameOfCPURegister(rm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000549 return 1;
550 }
551 break;
552 case 1: // fall through
553 case 2:
554 if ((rm & 7) == 4) {
555 byte sib = *(modrmp + 1);
556 int scale, index, base;
557 get_sib(sib, &scale, &index, &base);
558 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000559 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 AppendToBuffer("[%s%s0x%x]",
562 NameOfCPURegister(base),
563 disp < 0 ? "-" : "+",
564 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000565 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 AppendToBuffer("[%s+%s*%d%s0x%x]",
567 NameOfCPURegister(base),
568 NameOfCPURegister(index),
569 1 << scale,
570 disp < 0 ? "-" : "+",
571 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000572 }
573 return mod == 2 ? 6 : 3;
574 } else {
575 // No sib.
576 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 : *reinterpret_cast<int8_t*>(modrmp + 1);
578 AppendToBuffer("[%s%s0x%x]",
579 NameOfCPURegister(rm),
580 disp < 0 ? "-" : "+",
581 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000582 return (mod == 2) ? 5 : 2;
583 }
584 break;
585 case 3:
586 AppendToBuffer("%s", (this->*register_name)(rm));
587 return 1;
588 default:
589 UnimplementedInstruction();
590 return 1;
591 }
592 UNREACHABLE();
593}
594
595
596int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
597 int64_t value;
598 int count;
599 switch (size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 case OPERAND_BYTE_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000601 value = *data;
602 count = 1;
603 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000605 value = *reinterpret_cast<int16_t*>(data);
606 count = 2;
607 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000608 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000609 value = *reinterpret_cast<uint32_t*>(data);
610 count = 4;
611 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 value = *reinterpret_cast<int32_t*>(data);
614 count = 4;
615 break;
616 default:
617 UNREACHABLE();
618 value = 0; // Initialize variables on all paths to satisfy the compiler.
619 count = 0;
620 }
621 AppendToBuffer("%" V8_PTR_PREFIX "x", value);
622 return count;
623}
624
625
626int DisassemblerX64::PrintRightOperand(byte* modrmp) {
627 return PrintRightOperandHelper(modrmp,
628 &DisassemblerX64::NameOfCPURegister);
629}
630
631
632int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
633 return PrintRightOperandHelper(modrmp,
634 &DisassemblerX64::NameOfByteCPURegister);
635}
636
637
Steve Blockd0582a62009-12-15 09:54:21 +0000638int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
639 return PrintRightOperandHelper(modrmp,
640 &DisassemblerX64::NameOfXMMRegister);
641}
642
643
Steve Blocka7e24c12009-10-30 11:49:00 +0000644// Returns number of bytes used including the current *data.
645// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
646int DisassemblerX64::PrintOperands(const char* mnem,
647 OperandType op_order,
648 byte* data) {
649 byte modrm = *data;
650 int mod, regop, rm;
651 get_modrm(modrm, &mod, &regop, &rm);
652 int advance = 0;
653 const char* register_name =
654 byte_size_operand_ ? NameOfByteCPURegister(regop)
655 : NameOfCPURegister(regop);
656 switch (op_order) {
657 case REG_OPER_OP_ORDER: {
658 AppendToBuffer("%s%c %s,",
659 mnem,
660 operand_size_code(),
661 register_name);
662 advance = byte_size_operand_ ? PrintRightByteOperand(data)
663 : PrintRightOperand(data);
664 break;
665 }
666 case OPER_REG_OP_ORDER: {
667 AppendToBuffer("%s%c ", mnem, operand_size_code());
668 advance = byte_size_operand_ ? PrintRightByteOperand(data)
669 : PrintRightOperand(data);
670 AppendToBuffer(",%s", register_name);
671 break;
672 }
673 default:
674 UNREACHABLE();
675 break;
676 }
677 return advance;
678}
679
680
681// Returns number of bytes used by machine instruction, including *data byte.
682// Writes immediate instructions to 'tmp_buffer_'.
683int DisassemblerX64::PrintImmediateOp(byte* data) {
684 bool byte_size_immediate = (*data & 0x02) != 0;
685 byte modrm = *(data + 1);
686 int mod, regop, rm;
687 get_modrm(modrm, &mod, &regop, &rm);
688 const char* mnem = "Imm???";
689 switch (regop) {
690 case 0:
691 mnem = "add";
692 break;
693 case 1:
694 mnem = "or";
695 break;
696 case 2:
697 mnem = "adc";
698 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100699 case 3:
700 mnem = "sbb";
701 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000702 case 4:
703 mnem = "and";
704 break;
705 case 5:
706 mnem = "sub";
707 break;
708 case 6:
709 mnem = "xor";
710 break;
711 case 7:
712 mnem = "cmp";
713 break;
714 default:
715 UnimplementedInstruction();
716 }
717 AppendToBuffer("%s%c ", mnem, operand_size_code());
718 int count = PrintRightOperand(data + 1);
719 AppendToBuffer(",0x");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000720 OperandSize immediate_size =
721 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 count += PrintImmediate(data + 1 + count, immediate_size);
723 return 1 + count;
724}
725
726
727// Returns number of bytes used, including *data.
Steve Blockd0582a62009-12-15 09:54:21 +0000728int DisassemblerX64::F6F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000729 DCHECK(*data == 0xF7 || *data == 0xF6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000730 byte modrm = *(data + 1);
731 int mod, regop, rm;
732 get_modrm(modrm, &mod, &regop, &rm);
733 if (mod == 3 && regop != 0) {
734 const char* mnem = NULL;
735 switch (regop) {
736 case 2:
737 mnem = "not";
738 break;
739 case 3:
740 mnem = "neg";
741 break;
742 case 4:
743 mnem = "mul";
744 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000745 case 5:
746 mnem = "imul";
747 break;
748 case 6:
749 mnem = "div";
750 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 case 7:
752 mnem = "idiv";
753 break;
754 default:
755 UnimplementedInstruction();
756 }
757 AppendToBuffer("%s%c %s",
758 mnem,
759 operand_size_code(),
760 NameOfCPURegister(rm));
761 return 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 } else if (regop == 0) {
763 AppendToBuffer("test%c ", operand_size_code());
Steve Blockd0582a62009-12-15 09:54:21 +0000764 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
765 AppendToBuffer(",0x");
766 count += PrintImmediate(data + 1 + count, operand_size());
767 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 } else {
769 UnimplementedInstruction();
770 return 2;
771 }
772}
773
774
775int DisassemblerX64::ShiftInstruction(byte* data) {
776 byte op = *data & (~1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400777 int count = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000778 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
779 UnimplementedInstruction();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400780 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400782 // Print mneumonic.
783 {
784 byte modrm = *(data + count);
785 int mod, regop, rm;
786 get_modrm(modrm, &mod, &regop, &rm);
787 regop &= 0x7; // The REX.R bit does not affect the operation.
788 const char* mnem = NULL;
789 switch (regop) {
790 case 0:
791 mnem = "rol";
792 break;
793 case 1:
794 mnem = "ror";
795 break;
796 case 2:
797 mnem = "rcl";
798 break;
799 case 3:
800 mnem = "rcr";
801 break;
802 case 4:
803 mnem = "shl";
804 break;
805 case 5:
806 mnem = "shr";
807 break;
808 case 7:
809 mnem = "sar";
810 break;
811 default:
812 UnimplementedInstruction();
813 return count + 1;
814 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000815 DCHECK_NOT_NULL(mnem);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400816 AppendToBuffer("%s%c ", mnem, operand_size_code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000817 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400818 count += PrintRightOperand(data + count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 if (op == 0xD2) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400820 AppendToBuffer(", cl");
Steve Blocka7e24c12009-10-30 11:49:00 +0000821 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400822 int imm8 = -1;
823 if (op == 0xD0) {
824 imm8 = 1;
825 } else {
826 DCHECK_EQ(0xC0, op);
827 imm8 = *(data + count);
828 count++;
829 }
830 AppendToBuffer(", %d", imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000831 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400832 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000833}
834
835
836// Returns number of bytes used, including *data.
837int DisassemblerX64::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000838 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000839 byte b = *(data + 1);
840 byte* dest = data + static_cast<int8_t>(b) + 2;
841 AppendToBuffer("jmp %s", NameOfAddress(dest));
842 return 2;
843}
844
845
846// Returns number of bytes used, including *data.
847int DisassemblerX64::JumpConditional(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 byte cond = *(data + 1) & 0x0F;
850 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
851 const char* mnem = conditional_code_suffix[cond];
852 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
853 return 6; // includes 0x0F
854}
855
856
857// Returns number of bytes used, including *data.
858int DisassemblerX64::JumpConditionalShort(byte* data) {
859 byte cond = *data & 0x0F;
860 byte b = *(data + 1);
861 byte* dest = data + static_cast<int8_t>(b) + 2;
862 const char* mnem = conditional_code_suffix[cond];
863 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
864 return 2;
865}
866
867
868// Returns number of bytes used, including *data.
869int DisassemblerX64::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000870 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000871 byte cond = *(data + 1) & 0x0F;
872 const char* mnem = conditional_code_suffix[cond];
873 AppendToBuffer("set%s%c ", mnem, operand_size_code());
874 PrintRightByteOperand(data + 2);
875 return 3; // includes 0x0F
876}
877
878
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400879int DisassemblerX64::AVXInstruction(byte* data) {
880 byte opcode = *data;
881 byte* current = data + 1;
882 if (vex_66() && vex_0f38()) {
883 int mod, regop, rm, vvvv = vex_vreg();
884 get_modrm(*current, &mod, &regop, &rm);
885 switch (opcode) {
886 case 0x99:
887 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
888 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
889 current += PrintRightXMMOperand(current);
890 break;
891 case 0xa9:
892 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
893 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
894 current += PrintRightXMMOperand(current);
895 break;
896 case 0xb9:
897 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
898 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
899 current += PrintRightXMMOperand(current);
900 break;
901 case 0x9b:
902 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
903 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
904 current += PrintRightXMMOperand(current);
905 break;
906 case 0xab:
907 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
908 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
909 current += PrintRightXMMOperand(current);
910 break;
911 case 0xbb:
912 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
913 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
914 current += PrintRightXMMOperand(current);
915 break;
916 case 0x9d:
917 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
918 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
919 current += PrintRightXMMOperand(current);
920 break;
921 case 0xad:
922 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
923 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
924 current += PrintRightXMMOperand(current);
925 break;
926 case 0xbd:
927 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
928 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
929 current += PrintRightXMMOperand(current);
930 break;
931 case 0x9f:
932 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
933 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
934 current += PrintRightXMMOperand(current);
935 break;
936 case 0xaf:
937 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
938 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
939 current += PrintRightXMMOperand(current);
940 break;
941 case 0xbf:
942 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
943 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
944 current += PrintRightXMMOperand(current);
945 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946 case 0xf7:
947 AppendToBuffer("shlx%c %s,", operand_size_code(),
948 NameOfCPURegister(regop));
949 current += PrintRightOperand(current);
950 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
951 break;
952 default:
953 UnimplementedInstruction();
954 }
955 } else if (vex_66() && vex_0f3a()) {
956 int mod, regop, rm, vvvv = vex_vreg();
957 get_modrm(*current, &mod, &regop, &rm);
958 switch (opcode) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100959 case 0x0a:
960 AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
961 NameOfXMMRegister(vvvv));
962 current += PrintRightXMMOperand(current);
963 AppendToBuffer(",0x%x", *current++);
964 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000965 case 0x0b:
966 AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
967 NameOfXMMRegister(vvvv));
968 current += PrintRightXMMOperand(current);
969 AppendToBuffer(",0x%x", *current++);
970 break;
971 default:
972 UnimplementedInstruction();
973 }
974 } else if (vex_f3() && vex_0f()) {
975 int mod, regop, rm, vvvv = vex_vreg();
976 get_modrm(*current, &mod, &regop, &rm);
977 switch (opcode) {
978 case 0x10:
979 AppendToBuffer("vmovss %s,", NameOfXMMRegister(regop));
980 if (mod == 3) {
981 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
982 }
983 current += PrintRightXMMOperand(current);
984 break;
985 case 0x11:
986 AppendToBuffer("vmovss ");
987 current += PrintRightXMMOperand(current);
988 if (mod == 3) {
989 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
990 }
991 AppendToBuffer(",%s", NameOfXMMRegister(regop));
992 break;
993 case 0x2a:
994 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2ss" : "vcvtlsi2ss",
995 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
996 current += PrintRightOperand(current);
997 break;
998 case 0x2c:
999 AppendToBuffer("vcvttss2si%s %s,", vex_w() ? "q" : "",
1000 NameOfCPURegister(regop));
1001 current += PrintRightXMMOperand(current);
1002 break;
1003 case 0x58:
1004 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
1005 NameOfXMMRegister(vvvv));
1006 current += PrintRightXMMOperand(current);
1007 break;
1008 case 0x59:
1009 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
1010 NameOfXMMRegister(vvvv));
1011 current += PrintRightXMMOperand(current);
1012 break;
1013 case 0x5a:
1014 AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
1015 NameOfXMMRegister(vvvv));
1016 current += PrintRightXMMOperand(current);
1017 break;
1018 case 0x5c:
1019 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
1020 NameOfXMMRegister(vvvv));
1021 current += PrintRightXMMOperand(current);
1022 break;
1023 case 0x5d:
1024 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
1025 NameOfXMMRegister(vvvv));
1026 current += PrintRightXMMOperand(current);
1027 break;
1028 case 0x5e:
1029 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
1030 NameOfXMMRegister(vvvv));
1031 current += PrintRightXMMOperand(current);
1032 break;
1033 case 0x5f:
1034 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
1035 NameOfXMMRegister(vvvv));
1036 current += PrintRightXMMOperand(current);
1037 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001038 default:
1039 UnimplementedInstruction();
1040 }
1041 } else if (vex_f2() && vex_0f()) {
1042 int mod, regop, rm, vvvv = vex_vreg();
1043 get_modrm(*current, &mod, &regop, &rm);
1044 switch (opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001045 case 0x10:
1046 AppendToBuffer("vmovsd %s,", NameOfXMMRegister(regop));
1047 if (mod == 3) {
1048 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1049 }
1050 current += PrintRightXMMOperand(current);
1051 break;
1052 case 0x11:
1053 AppendToBuffer("vmovsd ");
1054 current += PrintRightXMMOperand(current);
1055 if (mod == 3) {
1056 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1057 }
1058 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1059 break;
1060 case 0x2a:
1061 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd",
1062 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1063 current += PrintRightOperand(current);
1064 break;
1065 case 0x2c:
1066 AppendToBuffer("vcvttsd2si%s %s,", vex_w() ? "q" : "",
1067 NameOfCPURegister(regop));
1068 current += PrintRightXMMOperand(current);
1069 break;
1070 case 0x2d:
1071 AppendToBuffer("vcvtsd2si%s %s,", vex_w() ? "q" : "",
1072 NameOfCPURegister(regop));
1073 current += PrintRightXMMOperand(current);
1074 break;
1075 case 0x51:
1076 AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
1077 NameOfXMMRegister(vvvv));
1078 current += PrintRightXMMOperand(current);
1079 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001080 case 0x58:
1081 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
1082 NameOfXMMRegister(vvvv));
1083 current += PrintRightXMMOperand(current);
1084 break;
1085 case 0x59:
1086 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
1087 NameOfXMMRegister(vvvv));
1088 current += PrintRightXMMOperand(current);
1089 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001090 case 0x5a:
1091 AppendToBuffer("vcvtsd2ss %s,%s,", NameOfXMMRegister(regop),
1092 NameOfXMMRegister(vvvv));
1093 current += PrintRightXMMOperand(current);
1094 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001095 case 0x5c:
1096 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
1097 NameOfXMMRegister(vvvv));
1098 current += PrintRightXMMOperand(current);
1099 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001100 case 0x5d:
1101 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
1102 NameOfXMMRegister(vvvv));
1103 current += PrintRightXMMOperand(current);
1104 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001105 case 0x5e:
1106 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
1107 NameOfXMMRegister(vvvv));
1108 current += PrintRightXMMOperand(current);
1109 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001110 case 0x5f:
1111 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
1112 NameOfXMMRegister(vvvv));
1113 current += PrintRightXMMOperand(current);
1114 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001115 default:
1116 UnimplementedInstruction();
1117 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001118 } else if (vex_none() && vex_0f38()) {
1119 int mod, regop, rm, vvvv = vex_vreg();
1120 get_modrm(*current, &mod, &regop, &rm);
1121 const char* mnem = "?";
1122 switch (opcode) {
1123 case 0xf2:
1124 AppendToBuffer("andn%c %s,%s,", operand_size_code(),
1125 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1126 current += PrintRightOperand(current);
1127 break;
1128 case 0xf5:
1129 AppendToBuffer("bzhi%c %s,", operand_size_code(),
1130 NameOfCPURegister(regop));
1131 current += PrintRightOperand(current);
1132 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1133 break;
1134 case 0xf7:
1135 AppendToBuffer("bextr%c %s,", operand_size_code(),
1136 NameOfCPURegister(regop));
1137 current += PrintRightOperand(current);
1138 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1139 break;
1140 case 0xf3:
1141 switch (regop) {
1142 case 1:
1143 mnem = "blsr";
1144 break;
1145 case 2:
1146 mnem = "blsmsk";
1147 break;
1148 case 3:
1149 mnem = "blsi";
1150 break;
1151 default:
1152 UnimplementedInstruction();
1153 }
1154 AppendToBuffer("%s%c %s,", mnem, operand_size_code(),
1155 NameOfCPURegister(vvvv));
1156 current += PrintRightOperand(current);
1157 mnem = "?";
1158 break;
1159 default:
1160 UnimplementedInstruction();
1161 }
1162 } else if (vex_f2() && vex_0f38()) {
1163 int mod, regop, rm, vvvv = vex_vreg();
1164 get_modrm(*current, &mod, &regop, &rm);
1165 switch (opcode) {
1166 case 0xf5:
1167 AppendToBuffer("pdep%c %s,%s,", operand_size_code(),
1168 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1169 current += PrintRightOperand(current);
1170 break;
1171 case 0xf6:
1172 AppendToBuffer("mulx%c %s,%s,", operand_size_code(),
1173 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1174 current += PrintRightOperand(current);
1175 break;
1176 case 0xf7:
1177 AppendToBuffer("shrx%c %s,", operand_size_code(),
1178 NameOfCPURegister(regop));
1179 current += PrintRightOperand(current);
1180 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1181 break;
1182 default:
1183 UnimplementedInstruction();
1184 }
1185 } else if (vex_f3() && vex_0f38()) {
1186 int mod, regop, rm, vvvv = vex_vreg();
1187 get_modrm(*current, &mod, &regop, &rm);
1188 switch (opcode) {
1189 case 0xf5:
1190 AppendToBuffer("pext%c %s,%s,", operand_size_code(),
1191 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1192 current += PrintRightOperand(current);
1193 break;
1194 case 0xf7:
1195 AppendToBuffer("sarx%c %s,", operand_size_code(),
1196 NameOfCPURegister(regop));
1197 current += PrintRightOperand(current);
1198 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1199 break;
1200 default:
1201 UnimplementedInstruction();
1202 }
1203 } else if (vex_f2() && vex_0f3a()) {
1204 int mod, regop, rm;
1205 get_modrm(*current, &mod, &regop, &rm);
1206 switch (opcode) {
1207 case 0xf0:
1208 AppendToBuffer("rorx%c %s,", operand_size_code(),
1209 NameOfCPURegister(regop));
1210 current += PrintRightOperand(current);
1211 switch (operand_size()) {
1212 case OPERAND_DOUBLEWORD_SIZE:
1213 AppendToBuffer(",%d", *current & 0x1f);
1214 break;
1215 case OPERAND_QUADWORD_SIZE:
1216 AppendToBuffer(",%d", *current & 0x3f);
1217 break;
1218 default:
1219 UnimplementedInstruction();
1220 }
1221 current += 1;
1222 break;
1223 default:
1224 UnimplementedInstruction();
1225 }
1226 } else if (vex_none() && vex_0f()) {
1227 int mod, regop, rm, vvvv = vex_vreg();
1228 get_modrm(*current, &mod, &regop, &rm);
1229 switch (opcode) {
1230 case 0x28:
1231 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1232 current += PrintRightXMMOperand(current);
1233 break;
1234 case 0x29:
1235 AppendToBuffer("vmovaps ");
1236 current += PrintRightXMMOperand(current);
1237 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1238 break;
1239 case 0x2e:
1240 AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1241 current += PrintRightXMMOperand(current);
1242 break;
1243 case 0x54:
1244 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1245 NameOfXMMRegister(vvvv));
1246 current += PrintRightXMMOperand(current);
1247 break;
1248 case 0x57:
1249 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1250 NameOfXMMRegister(vvvv));
1251 current += PrintRightXMMOperand(current);
1252 break;
1253 default:
1254 UnimplementedInstruction();
1255 }
1256 } else if (vex_66() && vex_0f()) {
1257 int mod, regop, rm, vvvv = vex_vreg();
1258 get_modrm(*current, &mod, &regop, &rm);
1259 switch (opcode) {
1260 case 0x28:
1261 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1262 current += PrintRightXMMOperand(current);
1263 break;
1264 case 0x29:
1265 AppendToBuffer("vmovapd ");
1266 current += PrintRightXMMOperand(current);
1267 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1268 break;
1269 case 0x2e:
1270 AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1271 current += PrintRightXMMOperand(current);
1272 break;
1273 case 0x50:
1274 AppendToBuffer("vmovmskpd %s,", NameOfCPURegister(regop));
1275 current += PrintRightXMMOperand(current);
1276 break;
1277 case 0x54:
1278 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1279 NameOfXMMRegister(vvvv));
1280 current += PrintRightXMMOperand(current);
1281 break;
1282 case 0x56:
1283 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1284 NameOfXMMRegister(vvvv));
1285 current += PrintRightXMMOperand(current);
1286 break;
1287 case 0x57:
1288 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1289 NameOfXMMRegister(vvvv));
1290 current += PrintRightXMMOperand(current);
1291 break;
1292 case 0x6e:
1293 AppendToBuffer("vmov%c %s,", vex_w() ? 'q' : 'd',
1294 NameOfXMMRegister(regop));
1295 current += PrintRightOperand(current);
1296 break;
1297 case 0x73:
1298 AppendToBuffer("%s %s,", regop == 6 ? "vpsllq" : "vpsrlq",
1299 NameOfXMMRegister(vvvv));
1300 current += PrintRightXMMOperand(current);
1301 AppendToBuffer(",%u", *current++);
1302 break;
1303 case 0x76:
1304 AppendToBuffer("vpcmpeqd %s,%s,", NameOfXMMRegister(regop),
1305 NameOfXMMRegister(vvvv));
1306 current += PrintRightXMMOperand(current);
1307 break;
1308 case 0x7e:
1309 AppendToBuffer("vmov%c ", vex_w() ? 'q' : 'd');
1310 current += PrintRightOperand(current);
1311 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1312 break;
1313 default:
1314 UnimplementedInstruction();
1315 }
1316
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001317 } else {
1318 UnimplementedInstruction();
1319 }
1320
1321 return static_cast<int>(current - data);
1322}
1323
1324
Steve Blocka7e24c12009-10-30 11:49:00 +00001325// Returns number of bytes used, including *data.
1326int DisassemblerX64::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001327 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001329 byte modrm_byte = *(data+1);
1330
1331 if (modrm_byte >= 0xC0) {
1332 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1333 } else {
1334 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 }
Steve Blockd0582a62009-12-15 09:54:21 +00001336}
1337
1338int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
1339 int modrm_byte,
1340 byte* modrm_start) {
1341 const char* mnem = "?";
1342 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1343 switch (escape_opcode) {
1344 case 0xD9: switch (regop) {
1345 case 0: mnem = "fld_s"; break;
1346 case 3: mnem = "fstp_s"; break;
1347 case 7: mnem = "fstcw"; break;
1348 default: UnimplementedInstruction();
1349 }
1350 break;
1351
1352 case 0xDB: switch (regop) {
1353 case 0: mnem = "fild_s"; break;
1354 case 1: mnem = "fisttp_s"; break;
1355 case 2: mnem = "fist_s"; break;
1356 case 3: mnem = "fistp_s"; break;
1357 default: UnimplementedInstruction();
1358 }
1359 break;
1360
1361 case 0xDD: switch (regop) {
1362 case 0: mnem = "fld_d"; break;
1363 case 3: mnem = "fstp_d"; break;
1364 default: UnimplementedInstruction();
1365 }
1366 break;
1367
1368 case 0xDF: switch (regop) {
1369 case 5: mnem = "fild_d"; break;
1370 case 7: mnem = "fistp_d"; break;
1371 default: UnimplementedInstruction();
1372 }
1373 break;
1374
1375 default: UnimplementedInstruction();
1376 }
1377 AppendToBuffer("%s ", mnem);
1378 int count = PrintRightOperand(modrm_start);
1379 return count + 1;
1380}
1381
1382int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1383 byte modrm_byte) {
1384 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1385 const char* mnem = "?";
1386
1387 switch (escape_opcode) {
1388 case 0xD8:
1389 UnimplementedInstruction();
1390 break;
1391
1392 case 0xD9:
1393 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001394 case 0xC0:
1395 mnem = "fld";
1396 has_register = true;
1397 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001398 case 0xC8:
1399 mnem = "fxch";
1400 has_register = true;
1401 break;
1402 default:
1403 switch (modrm_byte) {
1404 case 0xE0: mnem = "fchs"; break;
1405 case 0xE1: mnem = "fabs"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001406 case 0xE3: mnem = "fninit"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001407 case 0xE4: mnem = "ftst"; break;
1408 case 0xE8: mnem = "fld1"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001409 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001410 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001411 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001412 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001413 case 0xF1: mnem = "fyl2x"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001414 case 0xF2: mnem = "fptan"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001415 case 0xF5: mnem = "fprem1"; break;
1416 case 0xF7: mnem = "fincstp"; break;
1417 case 0xF8: mnem = "fprem"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418 case 0xFC: mnem = "frndint"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001419 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001420 case 0xFE: mnem = "fsin"; break;
1421 case 0xFF: mnem = "fcos"; break;
1422 default: UnimplementedInstruction();
1423 }
1424 }
1425 break;
1426
1427 case 0xDA:
1428 if (modrm_byte == 0xE9) {
1429 mnem = "fucompp";
1430 } else {
1431 UnimplementedInstruction();
1432 }
1433 break;
1434
1435 case 0xDB:
1436 if ((modrm_byte & 0xF8) == 0xE8) {
1437 mnem = "fucomi";
1438 has_register = true;
1439 } else if (modrm_byte == 0xE2) {
1440 mnem = "fclex";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441 } else if (modrm_byte == 0xE3) {
1442 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001443 } else {
1444 UnimplementedInstruction();
1445 }
1446 break;
1447
1448 case 0xDC:
1449 has_register = true;
1450 switch (modrm_byte & 0xF8) {
1451 case 0xC0: mnem = "fadd"; break;
1452 case 0xE8: mnem = "fsub"; break;
1453 case 0xC8: mnem = "fmul"; break;
1454 case 0xF8: mnem = "fdiv"; break;
1455 default: UnimplementedInstruction();
1456 }
1457 break;
1458
1459 case 0xDD:
1460 has_register = true;
1461 switch (modrm_byte & 0xF8) {
1462 case 0xC0: mnem = "ffree"; break;
1463 case 0xD8: mnem = "fstp"; break;
1464 default: UnimplementedInstruction();
1465 }
1466 break;
1467
1468 case 0xDE:
1469 if (modrm_byte == 0xD9) {
1470 mnem = "fcompp";
1471 } else {
1472 has_register = true;
1473 switch (modrm_byte & 0xF8) {
1474 case 0xC0: mnem = "faddp"; break;
1475 case 0xE8: mnem = "fsubp"; break;
1476 case 0xC8: mnem = "fmulp"; break;
1477 case 0xF8: mnem = "fdivp"; break;
1478 default: UnimplementedInstruction();
1479 }
1480 }
1481 break;
1482
1483 case 0xDF:
1484 if (modrm_byte == 0xE0) {
1485 mnem = "fnstsw_ax";
1486 } else if ((modrm_byte & 0xF8) == 0xE8) {
1487 mnem = "fucomip";
1488 has_register = true;
1489 }
1490 break;
1491
1492 default: UnimplementedInstruction();
1493 }
1494
1495 if (has_register) {
1496 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1497 } else {
1498 AppendToBuffer("%s", mnem);
1499 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 return 2;
1501}
1502
1503
Steve Blockd0582a62009-12-15 09:54:21 +00001504
Steve Blocka7e24c12009-10-30 11:49:00 +00001505// Handle all two-byte opcodes, which start with 0x0F.
1506// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1507// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1508int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1509 byte opcode = *(data + 1);
1510 byte* current = data + 2;
1511 // At return, "current" points to the start of the next instruction.
1512 const char* mnemonic = TwoByteMnemonic(opcode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001513 if (operand_size_ == 0x66) {
1514 // 0x66 0x0F prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001515 int mod, regop, rm;
Steve Block6ded16b2010-05-10 14:33:55 +01001516 if (opcode == 0x3A) {
1517 byte third_byte = *current;
1518 current = data + 3;
1519 if (third_byte == 0x17) {
1520 get_modrm(*current, &mod, &regop, &rm);
1521 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1522 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001523 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
Steve Block6ded16b2010-05-10 14:33:55 +01001524 current += 1;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001525 } else if (third_byte == 0x0a) {
1526 get_modrm(*current, &mod, &regop, &rm);
1527 AppendToBuffer("roundss %s,", NameOfXMMRegister(regop));
1528 current += PrintRightXMMOperand(current);
1529 AppendToBuffer(",0x%x", (*current) & 3);
1530 current += 1;
Ben Murdoch257744e2011-11-30 15:57:28 +00001531 } else if (third_byte == 0x0b) {
1532 get_modrm(*current, &mod, &regop, &rm);
1533 // roundsd xmm, xmm/m64, imm8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1535 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 AppendToBuffer(",0x%x", (*current) & 3);
1537 current += 1;
1538 } else if (third_byte == 0x16) {
1539 get_modrm(*current, &mod, &rm, &regop);
1540 AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
1541 current += PrintRightOperand(current);
1542 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1543 current += 1;
1544 } else if (third_byte == 0x22) {
1545 get_modrm(*current, &mod, &regop, &rm);
1546 AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
1547 AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1548 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001549 AppendToBuffer(",%d", (*current) & 3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001550 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001551 } else {
1552 UnimplementedInstruction();
1553 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001555 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001556 if (opcode == 0x1f) {
1557 current++;
1558 if (rm == 4) { // SIB byte present.
1559 current++;
1560 }
1561 if (mod == 1) { // Byte displacement.
1562 current += 1;
1563 } else if (mod == 2) { // 32-bit displacement.
1564 current += 4;
1565 } // else no immediate displacement.
1566 AppendToBuffer("nop");
1567 } else if (opcode == 0x28) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001568 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001569 current += PrintRightXMMOperand(current);
1570 } else if (opcode == 0x29) {
1571 AppendToBuffer("movapd ");
1572 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001573 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001574 } else if (opcode == 0x6E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001575 AppendToBuffer("mov%c %s,",
1576 rex_w() ? 'q' : 'd',
1577 NameOfXMMRegister(regop));
1578 current += PrintRightOperand(current);
Steve Block1e0659c2011-05-24 12:43:12 +01001579 } else if (opcode == 0x6F) {
1580 AppendToBuffer("movdqa %s,",
1581 NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001582 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001583 } else if (opcode == 0x7E) {
Ben Murdochbb769b22010-08-11 14:56:33 +01001584 AppendToBuffer("mov%c ",
1585 rex_w() ? 'q' : 'd');
1586 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001587 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block1e0659c2011-05-24 12:43:12 +01001588 } else if (opcode == 0x7F) {
1589 AppendToBuffer("movdqa ");
Steve Block44f0eee2011-05-26 01:26:41 +01001590 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001591 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001592 } else if (opcode == 0xD6) {
1593 AppendToBuffer("movq ");
1594 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001595 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001596 } else if (opcode == 0x50) {
1597 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1598 current += PrintRightXMMOperand(current);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001599 } else if (opcode == 0x72) {
1600 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001601 AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001602 NameOfXMMRegister(rm), *current & 0x7f);
1603 current += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001604 } else if (opcode == 0x73) {
1605 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001606 AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001607 NameOfXMMRegister(rm), *current & 0x7f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001608 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001609 } else {
1610 const char* mnemonic = "?";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001611 if (opcode == 0x54) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001612 mnemonic = "andpd";
1613 } else if (opcode == 0x56) {
1614 mnemonic = "orpd";
1615 } else if (opcode == 0x57) {
Steve Block6ded16b2010-05-10 14:33:55 +01001616 mnemonic = "xorpd";
1617 } else if (opcode == 0x2E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001618 mnemonic = "ucomisd";
Steve Block8defd9f2010-07-08 12:39:36 +01001619 } else if (opcode == 0x2F) {
1620 mnemonic = "comisd";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001621 } else if (opcode == 0x76) {
1622 mnemonic = "pcmpeqd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001623 } else if (opcode == 0x62) {
1624 mnemonic = "punpckldq";
1625 } else if (opcode == 0x6A) {
1626 mnemonic = "punpckhdq";
Steve Block6ded16b2010-05-10 14:33:55 +01001627 } else {
1628 UnimplementedInstruction();
1629 }
1630 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1631 current += PrintRightXMMOperand(current);
1632 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001633 }
1634 } else if (group_1_prefix_ == 0xF2) {
1635 // Beginning of instructions with prefix 0xF2.
1636
1637 if (opcode == 0x11 || opcode == 0x10) {
1638 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1639 AppendToBuffer("movsd ");
1640 int mod, regop, rm;
1641 get_modrm(*current, &mod, &regop, &rm);
1642 if (opcode == 0x11) {
Steve Block44f0eee2011-05-26 01:26:41 +01001643 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001644 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1645 } else {
1646 AppendToBuffer("%s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001647 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001648 }
1649 } else if (opcode == 0x2A) {
1650 // CVTSI2SD: integer to XMM double conversion.
1651 int mod, regop, rm;
1652 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001653 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Blockd0582a62009-12-15 09:54:21 +00001654 current += PrintRightOperand(current);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001655 } else if (opcode == 0x2C) {
1656 // CVTTSD2SI:
1657 // Convert with truncation scalar double-precision FP to integer.
1658 int mod, regop, rm;
1659 get_modrm(*current, &mod, &regop, &rm);
1660 AppendToBuffer("cvttsd2si%c %s,",
1661 operand_size_code(), NameOfCPURegister(regop));
1662 current += PrintRightXMMOperand(current);
1663 } else if (opcode == 0x2D) {
1664 // CVTSD2SI: Convert scalar double-precision FP to integer.
1665 int mod, regop, rm;
1666 get_modrm(*current, &mod, &regop, &rm);
1667 AppendToBuffer("cvtsd2si%c %s,",
1668 operand_size_code(), NameOfCPURegister(regop));
1669 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001670 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001671 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1672 int mod, regop, rm;
1673 get_modrm(*current, &mod, &regop, &rm);
Steve Blockd0582a62009-12-15 09:54:21 +00001674 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1675 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001676 } else if (opcode == 0xC2) {
1677 // Intel manual 2A, Table 3-18.
1678 int mod, regop, rm;
1679 get_modrm(*current, &mod, &regop, &rm);
1680 const char* const pseudo_op[] = {
1681 "cmpeqsd",
1682 "cmpltsd",
1683 "cmplesd",
1684 "cmpunordsd",
1685 "cmpneqsd",
1686 "cmpnltsd",
1687 "cmpnlesd",
1688 "cmpordsd"
1689 };
1690 AppendToBuffer("%s %s,%s",
1691 pseudo_op[current[1]],
1692 NameOfXMMRegister(regop),
1693 NameOfXMMRegister(rm));
1694 current += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 } else {
1696 UnimplementedInstruction();
1697 }
Steve Block6ded16b2010-05-10 14:33:55 +01001698 } else if (group_1_prefix_ == 0xF3) {
1699 // Instructions with prefix 0xF3.
Steve Block8defd9f2010-07-08 12:39:36 +01001700 if (opcode == 0x11 || opcode == 0x10) {
1701 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1702 AppendToBuffer("movss ");
1703 int mod, regop, rm;
1704 get_modrm(*current, &mod, &regop, &rm);
1705 if (opcode == 0x11) {
1706 current += PrintRightOperand(current);
1707 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1708 } else {
1709 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1710 current += PrintRightOperand(current);
1711 }
1712 } else if (opcode == 0x2A) {
1713 // CVTSI2SS: integer to XMM single conversion.
1714 int mod, regop, rm;
1715 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001716 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Block8defd9f2010-07-08 12:39:36 +01001717 current += PrintRightOperand(current);
1718 } else if (opcode == 0x2C) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001719 // CVTTSS2SI:
1720 // Convert with truncation scalar single-precision FP to dword integer.
Steve Block1e0659c2011-05-24 12:43:12 +01001721 int mod, regop, rm;
1722 get_modrm(*current, &mod, &regop, &rm);
1723 AppendToBuffer("cvttss2si%c %s,",
1724 operand_size_code(), NameOfCPURegister(regop));
1725 current += PrintRightXMMOperand(current);
Ben Murdoch257744e2011-11-30 15:57:28 +00001726 } else if (opcode == 0x7E) {
1727 int mod, regop, rm;
1728 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001729 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001730 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001731 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1732 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1733 int mod, regop, rm;
1734 get_modrm(*current, &mod, &regop, &rm);
1735 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1736 current += PrintRightXMMOperand(current);
1737 } else if (opcode == 0xB8) {
1738 int mod, regop, rm;
1739 get_modrm(*current, &mod, &regop, &rm);
1740 AppendToBuffer("popcnt%c %s,", operand_size_code(),
1741 NameOfCPURegister(regop));
1742 current += PrintRightOperand(current);
1743 } else if (opcode == 0xBC) {
1744 int mod, regop, rm;
1745 get_modrm(*current, &mod, &regop, &rm);
1746 AppendToBuffer("tzcnt%c %s,", operand_size_code(),
1747 NameOfCPURegister(regop));
1748 current += PrintRightOperand(current);
1749 } else if (opcode == 0xBD) {
1750 int mod, regop, rm;
1751 get_modrm(*current, &mod, &regop, &rm);
1752 AppendToBuffer("lzcnt%c %s,", operand_size_code(),
1753 NameOfCPURegister(regop));
1754 current += PrintRightOperand(current);
1755 } else if (opcode == 0xC2) {
1756 // Intel manual 2A, Table 3-18.
1757 int mod, regop, rm;
1758 get_modrm(*current, &mod, &regop, &rm);
1759 const char* const pseudo_op[] = {"cmpeqss", "cmpltss", "cmpless",
1760 "cmpunordss", "cmpneqss", "cmpnltss",
1761 "cmpnless", "cmpordss"};
1762 AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
1763 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
1764 current += 2;
Steve Block6ded16b2010-05-10 14:33:55 +01001765 } else {
1766 UnimplementedInstruction();
1767 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001768 } else if (opcode == 0x1F) {
1769 // NOP
1770 int mod, regop, rm;
1771 get_modrm(*current, &mod, &regop, &rm);
1772 current++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001773 if (rm == 4) { // SIB byte present.
Andrei Popescu402d9372010-02-26 13:31:12 +00001774 current++;
1775 }
1776 if (mod == 1) { // Byte displacement.
1777 current += 1;
1778 } else if (mod == 2) { // 32-bit displacement.
1779 current += 4;
1780 } // else no immediate displacement.
1781 AppendToBuffer("nop");
Ben Murdoch257744e2011-11-30 15:57:28 +00001782
1783 } else if (opcode == 0x28) {
1784 // movaps xmm, xmm/m128
1785 int mod, regop, rm;
1786 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001787 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001788 current += PrintRightXMMOperand(current);
1789
1790 } else if (opcode == 0x29) {
1791 // movaps xmm/m128, xmm
1792 int mod, regop, rm;
1793 get_modrm(*current, &mod, &regop, &rm);
1794 AppendToBuffer("movaps ");
1795 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001796 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001797
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001798 } else if (opcode == 0x2e) {
1799 int mod, regop, rm;
1800 get_modrm(*current, &mod, &regop, &rm);
1801 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1802 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001803 } else if (opcode == 0xA2) {
1804 // CPUID
Andrei Popescu402d9372010-02-26 13:31:12 +00001805 AppendToBuffer("%s", mnemonic);
1806
1807 } else if ((opcode & 0xF0) == 0x40) {
1808 // CMOVcc: conditional move.
1809 int condition = opcode & 0x0F;
1810 const InstructionDesc& idesc = cmov_instructions[condition];
1811 byte_size_operand_ = idesc.byte_size_operation;
1812 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1813
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001814 } else if (opcode >= 0x53 && opcode <= 0x5F) {
1815 const char* const pseudo_op[] = {
1816 "rcpps",
1817 "andps",
1818 "andnps",
1819 "orps",
1820 "xorps",
1821 "addps",
1822 "mulps",
1823 "cvtps2pd",
1824 "cvtdq2ps",
1825 "subps",
1826 "minps",
1827 "divps",
1828 "maxps",
1829 };
Ben Murdoch257744e2011-11-30 15:57:28 +00001830 int mod, regop, rm;
1831 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001832 AppendToBuffer("%s %s,",
1833 pseudo_op[opcode - 0x53],
1834 NameOfXMMRegister(regop));
1835 current += PrintRightXMMOperand(current);
1836
1837 } else if (opcode == 0xC6) {
1838 // shufps xmm, xmm/m128, imm8
1839 int mod, regop, rm;
1840 get_modrm(*current, &mod, &regop, &rm);
1841 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1842 current += PrintRightXMMOperand(current);
1843 AppendToBuffer(", %d", (*current) & 3);
1844 current += 1;
1845
1846 } else if (opcode == 0x50) {
1847 // movmskps reg, xmm
1848 int mod, regop, rm;
1849 get_modrm(*current, &mod, &regop, &rm);
1850 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001851 current += PrintRightXMMOperand(current);
1852
Andrei Popescu402d9372010-02-26 13:31:12 +00001853 } else if ((opcode & 0xF0) == 0x80) {
1854 // Jcc: Conditional jump (branch).
1855 current = data + JumpConditional(data);
1856
1857 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1858 opcode == 0xB7 || opcode == 0xAF) {
1859 // Size-extending moves, IMUL.
1860 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1861
1862 } else if ((opcode & 0xF0) == 0x90) {
1863 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1864 current = data + SetCC(data);
1865
1866 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1867 // SHLD, SHRD (double-precision shift), BTS (bit set).
1868 AppendToBuffer("%s ", mnemonic);
1869 int mod, regop, rm;
1870 get_modrm(*current, &mod, &regop, &rm);
1871 current += PrintRightOperand(current);
1872 if (opcode == 0xAB) {
1873 AppendToBuffer(",%s", NameOfCPURegister(regop));
1874 } else {
1875 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1876 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001877 } else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
1878 // POPCNT, CTZ, CLZ.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1880 int mod, regop, rm;
1881 get_modrm(*current, &mod, &regop, &rm);
1882 AppendToBuffer("%s,", NameOfCPURegister(regop));
1883 current += PrintRightOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001884 } else if (opcode == 0x0B) {
1885 AppendToBuffer("ud2");
Steve Blocka7e24c12009-10-30 11:49:00 +00001886 } else {
1887 UnimplementedInstruction();
1888 }
Steve Blockd0582a62009-12-15 09:54:21 +00001889 return static_cast<int>(current - data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001890}
1891
1892
1893// Mnemonics for two-byte opcode instructions starting with 0x0F.
1894// The argument is the second byte of the two-byte opcode.
1895// Returns NULL if the instruction is not handled here.
1896const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1897 switch (opcode) {
1898 case 0x1F:
1899 return "nop";
Steve Block8defd9f2010-07-08 12:39:36 +01001900 case 0x2A: // F2/F3 prefix.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001901 return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
1902 case 0x51: // F2/F3 prefix.
1903 return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
1904 case 0x58: // F2/F3 prefix.
1905 return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
1906 case 0x59: // F2/F3 prefix.
1907 return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
1908 case 0x5A: // F2/F3 prefix.
1909 return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
1910 case 0x5D: // F2/F3 prefix.
1911 return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
1912 case 0x5C: // F2/F3 prefix.
1913 return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
1914 case 0x5E: // F2/F3 prefix.
1915 return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
1916 case 0x5F: // F2/F3 prefix.
1917 return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
Steve Blocka7e24c12009-10-30 11:49:00 +00001918 case 0xA2:
1919 return "cpuid";
1920 case 0xA5:
1921 return "shld";
1922 case 0xAB:
1923 return "bts";
1924 case 0xAD:
1925 return "shrd";
1926 case 0xAF:
1927 return "imul";
1928 case 0xB6:
1929 return "movzxb";
1930 case 0xB7:
1931 return "movzxw";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001932 case 0xBC:
1933 return "bsf";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001934 case 0xBD:
1935 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 case 0xBE:
1937 return "movsxb";
1938 case 0xBF:
1939 return "movsxw";
1940 default:
1941 return NULL;
1942 }
1943}
1944
1945
1946// Disassembles the instruction at instr, and writes it into out_buffer.
1947int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1948 byte* instr) {
1949 tmp_buffer_pos_ = 0; // starting to write as position 0
1950 byte* data = instr;
1951 bool processed = true; // Will be set to false if the current instruction
1952 // is not in 'instructions' table.
1953 byte current;
1954
1955 // Scan for prefixes.
1956 while (true) {
1957 current = *data;
Leon Clarked91b9f72010-01-27 17:25:45 +00001958 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001959 operand_size_ = current;
1960 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1961 setRex(current);
1962 if (rex_w()) AppendToBuffer("REX.W ");
Leon Clarked91b9f72010-01-27 17:25:45 +00001963 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
Steve Blocka7e24c12009-10-30 11:49:00 +00001964 group_1_prefix_ = current;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001965 } else if (current == VEX3_PREFIX) {
1966 vex_byte0_ = current;
1967 vex_byte1_ = *(data + 1);
1968 vex_byte2_ = *(data + 2);
1969 setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001970 data += 3;
1971 break; // Vex is the last prefix.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001972 } else if (current == VEX2_PREFIX) {
1973 vex_byte0_ = current;
1974 vex_byte1_ = *(data + 1);
1975 setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001976 data += 2;
1977 break; // Vex is the last prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001978 } else { // Not a prefix - an opcode.
1979 break;
1980 }
1981 data++;
1982 }
1983
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001984 // Decode AVX instructions.
1985 if (vex_byte0_ != 0) {
1986 processed = true;
1987 data += AVXInstruction(data);
1988 } else {
1989 const InstructionDesc& idesc = instruction_table_->Get(current);
1990 byte_size_operand_ = idesc.byte_size_operation;
1991 switch (idesc.type) {
1992 case ZERO_OPERANDS_INSTR:
1993 if (current >= 0xA4 && current <= 0xA7) {
1994 // String move or compare operations.
1995 if (group_1_prefix_ == REP_PREFIX) {
1996 // REP.
1997 AppendToBuffer("rep ");
1998 }
1999 if (rex_w()) AppendToBuffer("REX.W ");
2000 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2001 } else {
2002 AppendToBuffer("%s", idesc.mnem, operand_size_code());
Leon Clarked91b9f72010-01-27 17:25:45 +00002003 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002004 data++;
2005 break;
2006
2007 case TWO_OPERANDS_INSTR:
2008 data++;
2009 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
2010 break;
2011
2012 case JUMP_CONDITIONAL_SHORT_INSTR:
2013 data += JumpConditionalShort(data);
2014 break;
2015
2016 case REGISTER_INSTR:
2017 AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
2018 NameOfCPURegister(base_reg(current & 0x07)));
2019 data++;
2020 break;
2021 case PUSHPOP_INSTR:
2022 AppendToBuffer("%s %s", idesc.mnem,
2023 NameOfCPURegister(base_reg(current & 0x07)));
2024 data++;
2025 break;
2026 case MOVE_REG_INSTR: {
2027 byte* addr = NULL;
2028 switch (operand_size()) {
2029 case OPERAND_WORD_SIZE:
2030 addr =
2031 reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
2032 data += 3;
2033 break;
2034 case OPERAND_DOUBLEWORD_SIZE:
2035 addr =
2036 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
2037 data += 5;
2038 break;
2039 case OPERAND_QUADWORD_SIZE:
2040 addr =
2041 reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
2042 data += 9;
2043 break;
2044 default:
2045 UNREACHABLE();
2046 }
2047 AppendToBuffer("mov%c %s,%s", operand_size_code(),
2048 NameOfCPURegister(base_reg(current & 0x07)),
2049 NameOfAddress(addr));
2050 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00002051 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002052
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002053 case CALL_JUMP_INSTR: {
2054 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
2055 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
2056 data += 5;
2057 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002058 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002059
2060 case SHORT_IMMEDIATE_INSTR: {
2061 byte* addr =
2062 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
2063 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
2064 data += 5;
2065 break;
2066 }
2067
2068 case NO_INSTR:
2069 processed = false;
2070 break;
2071
2072 default:
2073 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00002074 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002075 }
2076
2077 // The first byte didn't match any of the simple opcodes, so we
2078 // need to do special processing on it.
2079 if (!processed) {
2080 switch (*data) {
2081 case 0xC2:
2082 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
2083 data += 3;
2084 break;
2085
2086 case 0x69: // fall through
2087 case 0x6B: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002088 int count = 1;
2089 count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
2090 AppendToBuffer(",0x");
2091 if (*data == 0x69) {
2092 count += PrintImmediate(data + count, operand_size());
2093 } else {
2094 count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
2095 }
2096 data += count;
Steve Blocka7e24c12009-10-30 11:49:00 +00002097 break;
2098 }
2099
Steve Blocka7e24c12009-10-30 11:49:00 +00002100 case 0x81: // fall through
2101 case 0x83: // 0x81 with sign extension bit set
2102 data += PrintImmediateOp(data);
2103 break;
2104
2105 case 0x0F:
2106 data += TwoByteOpcodeInstruction(data);
2107 break;
2108
2109 case 0x8F: {
2110 data++;
2111 int mod, regop, rm;
2112 get_modrm(*data, &mod, &regop, &rm);
2113 if (regop == 0) {
2114 AppendToBuffer("pop ");
2115 data += PrintRightOperand(data);
2116 }
2117 }
2118 break;
2119
2120 case 0xFF: {
2121 data++;
2122 int mod, regop, rm;
2123 get_modrm(*data, &mod, &regop, &rm);
2124 const char* mnem = NULL;
2125 switch (regop) {
2126 case 0:
2127 mnem = "inc";
2128 break;
2129 case 1:
2130 mnem = "dec";
2131 break;
2132 case 2:
2133 mnem = "call";
2134 break;
2135 case 4:
2136 mnem = "jmp";
2137 break;
2138 case 6:
2139 mnem = "push";
2140 break;
2141 default:
2142 mnem = "???";
2143 }
2144 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
2145 mnem,
2146 operand_size_code());
2147 data += PrintRightOperand(data);
2148 }
2149 break;
2150
2151 case 0xC7: // imm32, fall through
2152 case 0xC6: // imm8
2153 {
2154 bool is_byte = *data == 0xC6;
2155 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01002156 if (is_byte) {
2157 AppendToBuffer("movb ");
2158 data += PrintRightByteOperand(data);
2159 int32_t imm = *data;
2160 AppendToBuffer(",0x%x", imm);
2161 data++;
2162 } else {
2163 AppendToBuffer("mov%c ", operand_size_code());
2164 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002165 if (operand_size() == OPERAND_WORD_SIZE) {
2166 int16_t imm = *reinterpret_cast<int16_t*>(data);
2167 AppendToBuffer(",0x%x", imm);
2168 data += 2;
2169 } else {
2170 int32_t imm = *reinterpret_cast<int32_t*>(data);
2171 AppendToBuffer(",0x%x", imm);
2172 data += 4;
2173 }
Steve Block44f0eee2011-05-26 01:26:41 +01002174 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002175 }
2176 break;
2177
2178 case 0x80: {
2179 data++;
2180 AppendToBuffer("cmpb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002181 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002182 int32_t imm = *data;
2183 AppendToBuffer(",0x%x", imm);
2184 data++;
2185 }
2186 break;
2187
2188 case 0x88: // 8bit, fall through
2189 case 0x89: // 32bit
2190 {
2191 bool is_byte = *data == 0x88;
2192 int mod, regop, rm;
2193 data++;
2194 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002195 if (is_byte) {
2196 AppendToBuffer("movb ");
2197 data += PrintRightByteOperand(data);
2198 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2199 } else {
2200 AppendToBuffer("mov%c ", operand_size_code());
2201 data += PrintRightOperand(data);
2202 AppendToBuffer(",%s", NameOfCPURegister(regop));
2203 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002204 }
2205 break;
2206
2207 case 0x90:
2208 case 0x91:
2209 case 0x92:
2210 case 0x93:
2211 case 0x94:
2212 case 0x95:
2213 case 0x96:
2214 case 0x97: {
Steve Blockd0582a62009-12-15 09:54:21 +00002215 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002216 if (reg == 0) {
2217 AppendToBuffer("nop"); // Common name for xchg rax,rax.
2218 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002219 AppendToBuffer("xchg%c rax,%s",
Steve Blocka7e24c12009-10-30 11:49:00 +00002220 operand_size_code(),
2221 NameOfCPURegister(reg));
2222 }
Steve Blockd0582a62009-12-15 09:54:21 +00002223 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00002224 }
Steve Blockd0582a62009-12-15 09:54:21 +00002225 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002226 case 0xB0:
2227 case 0xB1:
2228 case 0xB2:
2229 case 0xB3:
2230 case 0xB4:
2231 case 0xB5:
2232 case 0xB6:
2233 case 0xB7:
2234 case 0xB8:
2235 case 0xB9:
2236 case 0xBA:
2237 case 0xBB:
2238 case 0xBC:
2239 case 0xBD:
2240 case 0xBE:
2241 case 0xBF: {
2242 // mov reg8,imm8 or mov reg32,imm32
2243 byte opcode = *data;
2244 data++;
2245 bool is_32bit = (opcode >= 0xB8);
2246 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
2247 if (is_32bit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002248 AppendToBuffer("mov%c %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002249 operand_size_code(),
2250 NameOfCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002251 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002252 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002253 AppendToBuffer("movb %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002254 NameOfByteCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002255 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002256 }
2257 break;
2258 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002259 case 0xFE: {
2260 data++;
2261 int mod, regop, rm;
2262 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002263 if (regop == 1) {
2264 AppendToBuffer("decb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002265 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002266 } else {
2267 UnimplementedInstruction();
2268 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002269 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002270 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002271 case 0x68:
2272 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
2273 data += 5;
2274 break;
2275
2276 case 0x6A:
2277 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
2278 data += 2;
2279 break;
2280
2281 case 0xA1: // Fall through.
2282 case 0xA3:
2283 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002284 case OPERAND_DOUBLEWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002285 const char* memory_location = NameOfAddress(
2286 reinterpret_cast<byte*>(
2287 *reinterpret_cast<int32_t*>(data + 1)));
2288 if (*data == 0xA1) { // Opcode 0xA1
2289 AppendToBuffer("movzxlq rax,(%s)", memory_location);
2290 } else { // Opcode 0xA3
2291 AppendToBuffer("movzxlq (%s),rax", memory_location);
2292 }
2293 data += 5;
2294 break;
2295 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002296 case OPERAND_QUADWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002297 // New x64 instruction mov rax,(imm_64).
2298 const char* memory_location = NameOfAddress(
2299 *reinterpret_cast<byte**>(data + 1));
2300 if (*data == 0xA1) { // Opcode 0xA1
2301 AppendToBuffer("movq rax,(%s)", memory_location);
2302 } else { // Opcode 0xA3
2303 AppendToBuffer("movq (%s),rax", memory_location);
2304 }
2305 data += 9;
2306 break;
2307 }
2308 default:
2309 UnimplementedInstruction();
2310 data += 2;
2311 }
2312 break;
2313
2314 case 0xA8:
2315 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
2316 data += 2;
2317 break;
2318
2319 case 0xA9: {
2320 int64_t value = 0;
2321 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002322 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002323 value = *reinterpret_cast<uint16_t*>(data + 1);
2324 data += 3;
2325 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002326 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002327 value = *reinterpret_cast<uint32_t*>(data + 1);
2328 data += 5;
2329 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002330 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002331 value = *reinterpret_cast<int32_t*>(data + 1);
2332 data += 5;
2333 break;
2334 default:
2335 UNREACHABLE();
2336 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002337 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
Steve Blocka7e24c12009-10-30 11:49:00 +00002338 operand_size_code(),
2339 value);
2340 break;
2341 }
2342 case 0xD1: // fall through
2343 case 0xD3: // fall through
2344 case 0xC1:
2345 data += ShiftInstruction(data);
2346 break;
2347 case 0xD0: // fall through
2348 case 0xD2: // fall through
2349 case 0xC0:
2350 byte_size_operand_ = true;
2351 data += ShiftInstruction(data);
2352 break;
2353
2354 case 0xD9: // fall through
2355 case 0xDA: // fall through
2356 case 0xDB: // fall through
2357 case 0xDC: // fall through
2358 case 0xDD: // fall through
2359 case 0xDE: // fall through
2360 case 0xDF:
2361 data += FPUInstruction(data);
2362 break;
2363
2364 case 0xEB:
2365 data += JumpShort(data);
2366 break;
2367
Steve Blockd0582a62009-12-15 09:54:21 +00002368 case 0xF6:
2369 byte_size_operand_ = true; // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00002370 case 0xF7:
Steve Blockd0582a62009-12-15 09:54:21 +00002371 data += F6F7Instruction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002372 break;
2373
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002374 case 0x3C:
2375 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2376 data +=2;
2377 break;
2378
Steve Blocka7e24c12009-10-30 11:49:00 +00002379 default:
2380 UnimplementedInstruction();
2381 data += 1;
2382 }
2383 } // !processed
2384
2385 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2386 tmp_buffer_[tmp_buffer_pos_] = '\0';
2387 }
2388
Steve Blockd0582a62009-12-15 09:54:21 +00002389 int instr_len = static_cast<int>(data - instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002390 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002391
2392 int outp = 0;
2393 // Instruction bytes.
2394 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002395 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002396 }
2397 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002398 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002399 }
2400
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002401 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2402 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002403 return instr_len;
2404}
2405
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002406
Steve Blocka7e24c12009-10-30 11:49:00 +00002407//------------------------------------------------------------------------------
2408
2409
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002410static const char* const cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002411 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2412 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2413};
2414
2415
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002416static const char* const byte_cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002417 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2418 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2419};
2420
2421
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002422static const char* const xmm_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002423 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2424 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2425};
2426
2427
2428const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002429 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002430 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002431}
2432
2433
2434const char* NameConverter::NameOfConstant(byte* addr) const {
2435 return NameOfAddress(addr);
2436}
2437
2438
2439const char* NameConverter::NameOfCPURegister(int reg) const {
2440 if (0 <= reg && reg < 16)
2441 return cpu_regs[reg];
2442 return "noreg";
2443}
2444
2445
2446const char* NameConverter::NameOfByteCPURegister(int reg) const {
2447 if (0 <= reg && reg < 16)
2448 return byte_cpu_regs[reg];
2449 return "noreg";
2450}
2451
2452
2453const char* NameConverter::NameOfXMMRegister(int reg) const {
2454 if (0 <= reg && reg < 16)
2455 return xmm_regs[reg];
2456 return "noxmmreg";
2457}
2458
2459
2460const char* NameConverter::NameInCode(byte* addr) const {
2461 // X64 does not embed debug strings at the moment.
2462 UNREACHABLE();
2463 return "";
2464}
2465
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466
Steve Blocka7e24c12009-10-30 11:49:00 +00002467//------------------------------------------------------------------------------
2468
2469Disassembler::Disassembler(const NameConverter& converter)
2470 : converter_(converter) { }
2471
2472Disassembler::~Disassembler() { }
2473
2474
2475int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2476 byte* instruction) {
2477 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2478 return d.InstructionDecode(buffer, instruction);
2479}
2480
2481
2482// The X64 assembler does not use constant pools.
2483int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2484 return -1;
2485}
2486
2487
2488void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2489 NameConverter converter;
2490 Disassembler d(converter);
2491 for (byte* pc = begin; pc < end;) {
2492 v8::internal::EmbeddedVector<char, 128> buffer;
2493 buffer[0] = '\0';
2494 byte* prev_pc = pc;
2495 pc += d.InstructionDecode(buffer, pc);
2496 fprintf(f, "%p", prev_pc);
2497 fprintf(f, " ");
2498
2499 for (byte* bp = prev_pc; bp < pc; bp++) {
2500 fprintf(f, "%02x", *bp);
2501 }
Steve Blockd0582a62009-12-15 09:54:21 +00002502 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002503 fprintf(f, " ");
2504 }
2505 fprintf(f, " %s\n", buffer.start());
2506 }
2507}
2508
2509} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002510
2511#endif // V8_TARGET_ARCH_X64