blob: bf88f69c96a87735f2f3569919402620bd5cd37c [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),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400249 vex_byte0_(0),
250 vex_byte1_(0),
251 vex_byte2_(0),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100252 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000253 tmp_buffer_pos_(0),
254 abort_on_unimplemented_(abort_on_unimplemented) {
255 tmp_buffer_[0] = '\0';
256 }
257
258 virtual ~DisassemblerIA32() {}
259
260 // Writes one disassembled instruction into 'buffer' (0-terminated).
261 // Returns the length of the disassembled machine instruction in bytes.
262 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
263
264 private:
265 const NameConverter& converter_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400266 byte vex_byte0_; // 0xc4 or 0xc5
267 byte vex_byte1_;
268 byte vex_byte2_; // only for 3 bytes vex prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100269 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000270 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
271 unsigned int tmp_buffer_pos_;
272 bool abort_on_unimplemented_;
273
Steve Blocka7e24c12009-10-30 11:49:00 +0000274 enum {
275 eax = 0,
276 ecx = 1,
277 edx = 2,
278 ebx = 3,
279 esp = 4,
280 ebp = 5,
281 esi = 6,
282 edi = 7
283 };
284
285
Steve Blockd0582a62009-12-15 09:54:21 +0000286 enum ShiftOpcodeExtension {
287 kROL = 0,
288 kROR = 1,
289 kRCL = 2,
290 kRCR = 3,
291 kSHL = 4,
292 KSHR = 5,
293 kSAR = 7
294 };
295
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400296 bool vex_128() {
297 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
298 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
299 return (checked & 4) != 1;
300 }
301
302 bool vex_66() {
303 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
304 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
305 return (checked & 3) == 1;
306 }
307
308 bool vex_f3() {
309 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
310 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
311 return (checked & 3) == 2;
312 }
313
314 bool vex_f2() {
315 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
316 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
317 return (checked & 3) == 3;
318 }
319
320 bool vex_w() {
321 if (vex_byte0_ == 0xc5) return false;
322 return (vex_byte2_ & 0x80) != 0;
323 }
324
325 bool vex_0f() {
326 if (vex_byte0_ == 0xc5) return true;
327 return (vex_byte1_ & 3) == 1;
328 }
329
330 bool vex_0f38() {
331 if (vex_byte0_ == 0xc5) return false;
332 return (vex_byte1_ & 3) == 2;
333 }
334
335 bool vex_0f3a() {
336 if (vex_byte0_ == 0xc5) return false;
337 return (vex_byte1_ & 3) == 3;
338 }
339
340 int vex_vreg() {
341 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5);
342 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_;
343 return ~(checked >> 3) & 0xf;
344 }
345
346 char float_size_code() { return "sd"[vex_w()]; }
Steve Blockd0582a62009-12-15 09:54:21 +0000347
Steve Blocka7e24c12009-10-30 11:49:00 +0000348 const char* NameOfCPURegister(int reg) const {
349 return converter_.NameOfCPURegister(reg);
350 }
351
352
353 const char* NameOfByteCPURegister(int reg) const {
354 return converter_.NameOfByteCPURegister(reg);
355 }
356
357
358 const char* NameOfXMMRegister(int reg) const {
359 return converter_.NameOfXMMRegister(reg);
360 }
361
362
363 const char* NameOfAddress(byte* addr) const {
364 return converter_.NameOfAddress(addr);
365 }
366
367
368 // Disassembler helper functions.
369 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
370 *mod = (data >> 6) & 3;
371 *regop = (data & 0x38) >> 3;
372 *rm = data & 7;
373 }
374
375
376 static void get_sib(byte data, int* scale, int* index, int* base) {
377 *scale = (data >> 6) & 3;
378 *index = (data >> 3) & 7;
379 *base = data & 7;
380 }
381
382 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
383
384 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
385 int PrintRightOperand(byte* modrmp);
386 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100387 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
389 int PrintImmediateOp(byte* data);
390 int F7Instruction(byte* data);
391 int D1D3C1Instruction(byte* data);
392 int JumpShort(byte* data);
393 int JumpConditional(byte* data, const char* comment);
394 int JumpConditionalShort(byte* data, const char* comment);
395 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000396 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000397 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000398 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
399 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400400 int AVXInstruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 void AppendToBuffer(const char* format, ...);
402
403
404 void UnimplementedInstruction() {
405 if (abort_on_unimplemented_) {
406 UNIMPLEMENTED();
407 } else {
408 AppendToBuffer("'Unimplemented Instruction'");
409 }
410 }
411};
412
413
414void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
415 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
416 va_list args;
417 va_start(args, format);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 int result = v8::internal::VSNPrintF(buf, format, args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 va_end(args);
420 tmp_buffer_pos_ += result;
421}
422
423int DisassemblerIA32::PrintRightOperandHelper(
424 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100425 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 int mod, regop, rm;
427 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100428 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
429 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000430 switch (mod) {
431 case 0:
432 if (rm == ebp) {
433 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
434 AppendToBuffer("[0x%x]", disp);
435 return 5;
436 } else if (rm == esp) {
437 byte sib = *(modrmp + 1);
438 int scale, index, base;
439 get_sib(sib, &scale, &index, &base);
440 if (index == esp && base == esp && scale == 0 /*times_1*/) {
441 AppendToBuffer("[%s]", (this->*register_name)(rm));
442 return 2;
443 } else if (base == ebp) {
444 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000445 AppendToBuffer("[%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 (this->*register_name)(index),
447 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 disp < 0 ? "-" : "+",
449 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000450 return 6;
451 } else if (index != esp && base != ebp) {
452 // [base+index*scale]
453 AppendToBuffer("[%s+%s*%d]",
454 (this->*register_name)(base),
455 (this->*register_name)(index),
456 1 << scale);
457 return 2;
458 } else {
459 UnimplementedInstruction();
460 return 1;
461 }
462 } else {
463 AppendToBuffer("[%s]", (this->*register_name)(rm));
464 return 1;
465 }
466 break;
467 case 1: // fall through
468 case 2:
469 if (rm == esp) {
470 byte sib = *(modrmp + 1);
471 int scale, index, base;
472 get_sib(sib, &scale, &index, &base);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
474 : *reinterpret_cast<int8_t*>(modrmp + 2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 AppendToBuffer("[%s%s0x%x]",
477 (this->*register_name)(rm),
478 disp < 0 ? "-" : "+",
479 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 AppendToBuffer("[%s+%s*%d%s0x%x]",
Steve Blocka7e24c12009-10-30 11:49:00 +0000482 (this->*register_name)(base),
483 (this->*register_name)(index),
484 1 << scale,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000485 disp < 0 ? "-" : "+",
486 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000487 }
488 return mod == 2 ? 6 : 3;
489 } else {
490 // No sib.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000491 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
492 : *reinterpret_cast<int8_t*>(modrmp + 1);
493 AppendToBuffer("[%s%s0x%x]",
494 (this->*register_name)(rm),
495 disp < 0 ? "-" : "+",
496 disp < 0 ? -disp : disp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000497 return mod == 2 ? 5 : 2;
498 }
499 break;
500 case 3:
501 AppendToBuffer("%s", (this->*register_name)(rm));
502 return 1;
503 default:
504 UnimplementedInstruction();
505 return 1;
506 }
507 UNREACHABLE();
508}
509
510
511int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
512 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
513}
514
515
516int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
517 return PrintRightOperandHelper(modrmp,
518 &DisassemblerIA32::NameOfByteCPURegister);
519}
520
521
Steve Block44f0eee2011-05-26 01:26:41 +0100522int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
523 return PrintRightOperandHelper(modrmp,
524 &DisassemblerIA32::NameOfXMMRegister);
525}
526
527
Steve Blocka7e24c12009-10-30 11:49:00 +0000528// Returns number of bytes used including the current *data.
529// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
530int DisassemblerIA32::PrintOperands(const char* mnem,
531 OperandOrder op_order,
532 byte* data) {
533 byte modrm = *data;
534 int mod, regop, rm;
535 get_modrm(modrm, &mod, &regop, &rm);
536 int advance = 0;
537 switch (op_order) {
538 case REG_OPER_OP_ORDER: {
539 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
540 advance = PrintRightOperand(data);
541 break;
542 }
543 case OPER_REG_OP_ORDER: {
544 AppendToBuffer("%s ", mnem);
545 advance = PrintRightOperand(data);
546 AppendToBuffer(",%s", NameOfCPURegister(regop));
547 break;
548 }
549 default:
550 UNREACHABLE();
551 break;
552 }
553 return advance;
554}
555
556
557// Returns number of bytes used by machine instruction, including *data byte.
558// Writes immediate instructions to 'tmp_buffer_'.
559int DisassemblerIA32::PrintImmediateOp(byte* data) {
560 bool sign_extension_bit = (*data & 0x02) != 0;
561 byte modrm = *(data+1);
562 int mod, regop, rm;
563 get_modrm(modrm, &mod, &regop, &rm);
564 const char* mnem = "Imm???";
565 switch (regop) {
566 case 0: mnem = "add"; break;
567 case 1: mnem = "or"; break;
568 case 2: mnem = "adc"; break;
569 case 4: mnem = "and"; break;
570 case 5: mnem = "sub"; break;
571 case 6: mnem = "xor"; break;
572 case 7: mnem = "cmp"; break;
573 default: UnimplementedInstruction();
574 }
575 AppendToBuffer("%s ", mnem);
576 int count = PrintRightOperand(data+1);
577 if (sign_extension_bit) {
578 AppendToBuffer(",0x%x", *(data + 1 + count));
579 return 1 + count + 1 /*int8*/;
580 } else {
581 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
582 return 1 + count + 4 /*int32_t*/;
583 }
584}
585
586
587// Returns number of bytes used, including *data.
588int DisassemblerIA32::F7Instruction(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000589 DCHECK_EQ(0xF7, *data);
590 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 int mod, regop, rm;
592 get_modrm(modrm, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000593 const char* mnem = NULL;
594 switch (regop) {
595 case 0:
596 mnem = "test";
597 break;
598 case 2:
599 mnem = "not";
600 break;
601 case 3:
602 mnem = "neg";
603 break;
604 case 4:
605 mnem = "mul";
606 break;
607 case 5:
608 mnem = "imul";
609 break;
610 case 6:
611 mnem = "div";
612 break;
613 case 7:
614 mnem = "idiv";
615 break;
616 default:
617 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000618 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 AppendToBuffer("%s ", mnem);
620 int count = PrintRightOperand(data);
621 if (regop == 0) {
622 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
623 count += 4;
624 }
625 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000626}
627
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000628
Steve Blocka7e24c12009-10-30 11:49:00 +0000629int DisassemblerIA32::D1D3C1Instruction(byte* data) {
630 byte op = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000631 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
632 byte modrm = *++data;
Steve Blocka7e24c12009-10-30 11:49:00 +0000633 int mod, regop, rm;
634 get_modrm(modrm, &mod, &regop, &rm);
635 int imm8 = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000636 const char* mnem = NULL;
637 switch (regop) {
638 case kROL:
639 mnem = "rol";
640 break;
641 case kROR:
642 mnem = "ror";
643 break;
644 case kRCL:
645 mnem = "rcl";
646 break;
647 case kRCR:
648 mnem = "rcr";
649 break;
650 case kSHL:
651 mnem = "shl";
652 break;
653 case KSHR:
654 mnem = "shr";
655 break;
656 case kSAR:
657 mnem = "sar";
658 break;
659 default:
660 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +0000661 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662 AppendToBuffer("%s ", mnem);
663 int count = PrintRightOperand(data);
664 if (op == 0xD1) {
665 imm8 = 1;
666 } else if (op == 0xC1) {
667 imm8 = *(data + 1);
668 count++;
669 } else if (op == 0xD3) {
670 // Shift/rotate by cl.
671 }
672 if (imm8 >= 0) {
673 AppendToBuffer(",%d", imm8);
674 } else {
675 AppendToBuffer(",cl");
676 }
677 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000678}
679
680
681// Returns number of bytes used, including *data.
682int DisassemblerIA32::JumpShort(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000683 DCHECK_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 byte b = *(data+1);
685 byte* dest = data + static_cast<int8_t>(b) + 2;
686 AppendToBuffer("jmp %s", NameOfAddress(dest));
687 return 2;
688}
689
690
691// Returns number of bytes used, including *data.
692int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000693 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000694 byte cond = *(data+1) & 0x0F;
695 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
696 const char* mnem = jump_conditional_mnem[cond];
697 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
698 if (comment != NULL) {
699 AppendToBuffer(", %s", comment);
700 }
701 return 6; // includes 0x0F
702}
703
704
705// Returns number of bytes used, including *data.
706int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
707 byte cond = *data & 0x0F;
708 byte b = *(data+1);
709 byte* dest = data + static_cast<int8_t>(b) + 2;
710 const char* mnem = jump_conditional_mnem[cond];
711 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
712 if (comment != NULL) {
713 AppendToBuffer(", %s", comment);
714 }
715 return 2;
716}
717
718
719// Returns number of bytes used, including *data.
720int DisassemblerIA32::SetCC(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 DCHECK_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 byte cond = *(data+1) & 0x0F;
723 const char* mnem = set_conditional_mnem[cond];
724 AppendToBuffer("%s ", mnem);
725 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000726 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000727}
728
729
730// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000731int DisassemblerIA32::CMov(byte* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732 DCHECK_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000733 byte cond = *(data + 1) & 0x0F;
734 const char* mnem = conditional_move_mnem[cond];
735 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
736 return 2 + op_size; // includes 0x0F
737}
738
739
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400740int DisassemblerIA32::AVXInstruction(byte* data) {
741 byte opcode = *data;
742 byte* current = data + 1;
743 if (vex_66() && vex_0f38()) {
744 int mod, regop, rm, vvvv = vex_vreg();
745 get_modrm(*current, &mod, &regop, &rm);
746 switch (opcode) {
747 case 0x99:
748 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
749 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
750 current += PrintRightXMMOperand(current);
751 break;
752 case 0xa9:
753 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
754 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
755 current += PrintRightXMMOperand(current);
756 break;
757 case 0xb9:
758 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
759 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
760 current += PrintRightXMMOperand(current);
761 break;
762 case 0x9b:
763 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
764 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
765 current += PrintRightXMMOperand(current);
766 break;
767 case 0xab:
768 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
769 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
770 current += PrintRightXMMOperand(current);
771 break;
772 case 0xbb:
773 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
774 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
775 current += PrintRightXMMOperand(current);
776 break;
777 case 0x9d:
778 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
779 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
780 current += PrintRightXMMOperand(current);
781 break;
782 case 0xad:
783 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
784 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
785 current += PrintRightXMMOperand(current);
786 break;
787 case 0xbd:
788 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
789 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
790 current += PrintRightXMMOperand(current);
791 break;
792 case 0x9f:
793 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
794 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
795 current += PrintRightXMMOperand(current);
796 break;
797 case 0xaf:
798 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
799 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
800 current += PrintRightXMMOperand(current);
801 break;
802 case 0xbf:
803 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
804 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
805 current += PrintRightXMMOperand(current);
806 break;
807 default:
808 UnimplementedInstruction();
809 }
810 } else if (vex_f2() && vex_0f()) {
811 int mod, regop, rm, vvvv = vex_vreg();
812 get_modrm(*current, &mod, &regop, &rm);
813 switch (opcode) {
814 case 0x58:
815 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
816 NameOfXMMRegister(vvvv));
817 current += PrintRightXMMOperand(current);
818 break;
819 case 0x59:
820 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
821 NameOfXMMRegister(vvvv));
822 current += PrintRightXMMOperand(current);
823 break;
824 case 0x5c:
825 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
826 NameOfXMMRegister(vvvv));
827 current += PrintRightXMMOperand(current);
828 break;
829 case 0x5e:
830 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
831 NameOfXMMRegister(vvvv));
832 current += PrintRightXMMOperand(current);
833 break;
834 default:
835 UnimplementedInstruction();
836 }
837 } else {
838 UnimplementedInstruction();
839 }
840
841 return static_cast<int>(current - data);
842}
843
844
Steve Block3ce2e202009-11-05 08:53:23 +0000845// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000846int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000847 byte escape_opcode = *data;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000848 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
Steve Blockd0582a62009-12-15 09:54:21 +0000849 byte modrm_byte = *(data+1);
850
851 if (modrm_byte >= 0xC0) {
852 return RegisterFPUInstruction(escape_opcode, modrm_byte);
853 } else {
854 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000855 }
Steve Blockd0582a62009-12-15 09:54:21 +0000856}
857
858int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
859 int modrm_byte,
860 byte* modrm_start) {
861 const char* mnem = "?";
862 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
863 switch (escape_opcode) {
864 case 0xD9: switch (regop) {
865 case 0: mnem = "fld_s"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000866 case 2: mnem = "fst_s"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000867 case 3: mnem = "fstp_s"; break;
868 case 7: mnem = "fstcw"; break;
869 default: UnimplementedInstruction();
870 }
871 break;
872
873 case 0xDB: switch (regop) {
874 case 0: mnem = "fild_s"; break;
875 case 1: mnem = "fisttp_s"; break;
876 case 2: mnem = "fist_s"; break;
877 case 3: mnem = "fistp_s"; break;
878 default: UnimplementedInstruction();
879 }
880 break;
881
882 case 0xDD: switch (regop) {
883 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100884 case 1: mnem = "fisttp_d"; break;
885 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000886 case 3: mnem = "fstp_d"; break;
887 default: UnimplementedInstruction();
888 }
889 break;
890
891 case 0xDF: switch (regop) {
892 case 5: mnem = "fild_d"; break;
893 case 7: mnem = "fistp_d"; break;
894 default: UnimplementedInstruction();
895 }
896 break;
897
898 default: UnimplementedInstruction();
899 }
900 AppendToBuffer("%s ", mnem);
901 int count = PrintRightOperand(modrm_start);
902 return count + 1;
903}
904
905int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
906 byte modrm_byte) {
907 bool has_register = false; // Is the FPU register encoded in modrm_byte?
908 const char* mnem = "?";
909
910 switch (escape_opcode) {
911 case 0xD8:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912 has_register = true;
913 switch (modrm_byte & 0xF8) {
914 case 0xC0: mnem = "fadd_i"; break;
915 case 0xE0: mnem = "fsub_i"; break;
916 case 0xC8: mnem = "fmul_i"; break;
917 case 0xF0: mnem = "fdiv_i"; break;
918 default: UnimplementedInstruction();
919 }
Steve Blockd0582a62009-12-15 09:54:21 +0000920 break;
921
922 case 0xD9:
923 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100924 case 0xC0:
925 mnem = "fld";
926 has_register = true;
927 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000928 case 0xC8:
929 mnem = "fxch";
930 has_register = true;
931 break;
932 default:
933 switch (modrm_byte) {
934 case 0xE0: mnem = "fchs"; break;
935 case 0xE1: mnem = "fabs"; break;
936 case 0xE4: mnem = "ftst"; break;
937 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000938 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100939 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000940 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100941 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100942 case 0xF1: mnem = "fyl2x"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943 case 0xF4: mnem = "fxtract"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000944 case 0xF5: mnem = "fprem1"; break;
945 case 0xF7: mnem = "fincstp"; break;
946 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100947 case 0xFC: mnem = "frndint"; break;
948 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000949 case 0xFE: mnem = "fsin"; break;
950 case 0xFF: mnem = "fcos"; break;
951 default: UnimplementedInstruction();
952 }
953 }
954 break;
955
956 case 0xDA:
957 if (modrm_byte == 0xE9) {
958 mnem = "fucompp";
959 } else {
960 UnimplementedInstruction();
961 }
962 break;
963
964 case 0xDB:
965 if ((modrm_byte & 0xF8) == 0xE8) {
966 mnem = "fucomi";
967 has_register = true;
968 } else if (modrm_byte == 0xE2) {
969 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100970 } else if (modrm_byte == 0xE3) {
971 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +0000972 } else {
973 UnimplementedInstruction();
974 }
975 break;
976
977 case 0xDC:
978 has_register = true;
979 switch (modrm_byte & 0xF8) {
980 case 0xC0: mnem = "fadd"; break;
981 case 0xE8: mnem = "fsub"; break;
982 case 0xC8: mnem = "fmul"; break;
983 case 0xF8: mnem = "fdiv"; break;
984 default: UnimplementedInstruction();
985 }
986 break;
987
988 case 0xDD:
989 has_register = true;
990 switch (modrm_byte & 0xF8) {
991 case 0xC0: mnem = "ffree"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 case 0xD0: mnem = "fst"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000993 case 0xD8: mnem = "fstp"; break;
994 default: UnimplementedInstruction();
995 }
996 break;
997
998 case 0xDE:
999 if (modrm_byte == 0xD9) {
1000 mnem = "fcompp";
1001 } else {
1002 has_register = true;
1003 switch (modrm_byte & 0xF8) {
1004 case 0xC0: mnem = "faddp"; break;
1005 case 0xE8: mnem = "fsubp"; break;
1006 case 0xC8: mnem = "fmulp"; break;
1007 case 0xF8: mnem = "fdivp"; break;
1008 default: UnimplementedInstruction();
1009 }
1010 }
1011 break;
1012
1013 case 0xDF:
1014 if (modrm_byte == 0xE0) {
1015 mnem = "fnstsw_ax";
1016 } else if ((modrm_byte & 0xF8) == 0xE8) {
1017 mnem = "fucomip";
1018 has_register = true;
1019 }
1020 break;
1021
1022 default: UnimplementedInstruction();
1023 }
1024
1025 if (has_register) {
1026 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1027 } else {
1028 AppendToBuffer("%s", mnem);
1029 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001030 return 2;
1031}
1032
1033
1034// Mnemonics for instructions 0xF0 byte.
1035// Returns NULL if the instruction is not handled here.
1036static const char* F0Mnem(byte f0byte) {
1037 switch (f0byte) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001038 case 0x18: return "prefetch";
Steve Blocka7e24c12009-10-30 11:49:00 +00001039 case 0xA2: return "cpuid";
Steve Blocka7e24c12009-10-30 11:49:00 +00001040 case 0xBE: return "movsx_b";
1041 case 0xBF: return "movsx_w";
1042 case 0xB6: return "movzx_b";
1043 case 0xB7: return "movzx_w";
1044 case 0xAF: return "imul";
1045 case 0xA5: return "shld";
1046 case 0xAD: return "shrd";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001047 case 0xAC: return "shrd"; // 3-operand version.
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 case 0xAB: return "bts";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001049 case 0xBD: return "bsr";
Steve Blocka7e24c12009-10-30 11:49:00 +00001050 default: return NULL;
1051 }
1052}
1053
1054
1055// Disassembled instruction '*instr' and writes it into 'out_buffer'.
1056int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1057 byte* instr) {
1058 tmp_buffer_pos_ = 0; // starting to write as position 0
1059 byte* data = instr;
1060 // Check for hints.
1061 const char* branch_hint = NULL;
1062 // We use these two prefixes only with branch prediction
1063 if (*data == 0x3E /*ds*/) {
1064 branch_hint = "predicted taken";
1065 data++;
1066 } else if (*data == 0x2E /*cs*/) {
1067 branch_hint = "predicted not taken";
1068 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001069 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) {
1070 vex_byte0_ = *data;
1071 vex_byte1_ = *(data + 1);
1072 vex_byte2_ = *(data + 2);
1073 data += 3;
1074 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) {
1075 vex_byte0_ = *data;
1076 vex_byte1_ = *(data + 1);
1077 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001078 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001079
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 bool processed = true; // Will be set to false if the current instruction
1081 // is not in 'instructions' table.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001082 // Decode AVX instructions.
1083 if (vex_byte0_ != 0) {
1084 data += AVXInstruction(data);
1085 } else {
1086 const InstructionDesc& idesc = instruction_table_->Get(*data);
1087 switch (idesc.type) {
1088 case ZERO_OPERANDS_INSTR:
1089 AppendToBuffer(idesc.mnem);
1090 data++;
1091 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001092
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001093 case TWO_OPERANDS_INSTR:
1094 data++;
1095 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1096 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001097
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001098 case JUMP_CONDITIONAL_SHORT_INSTR:
1099 data += JumpConditionalShort(data, branch_hint);
1100 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001101
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001102 case REGISTER_INSTR:
1103 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1104 data++;
1105 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001106
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001107 case MOVE_REG_INSTR: {
1108 byte* addr =
1109 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1110 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1111 NameOfAddress(addr));
1112 data += 5;
1113 break;
1114 }
1115
1116 case CALL_JUMP_INSTR: {
1117 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1118 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1119 data += 5;
1120 break;
1121 }
1122
1123 case SHORT_IMMEDIATE_INSTR: {
1124 byte* addr =
1125 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1126 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1127 data += 5;
1128 break;
1129 }
1130
1131 case BYTE_IMMEDIATE_INSTR: {
1132 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1133 data += 2;
1134 break;
1135 }
1136
1137 case NO_INSTR:
1138 processed = false;
1139 break;
1140
1141 default:
1142 UNIMPLEMENTED(); // This type is not implemented.
Steve Blocka7e24c12009-10-30 11:49:00 +00001143 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001144 }
1145 //----------------------------
1146 if (!processed) {
1147 switch (*data) {
1148 case 0xC2:
1149 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
1150 data += 3;
1151 break;
1152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001153 case 0x6B: {
1154 data++;
1155 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1156 AppendToBuffer(",%d", *data);
1157 data++;
1158 } break;
1159
1160 case 0x69: {
1161 data++;
1162 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1163 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1164 data += 4;
Steve Blocka7e24c12009-10-30 11:49:00 +00001165 }
1166 break;
1167
1168 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001169 { data++;
1170 int mod, regop, rm;
1171 get_modrm(*data, &mod, &regop, &rm);
1172 if (regop == eax) {
1173 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +01001174 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001175 int32_t imm = *data;
1176 AppendToBuffer(",0x%x", imm);
1177 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 } else {
1179 UnimplementedInstruction();
1180 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001181 }
1182 break;
1183
1184 case 0x81: // fall through
1185 case 0x83: // 0x81 with sign extension bit set
1186 data += PrintImmediateOp(data);
1187 break;
1188
1189 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001190 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +00001191 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001192 if (f0byte == 0x18) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001193 data += 2;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001194 int mod, regop, rm;
1195 get_modrm(*data, &mod, &regop, &rm);
1196 const char* suffix[] = {"nta", "1", "2", "3"};
1197 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1198 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001199 } else if (f0byte == 0x1F && data[2] == 0) {
1200 AppendToBuffer("nop"); // 3 byte nop.
1201 data += 3;
1202 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1203 AppendToBuffer("nop"); // 4 byte nop.
1204 data += 4;
1205 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1206 data[4] == 0) {
1207 AppendToBuffer("nop"); // 5 byte nop.
1208 data += 5;
1209 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1210 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1211 AppendToBuffer("nop"); // 7 byte nop.
1212 data += 7;
1213 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1214 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1215 data[7] == 0) {
1216 AppendToBuffer("nop"); // 8 byte nop.
1217 data += 8;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001218 } else if (f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 AppendToBuffer("%s", f0mnem);
1220 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001221 } else if (f0byte == 0x28) {
1222 data += 2;
1223 int mod, regop, rm;
1224 get_modrm(*data, &mod, &regop, &rm);
1225 AppendToBuffer("movaps %s,%s",
1226 NameOfXMMRegister(regop),
1227 NameOfXMMRegister(rm));
1228 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001229 } else if (f0byte == 0x2e) {
1230 data += 2;
1231 int mod, regop, rm;
1232 get_modrm(*data, &mod, &regop, &rm);
1233 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1234 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001235 } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1236 const char* const pseudo_op[] = {
1237 "rcpps",
1238 "andps",
1239 "andnps",
1240 "orps",
1241 "xorps",
1242 "addps",
1243 "mulps",
1244 "cvtps2pd",
1245 "cvtdq2ps",
1246 "subps",
1247 "minps",
1248 "divps",
1249 "maxps",
1250 };
1251
Ben Murdoch257744e2011-11-30 15:57:28 +00001252 data += 2;
1253 int mod, regop, rm;
1254 get_modrm(*data, &mod, &regop, &rm);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 AppendToBuffer("%s %s,",
1256 pseudo_op[f0byte - 0x53],
1257 NameOfXMMRegister(regop));
1258 data += PrintRightXMMOperand(data);
1259 } else if (f0byte == 0x50) {
1260 data += 2;
1261 int mod, regop, rm;
1262 get_modrm(*data, &mod, &regop, &rm);
1263 AppendToBuffer("movmskps %s,%s",
1264 NameOfCPURegister(regop),
Ben Murdoch257744e2011-11-30 15:57:28 +00001265 NameOfXMMRegister(rm));
1266 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001267 } else if (f0byte== 0xC6) {
1268 // shufps xmm, xmm/m128, imm8
1269 data += 2;
1270 int mod, regop, rm;
1271 get_modrm(*data, &mod, &regop, &rm);
1272 int8_t imm8 = static_cast<int8_t>(data[1]);
1273 AppendToBuffer("shufps %s,%s,%d",
1274 NameOfXMMRegister(rm),
1275 NameOfXMMRegister(regop),
1276 static_cast<int>(imm8));
1277 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001278 } else if ((f0byte & 0xF0) == 0x80) {
1279 data += JumpConditional(data, branch_hint);
1280 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1281 f0byte == 0xB7 || f0byte == 0xAF) {
1282 data += 2;
1283 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1284 } else if ((f0byte & 0xF0) == 0x90) {
1285 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001286 } else if ((f0byte & 0xF0) == 0x40) {
1287 data += CMov(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1289 // shrd, shld, bts
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001291 AppendToBuffer("%s ", f0mnem);
1292 int mod, regop, rm;
1293 get_modrm(*data, &mod, &regop, &rm);
1294 data += PrintRightOperand(data);
1295 if (f0byte == 0xAB) {
1296 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001298 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001300 } else if (f0byte == 0xBD) {
1301 data += 2;
1302 int mod, regop, rm;
1303 get_modrm(*data, &mod, &regop, &rm);
1304 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1305 data += PrintRightOperand(data);
1306 } else {
1307 UnimplementedInstruction();
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 }
1309 }
1310 break;
1311
1312 case 0x8F:
1313 { data++;
1314 int mod, regop, rm;
1315 get_modrm(*data, &mod, &regop, &rm);
1316 if (regop == eax) {
1317 AppendToBuffer("pop ");
1318 data += PrintRightOperand(data);
1319 }
1320 }
1321 break;
1322
1323 case 0xFF:
1324 { data++;
1325 int mod, regop, rm;
1326 get_modrm(*data, &mod, &regop, &rm);
1327 const char* mnem = NULL;
1328 switch (regop) {
1329 case esi: mnem = "push"; break;
1330 case eax: mnem = "inc"; break;
1331 case ecx: mnem = "dec"; break;
1332 case edx: mnem = "call"; break;
1333 case esp: mnem = "jmp"; break;
1334 default: mnem = "???";
1335 }
1336 AppendToBuffer("%s ", mnem);
1337 data += PrintRightOperand(data);
1338 }
1339 break;
1340
1341 case 0xC7: // imm32, fall through
1342 case 0xC6: // imm8
1343 { bool is_byte = *data == 0xC6;
1344 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001345 if (is_byte) {
1346 AppendToBuffer("%s ", "mov_b");
1347 data += PrintRightByteOperand(data);
1348 int32_t imm = *data;
1349 AppendToBuffer(",0x%x", imm);
1350 data++;
1351 } else {
1352 AppendToBuffer("%s ", "mov");
1353 data += PrintRightOperand(data);
1354 int32_t imm = *reinterpret_cast<int32_t*>(data);
1355 AppendToBuffer(",0x%x", imm);
1356 data += 4;
1357 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001358 }
1359 break;
1360
1361 case 0x80:
1362 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001363 int mod, regop, rm;
1364 get_modrm(*data, &mod, &regop, &rm);
1365 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001366 switch (regop) {
1367 case 5: mnem = "subb"; break;
1368 case 7: mnem = "cmpb"; break;
1369 default: UnimplementedInstruction();
1370 }
1371 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001372 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001373 int32_t imm = *data;
1374 AppendToBuffer(",0x%x", imm);
1375 data++;
1376 }
1377 break;
1378
1379 case 0x88: // 8bit, fall through
1380 case 0x89: // 32bit
1381 { bool is_byte = *data == 0x88;
1382 int mod, regop, rm;
1383 data++;
1384 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001385 if (is_byte) {
1386 AppendToBuffer("%s ", "mov_b");
1387 data += PrintRightByteOperand(data);
1388 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1389 } else {
1390 AppendToBuffer("%s ", "mov");
1391 data += PrintRightOperand(data);
1392 AppendToBuffer(",%s", NameOfCPURegister(regop));
1393 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001394 }
1395 break;
1396
1397 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001398 while (*data == 0x66) data++;
1399 if (*data == 0xf && data[1] == 0x1f) {
1400 AppendToBuffer("nop"); // 0x66 prefix
1401 } else if (*data == 0x90) {
1402 AppendToBuffer("nop"); // 0x66 prefix
1403 } else if (*data == 0x8B) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 data++;
1405 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1406 } else if (*data == 0x89) {
1407 data++;
1408 int mod, regop, rm;
1409 get_modrm(*data, &mod, &regop, &rm);
1410 AppendToBuffer("mov_w ");
1411 data += PrintRightOperand(data);
1412 AppendToBuffer(",%s", NameOfCPURegister(regop));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413 } else if (*data == 0xC7) {
1414 data++;
1415 AppendToBuffer("%s ", "mov_w");
1416 data += PrintRightOperand(data);
1417 int imm = *reinterpret_cast<int16_t*>(data);
1418 AppendToBuffer(",0x%x", imm);
1419 data += 2;
Steve Block3ce2e202009-11-05 08:53:23 +00001420 } else if (*data == 0x0F) {
1421 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001422 if (*data == 0x38) {
1423 data++;
1424 if (*data == 0x17) {
1425 data++;
1426 int mod, regop, rm;
1427 get_modrm(*data, &mod, &regop, &rm);
1428 AppendToBuffer("ptest %s,%s",
1429 NameOfXMMRegister(regop),
1430 NameOfXMMRegister(rm));
1431 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001432 } else if (*data == 0x2A) {
1433 // movntdqa
1434 data++;
1435 int mod, regop, rm;
1436 get_modrm(*data, &mod, &regop, &rm);
1437 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1438 data += PrintRightOperand(data);
Steve Block6ded16b2010-05-10 14:33:55 +01001439 } else {
1440 UnimplementedInstruction();
1441 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001442 } else if (*data == 0x3A) {
1443 data++;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001444 if (*data == 0x0B) {
1445 data++;
1446 int mod, regop, rm;
1447 get_modrm(*data, &mod, &regop, &rm);
1448 int8_t imm8 = static_cast<int8_t>(data[1]);
1449 AppendToBuffer("roundsd %s,%s,%d",
1450 NameOfXMMRegister(regop),
1451 NameOfXMMRegister(rm),
1452 static_cast<int>(imm8));
1453 data += 2;
1454 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001455 data++;
1456 int mod, regop, rm;
1457 get_modrm(*data, &mod, &regop, &rm);
1458 int8_t imm8 = static_cast<int8_t>(data[1]);
1459 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001460 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001461 NameOfXMMRegister(rm),
1462 static_cast<int>(imm8));
1463 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001464 } else if (*data == 0x17) {
1465 data++;
1466 int mod, regop, rm;
1467 get_modrm(*data, &mod, &regop, &rm);
1468 int8_t imm8 = static_cast<int8_t>(data[1]);
1469 AppendToBuffer("extractps %s,%s,%d",
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470 NameOfCPURegister(rm),
1471 NameOfXMMRegister(regop),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001472 static_cast<int>(imm8));
1473 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001474 } else if (*data == 0x22) {
1475 data++;
1476 int mod, regop, rm;
1477 get_modrm(*data, &mod, &regop, &rm);
1478 int8_t imm8 = static_cast<int8_t>(data[1]);
1479 AppendToBuffer("pinsrd %s,%s,%d",
1480 NameOfXMMRegister(regop),
1481 NameOfCPURegister(rm),
1482 static_cast<int>(imm8));
1483 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001484 } else {
1485 UnimplementedInstruction();
1486 }
Steve Block6ded16b2010-05-10 14:33:55 +01001487 } else if (*data == 0x2E || *data == 0x2F) {
1488 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001489 data++;
1490 int mod, regop, rm;
1491 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001492 if (mod == 0x3) {
1493 AppendToBuffer("%s %s,%s", mnem,
1494 NameOfXMMRegister(regop),
1495 NameOfXMMRegister(rm));
1496 data++;
1497 } else {
1498 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1499 data += PrintRightOperand(data);
1500 }
1501 } else if (*data == 0x50) {
1502 data++;
1503 int mod, regop, rm;
1504 get_modrm(*data, &mod, &regop, &rm);
1505 AppendToBuffer("movmskpd %s,%s",
1506 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001507 NameOfXMMRegister(rm));
1508 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001509 } else if (*data == 0x54) {
1510 data++;
1511 int mod, regop, rm;
1512 get_modrm(*data, &mod, &regop, &rm);
1513 AppendToBuffer("andpd %s,%s",
1514 NameOfXMMRegister(regop),
1515 NameOfXMMRegister(rm));
1516 data++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 } else if (*data == 0x56) {
1518 data++;
1519 int mod, regop, rm;
1520 get_modrm(*data, &mod, &regop, &rm);
1521 AppendToBuffer("orpd %s,%s",
1522 NameOfXMMRegister(regop),
1523 NameOfXMMRegister(rm));
1524 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001525 } else if (*data == 0x57) {
1526 data++;
1527 int mod, regop, rm;
1528 get_modrm(*data, &mod, &regop, &rm);
1529 AppendToBuffer("xorpd %s,%s",
1530 NameOfXMMRegister(regop),
1531 NameOfXMMRegister(rm));
1532 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001533 } else if (*data == 0x6E) {
1534 data++;
1535 int mod, regop, rm;
1536 get_modrm(*data, &mod, &regop, &rm);
1537 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1538 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001539 } else if (*data == 0x6F) {
1540 data++;
1541 int mod, regop, rm;
1542 get_modrm(*data, &mod, &regop, &rm);
1543 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001544 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001545 } else if (*data == 0x70) {
1546 data++;
1547 int mod, regop, rm;
1548 get_modrm(*data, &mod, &regop, &rm);
1549 int8_t imm8 = static_cast<int8_t>(data[1]);
1550 AppendToBuffer("pshufd %s,%s,%d",
1551 NameOfXMMRegister(regop),
1552 NameOfXMMRegister(rm),
1553 static_cast<int>(imm8));
1554 data += 2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555 } else if (*data == 0x76) {
1556 data++;
1557 int mod, regop, rm;
1558 get_modrm(*data, &mod, &regop, &rm);
1559 AppendToBuffer("pcmpeqd %s,%s",
1560 NameOfXMMRegister(regop),
1561 NameOfXMMRegister(rm));
1562 data++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001563 } else if (*data == 0x90) {
1564 data++;
1565 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001566 } else if (*data == 0xF3) {
1567 data++;
1568 int mod, regop, rm;
1569 get_modrm(*data, &mod, &regop, &rm);
1570 AppendToBuffer("psllq %s,%s",
1571 NameOfXMMRegister(regop),
1572 NameOfXMMRegister(rm));
1573 data++;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001574 } else if (*data == 0x72) {
1575 data++;
1576 int mod, regop, rm;
1577 get_modrm(*data, &mod, &regop, &rm);
1578 int8_t imm8 = static_cast<int8_t>(data[1]);
1579 DCHECK(regop == esi || regop == edx);
1580 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld",
1581 NameOfXMMRegister(rm), static_cast<int>(imm8));
1582 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001583 } else if (*data == 0x73) {
1584 data++;
1585 int mod, regop, rm;
1586 get_modrm(*data, &mod, &regop, &rm);
1587 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 DCHECK(regop == esi || regop == edx);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001589 AppendToBuffer("%s %s,%d",
1590 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001591 NameOfXMMRegister(rm),
1592 static_cast<int>(imm8));
1593 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001594 } else if (*data == 0xD3) {
1595 data++;
1596 int mod, regop, rm;
1597 get_modrm(*data, &mod, &regop, &rm);
1598 AppendToBuffer("psrlq %s,%s",
1599 NameOfXMMRegister(regop),
1600 NameOfXMMRegister(rm));
1601 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001602 } else if (*data == 0x7F) {
1603 AppendToBuffer("movdqa ");
1604 data++;
1605 int mod, regop, rm;
1606 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001607 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001608 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001609 } else if (*data == 0x7E) {
1610 data++;
1611 int mod, regop, rm;
1612 get_modrm(*data, &mod, &regop, &rm);
1613 AppendToBuffer("movd ");
1614 data += PrintRightOperand(data);
1615 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1616 } else if (*data == 0xDB) {
1617 data++;
1618 int mod, regop, rm;
1619 get_modrm(*data, &mod, &regop, &rm);
1620 AppendToBuffer("pand %s,%s",
1621 NameOfXMMRegister(regop),
1622 NameOfXMMRegister(rm));
1623 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001624 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001625 data++;
1626 int mod, regop, rm;
1627 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001628 if (mod == 3) {
1629 AppendToBuffer("movntdq ");
1630 data += PrintRightOperand(data);
1631 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1632 } else {
1633 UnimplementedInstruction();
1634 }
Steve Block6ded16b2010-05-10 14:33:55 +01001635 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001636 data++;
1637 int mod, regop, rm;
1638 get_modrm(*data, &mod, &regop, &rm);
1639 AppendToBuffer("pxor %s,%s",
1640 NameOfXMMRegister(regop),
1641 NameOfXMMRegister(rm));
1642 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001643 } else if (*data == 0xEB) {
1644 data++;
1645 int mod, regop, rm;
1646 get_modrm(*data, &mod, &regop, &rm);
1647 AppendToBuffer("por %s,%s",
1648 NameOfXMMRegister(regop),
1649 NameOfXMMRegister(rm));
1650 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001651 } else {
1652 UnimplementedInstruction();
1653 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001654 } else {
1655 UnimplementedInstruction();
1656 }
1657 break;
1658
1659 case 0xFE:
1660 { data++;
1661 int mod, regop, rm;
1662 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001663 if (regop == ecx) {
1664 AppendToBuffer("dec_b ");
1665 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001666 } else {
1667 UnimplementedInstruction();
1668 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 }
1670 break;
1671
1672 case 0x68:
1673 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1674 data += 5;
1675 break;
1676
1677 case 0x6A:
1678 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1679 data += 2;
1680 break;
1681
1682 case 0xA8:
1683 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1684 data += 2;
1685 break;
1686
1687 case 0xA9:
1688 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1689 data += 5;
1690 break;
1691
1692 case 0xD1: // fall through
1693 case 0xD3: // fall through
1694 case 0xC1:
1695 data += D1D3C1Instruction(data);
1696 break;
1697
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001698 case 0xD8: // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 case 0xD9: // fall through
1700 case 0xDA: // fall through
1701 case 0xDB: // fall through
1702 case 0xDC: // fall through
1703 case 0xDD: // fall through
1704 case 0xDE: // fall through
1705 case 0xDF:
1706 data += FPUInstruction(data);
1707 break;
1708
1709 case 0xEB:
1710 data += JumpShort(data);
1711 break;
1712
1713 case 0xF2:
1714 if (*(data+1) == 0x0F) {
1715 byte b2 = *(data+2);
1716 if (b2 == 0x11) {
1717 AppendToBuffer("movsd ");
1718 data += 3;
1719 int mod, regop, rm;
1720 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001721 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001722 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1723 } else if (b2 == 0x10) {
1724 data += 3;
1725 int mod, regop, rm;
1726 get_modrm(*data, &mod, &regop, &rm);
1727 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001728 data += PrintRightXMMOperand(data);
1729 } else if (b2 == 0x5A) {
1730 data += 3;
1731 int mod, regop, rm;
1732 get_modrm(*data, &mod, &regop, &rm);
1733 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1734 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001735 } else {
1736 const char* mnem = "?";
1737 switch (b2) {
1738 case 0x2A: mnem = "cvtsi2sd"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001739 case 0x2C: mnem = "cvttsd2si"; break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001740 case 0x2D: mnem = "cvtsd2si"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001741 case 0x51: mnem = "sqrtsd"; break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 case 0x58: mnem = "addsd"; break;
1743 case 0x59: mnem = "mulsd"; break;
1744 case 0x5C: mnem = "subsd"; break;
1745 case 0x5E: mnem = "divsd"; break;
1746 }
1747 data += 3;
1748 int mod, regop, rm;
1749 get_modrm(*data, &mod, &regop, &rm);
1750 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01001751 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1752 data += PrintRightOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001753 } else if (b2 == 0x2C || b2 == 0x2D) {
Steve Block44f0eee2011-05-26 01:26:41 +01001754 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1755 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001756 } else if (b2 == 0xC2) {
1757 // Intel manual 2A, Table 3-18.
1758 const char* const pseudo_op[] = {
1759 "cmpeqsd",
1760 "cmpltsd",
1761 "cmplesd",
1762 "cmpunordsd",
1763 "cmpneqsd",
1764 "cmpnltsd",
1765 "cmpnlesd",
1766 "cmpordsd"
1767 };
1768 AppendToBuffer("%s %s,%s",
1769 pseudo_op[data[1]],
1770 NameOfXMMRegister(regop),
1771 NameOfXMMRegister(rm));
1772 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001773 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001774 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1775 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001776 }
1777 }
1778 } else {
1779 UnimplementedInstruction();
1780 }
1781 break;
1782
1783 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00001784 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01001785 byte b2 = *(data+2);
1786 if (b2 == 0x11) {
1787 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01001788 data += 3;
1789 int mod, regop, rm;
1790 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001791 data += PrintRightXMMOperand(data);
1792 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1793 } else if (b2 == 0x10) {
1794 data += 3;
1795 int mod, regop, rm;
1796 get_modrm(*data, &mod, &regop, &rm);
1797 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1798 data += PrintRightXMMOperand(data);
1799 } else if (b2 == 0x2C) {
1800 data += 3;
1801 int mod, regop, rm;
1802 get_modrm(*data, &mod, &regop, &rm);
1803 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1804 data += PrintRightXMMOperand(data);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001805 } else if (b2 == 0x58) {
1806 data += 3;
1807 int mod, regop, rm;
1808 get_modrm(*data, &mod, &regop, &rm);
1809 AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
1810 data += PrintRightXMMOperand(data);
1811 } else if (b2 == 0x59) {
1812 data += 3;
1813 int mod, regop, rm;
1814 get_modrm(*data, &mod, &regop, &rm);
1815 AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
1816 data += PrintRightXMMOperand(data);
Steve Block44f0eee2011-05-26 01:26:41 +01001817 } else if (b2 == 0x5A) {
1818 data += 3;
1819 int mod, regop, rm;
1820 get_modrm(*data, &mod, &regop, &rm);
1821 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1822 data += PrintRightXMMOperand(data);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001823 } else if (b2 == 0x5c) {
1824 data += 3;
1825 int mod, regop, rm;
1826 get_modrm(*data, &mod, &regop, &rm);
1827 AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
1828 data += PrintRightXMMOperand(data);
1829 } else if (b2 == 0x5e) {
1830 data += 3;
1831 int mod, regop, rm;
1832 get_modrm(*data, &mod, &regop, &rm);
1833 AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
1834 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001835 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001836 data += 3;
1837 int mod, regop, rm;
1838 get_modrm(*data, &mod, &regop, &rm);
1839 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001840 data += PrintRightXMMOperand(data);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001841 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001842 AppendToBuffer("movdqu ");
1843 data += 3;
1844 int mod, regop, rm;
1845 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001846 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001847 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1848 } else {
1849 UnimplementedInstruction();
1850 }
1851 } else if (*(data+1) == 0xA5) {
1852 data += 2;
1853 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01001854 } else if (*(data+1) == 0xAB) {
1855 data += 2;
1856 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00001857 } else {
1858 UnimplementedInstruction();
1859 }
1860 break;
1861
1862 case 0xF7:
1863 data += F7Instruction(data);
1864 break;
1865
1866 default:
1867 UnimplementedInstruction();
1868 }
1869 }
1870
1871 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1872 tmp_buffer_[tmp_buffer_pos_] = '\0';
1873 }
1874
1875 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00001876 if (instr_len == 0) {
1877 printf("%02x", *data);
1878 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 DCHECK(instr_len > 0); // Ensure progress.
Steve Blocka7e24c12009-10-30 11:49:00 +00001880
1881 int outp = 0;
1882 // Instruction bytes.
1883 for (byte* bp = instr; bp < data; bp++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 outp += v8::internal::SNPrintF(out_buffer + outp,
1885 "%02x",
1886 *bp);
Steve Blocka7e24c12009-10-30 11:49:00 +00001887 }
1888 for (int i = 6 - instr_len; i >= 0; i--) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 outp += v8::internal::SNPrintF(out_buffer + outp, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00001890 }
1891
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892 outp += v8::internal::SNPrintF(out_buffer + outp,
1893 " %s",
1894 tmp_buffer_.start());
Steve Blocka7e24c12009-10-30 11:49:00 +00001895 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001896} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00001897
1898
1899//------------------------------------------------------------------------------
1900
1901
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001902static const char* const cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001903 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1904};
1905
1906
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001907static const char* const byte_cpu_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001908 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1909};
1910
1911
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001912static const char* const xmm_regs[8] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001913 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1914};
1915
1916
1917const char* NameConverter::NameOfAddress(byte* addr) const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
Steve Block44f0eee2011-05-26 01:26:41 +01001919 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00001920}
1921
1922
1923const char* NameConverter::NameOfConstant(byte* addr) const {
1924 return NameOfAddress(addr);
1925}
1926
1927
1928const char* NameConverter::NameOfCPURegister(int reg) const {
1929 if (0 <= reg && reg < 8) return cpu_regs[reg];
1930 return "noreg";
1931}
1932
1933
1934const char* NameConverter::NameOfByteCPURegister(int reg) const {
1935 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1936 return "noreg";
1937}
1938
1939
1940const char* NameConverter::NameOfXMMRegister(int reg) const {
1941 if (0 <= reg && reg < 8) return xmm_regs[reg];
1942 return "noxmmreg";
1943}
1944
1945
1946const char* NameConverter::NameInCode(byte* addr) const {
1947 // IA32 does not embed debug strings at the moment.
1948 UNREACHABLE();
1949 return "";
1950}
1951
1952
1953//------------------------------------------------------------------------------
1954
1955Disassembler::Disassembler(const NameConverter& converter)
1956 : converter_(converter) {}
1957
1958
1959Disassembler::~Disassembler() {}
1960
1961
1962int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1963 byte* instruction) {
1964 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1965 return d.InstructionDecode(buffer, instruction);
1966}
1967
1968
1969// The IA-32 assembler does not currently use constant pools.
1970int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1971
1972
1973/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1974 NameConverter converter;
1975 Disassembler d(converter);
1976 for (byte* pc = begin; pc < end;) {
1977 v8::internal::EmbeddedVector<char, 128> buffer;
1978 buffer[0] = '\0';
1979 byte* prev_pc = pc;
1980 pc += d.InstructionDecode(buffer, pc);
1981 fprintf(f, "%p", prev_pc);
1982 fprintf(f, " ");
1983
1984 for (byte* bp = prev_pc; bp < pc; bp++) {
1985 fprintf(f, "%02x", *bp);
1986 }
1987 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1988 fprintf(f, " ");
1989 }
1990 fprintf(f, " %s\n", buffer.start());
1991 }
1992}
1993
1994
1995} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01001996
1997#endif // V8_TARGET_ARCH_IA32