Bug Summary

File:out/../deps/v8/src/diagnostics/x64/disasm-x64.cc
Warning:line 1280, column 9
Value stored to 'mnem' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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