blob: 05b199d558df567d3fae301a15a84713d61313d6 [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) {
959 case 0x0b:
960 AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
961 NameOfXMMRegister(vvvv));
962 current += PrintRightXMMOperand(current);
963 AppendToBuffer(",0x%x", *current++);
964 break;
965 default:
966 UnimplementedInstruction();
967 }
968 } else if (vex_f3() && vex_0f()) {
969 int mod, regop, rm, vvvv = vex_vreg();
970 get_modrm(*current, &mod, &regop, &rm);
971 switch (opcode) {
972 case 0x10:
973 AppendToBuffer("vmovss %s,", NameOfXMMRegister(regop));
974 if (mod == 3) {
975 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
976 }
977 current += PrintRightXMMOperand(current);
978 break;
979 case 0x11:
980 AppendToBuffer("vmovss ");
981 current += PrintRightXMMOperand(current);
982 if (mod == 3) {
983 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
984 }
985 AppendToBuffer(",%s", NameOfXMMRegister(regop));
986 break;
987 case 0x2a:
988 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2ss" : "vcvtlsi2ss",
989 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
990 current += PrintRightOperand(current);
991 break;
992 case 0x2c:
993 AppendToBuffer("vcvttss2si%s %s,", vex_w() ? "q" : "",
994 NameOfCPURegister(regop));
995 current += PrintRightXMMOperand(current);
996 break;
997 case 0x58:
998 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
999 NameOfXMMRegister(vvvv));
1000 current += PrintRightXMMOperand(current);
1001 break;
1002 case 0x59:
1003 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
1004 NameOfXMMRegister(vvvv));
1005 current += PrintRightXMMOperand(current);
1006 break;
1007 case 0x5a:
1008 AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
1009 NameOfXMMRegister(vvvv));
1010 current += PrintRightXMMOperand(current);
1011 break;
1012 case 0x5c:
1013 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
1014 NameOfXMMRegister(vvvv));
1015 current += PrintRightXMMOperand(current);
1016 break;
1017 case 0x5d:
1018 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
1019 NameOfXMMRegister(vvvv));
1020 current += PrintRightXMMOperand(current);
1021 break;
1022 case 0x5e:
1023 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
1024 NameOfXMMRegister(vvvv));
1025 current += PrintRightXMMOperand(current);
1026 break;
1027 case 0x5f:
1028 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
1029 NameOfXMMRegister(vvvv));
1030 current += PrintRightXMMOperand(current);
1031 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001032 default:
1033 UnimplementedInstruction();
1034 }
1035 } else if (vex_f2() && vex_0f()) {
1036 int mod, regop, rm, vvvv = vex_vreg();
1037 get_modrm(*current, &mod, &regop, &rm);
1038 switch (opcode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001039 case 0x10:
1040 AppendToBuffer("vmovsd %s,", NameOfXMMRegister(regop));
1041 if (mod == 3) {
1042 AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1043 }
1044 current += PrintRightXMMOperand(current);
1045 break;
1046 case 0x11:
1047 AppendToBuffer("vmovsd ");
1048 current += PrintRightXMMOperand(current);
1049 if (mod == 3) {
1050 AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1051 }
1052 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1053 break;
1054 case 0x2a:
1055 AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd",
1056 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1057 current += PrintRightOperand(current);
1058 break;
1059 case 0x2c:
1060 AppendToBuffer("vcvttsd2si%s %s,", vex_w() ? "q" : "",
1061 NameOfCPURegister(regop));
1062 current += PrintRightXMMOperand(current);
1063 break;
1064 case 0x2d:
1065 AppendToBuffer("vcvtsd2si%s %s,", vex_w() ? "q" : "",
1066 NameOfCPURegister(regop));
1067 current += PrintRightXMMOperand(current);
1068 break;
1069 case 0x51:
1070 AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
1071 NameOfXMMRegister(vvvv));
1072 current += PrintRightXMMOperand(current);
1073 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001074 case 0x58:
1075 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
1076 NameOfXMMRegister(vvvv));
1077 current += PrintRightXMMOperand(current);
1078 break;
1079 case 0x59:
1080 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
1081 NameOfXMMRegister(vvvv));
1082 current += PrintRightXMMOperand(current);
1083 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 case 0x5a:
1085 AppendToBuffer("vcvtsd2ss %s,%s,", NameOfXMMRegister(regop),
1086 NameOfXMMRegister(vvvv));
1087 current += PrintRightXMMOperand(current);
1088 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001089 case 0x5c:
1090 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
1091 NameOfXMMRegister(vvvv));
1092 current += PrintRightXMMOperand(current);
1093 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001094 case 0x5d:
1095 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
1096 NameOfXMMRegister(vvvv));
1097 current += PrintRightXMMOperand(current);
1098 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001099 case 0x5e:
1100 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
1101 NameOfXMMRegister(vvvv));
1102 current += PrintRightXMMOperand(current);
1103 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001104 case 0x5f:
1105 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
1106 NameOfXMMRegister(vvvv));
1107 current += PrintRightXMMOperand(current);
1108 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001109 default:
1110 UnimplementedInstruction();
1111 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001112 } else if (vex_none() && vex_0f38()) {
1113 int mod, regop, rm, vvvv = vex_vreg();
1114 get_modrm(*current, &mod, &regop, &rm);
1115 const char* mnem = "?";
1116 switch (opcode) {
1117 case 0xf2:
1118 AppendToBuffer("andn%c %s,%s,", operand_size_code(),
1119 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1120 current += PrintRightOperand(current);
1121 break;
1122 case 0xf5:
1123 AppendToBuffer("bzhi%c %s,", operand_size_code(),
1124 NameOfCPURegister(regop));
1125 current += PrintRightOperand(current);
1126 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1127 break;
1128 case 0xf7:
1129 AppendToBuffer("bextr%c %s,", operand_size_code(),
1130 NameOfCPURegister(regop));
1131 current += PrintRightOperand(current);
1132 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1133 break;
1134 case 0xf3:
1135 switch (regop) {
1136 case 1:
1137 mnem = "blsr";
1138 break;
1139 case 2:
1140 mnem = "blsmsk";
1141 break;
1142 case 3:
1143 mnem = "blsi";
1144 break;
1145 default:
1146 UnimplementedInstruction();
1147 }
1148 AppendToBuffer("%s%c %s,", mnem, operand_size_code(),
1149 NameOfCPURegister(vvvv));
1150 current += PrintRightOperand(current);
1151 mnem = "?";
1152 break;
1153 default:
1154 UnimplementedInstruction();
1155 }
1156 } else if (vex_f2() && vex_0f38()) {
1157 int mod, regop, rm, vvvv = vex_vreg();
1158 get_modrm(*current, &mod, &regop, &rm);
1159 switch (opcode) {
1160 case 0xf5:
1161 AppendToBuffer("pdep%c %s,%s,", operand_size_code(),
1162 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1163 current += PrintRightOperand(current);
1164 break;
1165 case 0xf6:
1166 AppendToBuffer("mulx%c %s,%s,", operand_size_code(),
1167 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1168 current += PrintRightOperand(current);
1169 break;
1170 case 0xf7:
1171 AppendToBuffer("shrx%c %s,", operand_size_code(),
1172 NameOfCPURegister(regop));
1173 current += PrintRightOperand(current);
1174 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1175 break;
1176 default:
1177 UnimplementedInstruction();
1178 }
1179 } else if (vex_f3() && vex_0f38()) {
1180 int mod, regop, rm, vvvv = vex_vreg();
1181 get_modrm(*current, &mod, &regop, &rm);
1182 switch (opcode) {
1183 case 0xf5:
1184 AppendToBuffer("pext%c %s,%s,", operand_size_code(),
1185 NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1186 current += PrintRightOperand(current);
1187 break;
1188 case 0xf7:
1189 AppendToBuffer("sarx%c %s,", operand_size_code(),
1190 NameOfCPURegister(regop));
1191 current += PrintRightOperand(current);
1192 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1193 break;
1194 default:
1195 UnimplementedInstruction();
1196 }
1197 } else if (vex_f2() && vex_0f3a()) {
1198 int mod, regop, rm;
1199 get_modrm(*current, &mod, &regop, &rm);
1200 switch (opcode) {
1201 case 0xf0:
1202 AppendToBuffer("rorx%c %s,", operand_size_code(),
1203 NameOfCPURegister(regop));
1204 current += PrintRightOperand(current);
1205 switch (operand_size()) {
1206 case OPERAND_DOUBLEWORD_SIZE:
1207 AppendToBuffer(",%d", *current & 0x1f);
1208 break;
1209 case OPERAND_QUADWORD_SIZE:
1210 AppendToBuffer(",%d", *current & 0x3f);
1211 break;
1212 default:
1213 UnimplementedInstruction();
1214 }
1215 current += 1;
1216 break;
1217 default:
1218 UnimplementedInstruction();
1219 }
1220 } else if (vex_none() && vex_0f()) {
1221 int mod, regop, rm, vvvv = vex_vreg();
1222 get_modrm(*current, &mod, &regop, &rm);
1223 switch (opcode) {
1224 case 0x28:
1225 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1226 current += PrintRightXMMOperand(current);
1227 break;
1228 case 0x29:
1229 AppendToBuffer("vmovaps ");
1230 current += PrintRightXMMOperand(current);
1231 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1232 break;
1233 case 0x2e:
1234 AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1235 current += PrintRightXMMOperand(current);
1236 break;
1237 case 0x54:
1238 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1239 NameOfXMMRegister(vvvv));
1240 current += PrintRightXMMOperand(current);
1241 break;
1242 case 0x57:
1243 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1244 NameOfXMMRegister(vvvv));
1245 current += PrintRightXMMOperand(current);
1246 break;
1247 default:
1248 UnimplementedInstruction();
1249 }
1250 } else if (vex_66() && vex_0f()) {
1251 int mod, regop, rm, vvvv = vex_vreg();
1252 get_modrm(*current, &mod, &regop, &rm);
1253 switch (opcode) {
1254 case 0x28:
1255 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1256 current += PrintRightXMMOperand(current);
1257 break;
1258 case 0x29:
1259 AppendToBuffer("vmovapd ");
1260 current += PrintRightXMMOperand(current);
1261 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1262 break;
1263 case 0x2e:
1264 AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1265 current += PrintRightXMMOperand(current);
1266 break;
1267 case 0x50:
1268 AppendToBuffer("vmovmskpd %s,", NameOfCPURegister(regop));
1269 current += PrintRightXMMOperand(current);
1270 break;
1271 case 0x54:
1272 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1273 NameOfXMMRegister(vvvv));
1274 current += PrintRightXMMOperand(current);
1275 break;
1276 case 0x56:
1277 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1278 NameOfXMMRegister(vvvv));
1279 current += PrintRightXMMOperand(current);
1280 break;
1281 case 0x57:
1282 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1283 NameOfXMMRegister(vvvv));
1284 current += PrintRightXMMOperand(current);
1285 break;
1286 case 0x6e:
1287 AppendToBuffer("vmov%c %s,", vex_w() ? 'q' : 'd',
1288 NameOfXMMRegister(regop));
1289 current += PrintRightOperand(current);
1290 break;
1291 case 0x73:
1292 AppendToBuffer("%s %s,", regop == 6 ? "vpsllq" : "vpsrlq",
1293 NameOfXMMRegister(vvvv));
1294 current += PrintRightXMMOperand(current);
1295 AppendToBuffer(",%u", *current++);
1296 break;
1297 case 0x76:
1298 AppendToBuffer("vpcmpeqd %s,%s,", NameOfXMMRegister(regop),
1299 NameOfXMMRegister(vvvv));
1300 current += PrintRightXMMOperand(current);
1301 break;
1302 case 0x7e:
1303 AppendToBuffer("vmov%c ", vex_w() ? 'q' : 'd');
1304 current += PrintRightOperand(current);
1305 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1306 break;
1307 default:
1308 UnimplementedInstruction();
1309 }
1310
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001311 } else {
1312 UnimplementedInstruction();
1313 }
1314
1315 return static_cast<int>(current - data);
1316}
1317
1318
Steve Blocka7e24c12009-10-30 11:49:00 +00001319// Returns number of bytes used, including *data.
1320int DisassemblerX64::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +00001321 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +00001323 byte modrm_byte = *(data+1);
1324
1325 if (modrm_byte >= 0xC0) {
1326 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1327 } else {
1328 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001329 }
Steve Blockd0582a62009-12-15 09:54:21 +00001330}
1331
1332int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
1333 int modrm_byte,
1334 byte* modrm_start) {
1335 const char* mnem = "?";
1336 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1337 switch (escape_opcode) {
1338 case 0xD9: switch (regop) {
1339 case 0: mnem = "fld_s"; break;
1340 case 3: mnem = "fstp_s"; break;
1341 case 7: mnem = "fstcw"; break;
1342 default: UnimplementedInstruction();
1343 }
1344 break;
1345
1346 case 0xDB: switch (regop) {
1347 case 0: mnem = "fild_s"; break;
1348 case 1: mnem = "fisttp_s"; break;
1349 case 2: mnem = "fist_s"; break;
1350 case 3: mnem = "fistp_s"; break;
1351 default: UnimplementedInstruction();
1352 }
1353 break;
1354
1355 case 0xDD: switch (regop) {
1356 case 0: mnem = "fld_d"; break;
1357 case 3: mnem = "fstp_d"; break;
1358 default: UnimplementedInstruction();
1359 }
1360 break;
1361
1362 case 0xDF: switch (regop) {
1363 case 5: mnem = "fild_d"; break;
1364 case 7: mnem = "fistp_d"; break;
1365 default: UnimplementedInstruction();
1366 }
1367 break;
1368
1369 default: UnimplementedInstruction();
1370 }
1371 AppendToBuffer("%s ", mnem);
1372 int count = PrintRightOperand(modrm_start);
1373 return count + 1;
1374}
1375
1376int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1377 byte modrm_byte) {
1378 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1379 const char* mnem = "?";
1380
1381 switch (escape_opcode) {
1382 case 0xD8:
1383 UnimplementedInstruction();
1384 break;
1385
1386 case 0xD9:
1387 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001388 case 0xC0:
1389 mnem = "fld";
1390 has_register = true;
1391 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001392 case 0xC8:
1393 mnem = "fxch";
1394 has_register = true;
1395 break;
1396 default:
1397 switch (modrm_byte) {
1398 case 0xE0: mnem = "fchs"; break;
1399 case 0xE1: mnem = "fabs"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001400 case 0xE3: mnem = "fninit"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001401 case 0xE4: mnem = "ftst"; break;
1402 case 0xE8: mnem = "fld1"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001403 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001404 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001405 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001406 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001407 case 0xF1: mnem = "fyl2x"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001408 case 0xF2: mnem = "fptan"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001409 case 0xF5: mnem = "fprem1"; break;
1410 case 0xF7: mnem = "fincstp"; break;
1411 case 0xF8: mnem = "fprem"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412 case 0xFC: mnem = "frndint"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001413 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +00001414 case 0xFE: mnem = "fsin"; break;
1415 case 0xFF: mnem = "fcos"; break;
1416 default: UnimplementedInstruction();
1417 }
1418 }
1419 break;
1420
1421 case 0xDA:
1422 if (modrm_byte == 0xE9) {
1423 mnem = "fucompp";
1424 } else {
1425 UnimplementedInstruction();
1426 }
1427 break;
1428
1429 case 0xDB:
1430 if ((modrm_byte & 0xF8) == 0xE8) {
1431 mnem = "fucomi";
1432 has_register = true;
1433 } else if (modrm_byte == 0xE2) {
1434 mnem = "fclex";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 } else if (modrm_byte == 0xE3) {
1436 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +00001437 } else {
1438 UnimplementedInstruction();
1439 }
1440 break;
1441
1442 case 0xDC:
1443 has_register = true;
1444 switch (modrm_byte & 0xF8) {
1445 case 0xC0: mnem = "fadd"; break;
1446 case 0xE8: mnem = "fsub"; break;
1447 case 0xC8: mnem = "fmul"; break;
1448 case 0xF8: mnem = "fdiv"; break;
1449 default: UnimplementedInstruction();
1450 }
1451 break;
1452
1453 case 0xDD:
1454 has_register = true;
1455 switch (modrm_byte & 0xF8) {
1456 case 0xC0: mnem = "ffree"; break;
1457 case 0xD8: mnem = "fstp"; break;
1458 default: UnimplementedInstruction();
1459 }
1460 break;
1461
1462 case 0xDE:
1463 if (modrm_byte == 0xD9) {
1464 mnem = "fcompp";
1465 } else {
1466 has_register = true;
1467 switch (modrm_byte & 0xF8) {
1468 case 0xC0: mnem = "faddp"; break;
1469 case 0xE8: mnem = "fsubp"; break;
1470 case 0xC8: mnem = "fmulp"; break;
1471 case 0xF8: mnem = "fdivp"; break;
1472 default: UnimplementedInstruction();
1473 }
1474 }
1475 break;
1476
1477 case 0xDF:
1478 if (modrm_byte == 0xE0) {
1479 mnem = "fnstsw_ax";
1480 } else if ((modrm_byte & 0xF8) == 0xE8) {
1481 mnem = "fucomip";
1482 has_register = true;
1483 }
1484 break;
1485
1486 default: UnimplementedInstruction();
1487 }
1488
1489 if (has_register) {
1490 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1491 } else {
1492 AppendToBuffer("%s", mnem);
1493 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001494 return 2;
1495}
1496
1497
Steve Blockd0582a62009-12-15 09:54:21 +00001498
Steve Blocka7e24c12009-10-30 11:49:00 +00001499// Handle all two-byte opcodes, which start with 0x0F.
1500// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1501// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1502int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1503 byte opcode = *(data + 1);
1504 byte* current = data + 2;
1505 // At return, "current" points to the start of the next instruction.
1506 const char* mnemonic = TwoByteMnemonic(opcode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001507 if (operand_size_ == 0x66) {
1508 // 0x66 0x0F prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 int mod, regop, rm;
Steve Block6ded16b2010-05-10 14:33:55 +01001510 if (opcode == 0x3A) {
1511 byte third_byte = *current;
1512 current = data + 3;
1513 if (third_byte == 0x17) {
1514 get_modrm(*current, &mod, &regop, &rm);
1515 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1516 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
Steve Block6ded16b2010-05-10 14:33:55 +01001518 current += 1;
Ben Murdoch257744e2011-11-30 15:57:28 +00001519 } else if (third_byte == 0x0b) {
1520 get_modrm(*current, &mod, &regop, &rm);
1521 // roundsd xmm, xmm/m64, imm8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001522 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1523 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001524 AppendToBuffer(",0x%x", (*current) & 3);
1525 current += 1;
1526 } else if (third_byte == 0x16) {
1527 get_modrm(*current, &mod, &rm, &regop);
1528 AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
1529 current += PrintRightOperand(current);
1530 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1531 current += 1;
1532 } else if (third_byte == 0x22) {
1533 get_modrm(*current, &mod, &regop, &rm);
1534 AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
1535 AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1536 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001537 AppendToBuffer(",%d", (*current) & 3);
Ben Murdoch257744e2011-11-30 15:57:28 +00001538 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001539 } else {
1540 UnimplementedInstruction();
1541 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001543 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001544 if (opcode == 0x1f) {
1545 current++;
1546 if (rm == 4) { // SIB byte present.
1547 current++;
1548 }
1549 if (mod == 1) { // Byte displacement.
1550 current += 1;
1551 } else if (mod == 2) { // 32-bit displacement.
1552 current += 4;
1553 } // else no immediate displacement.
1554 AppendToBuffer("nop");
1555 } else if (opcode == 0x28) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001556 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001557 current += PrintRightXMMOperand(current);
1558 } else if (opcode == 0x29) {
1559 AppendToBuffer("movapd ");
1560 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001561 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001562 } else if (opcode == 0x6E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001563 AppendToBuffer("mov%c %s,",
1564 rex_w() ? 'q' : 'd',
1565 NameOfXMMRegister(regop));
1566 current += PrintRightOperand(current);
Steve Block1e0659c2011-05-24 12:43:12 +01001567 } else if (opcode == 0x6F) {
1568 AppendToBuffer("movdqa %s,",
1569 NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001570 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001571 } else if (opcode == 0x7E) {
Ben Murdochbb769b22010-08-11 14:56:33 +01001572 AppendToBuffer("mov%c ",
1573 rex_w() ? 'q' : 'd');
1574 current += PrintRightOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001575 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block1e0659c2011-05-24 12:43:12 +01001576 } else if (opcode == 0x7F) {
1577 AppendToBuffer("movdqa ");
Steve Block44f0eee2011-05-26 01:26:41 +01001578 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001579 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001580 } else if (opcode == 0xD6) {
1581 AppendToBuffer("movq ");
1582 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001583 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001584 } else if (opcode == 0x50) {
1585 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1586 current += PrintRightXMMOperand(current);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001587 } else if (opcode == 0x72) {
1588 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001589 AppendToBuffer("%s %s,%d", (regop == 6) ? "pslld" : "psrld",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001590 NameOfXMMRegister(rm), *current & 0x7f);
1591 current += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001592 } else if (opcode == 0x73) {
1593 current += 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001594 AppendToBuffer("%s %s,%d", (regop == 6) ? "psllq" : "psrlq",
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001595 NameOfXMMRegister(rm), *current & 0x7f);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001596 current += 1;
Steve Block6ded16b2010-05-10 14:33:55 +01001597 } else {
1598 const char* mnemonic = "?";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001599 if (opcode == 0x54) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001600 mnemonic = "andpd";
1601 } else if (opcode == 0x56) {
1602 mnemonic = "orpd";
1603 } else if (opcode == 0x57) {
Steve Block6ded16b2010-05-10 14:33:55 +01001604 mnemonic = "xorpd";
1605 } else if (opcode == 0x2E) {
Steve Block6ded16b2010-05-10 14:33:55 +01001606 mnemonic = "ucomisd";
Steve Block8defd9f2010-07-08 12:39:36 +01001607 } else if (opcode == 0x2F) {
1608 mnemonic = "comisd";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001609 } else if (opcode == 0x76) {
1610 mnemonic = "pcmpeqd";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001611 } else if (opcode == 0x62) {
1612 mnemonic = "punpckldq";
1613 } else if (opcode == 0x6A) {
1614 mnemonic = "punpckhdq";
Steve Block6ded16b2010-05-10 14:33:55 +01001615 } else {
1616 UnimplementedInstruction();
1617 }
1618 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1619 current += PrintRightXMMOperand(current);
1620 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 }
1622 } else if (group_1_prefix_ == 0xF2) {
1623 // Beginning of instructions with prefix 0xF2.
1624
1625 if (opcode == 0x11 || opcode == 0x10) {
1626 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1627 AppendToBuffer("movsd ");
1628 int mod, regop, rm;
1629 get_modrm(*current, &mod, &regop, &rm);
1630 if (opcode == 0x11) {
Steve Block44f0eee2011-05-26 01:26:41 +01001631 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001632 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1633 } else {
1634 AppendToBuffer("%s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001635 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001636 }
1637 } else if (opcode == 0x2A) {
1638 // CVTSI2SD: integer to XMM double conversion.
1639 int mod, regop, rm;
1640 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001641 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Blockd0582a62009-12-15 09:54:21 +00001642 current += PrintRightOperand(current);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001643 } else if (opcode == 0x2C) {
1644 // CVTTSD2SI:
1645 // Convert with truncation scalar double-precision FP to integer.
1646 int mod, regop, rm;
1647 get_modrm(*current, &mod, &regop, &rm);
1648 AppendToBuffer("cvttsd2si%c %s,",
1649 operand_size_code(), NameOfCPURegister(regop));
1650 current += PrintRightXMMOperand(current);
1651 } else if (opcode == 0x2D) {
1652 // CVTSD2SI: Convert scalar double-precision FP to integer.
1653 int mod, regop, rm;
1654 get_modrm(*current, &mod, &regop, &rm);
1655 AppendToBuffer("cvtsd2si%c %s,",
1656 operand_size_code(), NameOfCPURegister(regop));
1657 current += PrintRightXMMOperand(current);
Steve Block6ded16b2010-05-10 14:33:55 +01001658 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001659 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1660 int mod, regop, rm;
1661 get_modrm(*current, &mod, &regop, &rm);
Steve Blockd0582a62009-12-15 09:54:21 +00001662 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1663 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001664 } else if (opcode == 0xC2) {
1665 // Intel manual 2A, Table 3-18.
1666 int mod, regop, rm;
1667 get_modrm(*current, &mod, &regop, &rm);
1668 const char* const pseudo_op[] = {
1669 "cmpeqsd",
1670 "cmpltsd",
1671 "cmplesd",
1672 "cmpunordsd",
1673 "cmpneqsd",
1674 "cmpnltsd",
1675 "cmpnlesd",
1676 "cmpordsd"
1677 };
1678 AppendToBuffer("%s %s,%s",
1679 pseudo_op[current[1]],
1680 NameOfXMMRegister(regop),
1681 NameOfXMMRegister(rm));
1682 current += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001683 } else {
1684 UnimplementedInstruction();
1685 }
Steve Block6ded16b2010-05-10 14:33:55 +01001686 } else if (group_1_prefix_ == 0xF3) {
1687 // Instructions with prefix 0xF3.
Steve Block8defd9f2010-07-08 12:39:36 +01001688 if (opcode == 0x11 || opcode == 0x10) {
1689 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1690 AppendToBuffer("movss ");
1691 int mod, regop, rm;
1692 get_modrm(*current, &mod, &regop, &rm);
1693 if (opcode == 0x11) {
1694 current += PrintRightOperand(current);
1695 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1696 } else {
1697 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1698 current += PrintRightOperand(current);
1699 }
1700 } else if (opcode == 0x2A) {
1701 // CVTSI2SS: integer to XMM single conversion.
1702 int mod, regop, rm;
1703 get_modrm(*current, &mod, &regop, &rm);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001704 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Block8defd9f2010-07-08 12:39:36 +01001705 current += PrintRightOperand(current);
1706 } else if (opcode == 0x2C) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001707 // CVTTSS2SI:
1708 // Convert with truncation scalar single-precision FP to dword integer.
Steve Block1e0659c2011-05-24 12:43:12 +01001709 int mod, regop, rm;
1710 get_modrm(*current, &mod, &regop, &rm);
1711 AppendToBuffer("cvttss2si%c %s,",
1712 operand_size_code(), NameOfCPURegister(regop));
1713 current += PrintRightXMMOperand(current);
Ben Murdoch257744e2011-11-30 15:57:28 +00001714 } else if (opcode == 0x7E) {
1715 int mod, regop, rm;
1716 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001717 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001718 current += PrintRightXMMOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001719 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1720 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1721 int mod, regop, rm;
1722 get_modrm(*current, &mod, &regop, &rm);
1723 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1724 current += PrintRightXMMOperand(current);
1725 } else if (opcode == 0xB8) {
1726 int mod, regop, rm;
1727 get_modrm(*current, &mod, &regop, &rm);
1728 AppendToBuffer("popcnt%c %s,", operand_size_code(),
1729 NameOfCPURegister(regop));
1730 current += PrintRightOperand(current);
1731 } else if (opcode == 0xBC) {
1732 int mod, regop, rm;
1733 get_modrm(*current, &mod, &regop, &rm);
1734 AppendToBuffer("tzcnt%c %s,", operand_size_code(),
1735 NameOfCPURegister(regop));
1736 current += PrintRightOperand(current);
1737 } else if (opcode == 0xBD) {
1738 int mod, regop, rm;
1739 get_modrm(*current, &mod, &regop, &rm);
1740 AppendToBuffer("lzcnt%c %s,", operand_size_code(),
1741 NameOfCPURegister(regop));
1742 current += PrintRightOperand(current);
1743 } else if (opcode == 0xC2) {
1744 // Intel manual 2A, Table 3-18.
1745 int mod, regop, rm;
1746 get_modrm(*current, &mod, &regop, &rm);
1747 const char* const pseudo_op[] = {"cmpeqss", "cmpltss", "cmpless",
1748 "cmpunordss", "cmpneqss", "cmpnltss",
1749 "cmpnless", "cmpordss"};
1750 AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
1751 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
1752 current += 2;
Steve Block6ded16b2010-05-10 14:33:55 +01001753 } else {
1754 UnimplementedInstruction();
1755 }
Andrei Popescu402d9372010-02-26 13:31:12 +00001756 } else if (opcode == 0x1F) {
1757 // NOP
1758 int mod, regop, rm;
1759 get_modrm(*current, &mod, &regop, &rm);
1760 current++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001761 if (rm == 4) { // SIB byte present.
Andrei Popescu402d9372010-02-26 13:31:12 +00001762 current++;
1763 }
1764 if (mod == 1) { // Byte displacement.
1765 current += 1;
1766 } else if (mod == 2) { // 32-bit displacement.
1767 current += 4;
1768 } // else no immediate displacement.
1769 AppendToBuffer("nop");
Ben Murdoch257744e2011-11-30 15:57:28 +00001770
1771 } else if (opcode == 0x28) {
1772 // movaps xmm, xmm/m128
1773 int mod, regop, rm;
1774 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001775 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001776 current += PrintRightXMMOperand(current);
1777
1778 } else if (opcode == 0x29) {
1779 // movaps xmm/m128, xmm
1780 int mod, regop, rm;
1781 get_modrm(*current, &mod, &regop, &rm);
1782 AppendToBuffer("movaps ");
1783 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001784 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001785
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001786 } else if (opcode == 0x2e) {
1787 int mod, regop, rm;
1788 get_modrm(*current, &mod, &regop, &rm);
1789 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1790 current += PrintRightXMMOperand(current);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001791 } else if (opcode == 0xA2) {
1792 // CPUID
Andrei Popescu402d9372010-02-26 13:31:12 +00001793 AppendToBuffer("%s", mnemonic);
1794
1795 } else if ((opcode & 0xF0) == 0x40) {
1796 // CMOVcc: conditional move.
1797 int condition = opcode & 0x0F;
1798 const InstructionDesc& idesc = cmov_instructions[condition];
1799 byte_size_operand_ = idesc.byte_size_operation;
1800 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001802 } else if (opcode >= 0x53 && opcode <= 0x5F) {
1803 const char* const pseudo_op[] = {
1804 "rcpps",
1805 "andps",
1806 "andnps",
1807 "orps",
1808 "xorps",
1809 "addps",
1810 "mulps",
1811 "cvtps2pd",
1812 "cvtdq2ps",
1813 "subps",
1814 "minps",
1815 "divps",
1816 "maxps",
1817 };
Ben Murdoch257744e2011-11-30 15:57:28 +00001818 int mod, regop, rm;
1819 get_modrm(*current, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001820 AppendToBuffer("%s %s,",
1821 pseudo_op[opcode - 0x53],
1822 NameOfXMMRegister(regop));
1823 current += PrintRightXMMOperand(current);
1824
1825 } else if (opcode == 0xC6) {
1826 // shufps xmm, xmm/m128, imm8
1827 int mod, regop, rm;
1828 get_modrm(*current, &mod, &regop, &rm);
1829 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
1830 current += PrintRightXMMOperand(current);
1831 AppendToBuffer(", %d", (*current) & 3);
1832 current += 1;
1833
1834 } else if (opcode == 0x50) {
1835 // movmskps reg, xmm
1836 int mod, regop, rm;
1837 get_modrm(*current, &mod, &regop, &rm);
1838 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
Ben Murdoch257744e2011-11-30 15:57:28 +00001839 current += PrintRightXMMOperand(current);
1840
Andrei Popescu402d9372010-02-26 13:31:12 +00001841 } else if ((opcode & 0xF0) == 0x80) {
1842 // Jcc: Conditional jump (branch).
1843 current = data + JumpConditional(data);
1844
1845 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1846 opcode == 0xB7 || opcode == 0xAF) {
1847 // Size-extending moves, IMUL.
1848 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1849
1850 } else if ((opcode & 0xF0) == 0x90) {
1851 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1852 current = data + SetCC(data);
1853
1854 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1855 // SHLD, SHRD (double-precision shift), BTS (bit set).
1856 AppendToBuffer("%s ", mnemonic);
1857 int mod, regop, rm;
1858 get_modrm(*current, &mod, &regop, &rm);
1859 current += PrintRightOperand(current);
1860 if (opcode == 0xAB) {
1861 AppendToBuffer(",%s", NameOfCPURegister(regop));
1862 } else {
1863 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1864 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001865 } else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
1866 // POPCNT, CTZ, CLZ.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001867 AppendToBuffer("%s%c ", mnemonic, operand_size_code());
1868 int mod, regop, rm;
1869 get_modrm(*current, &mod, &regop, &rm);
1870 AppendToBuffer("%s,", NameOfCPURegister(regop));
1871 current += PrintRightOperand(current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001872 } else if (opcode == 0x0B) {
1873 AppendToBuffer("ud2");
Steve Blocka7e24c12009-10-30 11:49:00 +00001874 } else {
1875 UnimplementedInstruction();
1876 }
Steve Blockd0582a62009-12-15 09:54:21 +00001877 return static_cast<int>(current - data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001878}
1879
1880
1881// Mnemonics for two-byte opcode instructions starting with 0x0F.
1882// The argument is the second byte of the two-byte opcode.
1883// Returns NULL if the instruction is not handled here.
1884const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1885 switch (opcode) {
1886 case 0x1F:
1887 return "nop";
Steve Block8defd9f2010-07-08 12:39:36 +01001888 case 0x2A: // F2/F3 prefix.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001889 return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
1890 case 0x51: // F2/F3 prefix.
1891 return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
1892 case 0x58: // F2/F3 prefix.
1893 return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
1894 case 0x59: // F2/F3 prefix.
1895 return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
1896 case 0x5A: // F2/F3 prefix.
1897 return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
1898 case 0x5D: // F2/F3 prefix.
1899 return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
1900 case 0x5C: // F2/F3 prefix.
1901 return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
1902 case 0x5E: // F2/F3 prefix.
1903 return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
1904 case 0x5F: // F2/F3 prefix.
1905 return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
Steve Blocka7e24c12009-10-30 11:49:00 +00001906 case 0xA2:
1907 return "cpuid";
1908 case 0xA5:
1909 return "shld";
1910 case 0xAB:
1911 return "bts";
1912 case 0xAD:
1913 return "shrd";
1914 case 0xAF:
1915 return "imul";
1916 case 0xB6:
1917 return "movzxb";
1918 case 0xB7:
1919 return "movzxw";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001920 case 0xBC:
1921 return "bsf";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001922 case 0xBD:
1923 return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001924 case 0xBE:
1925 return "movsxb";
1926 case 0xBF:
1927 return "movsxw";
1928 default:
1929 return NULL;
1930 }
1931}
1932
1933
1934// Disassembles the instruction at instr, and writes it into out_buffer.
1935int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1936 byte* instr) {
1937 tmp_buffer_pos_ = 0; // starting to write as position 0
1938 byte* data = instr;
1939 bool processed = true; // Will be set to false if the current instruction
1940 // is not in 'instructions' table.
1941 byte current;
1942
1943 // Scan for prefixes.
1944 while (true) {
1945 current = *data;
Leon Clarked91b9f72010-01-27 17:25:45 +00001946 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 operand_size_ = current;
1948 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1949 setRex(current);
1950 if (rex_w()) AppendToBuffer("REX.W ");
Leon Clarked91b9f72010-01-27 17:25:45 +00001951 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
Steve Blocka7e24c12009-10-30 11:49:00 +00001952 group_1_prefix_ = current;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001953 } else if (current == VEX3_PREFIX) {
1954 vex_byte0_ = current;
1955 vex_byte1_ = *(data + 1);
1956 vex_byte2_ = *(data + 2);
1957 setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001958 data += 3;
1959 break; // Vex is the last prefix.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001960 } else if (current == VEX2_PREFIX) {
1961 vex_byte0_ = current;
1962 vex_byte1_ = *(data + 1);
1963 setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001964 data += 2;
1965 break; // Vex is the last prefix.
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 } else { // Not a prefix - an opcode.
1967 break;
1968 }
1969 data++;
1970 }
1971
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001972 // Decode AVX instructions.
1973 if (vex_byte0_ != 0) {
1974 processed = true;
1975 data += AVXInstruction(data);
1976 } else {
1977 const InstructionDesc& idesc = instruction_table_->Get(current);
1978 byte_size_operand_ = idesc.byte_size_operation;
1979 switch (idesc.type) {
1980 case ZERO_OPERANDS_INSTR:
1981 if (current >= 0xA4 && current <= 0xA7) {
1982 // String move or compare operations.
1983 if (group_1_prefix_ == REP_PREFIX) {
1984 // REP.
1985 AppendToBuffer("rep ");
1986 }
1987 if (rex_w()) AppendToBuffer("REX.W ");
1988 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1989 } else {
1990 AppendToBuffer("%s", idesc.mnem, operand_size_code());
Leon Clarked91b9f72010-01-27 17:25:45 +00001991 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001992 data++;
1993 break;
1994
1995 case TWO_OPERANDS_INSTR:
1996 data++;
1997 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1998 break;
1999
2000 case JUMP_CONDITIONAL_SHORT_INSTR:
2001 data += JumpConditionalShort(data);
2002 break;
2003
2004 case REGISTER_INSTR:
2005 AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
2006 NameOfCPURegister(base_reg(current & 0x07)));
2007 data++;
2008 break;
2009 case PUSHPOP_INSTR:
2010 AppendToBuffer("%s %s", idesc.mnem,
2011 NameOfCPURegister(base_reg(current & 0x07)));
2012 data++;
2013 break;
2014 case MOVE_REG_INSTR: {
2015 byte* addr = NULL;
2016 switch (operand_size()) {
2017 case OPERAND_WORD_SIZE:
2018 addr =
2019 reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
2020 data += 3;
2021 break;
2022 case OPERAND_DOUBLEWORD_SIZE:
2023 addr =
2024 reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
2025 data += 5;
2026 break;
2027 case OPERAND_QUADWORD_SIZE:
2028 addr =
2029 reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
2030 data += 9;
2031 break;
2032 default:
2033 UNREACHABLE();
2034 }
2035 AppendToBuffer("mov%c %s,%s", operand_size_code(),
2036 NameOfCPURegister(base_reg(current & 0x07)),
2037 NameOfAddress(addr));
2038 break;
Leon Clarked91b9f72010-01-27 17:25:45 +00002039 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002040
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002041 case CALL_JUMP_INSTR: {
2042 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
2043 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
2044 data += 5;
2045 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002046 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002047
2048 case SHORT_IMMEDIATE_INSTR: {
2049 byte* addr =
2050 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
2051 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
2052 data += 5;
2053 break;
2054 }
2055
2056 case NO_INSTR:
2057 processed = false;
2058 break;
2059
2060 default:
2061 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00002062 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002063 }
2064
2065 // The first byte didn't match any of the simple opcodes, so we
2066 // need to do special processing on it.
2067 if (!processed) {
2068 switch (*data) {
2069 case 0xC2:
2070 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
2071 data += 3;
2072 break;
2073
2074 case 0x69: // fall through
2075 case 0x6B: {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002076 int count = 1;
2077 count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
2078 AppendToBuffer(",0x");
2079 if (*data == 0x69) {
2080 count += PrintImmediate(data + count, operand_size());
2081 } else {
2082 count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
2083 }
2084 data += count;
Steve Blocka7e24c12009-10-30 11:49:00 +00002085 break;
2086 }
2087
Steve Blocka7e24c12009-10-30 11:49:00 +00002088 case 0x81: // fall through
2089 case 0x83: // 0x81 with sign extension bit set
2090 data += PrintImmediateOp(data);
2091 break;
2092
2093 case 0x0F:
2094 data += TwoByteOpcodeInstruction(data);
2095 break;
2096
2097 case 0x8F: {
2098 data++;
2099 int mod, regop, rm;
2100 get_modrm(*data, &mod, &regop, &rm);
2101 if (regop == 0) {
2102 AppendToBuffer("pop ");
2103 data += PrintRightOperand(data);
2104 }
2105 }
2106 break;
2107
2108 case 0xFF: {
2109 data++;
2110 int mod, regop, rm;
2111 get_modrm(*data, &mod, &regop, &rm);
2112 const char* mnem = NULL;
2113 switch (regop) {
2114 case 0:
2115 mnem = "inc";
2116 break;
2117 case 1:
2118 mnem = "dec";
2119 break;
2120 case 2:
2121 mnem = "call";
2122 break;
2123 case 4:
2124 mnem = "jmp";
2125 break;
2126 case 6:
2127 mnem = "push";
2128 break;
2129 default:
2130 mnem = "???";
2131 }
2132 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
2133 mnem,
2134 operand_size_code());
2135 data += PrintRightOperand(data);
2136 }
2137 break;
2138
2139 case 0xC7: // imm32, fall through
2140 case 0xC6: // imm8
2141 {
2142 bool is_byte = *data == 0xC6;
2143 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01002144 if (is_byte) {
2145 AppendToBuffer("movb ");
2146 data += PrintRightByteOperand(data);
2147 int32_t imm = *data;
2148 AppendToBuffer(",0x%x", imm);
2149 data++;
2150 } else {
2151 AppendToBuffer("mov%c ", operand_size_code());
2152 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002153 if (operand_size() == OPERAND_WORD_SIZE) {
2154 int16_t imm = *reinterpret_cast<int16_t*>(data);
2155 AppendToBuffer(",0x%x", imm);
2156 data += 2;
2157 } else {
2158 int32_t imm = *reinterpret_cast<int32_t*>(data);
2159 AppendToBuffer(",0x%x", imm);
2160 data += 4;
2161 }
Steve Block44f0eee2011-05-26 01:26:41 +01002162 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002163 }
2164 break;
2165
2166 case 0x80: {
2167 data++;
2168 AppendToBuffer("cmpb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002169 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002170 int32_t imm = *data;
2171 AppendToBuffer(",0x%x", imm);
2172 data++;
2173 }
2174 break;
2175
2176 case 0x88: // 8bit, fall through
2177 case 0x89: // 32bit
2178 {
2179 bool is_byte = *data == 0x88;
2180 int mod, regop, rm;
2181 data++;
2182 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01002183 if (is_byte) {
2184 AppendToBuffer("movb ");
2185 data += PrintRightByteOperand(data);
2186 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2187 } else {
2188 AppendToBuffer("mov%c ", operand_size_code());
2189 data += PrintRightOperand(data);
2190 AppendToBuffer(",%s", NameOfCPURegister(regop));
2191 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002192 }
2193 break;
2194
2195 case 0x90:
2196 case 0x91:
2197 case 0x92:
2198 case 0x93:
2199 case 0x94:
2200 case 0x95:
2201 case 0x96:
2202 case 0x97: {
Steve Blockd0582a62009-12-15 09:54:21 +00002203 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00002204 if (reg == 0) {
2205 AppendToBuffer("nop"); // Common name for xchg rax,rax.
2206 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002207 AppendToBuffer("xchg%c rax,%s",
Steve Blocka7e24c12009-10-30 11:49:00 +00002208 operand_size_code(),
2209 NameOfCPURegister(reg));
2210 }
Steve Blockd0582a62009-12-15 09:54:21 +00002211 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00002212 }
Steve Blockd0582a62009-12-15 09:54:21 +00002213 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002214 case 0xB0:
2215 case 0xB1:
2216 case 0xB2:
2217 case 0xB3:
2218 case 0xB4:
2219 case 0xB5:
2220 case 0xB6:
2221 case 0xB7:
2222 case 0xB8:
2223 case 0xB9:
2224 case 0xBA:
2225 case 0xBB:
2226 case 0xBC:
2227 case 0xBD:
2228 case 0xBE:
2229 case 0xBF: {
2230 // mov reg8,imm8 or mov reg32,imm32
2231 byte opcode = *data;
2232 data++;
2233 bool is_32bit = (opcode >= 0xB8);
2234 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
2235 if (is_32bit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002236 AppendToBuffer("mov%c %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002237 operand_size_code(),
2238 NameOfCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002239 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002240 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002241 AppendToBuffer("movb %s,",
Ben Murdoch8b112d22011-06-08 16:22:53 +01002242 NameOfByteCPURegister(reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002243 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002244 }
2245 break;
2246 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002247 case 0xFE: {
2248 data++;
2249 int mod, regop, rm;
2250 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002251 if (regop == 1) {
2252 AppendToBuffer("decb ");
Steve Block44f0eee2011-05-26 01:26:41 +01002253 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 } else {
2255 UnimplementedInstruction();
2256 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002257 break;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002258 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002259 case 0x68:
2260 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
2261 data += 5;
2262 break;
2263
2264 case 0x6A:
2265 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
2266 data += 2;
2267 break;
2268
2269 case 0xA1: // Fall through.
2270 case 0xA3:
2271 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002272 case OPERAND_DOUBLEWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002273 const char* memory_location = NameOfAddress(
2274 reinterpret_cast<byte*>(
2275 *reinterpret_cast<int32_t*>(data + 1)));
2276 if (*data == 0xA1) { // Opcode 0xA1
2277 AppendToBuffer("movzxlq rax,(%s)", memory_location);
2278 } else { // Opcode 0xA3
2279 AppendToBuffer("movzxlq (%s),rax", memory_location);
2280 }
2281 data += 5;
2282 break;
2283 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002284 case OPERAND_QUADWORD_SIZE: {
Steve Blocka7e24c12009-10-30 11:49:00 +00002285 // New x64 instruction mov rax,(imm_64).
2286 const char* memory_location = NameOfAddress(
2287 *reinterpret_cast<byte**>(data + 1));
2288 if (*data == 0xA1) { // Opcode 0xA1
2289 AppendToBuffer("movq rax,(%s)", memory_location);
2290 } else { // Opcode 0xA3
2291 AppendToBuffer("movq (%s),rax", memory_location);
2292 }
2293 data += 9;
2294 break;
2295 }
2296 default:
2297 UnimplementedInstruction();
2298 data += 2;
2299 }
2300 break;
2301
2302 case 0xA8:
2303 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
2304 data += 2;
2305 break;
2306
2307 case 0xA9: {
2308 int64_t value = 0;
2309 switch (operand_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002310 case OPERAND_WORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002311 value = *reinterpret_cast<uint16_t*>(data + 1);
2312 data += 3;
2313 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002314 case OPERAND_DOUBLEWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002315 value = *reinterpret_cast<uint32_t*>(data + 1);
2316 data += 5;
2317 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002318 case OPERAND_QUADWORD_SIZE:
Steve Blocka7e24c12009-10-30 11:49:00 +00002319 value = *reinterpret_cast<int32_t*>(data + 1);
2320 data += 5;
2321 break;
2322 default:
2323 UNREACHABLE();
2324 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002325 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
Steve Blocka7e24c12009-10-30 11:49:00 +00002326 operand_size_code(),
2327 value);
2328 break;
2329 }
2330 case 0xD1: // fall through
2331 case 0xD3: // fall through
2332 case 0xC1:
2333 data += ShiftInstruction(data);
2334 break;
2335 case 0xD0: // fall through
2336 case 0xD2: // fall through
2337 case 0xC0:
2338 byte_size_operand_ = true;
2339 data += ShiftInstruction(data);
2340 break;
2341
2342 case 0xD9: // fall through
2343 case 0xDA: // fall through
2344 case 0xDB: // fall through
2345 case 0xDC: // fall through
2346 case 0xDD: // fall through
2347 case 0xDE: // fall through
2348 case 0xDF:
2349 data += FPUInstruction(data);
2350 break;
2351
2352 case 0xEB:
2353 data += JumpShort(data);
2354 break;
2355
Steve Blockd0582a62009-12-15 09:54:21 +00002356 case 0xF6:
2357 byte_size_operand_ = true; // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00002358 case 0xF7:
Steve Blockd0582a62009-12-15 09:54:21 +00002359 data += F6F7Instruction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00002360 break;
2361
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002362 case 0x3C:
2363 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2364 data +=2;
2365 break;
2366
Steve Blocka7e24c12009-10-30 11:49:00 +00002367 default:
2368 UnimplementedInstruction();
2369 data += 1;
2370 }
2371 } // !processed
2372
2373 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2374 tmp_buffer_[tmp_buffer_pos_] = '\0';
2375 }
2376
Steve Blockd0582a62009-12-15 09:54:21 +00002377 int instr_len = static_cast<int>(data - instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002378 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00002379
2380 int outp = 0;
2381 // Instruction bytes.
2382 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002383 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00002384 }
2385 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002386 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00002387 }
2388
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002389 outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2390 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00002391 return instr_len;
2392}
2393
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002394
Steve Blocka7e24c12009-10-30 11:49:00 +00002395//------------------------------------------------------------------------------
2396
2397
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002398static const char* const cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002399 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2400 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2401};
2402
2403
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002404static const char* const byte_cpu_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002405 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2406 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2407};
2408
2409
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002410static const char* const xmm_regs[16] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00002411 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2412 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2413};
2414
2415
2416const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002417 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01002418 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00002419}
2420
2421
2422const char* NameConverter::NameOfConstant(byte* addr) const {
2423 return NameOfAddress(addr);
2424}
2425
2426
2427const char* NameConverter::NameOfCPURegister(int reg) const {
2428 if (0 <= reg && reg < 16)
2429 return cpu_regs[reg];
2430 return "noreg";
2431}
2432
2433
2434const char* NameConverter::NameOfByteCPURegister(int reg) const {
2435 if (0 <= reg && reg < 16)
2436 return byte_cpu_regs[reg];
2437 return "noreg";
2438}
2439
2440
2441const char* NameConverter::NameOfXMMRegister(int reg) const {
2442 if (0 <= reg && reg < 16)
2443 return xmm_regs[reg];
2444 return "noxmmreg";
2445}
2446
2447
2448const char* NameConverter::NameInCode(byte* addr) const {
2449 // X64 does not embed debug strings at the moment.
2450 UNREACHABLE();
2451 return "";
2452}
2453
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002454
Steve Blocka7e24c12009-10-30 11:49:00 +00002455//------------------------------------------------------------------------------
2456
2457Disassembler::Disassembler(const NameConverter& converter)
2458 : converter_(converter) { }
2459
2460Disassembler::~Disassembler() { }
2461
2462
2463int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2464 byte* instruction) {
2465 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2466 return d.InstructionDecode(buffer, instruction);
2467}
2468
2469
2470// The X64 assembler does not use constant pools.
2471int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2472 return -1;
2473}
2474
2475
2476void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2477 NameConverter converter;
2478 Disassembler d(converter);
2479 for (byte* pc = begin; pc < end;) {
2480 v8::internal::EmbeddedVector<char, 128> buffer;
2481 buffer[0] = '\0';
2482 byte* prev_pc = pc;
2483 pc += d.InstructionDecode(buffer, pc);
2484 fprintf(f, "%p", prev_pc);
2485 fprintf(f, " ");
2486
2487 for (byte* bp = prev_pc; bp < pc; bp++) {
2488 fprintf(f, "%02x", *bp);
2489 }
Steve Blockd0582a62009-12-15 09:54:21 +00002490 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002491 fprintf(f, " ");
2492 }
2493 fprintf(f, " %s\n", buffer.start());
2494 }
2495}
2496
2497} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01002498
2499#endif // V8_TARGET_ARCH_X64