blob: 22c2a55c17b9413c413fd064bbbf2bbf68c3d1ea [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
5#include <assert.h>
Steve Blocka7e24c12009-10-30 11:49:00 +00006#include <stdarg.h>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include <stdio.h>
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/v8.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010010
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011#if V8_TARGET_ARCH_IA32
Leon Clarkef7060e22010-06-03 12:02:55 +010012
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000014
15namespace disasm {
16
17enum OperandOrder {
18 UNSET_OP_ORDER = 0,
19 REG_OPER_OP_ORDER,
20 OPER_REG_OP_ORDER
21};
22
23
24//------------------------------------------------------------------
25// Tables
26//------------------------------------------------------------------
27struct ByteMnemonic {
28 int b; // -1 terminates, otherwise must be in range (0..255)
29 const char* mnem;
30 OperandOrder op_order_;
31};
32
33
Ben Murdoch69a99ed2011-11-30 16:03:39 +000034static const ByteMnemonic two_operands_instr[] = {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010035 {0x01, "add", OPER_REG_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000036 {0x03, "add", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000037 {0x09, "or", OPER_REG_OP_ORDER},
38 {0x0B, "or", REG_OPER_OP_ORDER},
39 {0x1B, "sbb", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000040 {0x21, "and", OPER_REG_OP_ORDER},
41 {0x23, "and", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000042 {0x29, "sub", OPER_REG_OP_ORDER},
Leon Clarkee46be812010-01-19 14:06:41 +000043 {0x2A, "subb", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000044 {0x2B, "sub", REG_OPER_OP_ORDER},
Leon Clarkeeab96aa2010-01-27 16:31:12 +000045 {0x31, "xor", OPER_REG_OP_ORDER},
46 {0x33, "xor", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000047 {0x38, "cmpb", OPER_REG_OP_ORDER},
48 {0x3A, "cmpb", REG_OPER_OP_ORDER},
49 {0x3B, "cmp", REG_OPER_OP_ORDER},
50 {0x84, "test_b", REG_OPER_OP_ORDER},
51 {0x85, "test", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000052 {0x87, "xchg", REG_OPER_OP_ORDER},
53 {0x8A, "mov_b", REG_OPER_OP_ORDER},
54 {0x8B, "mov", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000055 {0x8D, "lea", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000056 {-1, "", UNSET_OP_ORDER}
57};
58
59
Ben Murdoch69a99ed2011-11-30 16:03:39 +000060static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000061 {0xC3, "ret", UNSET_OP_ORDER},
62 {0xC9, "leave", UNSET_OP_ORDER},
63 {0x90, "nop", UNSET_OP_ORDER},
64 {0xF4, "hlt", UNSET_OP_ORDER},
65 {0xCC, "int3", UNSET_OP_ORDER},
66 {0x60, "pushad", UNSET_OP_ORDER},
67 {0x61, "popad", UNSET_OP_ORDER},
68 {0x9C, "pushfd", UNSET_OP_ORDER},
69 {0x9D, "popfd", UNSET_OP_ORDER},
70 {0x9E, "sahf", UNSET_OP_ORDER},
71 {0x99, "cdq", UNSET_OP_ORDER},
72 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010073 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010074 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000075 {-1, "", UNSET_OP_ORDER}
76};
77
78
Ben Murdoch69a99ed2011-11-30 16:03:39 +000079static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000080 {0xE8, "call", UNSET_OP_ORDER},
81 {0xE9, "jmp", UNSET_OP_ORDER},
82 {-1, "", UNSET_OP_ORDER}
83};
84
85
Ben Murdoch69a99ed2011-11-30 16:03:39 +000086static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000087 {0x05, "add", UNSET_OP_ORDER},
88 {0x0D, "or", UNSET_OP_ORDER},
89 {0x15, "adc", UNSET_OP_ORDER},
90 {0x25, "and", UNSET_OP_ORDER},
91 {0x2D, "sub", UNSET_OP_ORDER},
92 {0x35, "xor", UNSET_OP_ORDER},
93 {0x3D, "cmp", UNSET_OP_ORDER},
94 {-1, "", UNSET_OP_ORDER}
95};
96
97
Ben Murdoch3ef787d2012-04-12 10:51:47 +010098// Generally we don't want to generate these because they are subject to partial
99// register stalls. They are included for completeness and because the cmp
100// variant is used by the RecordWrite stub. Because it does not update the
101// register it is not subject to partial register stalls.
102static ByteMnemonic byte_immediate_instr[] = {
103 {0x0c, "or", UNSET_OP_ORDER},
104 {0x24, "and", UNSET_OP_ORDER},
105 {0x34, "xor", UNSET_OP_ORDER},
106 {0x3c, "cmp", UNSET_OP_ORDER},
107 {-1, "", UNSET_OP_ORDER}
108};
109
110
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000111static const char* const jump_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 /*0*/ "jo", "jno", "jc", "jnc",
113 /*4*/ "jz", "jnz", "jna", "ja",
114 /*8*/ "js", "jns", "jpe", "jpo",
115 /*12*/ "jl", "jnl", "jng", "jg"
116};
117
118
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000119static const char* const set_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000120 /*0*/ "seto", "setno", "setc", "setnc",
121 /*4*/ "setz", "setnz", "setna", "seta",
122 /*8*/ "sets", "setns", "setpe", "setpo",
123 /*12*/ "setl", "setnl", "setng", "setg"
124};
125
126
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000127static const char* const conditional_move_mnem[] = {
Steve Block3ce2e202009-11-05 08:53:23 +0000128 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
129 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
130 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
131 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
132};
133
134
Steve Blocka7e24c12009-10-30 11:49:00 +0000135enum InstructionType {
136 NO_INSTR,
137 ZERO_OPERANDS_INSTR,
138 TWO_OPERANDS_INSTR,
139 JUMP_CONDITIONAL_SHORT_INSTR,
140 REGISTER_INSTR,
141 MOVE_REG_INSTR,
142 CALL_JUMP_INSTR,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100143 SHORT_IMMEDIATE_INSTR,
144 BYTE_IMMEDIATE_INSTR
Steve Blocka7e24c12009-10-30 11:49:00 +0000145};
146
147
148struct InstructionDesc {
149 const char* mnem;
150 InstructionType type;
151 OperandOrder op_order_;
152};
153
154
155class InstructionTable {
156 public:
157 InstructionTable();
158 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100159 static InstructionTable* get_instance() {
160 static InstructionTable table;
161 return &table;
162 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000163
164 private:
165 InstructionDesc instructions_[256];
166 void Clear();
167 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000168 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000169 void SetTableRange(InstructionType type,
170 byte start,
171 byte end,
172 const char* mnem);
173 void AddJumpConditionalShort();
174};
175
176
177InstructionTable::InstructionTable() {
178 Clear();
179 Init();
180}
181
182
183void InstructionTable::Clear() {
184 for (int i = 0; i < 256; i++) {
185 instructions_[i].mnem = "";
186 instructions_[i].type = NO_INSTR;
187 instructions_[i].op_order_ = UNSET_OP_ORDER;
188 }
189}
190
191
192void InstructionTable::Init() {
193 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
194 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
195 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
196 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100197 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 AddJumpConditionalShort();
199 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
200 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
201 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
202 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
203 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
204 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
205}
206
207
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000208void InstructionTable::CopyTable(const ByteMnemonic bm[],
209 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 for (int i = 0; bm[i].b >= 0; i++) {
211 InstructionDesc* id = &instructions_[bm[i].b];
212 id->mnem = bm[i].mnem;
213 id->op_order_ = bm[i].op_order_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 id->type = type;
216 }
217}
218
219
220void InstructionTable::SetTableRange(InstructionType type,
221 byte start,
222 byte end,
223 const char* mnem) {
224 for (byte b = start; b <= end; b++) {
225 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000226 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000227 id->mnem = mnem;
228 id->type = type;
229 }
230}
231
232
233void InstructionTable::AddJumpConditionalShort() {
234 for (byte b = 0x70; b <= 0x7F; b++) {
235 InstructionDesc* id = &instructions_[b];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 id->mnem = jump_conditional_mnem[b & 0x0F];
238 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
239 }
240}
241
242
Steve Blocka7e24c12009-10-30 11:49:00 +0000243// The IA32 disassembler implementation.
244class DisassemblerIA32 {
245 public:
246 DisassemblerIA32(const NameConverter& converter,
247 bool abort_on_unimplemented = true)
248 : converter_(converter),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100249 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000250 tmp_buffer_pos_(0),
251 abort_on_unimplemented_(abort_on_unimplemented) {
252 tmp_buffer_[0] = '\0';
253 }
254
255 virtual ~DisassemblerIA32() {}
256
257 // Writes one disassembled instruction into 'buffer' (0-terminated).
258 // Returns the length of the disassembled machine instruction in bytes.
259 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
260
261 private:
262 const NameConverter& converter_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100263 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000264 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
265 unsigned int tmp_buffer_pos_;
266 bool abort_on_unimplemented_;
267
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 enum {
269 eax = 0,
270 ecx = 1,
271 edx = 2,
272 ebx = 3,
273 esp = 4,
274 ebp = 5,
275 esi = 6,
276 edi = 7
277 };
278
279
Steve Blockd0582a62009-12-15 09:54:21 +0000280 enum ShiftOpcodeExtension {
281 kROL = 0,
282 kROR = 1,
283 kRCL = 2,
284 kRCR = 3,
285 kSHL = 4,
286 KSHR = 5,
287 kSAR = 7
288 };
289
290
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 const char* NameOfCPURegister(int reg) const {
292 return converter_.NameOfCPURegister(reg);
293 }
294
295
296 const char* NameOfByteCPURegister(int reg) const {
297 return converter_.NameOfByteCPURegister(reg);
298 }
299
300
301 const char* NameOfXMMRegister(int reg) const {
302 return converter_.NameOfXMMRegister(reg);
303 }
304
305
306 const char* NameOfAddress(byte* addr) const {
307 return converter_.NameOfAddress(addr);
308 }
309
310
311 // Disassembler helper functions.
312 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
313 *mod = (data >> 6) & 3;
314 *regop = (data & 0x38) >> 3;
315 *rm = data & 7;
316 }
317
318
319 static void get_sib(byte data, int* scale, int* index, int* base) {
320 *scale = (data >> 6) & 3;
321 *index = (data >> 3) & 7;
322 *base = data & 7;
323 }
324
325 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
326
327 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
328 int PrintRightOperand(byte* modrmp);
329 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100330 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000331 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
332 int PrintImmediateOp(byte* data);
333 int F7Instruction(byte* data);
334 int D1D3C1Instruction(byte* data);
335 int JumpShort(byte* data);
336 int JumpConditional(byte* data, const char* comment);
337 int JumpConditionalShort(byte* data, const char* comment);
338 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000339 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000340 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000341 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
342 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 void AppendToBuffer(const char* format, ...);
344
345
346 void UnimplementedInstruction() {
347 if (abort_on_unimplemented_) {
348 UNIMPLEMENTED();
349 } else {
350 AppendToBuffer("'Unimplemented Instruction'");
351 }
352 }
353};
354
355
356void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
357 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
358 va_list args;
359 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000360 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000361 va_end(args);
362 tmp_buffer_pos_ += result;
363}
364
365int DisassemblerIA32::PrintRightOperandHelper(
366 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100367 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 int mod, regop, rm;
369 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100370 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
371 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 switch (mod) {
373 case 0:
374 if (rm == ebp) {
375 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
376 AppendToBuffer("[0x%x]", disp);
377 return 5;
378 } else if (rm == esp) {
379 byte sib = *(modrmp + 1);
380 int scale, index, base;
381 get_sib(sib, &scale, &index, &base);
382 if (index == esp && base == esp && scale == 0 /*times_1*/) {
383 AppendToBuffer("[%s]", (this->*register_name)(rm));
384 return 2;
385 } else if (base == ebp) {
386 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000387 AppendToBuffer("[%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 (this->*register_name)(index),
389 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000390 disp < 0 ? "-" : "+",
391 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 return 6;
393 } else if (index != esp && base != ebp) {
394 // [base+index*scale]
395 AppendToBuffer("[%s+%s*%d]",
396 (this->*register_name)(base),
397 (this->*register_name)(index),
398 1 << scale);
399 return 2;
400 } else {
401 UnimplementedInstruction();
402 return 1;
403 }
404 } else {
405 AppendToBuffer("[%s]", (this->*register_name)(rm));
406 return 1;
407 }
408 break;
409 case 1: // fall through
410 case 2:
411 if (rm == esp) {
412 byte sib = *(modrmp + 1);
413 int scale, index, base;
414 get_sib(sib, &scale, &index, &base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
416 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 AppendToBuffer("[%s%s0x%x]",
419 (this->*register_name)(rm),
420 disp < 0 ? "-" : "+",
421 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000422 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000423 AppendToBuffer("[%s+%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 (this->*register_name)(base),
425 (this->*register_name)(index),
426 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 disp < 0 ? "-" : "+",
428 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000429 }
430 return mod == 2 ? 6 : 3;
431 } else {
432 // No sib.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
434 : *reinterpret_cast<int8_t*>(modrmp + 1);
435 AppendToBuffer("[%s%s0x%x]",
436 (this->*register_name)(rm),
437 disp < 0 ? "-" : "+",
438 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 return mod == 2 ? 5 : 2;
440 }
441 break;
442 case 3:
443 AppendToBuffer("%s", (this->*register_name)(rm));
444 return 1;
445 default:
446 UnimplementedInstruction();
447 return 1;
448 }
449 UNREACHABLE();
450}
451
452
453int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
454 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
455}
456
457
458int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
459 return PrintRightOperandHelper(modrmp,
460 &DisassemblerIA32::NameOfByteCPURegister);
461}
462
463
Steve Block44f0eee2011-05-26 01:26:41 +0100464int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
465 return PrintRightOperandHelper(modrmp,
466 &DisassemblerIA32::NameOfXMMRegister);
467}
468
469
Steve Blocka7e24c12009-10-30 11:49:00 +0000470// Returns number of bytes used including the current *data.
471// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
472int DisassemblerIA32::PrintOperands(const char* mnem,
473 OperandOrder op_order,
474 byte* data) {
475 byte modrm = *data;
476 int mod, regop, rm;
477 get_modrm(modrm, &mod, &regop, &rm);
478 int advance = 0;
479 switch (op_order) {
480 case REG_OPER_OP_ORDER: {
481 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
482 advance = PrintRightOperand(data);
483 break;
484 }
485 case OPER_REG_OP_ORDER: {
486 AppendToBuffer("%s ", mnem);
487 advance = PrintRightOperand(data);
488 AppendToBuffer(",%s", NameOfCPURegister(regop));
489 break;
490 }
491 default:
492 UNREACHABLE();
493 break;
494 }
495 return advance;
496}
497
498
499// Returns number of bytes used by machine instruction, including *data byte.
500// Writes immediate instructions to 'tmp_buffer_'.
501int DisassemblerIA32::PrintImmediateOp(byte* data) {
502 bool sign_extension_bit = (*data & 0x02) != 0;
503 byte modrm = *(data+1);
504 int mod, regop, rm;
505 get_modrm(modrm, &mod, &regop, &rm);
506 const char* mnem = "Imm???";
507 switch (regop) {
508 case 0: mnem = "add"; break;
509 case 1: mnem = "or"; break;
510 case 2: mnem = "adc"; break;
511 case 4: mnem = "and"; break;
512 case 5: mnem = "sub"; break;
513 case 6: mnem = "xor"; break;
514 case 7: mnem = "cmp"; break;
515 default: UnimplementedInstruction();
516 }
517 AppendToBuffer("%s ", mnem);
518 int count = PrintRightOperand(data+1);
519 if (sign_extension_bit) {
520 AppendToBuffer(",0x%x", *(data + 1 + count));
521 return 1 + count + 1 /*int8*/;
522 } else {
523 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
524 return 1 + count + 4 /*int32_t*/;
525 }
526}
527
528
529// Returns number of bytes used, including *data.
530int DisassemblerIA32::F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 DCHECK_EQ(0xF7, *data);
532 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000533 int mod, regop, rm;
534 get_modrm(modrm, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 const char* mnem = NULL;
536 switch (regop) {
537 case 0:
538 mnem = "test";
539 break;
540 case 2:
541 mnem = "not";
542 break;
543 case 3:
544 mnem = "neg";
545 break;
546 case 4:
547 mnem = "mul";
548 break;
549 case 5:
550 mnem = "imul";
551 break;
552 case 6:
553 mnem = "div";
554 break;
555 case 7:
556 mnem = "idiv";
557 break;
558 default:
559 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000561 AppendToBuffer("%s ", mnem);
562 int count = PrintRightOperand(data);
563 if (regop == 0) {
564 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
565 count += 4;
566 }
567 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000568}
569
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000570
Steve Blocka7e24c12009-10-30 11:49:00 +0000571int DisassemblerIA32::D1D3C1Instruction(byte* data) {
572 byte op = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000573 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
574 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 int mod, regop, rm;
576 get_modrm(modrm, &mod, &regop, &rm);
577 int imm8 = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000578 const char* mnem = NULL;
579 switch (regop) {
580 case kROL:
581 mnem = "rol";
582 break;
583 case kROR:
584 mnem = "ror";
585 break;
586 case kRCL:
587 mnem = "rcl";
588 break;
589 case kRCR:
590 mnem = "rcr";
591 break;
592 case kSHL:
593 mnem = "shl";
594 break;
595 case KSHR:
596 mnem = "shr";
597 break;
598 case kSAR:
599 mnem = "sar";
600 break;
601 default:
602 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604 AppendToBuffer("%s ", mnem);
605 int count = PrintRightOperand(data);
606 if (op == 0xD1) {
607 imm8 = 1;
608 } else if (op == 0xC1) {
609 imm8 = *(data + 1);
610 count++;
611 } else if (op == 0xD3) {
612 // Shift/rotate by cl.
613 }
614 if (imm8 >= 0) {
615 AppendToBuffer(",%d", imm8);
616 } else {
617 AppendToBuffer(",cl");
618 }
619 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000620}
621
622
623// Returns number of bytes used, including *data.
624int DisassemblerIA32::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000625 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 byte b = *(data+1);
627 byte* dest = data + static_cast<int8_t>(b) + 2;
628 AppendToBuffer("jmp %s", NameOfAddress(dest));
629 return 2;
630}
631
632
633// Returns number of bytes used, including *data.
634int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 byte cond = *(data+1) & 0x0F;
637 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
638 const char* mnem = jump_conditional_mnem[cond];
639 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
640 if (comment != NULL) {
641 AppendToBuffer(", %s", comment);
642 }
643 return 6; // includes 0x0F
644}
645
646
647// Returns number of bytes used, including *data.
648int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
649 byte cond = *data & 0x0F;
650 byte b = *(data+1);
651 byte* dest = data + static_cast<int8_t>(b) + 2;
652 const char* mnem = jump_conditional_mnem[cond];
653 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
654 if (comment != NULL) {
655 AppendToBuffer(", %s", comment);
656 }
657 return 2;
658}
659
660
661// Returns number of bytes used, including *data.
662int DisassemblerIA32::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000664 byte cond = *(data+1) & 0x0F;
665 const char* mnem = set_conditional_mnem[cond];
666 AppendToBuffer("%s ", mnem);
667 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000668 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000669}
670
671
672// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000673int DisassemblerIA32::CMov(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000674 DCHECK_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000675 byte cond = *(data + 1) & 0x0F;
676 const char* mnem = conditional_move_mnem[cond];
677 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
678 return 2 + op_size; // includes 0x0F
679}
680
681
682// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000683int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000684 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +0000686 byte modrm_byte = *(data+1);
687
688 if (modrm_byte >= 0xC0) {
689 return RegisterFPUInstruction(escape_opcode, modrm_byte);
690 } else {
691 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000692 }
Steve Blockd0582a62009-12-15 09:54:21 +0000693}
694
695int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
696 int modrm_byte,
697 byte* modrm_start) {
698 const char* mnem = "?";
699 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
700 switch (escape_opcode) {
701 case 0xD9: switch (regop) {
702 case 0: mnem = "fld_s"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000703 case 2: mnem = "fst_s"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000704 case 3: mnem = "fstp_s"; break;
705 case 7: mnem = "fstcw"; break;
706 default: UnimplementedInstruction();
707 }
708 break;
709
710 case 0xDB: switch (regop) {
711 case 0: mnem = "fild_s"; break;
712 case 1: mnem = "fisttp_s"; break;
713 case 2: mnem = "fist_s"; break;
714 case 3: mnem = "fistp_s"; break;
715 default: UnimplementedInstruction();
716 }
717 break;
718
719 case 0xDD: switch (regop) {
720 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100721 case 1: mnem = "fisttp_d"; break;
722 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000723 case 3: mnem = "fstp_d"; break;
724 default: UnimplementedInstruction();
725 }
726 break;
727
728 case 0xDF: switch (regop) {
729 case 5: mnem = "fild_d"; break;
730 case 7: mnem = "fistp_d"; break;
731 default: UnimplementedInstruction();
732 }
733 break;
734
735 default: UnimplementedInstruction();
736 }
737 AppendToBuffer("%s ", mnem);
738 int count = PrintRightOperand(modrm_start);
739 return count + 1;
740}
741
742int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
743 byte modrm_byte) {
744 bool has_register = false; // Is the FPU register encoded in modrm_byte?
745 const char* mnem = "?";
746
747 switch (escape_opcode) {
748 case 0xD8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 has_register = true;
750 switch (modrm_byte & 0xF8) {
751 case 0xC0: mnem = "fadd_i"; break;
752 case 0xE0: mnem = "fsub_i"; break;
753 case 0xC8: mnem = "fmul_i"; break;
754 case 0xF0: mnem = "fdiv_i"; break;
755 default: UnimplementedInstruction();
756 }
Steve Blockd0582a62009-12-15 09:54:21 +0000757 break;
758
759 case 0xD9:
760 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100761 case 0xC0:
762 mnem = "fld";
763 has_register = true;
764 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000765 case 0xC8:
766 mnem = "fxch";
767 has_register = true;
768 break;
769 default:
770 switch (modrm_byte) {
771 case 0xE0: mnem = "fchs"; break;
772 case 0xE1: mnem = "fabs"; break;
773 case 0xE4: mnem = "ftst"; break;
774 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000775 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100776 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000777 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100778 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100779 case 0xF1: mnem = "fyl2x"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780 case 0xF4: mnem = "fxtract"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000781 case 0xF5: mnem = "fprem1"; break;
782 case 0xF7: mnem = "fincstp"; break;
783 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100784 case 0xFC: mnem = "frndint"; break;
785 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000786 case 0xFE: mnem = "fsin"; break;
787 case 0xFF: mnem = "fcos"; break;
788 default: UnimplementedInstruction();
789 }
790 }
791 break;
792
793 case 0xDA:
794 if (modrm_byte == 0xE9) {
795 mnem = "fucompp";
796 } else {
797 UnimplementedInstruction();
798 }
799 break;
800
801 case 0xDB:
802 if ((modrm_byte & 0xF8) == 0xE8) {
803 mnem = "fucomi";
804 has_register = true;
805 } else if (modrm_byte == 0xE2) {
806 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100807 } else if (modrm_byte == 0xE3) {
808 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +0000809 } else {
810 UnimplementedInstruction();
811 }
812 break;
813
814 case 0xDC:
815 has_register = true;
816 switch (modrm_byte & 0xF8) {
817 case 0xC0: mnem = "fadd"; break;
818 case 0xE8: mnem = "fsub"; break;
819 case 0xC8: mnem = "fmul"; break;
820 case 0xF8: mnem = "fdiv"; break;
821 default: UnimplementedInstruction();
822 }
823 break;
824
825 case 0xDD:
826 has_register = true;
827 switch (modrm_byte & 0xF8) {
828 case 0xC0: mnem = "ffree"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 case 0xD0: mnem = "fst"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000830 case 0xD8: mnem = "fstp"; break;
831 default: UnimplementedInstruction();
832 }
833 break;
834
835 case 0xDE:
836 if (modrm_byte == 0xD9) {
837 mnem = "fcompp";
838 } else {
839 has_register = true;
840 switch (modrm_byte & 0xF8) {
841 case 0xC0: mnem = "faddp"; break;
842 case 0xE8: mnem = "fsubp"; break;
843 case 0xC8: mnem = "fmulp"; break;
844 case 0xF8: mnem = "fdivp"; break;
845 default: UnimplementedInstruction();
846 }
847 }
848 break;
849
850 case 0xDF:
851 if (modrm_byte == 0xE0) {
852 mnem = "fnstsw_ax";
853 } else if ((modrm_byte & 0xF8) == 0xE8) {
854 mnem = "fucomip";
855 has_register = true;
856 }
857 break;
858
859 default: UnimplementedInstruction();
860 }
861
862 if (has_register) {
863 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
864 } else {
865 AppendToBuffer("%s", mnem);
866 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000867 return 2;
868}
869
870
871// Mnemonics for instructions 0xF0 byte.
872// Returns NULL if the instruction is not handled here.
873static const char* F0Mnem(byte f0byte) {
874 switch (f0byte) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100875 case 0x18: return "prefetch";
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 case 0xA2: return "cpuid";
Steve Blocka7e24c12009-10-30 11:49:00 +0000877 case 0xBE: return "movsx_b";
878 case 0xBF: return "movsx_w";
879 case 0xB6: return "movzx_b";
880 case 0xB7: return "movzx_w";
881 case 0xAF: return "imul";
882 case 0xA5: return "shld";
883 case 0xAD: return "shrd";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000884 case 0xAC: return "shrd"; // 3-operand version.
Steve Blocka7e24c12009-10-30 11:49:00 +0000885 case 0xAB: return "bts";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000886 case 0xBD: return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +0000887 default: return NULL;
888 }
889}
890
891
892// Disassembled instruction '*instr' and writes it into 'out_buffer'.
893int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
894 byte* instr) {
895 tmp_buffer_pos_ = 0; // starting to write as position 0
896 byte* data = instr;
897 // Check for hints.
898 const char* branch_hint = NULL;
899 // We use these two prefixes only with branch prediction
900 if (*data == 0x3E /*ds*/) {
901 branch_hint = "predicted taken";
902 data++;
903 } else if (*data == 0x2E /*cs*/) {
904 branch_hint = "predicted not taken";
905 data++;
906 }
907 bool processed = true; // Will be set to false if the current instruction
908 // is not in 'instructions' table.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100909 const InstructionDesc& idesc = instruction_table_->Get(*data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 switch (idesc.type) {
911 case ZERO_OPERANDS_INSTR:
912 AppendToBuffer(idesc.mnem);
913 data++;
914 break;
915
916 case TWO_OPERANDS_INSTR:
917 data++;
918 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
919 break;
920
921 case JUMP_CONDITIONAL_SHORT_INSTR:
922 data += JumpConditionalShort(data, branch_hint);
923 break;
924
925 case REGISTER_INSTR:
926 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
927 data++;
928 break;
929
930 case MOVE_REG_INSTR: {
931 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
932 AppendToBuffer("mov %s,%s",
933 NameOfCPURegister(*data & 0x07),
934 NameOfAddress(addr));
935 data += 5;
936 break;
937 }
938
939 case CALL_JUMP_INSTR: {
940 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
941 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
942 data += 5;
943 break;
944 }
945
946 case SHORT_IMMEDIATE_INSTR: {
947 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000948 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 data += 5;
950 break;
951 }
952
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100953 case BYTE_IMMEDIATE_INSTR: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000954 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100955 data += 2;
956 break;
957 }
958
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 case NO_INSTR:
960 processed = false;
961 break;
962
963 default:
964 UNIMPLEMENTED(); // This type is not implemented.
965 }
966 //----------------------------
967 if (!processed) {
968 switch (*data) {
969 case 0xC2:
970 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
971 data += 3;
972 break;
973
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000974 case 0x6B: {
975 data++;
976 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
977 AppendToBuffer(",%d", *data);
978 data++;
979 } break;
980
981 case 0x69: {
982 data++;
983 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
984 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
985 data += 4;
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 }
987 break;
988
989 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100990 { data++;
991 int mod, regop, rm;
992 get_modrm(*data, &mod, &regop, &rm);
993 if (regop == eax) {
994 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +0100995 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100996 int32_t imm = *data;
997 AppendToBuffer(",0x%x", imm);
998 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000999 } else {
1000 UnimplementedInstruction();
1001 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001002 }
1003 break;
1004
1005 case 0x81: // fall through
1006 case 0x83: // 0x81 with sign extension bit set
1007 data += PrintImmediateOp(data);
1008 break;
1009
1010 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001011 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +00001012 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001013 if (f0byte == 0x18) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001014 data += 2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001015 int mod, regop, rm;
1016 get_modrm(*data, &mod, &regop, &rm);
1017 const char* suffix[] = {"nta", "1", "2", "3"};
1018 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1019 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001020 } else if (f0byte == 0x1F && data[2] == 0) {
1021 AppendToBuffer("nop"); // 3 byte nop.
1022 data += 3;
1023 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1024 AppendToBuffer("nop"); // 4 byte nop.
1025 data += 4;
1026 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1027 data[4] == 0) {
1028 AppendToBuffer("nop"); // 5 byte nop.
1029 data += 5;
1030 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1031 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1032 AppendToBuffer("nop"); // 7 byte nop.
1033 data += 7;
1034 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1035 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1036 data[7] == 0) {
1037 AppendToBuffer("nop"); // 8 byte nop.
1038 data += 8;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001039 } else if (f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001040 AppendToBuffer("%s", f0mnem);
1041 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001042 } else if (f0byte == 0x28) {
1043 data += 2;
1044 int mod, regop, rm;
1045 get_modrm(*data, &mod, &regop, &rm);
1046 AppendToBuffer("movaps %s,%s",
1047 NameOfXMMRegister(regop),
1048 NameOfXMMRegister(rm));
1049 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001050 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1051 const char* const pseudo_op[] = {
1052 "rcpps",
1053 "andps",
1054 "andnps",
1055 "orps",
1056 "xorps",
1057 "addps",
1058 "mulps",
1059 "cvtps2pd",
1060 "cvtdq2ps",
1061 "subps",
1062 "minps",
1063 "divps",
1064 "maxps",
1065 };
1066
Ben Murdoch257744e2011-11-30 15:57:28 +00001067 data += 2;
1068 int mod, regop, rm;
1069 get_modrm(*data, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001070 AppendToBuffer("%s %s,",
1071 pseudo_op[f0byte - 0x53],
1072 NameOfXMMRegister(regop));
1073 data += PrintRightXMMOperand(data);
1074 } else if (f0byte == 0x50) {
1075 data += 2;
1076 int mod, regop, rm;
1077 get_modrm(*data, &mod, &regop, &rm);
1078 AppendToBuffer("movmskps %s,%s",
1079 NameOfCPURegister(regop),
Ben Murdoch257744e2011-11-30 15:57:28 +00001080 NameOfXMMRegister(rm));
1081 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082 } else if (f0byte== 0xC6) {
1083 // shufps xmm, xmm/m128, imm8
1084 data += 2;
1085 int mod, regop, rm;
1086 get_modrm(*data, &mod, &regop, &rm);
1087 int8_t imm8 = static_cast<int8_t>(data[1]);
1088 AppendToBuffer("shufps %s,%s,%d",
1089 NameOfXMMRegister(rm),
1090 NameOfXMMRegister(regop),
1091 static_cast<int>(imm8));
1092 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 } else if ((f0byte & 0xF0) == 0x80) {
1094 data += JumpConditional(data, branch_hint);
1095 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1096 f0byte == 0xB7 || f0byte == 0xAF) {
1097 data += 2;
1098 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1099 } else if ((f0byte & 0xF0) == 0x90) {
1100 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001101 } else if ((f0byte & 0xF0) == 0x40) {
1102 data += CMov(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1104 // shrd, shld, bts
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001106 AppendToBuffer("%s ", f0mnem);
1107 int mod, regop, rm;
1108 get_modrm(*data, &mod, &regop, &rm);
1109 data += PrintRightOperand(data);
1110 if (f0byte == 0xAB) {
1111 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001112 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001113 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001114 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001115 } else if (f0byte == 0xBD) {
1116 data += 2;
1117 int mod, regop, rm;
1118 get_modrm(*data, &mod, &regop, &rm);
1119 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1120 data += PrintRightOperand(data);
1121 } else {
1122 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +00001123 }
1124 }
1125 break;
1126
1127 case 0x8F:
1128 { data++;
1129 int mod, regop, rm;
1130 get_modrm(*data, &mod, &regop, &rm);
1131 if (regop == eax) {
1132 AppendToBuffer("pop ");
1133 data += PrintRightOperand(data);
1134 }
1135 }
1136 break;
1137
1138 case 0xFF:
1139 { data++;
1140 int mod, regop, rm;
1141 get_modrm(*data, &mod, &regop, &rm);
1142 const char* mnem = NULL;
1143 switch (regop) {
1144 case esi: mnem = "push"; break;
1145 case eax: mnem = "inc"; break;
1146 case ecx: mnem = "dec"; break;
1147 case edx: mnem = "call"; break;
1148 case esp: mnem = "jmp"; break;
1149 default: mnem = "???";
1150 }
1151 AppendToBuffer("%s ", mnem);
1152 data += PrintRightOperand(data);
1153 }
1154 break;
1155
1156 case 0xC7: // imm32, fall through
1157 case 0xC6: // imm8
1158 { bool is_byte = *data == 0xC6;
1159 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001160 if (is_byte) {
1161 AppendToBuffer("%s ", "mov_b");
1162 data += PrintRightByteOperand(data);
1163 int32_t imm = *data;
1164 AppendToBuffer(",0x%x", imm);
1165 data++;
1166 } else {
1167 AppendToBuffer("%s ", "mov");
1168 data += PrintRightOperand(data);
1169 int32_t imm = *reinterpret_cast<int32_t*>(data);
1170 AppendToBuffer(",0x%x", imm);
1171 data += 4;
1172 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001173 }
1174 break;
1175
1176 case 0x80:
1177 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001178 int mod, regop, rm;
1179 get_modrm(*data, &mod, &regop, &rm);
1180 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001181 switch (regop) {
1182 case 5: mnem = "subb"; break;
1183 case 7: mnem = "cmpb"; break;
1184 default: UnimplementedInstruction();
1185 }
1186 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001187 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001188 int32_t imm = *data;
1189 AppendToBuffer(",0x%x", imm);
1190 data++;
1191 }
1192 break;
1193
1194 case 0x88: // 8bit, fall through
1195 case 0x89: // 32bit
1196 { bool is_byte = *data == 0x88;
1197 int mod, regop, rm;
1198 data++;
1199 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001200 if (is_byte) {
1201 AppendToBuffer("%s ", "mov_b");
1202 data += PrintRightByteOperand(data);
1203 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1204 } else {
1205 AppendToBuffer("%s ", "mov");
1206 data += PrintRightOperand(data);
1207 AppendToBuffer(",%s", NameOfCPURegister(regop));
1208 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001209 }
1210 break;
1211
1212 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001213 while (*data == 0x66) data++;
1214 if (*data == 0xf && data[1] == 0x1f) {
1215 AppendToBuffer("nop"); // 0x66 prefix
1216 } else if (*data == 0x90) {
1217 AppendToBuffer("nop"); // 0x66 prefix
1218 } else if (*data == 0x8B) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 data++;
1220 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1221 } else if (*data == 0x89) {
1222 data++;
1223 int mod, regop, rm;
1224 get_modrm(*data, &mod, &regop, &rm);
1225 AppendToBuffer("mov_w ");
1226 data += PrintRightOperand(data);
1227 AppendToBuffer(",%s", NameOfCPURegister(regop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001228 } else if (*data == 0xC7) {
1229 data++;
1230 AppendToBuffer("%s ", "mov_w");
1231 data += PrintRightOperand(data);
1232 int imm = *reinterpret_cast<int16_t*>(data);
1233 AppendToBuffer(",0x%x", imm);
1234 data += 2;
Steve Block3ce2e202009-11-05 08:53:23 +00001235 } else if (*data == 0x0F) {
1236 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001237 if (*data == 0x38) {
1238 data++;
1239 if (*data == 0x17) {
1240 data++;
1241 int mod, regop, rm;
1242 get_modrm(*data, &mod, &regop, &rm);
1243 AppendToBuffer("ptest %s,%s",
1244 NameOfXMMRegister(regop),
1245 NameOfXMMRegister(rm));
1246 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001247 } else if (*data == 0x2A) {
1248 // movntdqa
1249 data++;
1250 int mod, regop, rm;
1251 get_modrm(*data, &mod, &regop, &rm);
1252 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1253 data += PrintRightOperand(data);
Steve Block6ded16b2010-05-10 14:33:55 +01001254 } else {
1255 UnimplementedInstruction();
1256 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001257 } else if (*data == 0x3A) {
1258 data++;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001259 if (*data == 0x0B) {
1260 data++;
1261 int mod, regop, rm;
1262 get_modrm(*data, &mod, &regop, &rm);
1263 int8_t imm8 = static_cast<int8_t>(data[1]);
1264 AppendToBuffer("roundsd %s,%s,%d",
1265 NameOfXMMRegister(regop),
1266 NameOfXMMRegister(rm),
1267 static_cast<int>(imm8));
1268 data += 2;
1269 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001270 data++;
1271 int mod, regop, rm;
1272 get_modrm(*data, &mod, &regop, &rm);
1273 int8_t imm8 = static_cast<int8_t>(data[1]);
1274 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001275 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001276 NameOfXMMRegister(rm),
1277 static_cast<int>(imm8));
1278 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001279 } else if (*data == 0x17) {
1280 data++;
1281 int mod, regop, rm;
1282 get_modrm(*data, &mod, &regop, &rm);
1283 int8_t imm8 = static_cast<int8_t>(data[1]);
1284 AppendToBuffer("extractps %s,%s,%d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001285 NameOfCPURegister(rm),
1286 NameOfXMMRegister(regop),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001287 static_cast<int>(imm8));
1288 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001289 } else if (*data == 0x22) {
1290 data++;
1291 int mod, regop, rm;
1292 get_modrm(*data, &mod, &regop, &rm);
1293 int8_t imm8 = static_cast<int8_t>(data[1]);
1294 AppendToBuffer("pinsrd %s,%s,%d",
1295 NameOfXMMRegister(regop),
1296 NameOfCPURegister(rm),
1297 static_cast<int>(imm8));
1298 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001299 } else {
1300 UnimplementedInstruction();
1301 }
Steve Block6ded16b2010-05-10 14:33:55 +01001302 } else if (*data == 0x2E || *data == 0x2F) {
1303 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001304 data++;
1305 int mod, regop, rm;
1306 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001307 if (mod == 0x3) {
1308 AppendToBuffer("%s %s,%s", mnem,
1309 NameOfXMMRegister(regop),
1310 NameOfXMMRegister(rm));
1311 data++;
1312 } else {
1313 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1314 data += PrintRightOperand(data);
1315 }
1316 } else if (*data == 0x50) {
1317 data++;
1318 int mod, regop, rm;
1319 get_modrm(*data, &mod, &regop, &rm);
1320 AppendToBuffer("movmskpd %s,%s",
1321 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001322 NameOfXMMRegister(rm));
1323 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001324 } else if (*data == 0x54) {
1325 data++;
1326 int mod, regop, rm;
1327 get_modrm(*data, &mod, &regop, &rm);
1328 AppendToBuffer("andpd %s,%s",
1329 NameOfXMMRegister(regop),
1330 NameOfXMMRegister(rm));
1331 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001332 } else if (*data == 0x56) {
1333 data++;
1334 int mod, regop, rm;
1335 get_modrm(*data, &mod, &regop, &rm);
1336 AppendToBuffer("orpd %s,%s",
1337 NameOfXMMRegister(regop),
1338 NameOfXMMRegister(rm));
1339 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001340 } else if (*data == 0x57) {
1341 data++;
1342 int mod, regop, rm;
1343 get_modrm(*data, &mod, &regop, &rm);
1344 AppendToBuffer("xorpd %s,%s",
1345 NameOfXMMRegister(regop),
1346 NameOfXMMRegister(rm));
1347 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001348 } else if (*data == 0x6E) {
1349 data++;
1350 int mod, regop, rm;
1351 get_modrm(*data, &mod, &regop, &rm);
1352 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1353 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001354 } else if (*data == 0x6F) {
1355 data++;
1356 int mod, regop, rm;
1357 get_modrm(*data, &mod, &regop, &rm);
1358 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001359 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001360 } else if (*data == 0x70) {
1361 data++;
1362 int mod, regop, rm;
1363 get_modrm(*data, &mod, &regop, &rm);
1364 int8_t imm8 = static_cast<int8_t>(data[1]);
1365 AppendToBuffer("pshufd %s,%s,%d",
1366 NameOfXMMRegister(regop),
1367 NameOfXMMRegister(rm),
1368 static_cast<int>(imm8));
1369 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 } else if (*data == 0x76) {
1371 data++;
1372 int mod, regop, rm;
1373 get_modrm(*data, &mod, &regop, &rm);
1374 AppendToBuffer("pcmpeqd %s,%s",
1375 NameOfXMMRegister(regop),
1376 NameOfXMMRegister(rm));
1377 data++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001378 } else if (*data == 0x90) {
1379 data++;
1380 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001381 } else if (*data == 0xF3) {
1382 data++;
1383 int mod, regop, rm;
1384 get_modrm(*data, &mod, &regop, &rm);
1385 AppendToBuffer("psllq %s,%s",
1386 NameOfXMMRegister(regop),
1387 NameOfXMMRegister(rm));
1388 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001389 } else if (*data == 0x73) {
1390 data++;
1391 int mod, regop, rm;
1392 get_modrm(*data, &mod, &regop, &rm);
1393 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001394 DCHECK(regop == esi || regop == edx);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001395 AppendToBuffer("%s %s,%d",
1396 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001397 NameOfXMMRegister(rm),
1398 static_cast<int>(imm8));
1399 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001400 } else if (*data == 0xD3) {
1401 data++;
1402 int mod, regop, rm;
1403 get_modrm(*data, &mod, &regop, &rm);
1404 AppendToBuffer("psrlq %s,%s",
1405 NameOfXMMRegister(regop),
1406 NameOfXMMRegister(rm));
1407 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001408 } else if (*data == 0x7F) {
1409 AppendToBuffer("movdqa ");
1410 data++;
1411 int mod, regop, rm;
1412 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001413 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001414 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001415 } else if (*data == 0x7E) {
1416 data++;
1417 int mod, regop, rm;
1418 get_modrm(*data, &mod, &regop, &rm);
1419 AppendToBuffer("movd ");
1420 data += PrintRightOperand(data);
1421 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1422 } else if (*data == 0xDB) {
1423 data++;
1424 int mod, regop, rm;
1425 get_modrm(*data, &mod, &regop, &rm);
1426 AppendToBuffer("pand %s,%s",
1427 NameOfXMMRegister(regop),
1428 NameOfXMMRegister(rm));
1429 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001430 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001431 data++;
1432 int mod, regop, rm;
1433 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001434 if (mod == 3) {
1435 AppendToBuffer("movntdq ");
1436 data += PrintRightOperand(data);
1437 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1438 } else {
1439 UnimplementedInstruction();
1440 }
Steve Block6ded16b2010-05-10 14:33:55 +01001441 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001442 data++;
1443 int mod, regop, rm;
1444 get_modrm(*data, &mod, &regop, &rm);
1445 AppendToBuffer("pxor %s,%s",
1446 NameOfXMMRegister(regop),
1447 NameOfXMMRegister(rm));
1448 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001449 } else if (*data == 0xEB) {
1450 data++;
1451 int mod, regop, rm;
1452 get_modrm(*data, &mod, &regop, &rm);
1453 AppendToBuffer("por %s,%s",
1454 NameOfXMMRegister(regop),
1455 NameOfXMMRegister(rm));
1456 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001457 } else {
1458 UnimplementedInstruction();
1459 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001460 } else {
1461 UnimplementedInstruction();
1462 }
1463 break;
1464
1465 case 0xFE:
1466 { data++;
1467 int mod, regop, rm;
1468 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001469 if (regop == ecx) {
1470 AppendToBuffer("dec_b ");
1471 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001472 } else {
1473 UnimplementedInstruction();
1474 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 }
1476 break;
1477
1478 case 0x68:
1479 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1480 data += 5;
1481 break;
1482
1483 case 0x6A:
1484 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1485 data += 2;
1486 break;
1487
1488 case 0xA8:
1489 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1490 data += 2;
1491 break;
1492
1493 case 0xA9:
1494 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1495 data += 5;
1496 break;
1497
1498 case 0xD1: // fall through
1499 case 0xD3: // fall through
1500 case 0xC1:
1501 data += D1D3C1Instruction(data);
1502 break;
1503
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504 case 0xD8: // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001505 case 0xD9: // fall through
1506 case 0xDA: // fall through
1507 case 0xDB: // fall through
1508 case 0xDC: // fall through
1509 case 0xDD: // fall through
1510 case 0xDE: // fall through
1511 case 0xDF:
1512 data += FPUInstruction(data);
1513 break;
1514
1515 case 0xEB:
1516 data += JumpShort(data);
1517 break;
1518
1519 case 0xF2:
1520 if (*(data+1) == 0x0F) {
1521 byte b2 = *(data+2);
1522 if (b2 == 0x11) {
1523 AppendToBuffer("movsd ");
1524 data += 3;
1525 int mod, regop, rm;
1526 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001527 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001528 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1529 } else if (b2 == 0x10) {
1530 data += 3;
1531 int mod, regop, rm;
1532 get_modrm(*data, &mod, &regop, &rm);
1533 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001534 data += PrintRightXMMOperand(data);
1535 } else if (b2 == 0x5A) {
1536 data += 3;
1537 int mod, regop, rm;
1538 get_modrm(*data, &mod, &regop, &rm);
1539 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1540 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001541 } else {
1542 const char* mnem = "?";
1543 switch (b2) {
1544 case 0x2A: mnem = "cvtsi2sd"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001545 case 0x2C: mnem = "cvttsd2si"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001546 case 0x2D: mnem = "cvtsd2si"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001547 case 0x51: mnem = "sqrtsd"; break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 case 0x58: mnem = "addsd"; break;
1549 case 0x59: mnem = "mulsd"; break;
1550 case 0x5C: mnem = "subsd"; break;
1551 case 0x5E: mnem = "divsd"; break;
1552 }
1553 data += 3;
1554 int mod, regop, rm;
1555 get_modrm(*data, &mod, &regop, &rm);
1556 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01001557 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1558 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001559 } else if (b2 == 0x2C || b2 == 0x2D) {
Steve Block44f0eee2011-05-26 01:26:41 +01001560 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1561 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001562 } else if (b2 == 0xC2) {
1563 // Intel manual 2A, Table 3-18.
1564 const char* const pseudo_op[] = {
1565 "cmpeqsd",
1566 "cmpltsd",
1567 "cmplesd",
1568 "cmpunordsd",
1569 "cmpneqsd",
1570 "cmpnltsd",
1571 "cmpnlesd",
1572 "cmpordsd"
1573 };
1574 AppendToBuffer("%s %s,%s",
1575 pseudo_op[data[1]],
1576 NameOfXMMRegister(regop),
1577 NameOfXMMRegister(rm));
1578 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001579 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001580 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1581 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001582 }
1583 }
1584 } else {
1585 UnimplementedInstruction();
1586 }
1587 break;
1588
1589 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00001590 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01001591 byte b2 = *(data+2);
1592 if (b2 == 0x11) {
1593 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01001594 data += 3;
1595 int mod, regop, rm;
1596 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001597 data += PrintRightXMMOperand(data);
1598 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1599 } else if (b2 == 0x10) {
1600 data += 3;
1601 int mod, regop, rm;
1602 get_modrm(*data, &mod, &regop, &rm);
1603 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1604 data += PrintRightXMMOperand(data);
1605 } else if (b2 == 0x2C) {
1606 data += 3;
1607 int mod, regop, rm;
1608 get_modrm(*data, &mod, &regop, &rm);
1609 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1610 data += PrintRightXMMOperand(data);
1611 } else if (b2 == 0x5A) {
1612 data += 3;
1613 int mod, regop, rm;
1614 get_modrm(*data, &mod, &regop, &rm);
1615 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1616 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001617 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001618 data += 3;
1619 int mod, regop, rm;
1620 get_modrm(*data, &mod, &regop, &rm);
1621 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001622 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001623 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001624 AppendToBuffer("movdqu ");
1625 data += 3;
1626 int mod, regop, rm;
1627 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001628 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001629 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1630 } else {
1631 UnimplementedInstruction();
1632 }
1633 } else if (*(data+1) == 0xA5) {
1634 data += 2;
1635 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01001636 } else if (*(data+1) == 0xAB) {
1637 data += 2;
1638 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00001639 } else {
1640 UnimplementedInstruction();
1641 }
1642 break;
1643
1644 case 0xF7:
1645 data += F7Instruction(data);
1646 break;
1647
1648 default:
1649 UnimplementedInstruction();
1650 }
1651 }
1652
1653 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1654 tmp_buffer_[tmp_buffer_pos_] = '\0';
1655 }
1656
1657 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00001658 if (instr_len == 0) {
1659 printf("%02x", *data);
1660 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001661 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00001662
1663 int outp = 0;
1664 // Instruction bytes.
1665 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666 outp += v8::internal::SNPrintF(out_buffer + outp,
1667 "%02x",
1668 *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 }
1670 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00001672 }
1673
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001674 outp += v8::internal::SNPrintF(out_buffer + outp,
1675 " %s",
1676 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00001677 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001678} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00001679
1680
1681//------------------------------------------------------------------------------
1682
1683
1684static const char* cpu_regs[8] = {
1685 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1686};
1687
1688
1689static const char* byte_cpu_regs[8] = {
1690 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1691};
1692
1693
1694static const char* xmm_regs[8] = {
1695 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1696};
1697
1698
1699const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001700 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001701 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00001702}
1703
1704
1705const char* NameConverter::NameOfConstant(byte* addr) const {
1706 return NameOfAddress(addr);
1707}
1708
1709
1710const char* NameConverter::NameOfCPURegister(int reg) const {
1711 if (0 <= reg && reg < 8) return cpu_regs[reg];
1712 return "noreg";
1713}
1714
1715
1716const char* NameConverter::NameOfByteCPURegister(int reg) const {
1717 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1718 return "noreg";
1719}
1720
1721
1722const char* NameConverter::NameOfXMMRegister(int reg) const {
1723 if (0 <= reg && reg < 8) return xmm_regs[reg];
1724 return "noxmmreg";
1725}
1726
1727
1728const char* NameConverter::NameInCode(byte* addr) const {
1729 // IA32 does not embed debug strings at the moment.
1730 UNREACHABLE();
1731 return "";
1732}
1733
1734
1735//------------------------------------------------------------------------------
1736
1737Disassembler::Disassembler(const NameConverter& converter)
1738 : converter_(converter) {}
1739
1740
1741Disassembler::~Disassembler() {}
1742
1743
1744int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1745 byte* instruction) {
1746 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1747 return d.InstructionDecode(buffer, instruction);
1748}
1749
1750
1751// The IA-32 assembler does not currently use constant pools.
1752int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1753
1754
1755/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1756 NameConverter converter;
1757 Disassembler d(converter);
1758 for (byte* pc = begin; pc < end;) {
1759 v8::internal::EmbeddedVector<char, 128> buffer;
1760 buffer[0] = '\0';
1761 byte* prev_pc = pc;
1762 pc += d.InstructionDecode(buffer, pc);
1763 fprintf(f, "%p", prev_pc);
1764 fprintf(f, " ");
1765
1766 for (byte* bp = prev_pc; bp < pc; bp++) {
1767 fprintf(f, "%02x", *bp);
1768 }
1769 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1770 fprintf(f, " ");
1771 }
1772 fprintf(f, " %s\n", buffer.start());
1773 }
1774}
1775
1776
1777} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01001778
1779#endif // V8_TARGET_ARCH_IA32