1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2012 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "disassembler_x86.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <inttypes.h>
20*795d594fSAndroid Build Coastguard Worker
21*795d594fSAndroid Build Coastguard Worker #include <ostream>
22*795d594fSAndroid Build Coastguard Worker #include <sstream>
23*795d594fSAndroid Build Coastguard Worker
24*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
25*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker #define TWO_BYTE_VEX 0xC5
28*795d594fSAndroid Build Coastguard Worker #define THREE_BYTE_VEX 0xC4
29*795d594fSAndroid Build Coastguard Worker #define VEX_M_0F 0x01
30*795d594fSAndroid Build Coastguard Worker #define VEX_M_0F_38 0x02
31*795d594fSAndroid Build Coastguard Worker #define VEX_M_0F_3A 0x03
32*795d594fSAndroid Build Coastguard Worker #define VEX_PP_NONE 0x00
33*795d594fSAndroid Build Coastguard Worker #define VEX_PP_66 0x01
34*795d594fSAndroid Build Coastguard Worker #define VEX_PP_F3 0x02
35*795d594fSAndroid Build Coastguard Worker #define VEX_PP_F2 0x03
36*795d594fSAndroid Build Coastguard Worker
37*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
38*795d594fSAndroid Build Coastguard Worker
39*795d594fSAndroid Build Coastguard Worker namespace art {
40*795d594fSAndroid Build Coastguard Worker namespace x86 {
41*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os,const uint8_t * begin)42*795d594fSAndroid Build Coastguard Worker size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) {
43*795d594fSAndroid Build Coastguard Worker return DumpInstruction(os, begin);
44*795d594fSAndroid Build Coastguard Worker }
45*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os,const uint8_t * begin,const uint8_t * end)46*795d594fSAndroid Build Coastguard Worker void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
47*795d594fSAndroid Build Coastguard Worker size_t length = 0;
48*795d594fSAndroid Build Coastguard Worker for (const uint8_t* cur = begin; cur < end; cur += length) {
49*795d594fSAndroid Build Coastguard Worker length = DumpInstruction(os, cur);
50*795d594fSAndroid Build Coastguard Worker }
51*795d594fSAndroid Build Coastguard Worker }
52*795d594fSAndroid Build Coastguard Worker
53*795d594fSAndroid Build Coastguard Worker static const char* gReg8Names[] = {
54*795d594fSAndroid Build Coastguard Worker "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
55*795d594fSAndroid Build Coastguard Worker };
56*795d594fSAndroid Build Coastguard Worker static const char* gExtReg8Names[] = {
57*795d594fSAndroid Build Coastguard Worker "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
58*795d594fSAndroid Build Coastguard Worker "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
59*795d594fSAndroid Build Coastguard Worker };
60*795d594fSAndroid Build Coastguard Worker static const char* gReg16Names[] = {
61*795d594fSAndroid Build Coastguard Worker "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
62*795d594fSAndroid Build Coastguard Worker "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
63*795d594fSAndroid Build Coastguard Worker };
64*795d594fSAndroid Build Coastguard Worker static const char* gReg32Names[] = {
65*795d594fSAndroid Build Coastguard Worker "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
66*795d594fSAndroid Build Coastguard Worker "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
67*795d594fSAndroid Build Coastguard Worker };
68*795d594fSAndroid Build Coastguard Worker static const char* gReg64Names[] = {
69*795d594fSAndroid Build Coastguard Worker "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
70*795d594fSAndroid Build Coastguard Worker "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
71*795d594fSAndroid Build Coastguard Worker };
72*795d594fSAndroid Build Coastguard Worker
73*795d594fSAndroid Build Coastguard Worker // 64-bit opcode REX modifier.
74*795d594fSAndroid Build Coastguard Worker constexpr uint8_t REX_W = 8U /* 0b1000 */;
75*795d594fSAndroid Build Coastguard Worker constexpr uint8_t REX_R = 4U /* 0b0100 */;
76*795d594fSAndroid Build Coastguard Worker constexpr uint8_t REX_X = 2U /* 0b0010 */;
77*795d594fSAndroid Build Coastguard Worker constexpr uint8_t REX_B = 1U /* 0b0001 */;
78*795d594fSAndroid Build Coastguard Worker
DumpReg0(std::ostream & os,uint8_t rex,size_t reg,bool byte_operand,uint8_t size_override)79*795d594fSAndroid Build Coastguard Worker static void DumpReg0(std::ostream& os, uint8_t rex, size_t reg,
80*795d594fSAndroid Build Coastguard Worker bool byte_operand, uint8_t size_override) {
81*795d594fSAndroid Build Coastguard Worker DCHECK_LT(reg, (rex == 0) ? 8u : 16u);
82*795d594fSAndroid Build Coastguard Worker bool rex_w = (rex & REX_W) != 0;
83*795d594fSAndroid Build Coastguard Worker if (byte_operand) {
84*795d594fSAndroid Build Coastguard Worker os << ((rex == 0) ? gReg8Names[reg] : gExtReg8Names[reg]);
85*795d594fSAndroid Build Coastguard Worker } else if (rex_w) {
86*795d594fSAndroid Build Coastguard Worker os << gReg64Names[reg];
87*795d594fSAndroid Build Coastguard Worker } else if (size_override == 0x66) {
88*795d594fSAndroid Build Coastguard Worker os << gReg16Names[reg];
89*795d594fSAndroid Build Coastguard Worker } else {
90*795d594fSAndroid Build Coastguard Worker os << gReg32Names[reg];
91*795d594fSAndroid Build Coastguard Worker }
92*795d594fSAndroid Build Coastguard Worker }
93*795d594fSAndroid Build Coastguard Worker
DumpAnyReg(std::ostream & os,uint8_t rex,size_t reg,bool byte_operand,uint8_t size_override,RegFile reg_file)94*795d594fSAndroid Build Coastguard Worker static void DumpAnyReg(std::ostream& os, uint8_t rex, size_t reg,
95*795d594fSAndroid Build Coastguard Worker bool byte_operand, uint8_t size_override, RegFile reg_file) {
96*795d594fSAndroid Build Coastguard Worker if (reg_file == GPR) {
97*795d594fSAndroid Build Coastguard Worker DumpReg0(os, rex, reg, byte_operand, size_override);
98*795d594fSAndroid Build Coastguard Worker } else if (reg_file == SSE) {
99*795d594fSAndroid Build Coastguard Worker os << "xmm" << reg;
100*795d594fSAndroid Build Coastguard Worker } else {
101*795d594fSAndroid Build Coastguard Worker os << "mm" << reg;
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker }
104*795d594fSAndroid Build Coastguard Worker
DumpReg(std::ostream & os,uint8_t rex,uint8_t reg,bool byte_operand,uint8_t size_override,RegFile reg_file)105*795d594fSAndroid Build Coastguard Worker static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
106*795d594fSAndroid Build Coastguard Worker bool byte_operand, uint8_t size_override, RegFile reg_file) {
107*795d594fSAndroid Build Coastguard Worker bool rex_r = (rex & REX_R) != 0;
108*795d594fSAndroid Build Coastguard Worker size_t reg_num = rex_r ? (reg + 8) : reg;
109*795d594fSAndroid Build Coastguard Worker DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker
DumpRmReg(std::ostream & os,uint8_t rex,uint8_t reg,bool byte_operand,uint8_t size_override,RegFile reg_file)112*795d594fSAndroid Build Coastguard Worker static void DumpRmReg(std::ostream& os, uint8_t rex, uint8_t reg,
113*795d594fSAndroid Build Coastguard Worker bool byte_operand, uint8_t size_override, RegFile reg_file) {
114*795d594fSAndroid Build Coastguard Worker bool rex_b = (rex & REX_B) != 0;
115*795d594fSAndroid Build Coastguard Worker size_t reg_num = rex_b ? (reg + 8) : reg;
116*795d594fSAndroid Build Coastguard Worker DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
117*795d594fSAndroid Build Coastguard Worker }
118*795d594fSAndroid Build Coastguard Worker
DumpAddrReg(std::ostream & os,uint8_t rex,uint8_t reg)119*795d594fSAndroid Build Coastguard Worker static void DumpAddrReg(std::ostream& os, uint8_t rex, uint8_t reg) {
120*795d594fSAndroid Build Coastguard Worker if (rex != 0) {
121*795d594fSAndroid Build Coastguard Worker os << gReg64Names[reg];
122*795d594fSAndroid Build Coastguard Worker } else {
123*795d594fSAndroid Build Coastguard Worker os << gReg32Names[reg];
124*795d594fSAndroid Build Coastguard Worker }
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker
DumpBaseReg(std::ostream & os,uint8_t rex,uint8_t reg)127*795d594fSAndroid Build Coastguard Worker static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
128*795d594fSAndroid Build Coastguard Worker bool rex_b = (rex & REX_B) != 0;
129*795d594fSAndroid Build Coastguard Worker size_t reg_num = rex_b ? (reg + 8) : reg;
130*795d594fSAndroid Build Coastguard Worker DumpAddrReg(os, rex, reg_num);
131*795d594fSAndroid Build Coastguard Worker }
132*795d594fSAndroid Build Coastguard Worker
DumpOpcodeReg(std::ostream & os,uint8_t rex,uint8_t reg,bool byte_operand,uint8_t size_override)133*795d594fSAndroid Build Coastguard Worker static void DumpOpcodeReg(std::ostream& os, uint8_t rex, uint8_t reg,
134*795d594fSAndroid Build Coastguard Worker bool byte_operand, uint8_t size_override) {
135*795d594fSAndroid Build Coastguard Worker bool rex_b = (rex & REX_B) != 0;
136*795d594fSAndroid Build Coastguard Worker size_t reg_num = rex_b ? (reg + 8) : reg;
137*795d594fSAndroid Build Coastguard Worker DumpReg0(os, rex, reg_num, byte_operand, size_override);
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker
140*795d594fSAndroid Build Coastguard Worker enum SegmentPrefix {
141*795d594fSAndroid Build Coastguard Worker kCs = 0x2e,
142*795d594fSAndroid Build Coastguard Worker kSs = 0x36,
143*795d594fSAndroid Build Coastguard Worker kDs = 0x3e,
144*795d594fSAndroid Build Coastguard Worker kEs = 0x26,
145*795d594fSAndroid Build Coastguard Worker kFs = 0x64,
146*795d594fSAndroid Build Coastguard Worker kGs = 0x65,
147*795d594fSAndroid Build Coastguard Worker };
148*795d594fSAndroid Build Coastguard Worker
DumpSegmentOverride(std::ostream & os,uint8_t segment_prefix)149*795d594fSAndroid Build Coastguard Worker static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) {
150*795d594fSAndroid Build Coastguard Worker switch (segment_prefix) {
151*795d594fSAndroid Build Coastguard Worker case kCs: os << "cs:"; break;
152*795d594fSAndroid Build Coastguard Worker case kSs: os << "ss:"; break;
153*795d594fSAndroid Build Coastguard Worker case kDs: os << "ds:"; break;
154*795d594fSAndroid Build Coastguard Worker case kEs: os << "es:"; break;
155*795d594fSAndroid Build Coastguard Worker case kFs: os << "fs:"; break;
156*795d594fSAndroid Build Coastguard Worker case kGs: os << "gs:"; break;
157*795d594fSAndroid Build Coastguard Worker default: break;
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker
161*795d594fSAndroid Build Coastguard Worker // Do not inline to avoid Clang stack frame problems. b/18733806
162*795d594fSAndroid Build Coastguard Worker NO_INLINE
DumpCodeHex(const uint8_t * begin,const uint8_t * end)163*795d594fSAndroid Build Coastguard Worker static std::string DumpCodeHex(const uint8_t* begin, const uint8_t* end) {
164*795d594fSAndroid Build Coastguard Worker std::stringstream hex;
165*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; begin + i < end; ++i) {
166*795d594fSAndroid Build Coastguard Worker hex << StringPrintf("%02X", begin[i]);
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker return hex.str();
169*795d594fSAndroid Build Coastguard Worker }
170*795d594fSAndroid Build Coastguard Worker
DumpAddress(uint8_t mod,uint8_t rm,uint8_t rex64,uint8_t rex_w,bool no_ops,bool byte_operand,bool byte_second_operand,uint8_t * prefix,bool load,RegFile src_reg_file,RegFile dst_reg_file,const uint8_t ** instr,uint32_t * address_bits)171*795d594fSAndroid Build Coastguard Worker std::string DisassemblerX86::DumpAddress(uint8_t mod, uint8_t rm, uint8_t rex64, uint8_t rex_w,
172*795d594fSAndroid Build Coastguard Worker bool no_ops, bool byte_operand, bool byte_second_operand,
173*795d594fSAndroid Build Coastguard Worker uint8_t* prefix, bool load, RegFile src_reg_file,
174*795d594fSAndroid Build Coastguard Worker RegFile dst_reg_file, const uint8_t** instr,
175*795d594fSAndroid Build Coastguard Worker uint32_t* address_bits) {
176*795d594fSAndroid Build Coastguard Worker std::ostringstream address;
177*795d594fSAndroid Build Coastguard Worker if (mod == 0 && rm == 5) {
178*795d594fSAndroid Build Coastguard Worker if (!supports_rex_) { // Absolute address.
179*795d594fSAndroid Build Coastguard Worker *address_bits = *reinterpret_cast<const uint32_t*>(*instr);
180*795d594fSAndroid Build Coastguard Worker address << StringPrintf("[0x%x]", *address_bits);
181*795d594fSAndroid Build Coastguard Worker } else { // 64-bit RIP relative addressing.
182*795d594fSAndroid Build Coastguard Worker address << StringPrintf("[RIP + 0x%x]", *reinterpret_cast<const uint32_t*>(*instr));
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker (*instr) += 4;
185*795d594fSAndroid Build Coastguard Worker } else if (rm == 4 && mod != 3) { // SIB
186*795d594fSAndroid Build Coastguard Worker uint8_t sib = **instr;
187*795d594fSAndroid Build Coastguard Worker (*instr)++;
188*795d594fSAndroid Build Coastguard Worker uint8_t scale = (sib >> 6) & 3;
189*795d594fSAndroid Build Coastguard Worker uint8_t index = (sib >> 3) & 7;
190*795d594fSAndroid Build Coastguard Worker uint8_t base = sib & 7;
191*795d594fSAndroid Build Coastguard Worker address << "[";
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker // REX.x is bit 3 of index.
194*795d594fSAndroid Build Coastguard Worker if ((rex64 & REX_X) != 0) {
195*795d594fSAndroid Build Coastguard Worker index += 8;
196*795d594fSAndroid Build Coastguard Worker }
197*795d594fSAndroid Build Coastguard Worker
198*795d594fSAndroid Build Coastguard Worker // Mod = 0 && base = 5 (ebp): no base (ignores REX.b).
199*795d594fSAndroid Build Coastguard Worker bool has_base = false;
200*795d594fSAndroid Build Coastguard Worker if (base != 5 || mod != 0) {
201*795d594fSAndroid Build Coastguard Worker has_base = true;
202*795d594fSAndroid Build Coastguard Worker DumpBaseReg(address, rex64, base);
203*795d594fSAndroid Build Coastguard Worker }
204*795d594fSAndroid Build Coastguard Worker
205*795d594fSAndroid Build Coastguard Worker // Index = 4 (esp/rsp) is disallowed.
206*795d594fSAndroid Build Coastguard Worker if (index != 4) {
207*795d594fSAndroid Build Coastguard Worker if (has_base) {
208*795d594fSAndroid Build Coastguard Worker address << " + ";
209*795d594fSAndroid Build Coastguard Worker }
210*795d594fSAndroid Build Coastguard Worker DumpAddrReg(address, rex64, index);
211*795d594fSAndroid Build Coastguard Worker if (scale != 0) {
212*795d594fSAndroid Build Coastguard Worker address << StringPrintf(" * %d", 1 << scale);
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker }
215*795d594fSAndroid Build Coastguard Worker
216*795d594fSAndroid Build Coastguard Worker if (mod == 0) {
217*795d594fSAndroid Build Coastguard Worker if (base == 5) {
218*795d594fSAndroid Build Coastguard Worker if (index != 4) {
219*795d594fSAndroid Build Coastguard Worker address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
220*795d594fSAndroid Build Coastguard Worker } else {
221*795d594fSAndroid Build Coastguard Worker // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit.
222*795d594fSAndroid Build Coastguard Worker *address_bits = *reinterpret_cast<const uint32_t*>(*instr);
223*795d594fSAndroid Build Coastguard Worker address << StringPrintf("%d", *address_bits);
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker (*instr) += 4;
226*795d594fSAndroid Build Coastguard Worker }
227*795d594fSAndroid Build Coastguard Worker } else if (mod == 1) {
228*795d594fSAndroid Build Coastguard Worker address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr));
229*795d594fSAndroid Build Coastguard Worker (*instr)++;
230*795d594fSAndroid Build Coastguard Worker } else if (mod == 2) {
231*795d594fSAndroid Build Coastguard Worker address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
232*795d594fSAndroid Build Coastguard Worker (*instr) += 4;
233*795d594fSAndroid Build Coastguard Worker }
234*795d594fSAndroid Build Coastguard Worker address << "]";
235*795d594fSAndroid Build Coastguard Worker } else {
236*795d594fSAndroid Build Coastguard Worker if (mod == 3) {
237*795d594fSAndroid Build Coastguard Worker if (!no_ops) {
238*795d594fSAndroid Build Coastguard Worker DumpRmReg(address, rex_w, rm, byte_operand || byte_second_operand,
239*795d594fSAndroid Build Coastguard Worker prefix[2], load ? src_reg_file : dst_reg_file);
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker } else {
242*795d594fSAndroid Build Coastguard Worker address << "[";
243*795d594fSAndroid Build Coastguard Worker DumpBaseReg(address, rex64, rm);
244*795d594fSAndroid Build Coastguard Worker if (mod == 1) {
245*795d594fSAndroid Build Coastguard Worker address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr));
246*795d594fSAndroid Build Coastguard Worker (*instr)++;
247*795d594fSAndroid Build Coastguard Worker } else if (mod == 2) {
248*795d594fSAndroid Build Coastguard Worker address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
249*795d594fSAndroid Build Coastguard Worker (*instr) += 4;
250*795d594fSAndroid Build Coastguard Worker }
251*795d594fSAndroid Build Coastguard Worker address << "]";
252*795d594fSAndroid Build Coastguard Worker }
253*795d594fSAndroid Build Coastguard Worker }
254*795d594fSAndroid Build Coastguard Worker return address.str();
255*795d594fSAndroid Build Coastguard Worker }
256*795d594fSAndroid Build Coastguard Worker
DumpNops(std::ostream & os,const uint8_t * instr)257*795d594fSAndroid Build Coastguard Worker size_t DisassemblerX86::DumpNops(std::ostream& os, const uint8_t* instr) {
258*795d594fSAndroid Build Coastguard Worker static constexpr uint8_t kNops[][10] = {
259*795d594fSAndroid Build Coastguard Worker { },
260*795d594fSAndroid Build Coastguard Worker { 0x90 },
261*795d594fSAndroid Build Coastguard Worker { 0x66, 0x90 },
262*795d594fSAndroid Build Coastguard Worker { 0x0f, 0x1f, 0x00 },
263*795d594fSAndroid Build Coastguard Worker { 0x0f, 0x1f, 0x40, 0x00 },
264*795d594fSAndroid Build Coastguard Worker { 0x0f, 0x1f, 0x44, 0x00, 0x00 },
265*795d594fSAndroid Build Coastguard Worker { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 },
266*795d594fSAndroid Build Coastguard Worker { 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 },
267*795d594fSAndroid Build Coastguard Worker { 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
268*795d594fSAndroid Build Coastguard Worker { 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
269*795d594fSAndroid Build Coastguard Worker { 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }
270*795d594fSAndroid Build Coastguard Worker };
271*795d594fSAndroid Build Coastguard Worker
272*795d594fSAndroid Build Coastguard Worker for (size_t i = 1; i < arraysize(kNops); ++i) {
273*795d594fSAndroid Build Coastguard Worker if (memcmp(instr, kNops[i], i) == 0) {
274*795d594fSAndroid Build Coastguard Worker os << FormatInstructionPointer(instr)
275*795d594fSAndroid Build Coastguard Worker << StringPrintf(": %22s \t nop \n", DumpCodeHex(instr, instr + i).c_str());
276*795d594fSAndroid Build Coastguard Worker return i;
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker }
279*795d594fSAndroid Build Coastguard Worker
280*795d594fSAndroid Build Coastguard Worker return 0;
281*795d594fSAndroid Build Coastguard Worker }
282*795d594fSAndroid Build Coastguard Worker
DumpInstruction(std::ostream & os,const uint8_t * instr)283*795d594fSAndroid Build Coastguard Worker size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) {
284*795d594fSAndroid Build Coastguard Worker size_t nop_size = DumpNops(os, instr);
285*795d594fSAndroid Build Coastguard Worker if (nop_size != 0u) {
286*795d594fSAndroid Build Coastguard Worker return nop_size;
287*795d594fSAndroid Build Coastguard Worker }
288*795d594fSAndroid Build Coastguard Worker
289*795d594fSAndroid Build Coastguard Worker const uint8_t* begin_instr = instr;
290*795d594fSAndroid Build Coastguard Worker bool have_prefixes = true;
291*795d594fSAndroid Build Coastguard Worker uint8_t prefix[4] = {0, 0, 0, 0};
292*795d594fSAndroid Build Coastguard Worker do {
293*795d594fSAndroid Build Coastguard Worker switch (*instr) {
294*795d594fSAndroid Build Coastguard Worker // Group 1 - lock and repeat prefixes:
295*795d594fSAndroid Build Coastguard Worker case 0xF0:
296*795d594fSAndroid Build Coastguard Worker case 0xF2:
297*795d594fSAndroid Build Coastguard Worker case 0xF3:
298*795d594fSAndroid Build Coastguard Worker prefix[0] = *instr;
299*795d594fSAndroid Build Coastguard Worker break;
300*795d594fSAndroid Build Coastguard Worker // Group 2 - segment override prefixes:
301*795d594fSAndroid Build Coastguard Worker case kCs:
302*795d594fSAndroid Build Coastguard Worker case kSs:
303*795d594fSAndroid Build Coastguard Worker case kDs:
304*795d594fSAndroid Build Coastguard Worker case kEs:
305*795d594fSAndroid Build Coastguard Worker case kFs:
306*795d594fSAndroid Build Coastguard Worker case kGs:
307*795d594fSAndroid Build Coastguard Worker prefix[1] = *instr;
308*795d594fSAndroid Build Coastguard Worker break;
309*795d594fSAndroid Build Coastguard Worker // Group 3 - operand size override:
310*795d594fSAndroid Build Coastguard Worker case 0x66:
311*795d594fSAndroid Build Coastguard Worker prefix[2] = *instr;
312*795d594fSAndroid Build Coastguard Worker break;
313*795d594fSAndroid Build Coastguard Worker // Group 4 - address size override:
314*795d594fSAndroid Build Coastguard Worker case 0x67:
315*795d594fSAndroid Build Coastguard Worker prefix[3] = *instr;
316*795d594fSAndroid Build Coastguard Worker break;
317*795d594fSAndroid Build Coastguard Worker default:
318*795d594fSAndroid Build Coastguard Worker have_prefixes = false;
319*795d594fSAndroid Build Coastguard Worker break;
320*795d594fSAndroid Build Coastguard Worker }
321*795d594fSAndroid Build Coastguard Worker if (have_prefixes) {
322*795d594fSAndroid Build Coastguard Worker instr++;
323*795d594fSAndroid Build Coastguard Worker }
324*795d594fSAndroid Build Coastguard Worker } while (have_prefixes);
325*795d594fSAndroid Build Coastguard Worker uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0;
326*795d594fSAndroid Build Coastguard Worker if (rex != 0) {
327*795d594fSAndroid Build Coastguard Worker instr++;
328*795d594fSAndroid Build Coastguard Worker }
329*795d594fSAndroid Build Coastguard Worker
330*795d594fSAndroid Build Coastguard Worker const char** modrm_opcodes = nullptr;
331*795d594fSAndroid Build Coastguard Worker bool has_modrm = false;
332*795d594fSAndroid Build Coastguard Worker bool reg_is_opcode = false;
333*795d594fSAndroid Build Coastguard Worker
334*795d594fSAndroid Build Coastguard Worker size_t immediate_bytes = 0;
335*795d594fSAndroid Build Coastguard Worker size_t branch_bytes = 0;
336*795d594fSAndroid Build Coastguard Worker std::string opcode_tmp; // Storage to keep StringPrintf result alive.
337*795d594fSAndroid Build Coastguard Worker const char* opcode0 = ""; // Prefix part.
338*795d594fSAndroid Build Coastguard Worker const char* opcode1 = ""; // Main opcode.
339*795d594fSAndroid Build Coastguard Worker const char* opcode2 = ""; // Sub-opcode. E.g., jump type.
340*795d594fSAndroid Build Coastguard Worker const char* opcode3 = ""; // Mod-rm part.
341*795d594fSAndroid Build Coastguard Worker const char* opcode4 = ""; // Suffix part.
342*795d594fSAndroid Build Coastguard Worker bool store = false; // stores to memory (ie rm is on the left)
343*795d594fSAndroid Build Coastguard Worker bool load = false; // loads from memory (ie rm is on the right)
344*795d594fSAndroid Build Coastguard Worker bool byte_operand = false; // true when the opcode is dealing with byte operands
345*795d594fSAndroid Build Coastguard Worker // true when the source operand is a byte register but the target register isn't
346*795d594fSAndroid Build Coastguard Worker // (ie movsxb/movzxb).
347*795d594fSAndroid Build Coastguard Worker bool byte_second_operand = false;
348*795d594fSAndroid Build Coastguard Worker bool target_specific = false; // register name depends on target (64 vs 32 bits).
349*795d594fSAndroid Build Coastguard Worker bool ax = false; // implicit use of ax
350*795d594fSAndroid Build Coastguard Worker bool cx = false; // implicit use of cx
351*795d594fSAndroid Build Coastguard Worker bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter
352*795d594fSAndroid Build Coastguard Worker bool no_ops = false;
353*795d594fSAndroid Build Coastguard Worker RegFile src_reg_file = GPR;
354*795d594fSAndroid Build Coastguard Worker RegFile dst_reg_file = GPR;
355*795d594fSAndroid Build Coastguard Worker
356*795d594fSAndroid Build Coastguard Worker
357*795d594fSAndroid Build Coastguard Worker switch (*instr) {
358*795d594fSAndroid Build Coastguard Worker #define DISASSEMBLER_ENTRY(opname, \
359*795d594fSAndroid Build Coastguard Worker rm8_r8, rm32_r32, \
360*795d594fSAndroid Build Coastguard Worker r8_rm8, r32_rm32, \
361*795d594fSAndroid Build Coastguard Worker ax8_i8, ax32_i32) \
362*795d594fSAndroid Build Coastguard Worker case rm8_r8: opcode1 = #opname; store = true; has_modrm = true; byte_operand = true; break; \
363*795d594fSAndroid Build Coastguard Worker case rm32_r32: opcode1 = #opname; store = true; has_modrm = true; break; \
364*795d594fSAndroid Build Coastguard Worker case r8_rm8: opcode1 = #opname; load = true; has_modrm = true; byte_operand = true; break; \
365*795d594fSAndroid Build Coastguard Worker case r32_rm32: opcode1 = #opname; load = true; has_modrm = true; break; \
366*795d594fSAndroid Build Coastguard Worker case ax8_i8: opcode1 = #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \
367*795d594fSAndroid Build Coastguard Worker case ax32_i32: opcode1 = #opname; ax = true; immediate_bytes = 4; break;
368*795d594fSAndroid Build Coastguard Worker
369*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(add,
370*795d594fSAndroid Build Coastguard Worker 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */,
371*795d594fSAndroid Build Coastguard Worker 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */,
372*795d594fSAndroid Build Coastguard Worker 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */)
373*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(or,
374*795d594fSAndroid Build Coastguard Worker 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */,
375*795d594fSAndroid Build Coastguard Worker 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */,
376*795d594fSAndroid Build Coastguard Worker 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */)
377*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(adc,
378*795d594fSAndroid Build Coastguard Worker 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */,
379*795d594fSAndroid Build Coastguard Worker 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */,
380*795d594fSAndroid Build Coastguard Worker 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */)
381*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(sbb,
382*795d594fSAndroid Build Coastguard Worker 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */,
383*795d594fSAndroid Build Coastguard Worker 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */,
384*795d594fSAndroid Build Coastguard Worker 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */)
385*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(and,
386*795d594fSAndroid Build Coastguard Worker 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */,
387*795d594fSAndroid Build Coastguard Worker 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */,
388*795d594fSAndroid Build Coastguard Worker 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */)
389*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(sub,
390*795d594fSAndroid Build Coastguard Worker 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */,
391*795d594fSAndroid Build Coastguard Worker 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */,
392*795d594fSAndroid Build Coastguard Worker 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */)
393*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(xor,
394*795d594fSAndroid Build Coastguard Worker 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */,
395*795d594fSAndroid Build Coastguard Worker 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */,
396*795d594fSAndroid Build Coastguard Worker 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */)
397*795d594fSAndroid Build Coastguard Worker DISASSEMBLER_ENTRY(cmp,
398*795d594fSAndroid Build Coastguard Worker 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem/Reg32 */,
399*795d594fSAndroid Build Coastguard Worker 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */,
400*795d594fSAndroid Build Coastguard Worker 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */)
401*795d594fSAndroid Build Coastguard Worker
402*795d594fSAndroid Build Coastguard Worker #undef DISASSEMBLER_ENTRY
403*795d594fSAndroid Build Coastguard Worker
404*795d594fSAndroid Build Coastguard Worker case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
405*795d594fSAndroid Build Coastguard Worker opcode1 = "push";
406*795d594fSAndroid Build Coastguard Worker reg_in_opcode = true;
407*795d594fSAndroid Build Coastguard Worker target_specific = true;
408*795d594fSAndroid Build Coastguard Worker break;
409*795d594fSAndroid Build Coastguard Worker case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F:
410*795d594fSAndroid Build Coastguard Worker opcode1 = "pop";
411*795d594fSAndroid Build Coastguard Worker reg_in_opcode = true;
412*795d594fSAndroid Build Coastguard Worker target_specific = true;
413*795d594fSAndroid Build Coastguard Worker break;
414*795d594fSAndroid Build Coastguard Worker case 0x63:
415*795d594fSAndroid Build Coastguard Worker if ((rex & REX_W) != 0) {
416*795d594fSAndroid Build Coastguard Worker opcode1 = "movsxd";
417*795d594fSAndroid Build Coastguard Worker has_modrm = true;
418*795d594fSAndroid Build Coastguard Worker load = true;
419*795d594fSAndroid Build Coastguard Worker } else {
420*795d594fSAndroid Build Coastguard Worker // In 32-bit mode (!supports_rex_) this is ARPL, with no REX prefix the functionality is the
421*795d594fSAndroid Build Coastguard Worker // same as 'mov' but the use of the instruction is discouraged.
422*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
423*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
424*795d594fSAndroid Build Coastguard Worker }
425*795d594fSAndroid Build Coastguard Worker break;
426*795d594fSAndroid Build Coastguard Worker case 0x68: opcode1 = "push"; immediate_bytes = 4; break;
427*795d594fSAndroid Build Coastguard Worker case 0x69: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 4; break;
428*795d594fSAndroid Build Coastguard Worker case 0x6A: opcode1 = "push"; immediate_bytes = 1; break;
429*795d594fSAndroid Build Coastguard Worker case 0x6B: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 1; break;
430*795d594fSAndroid Build Coastguard Worker case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
431*795d594fSAndroid Build Coastguard Worker case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
432*795d594fSAndroid Build Coastguard Worker static const char* condition_codes[] =
433*795d594fSAndroid Build Coastguard Worker {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a",
434*795d594fSAndroid Build Coastguard Worker "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g"
435*795d594fSAndroid Build Coastguard Worker };
436*795d594fSAndroid Build Coastguard Worker opcode1 = "j";
437*795d594fSAndroid Build Coastguard Worker opcode2 = condition_codes[*instr & 0xF];
438*795d594fSAndroid Build Coastguard Worker branch_bytes = 1;
439*795d594fSAndroid Build Coastguard Worker break;
440*795d594fSAndroid Build Coastguard Worker case 0x86: case 0x87:
441*795d594fSAndroid Build Coastguard Worker opcode1 = "xchg";
442*795d594fSAndroid Build Coastguard Worker store = true;
443*795d594fSAndroid Build Coastguard Worker has_modrm = true;
444*795d594fSAndroid Build Coastguard Worker byte_operand = (*instr == 0x86);
445*795d594fSAndroid Build Coastguard Worker break;
446*795d594fSAndroid Build Coastguard Worker case 0x88: opcode1 = "mov"; store = true; has_modrm = true; byte_operand = true; break;
447*795d594fSAndroid Build Coastguard Worker case 0x89: opcode1 = "mov"; store = true; has_modrm = true; break;
448*795d594fSAndroid Build Coastguard Worker case 0x8A: opcode1 = "mov"; load = true; has_modrm = true; byte_operand = true; break;
449*795d594fSAndroid Build Coastguard Worker case 0x8B: opcode1 = "mov"; load = true; has_modrm = true; break;
450*795d594fSAndroid Build Coastguard Worker case 0x9D: opcode1 = "popf"; break;
451*795d594fSAndroid Build Coastguard Worker
452*795d594fSAndroid Build Coastguard Worker case 0x0F: // 2 byte extended opcode
453*795d594fSAndroid Build Coastguard Worker instr++;
454*795d594fSAndroid Build Coastguard Worker switch (*instr) {
455*795d594fSAndroid Build Coastguard Worker case 0x10: case 0x11:
456*795d594fSAndroid Build Coastguard Worker if (prefix[0] == 0xF2) {
457*795d594fSAndroid Build Coastguard Worker opcode1 = "movsd";
458*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
459*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
460*795d594fSAndroid Build Coastguard Worker opcode1 = "movss";
461*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
462*795d594fSAndroid Build Coastguard Worker } else if (prefix[2] == 0x66) {
463*795d594fSAndroid Build Coastguard Worker opcode1 = "movupd";
464*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
465*795d594fSAndroid Build Coastguard Worker } else {
466*795d594fSAndroid Build Coastguard Worker opcode1 = "movups";
467*795d594fSAndroid Build Coastguard Worker }
468*795d594fSAndroid Build Coastguard Worker has_modrm = true;
469*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
470*795d594fSAndroid Build Coastguard Worker load = *instr == 0x10;
471*795d594fSAndroid Build Coastguard Worker store = !load;
472*795d594fSAndroid Build Coastguard Worker break;
473*795d594fSAndroid Build Coastguard Worker case 0x12: case 0x13:
474*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
475*795d594fSAndroid Build Coastguard Worker opcode1 = "movlpd";
476*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
477*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0) {
478*795d594fSAndroid Build Coastguard Worker opcode1 = "movlps";
479*795d594fSAndroid Build Coastguard Worker }
480*795d594fSAndroid Build Coastguard Worker has_modrm = true;
481*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
482*795d594fSAndroid Build Coastguard Worker load = *instr == 0x12;
483*795d594fSAndroid Build Coastguard Worker store = !load;
484*795d594fSAndroid Build Coastguard Worker break;
485*795d594fSAndroid Build Coastguard Worker case 0x16: case 0x17:
486*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
487*795d594fSAndroid Build Coastguard Worker opcode1 = "movhpd";
488*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
489*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0) {
490*795d594fSAndroid Build Coastguard Worker opcode1 = "movhps";
491*795d594fSAndroid Build Coastguard Worker }
492*795d594fSAndroid Build Coastguard Worker has_modrm = true;
493*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
494*795d594fSAndroid Build Coastguard Worker load = *instr == 0x16;
495*795d594fSAndroid Build Coastguard Worker store = !load;
496*795d594fSAndroid Build Coastguard Worker break;
497*795d594fSAndroid Build Coastguard Worker case 0x28: case 0x29:
498*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
499*795d594fSAndroid Build Coastguard Worker opcode1 = "movapd";
500*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
501*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0) {
502*795d594fSAndroid Build Coastguard Worker opcode1 = "movaps";
503*795d594fSAndroid Build Coastguard Worker }
504*795d594fSAndroid Build Coastguard Worker has_modrm = true;
505*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
506*795d594fSAndroid Build Coastguard Worker load = *instr == 0x28;
507*795d594fSAndroid Build Coastguard Worker store = !load;
508*795d594fSAndroid Build Coastguard Worker break;
509*795d594fSAndroid Build Coastguard Worker case 0x2A:
510*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
511*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtpi2pd";
512*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
513*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
514*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtsi2sd";
515*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
516*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
517*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtsi2ss";
518*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
519*795d594fSAndroid Build Coastguard Worker } else {
520*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtpi2ps";
521*795d594fSAndroid Build Coastguard Worker }
522*795d594fSAndroid Build Coastguard Worker load = true;
523*795d594fSAndroid Build Coastguard Worker has_modrm = true;
524*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
525*795d594fSAndroid Build Coastguard Worker break;
526*795d594fSAndroid Build Coastguard Worker case 0x2C:
527*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
528*795d594fSAndroid Build Coastguard Worker opcode1 = "cvttpd2pi";
529*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
530*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
531*795d594fSAndroid Build Coastguard Worker opcode1 = "cvttsd2si";
532*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
533*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
534*795d594fSAndroid Build Coastguard Worker opcode1 = "cvttss2si";
535*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
536*795d594fSAndroid Build Coastguard Worker } else {
537*795d594fSAndroid Build Coastguard Worker opcode1 = "cvttps2pi";
538*795d594fSAndroid Build Coastguard Worker }
539*795d594fSAndroid Build Coastguard Worker load = true;
540*795d594fSAndroid Build Coastguard Worker has_modrm = true;
541*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
542*795d594fSAndroid Build Coastguard Worker break;
543*795d594fSAndroid Build Coastguard Worker case 0x2D:
544*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
545*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtpd2pi";
546*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
547*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
548*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtsd2si";
549*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
550*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
551*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtss2si";
552*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
553*795d594fSAndroid Build Coastguard Worker } else {
554*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtps2pi";
555*795d594fSAndroid Build Coastguard Worker }
556*795d594fSAndroid Build Coastguard Worker load = true;
557*795d594fSAndroid Build Coastguard Worker has_modrm = true;
558*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
559*795d594fSAndroid Build Coastguard Worker break;
560*795d594fSAndroid Build Coastguard Worker case 0x2E:
561*795d594fSAndroid Build Coastguard Worker opcode0 = "u";
562*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
563*795d594fSAndroid Build Coastguard Worker case 0x2F:
564*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
565*795d594fSAndroid Build Coastguard Worker opcode1 = "comisd";
566*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
567*795d594fSAndroid Build Coastguard Worker } else {
568*795d594fSAndroid Build Coastguard Worker opcode1 = "comiss";
569*795d594fSAndroid Build Coastguard Worker }
570*795d594fSAndroid Build Coastguard Worker has_modrm = true;
571*795d594fSAndroid Build Coastguard Worker load = true;
572*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
573*795d594fSAndroid Build Coastguard Worker break;
574*795d594fSAndroid Build Coastguard Worker case 0x38: // 3 byte extended opcode
575*795d594fSAndroid Build Coastguard Worker instr++;
576*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
577*795d594fSAndroid Build Coastguard Worker switch (*instr) {
578*795d594fSAndroid Build Coastguard Worker case 0x01:
579*795d594fSAndroid Build Coastguard Worker opcode1 = "phaddw";
580*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
581*795d594fSAndroid Build Coastguard Worker has_modrm = true;
582*795d594fSAndroid Build Coastguard Worker load = true;
583*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
584*795d594fSAndroid Build Coastguard Worker break;
585*795d594fSAndroid Build Coastguard Worker case 0x02:
586*795d594fSAndroid Build Coastguard Worker opcode1 = "phaddd";
587*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
588*795d594fSAndroid Build Coastguard Worker has_modrm = true;
589*795d594fSAndroid Build Coastguard Worker load = true;
590*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
591*795d594fSAndroid Build Coastguard Worker break;
592*795d594fSAndroid Build Coastguard Worker case 0x29:
593*795d594fSAndroid Build Coastguard Worker opcode1 = "pcmpeqq";
594*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
595*795d594fSAndroid Build Coastguard Worker has_modrm = true;
596*795d594fSAndroid Build Coastguard Worker load = true;
597*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
598*795d594fSAndroid Build Coastguard Worker break;
599*795d594fSAndroid Build Coastguard Worker case 0x37:
600*795d594fSAndroid Build Coastguard Worker opcode1 = "pcmpgtq";
601*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
602*795d594fSAndroid Build Coastguard Worker has_modrm = true;
603*795d594fSAndroid Build Coastguard Worker load = true;
604*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
605*795d594fSAndroid Build Coastguard Worker break;
606*795d594fSAndroid Build Coastguard Worker case 0x38:
607*795d594fSAndroid Build Coastguard Worker opcode1 = "pminsb";
608*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
609*795d594fSAndroid Build Coastguard Worker has_modrm = true;
610*795d594fSAndroid Build Coastguard Worker load = true;
611*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
612*795d594fSAndroid Build Coastguard Worker break;
613*795d594fSAndroid Build Coastguard Worker case 0x39:
614*795d594fSAndroid Build Coastguard Worker opcode1 = "pminsd";
615*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
616*795d594fSAndroid Build Coastguard Worker has_modrm = true;
617*795d594fSAndroid Build Coastguard Worker load = true;
618*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
619*795d594fSAndroid Build Coastguard Worker break;
620*795d594fSAndroid Build Coastguard Worker case 0x3A:
621*795d594fSAndroid Build Coastguard Worker opcode1 = "pminuw";
622*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
623*795d594fSAndroid Build Coastguard Worker has_modrm = true;
624*795d594fSAndroid Build Coastguard Worker load = true;
625*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
626*795d594fSAndroid Build Coastguard Worker break;
627*795d594fSAndroid Build Coastguard Worker case 0x3B:
628*795d594fSAndroid Build Coastguard Worker opcode1 = "pminud";
629*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
630*795d594fSAndroid Build Coastguard Worker has_modrm = true;
631*795d594fSAndroid Build Coastguard Worker load = true;
632*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
633*795d594fSAndroid Build Coastguard Worker break;
634*795d594fSAndroid Build Coastguard Worker case 0x3C:
635*795d594fSAndroid Build Coastguard Worker opcode1 = "pmaxsb";
636*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
637*795d594fSAndroid Build Coastguard Worker has_modrm = true;
638*795d594fSAndroid Build Coastguard Worker load = true;
639*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
640*795d594fSAndroid Build Coastguard Worker break;
641*795d594fSAndroid Build Coastguard Worker case 0x3D:
642*795d594fSAndroid Build Coastguard Worker opcode1 = "pmaxsd";
643*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
644*795d594fSAndroid Build Coastguard Worker has_modrm = true;
645*795d594fSAndroid Build Coastguard Worker load = true;
646*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
647*795d594fSAndroid Build Coastguard Worker break;
648*795d594fSAndroid Build Coastguard Worker case 0x3E:
649*795d594fSAndroid Build Coastguard Worker opcode1 = "pmaxuw";
650*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
651*795d594fSAndroid Build Coastguard Worker has_modrm = true;
652*795d594fSAndroid Build Coastguard Worker load = true;
653*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
654*795d594fSAndroid Build Coastguard Worker break;
655*795d594fSAndroid Build Coastguard Worker case 0x3F:
656*795d594fSAndroid Build Coastguard Worker opcode1 = "pmaxud";
657*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
658*795d594fSAndroid Build Coastguard Worker has_modrm = true;
659*795d594fSAndroid Build Coastguard Worker load = true;
660*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
661*795d594fSAndroid Build Coastguard Worker break;
662*795d594fSAndroid Build Coastguard Worker case 0x40:
663*795d594fSAndroid Build Coastguard Worker opcode1 = "pmulld";
664*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
665*795d594fSAndroid Build Coastguard Worker has_modrm = true;
666*795d594fSAndroid Build Coastguard Worker load = true;
667*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
668*795d594fSAndroid Build Coastguard Worker break;
669*795d594fSAndroid Build Coastguard Worker default:
670*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr);
671*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
672*795d594fSAndroid Build Coastguard Worker }
673*795d594fSAndroid Build Coastguard Worker } else {
674*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr);
675*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
676*795d594fSAndroid Build Coastguard Worker }
677*795d594fSAndroid Build Coastguard Worker break;
678*795d594fSAndroid Build Coastguard Worker case 0x3A: // 3 byte extended opcode
679*795d594fSAndroid Build Coastguard Worker instr++;
680*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
681*795d594fSAndroid Build Coastguard Worker switch (*instr) {
682*795d594fSAndroid Build Coastguard Worker case 0x0A:
683*795d594fSAndroid Build Coastguard Worker opcode1 = "roundss";
684*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
685*795d594fSAndroid Build Coastguard Worker has_modrm = true;
686*795d594fSAndroid Build Coastguard Worker load = true;
687*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
688*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
689*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
690*795d594fSAndroid Build Coastguard Worker break;
691*795d594fSAndroid Build Coastguard Worker case 0x0B:
692*795d594fSAndroid Build Coastguard Worker opcode1 = "roundsd";
693*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
694*795d594fSAndroid Build Coastguard Worker has_modrm = true;
695*795d594fSAndroid Build Coastguard Worker load = true;
696*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
697*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
698*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
699*795d594fSAndroid Build Coastguard Worker break;
700*795d594fSAndroid Build Coastguard Worker case 0x14:
701*795d594fSAndroid Build Coastguard Worker opcode1 = "pextrb";
702*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
703*795d594fSAndroid Build Coastguard Worker has_modrm = true;
704*795d594fSAndroid Build Coastguard Worker store = true;
705*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
706*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
707*795d594fSAndroid Build Coastguard Worker break;
708*795d594fSAndroid Build Coastguard Worker case 0x15:
709*795d594fSAndroid Build Coastguard Worker opcode1 = "pextrw";
710*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
711*795d594fSAndroid Build Coastguard Worker has_modrm = true;
712*795d594fSAndroid Build Coastguard Worker store = true;
713*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
714*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
715*795d594fSAndroid Build Coastguard Worker break;
716*795d594fSAndroid Build Coastguard Worker case 0x16:
717*795d594fSAndroid Build Coastguard Worker opcode1 = "pextrd";
718*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
719*795d594fSAndroid Build Coastguard Worker has_modrm = true;
720*795d594fSAndroid Build Coastguard Worker store = true;
721*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
722*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
723*795d594fSAndroid Build Coastguard Worker break;
724*795d594fSAndroid Build Coastguard Worker default:
725*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr);
726*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
727*795d594fSAndroid Build Coastguard Worker }
728*795d594fSAndroid Build Coastguard Worker } else {
729*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr);
730*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
731*795d594fSAndroid Build Coastguard Worker }
732*795d594fSAndroid Build Coastguard Worker break;
733*795d594fSAndroid Build Coastguard Worker case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
734*795d594fSAndroid Build Coastguard Worker case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F:
735*795d594fSAndroid Build Coastguard Worker opcode1 = "cmov";
736*795d594fSAndroid Build Coastguard Worker opcode2 = condition_codes[*instr & 0xF];
737*795d594fSAndroid Build Coastguard Worker has_modrm = true;
738*795d594fSAndroid Build Coastguard Worker load = true;
739*795d594fSAndroid Build Coastguard Worker break;
740*795d594fSAndroid Build Coastguard Worker case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
741*795d594fSAndroid Build Coastguard Worker case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
742*795d594fSAndroid Build Coastguard Worker switch (*instr) {
743*795d594fSAndroid Build Coastguard Worker case 0x50: opcode1 = "movmsk"; break;
744*795d594fSAndroid Build Coastguard Worker case 0x51: opcode1 = "sqrt"; break;
745*795d594fSAndroid Build Coastguard Worker case 0x52: opcode1 = "rsqrt"; break;
746*795d594fSAndroid Build Coastguard Worker case 0x53: opcode1 = "rcp"; break;
747*795d594fSAndroid Build Coastguard Worker case 0x54: opcode1 = "and"; break;
748*795d594fSAndroid Build Coastguard Worker case 0x55: opcode1 = "andn"; break;
749*795d594fSAndroid Build Coastguard Worker case 0x56: opcode1 = "or"; break;
750*795d594fSAndroid Build Coastguard Worker case 0x57: opcode1 = "xor"; break;
751*795d594fSAndroid Build Coastguard Worker case 0x58: opcode1 = "add"; break;
752*795d594fSAndroid Build Coastguard Worker case 0x59: opcode1 = "mul"; break;
753*795d594fSAndroid Build Coastguard Worker case 0x5C: opcode1 = "sub"; break;
754*795d594fSAndroid Build Coastguard Worker case 0x5D: opcode1 = "min"; break;
755*795d594fSAndroid Build Coastguard Worker case 0x5E: opcode1 = "div"; break;
756*795d594fSAndroid Build Coastguard Worker case 0x5F: opcode1 = "max"; break;
757*795d594fSAndroid Build Coastguard Worker default: LOG(FATAL) << "Unreachable"; UNREACHABLE();
758*795d594fSAndroid Build Coastguard Worker }
759*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
760*795d594fSAndroid Build Coastguard Worker opcode2 = "pd";
761*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
762*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
763*795d594fSAndroid Build Coastguard Worker opcode2 = "sd";
764*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
765*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
766*795d594fSAndroid Build Coastguard Worker opcode2 = "ss";
767*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
768*795d594fSAndroid Build Coastguard Worker } else {
769*795d594fSAndroid Build Coastguard Worker opcode2 = "ps";
770*795d594fSAndroid Build Coastguard Worker }
771*795d594fSAndroid Build Coastguard Worker load = true;
772*795d594fSAndroid Build Coastguard Worker has_modrm = true;
773*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
774*795d594fSAndroid Build Coastguard Worker break;
775*795d594fSAndroid Build Coastguard Worker }
776*795d594fSAndroid Build Coastguard Worker case 0x5A:
777*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
778*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtpd2ps";
779*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
780*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
781*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtsd2ss";
782*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
783*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
784*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtss2sd";
785*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
786*795d594fSAndroid Build Coastguard Worker } else {
787*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtps2pd";
788*795d594fSAndroid Build Coastguard Worker }
789*795d594fSAndroid Build Coastguard Worker load = true;
790*795d594fSAndroid Build Coastguard Worker has_modrm = true;
791*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
792*795d594fSAndroid Build Coastguard Worker break;
793*795d594fSAndroid Build Coastguard Worker case 0x5B:
794*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
795*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtps2dq";
796*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
797*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
798*795d594fSAndroid Build Coastguard Worker opcode1 = "bad opcode F2 0F 5B";
799*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
800*795d594fSAndroid Build Coastguard Worker opcode1 = "cvttps2dq";
801*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
802*795d594fSAndroid Build Coastguard Worker } else {
803*795d594fSAndroid Build Coastguard Worker opcode1 = "cvtdq2ps";
804*795d594fSAndroid Build Coastguard Worker }
805*795d594fSAndroid Build Coastguard Worker load = true;
806*795d594fSAndroid Build Coastguard Worker has_modrm = true;
807*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
808*795d594fSAndroid Build Coastguard Worker break;
809*795d594fSAndroid Build Coastguard Worker case 0x60: case 0x61: case 0x62: case 0x6C:
810*795d594fSAndroid Build Coastguard Worker case 0x68: case 0x69: case 0x6A: case 0x6D:
811*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
812*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
813*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // Clear prefix now. It has served its purpose as part of the opcode.
814*795d594fSAndroid Build Coastguard Worker } else {
815*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
816*795d594fSAndroid Build Coastguard Worker }
817*795d594fSAndroid Build Coastguard Worker switch (*instr) {
818*795d594fSAndroid Build Coastguard Worker case 0x60: opcode1 = "punpcklbw"; break;
819*795d594fSAndroid Build Coastguard Worker case 0x61: opcode1 = "punpcklwd"; break;
820*795d594fSAndroid Build Coastguard Worker case 0x62: opcode1 = "punpckldq"; break;
821*795d594fSAndroid Build Coastguard Worker case 0x6c: opcode1 = "punpcklqdq"; break;
822*795d594fSAndroid Build Coastguard Worker case 0x68: opcode1 = "punpckhbw"; break;
823*795d594fSAndroid Build Coastguard Worker case 0x69: opcode1 = "punpckhwd"; break;
824*795d594fSAndroid Build Coastguard Worker case 0x6A: opcode1 = "punpckhdq"; break;
825*795d594fSAndroid Build Coastguard Worker case 0x6D: opcode1 = "punpckhqdq"; break;
826*795d594fSAndroid Build Coastguard Worker }
827*795d594fSAndroid Build Coastguard Worker load = true;
828*795d594fSAndroid Build Coastguard Worker has_modrm = true;
829*795d594fSAndroid Build Coastguard Worker break;
830*795d594fSAndroid Build Coastguard Worker case 0x64:
831*795d594fSAndroid Build Coastguard Worker case 0x65:
832*795d594fSAndroid Build Coastguard Worker case 0x66:
833*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
834*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
835*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
836*795d594fSAndroid Build Coastguard Worker } else {
837*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
838*795d594fSAndroid Build Coastguard Worker }
839*795d594fSAndroid Build Coastguard Worker switch (*instr) {
840*795d594fSAndroid Build Coastguard Worker case 0x64: opcode1 = "pcmpgtb"; break;
841*795d594fSAndroid Build Coastguard Worker case 0x65: opcode1 = "pcmpgtw"; break;
842*795d594fSAndroid Build Coastguard Worker case 0x66: opcode1 = "pcmpgtd"; break;
843*795d594fSAndroid Build Coastguard Worker }
844*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
845*795d594fSAndroid Build Coastguard Worker has_modrm = true;
846*795d594fSAndroid Build Coastguard Worker load = true;
847*795d594fSAndroid Build Coastguard Worker break;
848*795d594fSAndroid Build Coastguard Worker case 0x6E:
849*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
850*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
851*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
852*795d594fSAndroid Build Coastguard Worker } else {
853*795d594fSAndroid Build Coastguard Worker dst_reg_file = MMX;
854*795d594fSAndroid Build Coastguard Worker }
855*795d594fSAndroid Build Coastguard Worker opcode1 = "movd";
856*795d594fSAndroid Build Coastguard Worker load = true;
857*795d594fSAndroid Build Coastguard Worker has_modrm = true;
858*795d594fSAndroid Build Coastguard Worker break;
859*795d594fSAndroid Build Coastguard Worker case 0x6F:
860*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
861*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
862*795d594fSAndroid Build Coastguard Worker opcode1 = "movdqa";
863*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
864*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
865*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
866*795d594fSAndroid Build Coastguard Worker opcode1 = "movdqu";
867*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
868*795d594fSAndroid Build Coastguard Worker } else {
869*795d594fSAndroid Build Coastguard Worker dst_reg_file = MMX;
870*795d594fSAndroid Build Coastguard Worker opcode1 = "movq";
871*795d594fSAndroid Build Coastguard Worker }
872*795d594fSAndroid Build Coastguard Worker load = true;
873*795d594fSAndroid Build Coastguard Worker has_modrm = true;
874*795d594fSAndroid Build Coastguard Worker break;
875*795d594fSAndroid Build Coastguard Worker case 0x70:
876*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
877*795d594fSAndroid Build Coastguard Worker opcode1 = "pshufd";
878*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
879*795d594fSAndroid Build Coastguard Worker has_modrm = true;
880*795d594fSAndroid Build Coastguard Worker store = true;
881*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
882*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
883*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF2) {
884*795d594fSAndroid Build Coastguard Worker opcode1 = "pshuflw";
885*795d594fSAndroid Build Coastguard Worker prefix[0] = 0;
886*795d594fSAndroid Build Coastguard Worker has_modrm = true;
887*795d594fSAndroid Build Coastguard Worker store = true;
888*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
889*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
890*795d594fSAndroid Build Coastguard Worker } else {
891*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
892*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
893*795d594fSAndroid Build Coastguard Worker }
894*795d594fSAndroid Build Coastguard Worker break;
895*795d594fSAndroid Build Coastguard Worker case 0x71:
896*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
897*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
898*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
899*795d594fSAndroid Build Coastguard Worker } else {
900*795d594fSAndroid Build Coastguard Worker dst_reg_file = MMX;
901*795d594fSAndroid Build Coastguard Worker }
902*795d594fSAndroid Build Coastguard Worker static const char* x71_opcodes[] = {
903*795d594fSAndroid Build Coastguard Worker "unknown-71", "unknown-71", "psrlw", "unknown-71",
904*795d594fSAndroid Build Coastguard Worker "psraw", "unknown-71", "psllw", "unknown-71"};
905*795d594fSAndroid Build Coastguard Worker modrm_opcodes = x71_opcodes;
906*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
907*795d594fSAndroid Build Coastguard Worker has_modrm = true;
908*795d594fSAndroid Build Coastguard Worker store = true;
909*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
910*795d594fSAndroid Build Coastguard Worker break;
911*795d594fSAndroid Build Coastguard Worker case 0x72:
912*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
913*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
914*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
915*795d594fSAndroid Build Coastguard Worker } else {
916*795d594fSAndroid Build Coastguard Worker dst_reg_file = MMX;
917*795d594fSAndroid Build Coastguard Worker }
918*795d594fSAndroid Build Coastguard Worker static const char* x72_opcodes[] = {
919*795d594fSAndroid Build Coastguard Worker "unknown-72", "unknown-72", "psrld", "unknown-72",
920*795d594fSAndroid Build Coastguard Worker "psrad", "unknown-72", "pslld", "unknown-72"};
921*795d594fSAndroid Build Coastguard Worker modrm_opcodes = x72_opcodes;
922*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
923*795d594fSAndroid Build Coastguard Worker has_modrm = true;
924*795d594fSAndroid Build Coastguard Worker store = true;
925*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
926*795d594fSAndroid Build Coastguard Worker break;
927*795d594fSAndroid Build Coastguard Worker case 0x73:
928*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
929*795d594fSAndroid Build Coastguard Worker dst_reg_file = SSE;
930*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
931*795d594fSAndroid Build Coastguard Worker } else {
932*795d594fSAndroid Build Coastguard Worker dst_reg_file = MMX;
933*795d594fSAndroid Build Coastguard Worker }
934*795d594fSAndroid Build Coastguard Worker static const char* x73_opcodes[] = {
935*795d594fSAndroid Build Coastguard Worker "unknown-73", "unknown-73", "psrlq", "psrldq",
936*795d594fSAndroid Build Coastguard Worker "unknown-73", "unknown-73", "psllq", "unknown-73"};
937*795d594fSAndroid Build Coastguard Worker modrm_opcodes = x73_opcodes;
938*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
939*795d594fSAndroid Build Coastguard Worker has_modrm = true;
940*795d594fSAndroid Build Coastguard Worker store = true;
941*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
942*795d594fSAndroid Build Coastguard Worker break;
943*795d594fSAndroid Build Coastguard Worker case 0x74:
944*795d594fSAndroid Build Coastguard Worker case 0x75:
945*795d594fSAndroid Build Coastguard Worker case 0x76:
946*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
947*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
948*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
949*795d594fSAndroid Build Coastguard Worker } else {
950*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
951*795d594fSAndroid Build Coastguard Worker }
952*795d594fSAndroid Build Coastguard Worker switch (*instr) {
953*795d594fSAndroid Build Coastguard Worker case 0x74: opcode1 = "pcmpeqb"; break;
954*795d594fSAndroid Build Coastguard Worker case 0x75: opcode1 = "pcmpeqw"; break;
955*795d594fSAndroid Build Coastguard Worker case 0x76: opcode1 = "pcmpeqd"; break;
956*795d594fSAndroid Build Coastguard Worker }
957*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
958*795d594fSAndroid Build Coastguard Worker has_modrm = true;
959*795d594fSAndroid Build Coastguard Worker load = true;
960*795d594fSAndroid Build Coastguard Worker break;
961*795d594fSAndroid Build Coastguard Worker case 0x7C:
962*795d594fSAndroid Build Coastguard Worker if (prefix[0] == 0xF2) {
963*795d594fSAndroid Build Coastguard Worker opcode1 = "haddps";
964*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
965*795d594fSAndroid Build Coastguard Worker } else if (prefix[2] == 0x66) {
966*795d594fSAndroid Build Coastguard Worker opcode1 = "haddpd";
967*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
968*795d594fSAndroid Build Coastguard Worker } else {
969*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
970*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
971*795d594fSAndroid Build Coastguard Worker break;
972*795d594fSAndroid Build Coastguard Worker }
973*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
974*795d594fSAndroid Build Coastguard Worker has_modrm = true;
975*795d594fSAndroid Build Coastguard Worker load = true;
976*795d594fSAndroid Build Coastguard Worker break;
977*795d594fSAndroid Build Coastguard Worker case 0x7E:
978*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
979*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
980*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
981*795d594fSAndroid Build Coastguard Worker } else {
982*795d594fSAndroid Build Coastguard Worker src_reg_file = MMX;
983*795d594fSAndroid Build Coastguard Worker }
984*795d594fSAndroid Build Coastguard Worker opcode1 = "movd";
985*795d594fSAndroid Build Coastguard Worker has_modrm = true;
986*795d594fSAndroid Build Coastguard Worker store = true;
987*795d594fSAndroid Build Coastguard Worker break;
988*795d594fSAndroid Build Coastguard Worker case 0x7F:
989*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
990*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
991*795d594fSAndroid Build Coastguard Worker opcode1 = "movdqa";
992*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
993*795d594fSAndroid Build Coastguard Worker } else if (prefix[0] == 0xF3) {
994*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
995*795d594fSAndroid Build Coastguard Worker opcode1 = "movdqu";
996*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
997*795d594fSAndroid Build Coastguard Worker } else {
998*795d594fSAndroid Build Coastguard Worker dst_reg_file = MMX;
999*795d594fSAndroid Build Coastguard Worker opcode1 = "movq";
1000*795d594fSAndroid Build Coastguard Worker }
1001*795d594fSAndroid Build Coastguard Worker store = true;
1002*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1003*795d594fSAndroid Build Coastguard Worker break;
1004*795d594fSAndroid Build Coastguard Worker case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
1005*795d594fSAndroid Build Coastguard Worker case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
1006*795d594fSAndroid Build Coastguard Worker opcode1 = "j";
1007*795d594fSAndroid Build Coastguard Worker opcode2 = condition_codes[*instr & 0xF];
1008*795d594fSAndroid Build Coastguard Worker branch_bytes = 4;
1009*795d594fSAndroid Build Coastguard Worker break;
1010*795d594fSAndroid Build Coastguard Worker case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
1011*795d594fSAndroid Build Coastguard Worker case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
1012*795d594fSAndroid Build Coastguard Worker opcode1 = "set";
1013*795d594fSAndroid Build Coastguard Worker opcode2 = condition_codes[*instr & 0xF];
1014*795d594fSAndroid Build Coastguard Worker modrm_opcodes = nullptr;
1015*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1016*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1017*795d594fSAndroid Build Coastguard Worker store = true;
1018*795d594fSAndroid Build Coastguard Worker break;
1019*795d594fSAndroid Build Coastguard Worker case 0xA4:
1020*795d594fSAndroid Build Coastguard Worker opcode1 = "shld";
1021*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1022*795d594fSAndroid Build Coastguard Worker load = true;
1023*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
1024*795d594fSAndroid Build Coastguard Worker break;
1025*795d594fSAndroid Build Coastguard Worker case 0xA5:
1026*795d594fSAndroid Build Coastguard Worker opcode1 = "shld";
1027*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1028*795d594fSAndroid Build Coastguard Worker load = true;
1029*795d594fSAndroid Build Coastguard Worker cx = true;
1030*795d594fSAndroid Build Coastguard Worker break;
1031*795d594fSAndroid Build Coastguard Worker case 0xAC:
1032*795d594fSAndroid Build Coastguard Worker opcode1 = "shrd";
1033*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1034*795d594fSAndroid Build Coastguard Worker load = true;
1035*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
1036*795d594fSAndroid Build Coastguard Worker break;
1037*795d594fSAndroid Build Coastguard Worker case 0xAD:
1038*795d594fSAndroid Build Coastguard Worker opcode1 = "shrd";
1039*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1040*795d594fSAndroid Build Coastguard Worker load = true;
1041*795d594fSAndroid Build Coastguard Worker cx = true;
1042*795d594fSAndroid Build Coastguard Worker break;
1043*795d594fSAndroid Build Coastguard Worker case 0xAE:
1044*795d594fSAndroid Build Coastguard Worker if (prefix[0] == 0xF3) {
1045*795d594fSAndroid Build Coastguard Worker prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
1046*795d594fSAndroid Build Coastguard Worker static const char* xAE_opcodes[] = {
1047*795d594fSAndroid Build Coastguard Worker "rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase",
1048*795d594fSAndroid Build Coastguard Worker "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"};
1049*795d594fSAndroid Build Coastguard Worker modrm_opcodes = xAE_opcodes;
1050*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1051*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1052*795d594fSAndroid Build Coastguard Worker uint8_t reg_or_opcode = (instr[1] >> 3) & 7;
1053*795d594fSAndroid Build Coastguard Worker switch (reg_or_opcode) {
1054*795d594fSAndroid Build Coastguard Worker case 0:
1055*795d594fSAndroid Build Coastguard Worker prefix[1] = kFs;
1056*795d594fSAndroid Build Coastguard Worker load = true;
1057*795d594fSAndroid Build Coastguard Worker break;
1058*795d594fSAndroid Build Coastguard Worker case 1:
1059*795d594fSAndroid Build Coastguard Worker prefix[1] = kGs;
1060*795d594fSAndroid Build Coastguard Worker load = true;
1061*795d594fSAndroid Build Coastguard Worker break;
1062*795d594fSAndroid Build Coastguard Worker case 2:
1063*795d594fSAndroid Build Coastguard Worker prefix[1] = kFs;
1064*795d594fSAndroid Build Coastguard Worker store = true;
1065*795d594fSAndroid Build Coastguard Worker break;
1066*795d594fSAndroid Build Coastguard Worker case 3:
1067*795d594fSAndroid Build Coastguard Worker prefix[1] = kGs;
1068*795d594fSAndroid Build Coastguard Worker store = true;
1069*795d594fSAndroid Build Coastguard Worker break;
1070*795d594fSAndroid Build Coastguard Worker default:
1071*795d594fSAndroid Build Coastguard Worker load = true;
1072*795d594fSAndroid Build Coastguard Worker break;
1073*795d594fSAndroid Build Coastguard Worker }
1074*795d594fSAndroid Build Coastguard Worker } else {
1075*795d594fSAndroid Build Coastguard Worker static const char* xAE_opcodes[] = {
1076*795d594fSAndroid Build Coastguard Worker "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE",
1077*795d594fSAndroid Build Coastguard Worker "unknown-AE", "lfence", "mfence", "sfence"};
1078*795d594fSAndroid Build Coastguard Worker modrm_opcodes = xAE_opcodes;
1079*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1080*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1081*795d594fSAndroid Build Coastguard Worker load = true;
1082*795d594fSAndroid Build Coastguard Worker no_ops = true;
1083*795d594fSAndroid Build Coastguard Worker }
1084*795d594fSAndroid Build Coastguard Worker break;
1085*795d594fSAndroid Build Coastguard Worker case 0xAF:
1086*795d594fSAndroid Build Coastguard Worker opcode1 = "imul";
1087*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1088*795d594fSAndroid Build Coastguard Worker load = true;
1089*795d594fSAndroid Build Coastguard Worker break;
1090*795d594fSAndroid Build Coastguard Worker case 0xB1:
1091*795d594fSAndroid Build Coastguard Worker opcode1 = "cmpxchg";
1092*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1093*795d594fSAndroid Build Coastguard Worker store = true;
1094*795d594fSAndroid Build Coastguard Worker break;
1095*795d594fSAndroid Build Coastguard Worker case 0xB6:
1096*795d594fSAndroid Build Coastguard Worker opcode1 = "movzxb";
1097*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1098*795d594fSAndroid Build Coastguard Worker load = true;
1099*795d594fSAndroid Build Coastguard Worker byte_second_operand = true;
1100*795d594fSAndroid Build Coastguard Worker break;
1101*795d594fSAndroid Build Coastguard Worker case 0xB7:
1102*795d594fSAndroid Build Coastguard Worker opcode1 = "movzxw";
1103*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1104*795d594fSAndroid Build Coastguard Worker load = true;
1105*795d594fSAndroid Build Coastguard Worker break;
1106*795d594fSAndroid Build Coastguard Worker case 0xBC:
1107*795d594fSAndroid Build Coastguard Worker opcode1 = "bsf";
1108*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1109*795d594fSAndroid Build Coastguard Worker load = true;
1110*795d594fSAndroid Build Coastguard Worker break;
1111*795d594fSAndroid Build Coastguard Worker case 0xBD:
1112*795d594fSAndroid Build Coastguard Worker opcode1 = "bsr";
1113*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1114*795d594fSAndroid Build Coastguard Worker load = true;
1115*795d594fSAndroid Build Coastguard Worker break;
1116*795d594fSAndroid Build Coastguard Worker case 0xB8:
1117*795d594fSAndroid Build Coastguard Worker opcode1 = "popcnt";
1118*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1119*795d594fSAndroid Build Coastguard Worker load = true;
1120*795d594fSAndroid Build Coastguard Worker break;
1121*795d594fSAndroid Build Coastguard Worker case 0xBE:
1122*795d594fSAndroid Build Coastguard Worker opcode1 = "movsxb";
1123*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1124*795d594fSAndroid Build Coastguard Worker load = true;
1125*795d594fSAndroid Build Coastguard Worker byte_second_operand = true;
1126*795d594fSAndroid Build Coastguard Worker rex |= (rex == 0 ? 0 : REX_W);
1127*795d594fSAndroid Build Coastguard Worker break;
1128*795d594fSAndroid Build Coastguard Worker case 0xBF:
1129*795d594fSAndroid Build Coastguard Worker opcode1 = "movsxw";
1130*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1131*795d594fSAndroid Build Coastguard Worker load = true;
1132*795d594fSAndroid Build Coastguard Worker break;
1133*795d594fSAndroid Build Coastguard Worker case 0xC3:
1134*795d594fSAndroid Build Coastguard Worker opcode1 = "movnti";
1135*795d594fSAndroid Build Coastguard Worker store = true;
1136*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1137*795d594fSAndroid Build Coastguard Worker break;
1138*795d594fSAndroid Build Coastguard Worker case 0xC5:
1139*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1140*795d594fSAndroid Build Coastguard Worker opcode1 = "pextrw";
1141*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1142*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1143*795d594fSAndroid Build Coastguard Worker load = true;
1144*795d594fSAndroid Build Coastguard Worker src_reg_file = SSE;
1145*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
1146*795d594fSAndroid Build Coastguard Worker } else {
1147*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
1148*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
1149*795d594fSAndroid Build Coastguard Worker }
1150*795d594fSAndroid Build Coastguard Worker break;
1151*795d594fSAndroid Build Coastguard Worker case 0xC6:
1152*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1153*795d594fSAndroid Build Coastguard Worker opcode1 = "shufpd";
1154*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1155*795d594fSAndroid Build Coastguard Worker } else {
1156*795d594fSAndroid Build Coastguard Worker opcode1 = "shufps";
1157*795d594fSAndroid Build Coastguard Worker }
1158*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1159*795d594fSAndroid Build Coastguard Worker store = true;
1160*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1161*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
1162*795d594fSAndroid Build Coastguard Worker break;
1163*795d594fSAndroid Build Coastguard Worker case 0xC7:
1164*795d594fSAndroid Build Coastguard Worker static const char* x0FxC7_opcodes[] = {
1165*795d594fSAndroid Build Coastguard Worker "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7",
1166*795d594fSAndroid Build Coastguard Worker "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7"};
1167*795d594fSAndroid Build Coastguard Worker modrm_opcodes = x0FxC7_opcodes;
1168*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1169*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1170*795d594fSAndroid Build Coastguard Worker store = true;
1171*795d594fSAndroid Build Coastguard Worker break;
1172*795d594fSAndroid Build Coastguard Worker case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
1173*795d594fSAndroid Build Coastguard Worker opcode1 = "bswap";
1174*795d594fSAndroid Build Coastguard Worker reg_in_opcode = true;
1175*795d594fSAndroid Build Coastguard Worker break;
1176*795d594fSAndroid Build Coastguard Worker case 0xD4:
1177*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1178*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1179*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1180*795d594fSAndroid Build Coastguard Worker } else {
1181*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
1182*795d594fSAndroid Build Coastguard Worker }
1183*795d594fSAndroid Build Coastguard Worker opcode1 = "paddq";
1184*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1185*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1186*795d594fSAndroid Build Coastguard Worker load = true;
1187*795d594fSAndroid Build Coastguard Worker break;
1188*795d594fSAndroid Build Coastguard Worker case 0xDB:
1189*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1190*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1191*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1192*795d594fSAndroid Build Coastguard Worker } else {
1193*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
1194*795d594fSAndroid Build Coastguard Worker }
1195*795d594fSAndroid Build Coastguard Worker opcode1 = "pand";
1196*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1197*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1198*795d594fSAndroid Build Coastguard Worker load = true;
1199*795d594fSAndroid Build Coastguard Worker break;
1200*795d594fSAndroid Build Coastguard Worker case 0xD5:
1201*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1202*795d594fSAndroid Build Coastguard Worker opcode1 = "pmullw";
1203*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1204*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1205*795d594fSAndroid Build Coastguard Worker load = true;
1206*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1207*795d594fSAndroid Build Coastguard Worker } else {
1208*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
1209*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
1210*795d594fSAndroid Build Coastguard Worker }
1211*795d594fSAndroid Build Coastguard Worker break;
1212*795d594fSAndroid Build Coastguard Worker case 0xD8:
1213*795d594fSAndroid Build Coastguard Worker case 0xD9:
1214*795d594fSAndroid Build Coastguard Worker case 0xDA:
1215*795d594fSAndroid Build Coastguard Worker case 0xDC:
1216*795d594fSAndroid Build Coastguard Worker case 0xDD:
1217*795d594fSAndroid Build Coastguard Worker case 0xDE:
1218*795d594fSAndroid Build Coastguard Worker case 0xE0:
1219*795d594fSAndroid Build Coastguard Worker case 0xE3:
1220*795d594fSAndroid Build Coastguard Worker case 0xE8:
1221*795d594fSAndroid Build Coastguard Worker case 0xE9:
1222*795d594fSAndroid Build Coastguard Worker case 0xEA:
1223*795d594fSAndroid Build Coastguard Worker case 0xEC:
1224*795d594fSAndroid Build Coastguard Worker case 0xED:
1225*795d594fSAndroid Build Coastguard Worker case 0xEE:
1226*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1227*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1228*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1229*795d594fSAndroid Build Coastguard Worker } else {
1230*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
1231*795d594fSAndroid Build Coastguard Worker }
1232*795d594fSAndroid Build Coastguard Worker switch (*instr) {
1233*795d594fSAndroid Build Coastguard Worker case 0xD8: opcode1 = "psubusb"; break;
1234*795d594fSAndroid Build Coastguard Worker case 0xD9: opcode1 = "psubusw"; break;
1235*795d594fSAndroid Build Coastguard Worker case 0xDA: opcode1 = "pminub"; break;
1236*795d594fSAndroid Build Coastguard Worker case 0xDC: opcode1 = "paddusb"; break;
1237*795d594fSAndroid Build Coastguard Worker case 0xDD: opcode1 = "paddusw"; break;
1238*795d594fSAndroid Build Coastguard Worker case 0xDE: opcode1 = "pmaxub"; break;
1239*795d594fSAndroid Build Coastguard Worker case 0xE0: opcode1 = "pavgb"; break;
1240*795d594fSAndroid Build Coastguard Worker case 0xE3: opcode1 = "pavgw"; break;
1241*795d594fSAndroid Build Coastguard Worker case 0xE8: opcode1 = "psubsb"; break;
1242*795d594fSAndroid Build Coastguard Worker case 0xE9: opcode1 = "psubsw"; break;
1243*795d594fSAndroid Build Coastguard Worker case 0xEA: opcode1 = "pminsw"; break;
1244*795d594fSAndroid Build Coastguard Worker case 0xEC: opcode1 = "paddsb"; break;
1245*795d594fSAndroid Build Coastguard Worker case 0xED: opcode1 = "paddsw"; break;
1246*795d594fSAndroid Build Coastguard Worker case 0xEE: opcode1 = "pmaxsw"; break;
1247*795d594fSAndroid Build Coastguard Worker }
1248*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1249*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1250*795d594fSAndroid Build Coastguard Worker load = true;
1251*795d594fSAndroid Build Coastguard Worker break;
1252*795d594fSAndroid Build Coastguard Worker case 0xEB:
1253*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1254*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1255*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1256*795d594fSAndroid Build Coastguard Worker } else {
1257*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
1258*795d594fSAndroid Build Coastguard Worker }
1259*795d594fSAndroid Build Coastguard Worker opcode1 = "por";
1260*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1261*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1262*795d594fSAndroid Build Coastguard Worker load = true;
1263*795d594fSAndroid Build Coastguard Worker break;
1264*795d594fSAndroid Build Coastguard Worker case 0xEF:
1265*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1266*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1267*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1268*795d594fSAndroid Build Coastguard Worker } else {
1269*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
1270*795d594fSAndroid Build Coastguard Worker }
1271*795d594fSAndroid Build Coastguard Worker opcode1 = "pxor";
1272*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1273*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1274*795d594fSAndroid Build Coastguard Worker load = true;
1275*795d594fSAndroid Build Coastguard Worker break;
1276*795d594fSAndroid Build Coastguard Worker case 0xF4:
1277*795d594fSAndroid Build Coastguard Worker case 0xF6:
1278*795d594fSAndroid Build Coastguard Worker case 0xF8:
1279*795d594fSAndroid Build Coastguard Worker case 0xF9:
1280*795d594fSAndroid Build Coastguard Worker case 0xFA:
1281*795d594fSAndroid Build Coastguard Worker case 0xFB:
1282*795d594fSAndroid Build Coastguard Worker case 0xFC:
1283*795d594fSAndroid Build Coastguard Worker case 0xFD:
1284*795d594fSAndroid Build Coastguard Worker case 0xFE:
1285*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) {
1286*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = SSE;
1287*795d594fSAndroid Build Coastguard Worker prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1288*795d594fSAndroid Build Coastguard Worker } else {
1289*795d594fSAndroid Build Coastguard Worker src_reg_file = dst_reg_file = MMX;
1290*795d594fSAndroid Build Coastguard Worker }
1291*795d594fSAndroid Build Coastguard Worker switch (*instr) {
1292*795d594fSAndroid Build Coastguard Worker case 0xF4: opcode1 = "pmuludq"; break;
1293*795d594fSAndroid Build Coastguard Worker case 0xF6: opcode1 = "psadbw"; break;
1294*795d594fSAndroid Build Coastguard Worker case 0xF8: opcode1 = "psubb"; break;
1295*795d594fSAndroid Build Coastguard Worker case 0xF9: opcode1 = "psubw"; break;
1296*795d594fSAndroid Build Coastguard Worker case 0xFA: opcode1 = "psubd"; break;
1297*795d594fSAndroid Build Coastguard Worker case 0xFB: opcode1 = "psubq"; break;
1298*795d594fSAndroid Build Coastguard Worker case 0xFC: opcode1 = "paddb"; break;
1299*795d594fSAndroid Build Coastguard Worker case 0xFD: opcode1 = "paddw"; break;
1300*795d594fSAndroid Build Coastguard Worker case 0xFE: opcode1 = "paddd"; break;
1301*795d594fSAndroid Build Coastguard Worker }
1302*795d594fSAndroid Build Coastguard Worker prefix[2] = 0;
1303*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1304*795d594fSAndroid Build Coastguard Worker load = true;
1305*795d594fSAndroid Build Coastguard Worker break;
1306*795d594fSAndroid Build Coastguard Worker default:
1307*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
1308*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
1309*795d594fSAndroid Build Coastguard Worker break;
1310*795d594fSAndroid Build Coastguard Worker }
1311*795d594fSAndroid Build Coastguard Worker break;
1312*795d594fSAndroid Build Coastguard Worker case 0x80: case 0x81: case 0x82: case 0x83:
1313*795d594fSAndroid Build Coastguard Worker static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"};
1314*795d594fSAndroid Build Coastguard Worker modrm_opcodes = x80_opcodes;
1315*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1316*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1317*795d594fSAndroid Build Coastguard Worker store = true;
1318*795d594fSAndroid Build Coastguard Worker byte_operand = (*instr & 1) == 0;
1319*795d594fSAndroid Build Coastguard Worker immediate_bytes = *instr == 0x81 ? 4 : 1;
1320*795d594fSAndroid Build Coastguard Worker break;
1321*795d594fSAndroid Build Coastguard Worker case 0x84: case 0x85:
1322*795d594fSAndroid Build Coastguard Worker opcode1 = "test";
1323*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1324*795d594fSAndroid Build Coastguard Worker load = true;
1325*795d594fSAndroid Build Coastguard Worker byte_operand = (*instr & 1) == 0;
1326*795d594fSAndroid Build Coastguard Worker break;
1327*795d594fSAndroid Build Coastguard Worker case 0x8D:
1328*795d594fSAndroid Build Coastguard Worker opcode1 = "lea";
1329*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1330*795d594fSAndroid Build Coastguard Worker load = true;
1331*795d594fSAndroid Build Coastguard Worker break;
1332*795d594fSAndroid Build Coastguard Worker case 0x8F:
1333*795d594fSAndroid Build Coastguard Worker opcode1 = "pop";
1334*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1335*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1336*795d594fSAndroid Build Coastguard Worker store = true;
1337*795d594fSAndroid Build Coastguard Worker break;
1338*795d594fSAndroid Build Coastguard Worker case 0x99:
1339*795d594fSAndroid Build Coastguard Worker opcode1 = "cdq";
1340*795d594fSAndroid Build Coastguard Worker break;
1341*795d594fSAndroid Build Coastguard Worker case 0x9B:
1342*795d594fSAndroid Build Coastguard Worker if (instr[1] == 0xDF && instr[2] == 0xE0) {
1343*795d594fSAndroid Build Coastguard Worker opcode1 = "fstsw\tax";
1344*795d594fSAndroid Build Coastguard Worker instr += 2;
1345*795d594fSAndroid Build Coastguard Worker } else {
1346*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
1347*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
1348*795d594fSAndroid Build Coastguard Worker }
1349*795d594fSAndroid Build Coastguard Worker break;
1350*795d594fSAndroid Build Coastguard Worker case 0xA5:
1351*795d594fSAndroid Build Coastguard Worker opcode1 = (prefix[2] == 0x66 ? "movsw" : "movsl");
1352*795d594fSAndroid Build Coastguard Worker break;
1353*795d594fSAndroid Build Coastguard Worker case 0xA7:
1354*795d594fSAndroid Build Coastguard Worker opcode1 = (prefix[2] == 0x66 ? "cmpsw" : "cmpsl");
1355*795d594fSAndroid Build Coastguard Worker break;
1356*795d594fSAndroid Build Coastguard Worker case 0xAF:
1357*795d594fSAndroid Build Coastguard Worker opcode1 = (prefix[2] == 0x66 ? "scasw" : "scasl");
1358*795d594fSAndroid Build Coastguard Worker break;
1359*795d594fSAndroid Build Coastguard Worker case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
1360*795d594fSAndroid Build Coastguard Worker opcode1 = "mov";
1361*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
1362*795d594fSAndroid Build Coastguard Worker byte_operand = true;
1363*795d594fSAndroid Build Coastguard Worker reg_in_opcode = true;
1364*795d594fSAndroid Build Coastguard Worker byte_operand = true;
1365*795d594fSAndroid Build Coastguard Worker break;
1366*795d594fSAndroid Build Coastguard Worker case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
1367*795d594fSAndroid Build Coastguard Worker if ((rex & REX_W) != 0) {
1368*795d594fSAndroid Build Coastguard Worker opcode1 = "movabsq";
1369*795d594fSAndroid Build Coastguard Worker immediate_bytes = 8;
1370*795d594fSAndroid Build Coastguard Worker reg_in_opcode = true;
1371*795d594fSAndroid Build Coastguard Worker break;
1372*795d594fSAndroid Build Coastguard Worker }
1373*795d594fSAndroid Build Coastguard Worker opcode1 = "mov";
1374*795d594fSAndroid Build Coastguard Worker immediate_bytes = 4;
1375*795d594fSAndroid Build Coastguard Worker reg_in_opcode = true;
1376*795d594fSAndroid Build Coastguard Worker break;
1377*795d594fSAndroid Build Coastguard Worker case 0xC0: case 0xC1:
1378*795d594fSAndroid Build Coastguard Worker case 0xD0: case 0xD1: case 0xD2: case 0xD3:
1379*795d594fSAndroid Build Coastguard Worker static const char* shift_opcodes[] =
1380*795d594fSAndroid Build Coastguard Worker {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"};
1381*795d594fSAndroid Build Coastguard Worker modrm_opcodes = shift_opcodes;
1382*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1383*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1384*795d594fSAndroid Build Coastguard Worker store = true;
1385*795d594fSAndroid Build Coastguard Worker immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0;
1386*795d594fSAndroid Build Coastguard Worker cx = (*instr == 0xD2) || (*instr == 0xD3);
1387*795d594fSAndroid Build Coastguard Worker byte_operand = (*instr == 0xC0);
1388*795d594fSAndroid Build Coastguard Worker break;
1389*795d594fSAndroid Build Coastguard Worker case 0xC3: opcode1 = "ret"; break;
1390*795d594fSAndroid Build Coastguard Worker
1391*795d594fSAndroid Build Coastguard Worker case 0xC6:
1392*795d594fSAndroid Build Coastguard Worker static const char* c6_opcodes[] = {"mov", "unknown-c6", "unknown-c6",
1393*795d594fSAndroid Build Coastguard Worker "unknown-c6", "unknown-c6", "unknown-c6",
1394*795d594fSAndroid Build Coastguard Worker "unknown-c6", "unknown-c6"};
1395*795d594fSAndroid Build Coastguard Worker modrm_opcodes = c6_opcodes;
1396*795d594fSAndroid Build Coastguard Worker store = true;
1397*795d594fSAndroid Build Coastguard Worker immediate_bytes = 1;
1398*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1399*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1400*795d594fSAndroid Build Coastguard Worker byte_operand = true;
1401*795d594fSAndroid Build Coastguard Worker break;
1402*795d594fSAndroid Build Coastguard Worker case 0xC7:
1403*795d594fSAndroid Build Coastguard Worker static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7",
1404*795d594fSAndroid Build Coastguard Worker "unknown-c7", "unknown-c7", "unknown-c7",
1405*795d594fSAndroid Build Coastguard Worker "unknown-c7", "unknown-c7"};
1406*795d594fSAndroid Build Coastguard Worker modrm_opcodes = c7_opcodes;
1407*795d594fSAndroid Build Coastguard Worker store = true;
1408*795d594fSAndroid Build Coastguard Worker immediate_bytes = 4;
1409*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1410*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1411*795d594fSAndroid Build Coastguard Worker break;
1412*795d594fSAndroid Build Coastguard Worker case 0xCC: opcode1 = "int 3"; break;
1413*795d594fSAndroid Build Coastguard Worker case 0xD9:
1414*795d594fSAndroid Build Coastguard Worker if (instr[1] == 0xF8) {
1415*795d594fSAndroid Build Coastguard Worker opcode1 = "fprem";
1416*795d594fSAndroid Build Coastguard Worker instr++;
1417*795d594fSAndroid Build Coastguard Worker } else {
1418*795d594fSAndroid Build Coastguard Worker static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw",
1419*795d594fSAndroid Build Coastguard Worker "fnstenv", "fnstcw"};
1420*795d594fSAndroid Build Coastguard Worker modrm_opcodes = d9_opcodes;
1421*795d594fSAndroid Build Coastguard Worker store = true;
1422*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1423*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1424*795d594fSAndroid Build Coastguard Worker }
1425*795d594fSAndroid Build Coastguard Worker break;
1426*795d594fSAndroid Build Coastguard Worker case 0xDA:
1427*795d594fSAndroid Build Coastguard Worker if (instr[1] == 0xE9) {
1428*795d594fSAndroid Build Coastguard Worker opcode1 = "fucompp";
1429*795d594fSAndroid Build Coastguard Worker instr++;
1430*795d594fSAndroid Build Coastguard Worker } else {
1431*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
1432*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
1433*795d594fSAndroid Build Coastguard Worker }
1434*795d594fSAndroid Build Coastguard Worker break;
1435*795d594fSAndroid Build Coastguard Worker case 0xDB:
1436*795d594fSAndroid Build Coastguard Worker static const char* db_opcodes[] = {"fildl", "unknown-db", "unknown-db",
1437*795d594fSAndroid Build Coastguard Worker "unknown-db", "unknown-db", "unknown-db",
1438*795d594fSAndroid Build Coastguard Worker "unknown-db", "unknown-db"};
1439*795d594fSAndroid Build Coastguard Worker modrm_opcodes = db_opcodes;
1440*795d594fSAndroid Build Coastguard Worker load = true;
1441*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1442*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1443*795d594fSAndroid Build Coastguard Worker break;
1444*795d594fSAndroid Build Coastguard Worker case 0xDD:
1445*795d594fSAndroid Build Coastguard Worker static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl",
1446*795d594fSAndroid Build Coastguard Worker "fstpl", "frstor", "unknown-dd",
1447*795d594fSAndroid Build Coastguard Worker "fnsave", "fnstsw"};
1448*795d594fSAndroid Build Coastguard Worker modrm_opcodes = dd_opcodes;
1449*795d594fSAndroid Build Coastguard Worker store = true;
1450*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1451*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1452*795d594fSAndroid Build Coastguard Worker break;
1453*795d594fSAndroid Build Coastguard Worker case 0xDF:
1454*795d594fSAndroid Build Coastguard Worker static const char* df_opcodes[] = {"fild", "unknown-df", "unknown-df",
1455*795d594fSAndroid Build Coastguard Worker "unknown-df", "unknown-df", "fildll",
1456*795d594fSAndroid Build Coastguard Worker "unknown-df", "unknown-df"};
1457*795d594fSAndroid Build Coastguard Worker modrm_opcodes = df_opcodes;
1458*795d594fSAndroid Build Coastguard Worker load = true;
1459*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1460*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1461*795d594fSAndroid Build Coastguard Worker break;
1462*795d594fSAndroid Build Coastguard Worker case 0xE3: opcode1 = "jecxz"; branch_bytes = 1; break;
1463*795d594fSAndroid Build Coastguard Worker case 0xE8: opcode1 = "call"; branch_bytes = 4; break;
1464*795d594fSAndroid Build Coastguard Worker case 0xE9: opcode1 = "jmp"; branch_bytes = 4; break;
1465*795d594fSAndroid Build Coastguard Worker case 0xEB: opcode1 = "jmp"; branch_bytes = 1; break;
1466*795d594fSAndroid Build Coastguard Worker case 0xF5: opcode1 = "cmc"; break;
1467*795d594fSAndroid Build Coastguard Worker case 0xF6: case 0xF7:
1468*795d594fSAndroid Build Coastguard Worker static const char* f7_opcodes[] = {
1469*795d594fSAndroid Build Coastguard Worker "test", "unknown-f7", "not", "neg", "mul edx:eax, eax *",
1470*795d594fSAndroid Build Coastguard Worker "imul edx:eax, eax *", "div edx:eax, edx:eax /",
1471*795d594fSAndroid Build Coastguard Worker "idiv edx:eax, edx:eax /"};
1472*795d594fSAndroid Build Coastguard Worker modrm_opcodes = f7_opcodes;
1473*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1474*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1475*795d594fSAndroid Build Coastguard Worker store = true;
1476*795d594fSAndroid Build Coastguard Worker immediate_bytes = ((instr[1] & 0x38) == 0) ? (instr[0] == 0xF7 ? 4 : 1) : 0;
1477*795d594fSAndroid Build Coastguard Worker break;
1478*795d594fSAndroid Build Coastguard Worker case 0xFF:
1479*795d594fSAndroid Build Coastguard Worker {
1480*795d594fSAndroid Build Coastguard Worker static const char* ff_opcodes[] = {
1481*795d594fSAndroid Build Coastguard Worker "inc", "dec", "call", "call",
1482*795d594fSAndroid Build Coastguard Worker "jmp", "jmp", "push", "unknown-ff"};
1483*795d594fSAndroid Build Coastguard Worker modrm_opcodes = ff_opcodes;
1484*795d594fSAndroid Build Coastguard Worker has_modrm = true;
1485*795d594fSAndroid Build Coastguard Worker reg_is_opcode = true;
1486*795d594fSAndroid Build Coastguard Worker load = true;
1487*795d594fSAndroid Build Coastguard Worker const uint8_t opcode_digit = (instr[1] >> 3) & 7;
1488*795d594fSAndroid Build Coastguard Worker // 'call', 'jmp' and 'push' are target specific instructions
1489*795d594fSAndroid Build Coastguard Worker if (opcode_digit == 2 || opcode_digit == 4 || opcode_digit == 6) {
1490*795d594fSAndroid Build Coastguard Worker target_specific = true;
1491*795d594fSAndroid Build Coastguard Worker }
1492*795d594fSAndroid Build Coastguard Worker }
1493*795d594fSAndroid Build Coastguard Worker break;
1494*795d594fSAndroid Build Coastguard Worker default:
1495*795d594fSAndroid Build Coastguard Worker opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
1496*795d594fSAndroid Build Coastguard Worker opcode1 = opcode_tmp.c_str();
1497*795d594fSAndroid Build Coastguard Worker break;
1498*795d594fSAndroid Build Coastguard Worker }
1499*795d594fSAndroid Build Coastguard Worker std::ostringstream args;
1500*795d594fSAndroid Build Coastguard Worker // We force the REX prefix to be available for 64-bit target
1501*795d594fSAndroid Build Coastguard Worker // in order to dump addr (base/index) registers correctly.
1502*795d594fSAndroid Build Coastguard Worker uint8_t rex64 = supports_rex_ ? (rex | 0x40) : rex;
1503*795d594fSAndroid Build Coastguard Worker // REX.W should be forced for 64-target and target-specific instructions (i.e., push or pop).
1504*795d594fSAndroid Build Coastguard Worker uint8_t rex_w = (supports_rex_ && target_specific) ? (rex | 0x48) : rex;
1505*795d594fSAndroid Build Coastguard Worker if (reg_in_opcode) {
1506*795d594fSAndroid Build Coastguard Worker DCHECK(!has_modrm);
1507*795d594fSAndroid Build Coastguard Worker DumpOpcodeReg(args, rex_w, *instr & 0x7, byte_operand, prefix[2]);
1508*795d594fSAndroid Build Coastguard Worker }
1509*795d594fSAndroid Build Coastguard Worker instr++;
1510*795d594fSAndroid Build Coastguard Worker uint32_t address_bits = 0;
1511*795d594fSAndroid Build Coastguard Worker if (has_modrm) {
1512*795d594fSAndroid Build Coastguard Worker uint8_t modrm = *instr;
1513*795d594fSAndroid Build Coastguard Worker instr++;
1514*795d594fSAndroid Build Coastguard Worker uint8_t mod = modrm >> 6;
1515*795d594fSAndroid Build Coastguard Worker uint8_t reg_or_opcode = (modrm >> 3) & 7;
1516*795d594fSAndroid Build Coastguard Worker uint8_t rm = modrm & 7;
1517*795d594fSAndroid Build Coastguard Worker std::string address = DumpAddress(mod, rm, rex64, rex_w, no_ops, byte_operand,
1518*795d594fSAndroid Build Coastguard Worker byte_second_operand, prefix, load, src_reg_file, dst_reg_file,
1519*795d594fSAndroid Build Coastguard Worker &instr, &address_bits);
1520*795d594fSAndroid Build Coastguard Worker
1521*795d594fSAndroid Build Coastguard Worker if (reg_is_opcode && modrm_opcodes != nullptr) {
1522*795d594fSAndroid Build Coastguard Worker opcode3 = modrm_opcodes[reg_or_opcode];
1523*795d594fSAndroid Build Coastguard Worker }
1524*795d594fSAndroid Build Coastguard Worker
1525*795d594fSAndroid Build Coastguard Worker // Add opcode suffixes to indicate size.
1526*795d594fSAndroid Build Coastguard Worker if (byte_operand) {
1527*795d594fSAndroid Build Coastguard Worker opcode4 = "b";
1528*795d594fSAndroid Build Coastguard Worker } else if ((rex & REX_W) != 0) {
1529*795d594fSAndroid Build Coastguard Worker opcode4 = "q";
1530*795d594fSAndroid Build Coastguard Worker } else if (prefix[2] == 0x66) {
1531*795d594fSAndroid Build Coastguard Worker opcode4 = "w";
1532*795d594fSAndroid Build Coastguard Worker }
1533*795d594fSAndroid Build Coastguard Worker
1534*795d594fSAndroid Build Coastguard Worker if (load) {
1535*795d594fSAndroid Build Coastguard Worker if (!reg_is_opcode) {
1536*795d594fSAndroid Build Coastguard Worker DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
1537*795d594fSAndroid Build Coastguard Worker args << ", ";
1538*795d594fSAndroid Build Coastguard Worker }
1539*795d594fSAndroid Build Coastguard Worker DumpSegmentOverride(args, prefix[1]);
1540*795d594fSAndroid Build Coastguard Worker
1541*795d594fSAndroid Build Coastguard Worker args << address;
1542*795d594fSAndroid Build Coastguard Worker } else {
1543*795d594fSAndroid Build Coastguard Worker DCHECK(store);
1544*795d594fSAndroid Build Coastguard Worker DumpSegmentOverride(args, prefix[1]);
1545*795d594fSAndroid Build Coastguard Worker args << address;
1546*795d594fSAndroid Build Coastguard Worker if (!reg_is_opcode) {
1547*795d594fSAndroid Build Coastguard Worker args << ", ";
1548*795d594fSAndroid Build Coastguard Worker DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
1549*795d594fSAndroid Build Coastguard Worker }
1550*795d594fSAndroid Build Coastguard Worker }
1551*795d594fSAndroid Build Coastguard Worker }
1552*795d594fSAndroid Build Coastguard Worker if (ax) {
1553*795d594fSAndroid Build Coastguard Worker // If this opcode implicitly uses ax, ax is always the first arg.
1554*795d594fSAndroid Build Coastguard Worker DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
1555*795d594fSAndroid Build Coastguard Worker }
1556*795d594fSAndroid Build Coastguard Worker if (cx) {
1557*795d594fSAndroid Build Coastguard Worker args << ", ";
1558*795d594fSAndroid Build Coastguard Worker DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR);
1559*795d594fSAndroid Build Coastguard Worker }
1560*795d594fSAndroid Build Coastguard Worker if (immediate_bytes > 0) {
1561*795d594fSAndroid Build Coastguard Worker if (has_modrm || reg_in_opcode || ax || cx) {
1562*795d594fSAndroid Build Coastguard Worker args << ", ";
1563*795d594fSAndroid Build Coastguard Worker }
1564*795d594fSAndroid Build Coastguard Worker if (immediate_bytes == 1) {
1565*795d594fSAndroid Build Coastguard Worker args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr));
1566*795d594fSAndroid Build Coastguard Worker instr++;
1567*795d594fSAndroid Build Coastguard Worker } else if (immediate_bytes == 4) {
1568*795d594fSAndroid Build Coastguard Worker if (prefix[2] == 0x66) { // Operand size override from 32-bit to 16-bit.
1569*795d594fSAndroid Build Coastguard Worker args << StringPrintf("%d", *reinterpret_cast<const int16_t*>(instr));
1570*795d594fSAndroid Build Coastguard Worker instr += 2;
1571*795d594fSAndroid Build Coastguard Worker } else {
1572*795d594fSAndroid Build Coastguard Worker args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr));
1573*795d594fSAndroid Build Coastguard Worker instr += 4;
1574*795d594fSAndroid Build Coastguard Worker }
1575*795d594fSAndroid Build Coastguard Worker } else {
1576*795d594fSAndroid Build Coastguard Worker CHECK_EQ(immediate_bytes, 8u);
1577*795d594fSAndroid Build Coastguard Worker args << StringPrintf("%" PRId64, *reinterpret_cast<const int64_t*>(instr));
1578*795d594fSAndroid Build Coastguard Worker instr += 8;
1579*795d594fSAndroid Build Coastguard Worker }
1580*795d594fSAndroid Build Coastguard Worker } else if (branch_bytes > 0) {
1581*795d594fSAndroid Build Coastguard Worker DCHECK(!has_modrm);
1582*795d594fSAndroid Build Coastguard Worker int32_t displacement;
1583*795d594fSAndroid Build Coastguard Worker if (branch_bytes == 1) {
1584*795d594fSAndroid Build Coastguard Worker displacement = *reinterpret_cast<const int8_t*>(instr);
1585*795d594fSAndroid Build Coastguard Worker instr++;
1586*795d594fSAndroid Build Coastguard Worker } else {
1587*795d594fSAndroid Build Coastguard Worker CHECK_EQ(branch_bytes, 4u);
1588*795d594fSAndroid Build Coastguard Worker displacement = *reinterpret_cast<const int32_t*>(instr);
1589*795d594fSAndroid Build Coastguard Worker instr += 4;
1590*795d594fSAndroid Build Coastguard Worker }
1591*795d594fSAndroid Build Coastguard Worker args << StringPrintf("%+d (", displacement)
1592*795d594fSAndroid Build Coastguard Worker << FormatInstructionPointer(instr + displacement)
1593*795d594fSAndroid Build Coastguard Worker << ")";
1594*795d594fSAndroid Build Coastguard Worker }
1595*795d594fSAndroid Build Coastguard Worker if (prefix[1] == kFs && !supports_rex_) {
1596*795d594fSAndroid Build Coastguard Worker args << " ; ";
1597*795d594fSAndroid Build Coastguard Worker GetDisassemblerOptions()->thread_offset_name_function_(args, address_bits);
1598*795d594fSAndroid Build Coastguard Worker }
1599*795d594fSAndroid Build Coastguard Worker if (prefix[1] == kGs && supports_rex_) {
1600*795d594fSAndroid Build Coastguard Worker args << " ; ";
1601*795d594fSAndroid Build Coastguard Worker GetDisassemblerOptions()->thread_offset_name_function_(args, address_bits);
1602*795d594fSAndroid Build Coastguard Worker }
1603*795d594fSAndroid Build Coastguard Worker const char* prefix_str;
1604*795d594fSAndroid Build Coastguard Worker switch (prefix[0]) {
1605*795d594fSAndroid Build Coastguard Worker case 0xF0: prefix_str = "lock "; break;
1606*795d594fSAndroid Build Coastguard Worker case 0xF2: prefix_str = "repne "; break;
1607*795d594fSAndroid Build Coastguard Worker case 0xF3: prefix_str = "repe "; break;
1608*795d594fSAndroid Build Coastguard Worker case 0: prefix_str = ""; break;
1609*795d594fSAndroid Build Coastguard Worker default: LOG(FATAL) << "Unreachable"; UNREACHABLE();
1610*795d594fSAndroid Build Coastguard Worker }
1611*795d594fSAndroid Build Coastguard Worker os << FormatInstructionPointer(begin_instr)
1612*795d594fSAndroid Build Coastguard Worker << StringPrintf(": %22s \t%-7s%s%s%s%s%s ", DumpCodeHex(begin_instr, instr).c_str(),
1613*795d594fSAndroid Build Coastguard Worker prefix_str, opcode0, opcode1, opcode2, opcode3, opcode4)
1614*795d594fSAndroid Build Coastguard Worker << args.str() << '\n';
1615*795d594fSAndroid Build Coastguard Worker return instr - begin_instr;
1616*795d594fSAndroid Build Coastguard Worker } // NOLINT(readability/fn_size)
1617*795d594fSAndroid Build Coastguard Worker
1618*795d594fSAndroid Build Coastguard Worker } // namespace x86
1619*795d594fSAndroid Build Coastguard Worker } // namespace art
1620