blob: b58f5fa3c5889bb07fa5b409de2ed853ae50ceb7 [file] [log] [blame]
Ian Rogers706a10e2012-03-23 17:00:55 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "disassembler_x86.h"
18
Ian Rogerscf7f1912014-10-22 22:06:39 -070019#include <inttypes.h>
20
21#include <ostream>
Ian Rogersc7dd2952014-10-21 23:31:19 -070022#include <sstream>
Ian Rogers706a10e2012-03-23 17:00:55 -070023
Elliott Hughes07ed66b2012-12-12 18:34:25 -080024#include "base/logging.h"
Elliott Hughese222ee02012-12-13 14:41:43 -080025#include "base/stringprintf.h"
Elliott Hughes92301d92012-04-10 15:57:52 -070026#include "thread.h"
Elliott Hughes0f3c5532012-03-30 14:51:51 -070027
Ian Rogers706a10e2012-03-23 17:00:55 -070028namespace art {
29namespace x86 {
30
Ian Rogersb23a7722012-10-09 16:54:26 -070031size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) {
32 return DumpInstruction(os, begin);
33}
34
Ian Rogers706a10e2012-03-23 17:00:55 -070035void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
36 size_t length = 0;
37 for (const uint8_t* cur = begin; cur < end; cur += length) {
38 length = DumpInstruction(os, cur);
39 }
40}
41
Vladimir Kostyukov122113a2014-05-30 17:56:23 +070042static const char* gReg8Names[] = {
43 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
44};
45static const char* gExtReg8Names[] = {
46 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
47 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
48};
49static const char* gReg16Names[] = {
50 "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
51 "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
52};
53static const char* gReg32Names[] = {
54 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
55 "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
56};
Ian Rogers38e12032014-03-14 14:06:14 -070057static const char* gReg64Names[] = {
58 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
59 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
60};
Ian Rogers706a10e2012-03-23 17:00:55 -070061
Mark Mendella33720c2014-06-18 21:02:29 -040062// 64-bit opcode REX modifier.
Andreas Gampec8ccf682014-09-29 20:07:43 -070063constexpr uint8_t REX_W = 8U /* 0b1000 */;
64constexpr uint8_t REX_R = 4U /* 0b0100 */;
65constexpr uint8_t REX_X = 2U /* 0b0010 */;
66constexpr uint8_t REX_B = 1U /* 0b0001 */;
Mark Mendella33720c2014-06-18 21:02:29 -040067
Ian Rogers38e12032014-03-14 14:06:14 -070068static void DumpReg0(std::ostream& os, uint8_t rex, size_t reg,
Ian Rogers706a10e2012-03-23 17:00:55 -070069 bool byte_operand, uint8_t size_override) {
Ian Rogers38e12032014-03-14 14:06:14 -070070 DCHECK_LT(reg, (rex == 0) ? 8u : 16u);
Mark Mendella33720c2014-06-18 21:02:29 -040071 bool rex_w = (rex & REX_W) != 0;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +070072 if (byte_operand) {
73 os << ((rex == 0) ? gReg8Names[reg] : gExtReg8Names[reg]);
74 } else if (rex_w) {
75 os << gReg64Names[reg];
76 } else if (size_override == 0x66) {
77 os << gReg16Names[reg];
78 } else {
79 os << gReg32Names[reg];
Ian Rogers706a10e2012-03-23 17:00:55 -070080 }
81}
82
Mark Mendell88649c72014-06-04 21:20:00 -040083static void DumpAnyReg(std::ostream& os, uint8_t rex, size_t reg,
Vladimir Kostyukov122113a2014-05-30 17:56:23 +070084 bool byte_operand, uint8_t size_override, RegFile reg_file) {
85 if (reg_file == GPR) {
86 DumpReg0(os, rex, reg, byte_operand, size_override);
87 } else if (reg_file == SSE) {
88 os << "xmm" << reg;
89 } else {
90 os << "mm" << reg;
91 }
92}
93
Ian Rogers706a10e2012-03-23 17:00:55 -070094static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
Ian Rogersbf989802012-04-16 16:07:49 -070095 bool byte_operand, uint8_t size_override, RegFile reg_file) {
Mark Mendella33720c2014-06-18 21:02:29 -040096 bool rex_r = (rex & REX_R) != 0;
Ian Rogers38e12032014-03-14 14:06:14 -070097 size_t reg_num = rex_r ? (reg + 8) : reg;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +070098 DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
99}
100
101static void DumpRmReg(std::ostream& os, uint8_t rex, uint8_t reg,
102 bool byte_operand, uint8_t size_override, RegFile reg_file) {
Mark Mendella33720c2014-06-18 21:02:29 -0400103 bool rex_b = (rex & REX_B) != 0;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700104 size_t reg_num = rex_b ? (reg + 8) : reg;
105 DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
106}
107
108static void DumpAddrReg(std::ostream& os, uint8_t rex, uint8_t reg) {
109 if (rex != 0) {
110 os << gReg64Names[reg];
Ian Rogersbf989802012-04-16 16:07:49 -0700111 } else {
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700112 os << gReg32Names[reg];
Ian Rogersbf989802012-04-16 16:07:49 -0700113 }
Ian Rogers706a10e2012-03-23 17:00:55 -0700114}
115
Ian Rogers7caad772012-03-30 01:07:54 -0700116static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
Mark Mendella33720c2014-06-18 21:02:29 -0400117 bool rex_b = (rex & REX_B) != 0;
Ian Rogers38e12032014-03-14 14:06:14 -0700118 size_t reg_num = rex_b ? (reg + 8) : reg;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700119 DumpAddrReg(os, rex, reg_num);
Ian Rogers706a10e2012-03-23 17:00:55 -0700120}
121
Ian Rogers7caad772012-03-30 01:07:54 -0700122static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) {
Mark Mendella33720c2014-06-18 21:02:29 -0400123 bool rex_x = (rex & REX_X) != 0;
Ian Rogers38e12032014-03-14 14:06:14 -0700124 uint8_t reg_num = rex_x ? (reg + 8) : reg;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700125 DumpAddrReg(os, rex, reg_num);
126}
127
Vladimir Kostyukov79bb1842014-07-01 18:28:43 +0700128static void DumpOpcodeReg(std::ostream& os, uint8_t rex, uint8_t reg,
129 bool byte_operand, uint8_t size_override) {
Mark Mendella33720c2014-06-18 21:02:29 -0400130 bool rex_b = (rex & REX_B) != 0;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700131 size_t reg_num = rex_b ? (reg + 8) : reg;
Vladimir Kostyukov79bb1842014-07-01 18:28:43 +0700132 DumpReg0(os, rex, reg_num, byte_operand, size_override);
Ian Rogers706a10e2012-03-23 17:00:55 -0700133}
134
Elliott Hughes92301d92012-04-10 15:57:52 -0700135enum SegmentPrefix {
136 kCs = 0x2e,
137 kSs = 0x36,
138 kDs = 0x3e,
139 kEs = 0x26,
140 kFs = 0x64,
141 kGs = 0x65,
142};
143
Ian Rogers706a10e2012-03-23 17:00:55 -0700144static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) {
145 switch (segment_prefix) {
Elliott Hughes92301d92012-04-10 15:57:52 -0700146 case kCs: os << "cs:"; break;
147 case kSs: os << "ss:"; break;
148 case kDs: os << "ds:"; break;
149 case kEs: os << "es:"; break;
150 case kFs: os << "fs:"; break;
151 case kGs: os << "gs:"; break;
Ian Rogers706a10e2012-03-23 17:00:55 -0700152 default: break;
153 }
154}
155
Andreas Gampee5eb7062014-12-12 18:44:19 -0800156// Do not inline to avoid Clang stack frame problems. b/18733806
Andreas Gampe86830382014-12-12 21:41:29 -0800157NO_INLINE
158static std::string DumpCodeHex(const uint8_t* begin, const uint8_t* end) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800159 std::stringstream hex;
160 for (size_t i = 0; begin + i < end; ++i) {
161 hex << StringPrintf("%02X", begin[i]);
162 }
163 return hex.str();
164}
165
166std::string DisassemblerX86::DumpAddress(uint8_t mod, uint8_t rm, uint8_t rex64, uint8_t rex_w,
167 bool no_ops, bool byte_operand, bool byte_second_operand,
168 uint8_t* prefix, bool load, RegFile src_reg_file,
169 RegFile dst_reg_file, const uint8_t** instr,
170 uint32_t* address_bits) {
171 std::ostringstream address;
172 if (mod == 0 && rm == 5) {
173 if (!supports_rex_) { // Absolute address.
174 *address_bits = *reinterpret_cast<const uint32_t*>(**instr);
175 address << StringPrintf("[0x%x]", *address_bits);
176 } else { // 64-bit RIP relative addressing.
177 address << StringPrintf("[RIP + 0x%x]", *reinterpret_cast<const uint32_t*>(*instr));
178 }
179 (*instr) += 4;
180 } else if (rm == 4 && mod != 3) { // SIB
181 uint8_t sib = **instr;
182 (*instr)++;
183 uint8_t scale = (sib >> 6) & 3;
184 uint8_t index = (sib >> 3) & 7;
185 uint8_t base = sib & 7;
186 address << "[";
187 if (base != 5 || mod != 0) {
188 DumpBaseReg(address, rex64, base);
189 if (index != 4) {
190 address << " + ";
191 }
192 }
193 if (index != 4) {
194 DumpIndexReg(address, rex64, index);
195 if (scale != 0) {
196 address << StringPrintf(" * %d", 1 << scale);
197 }
198 }
199 if (mod == 0) {
200 if (base == 5) {
201 if (index != 4) {
202 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
203 } else {
204 // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit.
205 *address_bits = *reinterpret_cast<const uint32_t*>(*instr);
206 address << StringPrintf("%d", *address_bits);
207 }
208 (*instr) += 4;
209 }
210 } else if (mod == 1) {
211 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr));
212 (*instr)++;
213 } else if (mod == 2) {
214 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
215 (*instr) += 4;
216 }
217 address << "]";
218 } else {
219 if (mod == 3) {
220 if (!no_ops) {
221 DumpRmReg(address, rex_w, rm, byte_operand || byte_second_operand,
222 prefix[2], load ? src_reg_file : dst_reg_file);
223 }
224 } else {
225 address << "[";
226 DumpBaseReg(address, rex64, rm);
227 if (mod == 1) {
228 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr));
229 (*instr)++;
230 } else if (mod == 2) {
231 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr));
232 (*instr) += 4;
233 }
234 address << "]";
235 }
236 }
237 return address.str();
238}
239
Ian Rogers706a10e2012-03-23 17:00:55 -0700240size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) {
241 const uint8_t* begin_instr = instr;
242 bool have_prefixes = true;
243 uint8_t prefix[4] = {0, 0, 0, 0};
Ian Rogers706a10e2012-03-23 17:00:55 -0700244 do {
245 switch (*instr) {
Ian Rogers7caad772012-03-30 01:07:54 -0700246 // Group 1 - lock and repeat prefixes:
Ian Rogers706a10e2012-03-23 17:00:55 -0700247 case 0xF0:
248 case 0xF2:
249 case 0xF3:
250 prefix[0] = *instr;
251 break;
252 // Group 2 - segment override prefixes:
Elliott Hughes92301d92012-04-10 15:57:52 -0700253 case kCs:
254 case kSs:
255 case kDs:
256 case kEs:
257 case kFs:
258 case kGs:
Ian Rogers706a10e2012-03-23 17:00:55 -0700259 prefix[1] = *instr;
260 break;
261 // Group 3 - operand size override:
262 case 0x66:
263 prefix[2] = *instr;
264 break;
265 // Group 4 - address size override:
266 case 0x67:
267 prefix[3] = *instr;
268 break;
269 default:
270 have_prefixes = false;
271 break;
272 }
273 if (have_prefixes) {
274 instr++;
275 }
276 } while (have_prefixes);
Ian Rogers38e12032014-03-14 14:06:14 -0700277 uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0;
Vladimir Kostyukove8861b32014-04-18 17:06:15 +0700278 if (rex != 0) {
279 instr++;
280 }
Ian Rogers677c12f2014-11-07 16:58:38 -0800281 const char** modrm_opcodes = nullptr;
Ian Rogers706a10e2012-03-23 17:00:55 -0700282 bool has_modrm = false;
283 bool reg_is_opcode = false;
284 size_t immediate_bytes = 0;
285 size_t branch_bytes = 0;
Andreas Gampee5eb7062014-12-12 18:44:19 -0800286 std::string opcode_tmp; // Storage to keep StringPrintf result alive.
287 const char* opcode0 = ""; // Prefix part.
288 const char* opcode1 = ""; // Main opcode.
289 const char* opcode2 = ""; // Sub-opcode. E.g., jump type.
290 const char* opcode3 = ""; // Mod-rm part.
291 const char* opcode4 = ""; // Suffix part.
Ian Rogers706a10e2012-03-23 17:00:55 -0700292 bool store = false; // stores to memory (ie rm is on the left)
293 bool load = false; // loads from memory (ie rm is on the right)
Serguei Katkov94f3eb02014-06-24 13:23:17 +0700294 bool byte_operand = false; // true when the opcode is dealing with byte operands
Ian Rogers677c12f2014-11-07 16:58:38 -0800295 // true when the source operand is a byte register but the target register isn't
296 // (ie movsxb/movzxb).
297 bool byte_second_operand = false;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700298 bool target_specific = false; // register name depends on target (64 vs 32 bits).
Ian Rogers706a10e2012-03-23 17:00:55 -0700299 bool ax = false; // implicit use of ax
jeffhaoe2962482012-06-28 11:29:57 -0700300 bool cx = false; // implicit use of cx
Ian Rogers706a10e2012-03-23 17:00:55 -0700301 bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter
jeffhao703f2cd2012-07-13 17:25:52 -0700302 bool no_ops = false;
Ian Rogersbf989802012-04-16 16:07:49 -0700303 RegFile src_reg_file = GPR;
304 RegFile dst_reg_file = GPR;
Ian Rogers706a10e2012-03-23 17:00:55 -0700305 switch (*instr) {
306#define DISASSEMBLER_ENTRY(opname, \
307 rm8_r8, rm32_r32, \
308 r8_rm8, r32_rm32, \
309 ax8_i8, ax32_i32) \
Andreas Gampee5eb7062014-12-12 18:44:19 -0800310 case rm8_r8: opcode1 = #opname; store = true; has_modrm = true; byte_operand = true; break; \
311 case rm32_r32: opcode1 = #opname; store = true; has_modrm = true; break; \
312 case r8_rm8: opcode1 = #opname; load = true; has_modrm = true; byte_operand = true; break; \
313 case r32_rm32: opcode1 = #opname; load = true; has_modrm = true; break; \
314 case ax8_i8: opcode1 = #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \
315 case ax32_i32: opcode1 = #opname; ax = true; immediate_bytes = 4; break;
Ian Rogers706a10e2012-03-23 17:00:55 -0700316
317DISASSEMBLER_ENTRY(add,
318 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */,
319 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */,
320 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */)
321DISASSEMBLER_ENTRY(or,
322 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */,
323 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */,
324 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */)
325DISASSEMBLER_ENTRY(adc,
326 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */,
327 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */,
328 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */)
329DISASSEMBLER_ENTRY(sbb,
330 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */,
331 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */,
332 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */)
333DISASSEMBLER_ENTRY(and,
334 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */,
335 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */,
336 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */)
337DISASSEMBLER_ENTRY(sub,
338 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */,
339 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */,
340 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */)
341DISASSEMBLER_ENTRY(xor,
342 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */,
343 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */,
344 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */)
345DISASSEMBLER_ENTRY(cmp,
346 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */,
347 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */,
348 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */)
349
350#undef DISASSEMBLER_ENTRY
351 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800352 opcode1 = "push";
Ian Rogers706a10e2012-03-23 17:00:55 -0700353 reg_in_opcode = true;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700354 target_specific = true;
Ian Rogers706a10e2012-03-23 17:00:55 -0700355 break;
356 case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800357 opcode1 = "pop";
Ian Rogers706a10e2012-03-23 17:00:55 -0700358 reg_in_opcode = true;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +0700359 target_specific = true;
Ian Rogers706a10e2012-03-23 17:00:55 -0700360 break;
Mark Mendell33ecf8d2014-06-06 15:19:45 -0400361 case 0x63:
Vladimir Kostyukovec95f722014-07-23 12:10:07 +0700362 if ((rex & REX_W) != 0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800363 opcode1 = "movsxd";
Mark Mendell33ecf8d2014-06-06 15:19:45 -0400364 has_modrm = true;
365 load = true;
366 } else {
367 // In 32-bit mode (!supports_rex_) this is ARPL, with no REX prefix the functionality is the
368 // same as 'mov' but the use of the instruction is discouraged.
Andreas Gampee5eb7062014-12-12 18:44:19 -0800369 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
370 opcode1 = opcode_tmp.c_str();
Mark Mendell33ecf8d2014-06-06 15:19:45 -0400371 }
372 break;
Andreas Gampee5eb7062014-12-12 18:44:19 -0800373 case 0x68: opcode1 = "push"; immediate_bytes = 4; break;
374 case 0x69: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 4; break;
375 case 0x6A: opcode1 = "push"; immediate_bytes = 1; break;
376 case 0x6B: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 1; break;
Ian Rogers706a10e2012-03-23 17:00:55 -0700377 case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
378 case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
379 static const char* condition_codes[] =
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700380 {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a",
381 "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g"
Ian Rogers706a10e2012-03-23 17:00:55 -0700382 };
Andreas Gampee5eb7062014-12-12 18:44:19 -0800383 opcode1 = "j";
384 opcode2 = condition_codes[*instr & 0xF];
Ian Rogers706a10e2012-03-23 17:00:55 -0700385 branch_bytes = 1;
386 break;
Razvan A Lupusoru99ad7232014-02-25 17:41:08 -0800387 case 0x86: case 0x87:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800388 opcode1 = "xchg";
Razvan A Lupusoru99ad7232014-02-25 17:41:08 -0800389 store = true;
390 has_modrm = true;
391 byte_operand = (*instr == 0x86);
392 break;
Andreas Gampee5eb7062014-12-12 18:44:19 -0800393 case 0x88: opcode1 = "mov"; store = true; has_modrm = true; byte_operand = true; break;
394 case 0x89: opcode1 = "mov"; store = true; has_modrm = true; break;
395 case 0x8A: opcode1 = "mov"; load = true; has_modrm = true; byte_operand = true; break;
396 case 0x8B: opcode1 = "mov"; load = true; has_modrm = true; break;
Ian Rogers706a10e2012-03-23 17:00:55 -0700397
398 case 0x0F: // 2 byte extended opcode
399 instr++;
400 switch (*instr) {
Ian Rogers7caad772012-03-30 01:07:54 -0700401 case 0x10: case 0x11:
402 if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800403 opcode1 = "movsd";
jeffhaofdffdf82012-07-11 16:08:43 -0700404 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogers7caad772012-03-30 01:07:54 -0700405 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800406 opcode1 = "movss";
jeffhaofdffdf82012-07-11 16:08:43 -0700407 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogers7caad772012-03-30 01:07:54 -0700408 } else if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800409 opcode1 = "movupd";
jeffhaofdffdf82012-07-11 16:08:43 -0700410 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogers7caad772012-03-30 01:07:54 -0700411 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800412 opcode1 = "movups";
Ian Rogers7caad772012-03-30 01:07:54 -0700413 }
414 has_modrm = true;
Ian Rogersbf989802012-04-16 16:07:49 -0700415 src_reg_file = dst_reg_file = SSE;
Ian Rogers7caad772012-03-30 01:07:54 -0700416 load = *instr == 0x10;
417 store = !load;
418 break;
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800419 case 0x12: case 0x13:
420 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800421 opcode1 = "movlpd";
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800422 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
423 } else if (prefix[0] == 0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800424 opcode1 = "movlps";
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800425 }
426 has_modrm = true;
427 src_reg_file = dst_reg_file = SSE;
428 load = *instr == 0x12;
429 store = !load;
430 break;
431 case 0x16: case 0x17:
432 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800433 opcode1 = "movhpd";
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800434 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
435 } else if (prefix[0] == 0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800436 opcode1 = "movhps";
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800437 }
438 has_modrm = true;
439 src_reg_file = dst_reg_file = SSE;
440 load = *instr == 0x16;
441 store = !load;
442 break;
443 case 0x28: case 0x29:
444 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800445 opcode1 = "movapd";
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800446 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
447 } else if (prefix[0] == 0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800448 opcode1 = "movaps";
Razvan A Lupusoru2c498d12014-01-29 16:02:57 -0800449 }
450 has_modrm = true;
451 src_reg_file = dst_reg_file = SSE;
452 load = *instr == 0x28;
453 store = !load;
454 break;
jeffhaofdffdf82012-07-11 16:08:43 -0700455 case 0x2A:
456 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800457 opcode1 = "cvtpi2pd";
jeffhaofdffdf82012-07-11 16:08:43 -0700458 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
459 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800460 opcode1 = "cvtsi2sd";
jeffhaofdffdf82012-07-11 16:08:43 -0700461 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
462 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800463 opcode1 = "cvtsi2ss";
jeffhaofdffdf82012-07-11 16:08:43 -0700464 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
465 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800466 opcode1 = "cvtpi2ps";
jeffhaofdffdf82012-07-11 16:08:43 -0700467 }
468 load = true;
469 has_modrm = true;
470 dst_reg_file = SSE;
471 break;
472 case 0x2C:
473 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800474 opcode1 = "cvttpd2pi";
jeffhaofdffdf82012-07-11 16:08:43 -0700475 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
476 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800477 opcode1 = "cvttsd2si";
jeffhaofdffdf82012-07-11 16:08:43 -0700478 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
479 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800480 opcode1 = "cvttss2si";
jeffhaofdffdf82012-07-11 16:08:43 -0700481 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
482 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800483 opcode1 = "cvttps2pi";
jeffhaofdffdf82012-07-11 16:08:43 -0700484 }
485 load = true;
486 has_modrm = true;
487 src_reg_file = SSE;
488 break;
489 case 0x2D:
490 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800491 opcode1 = "cvtpd2pi";
jeffhaofdffdf82012-07-11 16:08:43 -0700492 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
493 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800494 opcode1 = "cvtsd2si";
jeffhaofdffdf82012-07-11 16:08:43 -0700495 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
496 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800497 opcode1 = "cvtss2si";
jeffhaofdffdf82012-07-11 16:08:43 -0700498 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
499 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800500 opcode1 = "cvtps2pi";
jeffhaofdffdf82012-07-11 16:08:43 -0700501 }
502 load = true;
503 has_modrm = true;
504 src_reg_file = SSE;
505 break;
506 case 0x2E:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800507 opcode0 = "u";
Ian Rogersfc787ec2014-10-09 21:56:44 -0700508 FALLTHROUGH_INTENDED;
jeffhaofdffdf82012-07-11 16:08:43 -0700509 case 0x2F:
510 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800511 opcode1 = "comisd";
jeffhaofdffdf82012-07-11 16:08:43 -0700512 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
513 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800514 opcode1 = "comiss";
jeffhaofdffdf82012-07-11 16:08:43 -0700515 }
516 has_modrm = true;
517 load = true;
518 src_reg_file = dst_reg_file = SSE;
519 break;
Ian Rogers706a10e2012-03-23 17:00:55 -0700520 case 0x38: // 3 byte extended opcode
Mark Mendellfe945782014-05-22 09:52:36 -0400521 instr++;
522 if (prefix[2] == 0x66) {
523 switch (*instr) {
Udayan Banerji60bfe7b2014-07-08 19:59:43 -0700524 case 0x01:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800525 opcode1 = "phaddw";
Udayan Banerji60bfe7b2014-07-08 19:59:43 -0700526 prefix[2] = 0;
527 has_modrm = true;
528 load = true;
529 src_reg_file = dst_reg_file = SSE;
530 break;
531 case 0x02:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800532 opcode1 = "phaddd";
Udayan Banerji60bfe7b2014-07-08 19:59:43 -0700533 prefix[2] = 0;
534 has_modrm = true;
535 load = true;
536 src_reg_file = dst_reg_file = SSE;
537 break;
Mark Mendellfe945782014-05-22 09:52:36 -0400538 case 0x40:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800539 opcode1 = "pmulld";
Mark Mendellfe945782014-05-22 09:52:36 -0400540 prefix[2] = 0;
541 has_modrm = true;
542 load = true;
543 src_reg_file = dst_reg_file = SSE;
544 break;
545 default:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800546 opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr);
547 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400548 }
549 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800550 opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr);
551 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400552 }
Ian Rogers706a10e2012-03-23 17:00:55 -0700553 break;
554 case 0x3A: // 3 byte extended opcode
Mark Mendellfe945782014-05-22 09:52:36 -0400555 instr++;
556 if (prefix[2] == 0x66) {
557 switch (*instr) {
558 case 0x14:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800559 opcode1 = "pextrb";
Mark Mendellfe945782014-05-22 09:52:36 -0400560 prefix[2] = 0;
561 has_modrm = true;
562 store = true;
Udayan Banerji60bfe7b2014-07-08 19:59:43 -0700563 src_reg_file = SSE;
Mark Mendellfe945782014-05-22 09:52:36 -0400564 immediate_bytes = 1;
565 break;
566 case 0x16:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800567 opcode1 = "pextrd";
Mark Mendellfe945782014-05-22 09:52:36 -0400568 prefix[2] = 0;
569 has_modrm = true;
570 store = true;
Udayan Banerji60bfe7b2014-07-08 19:59:43 -0700571 src_reg_file = SSE;
Mark Mendellfe945782014-05-22 09:52:36 -0400572 immediate_bytes = 1;
573 break;
574 default:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800575 opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr);
576 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400577 }
578 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800579 opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr);
580 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400581 }
Ian Rogers706a10e2012-03-23 17:00:55 -0700582 break;
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800583 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
584 case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800585 opcode1 = "cmov";
586 opcode2 = condition_codes[*instr & 0xF];
Razvan A Lupusorubd288c22013-12-20 17:27:23 -0800587 has_modrm = true;
588 load = true;
589 break;
Ian Rogersbf989802012-04-16 16:07:49 -0700590 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
591 case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
592 switch (*instr) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800593 case 0x50: opcode1 = "movmsk"; break;
594 case 0x51: opcode1 = "sqrt"; break;
595 case 0x52: opcode1 = "rsqrt"; break;
596 case 0x53: opcode1 = "rcp"; break;
597 case 0x54: opcode1 = "and"; break;
598 case 0x55: opcode1 = "andn"; break;
599 case 0x56: opcode1 = "or"; break;
600 case 0x57: opcode1 = "xor"; break;
601 case 0x58: opcode1 = "add"; break;
602 case 0x59: opcode1 = "mul"; break;
603 case 0x5C: opcode1 = "sub"; break;
604 case 0x5D: opcode1 = "min"; break;
605 case 0x5E: opcode1 = "div"; break;
606 case 0x5F: opcode1 = "max"; break;
Ian Rogers2c4257b2014-10-24 14:20:06 -0700607 default: LOG(FATAL) << "Unreachable"; UNREACHABLE();
Ian Rogersbf989802012-04-16 16:07:49 -0700608 }
609 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800610 opcode2 = "pd";
jeffhaofdffdf82012-07-11 16:08:43 -0700611 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700612 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800613 opcode2 = "sd";
jeffhaofdffdf82012-07-11 16:08:43 -0700614 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700615 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800616 opcode2 = "ss";
jeffhaofdffdf82012-07-11 16:08:43 -0700617 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700618 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800619 opcode2 = "ps";
Ian Rogersbf989802012-04-16 16:07:49 -0700620 }
621 load = true;
622 has_modrm = true;
623 src_reg_file = dst_reg_file = SSE;
624 break;
625 }
626 case 0x5A:
627 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800628 opcode1 = "cvtpd2ps";
jeffhaofdffdf82012-07-11 16:08:43 -0700629 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700630 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800631 opcode1 = "cvtsd2ss";
jeffhaofdffdf82012-07-11 16:08:43 -0700632 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700633 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800634 opcode1 = "cvtss2sd";
jeffhaofdffdf82012-07-11 16:08:43 -0700635 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700636 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800637 opcode1 = "cvtps2pd";
Ian Rogersbf989802012-04-16 16:07:49 -0700638 }
639 load = true;
640 has_modrm = true;
641 src_reg_file = dst_reg_file = SSE;
642 break;
643 case 0x5B:
644 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800645 opcode1 = "cvtps2dq";
jeffhaofdffdf82012-07-11 16:08:43 -0700646 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700647 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800648 opcode1 = "bad opcode F2 0F 5B";
Ian Rogersbf989802012-04-16 16:07:49 -0700649 } else if (prefix[0] == 0xF3) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800650 opcode1 = "cvttps2dq";
jeffhaofdffdf82012-07-11 16:08:43 -0700651 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700652 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800653 opcode1 = "cvtdq2ps";
Ian Rogersbf989802012-04-16 16:07:49 -0700654 }
655 load = true;
656 has_modrm = true;
657 src_reg_file = dst_reg_file = SSE;
658 break;
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -0700659 case 0x60: case 0x61: case 0x62: case 0x6C:
Razvan A Lupusorud3266bc2014-01-24 12:55:31 -0800660 if (prefix[2] == 0x66) {
661 src_reg_file = dst_reg_file = SSE;
662 prefix[2] = 0; // Clear prefix now. It has served its purpose as part of the opcode.
663 } else {
664 src_reg_file = dst_reg_file = MMX;
665 }
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -0700666 switch (*instr) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800667 case 0x60: opcode1 = "punpcklbw"; break;
668 case 0x61: opcode1 = "punpcklwd"; break;
669 case 0x62: opcode1 = "punpckldq"; break;
670 case 0x6c: opcode1 = "punpcklqdq"; break;
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -0700671 }
Razvan A Lupusorud3266bc2014-01-24 12:55:31 -0800672 load = true;
673 has_modrm = true;
674 break;
Ian Rogersbf989802012-04-16 16:07:49 -0700675 case 0x6E:
676 if (prefix[2] == 0x66) {
677 dst_reg_file = SSE;
jeffhaofdffdf82012-07-11 16:08:43 -0700678 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700679 } else {
680 dst_reg_file = MMX;
Ian Rogersbf989802012-04-16 16:07:49 -0700681 }
Andreas Gampee5eb7062014-12-12 18:44:19 -0800682 opcode1 = "movd";
Ian Rogersbf989802012-04-16 16:07:49 -0700683 load = true;
684 has_modrm = true;
685 break;
686 case 0x6F:
687 if (prefix[2] == 0x66) {
Mark Mendellfe945782014-05-22 09:52:36 -0400688 src_reg_file = dst_reg_file = SSE;
Andreas Gampee5eb7062014-12-12 18:44:19 -0800689 opcode1 = "movdqa";
jeffhaofdffdf82012-07-11 16:08:43 -0700690 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700691 } else if (prefix[0] == 0xF3) {
Mark Mendellfe945782014-05-22 09:52:36 -0400692 src_reg_file = dst_reg_file = SSE;
Andreas Gampee5eb7062014-12-12 18:44:19 -0800693 opcode1 = "movdqu";
jeffhaofdffdf82012-07-11 16:08:43 -0700694 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogersbf989802012-04-16 16:07:49 -0700695 } else {
696 dst_reg_file = MMX;
Andreas Gampee5eb7062014-12-12 18:44:19 -0800697 opcode1 = "movq";
Ian Rogersbf989802012-04-16 16:07:49 -0700698 }
699 load = true;
700 has_modrm = true;
701 break;
Mark Mendellfe945782014-05-22 09:52:36 -0400702 case 0x70:
703 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800704 opcode1 = "pshufd";
Mark Mendellfe945782014-05-22 09:52:36 -0400705 prefix[2] = 0;
706 has_modrm = true;
707 store = true;
708 src_reg_file = dst_reg_file = SSE;
709 immediate_bytes = 1;
710 } else if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800711 opcode1 = "pshuflw";
Mark Mendellfe945782014-05-22 09:52:36 -0400712 prefix[0] = 0;
713 has_modrm = true;
714 store = true;
715 src_reg_file = dst_reg_file = SSE;
716 immediate_bytes = 1;
717 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800718 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
719 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400720 }
721 break;
jeffhaofdffdf82012-07-11 16:08:43 -0700722 case 0x71:
723 if (prefix[2] == 0x66) {
724 dst_reg_file = SSE;
725 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
726 } else {
727 dst_reg_file = MMX;
728 }
Ian Rogers677c12f2014-11-07 16:58:38 -0800729 static const char* x71_opcodes[] = {
730 "unknown-71", "unknown-71", "psrlw", "unknown-71",
731 "psraw", "unknown-71", "psllw", "unknown-71"};
jeffhaofdffdf82012-07-11 16:08:43 -0700732 modrm_opcodes = x71_opcodes;
733 reg_is_opcode = true;
734 has_modrm = true;
735 store = true;
736 immediate_bytes = 1;
737 break;
738 case 0x72:
739 if (prefix[2] == 0x66) {
740 dst_reg_file = SSE;
741 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
742 } else {
743 dst_reg_file = MMX;
744 }
Ian Rogers677c12f2014-11-07 16:58:38 -0800745 static const char* x72_opcodes[] = {
746 "unknown-72", "unknown-72", "psrld", "unknown-72",
747 "psrad", "unknown-72", "pslld", "unknown-72"};
jeffhaofdffdf82012-07-11 16:08:43 -0700748 modrm_opcodes = x72_opcodes;
749 reg_is_opcode = true;
750 has_modrm = true;
751 store = true;
752 immediate_bytes = 1;
753 break;
754 case 0x73:
755 if (prefix[2] == 0x66) {
756 dst_reg_file = SSE;
757 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
758 } else {
759 dst_reg_file = MMX;
760 }
Ian Rogers677c12f2014-11-07 16:58:38 -0800761 static const char* x73_opcodes[] = {
762 "unknown-73", "unknown-73", "psrlq", "psrldq",
763 "unknown-73", "unknown-73", "psllq", "unknown-73"};
jeffhaofdffdf82012-07-11 16:08:43 -0700764 modrm_opcodes = x73_opcodes;
765 reg_is_opcode = true;
766 has_modrm = true;
767 store = true;
768 immediate_bytes = 1;
769 break;
Olivier Comefb0fecf2014-06-20 11:46:16 +0200770 case 0x7C:
771 if (prefix[0] == 0xF2) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800772 opcode1 = "haddps";
Olivier Comefb0fecf2014-06-20 11:46:16 +0200773 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
774 } else if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800775 opcode1 = "haddpd";
Olivier Comefb0fecf2014-06-20 11:46:16 +0200776 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
777 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800778 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
779 opcode1 = opcode_tmp.c_str();
Olivier Comefb0fecf2014-06-20 11:46:16 +0200780 break;
781 }
782 src_reg_file = dst_reg_file = SSE;
783 has_modrm = true;
784 load = true;
785 break;
jeffhaofdffdf82012-07-11 16:08:43 -0700786 case 0x7E:
787 if (prefix[2] == 0x66) {
788 src_reg_file = SSE;
789 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
790 } else {
791 src_reg_file = MMX;
792 }
Andreas Gampee5eb7062014-12-12 18:44:19 -0800793 opcode1 = "movd";
jeffhaofdffdf82012-07-11 16:08:43 -0700794 has_modrm = true;
795 store = true;
796 break;
Ian Rogers706a10e2012-03-23 17:00:55 -0700797 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
798 case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800799 opcode1 = "j";
800 opcode2 = condition_codes[*instr & 0xF];
Ian Rogers706a10e2012-03-23 17:00:55 -0700801 branch_bytes = 4;
802 break;
Ian Rogers7caad772012-03-30 01:07:54 -0700803 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
804 case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800805 opcode1 = "set";
806 opcode2 = condition_codes[*instr & 0xF];
Ian Rogers677c12f2014-11-07 16:58:38 -0800807 modrm_opcodes = nullptr;
Ian Rogers7caad772012-03-30 01:07:54 -0700808 reg_is_opcode = true;
809 has_modrm = true;
810 store = true;
811 break;
Mark Mendell4708dcd2014-01-22 09:05:18 -0800812 case 0xA4:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800813 opcode1 = "shld";
Mark Mendell4708dcd2014-01-22 09:05:18 -0800814 has_modrm = true;
815 load = true;
816 immediate_bytes = 1;
817 break;
Yixin Shouf40f8902014-08-14 14:10:32 -0400818 case 0xA5:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800819 opcode1 = "shld";
Yixin Shouf40f8902014-08-14 14:10:32 -0400820 has_modrm = true;
821 load = true;
822 cx = true;
823 break;
Mark Mendell4708dcd2014-01-22 09:05:18 -0800824 case 0xAC:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800825 opcode1 = "shrd";
Mark Mendell4708dcd2014-01-22 09:05:18 -0800826 has_modrm = true;
827 load = true;
828 immediate_bytes = 1;
829 break;
Yixin Shouf40f8902014-08-14 14:10:32 -0400830 case 0xAD:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800831 opcode1 = "shrd";
Yixin Shouf40f8902014-08-14 14:10:32 -0400832 has_modrm = true;
833 load = true;
834 cx = true;
835 break;
jeffhao703f2cd2012-07-13 17:25:52 -0700836 case 0xAE:
837 if (prefix[0] == 0xF3) {
Ian Rogers5e588b32013-02-21 15:05:09 -0800838 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
Ian Rogers677c12f2014-11-07 16:58:38 -0800839 static const char* xAE_opcodes[] = {
840 "rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase",
841 "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"};
jeffhao703f2cd2012-07-13 17:25:52 -0700842 modrm_opcodes = xAE_opcodes;
843 reg_is_opcode = true;
844 has_modrm = true;
845 uint8_t reg_or_opcode = (instr[1] >> 3) & 7;
846 switch (reg_or_opcode) {
847 case 0:
848 prefix[1] = kFs;
849 load = true;
850 break;
851 case 1:
852 prefix[1] = kGs;
853 load = true;
854 break;
855 case 2:
856 prefix[1] = kFs;
857 store = true;
858 break;
859 case 3:
860 prefix[1] = kGs;
861 store = true;
862 break;
863 default:
864 load = true;
865 break;
866 }
867 } else {
Ian Rogers677c12f2014-11-07 16:58:38 -0800868 static const char* xAE_opcodes[] = {
869 "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE",
870 "unknown-AE", "lfence", "mfence", "sfence"};
jeffhao703f2cd2012-07-13 17:25:52 -0700871 modrm_opcodes = xAE_opcodes;
872 reg_is_opcode = true;
873 has_modrm = true;
874 load = true;
875 no_ops = true;
876 }
877 break;
Ian Rogers677c12f2014-11-07 16:58:38 -0800878 case 0xAF:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800879 opcode1 = "imul";
Ian Rogers677c12f2014-11-07 16:58:38 -0800880 has_modrm = true;
881 load = true;
882 break;
883 case 0xB1:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800884 opcode1 = "cmpxchg";
Ian Rogers677c12f2014-11-07 16:58:38 -0800885 has_modrm = true;
886 store = true;
887 break;
888 case 0xB6:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800889 opcode1 = "movzxb";
Ian Rogers677c12f2014-11-07 16:58:38 -0800890 has_modrm = true;
891 load = true;
892 byte_second_operand = true;
893 break;
894 case 0xB7:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800895 opcode1 = "movzxw";
Ian Rogers677c12f2014-11-07 16:58:38 -0800896 has_modrm = true;
897 load = true;
898 break;
899 case 0xBE:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800900 opcode1 = "movsxb";
Ian Rogers677c12f2014-11-07 16:58:38 -0800901 has_modrm = true;
902 load = true;
903 byte_second_operand = true;
904 rex |= (rex == 0 ? 0 : REX_W);
905 break;
906 case 0xBF:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800907 opcode1 = "movsxw";
Ian Rogers677c12f2014-11-07 16:58:38 -0800908 has_modrm = true;
909 load = true;
910 break;
911 case 0xC3:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800912 opcode1 = "movnti";
Ian Rogers677c12f2014-11-07 16:58:38 -0800913 store = true;
914 has_modrm = true;
915 break;
Mark Mendellfe945782014-05-22 09:52:36 -0400916 case 0xC5:
917 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800918 opcode1 = "pextrw";
Mark Mendellfe945782014-05-22 09:52:36 -0400919 prefix[2] = 0;
920 has_modrm = true;
921 store = true;
Udayan Banerji60bfe7b2014-07-08 19:59:43 -0700922 src_reg_file = SSE;
Mark Mendellfe945782014-05-22 09:52:36 -0400923 immediate_bytes = 1;
924 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800925 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
926 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400927 }
928 break;
Olivier Comefb0fecf2014-06-20 11:46:16 +0200929 case 0xC6:
930 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800931 opcode1 = "shufpd";
Olivier Comefb0fecf2014-06-20 11:46:16 +0200932 prefix[2] = 0;
933 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800934 opcode1 = "shufps";
Olivier Comefb0fecf2014-06-20 11:46:16 +0200935 }
936 has_modrm = true;
937 store = true;
938 src_reg_file = dst_reg_file = SSE;
939 immediate_bytes = 1;
940 break;
Vladimir Marko70b797d2013-12-03 15:25:24 +0000941 case 0xC7:
Ian Rogers677c12f2014-11-07 16:58:38 -0800942 static const char* x0FxC7_opcodes[] = {
943 "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7",
944 "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7"};
Vladimir Marko70b797d2013-12-03 15:25:24 +0000945 modrm_opcodes = x0FxC7_opcodes;
946 has_modrm = true;
947 reg_is_opcode = true;
948 store = true;
949 break;
Vladimir Markoa8b4caf2013-10-24 15:08:57 +0100950 case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
Andreas Gampee5eb7062014-12-12 18:44:19 -0800951 opcode1 = "bswap";
Vladimir Markoa8b4caf2013-10-24 15:08:57 +0100952 reg_in_opcode = true;
953 break;
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -0700954 case 0xD4:
955 if (prefix[2] == 0x66) {
956 src_reg_file = dst_reg_file = SSE;
957 prefix[2] = 0;
958 } else {
959 src_reg_file = dst_reg_file = MMX;
960 }
Andreas Gampee5eb7062014-12-12 18:44:19 -0800961 opcode1 = "paddq";
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -0700962 prefix[2] = 0;
963 has_modrm = true;
964 load = true;
965 break;
Mark Mendellfe945782014-05-22 09:52:36 -0400966 case 0xDB:
967 if (prefix[2] == 0x66) {
968 src_reg_file = dst_reg_file = SSE;
969 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
970 } else {
971 src_reg_file = dst_reg_file = MMX;
972 }
Andreas Gampee5eb7062014-12-12 18:44:19 -0800973 opcode1 = "pand";
Mark Mendellfe945782014-05-22 09:52:36 -0400974 prefix[2] = 0;
975 has_modrm = true;
976 load = true;
977 break;
978 case 0xD5:
979 if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800980 opcode1 = "pmullw";
Mark Mendellfe945782014-05-22 09:52:36 -0400981 prefix[2] = 0;
982 has_modrm = true;
983 load = true;
984 src_reg_file = dst_reg_file = SSE;
985 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -0800986 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
987 opcode1 = opcode_tmp.c_str();
Mark Mendellfe945782014-05-22 09:52:36 -0400988 }
989 break;
990 case 0xEB:
991 if (prefix[2] == 0x66) {
992 src_reg_file = dst_reg_file = SSE;
993 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
994 } else {
995 src_reg_file = dst_reg_file = MMX;
996 }
Andreas Gampee5eb7062014-12-12 18:44:19 -0800997 opcode1 = "por";
Mark Mendellfe945782014-05-22 09:52:36 -0400998 prefix[2] = 0;
999 has_modrm = true;
1000 load = true;
1001 break;
1002 case 0xEF:
1003 if (prefix[2] == 0x66) {
1004 src_reg_file = dst_reg_file = SSE;
1005 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1006 } else {
1007 src_reg_file = dst_reg_file = MMX;
1008 }
Andreas Gampee5eb7062014-12-12 18:44:19 -08001009 opcode1 = "pxor";
Mark Mendellfe945782014-05-22 09:52:36 -04001010 prefix[2] = 0;
1011 has_modrm = true;
1012 load = true;
1013 break;
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -07001014 case 0xF4:
1015 case 0xF6:
Mark Mendellfe945782014-05-22 09:52:36 -04001016 case 0xF8:
Mark Mendellfe945782014-05-22 09:52:36 -04001017 case 0xF9:
Mark Mendellfe945782014-05-22 09:52:36 -04001018 case 0xFA:
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -07001019 case 0xFB:
Mark Mendellfe945782014-05-22 09:52:36 -04001020 case 0xFC:
Mark Mendellfe945782014-05-22 09:52:36 -04001021 case 0xFD:
Mark Mendellfe945782014-05-22 09:52:36 -04001022 case 0xFE:
1023 if (prefix[2] == 0x66) {
1024 src_reg_file = dst_reg_file = SSE;
1025 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
1026 } else {
1027 src_reg_file = dst_reg_file = MMX;
1028 }
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -07001029 switch (*instr) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001030 case 0xF4: opcode1 = "pmuludq"; break;
1031 case 0xF6: opcode1 = "psadbw"; break;
1032 case 0xF8: opcode1 = "psubb"; break;
1033 case 0xF9: opcode1 = "psubw"; break;
1034 case 0xFA: opcode1 = "psubd"; break;
1035 case 0xFB: opcode1 = "psubq"; break;
1036 case 0xFC: opcode1 = "paddb"; break;
1037 case 0xFD: opcode1 = "paddw"; break;
1038 case 0xFE: opcode1 = "paddd"; break;
Lupusoru, Razvan Ab3a84e22014-07-28 14:11:01 -07001039 }
Mark Mendellfe945782014-05-22 09:52:36 -04001040 prefix[2] = 0;
1041 has_modrm = true;
1042 load = true;
1043 break;
Ian Rogers706a10e2012-03-23 17:00:55 -07001044 default:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001045 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr);
1046 opcode1 = opcode_tmp.c_str();
Ian Rogers706a10e2012-03-23 17:00:55 -07001047 break;
1048 }
1049 break;
1050 case 0x80: case 0x81: case 0x82: case 0x83:
1051 static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"};
1052 modrm_opcodes = x80_opcodes;
1053 has_modrm = true;
1054 reg_is_opcode = true;
1055 store = true;
1056 byte_operand = (*instr & 1) == 0;
1057 immediate_bytes = *instr == 0x81 ? 4 : 1;
1058 break;
jeffhao703f2cd2012-07-13 17:25:52 -07001059 case 0x84: case 0x85:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001060 opcode1 = "test";
jeffhao703f2cd2012-07-13 17:25:52 -07001061 has_modrm = true;
1062 load = true;
1063 byte_operand = (*instr & 1) == 0;
1064 break;
Ian Rogers7caad772012-03-30 01:07:54 -07001065 case 0x8D:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001066 opcode1 = "lea";
Ian Rogers7caad772012-03-30 01:07:54 -07001067 has_modrm = true;
1068 load = true;
1069 break;
jeffhao703f2cd2012-07-13 17:25:52 -07001070 case 0x8F:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001071 opcode1 = "pop";
jeffhao703f2cd2012-07-13 17:25:52 -07001072 has_modrm = true;
1073 reg_is_opcode = true;
1074 store = true;
1075 break;
Mark Mendell2bf31e62014-01-23 12:13:40 -08001076 case 0x99:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001077 opcode1 = "cdq";
Mark Mendell2bf31e62014-01-23 12:13:40 -08001078 break;
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001079 case 0x9B:
1080 if (instr[1] == 0xDF && instr[2] == 0xE0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001081 opcode1 = "fstsw\tax";
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001082 instr += 2;
1083 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001084 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
1085 opcode1 = opcode_tmp.c_str();
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001086 }
1087 break;
Mark Mendell4028a6c2014-02-19 20:06:20 -08001088 case 0xAF:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001089 opcode1 = (prefix[2] == 0x66 ? "scasw" : "scasl");
Mark Mendell4028a6c2014-02-19 20:06:20 -08001090 break;
Ian Rogers706a10e2012-03-23 17:00:55 -07001091 case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001092 opcode1 = "mov";
Ian Rogers706a10e2012-03-23 17:00:55 -07001093 immediate_bytes = 1;
Mark Mendella33720c2014-06-18 21:02:29 -04001094 byte_operand = true;
Ian Rogers706a10e2012-03-23 17:00:55 -07001095 reg_in_opcode = true;
Vladimir Kostyukov79bb1842014-07-01 18:28:43 +07001096 byte_operand = true;
Ian Rogers706a10e2012-03-23 17:00:55 -07001097 break;
1098 case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
Vladimir Kostyukovec95f722014-07-23 12:10:07 +07001099 if ((rex & REX_W) != 0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001100 opcode1 = "movabsq";
Yixin Shou5192cbb2014-07-01 13:48:17 -04001101 immediate_bytes = 8;
1102 reg_in_opcode = true;
1103 break;
1104 }
Andreas Gampee5eb7062014-12-12 18:44:19 -08001105 opcode1 = "mov";
Ian Rogers706a10e2012-03-23 17:00:55 -07001106 immediate_bytes = 4;
1107 reg_in_opcode = true;
1108 break;
Ian Rogers7caad772012-03-30 01:07:54 -07001109 case 0xC0: case 0xC1:
jeffhaoe2962482012-06-28 11:29:57 -07001110 case 0xD0: case 0xD1: case 0xD2: case 0xD3:
Ian Rogers7caad772012-03-30 01:07:54 -07001111 static const char* shift_opcodes[] =
1112 {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"};
1113 modrm_opcodes = shift_opcodes;
1114 has_modrm = true;
1115 reg_is_opcode = true;
1116 store = true;
Elliott Hughes16b5c292012-04-16 20:37:16 -07001117 immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0;
jeffhaoe2962482012-06-28 11:29:57 -07001118 cx = (*instr == 0xD2) || (*instr == 0xD3);
1119 byte_operand = (*instr == 0xC0);
Ian Rogers7caad772012-03-30 01:07:54 -07001120 break;
Andreas Gampee5eb7062014-12-12 18:44:19 -08001121 case 0xC3: opcode1 = "ret"; break;
Mark Mendella33720c2014-06-18 21:02:29 -04001122 case 0xC6:
Ian Rogers677c12f2014-11-07 16:58:38 -08001123 static const char* c6_opcodes[] = {"mov", "unknown-c6", "unknown-c6",
1124 "unknown-c6", "unknown-c6", "unknown-c6",
1125 "unknown-c6", "unknown-c6"};
Mark Mendella33720c2014-06-18 21:02:29 -04001126 modrm_opcodes = c6_opcodes;
1127 store = true;
1128 immediate_bytes = 1;
1129 has_modrm = true;
1130 reg_is_opcode = true;
1131 byte_operand = true;
1132 break;
Elliott Hughes0589ca92012-04-09 18:26:20 -07001133 case 0xC7:
Ian Rogers677c12f2014-11-07 16:58:38 -08001134 static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7",
1135 "unknown-c7", "unknown-c7", "unknown-c7",
1136 "unknown-c7", "unknown-c7"};
Elliott Hughes0589ca92012-04-09 18:26:20 -07001137 modrm_opcodes = c7_opcodes;
1138 store = true;
1139 immediate_bytes = 4;
1140 has_modrm = true;
1141 reg_is_opcode = true;
1142 break;
Andreas Gampee5eb7062014-12-12 18:44:19 -08001143 case 0xCC: opcode1 = "int 3"; break;
Mark Mendelld19b55a2013-12-12 09:55:34 -08001144 case 0xD9:
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001145 if (instr[1] == 0xF8) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001146 opcode1 = "fprem";
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001147 instr++;
1148 } else {
1149 static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw",
1150 "fnstenv", "fnstcw"};
1151 modrm_opcodes = d9_opcodes;
1152 store = true;
1153 has_modrm = true;
1154 reg_is_opcode = true;
1155 }
1156 break;
1157 case 0xDA:
1158 if (instr[1] == 0xE9) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001159 opcode1 = "fucompp";
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001160 instr++;
1161 } else {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001162 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
1163 opcode1 = opcode_tmp.c_str();
Vladimir Kostyukovd48b8a22014-06-24 16:40:19 +07001164 }
Mark Mendelld19b55a2013-12-12 09:55:34 -08001165 break;
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -08001166 case 0xDB:
Ian Rogers677c12f2014-11-07 16:58:38 -08001167 static const char* db_opcodes[] = {"fildl", "unknown-db", "unknown-db",
1168 "unknown-db", "unknown-db", "unknown-db",
1169 "unknown-db", "unknown-db"};
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -08001170 modrm_opcodes = db_opcodes;
1171 load = true;
1172 has_modrm = true;
1173 reg_is_opcode = true;
1174 break;
Mark Mendelld19b55a2013-12-12 09:55:34 -08001175 case 0xDD:
Ian Rogers677c12f2014-11-07 16:58:38 -08001176 static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl",
1177 "fstpl", "frstor", "unknown-dd",
1178 "fnsave", "fnstsw"};
Mark Mendelld19b55a2013-12-12 09:55:34 -08001179 modrm_opcodes = dd_opcodes;
1180 store = true;
1181 has_modrm = true;
1182 reg_is_opcode = true;
1183 break;
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -08001184 case 0xDF:
Ian Rogers677c12f2014-11-07 16:58:38 -08001185 static const char* df_opcodes[] = {"fild", "unknown-df", "unknown-df",
1186 "unknown-df", "unknown-df", "fildll",
1187 "unknown-df", "unknown-df"};
Razvan A Lupusoru614c2b42014-01-28 17:05:21 -08001188 modrm_opcodes = df_opcodes;
1189 load = true;
1190 has_modrm = true;
1191 reg_is_opcode = true;
1192 break;
Andreas Gampee5eb7062014-12-12 18:44:19 -08001193 case 0xE3: opcode1 = "jecxz"; branch_bytes = 1; break;
1194 case 0xE8: opcode1 = "call"; branch_bytes = 4; break;
1195 case 0xE9: opcode1 = "jmp"; branch_bytes = 4; break;
1196 case 0xEB: opcode1 = "jmp"; branch_bytes = 1; break;
1197 case 0xF5: opcode1 = "cmc"; break;
jeffhao174651d2012-04-19 15:27:22 -07001198 case 0xF6: case 0xF7:
Ian Rogers677c12f2014-11-07 16:58:38 -08001199 static const char* f7_opcodes[] = {
1200 "test", "unknown-f7", "not", "neg", "mul edx:eax, eax *",
1201 "imul edx:eax, eax *", "div edx:eax, edx:eax /",
1202 "idiv edx:eax, edx:eax /"};
jeffhao174651d2012-04-19 15:27:22 -07001203 modrm_opcodes = f7_opcodes;
1204 has_modrm = true;
1205 reg_is_opcode = true;
1206 store = true;
1207 immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0;
1208 break;
Ian Rogers706a10e2012-03-23 17:00:55 -07001209 case 0xFF:
Vladimir Kostyukove443a802014-06-30 15:44:12 +07001210 {
Ian Rogers677c12f2014-11-07 16:58:38 -08001211 static const char* ff_opcodes[] = {
1212 "inc", "dec", "call", "call",
1213 "jmp", "jmp", "push", "unknown-ff"};
Vladimir Kostyukove443a802014-06-30 15:44:12 +07001214 modrm_opcodes = ff_opcodes;
1215 has_modrm = true;
1216 reg_is_opcode = true;
1217 load = true;
1218 const uint8_t opcode_digit = (instr[1] >> 3) & 7;
1219 // 'call', 'jmp' and 'push' are target specific instructions
1220 if (opcode_digit == 2 || opcode_digit == 4 || opcode_digit == 6) {
1221 target_specific = true;
1222 }
1223 }
Ian Rogers706a10e2012-03-23 17:00:55 -07001224 break;
1225 default:
Andreas Gampee5eb7062014-12-12 18:44:19 -08001226 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr);
1227 opcode1 = opcode_tmp.c_str();
Ian Rogers706a10e2012-03-23 17:00:55 -07001228 break;
1229 }
1230 std::ostringstream args;
Vladimir Kostyukov122113a2014-05-30 17:56:23 +07001231 // We force the REX prefix to be available for 64-bit target
1232 // in order to dump addr (base/index) registers correctly.
1233 uint8_t rex64 = supports_rex_ ? (rex | 0x40) : rex;
Vladimir Kostyukove443a802014-06-30 15:44:12 +07001234 // REX.W should be forced for 64-target and target-specific instructions (i.e., push or pop).
1235 uint8_t rex_w = (supports_rex_ && target_specific) ? (rex | 0x48) : rex;
Ian Rogers706a10e2012-03-23 17:00:55 -07001236 if (reg_in_opcode) {
1237 DCHECK(!has_modrm);
Vladimir Kostyukov79bb1842014-07-01 18:28:43 +07001238 DumpOpcodeReg(args, rex_w, *instr & 0x7, byte_operand, prefix[2]);
Ian Rogers706a10e2012-03-23 17:00:55 -07001239 }
1240 instr++;
Elliott Hughes92301d92012-04-10 15:57:52 -07001241 uint32_t address_bits = 0;
Ian Rogers706a10e2012-03-23 17:00:55 -07001242 if (has_modrm) {
1243 uint8_t modrm = *instr;
1244 instr++;
1245 uint8_t mod = modrm >> 6;
1246 uint8_t reg_or_opcode = (modrm >> 3) & 7;
1247 uint8_t rm = modrm & 7;
Andreas Gampee5eb7062014-12-12 18:44:19 -08001248 std::string address = DumpAddress(mod, rm, rex64, rex_w, no_ops, byte_operand,
1249 byte_second_operand, prefix, load, src_reg_file, dst_reg_file,
1250 &instr, &address_bits);
Ian Rogers706a10e2012-03-23 17:00:55 -07001251
Ian Rogers677c12f2014-11-07 16:58:38 -08001252 if (reg_is_opcode && modrm_opcodes != nullptr) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001253 opcode3 = modrm_opcodes[reg_or_opcode];
Ian Rogers706a10e2012-03-23 17:00:55 -07001254 }
Mark Mendella33720c2014-06-18 21:02:29 -04001255
1256 // Add opcode suffixes to indicate size.
1257 if (byte_operand) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001258 opcode4 = "b";
Mark Mendella33720c2014-06-18 21:02:29 -04001259 } else if ((rex & REX_W) != 0) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001260 opcode4 = "q";
Mark Mendella33720c2014-06-18 21:02:29 -04001261 } else if (prefix[2] == 0x66) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001262 opcode4 = "w";
Mark Mendella33720c2014-06-18 21:02:29 -04001263 }
1264
Ian Rogers706a10e2012-03-23 17:00:55 -07001265 if (load) {
1266 if (!reg_is_opcode) {
Ian Rogersbf989802012-04-16 16:07:49 -07001267 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
Ian Rogers706a10e2012-03-23 17:00:55 -07001268 args << ", ";
1269 }
1270 DumpSegmentOverride(args, prefix[1]);
Andreas Gampee5eb7062014-12-12 18:44:19 -08001271 args << address;
Ian Rogers706a10e2012-03-23 17:00:55 -07001272 } else {
1273 DCHECK(store);
1274 DumpSegmentOverride(args, prefix[1]);
Andreas Gampee5eb7062014-12-12 18:44:19 -08001275 args << address;
Ian Rogers706a10e2012-03-23 17:00:55 -07001276 if (!reg_is_opcode) {
1277 args << ", ";
Ian Rogersbf989802012-04-16 16:07:49 -07001278 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
Ian Rogers706a10e2012-03-23 17:00:55 -07001279 }
1280 }
1281 }
1282 if (ax) {
jeffhaofdffdf82012-07-11 16:08:43 -07001283 // If this opcode implicitly uses ax, ax is always the first arg.
Ian Rogersbf989802012-04-16 16:07:49 -07001284 DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
Ian Rogers706a10e2012-03-23 17:00:55 -07001285 }
jeffhaoe2962482012-06-28 11:29:57 -07001286 if (cx) {
1287 args << ", ";
1288 DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR);
1289 }
Ian Rogers706a10e2012-03-23 17:00:55 -07001290 if (immediate_bytes > 0) {
jeffhaoe2962482012-06-28 11:29:57 -07001291 if (has_modrm || reg_in_opcode || ax || cx) {
Ian Rogers706a10e2012-03-23 17:00:55 -07001292 args << ", ";
1293 }
1294 if (immediate_bytes == 1) {
1295 args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr));
1296 instr++;
Yixin Shou5192cbb2014-07-01 13:48:17 -04001297 } else if (immediate_bytes == 4) {
Mark Mendell67d18be2014-05-30 15:05:09 -04001298 if (prefix[2] == 0x66) { // Operand size override from 32-bit to 16-bit.
1299 args << StringPrintf("%d", *reinterpret_cast<const int16_t*>(instr));
1300 instr += 2;
1301 } else {
1302 args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr));
1303 instr += 4;
1304 }
Yixin Shou5192cbb2014-07-01 13:48:17 -04001305 } else {
1306 CHECK_EQ(immediate_bytes, 8u);
1307 args << StringPrintf("%" PRId64, *reinterpret_cast<const int64_t*>(instr));
1308 instr += 8;
Ian Rogers706a10e2012-03-23 17:00:55 -07001309 }
1310 } else if (branch_bytes > 0) {
1311 DCHECK(!has_modrm);
1312 int32_t displacement;
1313 if (branch_bytes == 1) {
1314 displacement = *reinterpret_cast<const int8_t*>(instr);
1315 instr++;
1316 } else {
1317 CHECK_EQ(branch_bytes, 4u);
1318 displacement = *reinterpret_cast<const int32_t*>(instr);
1319 instr += 4;
1320 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001321 args << StringPrintf("%+d (", displacement)
1322 << FormatInstructionPointer(instr + displacement)
1323 << ")";
Ian Rogers706a10e2012-03-23 17:00:55 -07001324 }
Ian Rogersdd7624d2014-03-14 17:43:00 -07001325 if (prefix[1] == kFs && !supports_rex_) {
Elliott Hughes92301d92012-04-10 15:57:52 -07001326 args << " ; ";
Ian Rogersdd7624d2014-03-14 17:43:00 -07001327 Thread::DumpThreadOffset<4>(args, address_bits);
1328 }
1329 if (prefix[1] == kGs && supports_rex_) {
1330 args << " ; ";
1331 Thread::DumpThreadOffset<8>(args, address_bits);
Elliott Hughes92301d92012-04-10 15:57:52 -07001332 }
Andreas Gampee5eb7062014-12-12 18:44:19 -08001333 const char* prefix_str;
Ian Rogers5e588b32013-02-21 15:05:09 -08001334 switch (prefix[0]) {
Andreas Gampee5eb7062014-12-12 18:44:19 -08001335 case 0xF0: prefix_str = "lock "; break;
1336 case 0xF2: prefix_str = "repne "; break;
1337 case 0xF3: prefix_str = "repe "; break;
1338 case 0: prefix_str = ""; break;
Ian Rogers2c4257b2014-10-24 14:20:06 -07001339 default: LOG(FATAL) << "Unreachable"; UNREACHABLE();
Ian Rogers5e588b32013-02-21 15:05:09 -08001340 }
Brian Carlstrom2cbaccb2014-09-14 20:34:17 -07001341 os << FormatInstructionPointer(begin_instr)
Andreas Gampee5eb7062014-12-12 18:44:19 -08001342 << StringPrintf(": %22s \t%-7s%s%s%s%s%s ", DumpCodeHex(begin_instr, instr).c_str(),
1343 prefix_str, opcode0, opcode1, opcode2, opcode3, opcode4)
Ian Rogers5e588b32013-02-21 15:05:09 -08001344 << args.str() << '\n';
Ian Rogers706a10e2012-03-23 17:00:55 -07001345 return instr - begin_instr;
Brian Carlstrom7934ac22013-07-26 10:54:15 -07001346} // NOLINT(readability/fn_size)
Ian Rogers706a10e2012-03-23 17:00:55 -07001347
1348} // namespace x86
1349} // namespace art