blob: 9eb0d292c74001159c74ad64b7f868e69b96c220 [file] [log] [blame]
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
28#include <assert.h>
29#include <stdio.h>
30#include <stdarg.h>
kasper.lund7276f142008-07-30 08:49:36 +000031
32#include "v8.h"
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000033
34#if defined(V8_TARGET_ARCH_IA32)
35
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "disasm.h"
37
38namespace disasm {
39
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040enum OperandOrder {
41 UNSET_OP_ORDER = 0,
42 REG_OPER_OP_ORDER,
43 OPER_REG_OP_ORDER
44};
45
46
47//------------------------------------------------------------------
48// Tables
49//------------------------------------------------------------------
50struct ByteMnemonic {
51 int b; // -1 terminates, otherwise must be in range (0..255)
52 const char* mnem;
53 OperandOrder op_order_;
54};
55
56
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000057static const ByteMnemonic two_operands_instr[] = {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000058 {0x01, "add", OPER_REG_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059 {0x03, "add", REG_OPER_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060 {0x09, "or", OPER_REG_OP_ORDER},
61 {0x0B, "or", REG_OPER_OP_ORDER},
62 {0x1B, "sbb", REG_OPER_OP_ORDER},
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000063 {0x21, "and", OPER_REG_OP_ORDER},
64 {0x23, "and", REG_OPER_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065 {0x29, "sub", OPER_REG_OP_ORDER},
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000066 {0x2A, "subb", REG_OPER_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067 {0x2B, "sub", REG_OPER_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068 {0x31, "xor", OPER_REG_OP_ORDER},
69 {0x33, "xor", REG_OPER_OP_ORDER},
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000070 {0x38, "cmpb", OPER_REG_OP_ORDER},
71 {0x3A, "cmpb", REG_OPER_OP_ORDER},
72 {0x3B, "cmp", REG_OPER_OP_ORDER},
73 {0x84, "test_b", REG_OPER_OP_ORDER},
74 {0x85, "test", REG_OPER_OP_ORDER},
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000075 {0x87, "xchg", REG_OPER_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076 {0x8A, "mov_b", REG_OPER_OP_ORDER},
77 {0x8B, "mov", REG_OPER_OP_ORDER},
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000078 {0x8D, "lea", REG_OPER_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 {-1, "", UNSET_OP_ORDER}
80};
81
82
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000083static const ByteMnemonic zero_operands_instr[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000084 {0xC3, "ret", UNSET_OP_ORDER},
85 {0xC9, "leave", UNSET_OP_ORDER},
86 {0x90, "nop", UNSET_OP_ORDER},
87 {0xF4, "hlt", UNSET_OP_ORDER},
88 {0xCC, "int3", UNSET_OP_ORDER},
89 {0x60, "pushad", UNSET_OP_ORDER},
90 {0x61, "popad", UNSET_OP_ORDER},
91 {0x9C, "pushfd", UNSET_OP_ORDER},
92 {0x9D, "popfd", UNSET_OP_ORDER},
93 {0x9E, "sahf", UNSET_OP_ORDER},
94 {0x99, "cdq", UNSET_OP_ORDER},
95 {0x9B, "fwait", UNSET_OP_ORDER},
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000096 {0xFC, "cld", UNSET_OP_ORDER},
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000097 {0xAB, "stos", UNSET_OP_ORDER},
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 {-1, "", UNSET_OP_ORDER}
99};
100
101
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000102static const ByteMnemonic call_jump_instr[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 {0xE8, "call", UNSET_OP_ORDER},
104 {0xE9, "jmp", UNSET_OP_ORDER},
105 {-1, "", UNSET_OP_ORDER}
106};
107
108
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000109static const ByteMnemonic short_immediate_instr[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 {0x05, "add", UNSET_OP_ORDER},
111 {0x0D, "or", UNSET_OP_ORDER},
112 {0x15, "adc", UNSET_OP_ORDER},
113 {0x25, "and", UNSET_OP_ORDER},
114 {0x2D, "sub", UNSET_OP_ORDER},
115 {0x35, "xor", UNSET_OP_ORDER},
116 {0x3D, "cmp", UNSET_OP_ORDER},
117 {-1, "", UNSET_OP_ORDER}
118};
119
120
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000121// Generally we don't want to generate these because they are subject to partial
122// register stalls. They are included for completeness and because the cmp
123// variant is used by the RecordWrite stub. Because it does not update the
124// register it is not subject to partial register stalls.
125static ByteMnemonic byte_immediate_instr[] = {
126 {0x0c, "or", UNSET_OP_ORDER},
127 {0x24, "and", UNSET_OP_ORDER},
128 {0x34, "xor", UNSET_OP_ORDER},
129 {0x3c, "cmp", UNSET_OP_ORDER},
130 {-1, "", UNSET_OP_ORDER}
131};
132
133
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000134static const char* const jump_conditional_mnem[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135 /*0*/ "jo", "jno", "jc", "jnc",
136 /*4*/ "jz", "jnz", "jna", "ja",
137 /*8*/ "js", "jns", "jpe", "jpo",
138 /*12*/ "jl", "jnl", "jng", "jg"
139};
140
141
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000142static const char* const set_conditional_mnem[] = {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000143 /*0*/ "seto", "setno", "setc", "setnc",
144 /*4*/ "setz", "setnz", "setna", "seta",
145 /*8*/ "sets", "setns", "setpe", "setpo",
146 /*12*/ "setl", "setnl", "setng", "setg"
147};
148
149
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000150static const char* const conditional_move_mnem[] = {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000151 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
152 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
153 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
154 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
155};
156
157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158enum InstructionType {
159 NO_INSTR,
160 ZERO_OPERANDS_INSTR,
161 TWO_OPERANDS_INSTR,
162 JUMP_CONDITIONAL_SHORT_INSTR,
163 REGISTER_INSTR,
164 MOVE_REG_INSTR,
165 CALL_JUMP_INSTR,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000166 SHORT_IMMEDIATE_INSTR,
167 BYTE_IMMEDIATE_INSTR
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168};
169
170
171struct InstructionDesc {
172 const char* mnem;
173 InstructionType type;
174 OperandOrder op_order_;
175};
176
177
178class InstructionTable {
179 public:
180 InstructionTable();
181 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000182 static InstructionTable* get_instance() {
183 static InstructionTable table;
184 return &table;
185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186
187 private:
188 InstructionDesc instructions_[256];
189 void Clear();
190 void Init();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000191 void CopyTable(const ByteMnemonic bm[], InstructionType type);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000192 void SetTableRange(InstructionType type,
193 byte start,
194 byte end,
195 const char* mnem);
196 void AddJumpConditionalShort();
197};
198
199
200InstructionTable::InstructionTable() {
201 Clear();
202 Init();
203}
204
205
206void InstructionTable::Clear() {
207 for (int i = 0; i < 256; i++) {
208 instructions_[i].mnem = "";
209 instructions_[i].type = NO_INSTR;
210 instructions_[i].op_order_ = UNSET_OP_ORDER;
211 }
212}
213
214
215void InstructionTable::Init() {
216 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
217 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
218 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
219 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000220 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 AddJumpConditionalShort();
222 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
223 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
224 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
225 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000226 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
228}
229
230
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000231void InstructionTable::CopyTable(const ByteMnemonic bm[],
232 InstructionType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233 for (int i = 0; bm[i].b >= 0; i++) {
234 InstructionDesc* id = &instructions_[bm[i].b];
235 id->mnem = bm[i].mnem;
236 id->op_order_ = bm[i].op_order_;
ager@chromium.org3811b432009-10-28 14:53:37 +0000237 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238 id->type = type;
239 }
240}
241
242
243void InstructionTable::SetTableRange(InstructionType type,
244 byte start,
245 byte end,
246 const char* mnem) {
247 for (byte b = start; b <= end; b++) {
248 InstructionDesc* id = &instructions_[b];
ager@chromium.org3811b432009-10-28 14:53:37 +0000249 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 id->mnem = mnem;
251 id->type = type;
252 }
253}
254
255
256void InstructionTable::AddJumpConditionalShort() {
257 for (byte b = 0x70; b <= 0x7F; b++) {
258 InstructionDesc* id = &instructions_[b];
ager@chromium.org3811b432009-10-28 14:53:37 +0000259 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000260 id->mnem = jump_conditional_mnem[b & 0x0F];
261 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
262 }
263}
264
265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266// The IA32 disassembler implementation.
267class DisassemblerIA32 {
268 public:
269 DisassemblerIA32(const NameConverter& converter,
270 bool abort_on_unimplemented = true)
271 : converter_(converter),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000272 instruction_table_(InstructionTable::get_instance()),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 tmp_buffer_pos_(0),
274 abort_on_unimplemented_(abort_on_unimplemented) {
275 tmp_buffer_[0] = '\0';
276 }
277
278 virtual ~DisassemblerIA32() {}
279
280 // Writes one disassembled instruction into 'buffer' (0-terminated).
281 // Returns the length of the disassembled machine instruction in bytes.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000282 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283
284 private:
285 const NameConverter& converter_;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000286 InstructionTable* instruction_table_;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000287 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 unsigned int tmp_buffer_pos_;
289 bool abort_on_unimplemented_;
290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000291 enum {
292 eax = 0,
293 ecx = 1,
294 edx = 2,
295 ebx = 3,
296 esp = 4,
297 ebp = 5,
298 esi = 6,
299 edi = 7
300 };
301
302
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000303 enum ShiftOpcodeExtension {
304 kROL = 0,
305 kROR = 1,
306 kRCL = 2,
307 kRCR = 3,
308 kSHL = 4,
309 KSHR = 5,
310 kSAR = 7
311 };
312
313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000314 const char* NameOfCPURegister(int reg) const {
315 return converter_.NameOfCPURegister(reg);
316 }
317
318
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000319 const char* NameOfByteCPURegister(int reg) const {
320 return converter_.NameOfByteCPURegister(reg);
321 }
322
323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 const char* NameOfXMMRegister(int reg) const {
325 return converter_.NameOfXMMRegister(reg);
326 }
327
328
329 const char* NameOfAddress(byte* addr) const {
330 return converter_.NameOfAddress(addr);
331 }
332
333
334 // Disassembler helper functions.
335 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
336 *mod = (data >> 6) & 3;
337 *regop = (data & 0x38) >> 3;
338 *rm = data & 7;
339 }
340
341
342 static void get_sib(byte data, int* scale, int* index, int* base) {
343 *scale = (data >> 6) & 3;
344 *index = (data >> 3) & 7;
345 *base = data & 7;
346 }
347
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000348 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000350 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351 int PrintRightOperand(byte* modrmp);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000352 int PrintRightByteOperand(byte* modrmp);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000353 int PrintRightXMMOperand(byte* modrmp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
355 int PrintImmediateOp(byte* data);
356 int F7Instruction(byte* data);
357 int D1D3C1Instruction(byte* data);
358 int JumpShort(byte* data);
359 int JumpConditional(byte* data, const char* comment);
360 int JumpConditionalShort(byte* data, const char* comment);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000361 int SetCC(byte* data);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000362 int CMov(byte* data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363 int FPUInstruction(byte* data);
ager@chromium.org3811b432009-10-28 14:53:37 +0000364 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
365 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 void AppendToBuffer(const char* format, ...);
367
368
369 void UnimplementedInstruction() {
370 if (abort_on_unimplemented_) {
371 UNIMPLEMENTED();
372 } else {
373 AppendToBuffer("'Unimplemented Instruction'");
374 }
375 }
376};
377
378
379void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000380 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 va_list args;
382 va_start(args, format);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000383 int result = v8::internal::OS::VSNPrintF(buf, format, args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 va_end(args);
385 tmp_buffer_pos_ += result;
386}
387
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000388int DisassemblerIA32::PrintRightOperandHelper(
389 byte* modrmp,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000390 RegisterNameMapping direct_register_name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 int mod, regop, rm;
392 get_modrm(*modrmp, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000393 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
394 &DisassemblerIA32::NameOfCPURegister;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 switch (mod) {
396 case 0:
397 if (rm == ebp) {
398 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
399 AppendToBuffer("[0x%x]", disp);
400 return 5;
401 } else if (rm == esp) {
402 byte sib = *(modrmp + 1);
403 int scale, index, base;
404 get_sib(sib, &scale, &index, &base);
405 if (index == esp && base == esp && scale == 0 /*times_1*/) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000406 AppendToBuffer("[%s]", (this->*register_name)(rm));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407 return 2;
408 } else if (base == ebp) {
409 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
410 AppendToBuffer("[%s*%d+0x%x]",
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000411 (this->*register_name)(index),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 1 << scale,
413 disp);
414 return 6;
415 } else if (index != esp && base != ebp) {
416 // [base+index*scale]
417 AppendToBuffer("[%s+%s*%d]",
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000418 (this->*register_name)(base),
419 (this->*register_name)(index),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420 1 << scale);
421 return 2;
422 } else {
423 UnimplementedInstruction();
424 return 1;
425 }
426 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000427 AppendToBuffer("[%s]", (this->*register_name)(rm));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 return 1;
429 }
430 break;
431 case 1: // fall through
432 case 2:
433 if (rm == esp) {
434 byte sib = *(modrmp + 1);
435 int scale, index, base;
436 get_sib(sib, &scale, &index, &base);
437 int disp =
438 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
439 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000440 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 } else {
442 AppendToBuffer("[%s+%s*%d+0x%x]",
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000443 (this->*register_name)(base),
444 (this->*register_name)(index),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445 1 << scale,
446 disp);
447 }
448 return mod == 2 ? 6 : 3;
449 } else {
450 // No sib.
451 int disp =
452 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000453 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 return mod == 2 ? 5 : 2;
455 }
456 break;
457 case 3:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000458 AppendToBuffer("%s", (this->*register_name)(rm));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 return 1;
460 default:
461 UnimplementedInstruction();
462 return 1;
463 }
464 UNREACHABLE();
465}
466
467
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000468int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
469 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
470}
471
472
473int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
474 return PrintRightOperandHelper(modrmp,
475 &DisassemblerIA32::NameOfByteCPURegister);
476}
477
478
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000479int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
480 return PrintRightOperandHelper(modrmp,
481 &DisassemblerIA32::NameOfXMMRegister);
482}
483
484
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485// Returns number of bytes used including the current *data.
486// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
487int DisassemblerIA32::PrintOperands(const char* mnem,
488 OperandOrder op_order,
489 byte* data) {
490 byte modrm = *data;
491 int mod, regop, rm;
492 get_modrm(modrm, &mod, &regop, &rm);
493 int advance = 0;
494 switch (op_order) {
495 case REG_OPER_OP_ORDER: {
496 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
497 advance = PrintRightOperand(data);
498 break;
499 }
500 case OPER_REG_OP_ORDER: {
501 AppendToBuffer("%s ", mnem);
502 advance = PrintRightOperand(data);
503 AppendToBuffer(",%s", NameOfCPURegister(regop));
504 break;
505 }
506 default:
507 UNREACHABLE();
508 break;
509 }
510 return advance;
511}
512
513
514// Returns number of bytes used by machine instruction, including *data byte.
515// Writes immediate instructions to 'tmp_buffer_'.
516int DisassemblerIA32::PrintImmediateOp(byte* data) {
517 bool sign_extension_bit = (*data & 0x02) != 0;
518 byte modrm = *(data+1);
519 int mod, regop, rm;
520 get_modrm(modrm, &mod, &regop, &rm);
521 const char* mnem = "Imm???";
522 switch (regop) {
523 case 0: mnem = "add"; break;
524 case 1: mnem = "or"; break;
525 case 2: mnem = "adc"; break;
526 case 4: mnem = "and"; break;
527 case 5: mnem = "sub"; break;
528 case 6: mnem = "xor"; break;
529 case 7: mnem = "cmp"; break;
530 default: UnimplementedInstruction();
531 }
532 AppendToBuffer("%s ", mnem);
533 int count = PrintRightOperand(data+1);
534 if (sign_extension_bit) {
535 AppendToBuffer(",0x%x", *(data + 1 + count));
536 return 1 + count + 1 /*int8*/;
537 } else {
538 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
539 return 1 + count + 4 /*int32_t*/;
540 }
541}
542
543
544// Returns number of bytes used, including *data.
545int DisassemblerIA32::F7Instruction(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000546 ASSERT_EQ(0xF7, *data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000547 byte modrm = *(data+1);
548 int mod, regop, rm;
549 get_modrm(modrm, &mod, &regop, &rm);
550 if (mod == 3 && regop != 0) {
551 const char* mnem = NULL;
552 switch (regop) {
553 case 2: mnem = "not"; break;
554 case 3: mnem = "neg"; break;
555 case 4: mnem = "mul"; break;
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +0000556 case 5: mnem = "imul"; break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 case 7: mnem = "idiv"; break;
558 default: UnimplementedInstruction();
559 }
560 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
561 return 2;
562 } else if (mod == 3 && regop == eax) {
563 int32_t imm = *reinterpret_cast<int32_t*>(data+2);
564 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
565 return 6;
566 } else if (regop == eax) {
567 AppendToBuffer("test ");
568 int count = PrintRightOperand(data+1);
569 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
570 AppendToBuffer(",0x%x", imm);
571 return 1+count+4 /*int32_t*/;
572 } else {
573 UnimplementedInstruction();
574 return 2;
575 }
576}
577
578int DisassemblerIA32::D1D3C1Instruction(byte* data) {
579 byte op = *data;
ager@chromium.org3811b432009-10-28 14:53:37 +0000580 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000581 byte modrm = *(data+1);
582 int mod, regop, rm;
583 get_modrm(modrm, &mod, &regop, &rm);
584 int imm8 = -1;
585 int num_bytes = 2;
586 if (mod == 3) {
587 const char* mnem = NULL;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000588 switch (regop) {
589 case kROL: mnem = "rol"; break;
590 case kROR: mnem = "ror"; break;
591 case kRCL: mnem = "rcl"; break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000592 case kRCR: mnem = "rcr"; break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000593 case kSHL: mnem = "shl"; break;
594 case KSHR: mnem = "shr"; break;
595 case kSAR: mnem = "sar"; break;
596 default: UnimplementedInstruction();
597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000598 if (op == 0xD1) {
599 imm8 = 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 } else if (op == 0xC1) {
601 imm8 = *(data+2);
602 num_bytes = 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603 } else if (op == 0xD3) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000604 // Shift/rotate by cl.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000606 ASSERT_NE(NULL, mnem);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
608 if (imm8 > 0) {
609 AppendToBuffer("%d", imm8);
610 } else {
611 AppendToBuffer("cl");
612 }
613 } else {
614 UnimplementedInstruction();
615 }
616 return num_bytes;
617}
618
619
620// Returns number of bytes used, including *data.
621int DisassemblerIA32::JumpShort(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000622 ASSERT_EQ(0xEB, *data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 byte b = *(data+1);
624 byte* dest = data + static_cast<int8_t>(b) + 2;
625 AppendToBuffer("jmp %s", NameOfAddress(dest));
626 return 2;
627}
628
629
630// Returns number of bytes used, including *data.
631int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000632 ASSERT_EQ(0x0F, *data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 byte cond = *(data+1) & 0x0F;
634 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
635 const char* mnem = jump_conditional_mnem[cond];
636 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
637 if (comment != NULL) {
638 AppendToBuffer(", %s", comment);
639 }
640 return 6; // includes 0x0F
641}
642
643
644// Returns number of bytes used, including *data.
645int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
646 byte cond = *data & 0x0F;
647 byte b = *(data+1);
648 byte* dest = data + static_cast<int8_t>(b) + 2;
649 const char* mnem = jump_conditional_mnem[cond];
650 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
651 if (comment != NULL) {
652 AppendToBuffer(", %s", comment);
653 }
654 return 2;
655}
656
657
658// Returns number of bytes used, including *data.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000659int DisassemblerIA32::SetCC(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000660 ASSERT_EQ(0x0F, *data);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000661 byte cond = *(data+1) & 0x0F;
662 const char* mnem = set_conditional_mnem[cond];
663 AppendToBuffer("%s ", mnem);
664 PrintRightByteOperand(data+2);
ager@chromium.org3811b432009-10-28 14:53:37 +0000665 return 3; // Includes 0x0F.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000666}
667
668
669// Returns number of bytes used, including *data.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000670int DisassemblerIA32::CMov(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000671 ASSERT_EQ(0x0F, *data);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000672 byte cond = *(data + 1) & 0x0F;
673 const char* mnem = conditional_move_mnem[cond];
674 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
675 return 2 + op_size; // includes 0x0F
676}
677
678
679// Returns number of bytes used, including *data.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680int DisassemblerIA32::FPUInstruction(byte* data) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000681 byte escape_opcode = *data;
682 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
683 byte modrm_byte = *(data+1);
684
685 if (modrm_byte >= 0xC0) {
686 return RegisterFPUInstruction(escape_opcode, modrm_byte);
687 } else {
688 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 }
ager@chromium.org3811b432009-10-28 14:53:37 +0000690}
691
692int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
693 int modrm_byte,
694 byte* modrm_start) {
695 const char* mnem = "?";
696 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
697 switch (escape_opcode) {
698 case 0xD9: switch (regop) {
699 case 0: mnem = "fld_s"; break;
700 case 3: mnem = "fstp_s"; break;
701 case 7: mnem = "fstcw"; break;
702 default: UnimplementedInstruction();
703 }
704 break;
705
706 case 0xDB: switch (regop) {
707 case 0: mnem = "fild_s"; break;
708 case 1: mnem = "fisttp_s"; break;
709 case 2: mnem = "fist_s"; break;
710 case 3: mnem = "fistp_s"; break;
711 default: UnimplementedInstruction();
712 }
713 break;
714
715 case 0xDD: switch (regop) {
716 case 0: mnem = "fld_d"; break;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000717 case 1: mnem = "fisttp_d"; break;
718 case 2: mnem = "fst_d"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000719 case 3: mnem = "fstp_d"; break;
720 default: UnimplementedInstruction();
721 }
722 break;
723
724 case 0xDF: switch (regop) {
725 case 5: mnem = "fild_d"; break;
726 case 7: mnem = "fistp_d"; break;
727 default: UnimplementedInstruction();
728 }
729 break;
730
731 default: UnimplementedInstruction();
732 }
733 AppendToBuffer("%s ", mnem);
734 int count = PrintRightOperand(modrm_start);
735 return count + 1;
736}
737
738int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
739 byte modrm_byte) {
740 bool has_register = false; // Is the FPU register encoded in modrm_byte?
741 const char* mnem = "?";
742
743 switch (escape_opcode) {
744 case 0xD8:
745 UnimplementedInstruction();
746 break;
747
748 case 0xD9:
749 switch (modrm_byte & 0xF8) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000750 case 0xC0:
751 mnem = "fld";
752 has_register = true;
753 break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000754 case 0xC8:
755 mnem = "fxch";
756 has_register = true;
757 break;
758 default:
759 switch (modrm_byte) {
760 case 0xE0: mnem = "fchs"; break;
761 case 0xE1: mnem = "fabs"; break;
762 case 0xE4: mnem = "ftst"; break;
763 case 0xE8: mnem = "fld1"; break;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000764 case 0xEB: mnem = "fldpi"; break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000765 case 0xED: mnem = "fldln2"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000766 case 0xEE: mnem = "fldz"; break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000767 case 0xF0: mnem = "f2xm1"; break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000768 case 0xF1: mnem = "fyl2x"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000769 case 0xF5: mnem = "fprem1"; break;
770 case 0xF7: mnem = "fincstp"; break;
771 case 0xF8: mnem = "fprem"; break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000772 case 0xFC: mnem = "frndint"; break;
773 case 0xFD: mnem = "fscale"; break;
ager@chromium.org3811b432009-10-28 14:53:37 +0000774 case 0xFE: mnem = "fsin"; break;
775 case 0xFF: mnem = "fcos"; break;
776 default: UnimplementedInstruction();
777 }
778 }
779 break;
780
781 case 0xDA:
782 if (modrm_byte == 0xE9) {
783 mnem = "fucompp";
784 } else {
785 UnimplementedInstruction();
786 }
787 break;
788
789 case 0xDB:
790 if ((modrm_byte & 0xF8) == 0xE8) {
791 mnem = "fucomi";
792 has_register = true;
793 } else if (modrm_byte == 0xE2) {
794 mnem = "fclex";
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000795 } else if (modrm_byte == 0xE3) {
796 mnem = "fninit";
ager@chromium.org3811b432009-10-28 14:53:37 +0000797 } else {
798 UnimplementedInstruction();
799 }
800 break;
801
802 case 0xDC:
803 has_register = true;
804 switch (modrm_byte & 0xF8) {
805 case 0xC0: mnem = "fadd"; break;
806 case 0xE8: mnem = "fsub"; break;
807 case 0xC8: mnem = "fmul"; break;
808 case 0xF8: mnem = "fdiv"; break;
809 default: UnimplementedInstruction();
810 }
811 break;
812
813 case 0xDD:
814 has_register = true;
815 switch (modrm_byte & 0xF8) {
816 case 0xC0: mnem = "ffree"; break;
817 case 0xD8: mnem = "fstp"; break;
818 default: UnimplementedInstruction();
819 }
820 break;
821
822 case 0xDE:
823 if (modrm_byte == 0xD9) {
824 mnem = "fcompp";
825 } else {
826 has_register = true;
827 switch (modrm_byte & 0xF8) {
828 case 0xC0: mnem = "faddp"; break;
829 case 0xE8: mnem = "fsubp"; break;
830 case 0xC8: mnem = "fmulp"; break;
831 case 0xF8: mnem = "fdivp"; break;
832 default: UnimplementedInstruction();
833 }
834 }
835 break;
836
837 case 0xDF:
838 if (modrm_byte == 0xE0) {
839 mnem = "fnstsw_ax";
840 } else if ((modrm_byte & 0xF8) == 0xE8) {
841 mnem = "fucomip";
842 has_register = true;
843 }
844 break;
845
846 default: UnimplementedInstruction();
847 }
848
849 if (has_register) {
850 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
851 } else {
852 AppendToBuffer("%s", mnem);
853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854 return 2;
855}
856
857
858// Mnemonics for instructions 0xF0 byte.
859// Returns NULL if the instruction is not handled here.
860static const char* F0Mnem(byte f0byte) {
861 switch (f0byte) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000862 case 0x18: return "prefetch";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 case 0xA2: return "cpuid";
864 case 0x31: return "rdtsc";
865 case 0xBE: return "movsx_b";
866 case 0xBF: return "movsx_w";
867 case 0xB6: return "movzx_b";
868 case 0xB7: return "movzx_w";
869 case 0xAF: return "imul";
870 case 0xA5: return "shld";
871 case 0xAD: return "shrd";
danno@chromium.org1f34ad32012-11-26 14:53:56 +0000872 case 0xAC: return "shrd"; // 3-operand version.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 case 0xAB: return "bts";
874 default: return NULL;
875 }
876}
877
878
ager@chromium.org6f10e412009-02-13 10:11:16 +0000879// Disassembled instruction '*instr' and writes it into 'out_buffer'.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000880int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 byte* instr) {
882 tmp_buffer_pos_ = 0; // starting to write as position 0
883 byte* data = instr;
884 // Check for hints.
885 const char* branch_hint = NULL;
ager@chromium.org6f10e412009-02-13 10:11:16 +0000886 // We use these two prefixes only with branch prediction
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 if (*data == 0x3E /*ds*/) {
888 branch_hint = "predicted taken";
889 data++;
890 } else if (*data == 0x2E /*cs*/) {
891 branch_hint = "predicted not taken";
892 data++;
893 }
894 bool processed = true; // Will be set to false if the current instruction
895 // is not in 'instructions' table.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000896 const InstructionDesc& idesc = instruction_table_->Get(*data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 switch (idesc.type) {
898 case ZERO_OPERANDS_INSTR:
899 AppendToBuffer(idesc.mnem);
900 data++;
901 break;
902
903 case TWO_OPERANDS_INSTR:
904 data++;
905 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
906 break;
907
908 case JUMP_CONDITIONAL_SHORT_INSTR:
909 data += JumpConditionalShort(data, branch_hint);
910 break;
911
912 case REGISTER_INSTR:
913 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
914 data++;
915 break;
916
917 case MOVE_REG_INSTR: {
918 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
919 AppendToBuffer("mov %s,%s",
920 NameOfCPURegister(*data & 0x07),
921 NameOfAddress(addr));
922 data += 5;
923 break;
924 }
925
926 case CALL_JUMP_INSTR: {
927 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
928 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
929 data += 5;
930 break;
931 }
932
933 case SHORT_IMMEDIATE_INSTR: {
934 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
935 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
936 data += 5;
937 break;
938 }
939
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000940 case BYTE_IMMEDIATE_INSTR: {
941 AppendToBuffer("%s al, 0x%x", idesc.mnem, data[1]);
942 data += 2;
943 break;
944 }
945
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000946 case NO_INSTR:
947 processed = false;
948 break;
949
950 default:
951 UNIMPLEMENTED(); // This type is not implemented.
952 }
953 //----------------------------
954 if (!processed) {
955 switch (*data) {
956 case 0xC2:
957 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
958 data += 3;
959 break;
960
961 case 0x69: // fall through
962 case 0x6B:
963 { int mod, regop, rm;
964 get_modrm(*(data+1), &mod, &regop, &rm);
965 int32_t imm =
966 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
967 AppendToBuffer("imul %s,%s,0x%x",
968 NameOfCPURegister(regop),
969 NameOfCPURegister(rm),
970 imm);
971 data += 2 + (*data == 0x6B ? 1 : 4);
972 }
973 break;
974
975 case 0xF6:
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000976 { data++;
977 int mod, regop, rm;
978 get_modrm(*data, &mod, &regop, &rm);
979 if (regop == eax) {
980 AppendToBuffer("test_b ");
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000981 data += PrintRightByteOperand(data);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000982 int32_t imm = *data;
983 AppendToBuffer(",0x%x", imm);
984 data++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 } else {
986 UnimplementedInstruction();
987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 }
989 break;
990
991 case 0x81: // fall through
992 case 0x83: // 0x81 with sign extension bit set
993 data += PrintImmediateOp(data);
994 break;
995
996 case 0x0F:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000997 { byte f0byte = data[1];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 const char* f0mnem = F0Mnem(f0byte);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000999 if (f0byte == 0x18) {
1000 int mod, regop, rm;
1001 get_modrm(*data, &mod, &regop, &rm);
1002 const char* suffix[] = {"nta", "1", "2", "3"};
1003 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1004 data += PrintRightOperand(data);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001005 } else if (f0byte == 0x1F && data[2] == 0) {
1006 AppendToBuffer("nop"); // 3 byte nop.
1007 data += 3;
1008 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1009 AppendToBuffer("nop"); // 4 byte nop.
1010 data += 4;
1011 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1012 data[4] == 0) {
1013 AppendToBuffer("nop"); // 5 byte nop.
1014 data += 5;
1015 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1016 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1017 AppendToBuffer("nop"); // 7 byte nop.
1018 data += 7;
1019 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1020 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1021 data[7] == 0) {
1022 AppendToBuffer("nop"); // 8 byte nop.
1023 data += 8;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001024 } else if (f0byte == 0xA2 || f0byte == 0x31) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025 AppendToBuffer("%s", f0mnem);
1026 data += 2;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001027 } else if (f0byte == 0x28) {
1028 data += 2;
1029 int mod, regop, rm;
1030 get_modrm(*data, &mod, &regop, &rm);
1031 AppendToBuffer("movaps %s,%s",
1032 NameOfXMMRegister(regop),
1033 NameOfXMMRegister(rm));
1034 data++;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001035 } else if (f0byte == 0x57) {
1036 data += 2;
1037 int mod, regop, rm;
1038 get_modrm(*data, &mod, &regop, &rm);
1039 AppendToBuffer("xorps %s,%s",
1040 NameOfXMMRegister(regop),
1041 NameOfXMMRegister(rm));
1042 data++;
ulan@chromium.org4121f232012-12-27 15:57:11 +00001043 } else if (f0byte == 0x50) {
1044 data += 2;
1045 int mod, regop, rm;
1046 get_modrm(*data, &mod, &regop, &rm);
1047 AppendToBuffer("movmskps %s,%s",
1048 NameOfCPURegister(regop),
1049 NameOfXMMRegister(rm));
1050 data++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 } else if ((f0byte & 0xF0) == 0x80) {
1052 data += JumpConditional(data, branch_hint);
1053 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1054 f0byte == 0xB7 || f0byte == 0xAF) {
1055 data += 2;
1056 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001057 } else if ((f0byte & 0xF0) == 0x90) {
1058 data += SetCC(data);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001059 } else if ((f0byte & 0xF0) == 0x40) {
1060 data += CMov(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061 } else {
1062 data += 2;
1063 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1064 // shrd, shld, bts
1065 AppendToBuffer("%s ", f0mnem);
1066 int mod, regop, rm;
1067 get_modrm(*data, &mod, &regop, &rm);
1068 data += PrintRightOperand(data);
1069 if (f0byte == 0xAB) {
1070 AppendToBuffer(",%s", NameOfCPURegister(regop));
1071 } else {
1072 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1073 }
1074 } else {
1075 UnimplementedInstruction();
1076 }
1077 }
1078 }
1079 break;
1080
1081 case 0x8F:
1082 { data++;
1083 int mod, regop, rm;
1084 get_modrm(*data, &mod, &regop, &rm);
1085 if (regop == eax) {
1086 AppendToBuffer("pop ");
1087 data += PrintRightOperand(data);
1088 }
1089 }
1090 break;
1091
1092 case 0xFF:
1093 { data++;
1094 int mod, regop, rm;
1095 get_modrm(*data, &mod, &regop, &rm);
1096 const char* mnem = NULL;
1097 switch (regop) {
1098 case esi: mnem = "push"; break;
1099 case eax: mnem = "inc"; break;
ager@chromium.org6f10e412009-02-13 10:11:16 +00001100 case ecx: mnem = "dec"; break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 case edx: mnem = "call"; break;
1102 case esp: mnem = "jmp"; break;
1103 default: mnem = "???";
1104 }
1105 AppendToBuffer("%s ", mnem);
1106 data += PrintRightOperand(data);
1107 }
1108 break;
1109
1110 case 0xC7: // imm32, fall through
1111 case 0xC6: // imm8
1112 { bool is_byte = *data == 0xC6;
1113 data++;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001114 if (is_byte) {
1115 AppendToBuffer("%s ", "mov_b");
1116 data += PrintRightByteOperand(data);
1117 int32_t imm = *data;
1118 AppendToBuffer(",0x%x", imm);
1119 data++;
1120 } else {
1121 AppendToBuffer("%s ", "mov");
1122 data += PrintRightOperand(data);
1123 int32_t imm = *reinterpret_cast<int32_t*>(data);
1124 AppendToBuffer(",0x%x", imm);
1125 data += 4;
1126 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127 }
1128 break;
1129
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001130 case 0x80:
1131 { data++;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001132 int mod, regop, rm;
1133 get_modrm(*data, &mod, &regop, &rm);
1134 const char* mnem = NULL;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001135 switch (regop) {
1136 case 5: mnem = "subb"; break;
1137 case 7: mnem = "cmpb"; break;
1138 default: UnimplementedInstruction();
1139 }
1140 AppendToBuffer("%s ", mnem);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001141 data += PrintRightByteOperand(data);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001142 int32_t imm = *data;
1143 AppendToBuffer(",0x%x", imm);
1144 data++;
1145 }
1146 break;
1147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 case 0x88: // 8bit, fall through
1149 case 0x89: // 32bit
1150 { bool is_byte = *data == 0x88;
1151 int mod, regop, rm;
1152 data++;
1153 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001154 if (is_byte) {
1155 AppendToBuffer("%s ", "mov_b");
1156 data += PrintRightByteOperand(data);
1157 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1158 } else {
1159 AppendToBuffer("%s ", "mov");
1160 data += PrintRightOperand(data);
1161 AppendToBuffer(",%s", NameOfCPURegister(regop));
1162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 }
1164 break;
1165
1166 case 0x66: // prefix
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001167 while (*data == 0x66) data++;
1168 if (*data == 0xf && data[1] == 0x1f) {
1169 AppendToBuffer("nop"); // 0x66 prefix
1170 } else if (*data == 0x90) {
1171 AppendToBuffer("nop"); // 0x66 prefix
1172 } else if (*data == 0x8B) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 data++;
1174 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1175 } else if (*data == 0x89) {
1176 data++;
1177 int mod, regop, rm;
1178 get_modrm(*data, &mod, &regop, &rm);
1179 AppendToBuffer("mov_w ");
1180 data += PrintRightOperand(data);
1181 AppendToBuffer(",%s", NameOfCPURegister(regop));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001182 } else if (*data == 0x0F) {
1183 data++;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001184 if (*data == 0x38) {
1185 data++;
1186 if (*data == 0x17) {
1187 data++;
1188 int mod, regop, rm;
1189 get_modrm(*data, &mod, &regop, &rm);
1190 AppendToBuffer("ptest %s,%s",
1191 NameOfXMMRegister(regop),
1192 NameOfXMMRegister(rm));
1193 data++;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001194 } else if (*data == 0x2A) {
1195 // movntdqa
1196 data++;
1197 int mod, regop, rm;
1198 get_modrm(*data, &mod, &regop, &rm);
1199 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1200 data += PrintRightOperand(data);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001201 } else {
1202 UnimplementedInstruction();
1203 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001204 } else if (*data == 0x3A) {
1205 data++;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001206 if (*data == 0x0B) {
1207 data++;
1208 int mod, regop, rm;
1209 get_modrm(*data, &mod, &regop, &rm);
1210 int8_t imm8 = static_cast<int8_t>(data[1]);
1211 AppendToBuffer("roundsd %s,%s,%d",
1212 NameOfXMMRegister(regop),
1213 NameOfXMMRegister(rm),
1214 static_cast<int>(imm8));
1215 data += 2;
1216 } else if (*data == 0x16) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001217 data++;
1218 int mod, regop, rm;
1219 get_modrm(*data, &mod, &regop, &rm);
1220 int8_t imm8 = static_cast<int8_t>(data[1]);
1221 AppendToBuffer("pextrd %s,%s,%d",
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001222 NameOfCPURegister(regop),
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001223 NameOfXMMRegister(rm),
1224 static_cast<int>(imm8));
1225 data += 2;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001226 } else if (*data == 0x17) {
1227 data++;
1228 int mod, regop, rm;
1229 get_modrm(*data, &mod, &regop, &rm);
1230 int8_t imm8 = static_cast<int8_t>(data[1]);
1231 AppendToBuffer("extractps %s,%s,%d",
1232 NameOfCPURegister(regop),
1233 NameOfXMMRegister(rm),
1234 static_cast<int>(imm8));
1235 data += 2;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001236 } else if (*data == 0x22) {
1237 data++;
1238 int mod, regop, rm;
1239 get_modrm(*data, &mod, &regop, &rm);
1240 int8_t imm8 = static_cast<int8_t>(data[1]);
1241 AppendToBuffer("pinsrd %s,%s,%d",
1242 NameOfXMMRegister(regop),
1243 NameOfCPURegister(rm),
1244 static_cast<int>(imm8));
1245 data += 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001246 } else {
1247 UnimplementedInstruction();
1248 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001249 } else if (*data == 0x2E || *data == 0x2F) {
1250 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001251 data++;
1252 int mod, regop, rm;
1253 get_modrm(*data, &mod, &regop, &rm);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001254 if (mod == 0x3) {
1255 AppendToBuffer("%s %s,%s", mnem,
1256 NameOfXMMRegister(regop),
1257 NameOfXMMRegister(rm));
1258 data++;
1259 } else {
1260 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1261 data += PrintRightOperand(data);
1262 }
1263 } else if (*data == 0x50) {
1264 data++;
1265 int mod, regop, rm;
1266 get_modrm(*data, &mod, &regop, &rm);
1267 AppendToBuffer("movmskpd %s,%s",
1268 NameOfCPURegister(regop),
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001269 NameOfXMMRegister(rm));
1270 data++;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001271 } else if (*data == 0x54) {
1272 data++;
1273 int mod, regop, rm;
1274 get_modrm(*data, &mod, &regop, &rm);
1275 AppendToBuffer("andpd %s,%s",
1276 NameOfXMMRegister(regop),
1277 NameOfXMMRegister(rm));
1278 data++;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001279 } else if (*data == 0x56) {
1280 data++;
1281 int mod, regop, rm;
1282 get_modrm(*data, &mod, &regop, &rm);
1283 AppendToBuffer("orpd %s,%s",
1284 NameOfXMMRegister(regop),
1285 NameOfXMMRegister(rm));
1286 data++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001287 } else if (*data == 0x57) {
1288 data++;
1289 int mod, regop, rm;
1290 get_modrm(*data, &mod, &regop, &rm);
1291 AppendToBuffer("xorpd %s,%s",
1292 NameOfXMMRegister(regop),
1293 NameOfXMMRegister(rm));
1294 data++;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001295 } else if (*data == 0x6E) {
1296 data++;
1297 int mod, regop, rm;
1298 get_modrm(*data, &mod, &regop, &rm);
1299 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1300 data += PrintRightOperand(data);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001301 } else if (*data == 0x6F) {
1302 data++;
1303 int mod, regop, rm;
1304 get_modrm(*data, &mod, &regop, &rm);
1305 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001306 data += PrintRightXMMOperand(data);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001307 } else if (*data == 0x70) {
1308 data++;
1309 int mod, regop, rm;
1310 get_modrm(*data, &mod, &regop, &rm);
1311 int8_t imm8 = static_cast<int8_t>(data[1]);
1312 AppendToBuffer("pshufd %s,%s,%d",
1313 NameOfXMMRegister(regop),
1314 NameOfXMMRegister(rm),
1315 static_cast<int>(imm8));
1316 data += 2;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001317 } else if (*data == 0x76) {
1318 data++;
1319 int mod, regop, rm;
1320 get_modrm(*data, &mod, &regop, &rm);
1321 AppendToBuffer("pcmpeqd %s,%s",
1322 NameOfXMMRegister(regop),
1323 NameOfXMMRegister(rm));
1324 data++;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001325 } else if (*data == 0x90) {
1326 data++;
1327 AppendToBuffer("nop"); // 2 byte nop.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001328 } else if (*data == 0xF3) {
1329 data++;
1330 int mod, regop, rm;
1331 get_modrm(*data, &mod, &regop, &rm);
1332 AppendToBuffer("psllq %s,%s",
1333 NameOfXMMRegister(regop),
1334 NameOfXMMRegister(rm));
1335 data++;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001336 } else if (*data == 0x73) {
1337 data++;
1338 int mod, regop, rm;
1339 get_modrm(*data, &mod, &regop, &rm);
1340 int8_t imm8 = static_cast<int8_t>(data[1]);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001341 ASSERT(regop == esi || regop == edx);
1342 AppendToBuffer("%s %s,%d",
1343 (regop == esi) ? "psllq" : "psrlq",
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001344 NameOfXMMRegister(rm),
1345 static_cast<int>(imm8));
1346 data += 2;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001347 } else if (*data == 0xD3) {
1348 data++;
1349 int mod, regop, rm;
1350 get_modrm(*data, &mod, &regop, &rm);
1351 AppendToBuffer("psrlq %s,%s",
1352 NameOfXMMRegister(regop),
1353 NameOfXMMRegister(rm));
1354 data++;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001355 } else if (*data == 0x7F) {
1356 AppendToBuffer("movdqa ");
1357 data++;
1358 int mod, regop, rm;
1359 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001360 data += PrintRightXMMOperand(data);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001361 AppendToBuffer(",%s", NameOfXMMRegister(regop));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001362 } else if (*data == 0x7E) {
1363 data++;
1364 int mod, regop, rm;
1365 get_modrm(*data, &mod, &regop, &rm);
1366 AppendToBuffer("movd ");
1367 data += PrintRightOperand(data);
1368 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1369 } else if (*data == 0xDB) {
1370 data++;
1371 int mod, regop, rm;
1372 get_modrm(*data, &mod, &regop, &rm);
1373 AppendToBuffer("pand %s,%s",
1374 NameOfXMMRegister(regop),
1375 NameOfXMMRegister(rm));
1376 data++;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001377 } else if (*data == 0xE7) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001378 data++;
1379 int mod, regop, rm;
1380 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001381 if (mod == 3) {
1382 AppendToBuffer("movntdq ");
1383 data += PrintRightOperand(data);
1384 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1385 } else {
1386 UnimplementedInstruction();
1387 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001388 } else if (*data == 0xEF) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001389 data++;
1390 int mod, regop, rm;
1391 get_modrm(*data, &mod, &regop, &rm);
1392 AppendToBuffer("pxor %s,%s",
1393 NameOfXMMRegister(regop),
1394 NameOfXMMRegister(rm));
1395 data++;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001396 } else if (*data == 0xEB) {
1397 data++;
1398 int mod, regop, rm;
1399 get_modrm(*data, &mod, &regop, &rm);
1400 AppendToBuffer("por %s,%s",
1401 NameOfXMMRegister(regop),
1402 NameOfXMMRegister(rm));
1403 data++;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001404 } else {
1405 UnimplementedInstruction();
1406 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 } else {
1408 UnimplementedInstruction();
1409 }
1410 break;
1411
1412 case 0xFE:
1413 { data++;
1414 int mod, regop, rm;
1415 get_modrm(*data, &mod, &regop, &rm);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001416 if (regop == ecx) {
1417 AppendToBuffer("dec_b ");
1418 data += PrintRightOperand(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 } else {
1420 UnimplementedInstruction();
1421 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 break;
1424
1425 case 0x68:
1426 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1427 data += 5;
1428 break;
1429
1430 case 0x6A:
1431 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1432 data += 2;
1433 break;
1434
1435 case 0xA8:
1436 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1437 data += 2;
1438 break;
1439
1440 case 0xA9:
1441 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1442 data += 5;
1443 break;
1444
1445 case 0xD1: // fall through
1446 case 0xD3: // fall through
1447 case 0xC1:
1448 data += D1D3C1Instruction(data);
1449 break;
1450
1451 case 0xD9: // fall through
kasper.lund7276f142008-07-30 08:49:36 +00001452 case 0xDA: // fall through
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453 case 0xDB: // fall through
1454 case 0xDC: // fall through
1455 case 0xDD: // fall through
1456 case 0xDE: // fall through
1457 case 0xDF:
1458 data += FPUInstruction(data);
1459 break;
1460
1461 case 0xEB:
1462 data += JumpShort(data);
1463 break;
1464
1465 case 0xF2:
1466 if (*(data+1) == 0x0F) {
1467 byte b2 = *(data+2);
1468 if (b2 == 0x11) {
1469 AppendToBuffer("movsd ");
1470 data += 3;
1471 int mod, regop, rm;
1472 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001473 data += PrintRightXMMOperand(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1475 } else if (b2 == 0x10) {
1476 data += 3;
1477 int mod, regop, rm;
1478 get_modrm(*data, &mod, &regop, &rm);
1479 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001480 data += PrintRightXMMOperand(data);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001481 } else if (b2 == 0x5A) {
1482 data += 3;
1483 int mod, regop, rm;
1484 get_modrm(*data, &mod, &regop, &rm);
1485 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1486 data += PrintRightXMMOperand(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 } else {
1488 const char* mnem = "?";
1489 switch (b2) {
1490 case 0x2A: mnem = "cvtsi2sd"; break;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001491 case 0x2C: mnem = "cvttsd2si"; break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001492 case 0x2D: mnem = "cvtsd2si"; break;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001493 case 0x51: mnem = "sqrtsd"; break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 case 0x58: mnem = "addsd"; break;
1495 case 0x59: mnem = "mulsd"; break;
1496 case 0x5C: mnem = "subsd"; break;
1497 case 0x5E: mnem = "divsd"; break;
1498 }
1499 data += 3;
1500 int mod, regop, rm;
1501 get_modrm(*data, &mod, &regop, &rm);
1502 if (b2 == 0x2A) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001503 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1504 data += PrintRightOperand(data);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001505 } else if (b2 == 0x2C || b2 == 0x2D) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001506 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1507 data += PrintRightXMMOperand(data);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001508 } else if (b2 == 0xC2) {
1509 // Intel manual 2A, Table 3-18.
1510 const char* const pseudo_op[] = {
1511 "cmpeqsd",
1512 "cmpltsd",
1513 "cmplesd",
1514 "cmpunordsd",
1515 "cmpneqsd",
1516 "cmpnltsd",
1517 "cmpnlesd",
1518 "cmpordsd"
1519 };
1520 AppendToBuffer("%s %s,%s",
1521 pseudo_op[data[1]],
1522 NameOfXMMRegister(regop),
1523 NameOfXMMRegister(rm));
1524 data += 2;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 } else {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001526 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1527 data += PrintRightXMMOperand(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 }
1529 }
1530 } else {
1531 UnimplementedInstruction();
1532 }
1533 break;
1534
1535 case 0xF3:
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001536 if (*(data+1) == 0x0F) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001537 byte b2 = *(data+2);
1538 if (b2 == 0x11) {
1539 AppendToBuffer("movss ");
1540 data += 3;
1541 int mod, regop, rm;
1542 get_modrm(*data, &mod, &regop, &rm);
1543 data += PrintRightXMMOperand(data);
1544 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1545 } else if (b2 == 0x10) {
1546 data += 3;
1547 int mod, regop, rm;
1548 get_modrm(*data, &mod, &regop, &rm);
1549 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1550 data += PrintRightXMMOperand(data);
1551 } else if (b2 == 0x2C) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001552 data += 3;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001553 int mod, regop, rm;
1554 get_modrm(*data, &mod, &regop, &rm);
1555 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1556 data += PrintRightXMMOperand(data);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001557 } else if (b2 == 0x5A) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001558 data += 3;
1559 int mod, regop, rm;
1560 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001561 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1562 data += PrintRightXMMOperand(data);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001563 } else if (b2 == 0x6F) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001564 data += 3;
1565 int mod, regop, rm;
1566 get_modrm(*data, &mod, &regop, &rm);
1567 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001568 data += PrintRightXMMOperand(data);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001569 } else if (b2 == 0x7F) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001570 AppendToBuffer("movdqu ");
1571 data += 3;
1572 int mod, regop, rm;
1573 get_modrm(*data, &mod, &regop, &rm);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001574 data += PrintRightXMMOperand(data);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001575 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1576 } else {
1577 UnimplementedInstruction();
1578 }
1579 } else if (*(data+1) == 0xA5) {
1580 data += 2;
1581 AppendToBuffer("rep_movs");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001582 } else if (*(data+1) == 0xAB) {
1583 data += 2;
1584 AppendToBuffer("rep_stos");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 } else {
1586 UnimplementedInstruction();
1587 }
1588 break;
1589
1590 case 0xF7:
1591 data += F7Instruction(data);
1592 break;
1593
1594 default:
1595 UnimplementedInstruction();
1596 }
1597 }
1598
1599 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1600 tmp_buffer_[tmp_buffer_pos_] = '\0';
1601 }
1602
1603 int instr_len = data - instr;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001604 if (instr_len == 0) {
1605 printf("%02x", *data);
1606 }
kasper.lund7276f142008-07-30 08:49:36 +00001607 ASSERT(instr_len > 0); // Ensure progress.
1608
1609 int outp = 0;
1610 // Instruction bytes.
1611 for (byte* bp = instr; bp < data; bp++) {
1612 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
kasper.lund7276f142008-07-30 08:49:36 +00001613 "%02x",
1614 *bp);
1615 }
1616 for (int i = 6 - instr_len; i >= 0; i--) {
1617 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
kasper.lund7276f142008-07-30 08:49:36 +00001618 " ");
1619 }
1620
1621 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
kasper.lund7276f142008-07-30 08:49:36 +00001622 " %s",
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001623 tmp_buffer_.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 return instr_len;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001625} // NOLINT (function is too long)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626
1627
1628//------------------------------------------------------------------------------
1629
1630
1631static const char* cpu_regs[8] = {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1633};
1634
1635
1636static const char* byte_cpu_regs[8] = {
1637 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638};
1639
1640
1641static const char* xmm_regs[8] = {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001642 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643};
1644
1645
1646const char* NameConverter::NameOfAddress(byte* addr) const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001647 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1648 return tmp_buffer_.start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649}
1650
1651
1652const char* NameConverter::NameOfConstant(byte* addr) const {
1653 return NameOfAddress(addr);
1654}
1655
1656
1657const char* NameConverter::NameOfCPURegister(int reg) const {
1658 if (0 <= reg && reg < 8) return cpu_regs[reg];
1659 return "noreg";
1660}
1661
1662
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001663const char* NameConverter::NameOfByteCPURegister(int reg) const {
1664 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1665 return "noreg";
1666}
1667
1668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669const char* NameConverter::NameOfXMMRegister(int reg) const {
1670 if (0 <= reg && reg < 8) return xmm_regs[reg];
1671 return "noxmmreg";
1672}
1673
1674
1675const char* NameConverter::NameInCode(byte* addr) const {
1676 // IA32 does not embed debug strings at the moment.
1677 UNREACHABLE();
1678 return "";
1679}
1680
1681
1682//------------------------------------------------------------------------------
1683
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001684Disassembler::Disassembler(const NameConverter& converter)
1685 : converter_(converter) {}
1686
1687
1688Disassembler::~Disassembler() {}
1689
1690
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001691int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 byte* instruction) {
1693 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001694 return d.InstructionDecode(buffer, instruction);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695}
1696
1697
kasper.lund7276f142008-07-30 08:49:36 +00001698// The IA-32 assembler does not currently use constant pools.
1699int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1700
1701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001703 NameConverter converter;
1704 Disassembler d(converter);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001705 for (byte* pc = begin; pc < end;) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001706 v8::internal::EmbeddedVector<char, 128> buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 buffer[0] = '\0';
1708 byte* prev_pc = pc;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001709 pc += d.InstructionDecode(buffer, pc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001710 fprintf(f, "%p", prev_pc);
1711 fprintf(f, " ");
1712
1713 for (byte* bp = prev_pc; bp < pc; bp++) {
1714 fprintf(f, "%02x", *bp);
1715 }
1716 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1717 fprintf(f, " ");
1718 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001719 fprintf(f, " %s\n", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001720 }
1721}
1722
1723
1724} // namespace disasm
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001725
1726#endif // V8_TARGET_ARCH_IA32