blob: 75adc8988f5d63d84b14ab0c3410e6cb1a1c0457 [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#include "src/v8.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010010
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#if V8_TARGET_ARCH_X64
Leon Clarkef7060e22010-06-03 12:02:55 +010012
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/base/lazy-instance.h"
14#include "src/disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000015
16namespace disasm {
17
18enum OperandType {
19 UNSET_OP_ORDER = 0,
20 // Operand size decides between 16, 32 and 64 bit operands.
21 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
22 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
23 // Fixed 8-bit operands.
24 BYTE_SIZE_OPERAND_FLAG = 4,
25 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
26 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
27};
28
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029
Steve Blocka7e24c12009-10-30 11:49:00 +000030//------------------------------------------------------------------
31// Tables
32//------------------------------------------------------------------
33struct ByteMnemonic {
34 int b; // -1 terminates, otherwise must be in range (0..255)
35 OperandType op_order_;
36 const char* mnem;
37};
38
39
Ben Murdoch69a99ed2011-11-30 16:03:39 +000040static const ByteMnemonic two_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000041 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
42 { 0x01, OPER_REG_OP_ORDER, "add" },
43 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
44 { 0x03, REG_OPER_OP_ORDER, "add" },
45 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
46 { 0x09, OPER_REG_OP_ORDER, "or" },
47 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
48 { 0x0B, REG_OPER_OP_ORDER, "or" },
49 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
50 { 0x11, OPER_REG_OP_ORDER, "adc" },
51 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
52 { 0x13, REG_OPER_OP_ORDER, "adc" },
53 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
54 { 0x19, OPER_REG_OP_ORDER, "sbb" },
55 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
56 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
57 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
58 { 0x21, OPER_REG_OP_ORDER, "and" },
59 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
60 { 0x23, REG_OPER_OP_ORDER, "and" },
61 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
62 { 0x29, OPER_REG_OP_ORDER, "sub" },
63 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
64 { 0x2B, REG_OPER_OP_ORDER, "sub" },
65 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
66 { 0x31, OPER_REG_OP_ORDER, "xor" },
67 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
68 { 0x33, REG_OPER_OP_ORDER, "xor" },
69 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
70 { 0x39, OPER_REG_OP_ORDER, "cmp" },
71 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
72 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 { 0x63, REG_OPER_OP_ORDER, "movsxl" },
Steve Blocka7e24c12009-10-30 11:49:00 +000074 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
75 { 0x85, REG_OPER_OP_ORDER, "test" },
76 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
77 { 0x87, REG_OPER_OP_ORDER, "xchg" },
78 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
79 { 0x89, OPER_REG_OP_ORDER, "mov" },
80 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
81 { 0x8B, REG_OPER_OP_ORDER, "mov" },
82 { 0x8D, REG_OPER_OP_ORDER, "lea" },
83 { -1, UNSET_OP_ORDER, "" }
84};
85
86
Ben Murdoch69a99ed2011-11-30 16:03:39 +000087static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000088 { 0xC3, UNSET_OP_ORDER, "ret" },
89 { 0xC9, UNSET_OP_ORDER, "leave" },
90 { 0xF4, UNSET_OP_ORDER, "hlt" },
Ben Murdoch3ef787d2012-04-12 10:51:47 +010091 { 0xFC, UNSET_OP_ORDER, "cld" },
Steve Blocka7e24c12009-10-30 11:49:00 +000092 { 0xCC, UNSET_OP_ORDER, "int3" },
93 { 0x60, UNSET_OP_ORDER, "pushad" },
94 { 0x61, UNSET_OP_ORDER, "popad" },
95 { 0x9C, UNSET_OP_ORDER, "pushfd" },
96 { 0x9D, UNSET_OP_ORDER, "popfd" },
97 { 0x9E, UNSET_OP_ORDER, "sahf" },
98 { 0x99, UNSET_OP_ORDER, "cdq" },
99 { 0x9B, UNSET_OP_ORDER, "fwait" },
Leon Clarked91b9f72010-01-27 17:25:45 +0000100 { 0xA4, UNSET_OP_ORDER, "movs" },
101 { 0xA5, UNSET_OP_ORDER, "movs" },
102 { 0xA6, UNSET_OP_ORDER, "cmps" },
103 { 0xA7, UNSET_OP_ORDER, "cmps" },
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 { -1, UNSET_OP_ORDER, "" }
105};
106
107
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000108static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 { 0xE8, UNSET_OP_ORDER, "call" },
110 { 0xE9, UNSET_OP_ORDER, "jmp" },
111 { -1, UNSET_OP_ORDER, "" }
112};
113
114
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000115static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000116 { 0x05, UNSET_OP_ORDER, "add" },
117 { 0x0D, UNSET_OP_ORDER, "or" },
118 { 0x15, UNSET_OP_ORDER, "adc" },
119 { 0x1D, UNSET_OP_ORDER, "sbb" },
120 { 0x25, UNSET_OP_ORDER, "and" },
121 { 0x2D, UNSET_OP_ORDER, "sub" },
122 { 0x35, UNSET_OP_ORDER, "xor" },
123 { 0x3D, UNSET_OP_ORDER, "cmp" },
124 { -1, UNSET_OP_ORDER, "" }
125};
126
127
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000128static const char* const conditional_code_suffix[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 "o", "no", "c", "nc", "z", "nz", "na", "a",
130 "s", "ns", "pe", "po", "l", "ge", "le", "g"
131};
132
133
134enum InstructionType {
135 NO_INSTR,
136 ZERO_OPERANDS_INSTR,
137 TWO_OPERANDS_INSTR,
138 JUMP_CONDITIONAL_SHORT_INSTR,
139 REGISTER_INSTR,
140 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
141 MOVE_REG_INSTR,
142 CALL_JUMP_INSTR,
143 SHORT_IMMEDIATE_INSTR
144};
145
146
Leon Clarked91b9f72010-01-27 17:25:45 +0000147enum Prefixes {
148 ESCAPE_PREFIX = 0x0F,
149 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
150 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400151 VEX3_PREFIX = 0xC4,
152 VEX2_PREFIX = 0xC5,
Leon Clarked91b9f72010-01-27 17:25:45 +0000153 REPNE_PREFIX = 0xF2,
154 REP_PREFIX = 0xF3,
155 REPEQ_PREFIX = REP_PREFIX
156};
157
158
Steve Blocka7e24c12009-10-30 11:49:00 +0000159struct InstructionDesc {
160 const char* mnem;
161 InstructionType type;
162 OperandType op_order_;
163 bool byte_size_operation; // Fixed 8-bit operation.
164};
165
166
167class InstructionTable {
168 public:
169 InstructionTable();
170 const InstructionDesc& Get(byte x) const {
171 return instructions_[x];
172 }
173
174 private:
175 InstructionDesc instructions_[256];
176 void Clear();
177 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000178 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
180 const char* mnem);
181 void AddJumpConditionalShort();
182};
183
184
185InstructionTable::InstructionTable() {
186 Clear();
187 Init();
188}
189
190
191void InstructionTable::Clear() {
192 for (int i = 0; i < 256; i++) {
193 instructions_[i].mnem = "(bad)";
194 instructions_[i].type = NO_INSTR;
195 instructions_[i].op_order_ = UNSET_OP_ORDER;
196 instructions_[i].byte_size_operation = false;
197 }
198}
199
200
201void InstructionTable::Init() {
202 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
203 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
204 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
205 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
206 AddJumpConditionalShort();
207 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
208 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
209 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
210}
211
212
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000213void InstructionTable::CopyTable(const ByteMnemonic bm[],
214 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 for (int i = 0; bm[i].b >= 0; i++) {
216 InstructionDesc* id = &instructions_[bm[i].b];
217 id->mnem = bm[i].mnem;
218 OperandType op_order = bm[i].op_order_;
219 id->op_order_ =
220 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 id->type = type;
223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
224 }
225}
226
227
228void InstructionTable::SetTableRange(InstructionType type,
229 byte start,
230 byte end,
231 bool byte_size,
232 const char* mnem) {
233 for (byte b = start; b <= end; b++) {
234 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 id->mnem = mnem;
237 id->type = type;
238 id->byte_size_operation = byte_size;
239 }
240}
241
242
243void InstructionTable::AddJumpConditionalShort() {
244 for (byte b = 0x70; b <= 0x7F; b++) {
245 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000247 id->mnem = NULL; // Computed depending on condition code.
248 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
249 }
250}
251
252
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000253static v8::base::LazyInstance<InstructionTable>::type instruction_table =
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100254 LAZY_INSTANCE_INITIALIZER;
Steve Blocka7e24c12009-10-30 11:49:00 +0000255
Steve Block44f0eee2011-05-26 01:26:41 +0100256
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400257static const InstructionDesc cmov_instructions[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000258 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
272 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
273 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
274};
275
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276
Steve Blocka7e24c12009-10-30 11:49:00 +0000277//------------------------------------------------------------------------------
278// DisassemblerX64 implementation.
279
280enum UnimplementedOpcodeAction {
281 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
282 ABORT_ON_UNIMPLEMENTED_OPCODE
283};
284
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000285
Steve Blocka7e24c12009-10-30 11:49:00 +0000286// A new DisassemblerX64 object is created to disassemble each instruction.
287// The object can only disassemble a single instruction.
288class DisassemblerX64 {
289 public:
290 DisassemblerX64(const NameConverter& converter,
291 UnimplementedOpcodeAction unimplemented_action =
292 ABORT_ON_UNIMPLEMENTED_OPCODE)
293 : converter_(converter),
294 tmp_buffer_pos_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400295 abort_on_unimplemented_(unimplemented_action ==
296 ABORT_ON_UNIMPLEMENTED_OPCODE),
Steve Blocka7e24c12009-10-30 11:49:00 +0000297 rex_(0),
298 operand_size_(0),
299 group_1_prefix_(0),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400300 vex_byte0_(0),
301 vex_byte1_(0),
302 vex_byte2_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000303 byte_size_operand_(false),
304 instruction_table_(instruction_table.Pointer()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 tmp_buffer_[0] = '\0';
306 }
307
308 virtual ~DisassemblerX64() {
309 }
310
311 // Writes one disassembled instruction into 'buffer' (0-terminated).
312 // Returns the length of the disassembled machine instruction in bytes.
313 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
314
315 private:
316 enum OperandSize {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000317 OPERAND_BYTE_SIZE = 0,
318 OPERAND_WORD_SIZE = 1,
319 OPERAND_DOUBLEWORD_SIZE = 2,
320 OPERAND_QUADWORD_SIZE = 3
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 };
322
323 const NameConverter& converter_;
324 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
325 unsigned int tmp_buffer_pos_;
326 bool abort_on_unimplemented_;
327 // Prefixes parsed
328 byte rex_;
329 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
330 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400331 byte vex_byte0_; // 0xc4 or 0xc5
332 byte vex_byte1_;
333 byte vex_byte2_; // only for 3 bytes vex prefix
Steve Blocka7e24c12009-10-30 11:49:00 +0000334 // Byte size operand override.
335 bool byte_size_operand_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336 const InstructionTable* const instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000337
338 void setRex(byte rex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 DCHECK_EQ(0x40, rex & 0xF0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 rex_ = rex;
341 }
342
343 bool rex() { return rex_ != 0; }
344
345 bool rex_b() { return (rex_ & 0x01) != 0; }
346
347 // Actual number of base register given the low bits and the rex.b state.
348 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
349
350 bool rex_x() { return (rex_ & 0x02) != 0; }
351
352 bool rex_r() { return (rex_ & 0x04) != 0; }
353
354 bool rex_w() { return (rex_ & 0x08) != 0; }
355
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400356 bool vex_128() {
357 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
358 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
359 return (checked & 4) != 1;
360 }
361
362 bool vex_66() {
363 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
364 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
365 return (checked & 3) == 1;
366 }
367
368 bool vex_f3() {
369 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
370 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
371 return (checked & 3) == 2;
372 }
373
374 bool vex_f2() {
375 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
376 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
377 return (checked & 3) == 3;
378 }
379
380 bool vex_0f() {
381 if (vex_byte0_ == VEX2_PREFIX) return true;
382 return (vex_byte1_ & 3) == 1;
383 }
384
385 bool vex_0f38() {
386 if (vex_byte0_ == VEX2_PREFIX) return false;
387 return (vex_byte1_ & 3) == 2;
388 }
389
390 bool vex_0f3a() {
391 if (vex_byte0_ == VEX2_PREFIX) return false;
392 return (vex_byte1_ & 3) == 3;
393 }
394
395 int vex_vreg() {
396 DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
397 byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
398 return ~(checked >> 3) & 0xf;
399 }
400
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 OperandSize operand_size() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000402 if (byte_size_operand_) return OPERAND_BYTE_SIZE;
403 if (rex_w()) return OPERAND_QUADWORD_SIZE;
404 if (operand_size_ != 0) return OPERAND_WORD_SIZE;
405 return OPERAND_DOUBLEWORD_SIZE;
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 }
407
408 char operand_size_code() {
409 return "bwlq"[operand_size()];
410 }
411
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400412 char float_size_code() { return "sd"[rex_w()]; }
413
Steve Blocka7e24c12009-10-30 11:49:00 +0000414 const char* NameOfCPURegister(int reg) const {
415 return converter_.NameOfCPURegister(reg);
416 }
417
418 const char* NameOfByteCPURegister(int reg) const {
419 return converter_.NameOfByteCPURegister(reg);
420 }
421
422 const char* NameOfXMMRegister(int reg) const {
423 return converter_.NameOfXMMRegister(reg);
424 }
425
426 const char* NameOfAddress(byte* addr) const {
427 return converter_.NameOfAddress(addr);
428 }
429
430 // Disassembler helper functions.
431 void get_modrm(byte data,
432 int* mod,
433 int* regop,
434 int* rm) {
435 *mod = (data >> 6) & 3;
436 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
437 *rm = (data & 7) | (rex_b() ? 8 : 0);
438 }
439
440 void get_sib(byte data,
441 int* scale,
442 int* index,
443 int* base) {
444 *scale = (data >> 6) & 3;
445 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
446 *base = (data & 7) | (rex_b() ? 8 : 0);
447 }
448
449 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
450
451 int PrintRightOperandHelper(byte* modrmp,
452 RegisterNameMapping register_name);
453 int PrintRightOperand(byte* modrmp);
454 int PrintRightByteOperand(byte* modrmp);
Steve Blockd0582a62009-12-15 09:54:21 +0000455 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000456 int PrintOperands(const char* mnem,
457 OperandType op_order,
458 byte* data);
459 int PrintImmediate(byte* data, OperandSize size);
460 int PrintImmediateOp(byte* data);
461 const char* TwoByteMnemonic(byte opcode);
462 int TwoByteOpcodeInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000463 int F6F7Instruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 int ShiftInstruction(byte* data);
465 int JumpShort(byte* data);
466 int JumpConditional(byte* data);
467 int JumpConditionalShort(byte* data);
468 int SetCC(byte* data);
469 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000470 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
471 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400472 int AVXInstruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 void AppendToBuffer(const char* format, ...);
474
475 void UnimplementedInstruction() {
476 if (abort_on_unimplemented_) {
477 CHECK(false);
478 } else {
479 AppendToBuffer("'Unimplemented Instruction'");
480 }
481 }
482};
483
484
485void DisassemblerX64::AppendToBuffer(const char* format, ...) {
486 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
487 va_list args;
488 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000490 va_end(args);
491 tmp_buffer_pos_ += result;
492}
493
494
495int DisassemblerX64::PrintRightOperandHelper(
496 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100497 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000498 int mod, regop, rm;
499 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100500 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
501 &DisassemblerX64::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 switch (mod) {
503 case 0:
504 if ((rm & 7) == 5) {
505 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
506 AppendToBuffer("[0x%x]", disp);
507 return 5;
508 } else if ((rm & 7) == 4) {
509 // Codes for SIB byte.
510 byte sib = *(modrmp + 1);
511 int scale, index, base;
512 get_sib(sib, &scale, &index, &base);
513 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
514 // index == rsp means no index. Only use sib byte with no index for
515 // rsp and r12 base.
Steve Block8defd9f2010-07-08 12:39:36 +0100516 AppendToBuffer("[%s]", NameOfCPURegister(base));
Steve Blocka7e24c12009-10-30 11:49:00 +0000517 return 2;
518 } else if (base == 5) {
519 // base == rbp means no base register (when mod == 0).
520 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000521 AppendToBuffer("[%s*%d%s0x%x]",
Steve Block8defd9f2010-07-08 12:39:36 +0100522 NameOfCPURegister(index),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000523 1 << scale,
524 disp < 0 ? "-" : "+",
525 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 return 6;
527 } else if (index != 4 && base != 5) {
528 // [base+index*scale]
529 AppendToBuffer("[%s+%s*%d]",
Steve Block8defd9f2010-07-08 12:39:36 +0100530 NameOfCPURegister(base),
531 NameOfCPURegister(index),
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 1 << scale);
533 return 2;
534 } else {
535 UnimplementedInstruction();
536 return 1;
537 }
538 } else {
Steve Block8defd9f2010-07-08 12:39:36 +0100539 AppendToBuffer("[%s]", NameOfCPURegister(rm));
Steve Blocka7e24c12009-10-30 11:49:00 +0000540 return 1;
541 }
542 break;
543 case 1: // fall through
544 case 2:
545 if ((rm & 7) == 4) {
546 byte sib = *(modrmp + 1);
547 int scale, index, base;
548 get_sib(sib, &scale, &index, &base);
549 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000551 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 AppendToBuffer("[%s%s0x%x]",
553 NameOfCPURegister(base),
554 disp < 0 ? "-" : "+",
555 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000556 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000557 AppendToBuffer("[%s+%s*%d%s0x%x]",
558 NameOfCPURegister(base),
559 NameOfCPURegister(index),
560 1 << scale,
561 disp < 0 ? "-" : "+",
562 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 }
564 return mod == 2 ? 6 : 3;
565 } else {
566 // No sib.
567 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000568 : *reinterpret_cast<int8_t*>(modrmp + 1);
569 AppendToBuffer("[%s%s0x%x]",
570 NameOfCPURegister(rm),
571 disp < 0 ? "-" : "+",
572 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 return (mod == 2) ? 5 : 2;
574 }
575 break;
576 case 3:
577 AppendToBuffer("%s", (this->*register_name)(rm));
578 return 1;
579 default:
580 UnimplementedInstruction();
581 return 1;
582 }
583 UNREACHABLE();
584}
585
586
587int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
588 int64_t value;
589 int count;
590 switch (size) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000591 case OPERAND_BYTE_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 value = *data;
593 count = 1;
594 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000595 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000596 value = *reinterpret_cast<int16_t*>(data);
597 count = 2;
598 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000599 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000600 value = *reinterpret_cast<uint32_t*>(data);
601 count = 4;
602 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000603 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 value = *reinterpret_cast<int32_t*>(data);
605 count = 4;
606 break;
607 default:
608 UNREACHABLE();
609 value = 0; // Initialize variables on all paths to satisfy the compiler.
610 count = 0;
611 }
612 AppendToBuffer("%" V8_PTR_PREFIX "x", value);
613 return count;
614}
615
616
617int DisassemblerX64::PrintRightOperand(byte* modrmp) {
618 return PrintRightOperandHelper(modrmp,
619 &DisassemblerX64::NameOfCPURegister);
620}
621
622
623int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
624 return PrintRightOperandHelper(modrmp,
625 &DisassemblerX64::NameOfByteCPURegister);
626}
627
628
Steve Blockd0582a62009-12-15 09:54:21 +0000629int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
630 return PrintRightOperandHelper(modrmp,
631 &DisassemblerX64::NameOfXMMRegister);
632}
633
634
Steve Blocka7e24c12009-10-30 11:49:00 +0000635// Returns number of bytes used including the current *data.
636// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
637int DisassemblerX64::PrintOperands(const char* mnem,
638 OperandType op_order,
639 byte* data) {
640 byte modrm = *data;
641 int mod, regop, rm;
642 get_modrm(modrm, &mod, &regop, &rm);
643 int advance = 0;
644 const char* register_name =
645 byte_size_operand_ ? NameOfByteCPURegister(regop)
646 : NameOfCPURegister(regop);
647 switch (op_order) {
648 case REG_OPER_OP_ORDER: {
649 AppendToBuffer("%s%c %s,",
650 mnem,
651 operand_size_code(),
652 register_name);
653 advance = byte_size_operand_ ? PrintRightByteOperand(data)
654 : PrintRightOperand(data);
655 break;
656 }
657 case OPER_REG_OP_ORDER: {
658 AppendToBuffer("%s%c ", mnem, operand_size_code());
659 advance = byte_size_operand_ ? PrintRightByteOperand(data)
660 : PrintRightOperand(data);
661 AppendToBuffer(",%s", register_name);
662 break;
663 }
664 default:
665 UNREACHABLE();
666 break;
667 }
668 return advance;
669}
670
671
672// Returns number of bytes used by machine instruction, including *data byte.
673// Writes immediate instructions to 'tmp_buffer_'.
674int DisassemblerX64::PrintImmediateOp(byte* data) {
675 bool byte_size_immediate = (*data & 0x02) != 0;
676 byte modrm = *(data + 1);
677 int mod, regop, rm;
678 get_modrm(modrm, &mod, &regop, &rm);
679 const char* mnem = "Imm???";
680 switch (regop) {
681 case 0:
682 mnem = "add";
683 break;
684 case 1:
685 mnem = "or";
686 break;
687 case 2:
688 mnem = "adc";
689 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100690 case 3:
691 mnem = "sbb";
692 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 case 4:
694 mnem = "and";
695 break;
696 case 5:
697 mnem = "sub";
698 break;
699 case 6:
700 mnem = "xor";
701 break;
702 case 7:
703 mnem = "cmp";
704 break;
705 default:
706 UnimplementedInstruction();
707 }
708 AppendToBuffer("%s%c ", mnem, operand_size_code());
709 int count = PrintRightOperand(data + 1);
710 AppendToBuffer(",0x");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711 OperandSize immediate_size =
712 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
Steve Blocka7e24c12009-10-30 11:49:00 +0000713 count += PrintImmediate(data + 1 + count, immediate_size);
714 return 1 + count;
715}
716
717
718// Returns number of bytes used, including *data.
Steve Blockd0582a62009-12-15 09:54:21 +0000719int DisassemblerX64::F6F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000720 DCHECK(*data == 0xF7 || *data == 0xF6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000721 byte modrm = *(data + 1);
722 int mod, regop, rm;
723 get_modrm(modrm, &mod, &regop, &rm);
724 if (mod == 3 && regop != 0) {
725 const char* mnem = NULL;
726 switch (regop) {
727 case 2:
728 mnem = "not";
729 break;
730 case 3:
731 mnem = "neg";
732 break;
733 case 4:
734 mnem = "mul";
735 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 case 5:
737 mnem = "imul";
738 break;
739 case 6:
740 mnem = "div";
741 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 case 7:
743 mnem = "idiv";
744 break;
745 default:
746 UnimplementedInstruction();
747 }
748 AppendToBuffer("%s%c %s",
749 mnem,
750 operand_size_code(),
751 NameOfCPURegister(rm));
752 return 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 } else if (regop == 0) {
754 AppendToBuffer("test%c ", operand_size_code());
Steve Blockd0582a62009-12-15 09:54:21 +0000755 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
756 AppendToBuffer(",0x");
757 count += PrintImmediate(data + 1 + count, operand_size());
758 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 } else {
760 UnimplementedInstruction();
761 return 2;
762 }
763}
764
765
766int DisassemblerX64::ShiftInstruction(byte* data) {
767 byte op = *data & (~1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400768 int count = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000769 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
770 UnimplementedInstruction();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400771 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400773 // Print mneumonic.
774 {
775 byte modrm = *(data + count);
776 int mod, regop, rm;
777 get_modrm(modrm, &mod, &regop, &rm);
778 regop &= 0x7; // The REX.R bit does not affect the operation.
779 const char* mnem = NULL;
780 switch (regop) {
781 case 0:
782 mnem = "rol";
783 break;
784 case 1:
785 mnem = "ror";
786 break;
787 case 2:
788 mnem = "rcl";
789 break;
790 case 3:
791 mnem = "rcr";
792 break;
793 case 4:
794 mnem = "shl";
795 break;
796 case 5:
797 mnem = "shr";
798 break;
799 case 7:
800 mnem = "sar";
801 break;
802 default:
803 UnimplementedInstruction();
804 return count + 1;
805 }
806 DCHECK_NE(NULL, mnem);
807 AppendToBuffer("%s%c ", mnem, operand_size_code());
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400809 count += PrintRightOperand(data + count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 if (op == 0xD2) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400811 AppendToBuffer(", cl");
Steve Blocka7e24c12009-10-30 11:49:00 +0000812 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400813 int imm8 = -1;
814 if (op == 0xD0) {
815 imm8 = 1;
816 } else {
817 DCHECK_EQ(0xC0, op);
818 imm8 = *(data + count);
819 count++;
820 }
821 AppendToBuffer(", %d", imm8);
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400823 return count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000824}
825
826
827// Returns number of bytes used, including *data.
828int DisassemblerX64::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000830 byte b = *(data + 1);
831 byte* dest = data + static_cast<int8_t>(b) + 2;
832 AppendToBuffer("jmp %s", NameOfAddress(dest));
833 return 2;
834}
835
836
837// Returns number of bytes used, including *data.
838int DisassemblerX64::JumpConditional(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000839 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 byte cond = *(data + 1) & 0x0F;
841 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
842 const char* mnem = conditional_code_suffix[cond];
843 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
844 return 6; // includes 0x0F
845}
846
847
848// Returns number of bytes used, including *data.
849int DisassemblerX64::JumpConditionalShort(byte* data) {
850 byte cond = *data & 0x0F;
851 byte b = *(data + 1);
852 byte* dest = data + static_cast<int8_t>(b) + 2;
853 const char* mnem = conditional_code_suffix[cond];
854 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
855 return 2;
856}
857
858
859// Returns number of bytes used, including *data.
860int DisassemblerX64::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000861 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000862 byte cond = *(data + 1) & 0x0F;
863 const char* mnem = conditional_code_suffix[cond];
864 AppendToBuffer("set%s%c ", mnem, operand_size_code());
865 PrintRightByteOperand(data + 2);
866 return 3; // includes 0x0F
867}
868
869
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400870int DisassemblerX64::AVXInstruction(byte* data) {
871 byte opcode = *data;
872 byte* current = data + 1;
873 if (vex_66() && vex_0f38()) {
874 int mod, regop, rm, vvvv = vex_vreg();
875 get_modrm(*current, &mod, &regop, &rm);
876 switch (opcode) {
877 case 0x99:
878 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
879 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
880 current += PrintRightXMMOperand(current);
881 break;
882 case 0xa9:
883 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
884 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
885 current += PrintRightXMMOperand(current);
886 break;
887 case 0xb9:
888 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
889 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
890 current += PrintRightXMMOperand(current);
891 break;
892 case 0x9b:
893 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
894 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
895 current += PrintRightXMMOperand(current);
896 break;
897 case 0xab:
898 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
899 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
900 current += PrintRightXMMOperand(current);
901 break;
902 case 0xbb:
903 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
904 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
905 current += PrintRightXMMOperand(current);
906 break;
907 case 0x9d:
908 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
909 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
910 current += PrintRightXMMOperand(current);
911 break;
912 case 0xad:
913 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
914 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
915 current += PrintRightXMMOperand(current);
916 break;
917 case 0xbd:
918 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
919 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
920 current += PrintRightXMMOperand(current);
921 break;
922 case 0x9f:
923 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
924 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
925 current += PrintRightXMMOperand(current);
926 break;
927 case 0xaf:
928 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
929 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
930 current += PrintRightXMMOperand(current);
931 break;
932 case 0xbf:
933 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
934 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
935 current += PrintRightXMMOperand(current);
936 break;
937 default:
938 UnimplementedInstruction();
939 }
940 } else if (vex_f2() && vex_0f()) {
941 int mod, regop, rm, vvvv = vex_vreg();
942 get_modrm(*current, &mod, &regop, &rm);
943 switch (opcode) {
944 case 0x58:
945 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
946 NameOfXMMRegister(vvvv));
947 current += PrintRightXMMOperand(current);
948 break;
949 case 0x59:
950 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
951 NameOfXMMRegister(vvvv));
952 current += PrintRightXMMOperand(current);
953 break;
954 case 0x5c:
955 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
956 NameOfXMMRegister(vvvv));
957 current += PrintRightXMMOperand(current);
958 break;
959 case 0x5e:
960 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
961 NameOfXMMRegister(vvvv));
962 current += PrintRightXMMOperand(current);
963 break;
964 default:
965 UnimplementedInstruction();
966 }
967 } else {
968 UnimplementedInstruction();
969 }
970
971 return static_cast<int>(current - data);
972}
973
974
Steve Blocka7e24c12009-10-30 11:49:00 +0000975// Returns number of bytes used, including *data.
976int DisassemblerX64::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000977 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +0000979 byte modrm_byte = *(data+1);
980
981 if (modrm_byte >= 0xC0) {
982 return RegisterFPUInstruction(escape_opcode, modrm_byte);
983 } else {
984 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000985 }
Steve Blockd0582a62009-12-15 09:54:21 +0000986}
987
988int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
989 int modrm_byte,
990 byte* modrm_start) {
991 const char* mnem = "?";
992 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
993 switch (escape_opcode) {
994 case 0xD9: switch (regop) {
995 case 0: mnem = "fld_s"; break;
996 case 3: mnem = "fstp_s"; break;
997 case 7: mnem = "fstcw"; break;
998 default: UnimplementedInstruction();
999 }
1000 break;
1001
1002 case 0xDB: switch (regop) {
1003 case 0: mnem = "fild_s"; break;
1004 case 1: mnem = "fisttp_s"; break;
1005 case 2: mnem = "fist_s"; break;
1006 case 3: mnem = "fistp_s"; break;
1007 default: UnimplementedInstruction();
1008 }
1009 break;
1010
1011 case 0xDD: switch (regop) {
1012 case 0: mnem = "fld_d"; break;
1013 case 3: mnem = "fstp_d"; break;
1014 default: UnimplementedInstruction();
1015 }
1016 break;
1017
1018 case 0xDF: switch (regop) {
1019 case 5: mnem = "fild_d"; break;
1020 case 7: mnem = "fistp_d"; break;
1021 default: UnimplementedInstruction();
1022 }
1023 break;
1024
1025 default: UnimplementedInstruction();
1026 }
1027 AppendToBuffer("%s ", mnem);
1028 int count = PrintRightOperand(modrm_start);
1029 return count + 1;
1030}
1031
1032int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1033 byte modrm_byte) {
1034 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1035 const char* mnem = "?";
1036
1037 switch (escape_opcode) {
1038 case 0xD8:
1039 UnimplementedInstruction();
1040 break;
1041
1042 case 0xD9:
1043 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001044 case 0xC0:
1045 mnem = "fld";
1046 has_register = true;
1047 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001048 case 0xC8:
1049 mnem = "fxch";
1050 has_register = true;
1051 break;
1052 default:
1053 switch (modrm_byte) {
1054 case 0xE0: mnem = "fchs"; break;
1055 case 0xE1: mnem = "fabs"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001056 case 0xE3: mnem = "fninit"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001057 case 0xE4: mnem = "ftst"; break;
1058 case 0xE8: mnem = "fld1"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001059 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001060 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001061 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001062 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001063 case 0xF1: mnem = "fyl2x"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001064 case 0xF2: mnem = "fptan"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001065 case 0xF5: mnem = "fprem1"; break;
1066 case 0xF7: mnem = "fincstp"; break;
1067 case 0xF8: mnem = "fprem"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001068 case 0xFC: mnem = "frndint"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001069 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001070 case 0xFE: mnem = "fsin"; break;
1071 case 0xFF: mnem = "fcos"; break;
1072 default: UnimplementedInstruction();
1073 }
1074 }
1075 break;
1076
1077 case 0xDA:
1078 if (modrm_byte == 0xE9) {
1079 mnem = "fucompp";
1080 } else {
1081 UnimplementedInstruction();
1082 }
1083 break;
1084
1085 case 0xDB:
1086 if ((modrm_byte & 0xF8) == 0xE8) {
1087 mnem = "fucomi";
1088 has_register = true;
1089 } else if (modrm_byte == 0xE2) {
1090 mnem = "fclex";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001091 } else if (modrm_byte == 0xE3) {
1092 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001093 } else {
1094 UnimplementedInstruction();
1095 }
1096 break;
1097
1098 case 0xDC:
1099 has_register = true;
1100 switch (modrm_byte & 0xF8) {
1101 case 0xC0: mnem = "fadd"; break;
1102 case 0xE8: mnem = "fsub"; break;
1103 case 0xC8: mnem = "fmul"; break;
1104 case 0xF8: mnem = "fdiv"; break;
1105 default: UnimplementedInstruction();
1106 }
1107 break;
1108
1109 case 0xDD:
1110 has_register = true;
1111 switch (modrm_byte & 0xF8) {
1112 case 0xC0: mnem = "ffree"; break;
1113 case 0xD8: mnem = "fstp"; break;
1114 default: UnimplementedInstruction();
1115 }
1116 break;
1117
1118 case 0xDE:
1119 if (modrm_byte == 0xD9) {
1120 mnem = "fcompp";
1121 } else {
1122 has_register = true;
1123 switch (modrm_byte & 0xF8) {
1124 case 0xC0: mnem = "faddp"; break;
1125 case 0xE8: mnem = "fsubp"; break;
1126 case 0xC8: mnem = "fmulp"; break;
1127 case 0xF8: mnem = "fdivp"; break;
1128 default: UnimplementedInstruction();
1129 }
1130 }
1131 break;
1132
1133 case 0xDF:
1134 if (modrm_byte == 0xE0) {
1135 mnem = "fnstsw_ax";
1136 } else if ((modrm_byte & 0xF8) == 0xE8) {
1137 mnem = "fucomip";
1138 has_register = true;
1139 }
1140 break;
1141
1142 default: UnimplementedInstruction();
1143 }
1144
1145 if (has_register) {
1146 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1147 } else {
1148 AppendToBuffer("%s", mnem);
1149 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 return 2;
1151}
1152
1153
Steve Blockd0582a62009-12-15 09:54:21 +00001154
Steve Blocka7e24c12009-10-30 11:49:00 +00001155// Handle all two-byte opcodes, which start with 0x0F.
1156// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1157// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1158int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1159 byte opcode = *(data + 1);
1160 byte* current = data + 2;
1161 // At return, "current" points to the start of the next instruction.
1162 const char* mnemonic = TwoByteMnemonic(opcode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001163 if (operand_size_ == 0x66) {
1164 // 0x66 0x0F prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001165 int mod, regop, rm;
Steve Block6ded16b2010-05-10 14:33:55 +01001166 if (opcode == 0x3A) {
1167 byte third_byte = *current;
1168 current = data + 3;
1169 if (third_byte == 0x17) {
1170 get_modrm(*current, &mod, &regop, &rm);
1171 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1172 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001173 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
Steve Block6ded16b2010-05-10 14:33:55 +01001174 current += 1;
Ben Murdoch257744e2011-11-30 15:57:28 +00001175 } else if (third_byte == 0x0b) {
1176 get_modrm(*current, &mod, &regop, &rm);
1177 // roundsd xmm, xmm/m64, imm8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001178 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1179 current += PrintRightXMMOperand(current);
1180 AppendToBuffer(",%d", (*current) & 3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001181 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001182 } else {
1183 UnimplementedInstruction();
1184 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001185 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001186 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001187 if (opcode == 0x1f) {
1188 current++;
1189 if (rm == 4) { // SIB byte present.
1190 current++;
1191 }
1192 if (mod == 1) { // Byte displacement.
1193 current += 1;
1194 } else if (mod == 2) { // 32-bit displacement.
1195 current += 4;
1196 } // else no immediate displacement.
1197 AppendToBuffer("nop");
1198 } else if (opcode == 0x28) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001200 current += PrintRightXMMOperand(current);
1201 } else if (opcode == 0x29) {
1202 AppendToBuffer("movapd ");
1203 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001204 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001205 } else if (opcode == 0x6E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001206 AppendToBuffer("mov%c %s,",
1207 rex_w() ? 'q' : 'd',
1208 NameOfXMMRegister(regop));
1209 current += PrintRightOperand(current);
Steve Block1e0659c2011-05-24 12:43:12 +01001210 } else if (opcode == 0x6F) {
1211 AppendToBuffer("movdqa %s,",
1212 NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001213 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001214 } else if (opcode == 0x7E) {
Ben Murdochbb769b22010-08-11 14:56:33 +01001215 AppendToBuffer("mov%c ",
1216 rex_w() ? 'q' : 'd');
1217 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001218 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block1e0659c2011-05-24 12:43:12 +01001219 } else if (opcode == 0x7F) {
1220 AppendToBuffer("movdqa ");
Steve Block44f0eee2011-05-26 01:26:41 +01001221 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001222 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001223 } else if (opcode == 0xD6) {
1224 AppendToBuffer("movq ");
1225 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001227 } else if (opcode == 0x50) {
1228 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1229 current += PrintRightXMMOperand(current);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001230 } else if (opcode == 0x72) {
1231 current += 1;
1232 AppendToBuffer("%s,%s,%d", (regop == 6) ? "pslld" : "psrld",
1233 NameOfXMMRegister(rm), *current & 0x7f);
1234 current += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 } else if (opcode == 0x73) {
1236 current += 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001237 AppendToBuffer("%s,%s,%d", (regop == 6) ? "psllq" : "psrlq",
1238 NameOfXMMRegister(rm), *current & 0x7f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001240 } else {
1241 const char* mnemonic = "?";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001242 if (opcode == 0x54) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001243 mnemonic = "andpd";
1244 } else if (opcode == 0x56) {
1245 mnemonic = "orpd";
1246 } else if (opcode == 0x57) {
Steve Block6ded16b2010-05-10 14:33:55 +01001247 mnemonic = "xorpd";
1248 } else if (opcode == 0x2E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001249 mnemonic = "ucomisd";
Steve Block8defd9f2010-07-08 12:39:36 +01001250 } else if (opcode == 0x2F) {
1251 mnemonic = "comisd";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001252 } else if (opcode == 0x76) {
1253 mnemonic = "pcmpeqd";
Steve Block6ded16b2010-05-10 14:33:55 +01001254 } else {
1255 UnimplementedInstruction();
1256 }
1257 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1258 current += PrintRightXMMOperand(current);
1259 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 }
1261 } else if (group_1_prefix_ == 0xF2) {
1262 // Beginning of instructions with prefix 0xF2.
1263
1264 if (opcode == 0x11 || opcode == 0x10) {
1265 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1266 AppendToBuffer("movsd ");
1267 int mod, regop, rm;
1268 get_modrm(*current, &mod, &regop, &rm);
1269 if (opcode == 0x11) {
Steve Block44f0eee2011-05-26 01:26:41 +01001270 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001271 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1272 } else {
1273 AppendToBuffer("%s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001274 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001275 }
1276 } else if (opcode == 0x2A) {
1277 // CVTSI2SD: integer to XMM double conversion.
1278 int mod, regop, rm;
1279 get_modrm(*current, &mod, &regop, &rm);
Steve Block8defd9f2010-07-08 12:39:36 +01001280 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
Steve Blockd0582a62009-12-15 09:54:21 +00001281 current += PrintRightOperand(current);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001282 } else if (opcode == 0x2C) {
1283 // CVTTSD2SI:
1284 // Convert with truncation scalar double-precision FP to integer.
1285 int mod, regop, rm;
1286 get_modrm(*current, &mod, &regop, &rm);
1287 AppendToBuffer("cvttsd2si%c %s,",
1288 operand_size_code(), NameOfCPURegister(regop));
1289 current += PrintRightXMMOperand(current);
1290 } else if (opcode == 0x2D) {
1291 // CVTSD2SI: Convert scalar double-precision FP to integer.
1292 int mod, regop, rm;
1293 get_modrm(*current, &mod, &regop, &rm);
1294 AppendToBuffer("cvtsd2si%c %s,",
1295 operand_size_code(), NameOfCPURegister(regop));
1296 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001297 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001298 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1299 int mod, regop, rm;
1300 get_modrm(*current, &mod, &regop, &rm);
Steve Blockd0582a62009-12-15 09:54:21 +00001301 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1302 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001303 } else if (opcode == 0xC2) {
1304 // Intel manual 2A, Table 3-18.
1305 int mod, regop, rm;
1306 get_modrm(*current, &mod, &regop, &rm);
1307 const char* const pseudo_op[] = {
1308 "cmpeqsd",
1309 "cmpltsd",
1310 "cmplesd",
1311 "cmpunordsd",
1312 "cmpneqsd",
1313 "cmpnltsd",
1314 "cmpnlesd",
1315 "cmpordsd"
1316 };
1317 AppendToBuffer("%s %s,%s",
1318 pseudo_op[current[1]],
1319 NameOfXMMRegister(regop),
1320 NameOfXMMRegister(rm));
1321 current += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001322 } else {
1323 UnimplementedInstruction();
1324 }
Steve Block6ded16b2010-05-10 14:33:55 +01001325 } else if (group_1_prefix_ == 0xF3) {
1326 // Instructions with prefix 0xF3.
Steve Block8defd9f2010-07-08 12:39:36 +01001327 if (opcode == 0x11 || opcode == 0x10) {
1328 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1329 AppendToBuffer("movss ");
1330 int mod, regop, rm;
1331 get_modrm(*current, &mod, &regop, &rm);
1332 if (opcode == 0x11) {
1333 current += PrintRightOperand(current);
1334 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1335 } else {
1336 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1337 current += PrintRightOperand(current);
1338 }
1339 } else if (opcode == 0x2A) {
1340 // CVTSI2SS: integer to XMM single conversion.
1341 int mod, regop, rm;
1342 get_modrm(*current, &mod, &regop, &rm);
1343 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1344 current += PrintRightOperand(current);
1345 } else if (opcode == 0x2C) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001346 // CVTTSS2SI:
1347 // Convert with truncation scalar single-precision FP to dword integer.
Steve Block1e0659c2011-05-24 12:43:12 +01001348 int mod, regop, rm;
1349 get_modrm(*current, &mod, &regop, &rm);
1350 AppendToBuffer("cvttss2si%c %s,",
1351 operand_size_code(), NameOfCPURegister(regop));
1352 current += PrintRightXMMOperand(current);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001353 } else if (opcode == 0x58) {
1354 int mod, regop, rm;
1355 get_modrm(*current, &mod, &regop, &rm);
1356 AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
1357 current += PrintRightXMMOperand(current);
1358 } else if (opcode == 0x59) {
1359 int mod, regop, rm;
1360 get_modrm(*current, &mod, &regop, &rm);
1361 AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
1362 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001363 } else if (opcode == 0x5A) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001364 // CVTSS2SD:
1365 // Convert scalar single-precision FP to scalar double-precision FP.
Steve Block6ded16b2010-05-10 14:33:55 +01001366 int mod, regop, rm;
1367 get_modrm(*current, &mod, &regop, &rm);
1368 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1369 current += PrintRightXMMOperand(current);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001370 } else if (opcode == 0x5c) {
1371 int mod, regop, rm;
1372 get_modrm(*current, &mod, &regop, &rm);
1373 AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
1374 current += PrintRightXMMOperand(current);
1375 } else if (opcode == 0x5e) {
1376 int mod, regop, rm;
1377 get_modrm(*current, &mod, &regop, &rm);
1378 AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
1379 current += PrintRightXMMOperand(current);
Ben Murdoch257744e2011-11-30 15:57:28 +00001380 } else if (opcode == 0x7E) {
1381 int mod, regop, rm;
1382 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001383 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001384 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001385 } else {
1386 UnimplementedInstruction();
1387 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001388 } else if (opcode == 0x1F) {
1389 // NOP
1390 int mod, regop, rm;
1391 get_modrm(*current, &mod, &regop, &rm);
1392 current++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001393 if (rm == 4) { // SIB byte present.
Andrei Popescu402d9372010-02-26 13:31:12 +00001394 current++;
1395 }
1396 if (mod == 1) { // Byte displacement.
1397 current += 1;
1398 } else if (mod == 2) { // 32-bit displacement.
1399 current += 4;
1400 } // else no immediate displacement.
1401 AppendToBuffer("nop");
Ben Murdoch257744e2011-11-30 15:57:28 +00001402
1403 } else if (opcode == 0x28) {
1404 // movaps xmm, xmm/m128
1405 int mod, regop, rm;
1406 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001407 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001408 current += PrintRightXMMOperand(current);
1409
1410 } else if (opcode == 0x29) {
1411 // movaps xmm/m128, xmm
1412 int mod, regop, rm;
1413 get_modrm(*current, &mod, &regop, &rm);
1414 AppendToBuffer("movaps ");
1415 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001416 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001417
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001418 } else if (opcode == 0x2e) {
1419 int mod, regop, rm;
1420 get_modrm(*current, &mod, &regop, &rm);
1421 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1422 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423 } else if (opcode == 0xA2) {
1424 // CPUID
Andrei Popescu402d9372010-02-26 13:31:12 +00001425 AppendToBuffer("%s", mnemonic);
1426
1427 } else if ((opcode & 0xF0) == 0x40) {
1428 // CMOVcc: conditional move.
1429 int condition = opcode & 0x0F;
1430 const InstructionDesc& idesc = cmov_instructions[condition];
1431 byte_size_operand_ = idesc.byte_size_operation;
1432 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1433
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001434 } else if (opcode >= 0x53 && opcode <= 0x5F) {
1435 const char* const pseudo_op[] = {
1436 "rcpps",
1437 "andps",
1438 "andnps",
1439 "orps",
1440 "xorps",
1441 "addps",
1442 "mulps",
1443 "cvtps2pd",
1444 "cvtdq2ps",
1445 "subps",
1446 "minps",
1447 "divps",
1448 "maxps",
1449 };
Ben Murdoch257744e2011-11-30 15:57:28 +00001450 int mod, regop, rm;
1451 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001452 AppendToBuffer("%s %s,",
1453 pseudo_op[opcode - 0x53],
1454 NameOfXMMRegister(regop));
1455 current += PrintRightXMMOperand(current);
1456
1457 } else if (opcode == 0xC6) {
1458 // shufps xmm, xmm/m128, imm8
1459 int mod, regop, rm;
1460 get_modrm(*current, &mod, &regop, &rm);
1461 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1462 current += PrintRightXMMOperand(current);
1463 AppendToBuffer(", %d", (*current) & 3);
1464 current += 1;
1465
1466 } else if (opcode == 0x50) {
1467 // movmskps reg, xmm
1468 int mod, regop, rm;
1469 get_modrm(*current, &mod, &regop, &rm);
1470 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001471 current += PrintRightXMMOperand(current);
1472
Andrei Popescu402d9372010-02-26 13:31:12 +00001473 } else if ((opcode & 0xF0) == 0x80) {
1474 // Jcc: Conditional jump (branch).
1475 current = data + JumpConditional(data);
1476
1477 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1478 opcode == 0xB7 || opcode == 0xAF) {
1479 // Size-extending moves, IMUL.
1480 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1481
1482 } else if ((opcode & 0xF0) == 0x90) {
1483 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1484 current = data + SetCC(data);
1485
1486 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1487 // SHLD, SHRD (double-precision shift), BTS (bit set).
1488 AppendToBuffer("%s ", mnemonic);
1489 int mod, regop, rm;
1490 get_modrm(*current, &mod, &regop, &rm);
1491 current += PrintRightOperand(current);
1492 if (opcode == 0xAB) {
1493 AppendToBuffer(",%s", NameOfCPURegister(regop));
1494 } else {
1495 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1496 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001497 } else if (opcode == 0xBD) {
1498 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1499 int mod, regop, rm;
1500 get_modrm(*current, &mod, &regop, &rm);
1501 AppendToBuffer("%s,", NameOfCPURegister(regop));
1502 current += PrintRightOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 } else {
1504 UnimplementedInstruction();
1505 }
Steve Blockd0582a62009-12-15 09:54:21 +00001506 return static_cast<int>(current - data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001507}
1508
1509
1510// Mnemonics for two-byte opcode instructions starting with 0x0F.
1511// The argument is the second byte of the two-byte opcode.
1512// Returns NULL if the instruction is not handled here.
1513const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1514 switch (opcode) {
1515 case 0x1F:
1516 return "nop";
Steve Block8defd9f2010-07-08 12:39:36 +01001517 case 0x2A: // F2/F3 prefix.
1518 return "cvtsi2s";
Steve Block6ded16b2010-05-10 14:33:55 +01001519 case 0x51: // F2 prefix.
1520 return "sqrtsd";
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 case 0x58: // F2 prefix.
1522 return "addsd";
1523 case 0x59: // F2 prefix.
1524 return "mulsd";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001525 case 0x5A: // F2 prefix.
1526 return "cvtsd2ss";
Steve Blocka7e24c12009-10-30 11:49:00 +00001527 case 0x5C: // F2 prefix.
1528 return "subsd";
1529 case 0x5E: // F2 prefix.
1530 return "divsd";
1531 case 0xA2:
1532 return "cpuid";
1533 case 0xA5:
1534 return "shld";
1535 case 0xAB:
1536 return "bts";
1537 case 0xAD:
1538 return "shrd";
1539 case 0xAF:
1540 return "imul";
1541 case 0xB6:
1542 return "movzxb";
1543 case 0xB7:
1544 return "movzxw";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001545 case 0xBD:
1546 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001547 case 0xBE:
1548 return "movsxb";
1549 case 0xBF:
1550 return "movsxw";
1551 default:
1552 return NULL;
1553 }
1554}
1555
1556
1557// Disassembles the instruction at instr, and writes it into out_buffer.
1558int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1559 byte* instr) {
1560 tmp_buffer_pos_ = 0; // starting to write as position 0
1561 byte* data = instr;
1562 bool processed = true; // Will be set to false if the current instruction
1563 // is not in 'instructions' table.
1564 byte current;
1565
1566 // Scan for prefixes.
1567 while (true) {
1568 current = *data;
Leon Clarked91b9f72010-01-27 17:25:45 +00001569 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 operand_size_ = current;
1571 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1572 setRex(current);
1573 if (rex_w()) AppendToBuffer("REX.W ");
Leon Clarked91b9f72010-01-27 17:25:45 +00001574 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
Steve Blocka7e24c12009-10-30 11:49:00 +00001575 group_1_prefix_ = current;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001576 } else if (current == VEX3_PREFIX) {
1577 vex_byte0_ = current;
1578 vex_byte1_ = *(data + 1);
1579 vex_byte2_ = *(data + 2);
1580 setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
1581 data += 2;
1582 } else if (current == VEX2_PREFIX) {
1583 vex_byte0_ = current;
1584 vex_byte1_ = *(data + 1);
1585 setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
1586 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001587 } else { // Not a prefix - an opcode.
1588 break;
1589 }
1590 data++;
1591 }
1592
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001593 // Decode AVX instructions.
1594 if (vex_byte0_ != 0) {
1595 processed = true;
1596 data += AVXInstruction(data);
1597 } else {
1598 const InstructionDesc& idesc = instruction_table_->Get(current);
1599 byte_size_operand_ = idesc.byte_size_operation;
1600 switch (idesc.type) {
1601 case ZERO_OPERANDS_INSTR:
1602 if (current >= 0xA4 && current <= 0xA7) {
1603 // String move or compare operations.
1604 if (group_1_prefix_ == REP_PREFIX) {
1605 // REP.
1606 AppendToBuffer("rep ");
1607 }
1608 if (rex_w()) AppendToBuffer("REX.W ");
1609 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1610 } else {
1611 AppendToBuffer("%s", idesc.mnem, operand_size_code());
Leon Clarked91b9f72010-01-27 17:25:45 +00001612 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001613 data++;
1614 break;
1615
1616 case TWO_OPERANDS_INSTR:
1617 data++;
1618 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1619 break;
1620
1621 case JUMP_CONDITIONAL_SHORT_INSTR:
1622 data += JumpConditionalShort(data);
1623 break;
1624
1625 case REGISTER_INSTR:
1626 AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
1627 NameOfCPURegister(base_reg(current & 0x07)));
1628 data++;
1629 break;
1630 case PUSHPOP_INSTR:
1631 AppendToBuffer("%s %s", idesc.mnem,
1632 NameOfCPURegister(base_reg(current & 0x07)));
1633 data++;
1634 break;
1635 case MOVE_REG_INSTR: {
1636 byte* addr = NULL;
1637 switch (operand_size()) {
1638 case OPERAND_WORD_SIZE:
1639 addr =
1640 reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1641 data += 3;
1642 break;
1643 case OPERAND_DOUBLEWORD_SIZE:
1644 addr =
1645 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
1646 data += 5;
1647 break;
1648 case OPERAND_QUADWORD_SIZE:
1649 addr =
1650 reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1651 data += 9;
1652 break;
1653 default:
1654 UNREACHABLE();
1655 }
1656 AppendToBuffer("mov%c %s,%s", operand_size_code(),
1657 NameOfCPURegister(base_reg(current & 0x07)),
1658 NameOfAddress(addr));
1659 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00001660 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001661
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001662 case CALL_JUMP_INSTR: {
1663 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1664 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1665 data += 5;
1666 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001667 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001668
1669 case SHORT_IMMEDIATE_INSTR: {
1670 byte* addr =
1671 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1672 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
1673 data += 5;
1674 break;
1675 }
1676
1677 case NO_INSTR:
1678 processed = false;
1679 break;
1680
1681 default:
1682 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00001683 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001684 }
1685
1686 // The first byte didn't match any of the simple opcodes, so we
1687 // need to do special processing on it.
1688 if (!processed) {
1689 switch (*data) {
1690 case 0xC2:
1691 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1692 data += 3;
1693 break;
1694
1695 case 0x69: // fall through
1696 case 0x6B: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001697 int count = 1;
1698 count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
1699 AppendToBuffer(",0x");
1700 if (*data == 0x69) {
1701 count += PrintImmediate(data + count, operand_size());
1702 } else {
1703 count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
1704 }
1705 data += count;
Steve Blocka7e24c12009-10-30 11:49:00 +00001706 break;
1707 }
1708
Steve Blocka7e24c12009-10-30 11:49:00 +00001709 case 0x81: // fall through
1710 case 0x83: // 0x81 with sign extension bit set
1711 data += PrintImmediateOp(data);
1712 break;
1713
1714 case 0x0F:
1715 data += TwoByteOpcodeInstruction(data);
1716 break;
1717
1718 case 0x8F: {
1719 data++;
1720 int mod, regop, rm;
1721 get_modrm(*data, &mod, &regop, &rm);
1722 if (regop == 0) {
1723 AppendToBuffer("pop ");
1724 data += PrintRightOperand(data);
1725 }
1726 }
1727 break;
1728
1729 case 0xFF: {
1730 data++;
1731 int mod, regop, rm;
1732 get_modrm(*data, &mod, &regop, &rm);
1733 const char* mnem = NULL;
1734 switch (regop) {
1735 case 0:
1736 mnem = "inc";
1737 break;
1738 case 1:
1739 mnem = "dec";
1740 break;
1741 case 2:
1742 mnem = "call";
1743 break;
1744 case 4:
1745 mnem = "jmp";
1746 break;
1747 case 6:
1748 mnem = "push";
1749 break;
1750 default:
1751 mnem = "???";
1752 }
1753 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1754 mnem,
1755 operand_size_code());
1756 data += PrintRightOperand(data);
1757 }
1758 break;
1759
1760 case 0xC7: // imm32, fall through
1761 case 0xC6: // imm8
1762 {
1763 bool is_byte = *data == 0xC6;
1764 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001765 if (is_byte) {
1766 AppendToBuffer("movb ");
1767 data += PrintRightByteOperand(data);
1768 int32_t imm = *data;
1769 AppendToBuffer(",0x%x", imm);
1770 data++;
1771 } else {
1772 AppendToBuffer("mov%c ", operand_size_code());
1773 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001774 if (operand_size() == OPERAND_WORD_SIZE) {
1775 int16_t imm = *reinterpret_cast<int16_t*>(data);
1776 AppendToBuffer(",0x%x", imm);
1777 data += 2;
1778 } else {
1779 int32_t imm = *reinterpret_cast<int32_t*>(data);
1780 AppendToBuffer(",0x%x", imm);
1781 data += 4;
1782 }
Steve Block44f0eee2011-05-26 01:26:41 +01001783 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001784 }
1785 break;
1786
1787 case 0x80: {
1788 data++;
1789 AppendToBuffer("cmpb ");
Steve Block44f0eee2011-05-26 01:26:41 +01001790 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001791 int32_t imm = *data;
1792 AppendToBuffer(",0x%x", imm);
1793 data++;
1794 }
1795 break;
1796
1797 case 0x88: // 8bit, fall through
1798 case 0x89: // 32bit
1799 {
1800 bool is_byte = *data == 0x88;
1801 int mod, regop, rm;
1802 data++;
1803 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001804 if (is_byte) {
1805 AppendToBuffer("movb ");
1806 data += PrintRightByteOperand(data);
1807 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1808 } else {
1809 AppendToBuffer("mov%c ", operand_size_code());
1810 data += PrintRightOperand(data);
1811 AppendToBuffer(",%s", NameOfCPURegister(regop));
1812 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001813 }
1814 break;
1815
1816 case 0x90:
1817 case 0x91:
1818 case 0x92:
1819 case 0x93:
1820 case 0x94:
1821 case 0x95:
1822 case 0x96:
1823 case 0x97: {
Steve Blockd0582a62009-12-15 09:54:21 +00001824 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001825 if (reg == 0) {
1826 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1827 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001828 AppendToBuffer("xchg%c rax,%s",
Steve Blocka7e24c12009-10-30 11:49:00 +00001829 operand_size_code(),
1830 NameOfCPURegister(reg));
1831 }
Steve Blockd0582a62009-12-15 09:54:21 +00001832 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001833 }
Steve Blockd0582a62009-12-15 09:54:21 +00001834 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001835 case 0xB0:
1836 case 0xB1:
1837 case 0xB2:
1838 case 0xB3:
1839 case 0xB4:
1840 case 0xB5:
1841 case 0xB6:
1842 case 0xB7:
1843 case 0xB8:
1844 case 0xB9:
1845 case 0xBA:
1846 case 0xBB:
1847 case 0xBC:
1848 case 0xBD:
1849 case 0xBE:
1850 case 0xBF: {
1851 // mov reg8,imm8 or mov reg32,imm32
1852 byte opcode = *data;
1853 data++;
1854 bool is_32bit = (opcode >= 0xB8);
1855 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1856 if (is_32bit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001857 AppendToBuffer("mov%c %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01001858 operand_size_code(),
1859 NameOfCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001860 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001861 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001862 AppendToBuffer("movb %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01001863 NameOfByteCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001864 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001865 }
1866 break;
1867 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 case 0xFE: {
1869 data++;
1870 int mod, regop, rm;
1871 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001872 if (regop == 1) {
1873 AppendToBuffer("decb ");
Steve Block44f0eee2011-05-26 01:26:41 +01001874 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 } else {
1876 UnimplementedInstruction();
1877 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01001879 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001880 case 0x68:
1881 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1882 data += 5;
1883 break;
1884
1885 case 0x6A:
1886 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1887 data += 2;
1888 break;
1889
1890 case 0xA1: // Fall through.
1891 case 0xA3:
1892 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001893 case OPERAND_DOUBLEWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001894 const char* memory_location = NameOfAddress(
1895 reinterpret_cast<byte*>(
1896 *reinterpret_cast<int32_t*>(data + 1)));
1897 if (*data == 0xA1) { // Opcode 0xA1
1898 AppendToBuffer("movzxlq rax,(%s)", memory_location);
1899 } else { // Opcode 0xA3
1900 AppendToBuffer("movzxlq (%s),rax", memory_location);
1901 }
1902 data += 5;
1903 break;
1904 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001905 case OPERAND_QUADWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 // New x64 instruction mov rax,(imm_64).
1907 const char* memory_location = NameOfAddress(
1908 *reinterpret_cast<byte**>(data + 1));
1909 if (*data == 0xA1) { // Opcode 0xA1
1910 AppendToBuffer("movq rax,(%s)", memory_location);
1911 } else { // Opcode 0xA3
1912 AppendToBuffer("movq (%s),rax", memory_location);
1913 }
1914 data += 9;
1915 break;
1916 }
1917 default:
1918 UnimplementedInstruction();
1919 data += 2;
1920 }
1921 break;
1922
1923 case 0xA8:
1924 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1925 data += 2;
1926 break;
1927
1928 case 0xA9: {
1929 int64_t value = 0;
1930 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001931 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001932 value = *reinterpret_cast<uint16_t*>(data + 1);
1933 data += 3;
1934 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001935 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 value = *reinterpret_cast<uint32_t*>(data + 1);
1937 data += 5;
1938 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001939 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001940 value = *reinterpret_cast<int32_t*>(data + 1);
1941 data += 5;
1942 break;
1943 default:
1944 UNREACHABLE();
1945 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001946 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 operand_size_code(),
1948 value);
1949 break;
1950 }
1951 case 0xD1: // fall through
1952 case 0xD3: // fall through
1953 case 0xC1:
1954 data += ShiftInstruction(data);
1955 break;
1956 case 0xD0: // fall through
1957 case 0xD2: // fall through
1958 case 0xC0:
1959 byte_size_operand_ = true;
1960 data += ShiftInstruction(data);
1961 break;
1962
1963 case 0xD9: // fall through
1964 case 0xDA: // fall through
1965 case 0xDB: // fall through
1966 case 0xDC: // fall through
1967 case 0xDD: // fall through
1968 case 0xDE: // fall through
1969 case 0xDF:
1970 data += FPUInstruction(data);
1971 break;
1972
1973 case 0xEB:
1974 data += JumpShort(data);
1975 break;
1976
Steve Blockd0582a62009-12-15 09:54:21 +00001977 case 0xF6:
1978 byte_size_operand_ = true; // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001979 case 0xF7:
Steve Blockd0582a62009-12-15 09:54:21 +00001980 data += F6F7Instruction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001981 break;
1982
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001983 case 0x3C:
1984 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
1985 data +=2;
1986 break;
1987
Steve Blocka7e24c12009-10-30 11:49:00 +00001988 default:
1989 UnimplementedInstruction();
1990 data += 1;
1991 }
1992 } // !processed
1993
1994 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1995 tmp_buffer_[tmp_buffer_pos_] = '\0';
1996 }
1997
Steve Blockd0582a62009-12-15 09:54:21 +00001998 int instr_len = static_cast<int>(data - instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001999 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002000
2001 int outp = 0;
2002 // Instruction bytes.
2003 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002004 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002005 }
2006 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002007 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002008 }
2009
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002010 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2011 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002012 return instr_len;
2013}
2014
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002015
Steve Blocka7e24c12009-10-30 11:49:00 +00002016//------------------------------------------------------------------------------
2017
2018
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002019static const char* const cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002020 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2021 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2022};
2023
2024
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002025static const char* const byte_cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002026 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2027 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2028};
2029
2030
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002031static const char* const xmm_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002032 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2033 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2034};
2035
2036
2037const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002038 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002039 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002040}
2041
2042
2043const char* NameConverter::NameOfConstant(byte* addr) const {
2044 return NameOfAddress(addr);
2045}
2046
2047
2048const char* NameConverter::NameOfCPURegister(int reg) const {
2049 if (0 <= reg && reg < 16)
2050 return cpu_regs[reg];
2051 return "noreg";
2052}
2053
2054
2055const char* NameConverter::NameOfByteCPURegister(int reg) const {
2056 if (0 <= reg && reg < 16)
2057 return byte_cpu_regs[reg];
2058 return "noreg";
2059}
2060
2061
2062const char* NameConverter::NameOfXMMRegister(int reg) const {
2063 if (0 <= reg && reg < 16)
2064 return xmm_regs[reg];
2065 return "noxmmreg";
2066}
2067
2068
2069const char* NameConverter::NameInCode(byte* addr) const {
2070 // X64 does not embed debug strings at the moment.
2071 UNREACHABLE();
2072 return "";
2073}
2074
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002075
Steve Blocka7e24c12009-10-30 11:49:00 +00002076//------------------------------------------------------------------------------
2077
2078Disassembler::Disassembler(const NameConverter& converter)
2079 : converter_(converter) { }
2080
2081Disassembler::~Disassembler() { }
2082
2083
2084int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2085 byte* instruction) {
2086 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2087 return d.InstructionDecode(buffer, instruction);
2088}
2089
2090
2091// The X64 assembler does not use constant pools.
2092int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2093 return -1;
2094}
2095
2096
2097void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2098 NameConverter converter;
2099 Disassembler d(converter);
2100 for (byte* pc = begin; pc < end;) {
2101 v8::internal::EmbeddedVector<char, 128> buffer;
2102 buffer[0] = '\0';
2103 byte* prev_pc = pc;
2104 pc += d.InstructionDecode(buffer, pc);
2105 fprintf(f, "%p", prev_pc);
2106 fprintf(f, " ");
2107
2108 for (byte* bp = prev_pc; bp < pc; bp++) {
2109 fprintf(f, "%02x", *bp);
2110 }
Steve Blockd0582a62009-12-15 09:54:21 +00002111 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002112 fprintf(f, " ");
2113 }
2114 fprintf(f, " %s\n", buffer.start());
2115 }
2116}
2117
2118} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002119
2120#endif // V8_TARGET_ARCH_X64