blob: 667561b7cf2571d6a2b60c444fc939baa2e54cf8 [file] [log] [blame]
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000028#include <assert.h>
29#include <stdio.h>
30#include <stdarg.h>
31
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000032#include "v8.h"
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000033
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000034#if V8_TARGET_ARCH_X64
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000035
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000036#include "disasm.h"
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000037#include "lazy-instance.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000038
39namespace disasm {
40
kasperl@chromium.orge959c182009-07-27 08:59:04 +000041enum OperandType {
42 UNSET_OP_ORDER = 0,
43 // Operand size decides between 16, 32 and 64 bit operands.
44 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
45 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
46 // Fixed 8-bit operands.
47 BYTE_SIZE_OPERAND_FLAG = 4,
48 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
49 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000050};
51
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000052
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000053//------------------------------------------------------------------
54// Tables
55//------------------------------------------------------------------
56struct ByteMnemonic {
57 int b; // -1 terminates, otherwise must be in range (0..255)
kasperl@chromium.orge959c182009-07-27 08:59:04 +000058 OperandType op_order_;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000059 const char* mnem;
60};
61
62
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000063static const ByteMnemonic two_operands_instr[] = {
kasperl@chromium.orge959c182009-07-27 08:59:04 +000064 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
65 { 0x01, OPER_REG_OP_ORDER, "add" },
66 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
67 { 0x03, REG_OPER_OP_ORDER, "add" },
68 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
69 { 0x09, OPER_REG_OP_ORDER, "or" },
70 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
71 { 0x0B, REG_OPER_OP_ORDER, "or" },
72 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
73 { 0x11, OPER_REG_OP_ORDER, "adc" },
74 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
75 { 0x13, REG_OPER_OP_ORDER, "adc" },
76 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
77 { 0x19, OPER_REG_OP_ORDER, "sbb" },
78 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
79 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
80 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
81 { 0x21, OPER_REG_OP_ORDER, "and" },
82 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
83 { 0x23, REG_OPER_OP_ORDER, "and" },
84 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
85 { 0x29, OPER_REG_OP_ORDER, "sub" },
86 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
87 { 0x2B, REG_OPER_OP_ORDER, "sub" },
88 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
89 { 0x31, OPER_REG_OP_ORDER, "xor" },
90 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
91 { 0x33, REG_OPER_OP_ORDER, "xor" },
92 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
93 { 0x39, OPER_REG_OP_ORDER, "cmp" },
94 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
95 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
machenbach@chromium.org528ce022013-09-23 14:09:36 +000096 { 0x63, REG_OPER_OP_ORDER, "movsxl" },
kasperl@chromium.orge959c182009-07-27 08:59:04 +000097 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
98 { 0x85, REG_OPER_OP_ORDER, "test" },
99 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
100 { 0x87, REG_OPER_OP_ORDER, "xchg" },
101 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
102 { 0x89, OPER_REG_OP_ORDER, "mov" },
103 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
104 { 0x8B, REG_OPER_OP_ORDER, "mov" },
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000105 { 0x8D, REG_OPER_OP_ORDER, "lea" },
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000106 { -1, UNSET_OP_ORDER, "" }
107};
108
109
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000110static const ByteMnemonic zero_operands_instr[] = {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000111 { 0xC3, UNSET_OP_ORDER, "ret" },
112 { 0xC9, UNSET_OP_ORDER, "leave" },
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000113 { 0xF4, UNSET_OP_ORDER, "hlt" },
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000114 { 0xFC, UNSET_OP_ORDER, "cld" },
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000115 { 0xCC, UNSET_OP_ORDER, "int3" },
116 { 0x60, UNSET_OP_ORDER, "pushad" },
117 { 0x61, UNSET_OP_ORDER, "popad" },
118 { 0x9C, UNSET_OP_ORDER, "pushfd" },
119 { 0x9D, UNSET_OP_ORDER, "popfd" },
120 { 0x9E, UNSET_OP_ORDER, "sahf" },
121 { 0x99, UNSET_OP_ORDER, "cdq" },
122 { 0x9B, UNSET_OP_ORDER, "fwait" },
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123 { 0xA4, UNSET_OP_ORDER, "movs" },
124 { 0xA5, UNSET_OP_ORDER, "movs" },
125 { 0xA6, UNSET_OP_ORDER, "cmps" },
126 { 0xA7, UNSET_OP_ORDER, "cmps" },
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000127 { -1, UNSET_OP_ORDER, "" }
128};
129
130
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000131static const ByteMnemonic call_jump_instr[] = {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000132 { 0xE8, UNSET_OP_ORDER, "call" },
133 { 0xE9, UNSET_OP_ORDER, "jmp" },
134 { -1, UNSET_OP_ORDER, "" }
135};
136
137
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000138static const ByteMnemonic short_immediate_instr[] = {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000139 { 0x05, UNSET_OP_ORDER, "add" },
140 { 0x0D, UNSET_OP_ORDER, "or" },
141 { 0x15, UNSET_OP_ORDER, "adc" },
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000142 { 0x1D, UNSET_OP_ORDER, "sbb" },
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000143 { 0x25, UNSET_OP_ORDER, "and" },
144 { 0x2D, UNSET_OP_ORDER, "sub" },
145 { 0x35, UNSET_OP_ORDER, "xor" },
146 { 0x3D, UNSET_OP_ORDER, "cmp" },
147 { -1, UNSET_OP_ORDER, "" }
148};
149
150
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000151static const char* const conditional_code_suffix[] = {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000152 "o", "no", "c", "nc", "z", "nz", "na", "a",
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000153 "s", "ns", "pe", "po", "l", "ge", "le", "g"
154};
155
156
157enum InstructionType {
158 NO_INSTR,
159 ZERO_OPERANDS_INSTR,
160 TWO_OPERANDS_INSTR,
161 JUMP_CONDITIONAL_SHORT_INSTR,
162 REGISTER_INSTR,
163 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
164 MOVE_REG_INSTR,
165 CALL_JUMP_INSTR,
166 SHORT_IMMEDIATE_INSTR
167};
168
169
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000170enum Prefixes {
171 ESCAPE_PREFIX = 0x0F,
172 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
173 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
174 REPNE_PREFIX = 0xF2,
175 REP_PREFIX = 0xF3,
176 REPEQ_PREFIX = REP_PREFIX
177};
178
179
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000180struct InstructionDesc {
181 const char* mnem;
182 InstructionType type;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000183 OperandType op_order_;
184 bool byte_size_operation; // Fixed 8-bit operation.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000185};
186
187
188class InstructionTable {
189 public:
190 InstructionTable();
191 const InstructionDesc& Get(byte x) const {
192 return instructions_[x];
193 }
194
195 private:
196 InstructionDesc instructions_[256];
197 void Clear();
198 void Init();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000199 void CopyTable(const ByteMnemonic bm[], InstructionType type);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000200 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000201 const char* mnem);
202 void AddJumpConditionalShort();
203};
204
205
206InstructionTable::InstructionTable() {
207 Clear();
208 Init();
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000209}
210
211
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000212void InstructionTable::Clear() {
213 for (int i = 0; i < 256; i++) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000214 instructions_[i].mnem = "(bad)";
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000215 instructions_[i].type = NO_INSTR;
216 instructions_[i].op_order_ = UNSET_OP_ORDER;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000217 instructions_[i].byte_size_operation = false;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000218 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000219}
220
221
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000222void InstructionTable::Init() {
223 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
224 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
225 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
226 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
227 AddJumpConditionalShort();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000228 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
229 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
230 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000231}
232
233
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000234void InstructionTable::CopyTable(const ByteMnemonic bm[],
235 InstructionType type) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000236 for (int i = 0; bm[i].b >= 0; i++) {
237 InstructionDesc* id = &instructions_[bm[i].b];
238 id->mnem = bm[i].mnem;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000239 OperandType op_order = bm[i].op_order_;
240 id->op_order_ =
241 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
ager@chromium.org3811b432009-10-28 14:53:37 +0000242 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000243 id->type = type;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000244 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000245 }
246}
247
248
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000249void InstructionTable::SetTableRange(InstructionType type,
250 byte start,
251 byte end,
252 bool byte_size,
253 const char* mnem) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000254 for (byte b = start; b <= end; b++) {
255 InstructionDesc* id = &instructions_[b];
ager@chromium.org3811b432009-10-28 14:53:37 +0000256 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000257 id->mnem = mnem;
258 id->type = type;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000259 id->byte_size_operation = byte_size;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000260 }
261}
262
263
264void InstructionTable::AddJumpConditionalShort() {
265 for (byte b = 0x70; b <= 0x7F; b++) {
266 InstructionDesc* id = &instructions_[b];
ager@chromium.org3811b432009-10-28 14:53:37 +0000267 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000268 id->mnem = NULL; // Computed depending on condition code.
269 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
270 }
271}
272
273
jkummerow@chromium.org1456e702012-03-30 08:38:13 +0000274static v8::internal::LazyInstance<InstructionTable>::type instruction_table =
275 LAZY_INSTANCE_INITIALIZER;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000277
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000278static InstructionDesc cmov_instructions[16] = {
279 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
280 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
281 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
282 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
283 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
284 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
285 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
286 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
287 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
288 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
289 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
290 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
291 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
292 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
293 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
294 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
295};
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000296
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000297
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000298//------------------------------------------------------------------------------
299// DisassemblerX64 implementation.
300
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000301enum UnimplementedOpcodeAction {
302 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
303 ABORT_ON_UNIMPLEMENTED_OPCODE
304};
305
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000306
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000307// A new DisassemblerX64 object is created to disassemble each instruction.
308// The object can only disassemble a single instruction.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000309class DisassemblerX64 {
310 public:
311 DisassemblerX64(const NameConverter& converter,
312 UnimplementedOpcodeAction unimplemented_action =
313 ABORT_ON_UNIMPLEMENTED_OPCODE)
314 : converter_(converter),
315 tmp_buffer_pos_(0),
316 abort_on_unimplemented_(
317 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
318 rex_(0),
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000319 operand_size_(0),
320 group_1_prefix_(0),
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000321 byte_size_operand_(false),
322 instruction_table_(instruction_table.Pointer()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000323 tmp_buffer_[0] = '\0';
324 }
325
326 virtual ~DisassemblerX64() {
327 }
328
329 // Writes one disassembled instruction into 'buffer' (0-terminated).
330 // Returns the length of the disassembled machine instruction in bytes.
331 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
332
333 private:
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000334 enum OperandSize {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000335 OPERAND_BYTE_SIZE = 0,
336 OPERAND_WORD_SIZE = 1,
337 OPERAND_DOUBLEWORD_SIZE = 2,
338 OPERAND_QUADWORD_SIZE = 3
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000339 };
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000340
341 const NameConverter& converter_;
342 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
343 unsigned int tmp_buffer_pos_;
344 bool abort_on_unimplemented_;
345 // Prefixes parsed
346 byte rex_;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000347 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
348 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
349 // Byte size operand override.
350 bool byte_size_operand_;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000351 const InstructionTable* const instruction_table_;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000352
353 void setRex(byte rex) {
354 ASSERT_EQ(0x40, rex & 0xF0);
355 rex_ = rex;
356 }
357
358 bool rex() { return rex_ != 0; }
359
360 bool rex_b() { return (rex_ & 0x01) != 0; }
361
362 // Actual number of base register given the low bits and the rex.b state.
363 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
364
365 bool rex_x() { return (rex_ & 0x02) != 0; }
366
367 bool rex_r() { return (rex_ & 0x04) != 0; }
368
369 bool rex_w() { return (rex_ & 0x08) != 0; }
370
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000371 OperandSize operand_size() {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000372 if (byte_size_operand_) return OPERAND_BYTE_SIZE;
373 if (rex_w()) return OPERAND_QUADWORD_SIZE;
374 if (operand_size_ != 0) return OPERAND_WORD_SIZE;
375 return OPERAND_DOUBLEWORD_SIZE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000376 }
377
378 char operand_size_code() {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000379 return "bwlq"[operand_size()];
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000380 }
381
382 const char* NameOfCPURegister(int reg) const {
383 return converter_.NameOfCPURegister(reg);
384 }
385
386 const char* NameOfByteCPURegister(int reg) const {
387 return converter_.NameOfByteCPURegister(reg);
388 }
389
390 const char* NameOfXMMRegister(int reg) const {
391 return converter_.NameOfXMMRegister(reg);
392 }
393
394 const char* NameOfAddress(byte* addr) const {
395 return converter_.NameOfAddress(addr);
396 }
397
398 // Disassembler helper functions.
399 void get_modrm(byte data,
400 int* mod,
401 int* regop,
402 int* rm) {
403 *mod = (data >> 6) & 3;
404 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
405 *rm = (data & 7) | (rex_b() ? 8 : 0);
406 }
407
408 void get_sib(byte data,
409 int* scale,
410 int* index,
411 int* base) {
412 *scale = (data >> 6) & 3;
413 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000414 *base = (data & 7) | (rex_b() ? 8 : 0);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000415 }
416
417 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
418
419 int PrintRightOperandHelper(byte* modrmp,
420 RegisterNameMapping register_name);
421 int PrintRightOperand(byte* modrmp);
422 int PrintRightByteOperand(byte* modrmp);
ager@chromium.org3811b432009-10-28 14:53:37 +0000423 int PrintRightXMMOperand(byte* modrmp);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000424 int PrintOperands(const char* mnem,
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000425 OperandType op_order,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000426 byte* data);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000427 int PrintImmediate(byte* data, OperandSize size);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000428 int PrintImmediateOp(byte* data);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000429 const char* TwoByteMnemonic(byte opcode);
430 int TwoByteOpcodeInstruction(byte* data);
ager@chromium.org3811b432009-10-28 14:53:37 +0000431 int F6F7Instruction(byte* data);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000432 int ShiftInstruction(byte* data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000433 int JumpShort(byte* data);
434 int JumpConditional(byte* data);
435 int JumpConditionalShort(byte* data);
436 int SetCC(byte* data);
437 int FPUInstruction(byte* data);
ager@chromium.org3811b432009-10-28 14:53:37 +0000438 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
439 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000440 void AppendToBuffer(const char* format, ...);
441
442 void UnimplementedInstruction() {
443 if (abort_on_unimplemented_) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000444 CHECK(false);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000445 } else {
446 AppendToBuffer("'Unimplemented Instruction'");
447 }
448 }
449};
450
451
452void DisassemblerX64::AppendToBuffer(const char* format, ...) {
453 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
454 va_list args;
455 va_start(args, format);
456 int result = v8::internal::OS::VSNPrintF(buf, format, args);
457 va_end(args);
458 tmp_buffer_pos_ += result;
459}
460
461
462int DisassemblerX64::PrintRightOperandHelper(
463 byte* modrmp,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000464 RegisterNameMapping direct_register_name) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000465 int mod, regop, rm;
466 get_modrm(*modrmp, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000467 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
468 &DisassemblerX64::NameOfCPURegister;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000469 switch (mod) {
470 case 0:
471 if ((rm & 7) == 5) {
472 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
473 AppendToBuffer("[0x%x]", disp);
474 return 5;
475 } else if ((rm & 7) == 4) {
476 // Codes for SIB byte.
477 byte sib = *(modrmp + 1);
478 int scale, index, base;
479 get_sib(sib, &scale, &index, &base);
480 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
481 // index == rsp means no index. Only use sib byte with no index for
482 // rsp and r12 base.
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000483 AppendToBuffer("[%s]", NameOfCPURegister(base));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000484 return 2;
485 } else if (base == 5) {
486 // base == rbp means no base register (when mod == 0).
487 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
488 AppendToBuffer("[%s*%d+0x%x]",
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000489 NameOfCPURegister(index),
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000490 1 << scale, disp);
491 return 6;
492 } else if (index != 4 && base != 5) {
493 // [base+index*scale]
494 AppendToBuffer("[%s+%s*%d]",
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000495 NameOfCPURegister(base),
496 NameOfCPURegister(index),
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000497 1 << scale);
498 return 2;
499 } else {
500 UnimplementedInstruction();
501 return 1;
502 }
503 } else {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000504 AppendToBuffer("[%s]", NameOfCPURegister(rm));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000505 return 1;
506 }
507 break;
508 case 1: // fall through
509 case 2:
510 if ((rm & 7) == 4) {
511 byte sib = *(modrmp + 1);
512 int scale, index, base;
513 get_sib(sib, &scale, &index, &base);
514 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
515 : *reinterpret_cast<char*>(modrmp + 2);
516 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
517 if (-disp > 0) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000518 AppendToBuffer("[%s-0x%x]", NameOfCPURegister(base), -disp);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000519 } else {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000520 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(base), disp);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000521 }
522 } else {
523 if (-disp > 0) {
524 AppendToBuffer("[%s+%s*%d-0x%x]",
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000525 NameOfCPURegister(base),
526 NameOfCPURegister(index),
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000527 1 << scale,
528 -disp);
529 } else {
530 AppendToBuffer("[%s+%s*%d+0x%x]",
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000531 NameOfCPURegister(base),
532 NameOfCPURegister(index),
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000533 1 << scale,
534 disp);
535 }
536 }
537 return mod == 2 ? 6 : 3;
538 } else {
539 // No sib.
540 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
541 : *reinterpret_cast<char*>(modrmp + 1);
542 if (-disp > 0) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000543 AppendToBuffer("[%s-0x%x]", NameOfCPURegister(rm), -disp);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000544 } else {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000545 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000546 }
547 return (mod == 2) ? 5 : 2;
548 }
549 break;
550 case 3:
551 AppendToBuffer("%s", (this->*register_name)(rm));
552 return 1;
553 default:
554 UnimplementedInstruction();
555 return 1;
556 }
557 UNREACHABLE();
558}
559
560
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000561int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
562 int64_t value;
563 int count;
564 switch (size) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000565 case OPERAND_BYTE_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000566 value = *data;
567 count = 1;
568 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000569 case OPERAND_WORD_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000570 value = *reinterpret_cast<int16_t*>(data);
571 count = 2;
572 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000573 case OPERAND_DOUBLEWORD_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000574 value = *reinterpret_cast<uint32_t*>(data);
575 count = 4;
576 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000577 case OPERAND_QUADWORD_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000578 value = *reinterpret_cast<int32_t*>(data);
579 count = 4;
580 break;
581 default:
582 UNREACHABLE();
583 value = 0; // Initialize variables on all paths to satisfy the compiler.
584 count = 0;
585 }
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000586 AppendToBuffer("%" V8_PTR_PREFIX "x", value);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000587 return count;
588}
589
590
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000591int DisassemblerX64::PrintRightOperand(byte* modrmp) {
592 return PrintRightOperandHelper(modrmp,
593 &DisassemblerX64::NameOfCPURegister);
594}
595
596
597int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
598 return PrintRightOperandHelper(modrmp,
599 &DisassemblerX64::NameOfByteCPURegister);
600}
601
602
ager@chromium.org3811b432009-10-28 14:53:37 +0000603int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
604 return PrintRightOperandHelper(modrmp,
605 &DisassemblerX64::NameOfXMMRegister);
606}
607
608
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000609// Returns number of bytes used including the current *data.
610// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
611int DisassemblerX64::PrintOperands(const char* mnem,
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000612 OperandType op_order,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000613 byte* data) {
614 byte modrm = *data;
615 int mod, regop, rm;
616 get_modrm(modrm, &mod, &regop, &rm);
617 int advance = 0;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000618 const char* register_name =
619 byte_size_operand_ ? NameOfByteCPURegister(regop)
620 : NameOfCPURegister(regop);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000621 switch (op_order) {
622 case REG_OPER_OP_ORDER: {
623 AppendToBuffer("%s%c %s,",
624 mnem,
625 operand_size_code(),
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000626 register_name);
627 advance = byte_size_operand_ ? PrintRightByteOperand(data)
628 : PrintRightOperand(data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000629 break;
630 }
631 case OPER_REG_OP_ORDER: {
632 AppendToBuffer("%s%c ", mnem, operand_size_code());
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000633 advance = byte_size_operand_ ? PrintRightByteOperand(data)
634 : PrintRightOperand(data);
635 AppendToBuffer(",%s", register_name);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000636 break;
637 }
638 default:
639 UNREACHABLE();
640 break;
641 }
642 return advance;
643}
644
645
646// Returns number of bytes used by machine instruction, including *data byte.
647// Writes immediate instructions to 'tmp_buffer_'.
648int DisassemblerX64::PrintImmediateOp(byte* data) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000649 bool byte_size_immediate = (*data & 0x02) != 0;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000650 byte modrm = *(data + 1);
651 int mod, regop, rm;
652 get_modrm(modrm, &mod, &regop, &rm);
653 const char* mnem = "Imm???";
654 switch (regop) {
655 case 0:
656 mnem = "add";
657 break;
658 case 1:
659 mnem = "or";
660 break;
661 case 2:
662 mnem = "adc";
663 break;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000664 case 3:
665 mnem = "sbb";
666 break;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000667 case 4:
668 mnem = "and";
669 break;
670 case 5:
671 mnem = "sub";
672 break;
673 case 6:
674 mnem = "xor";
675 break;
676 case 7:
677 mnem = "cmp";
678 break;
679 default:
680 UnimplementedInstruction();
681 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000682 AppendToBuffer("%s%c ", mnem, operand_size_code());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000683 int count = PrintRightOperand(data + 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000684 AppendToBuffer(",0x");
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000685 OperandSize immediate_size =
686 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000687 count += PrintImmediate(data + 1 + count, immediate_size);
688 return 1 + count;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000689}
690
691
692// Returns number of bytes used, including *data.
ager@chromium.org3811b432009-10-28 14:53:37 +0000693int DisassemblerX64::F6F7Instruction(byte* data) {
694 ASSERT(*data == 0xF7 || *data == 0xF6);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000695 byte modrm = *(data + 1);
696 int mod, regop, rm;
697 get_modrm(modrm, &mod, &regop, &rm);
698 if (mod == 3 && regop != 0) {
699 const char* mnem = NULL;
700 switch (regop) {
701 case 2:
702 mnem = "not";
703 break;
704 case 3:
705 mnem = "neg";
706 break;
707 case 4:
708 mnem = "mul";
709 break;
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +0000710 case 5:
711 mnem = "imul";
712 break;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000713 case 7:
714 mnem = "idiv";
715 break;
716 default:
717 UnimplementedInstruction();
718 }
719 AppendToBuffer("%s%c %s",
720 mnem,
721 operand_size_code(),
722 NameOfCPURegister(rm));
723 return 2;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000724 } else if (regop == 0) {
725 AppendToBuffer("test%c ", operand_size_code());
ager@chromium.org3811b432009-10-28 14:53:37 +0000726 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
727 AppendToBuffer(",0x");
728 count += PrintImmediate(data + 1 + count, operand_size());
729 return 1 + count;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000730 } else {
731 UnimplementedInstruction();
732 return 2;
733 }
734}
735
736
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000737int DisassemblerX64::ShiftInstruction(byte* data) {
738 byte op = *data & (~1);
739 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
740 UnimplementedInstruction();
741 return 1;
742 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000743 byte modrm = *(data + 1);
744 int mod, regop, rm;
745 get_modrm(modrm, &mod, &regop, &rm);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000746 regop &= 0x7; // The REX.R bit does not affect the operation.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000747 int imm8 = -1;
748 int num_bytes = 2;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000749 if (mod != 3) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000750 UnimplementedInstruction();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000751 return num_bytes;
752 }
753 const char* mnem = NULL;
754 switch (regop) {
755 case 0:
756 mnem = "rol";
757 break;
758 case 1:
759 mnem = "ror";
760 break;
761 case 2:
762 mnem = "rcl";
763 break;
764 case 3:
765 mnem = "rcr";
766 break;
767 case 4:
768 mnem = "shl";
769 break;
770 case 5:
771 mnem = "shr";
772 break;
773 case 7:
774 mnem = "sar";
775 break;
776 default:
777 UnimplementedInstruction();
778 return num_bytes;
779 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000780 ASSERT_NE(NULL, mnem);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000781 if (op == 0xD0) {
782 imm8 = 1;
783 } else if (op == 0xC0) {
784 imm8 = *(data + 2);
785 num_bytes = 3;
786 }
787 AppendToBuffer("%s%c %s,",
788 mnem,
789 operand_size_code(),
790 byte_size_operand_ ? NameOfByteCPURegister(rm)
791 : NameOfCPURegister(rm));
792 if (op == 0xD2) {
793 AppendToBuffer("cl");
794 } else {
795 AppendToBuffer("%d", imm8);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000796 }
797 return num_bytes;
798}
799
800
801// Returns number of bytes used, including *data.
802int DisassemblerX64::JumpShort(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000803 ASSERT_EQ(0xEB, *data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000804 byte b = *(data + 1);
805 byte* dest = data + static_cast<int8_t>(b) + 2;
806 AppendToBuffer("jmp %s", NameOfAddress(dest));
807 return 2;
808}
809
810
811// Returns number of bytes used, including *data.
812int DisassemblerX64::JumpConditional(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000813 ASSERT_EQ(0x0F, *data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000814 byte cond = *(data + 1) & 0x0F;
815 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
816 const char* mnem = conditional_code_suffix[cond];
817 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
818 return 6; // includes 0x0F
819}
820
821
822// Returns number of bytes used, including *data.
823int DisassemblerX64::JumpConditionalShort(byte* data) {
824 byte cond = *data & 0x0F;
825 byte b = *(data + 1);
826 byte* dest = data + static_cast<int8_t>(b) + 2;
827 const char* mnem = conditional_code_suffix[cond];
828 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
829 return 2;
830}
831
832
833// Returns number of bytes used, including *data.
834int DisassemblerX64::SetCC(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000835 ASSERT_EQ(0x0F, *data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000836 byte cond = *(data + 1) & 0x0F;
837 const char* mnem = conditional_code_suffix[cond];
838 AppendToBuffer("set%s%c ", mnem, operand_size_code());
839 PrintRightByteOperand(data + 2);
840 return 3; // includes 0x0F
841}
842
843
844// Returns number of bytes used, including *data.
845int DisassemblerX64::FPUInstruction(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000846 byte escape_opcode = *data;
847 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
848 byte modrm_byte = *(data+1);
849
850 if (modrm_byte >= 0xC0) {
851 return RegisterFPUInstruction(escape_opcode, modrm_byte);
852 } else {
853 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000854 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000855}
856
857int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
858 int modrm_byte,
859 byte* modrm_start) {
860 const char* mnem = "?";
861 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
862 switch (escape_opcode) {
863 case 0xD9: switch (regop) {
864 case 0: mnem = "fld_s"; break;
865 case 3: mnem = "fstp_s"; break;
866 case 7: mnem = "fstcw"; break;
867 default: UnimplementedInstruction();
868 }
869 break;
870
871 case 0xDB: switch (regop) {
872 case 0: mnem = "fild_s"; break;
873 case 1: mnem = "fisttp_s"; break;
874 case 2: mnem = "fist_s"; break;
875 case 3: mnem = "fistp_s"; break;
876 default: UnimplementedInstruction();
877 }
878 break;
879
880 case 0xDD: switch (regop) {
881 case 0: mnem = "fld_d"; break;
882 case 3: mnem = "fstp_d"; break;
883 default: UnimplementedInstruction();
884 }
885 break;
886
887 case 0xDF: switch (regop) {
888 case 5: mnem = "fild_d"; break;
889 case 7: mnem = "fistp_d"; break;
890 default: UnimplementedInstruction();
891 }
892 break;
893
894 default: UnimplementedInstruction();
895 }
896 AppendToBuffer("%s ", mnem);
897 int count = PrintRightOperand(modrm_start);
898 return count + 1;
899}
900
901int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
902 byte modrm_byte) {
903 bool has_register = false; // Is the FPU register encoded in modrm_byte?
904 const char* mnem = "?";
905
906 switch (escape_opcode) {
907 case 0xD8:
908 UnimplementedInstruction();
909 break;
910
911 case 0xD9:
912 switch (modrm_byte & 0xF8) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000913 case 0xC0:
914 mnem = "fld";
915 has_register = true;
916 break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000917 case 0xC8:
918 mnem = "fxch";
919 has_register = true;
920 break;
921 default:
922 switch (modrm_byte) {
923 case 0xE0: mnem = "fchs"; break;
924 case 0xE1: mnem = "fabs"; break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000925 case 0xE3: mnem = "fninit"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000926 case 0xE4: mnem = "ftst"; break;
927 case 0xE8: mnem = "fld1"; break;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000928 case 0xEB: mnem = "fldpi"; break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000929 case 0xED: mnem = "fldln2"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000930 case 0xEE: mnem = "fldz"; break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000931 case 0xF0: mnem = "f2xm1"; break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000932 case 0xF1: mnem = "fyl2x"; break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000933 case 0xF2: mnem = "fptan"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000934 case 0xF5: mnem = "fprem1"; break;
935 case 0xF7: mnem = "fincstp"; break;
936 case 0xF8: mnem = "fprem"; break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000937 case 0xFD: mnem = "fscale"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000938 case 0xFE: mnem = "fsin"; break;
939 case 0xFF: mnem = "fcos"; break;
940 default: UnimplementedInstruction();
941 }
942 }
943 break;
944
945 case 0xDA:
946 if (modrm_byte == 0xE9) {
947 mnem = "fucompp";
948 } else {
949 UnimplementedInstruction();
950 }
951 break;
952
953 case 0xDB:
954 if ((modrm_byte & 0xF8) == 0xE8) {
955 mnem = "fucomi";
956 has_register = true;
957 } else if (modrm_byte == 0xE2) {
958 mnem = "fclex";
959 } else {
960 UnimplementedInstruction();
961 }
962 break;
963
964 case 0xDC:
965 has_register = true;
966 switch (modrm_byte & 0xF8) {
967 case 0xC0: mnem = "fadd"; break;
968 case 0xE8: mnem = "fsub"; break;
969 case 0xC8: mnem = "fmul"; break;
970 case 0xF8: mnem = "fdiv"; break;
971 default: UnimplementedInstruction();
972 }
973 break;
974
975 case 0xDD:
976 has_register = true;
977 switch (modrm_byte & 0xF8) {
978 case 0xC0: mnem = "ffree"; break;
979 case 0xD8: mnem = "fstp"; break;
980 default: UnimplementedInstruction();
981 }
982 break;
983
984 case 0xDE:
985 if (modrm_byte == 0xD9) {
986 mnem = "fcompp";
987 } else {
988 has_register = true;
989 switch (modrm_byte & 0xF8) {
990 case 0xC0: mnem = "faddp"; break;
991 case 0xE8: mnem = "fsubp"; break;
992 case 0xC8: mnem = "fmulp"; break;
993 case 0xF8: mnem = "fdivp"; break;
994 default: UnimplementedInstruction();
995 }
996 }
997 break;
998
999 case 0xDF:
1000 if (modrm_byte == 0xE0) {
1001 mnem = "fnstsw_ax";
1002 } else if ((modrm_byte & 0xF8) == 0xE8) {
1003 mnem = "fucomip";
1004 has_register = true;
1005 }
1006 break;
1007
1008 default: UnimplementedInstruction();
1009 }
1010
1011 if (has_register) {
1012 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1013 } else {
1014 AppendToBuffer("%s", mnem);
1015 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001016 return 2;
1017}
1018
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001019
ager@chromium.org3811b432009-10-28 14:53:37 +00001020
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001021// Handle all two-byte opcodes, which start with 0x0F.
1022// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1023// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1024int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1025 byte opcode = *(data + 1);
1026 byte* current = data + 2;
1027 // At return, "current" points to the start of the next instruction.
1028 const char* mnemonic = TwoByteMnemonic(opcode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001029 if (operand_size_ == 0x66) {
1030 // 0x66 0x0F prefix.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001031 int mod, regop, rm;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001032 if (opcode == 0x3A) {
1033 byte third_byte = *current;
1034 current = data + 3;
1035 if (third_byte == 0x17) {
1036 get_modrm(*current, &mod, &regop, &rm);
1037 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1038 current += PrintRightOperand(current);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001039 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001040 current += 1;
danno@chromium.org160a7b02011-04-18 15:51:38 +00001041 } else if (third_byte == 0x0b) {
1042 get_modrm(*current, &mod, &regop, &rm);
1043 // roundsd xmm, xmm/m64, imm8
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001044 AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1045 current += PrintRightXMMOperand(current);
1046 AppendToBuffer(",%d", (*current) & 3);
danno@chromium.org160a7b02011-04-18 15:51:38 +00001047 current += 1;
ager@chromium.org357bf652010-04-12 11:30:10 +00001048 } else {
1049 UnimplementedInstruction();
1050 }
ager@chromium.orgac091b72010-05-05 07:34:42 +00001051 } else {
1052 get_modrm(*current, &mod, &regop, &rm);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001053 if (opcode == 0x1f) {
1054 current++;
1055 if (rm == 4) { // SIB byte present.
1056 current++;
1057 }
1058 if (mod == 1) { // Byte displacement.
1059 current += 1;
1060 } else if (mod == 2) { // 32-bit displacement.
1061 current += 4;
1062 } // else no immediate displacement.
1063 AppendToBuffer("nop");
1064 } else if (opcode == 0x28) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001065 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001066 current += PrintRightXMMOperand(current);
1067 } else if (opcode == 0x29) {
1068 AppendToBuffer("movapd ");
1069 current += PrintRightXMMOperand(current);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001070 AppendToBuffer(",%s", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001071 } else if (opcode == 0x6E) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001072 AppendToBuffer("mov%c %s,",
1073 rex_w() ? 'q' : 'd',
1074 NameOfXMMRegister(regop));
1075 current += PrintRightOperand(current);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001076 } else if (opcode == 0x6F) {
1077 AppendToBuffer("movdqa %s,",
1078 NameOfXMMRegister(regop));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001079 current += PrintRightXMMOperand(current);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001080 } else if (opcode == 0x7E) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001081 AppendToBuffer("mov%c ",
1082 rex_w() ? 'q' : 'd');
1083 current += PrintRightOperand(current);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001084 AppendToBuffer(",%s", NameOfXMMRegister(regop));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001085 } else if (opcode == 0x7F) {
1086 AppendToBuffer("movdqa ");
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001087 current += PrintRightXMMOperand(current);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001088 AppendToBuffer(",%s", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001089 } else if (opcode == 0xD6) {
1090 AppendToBuffer("movq ");
1091 current += PrintRightXMMOperand(current);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001092 AppendToBuffer(",%s", NameOfXMMRegister(regop));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001093 } else if (opcode == 0x50) {
1094 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1095 current += PrintRightXMMOperand(current);
ager@chromium.orgac091b72010-05-05 07:34:42 +00001096 } else {
1097 const char* mnemonic = "?";
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001098 if (opcode == 0x54) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001099 mnemonic = "andpd";
1100 } else if (opcode == 0x56) {
1101 mnemonic = "orpd";
1102 } else if (opcode == 0x57) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001103 mnemonic = "xorpd";
1104 } else if (opcode == 0x2E) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00001105 mnemonic = "ucomisd";
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001106 } else if (opcode == 0x2F) {
1107 mnemonic = "comisd";
ager@chromium.orgac091b72010-05-05 07:34:42 +00001108 } else {
1109 UnimplementedInstruction();
1110 }
1111 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1112 current += PrintRightXMMOperand(current);
1113 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001114 }
1115 } else if (group_1_prefix_ == 0xF2) {
1116 // Beginning of instructions with prefix 0xF2.
1117
1118 if (opcode == 0x11 || opcode == 0x10) {
1119 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1120 AppendToBuffer("movsd ");
1121 int mod, regop, rm;
1122 get_modrm(*current, &mod, &regop, &rm);
1123 if (opcode == 0x11) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001124 current += PrintRightXMMOperand(current);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001125 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1126 } else {
1127 AppendToBuffer("%s,", NameOfXMMRegister(regop));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001128 current += PrintRightXMMOperand(current);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001129 }
1130 } else if (opcode == 0x2A) {
1131 // CVTSI2SD: integer to XMM double conversion.
1132 int mod, regop, rm;
1133 get_modrm(*current, &mod, &regop, &rm);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001134 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
ager@chromium.org3811b432009-10-28 14:53:37 +00001135 current += PrintRightOperand(current);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001136 } else if (opcode == 0x2C) {
1137 // CVTTSD2SI:
1138 // Convert with truncation scalar double-precision FP to integer.
1139 int mod, regop, rm;
1140 get_modrm(*current, &mod, &regop, &rm);
1141 AppendToBuffer("cvttsd2si%c %s,",
1142 operand_size_code(), NameOfCPURegister(regop));
1143 current += PrintRightXMMOperand(current);
1144 } else if (opcode == 0x2D) {
1145 // CVTSD2SI: Convert scalar double-precision FP to integer.
1146 int mod, regop, rm;
1147 get_modrm(*current, &mod, &regop, &rm);
1148 AppendToBuffer("cvtsd2si%c %s,",
1149 operand_size_code(), NameOfCPURegister(regop));
1150 current += PrintRightXMMOperand(current);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001151 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001152 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1153 int mod, regop, rm;
1154 get_modrm(*current, &mod, &regop, &rm);
ager@chromium.org3811b432009-10-28 14:53:37 +00001155 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1156 current += PrintRightXMMOperand(current);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001157 } else if (opcode == 0xC2) {
1158 // Intel manual 2A, Table 3-18.
1159 int mod, regop, rm;
1160 get_modrm(*current, &mod, &regop, &rm);
1161 const char* const pseudo_op[] = {
1162 "cmpeqsd",
1163 "cmpltsd",
1164 "cmplesd",
1165 "cmpunordsd",
1166 "cmpneqsd",
1167 "cmpnltsd",
1168 "cmpnlesd",
1169 "cmpordsd"
1170 };
1171 AppendToBuffer("%s %s,%s",
1172 pseudo_op[current[1]],
1173 NameOfXMMRegister(regop),
1174 NameOfXMMRegister(rm));
1175 current += 2;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001176 } else {
1177 UnimplementedInstruction();
1178 }
ager@chromium.org357bf652010-04-12 11:30:10 +00001179 } else if (group_1_prefix_ == 0xF3) {
1180 // Instructions with prefix 0xF3.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001181 if (opcode == 0x11 || opcode == 0x10) {
1182 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1183 AppendToBuffer("movss ");
1184 int mod, regop, rm;
1185 get_modrm(*current, &mod, &regop, &rm);
1186 if (opcode == 0x11) {
1187 current += PrintRightOperand(current);
1188 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1189 } else {
1190 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1191 current += PrintRightOperand(current);
1192 }
1193 } else if (opcode == 0x2A) {
1194 // CVTSI2SS: integer to XMM single conversion.
1195 int mod, regop, rm;
1196 get_modrm(*current, &mod, &regop, &rm);
1197 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1198 current += PrintRightOperand(current);
1199 } else if (opcode == 0x2C) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001200 // CVTTSS2SI:
1201 // Convert with truncation scalar single-precision FP to dword integer.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001202 int mod, regop, rm;
1203 get_modrm(*current, &mod, &regop, &rm);
1204 AppendToBuffer("cvttss2si%c %s,",
1205 operand_size_code(), NameOfCPURegister(regop));
1206 current += PrintRightXMMOperand(current);
ager@chromium.org357bf652010-04-12 11:30:10 +00001207 } else if (opcode == 0x5A) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001208 // CVTSS2SD:
1209 // Convert scalar single-precision FP to scalar double-precision FP.
ager@chromium.org357bf652010-04-12 11:30:10 +00001210 int mod, regop, rm;
1211 get_modrm(*current, &mod, &regop, &rm);
1212 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1213 current += PrintRightXMMOperand(current);
danno@chromium.org160a7b02011-04-18 15:51:38 +00001214 } else if (opcode == 0x7E) {
1215 int mod, regop, rm;
1216 get_modrm(*current, &mod, &regop, &rm);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001217 AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001218 current += PrintRightXMMOperand(current);
ager@chromium.org357bf652010-04-12 11:30:10 +00001219 } else {
1220 UnimplementedInstruction();
1221 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001222 } else if (opcode == 0x1F) {
1223 // NOP
1224 int mod, regop, rm;
1225 get_modrm(*current, &mod, &regop, &rm);
1226 current++;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001227 if (rm == 4) { // SIB byte present.
ager@chromium.org5c838252010-02-19 08:53:10 +00001228 current++;
1229 }
1230 if (mod == 1) { // Byte displacement.
1231 current += 1;
1232 } else if (mod == 2) { // 32-bit displacement.
1233 current += 4;
1234 } // else no immediate displacement.
1235 AppendToBuffer("nop");
danno@chromium.org160a7b02011-04-18 15:51:38 +00001236
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001237 } else if (opcode == 0x28) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001238 // movaps xmm, xmm/m128
1239 int mod, regop, rm;
1240 get_modrm(*current, &mod, &regop, &rm);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001241 AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001242 current += PrintRightXMMOperand(current);
1243
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001244 } else if (opcode == 0x29) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001245 // movaps xmm/m128, xmm
1246 int mod, regop, rm;
1247 get_modrm(*current, &mod, &regop, &rm);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001248 AppendToBuffer("movaps ");
danno@chromium.org160a7b02011-04-18 15:51:38 +00001249 current += PrintRightXMMOperand(current);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001250 AppendToBuffer(",%s", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001251
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +00001252 } else if (opcode == 0xA2) {
1253 // CPUID
ager@chromium.org5c838252010-02-19 08:53:10 +00001254 AppendToBuffer("%s", mnemonic);
1255
1256 } else if ((opcode & 0xF0) == 0x40) {
1257 // CMOVcc: conditional move.
1258 int condition = opcode & 0x0F;
1259 const InstructionDesc& idesc = cmov_instructions[condition];
1260 byte_size_operand_ = idesc.byte_size_operation;
1261 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1262
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00001263 } else if (opcode == 0x54) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001264 // andps xmm, xmm/m128
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00001265 int mod, regop, rm;
1266 get_modrm(*current, &mod, &regop, &rm);
1267 AppendToBuffer("andps %s,", NameOfXMMRegister(regop));
1268 current += PrintRightXMMOperand(current);
1269
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001270 } else if (opcode == 0x56) {
1271 // orps xmm, xmm/m128
1272 int mod, regop, rm;
1273 get_modrm(*current, &mod, &regop, &rm);
1274 AppendToBuffer("orps %s,", NameOfXMMRegister(regop));
1275 current += PrintRightXMMOperand(current);
1276
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001277 } else if (opcode == 0x57) {
1278 // xorps xmm, xmm/m128
danno@chromium.org160a7b02011-04-18 15:51:38 +00001279 int mod, regop, rm;
1280 get_modrm(*current, &mod, &regop, &rm);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001281 AppendToBuffer("xorps %s,", NameOfXMMRegister(regop));
danno@chromium.org160a7b02011-04-18 15:51:38 +00001282 current += PrintRightXMMOperand(current);
1283
ulan@chromium.org4121f232012-12-27 15:57:11 +00001284 } else if (opcode == 0x50) {
1285 // movmskps reg, xmm
1286 int mod, regop, rm;
1287 get_modrm(*current, &mod, &regop, &rm);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001288 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
ulan@chromium.org4121f232012-12-27 15:57:11 +00001289 current += PrintRightXMMOperand(current);
1290
ager@chromium.org5c838252010-02-19 08:53:10 +00001291 } else if ((opcode & 0xF0) == 0x80) {
1292 // Jcc: Conditional jump (branch).
1293 current = data + JumpConditional(data);
1294
1295 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1296 opcode == 0xB7 || opcode == 0xAF) {
1297 // Size-extending moves, IMUL.
1298 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1299
1300 } else if ((opcode & 0xF0) == 0x90) {
1301 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1302 current = data + SetCC(data);
1303
1304 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1305 // SHLD, SHRD (double-precision shift), BTS (bit set).
1306 AppendToBuffer("%s ", mnemonic);
1307 int mod, regop, rm;
1308 get_modrm(*current, &mod, &regop, &rm);
1309 current += PrintRightOperand(current);
1310 if (opcode == 0xAB) {
1311 AppendToBuffer(",%s", NameOfCPURegister(regop));
1312 } else {
1313 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1314 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001315 } else {
1316 UnimplementedInstruction();
1317 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001318 return static_cast<int>(current - data);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001319}
1320
1321
1322// Mnemonics for two-byte opcode instructions starting with 0x0F.
1323// The argument is the second byte of the two-byte opcode.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001324// Returns NULL if the instruction is not handled here.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001325const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1326 switch (opcode) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001327 case 0x1F:
1328 return "nop";
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001329 case 0x2A: // F2/F3 prefix.
1330 return "cvtsi2s";
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001331 case 0x51: // F2 prefix.
1332 return "sqrtsd";
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001333 case 0x58: // F2 prefix.
1334 return "addsd";
1335 case 0x59: // F2 prefix.
1336 return "mulsd";
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001337 case 0x5A: // F2 prefix.
1338 return "cvtsd2ss";
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001339 case 0x5C: // F2 prefix.
1340 return "subsd";
1341 case 0x5E: // F2 prefix.
1342 return "divsd";
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001343 case 0xA2:
1344 return "cpuid";
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001345 case 0xA5:
1346 return "shld";
1347 case 0xAB:
1348 return "bts";
1349 case 0xAD:
1350 return "shrd";
1351 case 0xAF:
1352 return "imul";
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001353 case 0xB6:
1354 return "movzxb";
1355 case 0xB7:
1356 return "movzxw";
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001357 case 0xBE:
1358 return "movsxb";
1359 case 0xBF:
1360 return "movsxw";
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001361 default:
1362 return NULL;
1363 }
1364}
1365
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001366
1367// Disassembles the instruction at instr, and writes it into out_buffer.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001368int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1369 byte* instr) {
1370 tmp_buffer_pos_ = 0; // starting to write as position 0
1371 byte* data = instr;
1372 bool processed = true; // Will be set to false if the current instruction
1373 // is not in 'instructions' table.
1374 byte current;
1375
1376 // Scan for prefixes.
1377 while (true) {
1378 current = *data;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001379 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001380 operand_size_ = current;
1381 } else if ((current & 0xF0) == 0x40) { // REX prefix.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001382 setRex(current);
1383 if (rex_w()) AppendToBuffer("REX.W ");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001384 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001385 group_1_prefix_ = current;
1386 } else { // Not a prefix - an opcode.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001387 break;
1388 }
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001389 data++;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001390 }
1391
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001392 const InstructionDesc& idesc = instruction_table_->Get(current);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001393 byte_size_operand_ = idesc.byte_size_operation;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001394 switch (idesc.type) {
1395 case ZERO_OPERANDS_INSTR:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001396 if (current >= 0xA4 && current <= 0xA7) {
1397 // String move or compare operations.
1398 if (group_1_prefix_ == REP_PREFIX) {
1399 // REP.
1400 AppendToBuffer("rep ");
1401 }
1402 if (rex_w()) AppendToBuffer("REX.W ");
1403 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1404 } else {
1405 AppendToBuffer("%s", idesc.mnem, operand_size_code());
1406 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001407 data++;
1408 break;
1409
1410 case TWO_OPERANDS_INSTR:
1411 data++;
1412 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1413 break;
1414
1415 case JUMP_CONDITIONAL_SHORT_INSTR:
1416 data += JumpConditionalShort(data);
1417 break;
1418
1419 case REGISTER_INSTR:
1420 AppendToBuffer("%s%c %s",
1421 idesc.mnem,
1422 operand_size_code(),
1423 NameOfCPURegister(base_reg(current & 0x07)));
1424 data++;
1425 break;
1426 case PUSHPOP_INSTR:
1427 AppendToBuffer("%s %s",
1428 idesc.mnem,
1429 NameOfCPURegister(base_reg(current & 0x07)));
1430 data++;
1431 break;
1432 case MOVE_REG_INSTR: {
1433 byte* addr = NULL;
1434 switch (operand_size()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001435 case OPERAND_WORD_SIZE:
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001436 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1437 data += 3;
1438 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001439 case OPERAND_DOUBLEWORD_SIZE:
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001440 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1441 data += 5;
1442 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001443 case OPERAND_QUADWORD_SIZE:
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001444 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1445 data += 9;
1446 break;
1447 default:
1448 UNREACHABLE();
1449 }
1450 AppendToBuffer("mov%c %s,%s",
1451 operand_size_code(),
1452 NameOfCPURegister(base_reg(current & 0x07)),
1453 NameOfAddress(addr));
1454 break;
1455 }
1456
1457 case CALL_JUMP_INSTR: {
1458 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1459 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1460 data += 5;
1461 break;
1462 }
1463
1464 case SHORT_IMMEDIATE_INSTR: {
1465 byte* addr =
1466 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001467 AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001468 data += 5;
1469 break;
1470 }
1471
1472 case NO_INSTR:
1473 processed = false;
1474 break;
1475
1476 default:
1477 UNIMPLEMENTED(); // This type is not implemented.
1478 }
1479
1480 // The first byte didn't match any of the simple opcodes, so we
1481 // need to do special processing on it.
1482 if (!processed) {
1483 switch (*data) {
1484 case 0xC2:
1485 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1486 data += 3;
1487 break;
1488
1489 case 0x69: // fall through
1490 case 0x6B: {
1491 int mod, regop, rm;
1492 get_modrm(*(data + 1), &mod, &regop, &rm);
1493 int32_t imm = *data == 0x6B ? *(data + 2)
1494 : *reinterpret_cast<int32_t*>(data + 2);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00001495 AppendToBuffer("imul%c %s,%s,0x%x",
1496 operand_size_code(),
1497 NameOfCPURegister(regop),
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001498 NameOfCPURegister(rm), imm);
1499 data += 2 + (*data == 0x6B ? 1 : 4);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001500 break;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001501 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001502
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001503 case 0x81: // fall through
1504 case 0x83: // 0x81 with sign extension bit set
1505 data += PrintImmediateOp(data);
1506 break;
1507
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001508 case 0x0F:
1509 data += TwoByteOpcodeInstruction(data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001510 break;
1511
1512 case 0x8F: {
1513 data++;
1514 int mod, regop, rm;
1515 get_modrm(*data, &mod, &regop, &rm);
1516 if (regop == 0) {
1517 AppendToBuffer("pop ");
1518 data += PrintRightOperand(data);
1519 }
1520 }
1521 break;
1522
1523 case 0xFF: {
1524 data++;
1525 int mod, regop, rm;
1526 get_modrm(*data, &mod, &regop, &rm);
1527 const char* mnem = NULL;
1528 switch (regop) {
1529 case 0:
1530 mnem = "inc";
1531 break;
1532 case 1:
1533 mnem = "dec";
1534 break;
1535 case 2:
1536 mnem = "call";
1537 break;
1538 case 4:
1539 mnem = "jmp";
1540 break;
1541 case 6:
1542 mnem = "push";
1543 break;
1544 default:
1545 mnem = "???";
1546 }
1547 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1548 mnem,
1549 operand_size_code());
1550 data += PrintRightOperand(data);
1551 }
1552 break;
1553
1554 case 0xC7: // imm32, fall through
1555 case 0xC6: // imm8
1556 {
1557 bool is_byte = *data == 0xC6;
1558 data++;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001559 if (is_byte) {
1560 AppendToBuffer("movb ");
1561 data += PrintRightByteOperand(data);
1562 int32_t imm = *data;
1563 AppendToBuffer(",0x%x", imm);
1564 data++;
1565 } else {
1566 AppendToBuffer("mov%c ", operand_size_code());
1567 data += PrintRightOperand(data);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001568 if (operand_size() == OPERAND_WORD_SIZE) {
1569 int16_t imm = *reinterpret_cast<int16_t*>(data);
1570 AppendToBuffer(",0x%x", imm);
1571 data += 2;
1572 } else {
1573 int32_t imm = *reinterpret_cast<int32_t*>(data);
1574 AppendToBuffer(",0x%x", imm);
1575 data += 4;
1576 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001577 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001578 }
1579 break;
1580
1581 case 0x80: {
1582 data++;
1583 AppendToBuffer("cmpb ");
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001584 data += PrintRightByteOperand(data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001585 int32_t imm = *data;
1586 AppendToBuffer(",0x%x", imm);
1587 data++;
1588 }
1589 break;
1590
1591 case 0x88: // 8bit, fall through
1592 case 0x89: // 32bit
1593 {
1594 bool is_byte = *data == 0x88;
1595 int mod, regop, rm;
1596 data++;
1597 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001598 if (is_byte) {
1599 AppendToBuffer("movb ");
1600 data += PrintRightByteOperand(data);
1601 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1602 } else {
1603 AppendToBuffer("mov%c ", operand_size_code());
1604 data += PrintRightOperand(data);
1605 AppendToBuffer(",%s", NameOfCPURegister(regop));
1606 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001607 }
1608 break;
1609
1610 case 0x90:
1611 case 0x91:
1612 case 0x92:
1613 case 0x93:
1614 case 0x94:
1615 case 0x95:
1616 case 0x96:
1617 case 0x97: {
ager@chromium.org3811b432009-10-28 14:53:37 +00001618 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001619 if (reg == 0) {
1620 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1621 } else {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001622 AppendToBuffer("xchg%c rax,%s",
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001623 operand_size_code(),
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001624 NameOfCPURegister(reg));
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001625 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001626 data++;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001627 }
ager@chromium.org3811b432009-10-28 14:53:37 +00001628 break;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001629 case 0xB0:
1630 case 0xB1:
1631 case 0xB2:
1632 case 0xB3:
1633 case 0xB4:
1634 case 0xB5:
1635 case 0xB6:
1636 case 0xB7:
1637 case 0xB8:
1638 case 0xB9:
1639 case 0xBA:
1640 case 0xBB:
1641 case 0xBC:
1642 case 0xBD:
1643 case 0xBE:
1644 case 0xBF: {
1645 // mov reg8,imm8 or mov reg32,imm32
1646 byte opcode = *data;
1647 data++;
1648 bool is_32bit = (opcode >= 0xB8);
1649 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1650 if (is_32bit) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001651 AppendToBuffer("mov%c %s,",
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001652 operand_size_code(),
1653 NameOfCPURegister(reg));
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001654 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001655 } else {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001656 AppendToBuffer("movb %s,",
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001657 NameOfByteCPURegister(reg));
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001658 data += PrintImmediate(data, OPERAND_BYTE_SIZE);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001659 }
1660 break;
1661 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001662 case 0xFE: {
1663 data++;
1664 int mod, regop, rm;
1665 get_modrm(*data, &mod, &regop, &rm);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001666 if (regop == 1) {
1667 AppendToBuffer("decb ");
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001668 data += PrintRightByteOperand(data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001669 } else {
1670 UnimplementedInstruction();
1671 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001672 break;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001673 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001674 case 0x68:
1675 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1676 data += 5;
1677 break;
1678
1679 case 0x6A:
1680 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1681 data += 2;
1682 break;
1683
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001684 case 0xA1: // Fall through.
1685 case 0xA3:
1686 switch (operand_size()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001687 case OPERAND_DOUBLEWORD_SIZE: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001688 const char* memory_location = NameOfAddress(
1689 reinterpret_cast<byte*>(
1690 *reinterpret_cast<int32_t*>(data + 1)));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001691 if (*data == 0xA1) { // Opcode 0xA1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001692 AppendToBuffer("movzxlq rax,(%s)", memory_location);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001693 } else { // Opcode 0xA3
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001694 AppendToBuffer("movzxlq (%s),rax", memory_location);
1695 }
1696 data += 5;
1697 break;
1698 }
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001699 case OPERAND_QUADWORD_SIZE: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001700 // New x64 instruction mov rax,(imm_64).
1701 const char* memory_location = NameOfAddress(
1702 *reinterpret_cast<byte**>(data + 1));
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001703 if (*data == 0xA1) { // Opcode 0xA1
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001704 AppendToBuffer("movq rax,(%s)", memory_location);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001705 } else { // Opcode 0xA3
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001706 AppendToBuffer("movq (%s),rax", memory_location);
1707 }
1708 data += 9;
1709 break;
1710 }
1711 default:
1712 UnimplementedInstruction();
1713 data += 2;
1714 }
1715 break;
1716
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001717 case 0xA8:
1718 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1719 data += 2;
1720 break;
1721
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001722 case 0xA9: {
1723 int64_t value = 0;
1724 switch (operand_size()) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001725 case OPERAND_WORD_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001726 value = *reinterpret_cast<uint16_t*>(data + 1);
1727 data += 3;
1728 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001729 case OPERAND_DOUBLEWORD_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001730 value = *reinterpret_cast<uint32_t*>(data + 1);
1731 data += 5;
1732 break;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001733 case OPERAND_QUADWORD_SIZE:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001734 value = *reinterpret_cast<int32_t*>(data + 1);
1735 data += 5;
1736 break;
1737 default:
1738 UNREACHABLE();
1739 }
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00001740 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001741 operand_size_code(),
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001742 value);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001743 break;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001744 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001745 case 0xD1: // fall through
1746 case 0xD3: // fall through
1747 case 0xC1:
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001748 data += ShiftInstruction(data);
1749 break;
1750 case 0xD0: // fall through
1751 case 0xD2: // fall through
1752 case 0xC0:
1753 byte_size_operand_ = true;
1754 data += ShiftInstruction(data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001755 break;
1756
1757 case 0xD9: // fall through
1758 case 0xDA: // fall through
1759 case 0xDB: // fall through
1760 case 0xDC: // fall through
1761 case 0xDD: // fall through
1762 case 0xDE: // fall through
1763 case 0xDF:
1764 data += FPUInstruction(data);
1765 break;
1766
1767 case 0xEB:
1768 data += JumpShort(data);
1769 break;
1770
ager@chromium.org3811b432009-10-28 14:53:37 +00001771 case 0xF6:
1772 byte_size_operand_ = true; // fall through
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001773 case 0xF7:
ager@chromium.org3811b432009-10-28 14:53:37 +00001774 data += F6F7Instruction(data);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001775 break;
1776
ulan@chromium.org4121f232012-12-27 15:57:11 +00001777 case 0x3C:
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00001778 AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
ulan@chromium.org4121f232012-12-27 15:57:11 +00001779 data +=2;
1780 break;
1781
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001782 default:
1783 UnimplementedInstruction();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001784 data += 1;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001785 }
1786 } // !processed
1787
1788 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1789 tmp_buffer_[tmp_buffer_pos_] = '\0';
1790 }
1791
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001792 int instr_len = static_cast<int>(data - instr);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001793 ASSERT(instr_len > 0); // Ensure progress.
1794
1795 int outp = 0;
1796 // Instruction bytes.
1797 for (byte* bp = instr; bp < data; bp++) {
1798 outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
1799 }
1800 for (int i = 6 - instr_len; i >= 0; i--) {
1801 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " ");
1802 }
1803
1804 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
1805 tmp_buffer_.start());
1806 return instr_len;
1807}
1808
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001809
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001810//------------------------------------------------------------------------------
1811
1812
1813static const char* cpu_regs[16] = {
1814 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1815 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1816};
1817
1818
1819static const char* byte_cpu_regs[16] = {
1820 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1821 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1822};
1823
1824
1825static const char* xmm_regs[16] = {
1826 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1827 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1828};
1829
1830
1831const char* NameConverter::NameOfAddress(byte* addr) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1833 return tmp_buffer_.start();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001834}
1835
1836
1837const char* NameConverter::NameOfConstant(byte* addr) const {
1838 return NameOfAddress(addr);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001839}
1840
1841
1842const char* NameConverter::NameOfCPURegister(int reg) const {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001843 if (0 <= reg && reg < 16)
1844 return cpu_regs[reg];
1845 return "noreg";
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001846}
1847
1848
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001849const char* NameConverter::NameOfByteCPURegister(int reg) const {
1850 if (0 <= reg && reg < 16)
1851 return byte_cpu_regs[reg];
1852 return "noreg";
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001853}
1854
1855
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001856const char* NameConverter::NameOfXMMRegister(int reg) const {
1857 if (0 <= reg && reg < 16)
1858 return xmm_regs[reg];
1859 return "noxmmreg";
1860}
1861
1862
1863const char* NameConverter::NameInCode(byte* addr) const {
1864 // X64 does not embed debug strings at the moment.
1865 UNREACHABLE();
1866 return "";
1867}
1868
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001869
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001870//------------------------------------------------------------------------------
1871
1872Disassembler::Disassembler(const NameConverter& converter)
1873 : converter_(converter) { }
1874
1875Disassembler::~Disassembler() { }
1876
1877
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001878int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001879 byte* instruction) {
1880 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1881 return d.InstructionDecode(buffer, instruction);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001882}
1883
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001884
1885// The X64 assembler does not use constant pools.
1886int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1887 return -1;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001888}
1889
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001890
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001891void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1892 NameConverter converter;
1893 Disassembler d(converter);
1894 for (byte* pc = begin; pc < end;) {
1895 v8::internal::EmbeddedVector<char, 128> buffer;
1896 buffer[0] = '\0';
1897 byte* prev_pc = pc;
1898 pc += d.InstructionDecode(buffer, pc);
1899 fprintf(f, "%p", prev_pc);
1900 fprintf(f, " ");
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001901
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001902 for (byte* bp = prev_pc; bp < pc; bp++) {
1903 fprintf(f, "%02x", *bp);
1904 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001905 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001906 fprintf(f, " ");
1907 }
1908 fprintf(f, " %s\n", buffer.start());
1909 }
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001910}
1911
1912} // namespace disasm
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001913
1914#endif // V8_TARGET_ARCH_X64