Line data Source code
1 : // Copyright 2011 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <assert.h>
6 : #include <stdarg.h>
7 : #include <stdio.h>
8 :
9 : #if V8_TARGET_ARCH_X64
10 :
11 : #include "src/base/compiler-specific.h"
12 : #include "src/base/lazy-instance.h"
13 : #include "src/disasm.h"
14 : #include "src/x64/sse-instr.h"
15 :
16 : namespace disasm {
17 :
18 : enum OperandType {
19 : UNSET_OP_ORDER = 0,
20 : // Operand size decides between 16, 32 and 64 bit operands.
21 : REG_OPER_OP_ORDER = 1, // Register destination, operand source.
22 : OPER_REG_OP_ORDER = 2, // Operand destination, register source.
23 : // Fixed 8-bit operands.
24 : BYTE_SIZE_OPERAND_FLAG = 4,
25 : BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
26 : BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
27 : };
28 :
29 :
30 : //------------------------------------------------------------------
31 : // Tables
32 : //------------------------------------------------------------------
33 : struct ByteMnemonic {
34 : int b; // -1 terminates, otherwise must be in range (0..255)
35 : OperandType op_order_;
36 : const char* mnem;
37 : };
38 :
39 :
40 : static const ByteMnemonic two_operands_instr[] = {
41 : { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
42 : { 0x01, OPER_REG_OP_ORDER, "add" },
43 : { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
44 : { 0x03, REG_OPER_OP_ORDER, "add" },
45 : { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
46 : { 0x09, OPER_REG_OP_ORDER, "or" },
47 : { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
48 : { 0x0B, REG_OPER_OP_ORDER, "or" },
49 : { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
50 : { 0x11, OPER_REG_OP_ORDER, "adc" },
51 : { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
52 : { 0x13, REG_OPER_OP_ORDER, "adc" },
53 : { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
54 : { 0x19, OPER_REG_OP_ORDER, "sbb" },
55 : { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
56 : { 0x1B, REG_OPER_OP_ORDER, "sbb" },
57 : { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
58 : { 0x21, OPER_REG_OP_ORDER, "and" },
59 : { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
60 : { 0x23, REG_OPER_OP_ORDER, "and" },
61 : { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
62 : { 0x29, OPER_REG_OP_ORDER, "sub" },
63 : { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
64 : { 0x2B, REG_OPER_OP_ORDER, "sub" },
65 : { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
66 : { 0x31, OPER_REG_OP_ORDER, "xor" },
67 : { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
68 : { 0x33, REG_OPER_OP_ORDER, "xor" },
69 : { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
70 : { 0x39, OPER_REG_OP_ORDER, "cmp" },
71 : { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
72 : { 0x3B, REG_OPER_OP_ORDER, "cmp" },
73 : { 0x63, REG_OPER_OP_ORDER, "movsxl" },
74 : { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
75 : { 0x85, REG_OPER_OP_ORDER, "test" },
76 : { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
77 : { 0x87, REG_OPER_OP_ORDER, "xchg" },
78 : { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
79 : { 0x89, OPER_REG_OP_ORDER, "mov" },
80 : { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
81 : { 0x8B, REG_OPER_OP_ORDER, "mov" },
82 : { 0x8D, REG_OPER_OP_ORDER, "lea" },
83 : { -1, UNSET_OP_ORDER, "" }
84 : };
85 :
86 :
87 : static const ByteMnemonic zero_operands_instr[] = {
88 : { 0xC3, UNSET_OP_ORDER, "ret" },
89 : { 0xC9, UNSET_OP_ORDER, "leave" },
90 : { 0xF4, UNSET_OP_ORDER, "hlt" },
91 : { 0xFC, UNSET_OP_ORDER, "cld" },
92 : { 0xCC, UNSET_OP_ORDER, "int3" },
93 : { 0x60, UNSET_OP_ORDER, "pushad" },
94 : { 0x61, UNSET_OP_ORDER, "popad" },
95 : { 0x9C, UNSET_OP_ORDER, "pushfd" },
96 : { 0x9D, UNSET_OP_ORDER, "popfd" },
97 : { 0x9E, UNSET_OP_ORDER, "sahf" },
98 : { 0x99, UNSET_OP_ORDER, "cdq" },
99 : { 0x9B, UNSET_OP_ORDER, "fwait" },
100 : { 0xA4, UNSET_OP_ORDER, "movs" },
101 : { 0xA5, UNSET_OP_ORDER, "movs" },
102 : { 0xA6, UNSET_OP_ORDER, "cmps" },
103 : { 0xA7, UNSET_OP_ORDER, "cmps" },
104 : { -1, UNSET_OP_ORDER, "" }
105 : };
106 :
107 :
108 : static const ByteMnemonic call_jump_instr[] = {
109 : { 0xE8, UNSET_OP_ORDER, "call" },
110 : { 0xE9, UNSET_OP_ORDER, "jmp" },
111 : { -1, UNSET_OP_ORDER, "" }
112 : };
113 :
114 :
115 : static const ByteMnemonic short_immediate_instr[] = {
116 : { 0x05, UNSET_OP_ORDER, "add" },
117 : { 0x0D, UNSET_OP_ORDER, "or" },
118 : { 0x15, UNSET_OP_ORDER, "adc" },
119 : { 0x1D, UNSET_OP_ORDER, "sbb" },
120 : { 0x25, UNSET_OP_ORDER, "and" },
121 : { 0x2D, UNSET_OP_ORDER, "sub" },
122 : { 0x35, UNSET_OP_ORDER, "xor" },
123 : { 0x3D, UNSET_OP_ORDER, "cmp" },
124 : { -1, UNSET_OP_ORDER, "" }
125 : };
126 :
127 :
128 : static const char* const conditional_code_suffix[] = {
129 : "o", "no", "c", "nc", "z", "nz", "na", "a",
130 : "s", "ns", "pe", "po", "l", "ge", "le", "g"
131 : };
132 :
133 :
134 : enum InstructionType {
135 : NO_INSTR,
136 : ZERO_OPERANDS_INSTR,
137 : TWO_OPERANDS_INSTR,
138 : JUMP_CONDITIONAL_SHORT_INSTR,
139 : REGISTER_INSTR,
140 : PUSHPOP_INSTR, // Has implicit 64-bit operand size.
141 : MOVE_REG_INSTR,
142 : CALL_JUMP_INSTR,
143 : SHORT_IMMEDIATE_INSTR
144 : };
145 :
146 : enum Prefixes {
147 : ESCAPE_PREFIX = 0x0F,
148 : OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
149 : ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
150 : VEX3_PREFIX = 0xC4,
151 : VEX2_PREFIX = 0xC5,
152 : LOCK_PREFIX = 0xF0,
153 : REPNE_PREFIX = 0xF2,
154 : REP_PREFIX = 0xF3,
155 : REPEQ_PREFIX = REP_PREFIX
156 : };
157 :
158 : struct InstructionDesc {
159 : const char* mnem;
160 : InstructionType type;
161 : OperandType op_order_;
162 : bool byte_size_operation; // Fixed 8-bit operation.
163 : };
164 :
165 :
166 : class InstructionTable {
167 : public:
168 : InstructionTable();
169 : const InstructionDesc& Get(byte x) const {
170 0 : return instructions_[x];
171 : }
172 :
173 : private:
174 : InstructionDesc instructions_[256];
175 : void Clear();
176 : void Init();
177 : void CopyTable(const ByteMnemonic bm[], InstructionType type);
178 : void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
179 : const char* mnem);
180 : void AddJumpConditionalShort();
181 : };
182 :
183 :
184 0 : InstructionTable::InstructionTable() {
185 : Clear();
186 0 : Init();
187 0 : }
188 :
189 :
190 0 : void InstructionTable::Clear() {
191 0 : for (int i = 0; i < 256; i++) {
192 0 : instructions_[i].mnem = "(bad)";
193 0 : instructions_[i].type = NO_INSTR;
194 0 : instructions_[i].op_order_ = UNSET_OP_ORDER;
195 0 : instructions_[i].byte_size_operation = false;
196 : }
197 0 : }
198 :
199 :
200 0 : void InstructionTable::Init() {
201 : CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
202 : CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
203 : CopyTable(call_jump_instr, CALL_JUMP_INSTR);
204 : CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
205 : AddJumpConditionalShort();
206 : SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
207 : SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
208 : SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
209 0 : }
210 :
211 :
212 0 : void InstructionTable::CopyTable(const ByteMnemonic bm[],
213 : InstructionType type) {
214 0 : for (int i = 0; bm[i].b >= 0; i++) {
215 0 : InstructionDesc* id = &instructions_[bm[i].b];
216 0 : id->mnem = bm[i].mnem;
217 0 : OperandType op_order = bm[i].op_order_;
218 : id->op_order_ =
219 0 : static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
220 : DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
221 0 : id->type = type;
222 0 : id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
223 : }
224 0 : }
225 :
226 :
227 0 : void InstructionTable::SetTableRange(InstructionType type,
228 : byte start,
229 : byte end,
230 : bool byte_size,
231 : const char* mnem) {
232 0 : for (byte b = start; b <= end; b++) {
233 0 : InstructionDesc* id = &instructions_[b];
234 : DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
235 0 : id->mnem = mnem;
236 0 : id->type = type;
237 0 : id->byte_size_operation = byte_size;
238 : }
239 0 : }
240 :
241 :
242 0 : void InstructionTable::AddJumpConditionalShort() {
243 0 : for (byte b = 0x70; b <= 0x7F; b++) {
244 0 : InstructionDesc* id = &instructions_[b];
245 : DCHECK_EQ(NO_INSTR, id->type); // Information not already entered
246 0 : id->mnem = NULL; // Computed depending on condition code.
247 0 : id->type = JUMP_CONDITIONAL_SHORT_INSTR;
248 : }
249 0 : }
250 :
251 :
252 : static v8::base::LazyInstance<InstructionTable>::type instruction_table =
253 : LAZY_INSTANCE_INITIALIZER;
254 :
255 :
256 : static const InstructionDesc cmov_instructions[16] = {
257 : {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258 : {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 : {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 : {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 : {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 : {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 : {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 : {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 : {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 : {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 : {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 : {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 : {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 : {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 : {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
272 : {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
273 : };
274 :
275 :
276 : //------------------------------------------------------------------------------
277 : // DisassemblerX64 implementation.
278 :
279 : enum UnimplementedOpcodeAction {
280 : CONTINUE_ON_UNIMPLEMENTED_OPCODE,
281 : ABORT_ON_UNIMPLEMENTED_OPCODE
282 : };
283 :
284 :
285 : // A new DisassemblerX64 object is created to disassemble each instruction.
286 : // The object can only disassemble a single instruction.
287 : class DisassemblerX64 {
288 : public:
289 0 : DisassemblerX64(const NameConverter& converter,
290 : UnimplementedOpcodeAction unimplemented_action =
291 : ABORT_ON_UNIMPLEMENTED_OPCODE)
292 : : converter_(converter),
293 : tmp_buffer_pos_(0),
294 0 : abort_on_unimplemented_(unimplemented_action ==
295 : ABORT_ON_UNIMPLEMENTED_OPCODE),
296 : rex_(0),
297 : operand_size_(0),
298 : group_1_prefix_(0),
299 : vex_byte0_(0),
300 : vex_byte1_(0),
301 : vex_byte2_(0),
302 : byte_size_operand_(false),
303 0 : instruction_table_(instruction_table.Pointer()) {
304 0 : tmp_buffer_[0] = '\0';
305 0 : }
306 :
307 0 : virtual ~DisassemblerX64() {
308 0 : }
309 :
310 : // Writes one disassembled instruction into 'buffer' (0-terminated).
311 : // Returns the length of the disassembled machine instruction in bytes.
312 : int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
313 :
314 : private:
315 : enum OperandSize {
316 : OPERAND_BYTE_SIZE = 0,
317 : OPERAND_WORD_SIZE = 1,
318 : OPERAND_DOUBLEWORD_SIZE = 2,
319 : OPERAND_QUADWORD_SIZE = 3
320 : };
321 :
322 : const NameConverter& converter_;
323 : v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
324 : unsigned int tmp_buffer_pos_;
325 : bool abort_on_unimplemented_;
326 : // Prefixes parsed
327 : byte rex_;
328 : byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
329 : byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
330 : byte vex_byte0_; // 0xc4 or 0xc5
331 : byte vex_byte1_;
332 : byte vex_byte2_; // only for 3 bytes vex prefix
333 : // Byte size operand override.
334 : bool byte_size_operand_;
335 : const InstructionTable* const instruction_table_;
336 :
337 : void setRex(byte rex) {
338 : DCHECK_EQ(0x40, rex & 0xF0);
339 0 : rex_ = rex;
340 : }
341 :
342 : bool rex() { return rex_ != 0; }
343 :
344 0 : bool rex_b() { return (rex_ & 0x01) != 0; }
345 :
346 : // Actual number of base register given the low bits and the rex.b state.
347 0 : int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
348 :
349 0 : bool rex_x() { return (rex_ & 0x02) != 0; }
350 :
351 0 : bool rex_r() { return (rex_ & 0x04) != 0; }
352 :
353 0 : bool rex_w() { return (rex_ & 0x08) != 0; }
354 :
355 : bool vex_w() {
356 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
357 0 : return vex_byte0_ == VEX3_PREFIX ? (vex_byte2_ & 0x80) != 0 : false;
358 : }
359 :
360 : bool vex_128() {
361 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
362 : byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
363 : return (checked & 4) == 0;
364 : }
365 :
366 : bool vex_none() {
367 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
368 0 : byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
369 0 : return (checked & 3) == 0;
370 : }
371 :
372 : bool vex_66() {
373 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
374 0 : byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
375 0 : return (checked & 3) == 1;
376 : }
377 :
378 : bool vex_f3() {
379 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
380 0 : byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
381 0 : return (checked & 3) == 2;
382 : }
383 :
384 : bool vex_f2() {
385 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
386 0 : byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
387 0 : return (checked & 3) == 3;
388 : }
389 :
390 : bool vex_0f() {
391 0 : if (vex_byte0_ == VEX2_PREFIX) return true;
392 0 : return (vex_byte1_ & 3) == 1;
393 : }
394 :
395 : bool vex_0f38() {
396 0 : if (vex_byte0_ == VEX2_PREFIX) return false;
397 0 : return (vex_byte1_ & 3) == 2;
398 : }
399 :
400 : bool vex_0f3a() {
401 0 : if (vex_byte0_ == VEX2_PREFIX) return false;
402 0 : return (vex_byte1_ & 3) == 3;
403 : }
404 :
405 : int vex_vreg() {
406 : DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
407 0 : byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
408 0 : return ~(checked >> 3) & 0xf;
409 : }
410 :
411 0 : OperandSize operand_size() {
412 0 : if (byte_size_operand_) return OPERAND_BYTE_SIZE;
413 0 : if (rex_w()) return OPERAND_QUADWORD_SIZE;
414 0 : if (operand_size_ != 0) return OPERAND_WORD_SIZE;
415 : return OPERAND_DOUBLEWORD_SIZE;
416 : }
417 :
418 : char operand_size_code() {
419 0 : return "bwlq"[operand_size()];
420 : }
421 :
422 0 : char float_size_code() { return "sd"[rex_w()]; }
423 :
424 0 : const char* NameOfCPURegister(int reg) const {
425 0 : return converter_.NameOfCPURegister(reg);
426 : }
427 :
428 0 : const char* NameOfByteCPURegister(int reg) const {
429 0 : return converter_.NameOfByteCPURegister(reg);
430 : }
431 :
432 0 : const char* NameOfXMMRegister(int reg) const {
433 0 : return converter_.NameOfXMMRegister(reg);
434 : }
435 :
436 : const char* NameOfAddress(byte* addr) const {
437 0 : return converter_.NameOfAddress(addr);
438 : }
439 :
440 : // Disassembler helper functions.
441 : void get_modrm(byte data,
442 : int* mod,
443 : int* regop,
444 0 : int* rm) {
445 0 : *mod = (data >> 6) & 3;
446 0 : *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
447 0 : *rm = (data & 7) | (rex_b() ? 8 : 0);
448 : }
449 :
450 : void get_sib(byte data,
451 : int* scale,
452 : int* index,
453 : int* base) {
454 0 : *scale = (data >> 6) & 3;
455 0 : *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
456 0 : *base = (data & 7) | (rex_b() ? 8 : 0);
457 : }
458 :
459 : typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
460 :
461 : int PrintRightOperandHelper(byte* modrmp,
462 : RegisterNameMapping register_name);
463 : int PrintRightOperand(byte* modrmp);
464 : int PrintRightByteOperand(byte* modrmp);
465 : int PrintRightXMMOperand(byte* modrmp);
466 : int PrintOperands(const char* mnem,
467 : OperandType op_order,
468 : byte* data);
469 : int PrintImmediate(byte* data, OperandSize size);
470 : int PrintImmediateOp(byte* data);
471 : const char* TwoByteMnemonic(byte opcode);
472 : int TwoByteOpcodeInstruction(byte* data);
473 : int F6F7Instruction(byte* data);
474 : int ShiftInstruction(byte* data);
475 : int JumpShort(byte* data);
476 : int JumpConditional(byte* data);
477 : int JumpConditionalShort(byte* data);
478 : int SetCC(byte* data);
479 : int FPUInstruction(byte* data);
480 : int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
481 : int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
482 : int AVXInstruction(byte* data);
483 : PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
484 :
485 0 : void UnimplementedInstruction() {
486 0 : if (abort_on_unimplemented_) {
487 0 : CHECK(false);
488 : } else {
489 0 : AppendToBuffer("'Unimplemented Instruction'");
490 : }
491 0 : }
492 : };
493 :
494 :
495 0 : void DisassemblerX64::AppendToBuffer(const char* format, ...) {
496 0 : v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
497 : va_list args;
498 0 : va_start(args, format);
499 0 : int result = v8::internal::VSNPrintF(buf, format, args);
500 0 : va_end(args);
501 0 : tmp_buffer_pos_ += result;
502 0 : }
503 :
504 :
505 0 : int DisassemblerX64::PrintRightOperandHelper(
506 : byte* modrmp,
507 : RegisterNameMapping direct_register_name) {
508 : int mod, regop, rm;
509 0 : get_modrm(*modrmp, &mod, ®op, &rm);
510 : RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
511 0 : &DisassemblerX64::NameOfCPURegister;
512 0 : switch (mod) {
513 : case 0:
514 0 : if ((rm & 7) == 5) {
515 0 : int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
516 0 : AppendToBuffer("[rip+0x%x]", disp);
517 0 : return 5;
518 0 : } else if ((rm & 7) == 4) {
519 : // Codes for SIB byte.
520 0 : byte sib = *(modrmp + 1);
521 : int scale, index, base;
522 : get_sib(sib, &scale, &index, &base);
523 0 : if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
524 : // index == rsp means no index. Only use sib byte with no index for
525 : // rsp and r12 base.
526 0 : AppendToBuffer("[%s]", NameOfCPURegister(base));
527 0 : return 2;
528 0 : } else if (base == 5) {
529 : // base == rbp means no base register (when mod == 0).
530 0 : int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
531 : AppendToBuffer("[%s*%d%s0x%x]",
532 : NameOfCPURegister(index),
533 : 1 << scale,
534 : disp < 0 ? "-" : "+",
535 0 : disp < 0 ? -disp : disp);
536 0 : return 6;
537 0 : } else if (index != 4 && base != 5) {
538 : // [base+index*scale]
539 : AppendToBuffer("[%s+%s*%d]",
540 : NameOfCPURegister(base),
541 : NameOfCPURegister(index),
542 0 : 1 << scale);
543 0 : return 2;
544 : } else {
545 0 : UnimplementedInstruction();
546 0 : return 1;
547 : }
548 : } else {
549 0 : AppendToBuffer("[%s]", NameOfCPURegister(rm));
550 0 : return 1;
551 : }
552 : break;
553 : case 1: // fall through
554 : case 2:
555 0 : if ((rm & 7) == 4) {
556 0 : byte sib = *(modrmp + 1);
557 : int scale, index, base;
558 : get_sib(sib, &scale, &index, &base);
559 : int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
560 0 : : *reinterpret_cast<int8_t*>(modrmp + 2);
561 0 : if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
562 : AppendToBuffer("[%s%s0x%x]",
563 : NameOfCPURegister(base),
564 : disp < 0 ? "-" : "+",
565 0 : disp < 0 ? -disp : disp);
566 : } else {
567 : AppendToBuffer("[%s+%s*%d%s0x%x]",
568 : NameOfCPURegister(base),
569 : NameOfCPURegister(index),
570 : 1 << scale,
571 : disp < 0 ? "-" : "+",
572 0 : disp < 0 ? -disp : disp);
573 : }
574 0 : return mod == 2 ? 6 : 3;
575 : } else {
576 : // No sib.
577 : int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
578 0 : : *reinterpret_cast<int8_t*>(modrmp + 1);
579 : AppendToBuffer("[%s%s0x%x]",
580 : NameOfCPURegister(rm),
581 : disp < 0 ? "-" : "+",
582 0 : disp < 0 ? -disp : disp);
583 0 : return (mod == 2) ? 5 : 2;
584 : }
585 : break;
586 : case 3:
587 0 : AppendToBuffer("%s", (this->*register_name)(rm));
588 0 : return 1;
589 : default:
590 0 : UnimplementedInstruction();
591 0 : return 1;
592 : }
593 : UNREACHABLE();
594 : }
595 :
596 :
597 0 : int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
598 : int64_t value;
599 : int count;
600 0 : switch (size) {
601 : case OPERAND_BYTE_SIZE:
602 0 : value = *data;
603 : count = 1;
604 0 : break;
605 : case OPERAND_WORD_SIZE:
606 0 : value = *reinterpret_cast<int16_t*>(data);
607 : count = 2;
608 0 : break;
609 : case OPERAND_DOUBLEWORD_SIZE:
610 0 : value = *reinterpret_cast<uint32_t*>(data);
611 : count = 4;
612 0 : break;
613 : case OPERAND_QUADWORD_SIZE:
614 0 : value = *reinterpret_cast<int32_t*>(data);
615 : count = 4;
616 0 : break;
617 : default:
618 0 : UNREACHABLE();
619 : value = 0; // Initialize variables on all paths to satisfy the compiler.
620 : count = 0;
621 : }
622 0 : AppendToBuffer("%" PRIx64, value);
623 0 : return count;
624 : }
625 :
626 :
627 0 : int DisassemblerX64::PrintRightOperand(byte* modrmp) {
628 : return PrintRightOperandHelper(modrmp,
629 0 : &DisassemblerX64::NameOfCPURegister);
630 : }
631 :
632 :
633 0 : int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
634 : return PrintRightOperandHelper(modrmp,
635 0 : &DisassemblerX64::NameOfByteCPURegister);
636 : }
637 :
638 :
639 0 : int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
640 : return PrintRightOperandHelper(modrmp,
641 0 : &DisassemblerX64::NameOfXMMRegister);
642 : }
643 :
644 :
645 : // Returns number of bytes used including the current *data.
646 : // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
647 0 : int DisassemblerX64::PrintOperands(const char* mnem,
648 : OperandType op_order,
649 : byte* data) {
650 0 : byte modrm = *data;
651 : int mod, regop, rm;
652 : get_modrm(modrm, &mod, ®op, &rm);
653 : int advance = 0;
654 : const char* register_name =
655 : byte_size_operand_ ? NameOfByteCPURegister(regop)
656 0 : : NameOfCPURegister(regop);
657 0 : switch (op_order) {
658 : case REG_OPER_OP_ORDER: {
659 : AppendToBuffer("%s%c %s,",
660 : mnem,
661 : operand_size_code(),
662 0 : register_name);
663 : advance = byte_size_operand_ ? PrintRightByteOperand(data)
664 0 : : PrintRightOperand(data);
665 0 : break;
666 : }
667 : case OPER_REG_OP_ORDER: {
668 0 : AppendToBuffer("%s%c ", mnem, operand_size_code());
669 : advance = byte_size_operand_ ? PrintRightByteOperand(data)
670 0 : : PrintRightOperand(data);
671 0 : AppendToBuffer(",%s", register_name);
672 0 : break;
673 : }
674 : default:
675 0 : UNREACHABLE();
676 : break;
677 : }
678 0 : return advance;
679 : }
680 :
681 :
682 : // Returns number of bytes used by machine instruction, including *data byte.
683 : // Writes immediate instructions to 'tmp_buffer_'.
684 0 : int DisassemblerX64::PrintImmediateOp(byte* data) {
685 0 : bool byte_size_immediate = (*data & 0x02) != 0;
686 0 : byte modrm = *(data + 1);
687 : int mod, regop, rm;
688 : get_modrm(modrm, &mod, ®op, &rm);
689 : const char* mnem = "Imm???";
690 0 : switch (regop) {
691 : case 0:
692 : mnem = "add";
693 : break;
694 : case 1:
695 : mnem = "or";
696 0 : break;
697 : case 2:
698 : mnem = "adc";
699 0 : break;
700 : case 3:
701 : mnem = "sbb";
702 0 : break;
703 : case 4:
704 : mnem = "and";
705 0 : break;
706 : case 5:
707 : mnem = "sub";
708 0 : break;
709 : case 6:
710 : mnem = "xor";
711 0 : break;
712 : case 7:
713 : mnem = "cmp";
714 0 : break;
715 : default:
716 0 : UnimplementedInstruction();
717 : }
718 0 : AppendToBuffer("%s%c ", mnem, operand_size_code());
719 0 : int count = PrintRightOperand(data + 1);
720 0 : AppendToBuffer(",0x");
721 : OperandSize immediate_size =
722 0 : byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
723 0 : count += PrintImmediate(data + 1 + count, immediate_size);
724 0 : return 1 + count;
725 : }
726 :
727 :
728 : // Returns number of bytes used, including *data.
729 0 : int DisassemblerX64::F6F7Instruction(byte* data) {
730 : DCHECK(*data == 0xF7 || *data == 0xF6);
731 0 : byte modrm = *(data + 1);
732 : int mod, regop, rm;
733 : get_modrm(modrm, &mod, ®op, &rm);
734 0 : if (mod == 3 && regop != 0) {
735 : const char* mnem = NULL;
736 0 : switch (regop) {
737 : case 2:
738 : mnem = "not";
739 : break;
740 : case 3:
741 : mnem = "neg";
742 0 : break;
743 : case 4:
744 : mnem = "mul";
745 0 : break;
746 : case 5:
747 : mnem = "imul";
748 0 : break;
749 : case 6:
750 : mnem = "div";
751 0 : break;
752 : case 7:
753 : mnem = "idiv";
754 0 : break;
755 : default:
756 0 : UnimplementedInstruction();
757 : }
758 : AppendToBuffer("%s%c %s",
759 : mnem,
760 : operand_size_code(),
761 0 : NameOfCPURegister(rm));
762 0 : return 2;
763 0 : } else if (regop == 0) {
764 0 : AppendToBuffer("test%c ", operand_size_code());
765 0 : int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
766 0 : AppendToBuffer(",0x");
767 0 : count += PrintImmediate(data + 1 + count, operand_size());
768 0 : return 1 + count;
769 : } else {
770 0 : UnimplementedInstruction();
771 0 : return 2;
772 : }
773 : }
774 :
775 :
776 0 : int DisassemblerX64::ShiftInstruction(byte* data) {
777 0 : byte op = *data & (~1);
778 : int count = 1;
779 0 : if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
780 0 : UnimplementedInstruction();
781 0 : return count;
782 : }
783 : // Print mneumonic.
784 : {
785 0 : byte modrm = *(data + count);
786 : int mod, regop, rm;
787 : get_modrm(modrm, &mod, ®op, &rm);
788 0 : regop &= 0x7; // The REX.R bit does not affect the operation.
789 : const char* mnem = NULL;
790 0 : switch (regop) {
791 : case 0:
792 : mnem = "rol";
793 : break;
794 : case 1:
795 : mnem = "ror";
796 0 : break;
797 : case 2:
798 : mnem = "rcl";
799 0 : break;
800 : case 3:
801 : mnem = "rcr";
802 0 : break;
803 : case 4:
804 : mnem = "shl";
805 0 : break;
806 : case 5:
807 : mnem = "shr";
808 0 : break;
809 : case 7:
810 : mnem = "sar";
811 0 : break;
812 : default:
813 0 : UnimplementedInstruction();
814 : return count + 1;
815 : }
816 : DCHECK_NOT_NULL(mnem);
817 0 : AppendToBuffer("%s%c ", mnem, operand_size_code());
818 : }
819 0 : count += PrintRightOperand(data + count);
820 0 : if (op == 0xD2) {
821 0 : AppendToBuffer(", cl");
822 : } else {
823 : int imm8 = -1;
824 0 : if (op == 0xD0) {
825 : imm8 = 1;
826 : } else {
827 : DCHECK_EQ(0xC0, op);
828 0 : imm8 = *(data + count);
829 0 : count++;
830 : }
831 0 : AppendToBuffer(", %d", imm8);
832 : }
833 0 : return count;
834 : }
835 :
836 :
837 : // Returns number of bytes used, including *data.
838 0 : int DisassemblerX64::JumpShort(byte* data) {
839 : DCHECK_EQ(0xEB, *data);
840 0 : byte b = *(data + 1);
841 0 : byte* dest = data + static_cast<int8_t>(b) + 2;
842 0 : AppendToBuffer("jmp %s", NameOfAddress(dest));
843 0 : return 2;
844 : }
845 :
846 :
847 : // Returns number of bytes used, including *data.
848 0 : int DisassemblerX64::JumpConditional(byte* data) {
849 : DCHECK_EQ(0x0F, *data);
850 0 : byte cond = *(data + 1) & 0x0F;
851 0 : byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
852 0 : const char* mnem = conditional_code_suffix[cond];
853 0 : AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
854 0 : return 6; // includes 0x0F
855 : }
856 :
857 :
858 : // Returns number of bytes used, including *data.
859 0 : int DisassemblerX64::JumpConditionalShort(byte* data) {
860 0 : byte cond = *data & 0x0F;
861 0 : byte b = *(data + 1);
862 0 : byte* dest = data + static_cast<int8_t>(b) + 2;
863 0 : const char* mnem = conditional_code_suffix[cond];
864 0 : AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
865 0 : return 2;
866 : }
867 :
868 :
869 : // Returns number of bytes used, including *data.
870 0 : int DisassemblerX64::SetCC(byte* data) {
871 : DCHECK_EQ(0x0F, *data);
872 0 : byte cond = *(data + 1) & 0x0F;
873 0 : const char* mnem = conditional_code_suffix[cond];
874 0 : AppendToBuffer("set%s%c ", mnem, operand_size_code());
875 0 : PrintRightByteOperand(data + 2);
876 0 : return 3; // includes 0x0F
877 : }
878 :
879 : const char* sf_str[4] = {"", "rl", "ra", "ll"};
880 :
881 0 : int DisassemblerX64::AVXInstruction(byte* data) {
882 0 : byte opcode = *data;
883 0 : byte* current = data + 1;
884 0 : if (vex_66() && vex_0f38()) {
885 : int mod, regop, rm, vvvv = vex_vreg();
886 0 : get_modrm(*current, &mod, ®op, &rm);
887 0 : switch (opcode) {
888 : case 0x99:
889 : AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
890 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
891 0 : current += PrintRightXMMOperand(current);
892 0 : break;
893 : case 0xa9:
894 : AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
895 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
896 0 : current += PrintRightXMMOperand(current);
897 0 : break;
898 : case 0xb9:
899 : AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
900 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
901 0 : current += PrintRightXMMOperand(current);
902 0 : break;
903 : case 0x9b:
904 : AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
905 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
906 0 : current += PrintRightXMMOperand(current);
907 0 : break;
908 : case 0xab:
909 : AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
910 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
911 0 : current += PrintRightXMMOperand(current);
912 0 : break;
913 : case 0xbb:
914 : AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
915 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
916 0 : current += PrintRightXMMOperand(current);
917 0 : break;
918 : case 0x9d:
919 : AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
920 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
921 0 : current += PrintRightXMMOperand(current);
922 0 : break;
923 : case 0xad:
924 : AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
925 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
926 0 : current += PrintRightXMMOperand(current);
927 0 : break;
928 : case 0xbd:
929 : AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
930 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
931 0 : current += PrintRightXMMOperand(current);
932 0 : break;
933 : case 0x9f:
934 : AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
935 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
936 0 : current += PrintRightXMMOperand(current);
937 0 : break;
938 : case 0xaf:
939 : AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
940 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
941 0 : current += PrintRightXMMOperand(current);
942 0 : break;
943 : case 0xbf:
944 : AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
945 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
946 0 : current += PrintRightXMMOperand(current);
947 0 : break;
948 : case 0xf7:
949 : AppendToBuffer("shlx%c %s,", operand_size_code(),
950 0 : NameOfCPURegister(regop));
951 0 : current += PrintRightOperand(current);
952 0 : AppendToBuffer(",%s", NameOfCPURegister(vvvv));
953 0 : break;
954 : #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
955 : opcode) \
956 : case 0x##opcode: { \
957 : AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
958 : NameOfXMMRegister(vvvv)); \
959 : current += PrintRightXMMOperand(current); \
960 : break; \
961 : }
962 :
963 0 : SSSE3_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
964 0 : SSE4_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
965 : #undef DECLARE_SSE_AVX_DIS_CASE
966 : default:
967 0 : UnimplementedInstruction();
968 : }
969 0 : } else if (vex_66() && vex_0f3a()) {
970 : int mod, regop, rm, vvvv = vex_vreg();
971 0 : get_modrm(*current, &mod, ®op, &rm);
972 0 : switch (opcode) {
973 : case 0x0a:
974 : AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
975 0 : NameOfXMMRegister(vvvv));
976 0 : current += PrintRightXMMOperand(current);
977 0 : AppendToBuffer(",0x%x", *current++);
978 0 : break;
979 : case 0x0b:
980 : AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
981 0 : NameOfXMMRegister(vvvv));
982 0 : current += PrintRightXMMOperand(current);
983 0 : AppendToBuffer(",0x%x", *current++);
984 0 : break;
985 : case 0x14:
986 0 : AppendToBuffer("vpextrb ");
987 0 : current += PrintRightByteOperand(current);
988 0 : AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
989 0 : break;
990 : case 0x15:
991 0 : AppendToBuffer("vpextrw ");
992 0 : current += PrintRightOperand(current);
993 0 : AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
994 0 : break;
995 : case 0x16:
996 0 : AppendToBuffer("vpextrd ");
997 0 : current += PrintRightOperand(current);
998 0 : AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
999 0 : break;
1000 : case 0x20:
1001 : AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
1002 0 : NameOfXMMRegister(vvvv));
1003 0 : current += PrintRightByteOperand(current);
1004 0 : AppendToBuffer(",0x%x", *current++);
1005 0 : break;
1006 : case 0x22:
1007 : AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop),
1008 0 : NameOfXMMRegister(vvvv));
1009 0 : current += PrintRightOperand(current);
1010 0 : AppendToBuffer(",0x%x", *current++);
1011 0 : break;
1012 : default:
1013 0 : UnimplementedInstruction();
1014 : }
1015 0 : } else if (vex_f3() && vex_0f()) {
1016 : int mod, regop, rm, vvvv = vex_vreg();
1017 0 : get_modrm(*current, &mod, ®op, &rm);
1018 0 : switch (opcode) {
1019 : case 0x10:
1020 0 : AppendToBuffer("vmovss %s,", NameOfXMMRegister(regop));
1021 0 : if (mod == 3) {
1022 0 : AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1023 : }
1024 0 : current += PrintRightXMMOperand(current);
1025 0 : break;
1026 : case 0x11:
1027 0 : AppendToBuffer("vmovss ");
1028 0 : current += PrintRightXMMOperand(current);
1029 0 : if (mod == 3) {
1030 0 : AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1031 : }
1032 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1033 0 : break;
1034 : case 0x2a:
1035 : AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2ss" : "vcvtlsi2ss",
1036 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1037 0 : current += PrintRightOperand(current);
1038 0 : break;
1039 : case 0x2c:
1040 : AppendToBuffer("vcvttss2si%s %s,", vex_w() ? "q" : "",
1041 0 : NameOfCPURegister(regop));
1042 0 : current += PrintRightXMMOperand(current);
1043 0 : break;
1044 : case 0x58:
1045 : AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
1046 0 : NameOfXMMRegister(vvvv));
1047 0 : current += PrintRightXMMOperand(current);
1048 0 : break;
1049 : case 0x59:
1050 : AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
1051 0 : NameOfXMMRegister(vvvv));
1052 0 : current += PrintRightXMMOperand(current);
1053 0 : break;
1054 : case 0x5a:
1055 : AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
1056 0 : NameOfXMMRegister(vvvv));
1057 0 : current += PrintRightXMMOperand(current);
1058 0 : break;
1059 : case 0x5c:
1060 : AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
1061 0 : NameOfXMMRegister(vvvv));
1062 0 : current += PrintRightXMMOperand(current);
1063 0 : break;
1064 : case 0x5d:
1065 : AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
1066 0 : NameOfXMMRegister(vvvv));
1067 0 : current += PrintRightXMMOperand(current);
1068 0 : break;
1069 : case 0x5e:
1070 : AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
1071 0 : NameOfXMMRegister(vvvv));
1072 0 : current += PrintRightXMMOperand(current);
1073 0 : break;
1074 : case 0x5f:
1075 : AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
1076 0 : NameOfXMMRegister(vvvv));
1077 0 : current += PrintRightXMMOperand(current);
1078 0 : break;
1079 : default:
1080 0 : UnimplementedInstruction();
1081 : }
1082 0 : } else if (vex_f2() && vex_0f()) {
1083 : int mod, regop, rm, vvvv = vex_vreg();
1084 0 : get_modrm(*current, &mod, ®op, &rm);
1085 0 : switch (opcode) {
1086 : case 0x10:
1087 0 : AppendToBuffer("vmovsd %s,", NameOfXMMRegister(regop));
1088 0 : if (mod == 3) {
1089 0 : AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1090 : }
1091 0 : current += PrintRightXMMOperand(current);
1092 0 : break;
1093 : case 0x11:
1094 0 : AppendToBuffer("vmovsd ");
1095 0 : current += PrintRightXMMOperand(current);
1096 0 : if (mod == 3) {
1097 0 : AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1098 : }
1099 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1100 0 : break;
1101 : case 0x2a:
1102 : AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd",
1103 0 : NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1104 0 : current += PrintRightOperand(current);
1105 0 : break;
1106 : case 0x2c:
1107 : AppendToBuffer("vcvttsd2si%s %s,", vex_w() ? "q" : "",
1108 0 : NameOfCPURegister(regop));
1109 0 : current += PrintRightXMMOperand(current);
1110 0 : break;
1111 : case 0x2d:
1112 : AppendToBuffer("vcvtsd2si%s %s,", vex_w() ? "q" : "",
1113 0 : NameOfCPURegister(regop));
1114 0 : current += PrintRightXMMOperand(current);
1115 0 : break;
1116 : case 0x51:
1117 : AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
1118 0 : NameOfXMMRegister(vvvv));
1119 0 : current += PrintRightXMMOperand(current);
1120 0 : break;
1121 : case 0x58:
1122 : AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
1123 0 : NameOfXMMRegister(vvvv));
1124 0 : current += PrintRightXMMOperand(current);
1125 0 : break;
1126 : case 0x59:
1127 : AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
1128 0 : NameOfXMMRegister(vvvv));
1129 0 : current += PrintRightXMMOperand(current);
1130 0 : break;
1131 : case 0x5a:
1132 : AppendToBuffer("vcvtsd2ss %s,%s,", NameOfXMMRegister(regop),
1133 0 : NameOfXMMRegister(vvvv));
1134 0 : current += PrintRightXMMOperand(current);
1135 0 : break;
1136 : case 0x5c:
1137 : AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
1138 0 : NameOfXMMRegister(vvvv));
1139 0 : current += PrintRightXMMOperand(current);
1140 0 : break;
1141 : case 0x5d:
1142 : AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
1143 0 : NameOfXMMRegister(vvvv));
1144 0 : current += PrintRightXMMOperand(current);
1145 0 : break;
1146 : case 0x5e:
1147 : AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
1148 0 : NameOfXMMRegister(vvvv));
1149 0 : current += PrintRightXMMOperand(current);
1150 0 : break;
1151 : case 0x5f:
1152 : AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
1153 0 : NameOfXMMRegister(vvvv));
1154 0 : current += PrintRightXMMOperand(current);
1155 0 : break;
1156 : case 0xf0:
1157 0 : AppendToBuffer("vlddqu %s,", NameOfXMMRegister(regop));
1158 0 : current += PrintRightXMMOperand(current);
1159 0 : break;
1160 : default:
1161 0 : UnimplementedInstruction();
1162 : }
1163 0 : } else if (vex_none() && vex_0f38()) {
1164 : int mod, regop, rm, vvvv = vex_vreg();
1165 0 : get_modrm(*current, &mod, ®op, &rm);
1166 : const char* mnem = "?";
1167 0 : switch (opcode) {
1168 : case 0xf2:
1169 : AppendToBuffer("andn%c %s,%s,", operand_size_code(),
1170 0 : NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1171 0 : current += PrintRightOperand(current);
1172 0 : break;
1173 : case 0xf5:
1174 : AppendToBuffer("bzhi%c %s,", operand_size_code(),
1175 0 : NameOfCPURegister(regop));
1176 0 : current += PrintRightOperand(current);
1177 0 : AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1178 0 : break;
1179 : case 0xf7:
1180 : AppendToBuffer("bextr%c %s,", operand_size_code(),
1181 0 : NameOfCPURegister(regop));
1182 0 : current += PrintRightOperand(current);
1183 0 : AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1184 0 : break;
1185 : case 0xf3:
1186 0 : switch (regop) {
1187 : case 1:
1188 : mnem = "blsr";
1189 : break;
1190 : case 2:
1191 : mnem = "blsmsk";
1192 0 : break;
1193 : case 3:
1194 : mnem = "blsi";
1195 0 : break;
1196 : default:
1197 0 : UnimplementedInstruction();
1198 : }
1199 : AppendToBuffer("%s%c %s,", mnem, operand_size_code(),
1200 0 : NameOfCPURegister(vvvv));
1201 0 : current += PrintRightOperand(current);
1202 : mnem = "?";
1203 0 : break;
1204 : default:
1205 0 : UnimplementedInstruction();
1206 : }
1207 0 : } else if (vex_f2() && vex_0f38()) {
1208 : int mod, regop, rm, vvvv = vex_vreg();
1209 0 : get_modrm(*current, &mod, ®op, &rm);
1210 0 : switch (opcode) {
1211 : case 0xf5:
1212 : AppendToBuffer("pdep%c %s,%s,", operand_size_code(),
1213 0 : NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1214 0 : current += PrintRightOperand(current);
1215 0 : break;
1216 : case 0xf6:
1217 : AppendToBuffer("mulx%c %s,%s,", operand_size_code(),
1218 0 : NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1219 0 : current += PrintRightOperand(current);
1220 0 : break;
1221 : case 0xf7:
1222 : AppendToBuffer("shrx%c %s,", operand_size_code(),
1223 0 : NameOfCPURegister(regop));
1224 0 : current += PrintRightOperand(current);
1225 0 : AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1226 0 : break;
1227 : default:
1228 0 : UnimplementedInstruction();
1229 : }
1230 0 : } else if (vex_f3() && vex_0f38()) {
1231 : int mod, regop, rm, vvvv = vex_vreg();
1232 0 : get_modrm(*current, &mod, ®op, &rm);
1233 0 : switch (opcode) {
1234 : case 0xf5:
1235 : AppendToBuffer("pext%c %s,%s,", operand_size_code(),
1236 0 : NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1237 0 : current += PrintRightOperand(current);
1238 0 : break;
1239 : case 0xf7:
1240 : AppendToBuffer("sarx%c %s,", operand_size_code(),
1241 0 : NameOfCPURegister(regop));
1242 0 : current += PrintRightOperand(current);
1243 0 : AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1244 0 : break;
1245 : default:
1246 0 : UnimplementedInstruction();
1247 : }
1248 0 : } else if (vex_f2() && vex_0f3a()) {
1249 : int mod, regop, rm;
1250 0 : get_modrm(*current, &mod, ®op, &rm);
1251 0 : switch (opcode) {
1252 : case 0xf0:
1253 : AppendToBuffer("rorx%c %s,", operand_size_code(),
1254 0 : NameOfCPURegister(regop));
1255 0 : current += PrintRightOperand(current);
1256 0 : switch (operand_size()) {
1257 : case OPERAND_DOUBLEWORD_SIZE:
1258 0 : AppendToBuffer(",%d", *current & 0x1f);
1259 0 : break;
1260 : case OPERAND_QUADWORD_SIZE:
1261 0 : AppendToBuffer(",%d", *current & 0x3f);
1262 0 : break;
1263 : default:
1264 0 : UnimplementedInstruction();
1265 : }
1266 0 : current += 1;
1267 0 : break;
1268 : default:
1269 0 : UnimplementedInstruction();
1270 : }
1271 0 : } else if (vex_none() && vex_0f()) {
1272 : int mod, regop, rm, vvvv = vex_vreg();
1273 0 : get_modrm(*current, &mod, ®op, &rm);
1274 0 : switch (opcode) {
1275 : case 0x10:
1276 0 : AppendToBuffer("vmovups %s,", NameOfXMMRegister(regop));
1277 0 : current += PrintRightXMMOperand(current);
1278 0 : break;
1279 : case 0x11:
1280 0 : AppendToBuffer("vmovups ");
1281 0 : current += PrintRightXMMOperand(current);
1282 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1283 0 : break;
1284 : case 0x28:
1285 0 : AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1286 0 : current += PrintRightXMMOperand(current);
1287 0 : break;
1288 : case 0x29:
1289 0 : AppendToBuffer("vmovaps ");
1290 0 : current += PrintRightXMMOperand(current);
1291 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1292 0 : break;
1293 : case 0x2e:
1294 0 : AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1295 0 : current += PrintRightXMMOperand(current);
1296 0 : break;
1297 : case 0x50:
1298 0 : AppendToBuffer("vmovmskps %s,", NameOfCPURegister(regop));
1299 0 : current += PrintRightXMMOperand(current);
1300 0 : break;
1301 : case 0x54:
1302 : AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1303 0 : NameOfXMMRegister(vvvv));
1304 0 : current += PrintRightXMMOperand(current);
1305 0 : break;
1306 : case 0x57:
1307 : AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1308 0 : NameOfXMMRegister(vvvv));
1309 0 : current += PrintRightXMMOperand(current);
1310 0 : break;
1311 : case 0xC2: {
1312 : AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1313 0 : NameOfXMMRegister(vvvv));
1314 0 : current += PrintRightXMMOperand(current);
1315 : const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1316 0 : "neq", "nlt", "nle", "ord"};
1317 0 : AppendToBuffer(", (%s)", pseudo_op[*current]);
1318 0 : current += 1;
1319 : break;
1320 : }
1321 : default:
1322 0 : UnimplementedInstruction();
1323 : }
1324 0 : } else if (vex_66() && vex_0f()) {
1325 : int mod, regop, rm, vvvv = vex_vreg();
1326 0 : get_modrm(*current, &mod, ®op, &rm);
1327 0 : switch (opcode) {
1328 : case 0x10:
1329 0 : AppendToBuffer("vmovupd %s,", NameOfXMMRegister(regop));
1330 0 : current += PrintRightXMMOperand(current);
1331 0 : break;
1332 : case 0x11:
1333 0 : AppendToBuffer("vmovupd ");
1334 0 : current += PrintRightXMMOperand(current);
1335 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1336 0 : break;
1337 : case 0x28:
1338 0 : AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1339 0 : current += PrintRightXMMOperand(current);
1340 0 : break;
1341 : case 0x29:
1342 0 : AppendToBuffer("vmovapd ");
1343 0 : current += PrintRightXMMOperand(current);
1344 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1345 0 : break;
1346 : case 0x2e:
1347 0 : AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1348 0 : current += PrintRightXMMOperand(current);
1349 0 : break;
1350 : case 0x50:
1351 0 : AppendToBuffer("vmovmskpd %s,", NameOfCPURegister(regop));
1352 0 : current += PrintRightXMMOperand(current);
1353 0 : break;
1354 : case 0x54:
1355 : AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1356 0 : NameOfXMMRegister(vvvv));
1357 0 : current += PrintRightXMMOperand(current);
1358 0 : break;
1359 : case 0x56:
1360 : AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1361 0 : NameOfXMMRegister(vvvv));
1362 0 : current += PrintRightXMMOperand(current);
1363 0 : break;
1364 : case 0x57:
1365 : AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1366 0 : NameOfXMMRegister(vvvv));
1367 0 : current += PrintRightXMMOperand(current);
1368 0 : break;
1369 : case 0x6e:
1370 : AppendToBuffer("vmov%c %s,", vex_w() ? 'q' : 'd',
1371 0 : NameOfXMMRegister(regop));
1372 0 : current += PrintRightOperand(current);
1373 0 : break;
1374 : case 0x70:
1375 0 : AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1376 0 : current += PrintRightXMMOperand(current);
1377 0 : AppendToBuffer(",0x%x", *current++);
1378 0 : break;
1379 : case 0x71:
1380 0 : AppendToBuffer("vps%sw %s,", sf_str[regop / 2],
1381 0 : NameOfXMMRegister(vvvv));
1382 0 : current += PrintRightXMMOperand(current);
1383 0 : AppendToBuffer(",%u", *current++);
1384 0 : break;
1385 : case 0x72:
1386 0 : AppendToBuffer("vps%sd %s,", sf_str[regop / 2],
1387 0 : NameOfXMMRegister(vvvv));
1388 0 : current += PrintRightXMMOperand(current);
1389 0 : AppendToBuffer(",%u", *current++);
1390 0 : break;
1391 : case 0x73:
1392 0 : AppendToBuffer("vps%sq %s,", sf_str[regop / 2],
1393 0 : NameOfXMMRegister(vvvv));
1394 0 : current += PrintRightXMMOperand(current);
1395 0 : AppendToBuffer(",%u", *current++);
1396 0 : break;
1397 : case 0x7e:
1398 0 : AppendToBuffer("vmov%c ", vex_w() ? 'q' : 'd');
1399 0 : current += PrintRightOperand(current);
1400 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1401 0 : break;
1402 : case 0xC2: {
1403 : AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1404 0 : NameOfXMMRegister(vvvv));
1405 0 : current += PrintRightXMMOperand(current);
1406 : const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1407 0 : "neq", "nlt", "nle", "ord"};
1408 0 : AppendToBuffer(", (%s)", pseudo_op[*current]);
1409 0 : current += 1;
1410 : break;
1411 : }
1412 : case 0xc4:
1413 : AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1414 0 : NameOfXMMRegister(vvvv));
1415 0 : current += PrintRightOperand(current);
1416 0 : AppendToBuffer(",0x%x", *current++);
1417 0 : break;
1418 : case 0xc5:
1419 0 : AppendToBuffer("vpextrw %s,", NameOfCPURegister(regop));
1420 0 : current += PrintRightXMMOperand(current);
1421 0 : AppendToBuffer(",0x%x", *current++);
1422 0 : break;
1423 : #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1424 : case 0x##opcode: { \
1425 : AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
1426 : NameOfXMMRegister(vvvv)); \
1427 : current += PrintRightXMMOperand(current); \
1428 : break; \
1429 : }
1430 :
1431 0 : SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1432 : #undef DECLARE_SSE_AVX_DIS_CASE
1433 : default:
1434 0 : UnimplementedInstruction();
1435 : }
1436 :
1437 : } else {
1438 0 : UnimplementedInstruction();
1439 : }
1440 :
1441 0 : return static_cast<int>(current - data);
1442 : }
1443 :
1444 : // Returns number of bytes used, including *data.
1445 0 : int DisassemblerX64::FPUInstruction(byte* data) {
1446 0 : byte escape_opcode = *data;
1447 : DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1448 0 : byte modrm_byte = *(data+1);
1449 :
1450 0 : if (modrm_byte >= 0xC0) {
1451 0 : return RegisterFPUInstruction(escape_opcode, modrm_byte);
1452 : } else {
1453 0 : return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
1454 : }
1455 : }
1456 :
1457 0 : int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
1458 : int modrm_byte,
1459 : byte* modrm_start) {
1460 : const char* mnem = "?";
1461 0 : int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1462 0 : switch (escape_opcode) {
1463 0 : case 0xD9: switch (regop) {
1464 : case 0: mnem = "fld_s"; break;
1465 0 : case 3: mnem = "fstp_s"; break;
1466 0 : case 7: mnem = "fstcw"; break;
1467 0 : default: UnimplementedInstruction();
1468 : }
1469 : break;
1470 :
1471 0 : case 0xDB: switch (regop) {
1472 : case 0: mnem = "fild_s"; break;
1473 0 : case 1: mnem = "fisttp_s"; break;
1474 0 : case 2: mnem = "fist_s"; break;
1475 0 : case 3: mnem = "fistp_s"; break;
1476 0 : default: UnimplementedInstruction();
1477 : }
1478 : break;
1479 :
1480 0 : case 0xDD: switch (regop) {
1481 : case 0: mnem = "fld_d"; break;
1482 0 : case 3: mnem = "fstp_d"; break;
1483 0 : default: UnimplementedInstruction();
1484 : }
1485 : break;
1486 :
1487 0 : case 0xDF: switch (regop) {
1488 : case 5: mnem = "fild_d"; break;
1489 0 : case 7: mnem = "fistp_d"; break;
1490 0 : default: UnimplementedInstruction();
1491 : }
1492 : break;
1493 :
1494 0 : default: UnimplementedInstruction();
1495 : }
1496 0 : AppendToBuffer("%s ", mnem);
1497 : int count = PrintRightOperand(modrm_start);
1498 0 : return count + 1;
1499 : }
1500 :
1501 0 : int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1502 : byte modrm_byte) {
1503 : bool has_register = false; // Is the FPU register encoded in modrm_byte?
1504 : const char* mnem = "?";
1505 :
1506 0 : switch (escape_opcode) {
1507 : case 0xD8:
1508 0 : UnimplementedInstruction();
1509 0 : break;
1510 :
1511 : case 0xD9:
1512 0 : switch (modrm_byte & 0xF8) {
1513 : case 0xC0:
1514 : mnem = "fld";
1515 : has_register = true;
1516 : break;
1517 : case 0xC8:
1518 : mnem = "fxch";
1519 : has_register = true;
1520 0 : break;
1521 : default:
1522 0 : switch (modrm_byte) {
1523 : case 0xE0: mnem = "fchs"; break;
1524 0 : case 0xE1: mnem = "fabs"; break;
1525 0 : case 0xE3: mnem = "fninit"; break;
1526 0 : case 0xE4: mnem = "ftst"; break;
1527 0 : case 0xE8: mnem = "fld1"; break;
1528 0 : case 0xEB: mnem = "fldpi"; break;
1529 0 : case 0xED: mnem = "fldln2"; break;
1530 0 : case 0xEE: mnem = "fldz"; break;
1531 0 : case 0xF0: mnem = "f2xm1"; break;
1532 0 : case 0xF1: mnem = "fyl2x"; break;
1533 0 : case 0xF2: mnem = "fptan"; break;
1534 0 : case 0xF5: mnem = "fprem1"; break;
1535 0 : case 0xF7: mnem = "fincstp"; break;
1536 0 : case 0xF8: mnem = "fprem"; break;
1537 0 : case 0xFC: mnem = "frndint"; break;
1538 0 : case 0xFD: mnem = "fscale"; break;
1539 0 : case 0xFE: mnem = "fsin"; break;
1540 0 : case 0xFF: mnem = "fcos"; break;
1541 0 : default: UnimplementedInstruction();
1542 : }
1543 : }
1544 : break;
1545 :
1546 : case 0xDA:
1547 0 : if (modrm_byte == 0xE9) {
1548 : mnem = "fucompp";
1549 : } else {
1550 0 : UnimplementedInstruction();
1551 : }
1552 : break;
1553 :
1554 : case 0xDB:
1555 0 : if ((modrm_byte & 0xF8) == 0xE8) {
1556 : mnem = "fucomi";
1557 : has_register = true;
1558 0 : } else if (modrm_byte == 0xE2) {
1559 : mnem = "fclex";
1560 0 : } else if (modrm_byte == 0xE3) {
1561 : mnem = "fninit";
1562 : } else {
1563 0 : UnimplementedInstruction();
1564 : }
1565 : break;
1566 :
1567 : case 0xDC:
1568 : has_register = true;
1569 0 : switch (modrm_byte & 0xF8) {
1570 : case 0xC0: mnem = "fadd"; break;
1571 0 : case 0xE8: mnem = "fsub"; break;
1572 0 : case 0xC8: mnem = "fmul"; break;
1573 0 : case 0xF8: mnem = "fdiv"; break;
1574 0 : default: UnimplementedInstruction();
1575 : }
1576 : break;
1577 :
1578 : case 0xDD:
1579 : has_register = true;
1580 0 : switch (modrm_byte & 0xF8) {
1581 : case 0xC0: mnem = "ffree"; break;
1582 0 : case 0xD8: mnem = "fstp"; break;
1583 0 : default: UnimplementedInstruction();
1584 : }
1585 : break;
1586 :
1587 : case 0xDE:
1588 0 : if (modrm_byte == 0xD9) {
1589 : mnem = "fcompp";
1590 : } else {
1591 : has_register = true;
1592 0 : switch (modrm_byte & 0xF8) {
1593 : case 0xC0: mnem = "faddp"; break;
1594 0 : case 0xE8: mnem = "fsubp"; break;
1595 0 : case 0xC8: mnem = "fmulp"; break;
1596 0 : case 0xF8: mnem = "fdivp"; break;
1597 0 : default: UnimplementedInstruction();
1598 : }
1599 : }
1600 : break;
1601 :
1602 : case 0xDF:
1603 0 : if (modrm_byte == 0xE0) {
1604 : mnem = "fnstsw_ax";
1605 0 : } else if ((modrm_byte & 0xF8) == 0xE8) {
1606 : mnem = "fucomip";
1607 : has_register = true;
1608 : }
1609 : break;
1610 :
1611 0 : default: UnimplementedInstruction();
1612 : }
1613 :
1614 0 : if (has_register) {
1615 0 : AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1616 : } else {
1617 0 : AppendToBuffer("%s", mnem);
1618 : }
1619 0 : return 2;
1620 : }
1621 :
1622 :
1623 :
1624 : // Handle all two-byte opcodes, which start with 0x0F.
1625 : // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1626 : // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1627 0 : int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1628 0 : byte opcode = *(data + 1);
1629 0 : byte* current = data + 2;
1630 : // At return, "current" points to the start of the next instruction.
1631 0 : const char* mnemonic = TwoByteMnemonic(opcode);
1632 0 : if (operand_size_ == 0x66) {
1633 : // 0x66 0x0F prefix.
1634 : int mod, regop, rm;
1635 0 : if (opcode == 0x38) {
1636 0 : byte third_byte = *current;
1637 0 : current = data + 3;
1638 0 : get_modrm(*current, &mod, ®op, &rm);
1639 0 : switch (third_byte) {
1640 : #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
1641 : case 0x##opcode: { \
1642 : AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
1643 : current += PrintRightXMMOperand(current); \
1644 : break; \
1645 : }
1646 :
1647 0 : SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
1648 0 : SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
1649 : #undef SSE34_DIS_CASE
1650 : default:
1651 0 : UnimplementedInstruction();
1652 : }
1653 0 : } else if (opcode == 0x3A) {
1654 0 : byte third_byte = *current;
1655 0 : current = data + 3;
1656 0 : if (third_byte == 0x17) {
1657 0 : get_modrm(*current, &mod, ®op, &rm);
1658 0 : AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1659 0 : current += PrintRightOperand(current);
1660 0 : AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1661 0 : current += 1;
1662 0 : } else if (third_byte == 0x0a) {
1663 0 : get_modrm(*current, &mod, ®op, &rm);
1664 0 : AppendToBuffer("roundss %s,", NameOfXMMRegister(regop));
1665 0 : current += PrintRightXMMOperand(current);
1666 0 : AppendToBuffer(",0x%x", (*current) & 3);
1667 0 : current += 1;
1668 0 : } else if (third_byte == 0x0b) {
1669 0 : get_modrm(*current, &mod, ®op, &rm);
1670 : // roundsd xmm, xmm/m64, imm8
1671 0 : AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1672 0 : current += PrintRightXMMOperand(current);
1673 0 : AppendToBuffer(",0x%x", (*current) & 3);
1674 0 : current += 1;
1675 0 : } else if (third_byte == 0x14) {
1676 0 : get_modrm(*current, &mod, ®op, &rm);
1677 0 : AppendToBuffer("pextrb "); // reg/m32, xmm, imm8
1678 0 : current += PrintRightOperand(current);
1679 0 : AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1680 0 : current += 1;
1681 0 : } else if (third_byte == 0x15) {
1682 0 : get_modrm(*current, &mod, ®op, &rm);
1683 0 : AppendToBuffer("pextrw "); // reg/m32, xmm, imm8
1684 0 : current += PrintRightOperand(current);
1685 0 : AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
1686 0 : current += 1;
1687 0 : } else if (third_byte == 0x16) {
1688 0 : get_modrm(*current, &mod, ®op, &rm);
1689 0 : AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
1690 0 : current += PrintRightOperand(current);
1691 0 : AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1692 0 : current += 1;
1693 0 : } else if (third_byte == 0x20) {
1694 0 : get_modrm(*current, &mod, ®op, &rm);
1695 0 : AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
1696 0 : AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1697 0 : current += PrintRightOperand(current);
1698 0 : AppendToBuffer(",%d", (*current) & 3);
1699 0 : current += 1;
1700 0 : } else if (third_byte == 0x21) {
1701 0 : get_modrm(*current, &mod, ®op, &rm);
1702 : // insertps xmm, xmm/m32, imm8
1703 0 : AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
1704 0 : current += PrintRightXMMOperand(current);
1705 0 : AppendToBuffer(",0x%x", (*current) & 3);
1706 0 : current += 1;
1707 0 : } else if (third_byte == 0x22) {
1708 0 : get_modrm(*current, &mod, ®op, &rm);
1709 0 : AppendToBuffer("pinsrd "); // xmm, reg/m32, imm8
1710 0 : AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1711 0 : current += PrintRightOperand(current);
1712 0 : AppendToBuffer(",%d", (*current) & 3);
1713 0 : current += 1;
1714 : } else {
1715 0 : UnimplementedInstruction();
1716 : }
1717 : } else {
1718 0 : get_modrm(*current, &mod, ®op, &rm);
1719 0 : if (opcode == 0x1f) {
1720 0 : current++;
1721 0 : if (rm == 4) { // SIB byte present.
1722 0 : current++;
1723 : }
1724 0 : if (mod == 1) { // Byte displacement.
1725 0 : current += 1;
1726 0 : } else if (mod == 2) { // 32-bit displacement.
1727 0 : current += 4;
1728 : } // else no immediate displacement.
1729 0 : AppendToBuffer("nop");
1730 0 : } else if (opcode == 0x10) {
1731 0 : AppendToBuffer("movupd %s,", NameOfXMMRegister(regop));
1732 0 : current += PrintRightXMMOperand(current);
1733 0 : } else if (opcode == 0x11) {
1734 0 : AppendToBuffer("movupd ");
1735 0 : current += PrintRightXMMOperand(current);
1736 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1737 0 : } else if (opcode == 0x28) {
1738 0 : AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
1739 0 : current += PrintRightXMMOperand(current);
1740 0 : } else if (opcode == 0x29) {
1741 0 : AppendToBuffer("movapd ");
1742 0 : current += PrintRightXMMOperand(current);
1743 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1744 0 : } else if (opcode == 0x6E) {
1745 : AppendToBuffer("mov%c %s,",
1746 : rex_w() ? 'q' : 'd',
1747 0 : NameOfXMMRegister(regop));
1748 0 : current += PrintRightOperand(current);
1749 0 : } else if (opcode == 0x6F) {
1750 : AppendToBuffer("movdqa %s,",
1751 0 : NameOfXMMRegister(regop));
1752 0 : current += PrintRightXMMOperand(current);
1753 0 : } else if (opcode == 0x7E) {
1754 : AppendToBuffer("mov%c ",
1755 0 : rex_w() ? 'q' : 'd');
1756 0 : current += PrintRightOperand(current);
1757 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1758 0 : } else if (opcode == 0x7F) {
1759 0 : AppendToBuffer("movdqa ");
1760 0 : current += PrintRightXMMOperand(current);
1761 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1762 0 : } else if (opcode == 0xD6) {
1763 0 : AppendToBuffer("movq ");
1764 0 : current += PrintRightXMMOperand(current);
1765 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1766 0 : } else if (opcode == 0x50) {
1767 0 : AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1768 0 : current += PrintRightXMMOperand(current);
1769 0 : } else if (opcode == 0x70) {
1770 0 : AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
1771 0 : current += PrintRightXMMOperand(current);
1772 0 : AppendToBuffer(",0x%x", *current);
1773 0 : current += 1;
1774 0 : } else if (opcode == 0x71) {
1775 : current += 1;
1776 0 : AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm),
1777 0 : *current & 0x7f);
1778 0 : current += 1;
1779 0 : } else if (opcode == 0x72) {
1780 : current += 1;
1781 0 : AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm),
1782 0 : *current & 0x7f);
1783 0 : current += 1;
1784 0 : } else if (opcode == 0x73) {
1785 : current += 1;
1786 0 : AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm),
1787 0 : *current & 0x7f);
1788 0 : current += 1;
1789 0 : } else if (opcode == 0xB1) {
1790 0 : current += PrintOperands("cmpxchg", OPER_REG_OP_ORDER, current);
1791 0 : } else if (opcode == 0xC4) {
1792 0 : AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
1793 0 : current += PrintRightOperand(current);
1794 0 : AppendToBuffer(",0x%x", (*current) & 7);
1795 0 : current += 1;
1796 : } else {
1797 : const char* mnemonic = "?";
1798 0 : if (opcode == 0x54) {
1799 : mnemonic = "andpd";
1800 0 : } else if (opcode == 0x56) {
1801 : mnemonic = "orpd";
1802 0 : } else if (opcode == 0x57) {
1803 : mnemonic = "xorpd";
1804 0 : } else if (opcode == 0x5B) {
1805 : mnemonic = "cvtps2dq";
1806 0 : } else if (opcode == 0x2E) {
1807 : mnemonic = "ucomisd";
1808 0 : } else if (opcode == 0x2F) {
1809 : mnemonic = "comisd";
1810 0 : } else if (opcode == 0x64) {
1811 : mnemonic = "pcmpgtb";
1812 0 : } else if (opcode == 0x65) {
1813 : mnemonic = "pcmpgtw";
1814 0 : } else if (opcode == 0x66) {
1815 : mnemonic = "pcmpgtd";
1816 0 : } else if (opcode == 0x74) {
1817 : mnemonic = "pcmpeqb";
1818 0 : } else if (opcode == 0x75) {
1819 : mnemonic = "pcmpeqw";
1820 0 : } else if (opcode == 0x76) {
1821 : mnemonic = "pcmpeqd";
1822 0 : } else if (opcode == 0x62) {
1823 : mnemonic = "punpckldq";
1824 0 : } else if (opcode == 0x63) {
1825 : mnemonic = "packsswb";
1826 0 : } else if (opcode == 0x67) {
1827 : mnemonic = "packuswb";
1828 0 : } else if (opcode == 0x6A) {
1829 : mnemonic = "punpckhdq";
1830 0 : } else if (opcode == 0x6B) {
1831 : mnemonic = "packssdw";
1832 0 : } else if (opcode == 0xD1) {
1833 : mnemonic = "psrlw";
1834 0 : } else if (opcode == 0xD2) {
1835 : mnemonic = "psrld";
1836 0 : } else if (opcode == 0xD5) {
1837 : mnemonic = "pmullw";
1838 0 : } else if (opcode == 0xD7) {
1839 : mnemonic = "pmovmskb";
1840 0 : } else if (opcode == 0xD8) {
1841 : mnemonic = "psubusb";
1842 0 : } else if (opcode == 0xD9) {
1843 : mnemonic = "psubusw";
1844 0 : } else if (opcode == 0xDA) {
1845 : mnemonic = "pminub";
1846 0 : } else if (opcode == 0xDC) {
1847 : mnemonic = "paddusb";
1848 0 : } else if (opcode == 0xDD) {
1849 : mnemonic = "paddusw";
1850 0 : } else if (opcode == 0xDE) {
1851 : mnemonic = "pmaxub";
1852 0 : } else if (opcode == 0xE1) {
1853 : mnemonic = "psraw";
1854 0 : } else if (opcode == 0xE2) {
1855 : mnemonic = "psrad";
1856 0 : } else if (opcode == 0xE8) {
1857 : mnemonic = "psubsb";
1858 0 : } else if (opcode == 0xE9) {
1859 : mnemonic = "psubsw";
1860 0 : } else if (opcode == 0xEA) {
1861 : mnemonic = "pminsw";
1862 0 : } else if (opcode == 0xEC) {
1863 : mnemonic = "paddsb";
1864 0 : } else if (opcode == 0xED) {
1865 : mnemonic = "paddsw";
1866 0 : } else if (opcode == 0xEE) {
1867 : mnemonic = "pmaxsw";
1868 0 : } else if (opcode == 0xEF) {
1869 : mnemonic = "pxor";
1870 0 : } else if (opcode == 0xF1) {
1871 : mnemonic = "psllw";
1872 0 : } else if (opcode == 0xF2) {
1873 : mnemonic = "pslld";
1874 0 : } else if (opcode == 0xF4) {
1875 : mnemonic = "pmuludq";
1876 0 : } else if (opcode == 0xF8) {
1877 : mnemonic = "psubb";
1878 0 : } else if (opcode == 0xF9) {
1879 : mnemonic = "psubw";
1880 0 : } else if (opcode == 0xFA) {
1881 : mnemonic = "psubd";
1882 0 : } else if (opcode == 0xFC) {
1883 : mnemonic = "paddb";
1884 0 : } else if (opcode == 0xFD) {
1885 : mnemonic = "paddw";
1886 0 : } else if (opcode == 0xFE) {
1887 : mnemonic = "paddd";
1888 0 : } else if (opcode == 0xC2) {
1889 : mnemonic = "cmppd";
1890 : } else {
1891 0 : UnimplementedInstruction();
1892 : }
1893 0 : AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1894 0 : current += PrintRightXMMOperand(current);
1895 0 : if (opcode == 0xC2) {
1896 : const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
1897 0 : "neq", "nlt", "nle", "ord"};
1898 0 : AppendToBuffer(", (%s)", pseudo_op[*current]);
1899 0 : current += 1;
1900 : }
1901 : }
1902 : }
1903 0 : } else if (group_1_prefix_ == 0xF2) {
1904 : // Beginning of instructions with prefix 0xF2.
1905 :
1906 0 : if (opcode == 0x11 || opcode == 0x10) {
1907 : // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1908 0 : AppendToBuffer("movsd ");
1909 : int mod, regop, rm;
1910 0 : get_modrm(*current, &mod, ®op, &rm);
1911 0 : if (opcode == 0x11) {
1912 0 : current += PrintRightXMMOperand(current);
1913 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1914 : } else {
1915 0 : AppendToBuffer("%s,", NameOfXMMRegister(regop));
1916 0 : current += PrintRightXMMOperand(current);
1917 : }
1918 0 : } else if (opcode == 0x2A) {
1919 : // CVTSI2SD: integer to XMM double conversion.
1920 : int mod, regop, rm;
1921 0 : get_modrm(*current, &mod, ®op, &rm);
1922 0 : AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1923 0 : current += PrintRightOperand(current);
1924 0 : } else if (opcode == 0x2C) {
1925 : // CVTTSD2SI:
1926 : // Convert with truncation scalar double-precision FP to integer.
1927 : int mod, regop, rm;
1928 0 : get_modrm(*current, &mod, ®op, &rm);
1929 : AppendToBuffer("cvttsd2si%c %s,",
1930 0 : operand_size_code(), NameOfCPURegister(regop));
1931 0 : current += PrintRightXMMOperand(current);
1932 0 : } else if (opcode == 0x2D) {
1933 : // CVTSD2SI: Convert scalar double-precision FP to integer.
1934 : int mod, regop, rm;
1935 0 : get_modrm(*current, &mod, ®op, &rm);
1936 : AppendToBuffer("cvtsd2si%c %s,",
1937 0 : operand_size_code(), NameOfCPURegister(regop));
1938 0 : current += PrintRightXMMOperand(current);
1939 0 : } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1940 : // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1941 : int mod, regop, rm;
1942 0 : get_modrm(*current, &mod, ®op, &rm);
1943 0 : AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1944 0 : current += PrintRightXMMOperand(current);
1945 0 : } else if (opcode == 0x70) {
1946 : int mod, regop, rm;
1947 0 : get_modrm(*current, &mod, ®op, &rm);
1948 0 : AppendToBuffer("pshuflw %s, ", NameOfXMMRegister(regop));
1949 0 : current += PrintRightXMMOperand(current);
1950 0 : AppendToBuffer(", %d", (*current) & 7);
1951 0 : current += 1;
1952 0 : } else if (opcode == 0xC2) {
1953 : // Intel manual 2A, Table 3-18.
1954 : int mod, regop, rm;
1955 0 : get_modrm(*current, &mod, ®op, &rm);
1956 : const char* const pseudo_op[] = {
1957 : "cmpeqsd",
1958 : "cmpltsd",
1959 : "cmplesd",
1960 : "cmpunordsd",
1961 : "cmpneqsd",
1962 : "cmpnltsd",
1963 : "cmpnlesd",
1964 : "cmpordsd"
1965 0 : };
1966 : AppendToBuffer("%s %s,%s",
1967 0 : pseudo_op[current[1]],
1968 : NameOfXMMRegister(regop),
1969 0 : NameOfXMMRegister(rm));
1970 0 : current += 2;
1971 0 : } else if (opcode == 0xF0) {
1972 : int mod, regop, rm;
1973 0 : get_modrm(*current, &mod, ®op, &rm);
1974 0 : AppendToBuffer("lddqu %s,", NameOfXMMRegister(regop));
1975 0 : current += PrintRightOperand(current);
1976 : } else {
1977 0 : UnimplementedInstruction();
1978 : }
1979 0 : } else if (group_1_prefix_ == 0xF3) {
1980 : // Instructions with prefix 0xF3.
1981 0 : if (opcode == 0x11 || opcode == 0x10) {
1982 : // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1983 0 : AppendToBuffer("movss ");
1984 : int mod, regop, rm;
1985 0 : get_modrm(*current, &mod, ®op, &rm);
1986 0 : if (opcode == 0x11) {
1987 0 : current += PrintRightOperand(current);
1988 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
1989 : } else {
1990 0 : AppendToBuffer("%s,", NameOfXMMRegister(regop));
1991 0 : current += PrintRightOperand(current);
1992 : }
1993 0 : } else if (opcode == 0x2A) {
1994 : // CVTSI2SS: integer to XMM single conversion.
1995 : int mod, regop, rm;
1996 0 : get_modrm(*current, &mod, ®op, &rm);
1997 0 : AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1998 0 : current += PrintRightOperand(current);
1999 0 : } else if (opcode == 0x2C) {
2000 : // CVTTSS2SI:
2001 : // Convert with truncation scalar single-precision FP to dword integer.
2002 : int mod, regop, rm;
2003 0 : get_modrm(*current, &mod, ®op, &rm);
2004 : AppendToBuffer("cvttss2si%c %s,",
2005 0 : operand_size_code(), NameOfCPURegister(regop));
2006 0 : current += PrintRightXMMOperand(current);
2007 0 : } else if (opcode == 0x70) {
2008 : int mod, regop, rm;
2009 0 : get_modrm(*current, &mod, ®op, &rm);
2010 0 : AppendToBuffer("pshufhw %s, ", NameOfXMMRegister(regop));
2011 0 : current += PrintRightXMMOperand(current);
2012 0 : AppendToBuffer(", %d", (*current) & 7);
2013 0 : current += 1;
2014 0 : } else if (opcode == 0x7E) {
2015 : int mod, regop, rm;
2016 0 : get_modrm(*current, &mod, ®op, &rm);
2017 0 : AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
2018 0 : current += PrintRightXMMOperand(current);
2019 0 : } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
2020 : // XMM arithmetic. Mnemonic was retrieved at the start of this function.
2021 : int mod, regop, rm;
2022 0 : get_modrm(*current, &mod, ®op, &rm);
2023 0 : AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
2024 0 : current += PrintRightXMMOperand(current);
2025 0 : } else if (opcode == 0xB8) {
2026 : int mod, regop, rm;
2027 0 : get_modrm(*current, &mod, ®op, &rm);
2028 : AppendToBuffer("popcnt%c %s,", operand_size_code(),
2029 0 : NameOfCPURegister(regop));
2030 0 : current += PrintRightOperand(current);
2031 0 : } else if (opcode == 0xBC) {
2032 : int mod, regop, rm;
2033 0 : get_modrm(*current, &mod, ®op, &rm);
2034 : AppendToBuffer("tzcnt%c %s,", operand_size_code(),
2035 0 : NameOfCPURegister(regop));
2036 0 : current += PrintRightOperand(current);
2037 0 : } else if (opcode == 0xBD) {
2038 : int mod, regop, rm;
2039 0 : get_modrm(*current, &mod, ®op, &rm);
2040 : AppendToBuffer("lzcnt%c %s,", operand_size_code(),
2041 0 : NameOfCPURegister(regop));
2042 0 : current += PrintRightOperand(current);
2043 0 : } else if (opcode == 0xC2) {
2044 : // Intel manual 2A, Table 3-18.
2045 : int mod, regop, rm;
2046 0 : get_modrm(*current, &mod, ®op, &rm);
2047 : const char* const pseudo_op[] = {"cmpeqss", "cmpltss", "cmpless",
2048 : "cmpunordss", "cmpneqss", "cmpnltss",
2049 0 : "cmpnless", "cmpordss"};
2050 0 : AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
2051 0 : NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2052 0 : current += 2;
2053 : } else {
2054 0 : UnimplementedInstruction();
2055 : }
2056 0 : } else if (opcode == 0x10 || opcode == 0x11) {
2057 : // movups xmm, xmm/m128
2058 : // movups xmm/m128, xmm
2059 : int mod, regop, rm;
2060 0 : get_modrm(*current, &mod, ®op, &rm);
2061 0 : AppendToBuffer("movups ");
2062 0 : if (opcode == 0x11) {
2063 0 : current += PrintRightXMMOperand(current);
2064 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
2065 : } else {
2066 0 : AppendToBuffer("%s,", NameOfXMMRegister(regop));
2067 0 : current += PrintRightXMMOperand(current);
2068 : }
2069 0 : } else if (opcode == 0x1F) {
2070 : // NOP
2071 : int mod, regop, rm;
2072 0 : get_modrm(*current, &mod, ®op, &rm);
2073 0 : current++;
2074 0 : if (rm == 4) { // SIB byte present.
2075 0 : current++;
2076 : }
2077 0 : if (mod == 1) { // Byte displacement.
2078 0 : current += 1;
2079 0 : } else if (mod == 2) { // 32-bit displacement.
2080 0 : current += 4;
2081 : } // else no immediate displacement.
2082 0 : AppendToBuffer("nop");
2083 :
2084 0 : } else if (opcode == 0x28) {
2085 : // movaps xmm, xmm/m128
2086 : int mod, regop, rm;
2087 0 : get_modrm(*current, &mod, ®op, &rm);
2088 0 : AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
2089 0 : current += PrintRightXMMOperand(current);
2090 :
2091 0 : } else if (opcode == 0x29) {
2092 : // movaps xmm/m128, xmm
2093 : int mod, regop, rm;
2094 0 : get_modrm(*current, &mod, ®op, &rm);
2095 0 : AppendToBuffer("movaps ");
2096 0 : current += PrintRightXMMOperand(current);
2097 0 : AppendToBuffer(",%s", NameOfXMMRegister(regop));
2098 :
2099 0 : } else if (opcode == 0x2e) {
2100 : int mod, regop, rm;
2101 0 : get_modrm(*current, &mod, ®op, &rm);
2102 0 : AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
2103 0 : current += PrintRightXMMOperand(current);
2104 0 : } else if (opcode == 0xA2) {
2105 : // CPUID
2106 0 : AppendToBuffer("%s", mnemonic);
2107 :
2108 0 : } else if ((opcode & 0xF0) == 0x40) {
2109 : // CMOVcc: conditional move.
2110 0 : int condition = opcode & 0x0F;
2111 0 : const InstructionDesc& idesc = cmov_instructions[condition];
2112 0 : byte_size_operand_ = idesc.byte_size_operation;
2113 0 : current += PrintOperands(idesc.mnem, idesc.op_order_, current);
2114 :
2115 0 : } else if (opcode >= 0x51 && opcode <= 0x5F) {
2116 : const char* const pseudo_op[] = {
2117 : "sqrtps", "rsqrtps", "rcpps", "andps", "andnps",
2118 : "orps", "xorps", "addps", "mulps", "cvtps2pd",
2119 : "cvtdq2ps", "subps", "minps", "divps", "maxps",
2120 0 : };
2121 : int mod, regop, rm;
2122 0 : get_modrm(*current, &mod, ®op, &rm);
2123 0 : AppendToBuffer("%s %s,", pseudo_op[opcode - 0x51],
2124 0 : NameOfXMMRegister(regop));
2125 0 : current += PrintRightXMMOperand(current);
2126 :
2127 0 : } else if (opcode == 0xC2) {
2128 : // cmpps xmm, xmm/m128, imm8
2129 : int mod, regop, rm;
2130 0 : get_modrm(*current, &mod, ®op, &rm);
2131 : const char* const pseudo_op[] = {"eq", "lt", "le", "unord",
2132 0 : "neq", "nlt", "nle", "ord"};
2133 0 : AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
2134 0 : current += PrintRightXMMOperand(current);
2135 0 : AppendToBuffer(", %s", pseudo_op[*current]);
2136 0 : current += 1;
2137 0 : } else if (opcode == 0xC6) {
2138 : // shufps xmm, xmm/m128, imm8
2139 : int mod, regop, rm;
2140 0 : get_modrm(*current, &mod, ®op, &rm);
2141 0 : AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
2142 0 : current += PrintRightXMMOperand(current);
2143 0 : AppendToBuffer(", %d", (*current) & 3);
2144 0 : current += 1;
2145 0 : } else if (opcode == 0x50) {
2146 : // movmskps reg, xmm
2147 : int mod, regop, rm;
2148 0 : get_modrm(*current, &mod, ®op, &rm);
2149 0 : AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
2150 0 : current += PrintRightXMMOperand(current);
2151 0 : } else if (opcode == 0x70) {
2152 : int mod, regop, rm;
2153 0 : get_modrm(*current, &mod, ®op, &rm);
2154 0 : AppendToBuffer("pshufw %s, ", NameOfXMMRegister(regop));
2155 0 : current += PrintRightXMMOperand(current);
2156 0 : AppendToBuffer(", %d", (*current) & 3);
2157 0 : current += 1;
2158 0 : } else if ((opcode & 0xF0) == 0x80) {
2159 : // Jcc: Conditional jump (branch).
2160 0 : current = data + JumpConditional(data);
2161 :
2162 0 : } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
2163 0 : opcode == 0xB7 || opcode == 0xAF) {
2164 : // Size-extending moves, IMUL.
2165 0 : current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
2166 :
2167 0 : } else if ((opcode & 0xF0) == 0x90) {
2168 : // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
2169 0 : current = data + SetCC(data);
2170 :
2171 0 : } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
2172 : // SHLD, SHRD (double-precision shift), BTS (bit set).
2173 0 : AppendToBuffer("%s ", mnemonic);
2174 : int mod, regop, rm;
2175 0 : get_modrm(*current, &mod, ®op, &rm);
2176 0 : current += PrintRightOperand(current);
2177 0 : if (opcode == 0xAB) {
2178 0 : AppendToBuffer(",%s", NameOfCPURegister(regop));
2179 : } else {
2180 0 : AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
2181 : }
2182 0 : } else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
2183 : // POPCNT, CTZ, CLZ.
2184 0 : AppendToBuffer("%s%c ", mnemonic, operand_size_code());
2185 : int mod, regop, rm;
2186 0 : get_modrm(*current, &mod, ®op, &rm);
2187 0 : AppendToBuffer("%s,", NameOfCPURegister(regop));
2188 0 : current += PrintRightOperand(current);
2189 0 : } else if (opcode == 0x0B) {
2190 0 : AppendToBuffer("ud2");
2191 0 : } else if (opcode == 0xB0 || opcode == 0xB1) {
2192 : // CMPXCHG.
2193 0 : if (opcode == 0xB0) {
2194 0 : byte_size_operand_ = true;
2195 : }
2196 0 : current += PrintOperands(mnemonic, OPER_REG_OP_ORDER, current);
2197 : } else {
2198 0 : UnimplementedInstruction();
2199 : }
2200 0 : return static_cast<int>(current - data);
2201 : }
2202 :
2203 :
2204 : // Mnemonics for two-byte opcode instructions starting with 0x0F.
2205 : // The argument is the second byte of the two-byte opcode.
2206 : // Returns NULL if the instruction is not handled here.
2207 0 : const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
2208 0 : switch (opcode) {
2209 : case 0x1F:
2210 : return "nop";
2211 : case 0x2A: // F2/F3 prefix.
2212 0 : return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
2213 : case 0x51: // F2/F3 prefix.
2214 0 : return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
2215 : case 0x58: // F2/F3 prefix.
2216 0 : return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
2217 : case 0x59: // F2/F3 prefix.
2218 0 : return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
2219 : case 0x5A: // F2/F3 prefix.
2220 0 : return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
2221 : case 0x5D: // F2/F3 prefix.
2222 0 : return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
2223 : case 0x5C: // F2/F3 prefix.
2224 0 : return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
2225 : case 0x5E: // F2/F3 prefix.
2226 0 : return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
2227 : case 0x5F: // F2/F3 prefix.
2228 0 : return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
2229 : case 0xA2:
2230 0 : return "cpuid";
2231 : case 0xA5:
2232 0 : return "shld";
2233 : case 0xAB:
2234 0 : return "bts";
2235 : case 0xAD:
2236 0 : return "shrd";
2237 : case 0xAF:
2238 0 : return "imul";
2239 : case 0xB0:
2240 : case 0xB1:
2241 0 : return "cmpxchg";
2242 : case 0xB6:
2243 0 : return "movzxb";
2244 : case 0xB7:
2245 0 : return "movzxw";
2246 : case 0xBC:
2247 0 : return "bsf";
2248 : case 0xBD:
2249 0 : return "bsr";
2250 : case 0xBE:
2251 0 : return "movsxb";
2252 : case 0xBF:
2253 0 : return "movsxw";
2254 : default:
2255 0 : return NULL;
2256 : }
2257 : }
2258 :
2259 :
2260 : // Disassembles the instruction at instr, and writes it into out_buffer.
2261 0 : int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
2262 0 : byte* instr) {
2263 0 : tmp_buffer_pos_ = 0; // starting to write as position 0
2264 : byte* data = instr;
2265 : bool processed = true; // Will be set to false if the current instruction
2266 : // is not in 'instructions' table.
2267 : byte current;
2268 :
2269 : // Scan for prefixes.
2270 : while (true) {
2271 0 : current = *data;
2272 0 : if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
2273 0 : operand_size_ = current;
2274 0 : } else if ((current & 0xF0) == 0x40) { // REX prefix.
2275 : setRex(current);
2276 0 : if (rex_w()) AppendToBuffer("REX.W ");
2277 0 : } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
2278 0 : group_1_prefix_ = current;
2279 0 : } else if (current == LOCK_PREFIX) {
2280 0 : AppendToBuffer("lock ");
2281 0 : } else if (current == VEX3_PREFIX) {
2282 0 : vex_byte0_ = current;
2283 0 : vex_byte1_ = *(data + 1);
2284 0 : vex_byte2_ = *(data + 2);
2285 0 : setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
2286 0 : data += 3;
2287 0 : break; // Vex is the last prefix.
2288 0 : } else if (current == VEX2_PREFIX) {
2289 0 : vex_byte0_ = current;
2290 0 : vex_byte1_ = *(data + 1);
2291 0 : setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
2292 0 : data += 2;
2293 0 : break; // Vex is the last prefix.
2294 : } else { // Not a prefix - an opcode.
2295 : break;
2296 : }
2297 0 : data++;
2298 : }
2299 :
2300 : // Decode AVX instructions.
2301 0 : if (vex_byte0_ != 0) {
2302 : processed = true;
2303 0 : data += AVXInstruction(data);
2304 : } else {
2305 0 : const InstructionDesc& idesc = instruction_table_->Get(current);
2306 0 : byte_size_operand_ = idesc.byte_size_operation;
2307 0 : switch (idesc.type) {
2308 : case ZERO_OPERANDS_INSTR:
2309 0 : if (current >= 0xA4 && current <= 0xA7) {
2310 : // String move or compare operations.
2311 0 : if (group_1_prefix_ == REP_PREFIX) {
2312 : // REP.
2313 0 : AppendToBuffer("rep ");
2314 : }
2315 0 : if (rex_w()) AppendToBuffer("REX.W ");
2316 0 : AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2317 : } else {
2318 0 : AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2319 : }
2320 0 : data++;
2321 0 : break;
2322 :
2323 : case TWO_OPERANDS_INSTR:
2324 0 : data++;
2325 0 : data += PrintOperands(idesc.mnem, idesc.op_order_, data);
2326 0 : break;
2327 :
2328 : case JUMP_CONDITIONAL_SHORT_INSTR:
2329 0 : data += JumpConditionalShort(data);
2330 0 : break;
2331 :
2332 : case REGISTER_INSTR:
2333 : AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
2334 0 : NameOfCPURegister(base_reg(current & 0x07)));
2335 0 : data++;
2336 0 : break;
2337 : case PUSHPOP_INSTR:
2338 : AppendToBuffer("%s %s", idesc.mnem,
2339 0 : NameOfCPURegister(base_reg(current & 0x07)));
2340 0 : data++;
2341 0 : break;
2342 : case MOVE_REG_INSTR: {
2343 : byte* addr = NULL;
2344 0 : switch (operand_size()) {
2345 : case OPERAND_WORD_SIZE:
2346 : addr =
2347 0 : reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
2348 0 : data += 3;
2349 0 : break;
2350 : case OPERAND_DOUBLEWORD_SIZE:
2351 : addr =
2352 0 : reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
2353 0 : data += 5;
2354 0 : break;
2355 : case OPERAND_QUADWORD_SIZE:
2356 : addr =
2357 0 : reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
2358 0 : data += 9;
2359 0 : break;
2360 : default:
2361 0 : UNREACHABLE();
2362 : }
2363 : AppendToBuffer("mov%c %s,%s", operand_size_code(),
2364 : NameOfCPURegister(base_reg(current & 0x07)),
2365 0 : NameOfAddress(addr));
2366 0 : break;
2367 : }
2368 :
2369 : case CALL_JUMP_INSTR: {
2370 0 : byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
2371 0 : AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
2372 0 : data += 5;
2373 0 : break;
2374 : }
2375 :
2376 : case SHORT_IMMEDIATE_INSTR: {
2377 : byte* addr =
2378 0 : reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
2379 0 : AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
2380 0 : data += 5;
2381 0 : break;
2382 : }
2383 :
2384 : case NO_INSTR:
2385 : processed = false;
2386 : break;
2387 :
2388 : default:
2389 0 : UNIMPLEMENTED(); // This type is not implemented.
2390 : }
2391 : }
2392 :
2393 : // The first byte didn't match any of the simple opcodes, so we
2394 : // need to do special processing on it.
2395 0 : if (!processed) {
2396 0 : switch (*data) {
2397 : case 0xC2:
2398 0 : AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
2399 0 : data += 3;
2400 0 : break;
2401 :
2402 : case 0x69: // fall through
2403 : case 0x6B: {
2404 : int count = 1;
2405 0 : count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
2406 0 : AppendToBuffer(",0x");
2407 0 : if (*data == 0x69) {
2408 0 : count += PrintImmediate(data + count, operand_size());
2409 : } else {
2410 0 : count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
2411 : }
2412 0 : data += count;
2413 0 : break;
2414 : }
2415 :
2416 : case 0x81: // fall through
2417 : case 0x83: // 0x81 with sign extension bit set
2418 0 : data += PrintImmediateOp(data);
2419 0 : break;
2420 :
2421 : case 0x0F:
2422 0 : data += TwoByteOpcodeInstruction(data);
2423 0 : break;
2424 :
2425 : case 0x8F: {
2426 0 : data++;
2427 : int mod, regop, rm;
2428 0 : get_modrm(*data, &mod, ®op, &rm);
2429 0 : if (regop == 0) {
2430 0 : AppendToBuffer("pop ");
2431 0 : data += PrintRightOperand(data);
2432 : }
2433 : }
2434 : break;
2435 :
2436 : case 0xFF: {
2437 0 : data++;
2438 : int mod, regop, rm;
2439 0 : get_modrm(*data, &mod, ®op, &rm);
2440 : const char* mnem = NULL;
2441 : switch (regop) {
2442 : case 0:
2443 : mnem = "inc";
2444 : break;
2445 : case 1:
2446 : mnem = "dec";
2447 : break;
2448 : case 2:
2449 : mnem = "call";
2450 : break;
2451 : case 4:
2452 : mnem = "jmp";
2453 : break;
2454 : case 6:
2455 : mnem = "push";
2456 : break;
2457 : default:
2458 : mnem = "???";
2459 : }
2460 0 : if (regop <= 1) {
2461 0 : AppendToBuffer("%s%c ", mnem, operand_size_code());
2462 : } else {
2463 0 : AppendToBuffer("%s ", mnem);
2464 : }
2465 0 : data += PrintRightOperand(data);
2466 : }
2467 0 : break;
2468 :
2469 : case 0xC7: // imm32, fall through
2470 : case 0xC6: // imm8
2471 : {
2472 : bool is_byte = *data == 0xC6;
2473 0 : data++;
2474 0 : if (is_byte) {
2475 0 : AppendToBuffer("movb ");
2476 0 : data += PrintRightByteOperand(data);
2477 0 : int32_t imm = *data;
2478 0 : AppendToBuffer(",0x%x", imm);
2479 0 : data++;
2480 : } else {
2481 0 : AppendToBuffer("mov%c ", operand_size_code());
2482 0 : data += PrintRightOperand(data);
2483 0 : if (operand_size() == OPERAND_WORD_SIZE) {
2484 0 : int16_t imm = *reinterpret_cast<int16_t*>(data);
2485 0 : AppendToBuffer(",0x%x", imm);
2486 0 : data += 2;
2487 : } else {
2488 0 : int32_t imm = *reinterpret_cast<int32_t*>(data);
2489 0 : AppendToBuffer(",0x%x", imm);
2490 0 : data += 4;
2491 : }
2492 : }
2493 : }
2494 : break;
2495 :
2496 : case 0x80: {
2497 0 : data++;
2498 0 : AppendToBuffer("cmpb ");
2499 0 : data += PrintRightByteOperand(data);
2500 0 : int32_t imm = *data;
2501 0 : AppendToBuffer(",0x%x", imm);
2502 0 : data++;
2503 : }
2504 0 : break;
2505 :
2506 : case 0x88: // 8bit, fall through
2507 : case 0x89: // 32bit
2508 : {
2509 : bool is_byte = *data == 0x88;
2510 : int mod, regop, rm;
2511 0 : data++;
2512 0 : get_modrm(*data, &mod, ®op, &rm);
2513 0 : if (is_byte) {
2514 0 : AppendToBuffer("movb ");
2515 0 : data += PrintRightByteOperand(data);
2516 0 : AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2517 : } else {
2518 0 : AppendToBuffer("mov%c ", operand_size_code());
2519 0 : data += PrintRightOperand(data);
2520 0 : AppendToBuffer(",%s", NameOfCPURegister(regop));
2521 : }
2522 : }
2523 : break;
2524 :
2525 : case 0x90:
2526 : case 0x91:
2527 : case 0x92:
2528 : case 0x93:
2529 : case 0x94:
2530 : case 0x95:
2531 : case 0x96:
2532 : case 0x97: {
2533 0 : int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
2534 0 : if (reg == 0) {
2535 0 : AppendToBuffer("nop"); // Common name for xchg rax,rax.
2536 : } else {
2537 : AppendToBuffer("xchg%c rax,%s",
2538 : operand_size_code(),
2539 0 : NameOfCPURegister(reg));
2540 : }
2541 0 : data++;
2542 : }
2543 0 : break;
2544 : case 0xB0:
2545 : case 0xB1:
2546 : case 0xB2:
2547 : case 0xB3:
2548 : case 0xB4:
2549 : case 0xB5:
2550 : case 0xB6:
2551 : case 0xB7:
2552 : case 0xB8:
2553 : case 0xB9:
2554 : case 0xBA:
2555 : case 0xBB:
2556 : case 0xBC:
2557 : case 0xBD:
2558 : case 0xBE:
2559 : case 0xBF: {
2560 : // mov reg8,imm8 or mov reg32,imm32
2561 : byte opcode = *data;
2562 0 : data++;
2563 : bool is_32bit = (opcode >= 0xB8);
2564 0 : int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
2565 0 : if (is_32bit) {
2566 : AppendToBuffer("mov%c %s,",
2567 : operand_size_code(),
2568 0 : NameOfCPURegister(reg));
2569 0 : data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
2570 : } else {
2571 : AppendToBuffer("movb %s,",
2572 0 : NameOfByteCPURegister(reg));
2573 0 : data += PrintImmediate(data, OPERAND_BYTE_SIZE);
2574 : }
2575 : break;
2576 : }
2577 : case 0xFE: {
2578 0 : data++;
2579 : int mod, regop, rm;
2580 0 : get_modrm(*data, &mod, ®op, &rm);
2581 0 : if (regop == 1) {
2582 0 : AppendToBuffer("decb ");
2583 0 : data += PrintRightByteOperand(data);
2584 : } else {
2585 0 : UnimplementedInstruction();
2586 : }
2587 : break;
2588 : }
2589 : case 0x68:
2590 0 : AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
2591 0 : data += 5;
2592 0 : break;
2593 :
2594 : case 0x6A:
2595 0 : AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
2596 0 : data += 2;
2597 0 : break;
2598 :
2599 : case 0xA1: // Fall through.
2600 : case 0xA3:
2601 0 : switch (operand_size()) {
2602 : case OPERAND_DOUBLEWORD_SIZE: {
2603 : const char* memory_location = NameOfAddress(
2604 : reinterpret_cast<byte*>(
2605 0 : *reinterpret_cast<int32_t*>(data + 1)));
2606 0 : if (*data == 0xA1) { // Opcode 0xA1
2607 0 : AppendToBuffer("movzxlq rax,(%s)", memory_location);
2608 : } else { // Opcode 0xA3
2609 0 : AppendToBuffer("movzxlq (%s),rax", memory_location);
2610 : }
2611 0 : data += 5;
2612 0 : break;
2613 : }
2614 : case OPERAND_QUADWORD_SIZE: {
2615 : // New x64 instruction mov rax,(imm_64).
2616 : const char* memory_location = NameOfAddress(
2617 0 : *reinterpret_cast<byte**>(data + 1));
2618 0 : if (*data == 0xA1) { // Opcode 0xA1
2619 0 : AppendToBuffer("movq rax,(%s)", memory_location);
2620 : } else { // Opcode 0xA3
2621 0 : AppendToBuffer("movq (%s),rax", memory_location);
2622 : }
2623 0 : data += 9;
2624 0 : break;
2625 : }
2626 : default:
2627 0 : UnimplementedInstruction();
2628 0 : data += 2;
2629 : }
2630 : break;
2631 :
2632 : case 0xA8:
2633 0 : AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
2634 0 : data += 2;
2635 0 : break;
2636 :
2637 : case 0xA9: {
2638 : int64_t value = 0;
2639 0 : switch (operand_size()) {
2640 : case OPERAND_WORD_SIZE:
2641 0 : value = *reinterpret_cast<uint16_t*>(data + 1);
2642 0 : data += 3;
2643 0 : break;
2644 : case OPERAND_DOUBLEWORD_SIZE:
2645 0 : value = *reinterpret_cast<uint32_t*>(data + 1);
2646 0 : data += 5;
2647 0 : break;
2648 : case OPERAND_QUADWORD_SIZE:
2649 0 : value = *reinterpret_cast<int32_t*>(data + 1);
2650 0 : data += 5;
2651 0 : break;
2652 : default:
2653 0 : UNREACHABLE();
2654 : }
2655 0 : AppendToBuffer("test%c rax,0x%" PRIx64, operand_size_code(), value);
2656 0 : break;
2657 : }
2658 : case 0xD1: // fall through
2659 : case 0xD3: // fall through
2660 : case 0xC1:
2661 0 : data += ShiftInstruction(data);
2662 0 : break;
2663 : case 0xD0: // fall through
2664 : case 0xD2: // fall through
2665 : case 0xC0:
2666 0 : byte_size_operand_ = true;
2667 0 : data += ShiftInstruction(data);
2668 0 : break;
2669 :
2670 : case 0xD9: // fall through
2671 : case 0xDA: // fall through
2672 : case 0xDB: // fall through
2673 : case 0xDC: // fall through
2674 : case 0xDD: // fall through
2675 : case 0xDE: // fall through
2676 : case 0xDF:
2677 0 : data += FPUInstruction(data);
2678 0 : break;
2679 :
2680 : case 0xEB:
2681 0 : data += JumpShort(data);
2682 0 : break;
2683 :
2684 : case 0xF6:
2685 0 : byte_size_operand_ = true; // fall through
2686 : case 0xF7:
2687 0 : data += F6F7Instruction(data);
2688 0 : break;
2689 :
2690 : case 0x3C:
2691 0 : AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
2692 0 : data +=2;
2693 0 : break;
2694 :
2695 : default:
2696 0 : UnimplementedInstruction();
2697 0 : data += 1;
2698 : }
2699 : } // !processed
2700 :
2701 0 : if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2702 0 : tmp_buffer_[tmp_buffer_pos_] = '\0';
2703 : }
2704 :
2705 0 : int instr_len = static_cast<int>(data - instr);
2706 : DCHECK(instr_len > 0); // Ensure progress.
2707 :
2708 : int outp = 0;
2709 : // Instruction bytes.
2710 0 : for (byte* bp = instr; bp < data; bp++) {
2711 0 : outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2712 : }
2713 0 : for (int i = 6 - instr_len; i >= 0; i--) {
2714 0 : outp += v8::internal::SNPrintF(out_buffer + outp, " ");
2715 : }
2716 :
2717 : outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
2718 0 : tmp_buffer_.start());
2719 0 : return instr_len;
2720 : }
2721 :
2722 :
2723 : //------------------------------------------------------------------------------
2724 :
2725 :
2726 : static const char* const cpu_regs[16] = {
2727 : "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2728 : "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
2729 : };
2730 :
2731 :
2732 : static const char* const byte_cpu_regs[16] = {
2733 : "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
2734 : "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
2735 : };
2736 :
2737 :
2738 : static const char* const xmm_regs[16] = {
2739 : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
2740 : "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
2741 : };
2742 :
2743 :
2744 0 : const char* NameConverter::NameOfAddress(byte* addr) const {
2745 0 : v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
2746 0 : return tmp_buffer_.start();
2747 : }
2748 :
2749 :
2750 0 : const char* NameConverter::NameOfConstant(byte* addr) const {
2751 0 : return NameOfAddress(addr);
2752 : }
2753 :
2754 :
2755 0 : const char* NameConverter::NameOfCPURegister(int reg) const {
2756 0 : if (0 <= reg && reg < 16)
2757 0 : return cpu_regs[reg];
2758 : return "noreg";
2759 : }
2760 :
2761 :
2762 0 : const char* NameConverter::NameOfByteCPURegister(int reg) const {
2763 0 : if (0 <= reg && reg < 16)
2764 0 : return byte_cpu_regs[reg];
2765 : return "noreg";
2766 : }
2767 :
2768 :
2769 0 : const char* NameConverter::NameOfXMMRegister(int reg) const {
2770 0 : if (0 <= reg && reg < 16)
2771 0 : return xmm_regs[reg];
2772 : return "noxmmreg";
2773 : }
2774 :
2775 :
2776 0 : const char* NameConverter::NameInCode(byte* addr) const {
2777 : // X64 does not embed debug strings at the moment.
2778 0 : UNREACHABLE();
2779 : return "";
2780 : }
2781 :
2782 :
2783 : //------------------------------------------------------------------------------
2784 :
2785 0 : Disassembler::Disassembler(const NameConverter& converter)
2786 0 : : converter_(converter) { }
2787 :
2788 0 : Disassembler::~Disassembler() { }
2789 :
2790 :
2791 0 : int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2792 : byte* instruction) {
2793 0 : DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
2794 0 : return d.InstructionDecode(buffer, instruction);
2795 : }
2796 :
2797 :
2798 : // The X64 assembler does not use constant pools.
2799 0 : int Disassembler::ConstantPoolSizeAt(byte* instruction) {
2800 0 : return -1;
2801 : }
2802 :
2803 :
2804 0 : void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
2805 : NameConverter converter;
2806 : Disassembler d(converter);
2807 0 : for (byte* pc = begin; pc < end;) {
2808 : v8::internal::EmbeddedVector<char, 128> buffer;
2809 0 : buffer[0] = '\0';
2810 : byte* prev_pc = pc;
2811 0 : pc += d.InstructionDecode(buffer, pc);
2812 : fprintf(f, "%p", static_cast<void*>(prev_pc));
2813 : fprintf(f, " ");
2814 :
2815 0 : for (byte* bp = prev_pc; bp < pc; bp++) {
2816 0 : fprintf(f, "%02x", *bp);
2817 : }
2818 0 : for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
2819 : fprintf(f, " ");
2820 : }
2821 0 : fprintf(f, " %s\n", buffer.start());
2822 : }
2823 0 : }
2824 :
2825 : } // namespace disasm
2826 :
2827 : #endif // V8_TARGET_ARCH_X64
|