disassembler_x86.cc revision 122113a8a233f824c014a8fe9d90626218c4dcca
1706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers/* 2706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * Copyright (C) 2012 The Android Open Source Project 3706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * 4706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * Licensed under the Apache License, Version 2.0 (the "License"); 5706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * you may not use this file except in compliance with the License. 6706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * You may obtain a copy of the License at 7706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * 8706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * http://www.apache.org/licenses/LICENSE-2.0 9706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * 10706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * Unless required by applicable law or agreed to in writing, software 11706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * distributed under the License is distributed on an "AS IS" BASIS, 12706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * See the License for the specific language governing permissions and 14706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers * limitations under the License. 15706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers */ 16706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 17706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers#include "disassembler_x86.h" 18706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 19706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers#include <iostream> 20706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 2107ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "base/logging.h" 22e222ee0b794f941af4fb1b32fb8224e32942ea7bElliott Hughes#include "base/stringprintf.h" 2392301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes#include "thread.h" 240f3c55331439970e01af67f80ac117c473bc04cfElliott Hughes 25706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogersnamespace art { 26706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogersnamespace x86 { 27706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 28b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogerssize_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) { 29b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers return DumpInstruction(os, begin); 30b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers} 31b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers 32706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogersvoid DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { 33706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers size_t length = 0; 34706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers for (const uint8_t* cur = begin; cur < end; cur += length) { 35706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers length = DumpInstruction(os, cur); 36706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 37706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} 38706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 39122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic const char* gReg8Names[] = { 40122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 41122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov}; 42122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic const char* gExtReg8Names[] = { 43122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", 44122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l" 45122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov}; 46122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic const char* gReg16Names[] = { 47122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", 48122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" 49122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov}; 50122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic const char* gReg32Names[] = { 51122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", 52122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" 53122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov}; 5438e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogersstatic const char* gReg64Names[] = { 5538e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", 5638e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" 5738e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers}; 58706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 5938e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogersstatic void DumpReg0(std::ostream& os, uint8_t rex, size_t reg, 60706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool byte_operand, uint8_t size_override) { 6138e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers DCHECK_LT(reg, (rex == 0) ? 8u : 16u); 6238e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers bool rex_w = (rex & 0b1000) != 0; 63122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov if (byte_operand) { 64122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << ((rex == 0) ? gReg8Names[reg] : gExtReg8Names[reg]); 65122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov } else if (rex_w) { 66122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << gReg64Names[reg]; 67122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov } else if (size_override == 0x66) { 68122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << gReg16Names[reg]; 69122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov } else { 70122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << gReg32Names[reg]; 71706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 72706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} 73706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 74bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogersenum RegFile { GPR, MMX, SSE }; 75bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers 76122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic void DumpAnyReg(std::ostream& os, uint8_t rex, uint8_t reg, 77122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov bool byte_operand, uint8_t size_override, RegFile reg_file) { 78122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov if (reg_file == GPR) { 79122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpReg0(os, rex, reg, byte_operand, size_override); 80122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov } else if (reg_file == SSE) { 81122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << "xmm" << reg; 82122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov } else { 83122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << "mm" << reg; 84122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov } 85122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov} 86122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov 87706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogersstatic void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg, 88bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers bool byte_operand, uint8_t size_override, RegFile reg_file) { 8938e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers bool rex_r = (rex & 0b0100) != 0; 9038e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers size_t reg_num = rex_r ? (reg + 8) : reg; 91122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file); 92122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov} 93122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov 94122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic void DumpRmReg(std::ostream& os, uint8_t rex, uint8_t reg, 95122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov bool byte_operand, uint8_t size_override, RegFile reg_file) { 96122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov bool rex_b = (rex & 0b0001) != 0; 97122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov size_t reg_num = rex_b ? (reg + 8) : reg; 98122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file); 99122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov} 100122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov 101122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic void DumpAddrReg(std::ostream& os, uint8_t rex, uint8_t reg) { 102122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov if (rex != 0) { 103122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << gReg64Names[reg]; 104bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 105122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov os << gReg32Names[reg]; 106bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 107706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} 108706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 1097caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogersstatic void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) { 11038e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers bool rex_b = (rex & 0b0001) != 0; 11138e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers size_t reg_num = rex_b ? (reg + 8) : reg; 112122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpAddrReg(os, rex, reg_num); 113706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} 114706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 1157caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogersstatic void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) { 11638e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers bool rex_x = (rex & 0b0010) != 0; 11738e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers uint8_t reg_num = rex_x ? (reg + 8) : reg; 118122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpAddrReg(os, rex, reg_num); 119122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov} 120122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov 121122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukovstatic void DumpOpcodeReg(std::ostream& os, uint8_t rex, uint8_t reg) { 122122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov bool rex_b = (rex & 0b0001) != 0; 123122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov size_t reg_num = rex_b ? (reg + 8) : reg; 1247caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers DumpReg0(os, rex, reg_num, false, 0); 125706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} 126706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 12792301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughesenum SegmentPrefix { 12892301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes kCs = 0x2e, 12992301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes kSs = 0x36, 13092301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes kDs = 0x3e, 13192301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes kEs = 0x26, 13292301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes kFs = 0x64, 13392301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes kGs = 0x65, 13492301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes}; 13592301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes 136706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogersstatic void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) { 137706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers switch (segment_prefix) { 13892301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kCs: os << "cs:"; break; 13992301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kSs: os << "ss:"; break; 14092301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kDs: os << "ds:"; break; 14192301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kEs: os << "es:"; break; 14292301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kFs: os << "fs:"; break; 14392301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kGs: os << "gs:"; break; 144706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers default: break; 145706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 146706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} 147706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 148706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogerssize_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) { 149706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers const uint8_t* begin_instr = instr; 150706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool have_prefixes = true; 151706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t prefix[4] = {0, 0, 0, 0}; 152706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers const char** modrm_opcodes = NULL; 153706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers do { 154706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers switch (*instr) { 1557caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers // Group 1 - lock and repeat prefixes: 156706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xF0: 157706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xF2: 158706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xF3: 159706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers prefix[0] = *instr; 160706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 161706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers // Group 2 - segment override prefixes: 16292301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kCs: 16392301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kSs: 16492301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kDs: 16592301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kEs: 16692301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kFs: 16792301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes case kGs: 168706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers prefix[1] = *instr; 169706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 170706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers // Group 3 - operand size override: 171706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x66: 172706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers prefix[2] = *instr; 173706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 174706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers // Group 4 - address size override: 175706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x67: 176706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers prefix[3] = *instr; 177706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 178706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers default: 179706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers have_prefixes = false; 180706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 181706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 182706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (have_prefixes) { 183706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 184706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 185706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } while (have_prefixes); 18638e12034f1ef2b32e98b6e49cb36b7cc37a7f1beIan Rogers uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0; 187e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (rex != 0) { 188e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov instr++; 189e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } 190706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool has_modrm = false; 191706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool reg_is_opcode = false; 192706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers size_t immediate_bytes = 0; 193706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers size_t branch_bytes = 0; 194706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers std::ostringstream opcode; 195706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool store = false; // stores to memory (ie rm is on the left) 196706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool load = false; // loads from memory (ie rm is on the right) 197706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool byte_operand = false; 198122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov bool target_specific = false; // register name depends on target (64 vs 32 bits). 199706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool ax = false; // implicit use of ax 200e296248a124ed8287b38a9225463696c18d84cd6jeffhao bool cx = false; // implicit use of cx 201706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter 202703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao bool no_ops = false; 203bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers RegFile src_reg_file = GPR; 204bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers RegFile dst_reg_file = GPR; 205706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers switch (*instr) { 206706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers#define DISASSEMBLER_ENTRY(opname, \ 207706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers rm8_r8, rm32_r32, \ 208706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers r8_rm8, r32_rm32, \ 209706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers ax8_i8, ax32_i32) \ 210706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case rm8_r8: opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \ 211706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \ 212706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case r8_rm8: opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \ 213706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \ 214706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case ax8_i8: opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \ 215706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break; 216706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 217706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(add, 218706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */, 219706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */, 220706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */) 221706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(or, 222706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */, 223706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */, 224706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */) 225706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(adc, 226706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */, 227706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */, 228706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */) 229706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(sbb, 230706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */, 231706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */, 232706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */) 233706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(and, 234706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */, 235706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */, 236706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */) 237706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(sub, 238706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */, 239706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */, 240706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */) 241706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(xor, 242706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */, 243706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */, 244706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */) 245706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan RogersDISASSEMBLER_ENTRY(cmp, 246706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */, 247706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */, 248706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */) 249706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 250706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers#undef DISASSEMBLER_ENTRY 251706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 252706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << "push"; 253706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers reg_in_opcode = true; 254122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov target_specific = true; 255706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 256706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: 257706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << "pop"; 258706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers reg_in_opcode = true; 259122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov target_specific = true; 260706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 261706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x68: opcode << "push"; immediate_bytes = 4; break; 262d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell case 0x69: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 4; break; 263706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x6A: opcode << "push"; immediate_bytes = 1; break; 264d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell case 0x6B: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 1; break; 265706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: 266706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: 267706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers static const char* condition_codes[] = 268b25c3f6a86dc634ce44fb2849385b49465caa84dElliott Hughes {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a", 269b25c3f6a86dc634ce44fb2849385b49465caa84dElliott Hughes "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g" 270706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers }; 271706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << "j" << condition_codes[*instr & 0xF]; 272706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers branch_bytes = 1; 273706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 27499ad7230ccaace93bf323dea9790f35fe991a4a2Razvan A Lupusoru case 0x86: case 0x87: 27599ad7230ccaace93bf323dea9790f35fe991a4a2Razvan A Lupusoru opcode << "xchg"; 27699ad7230ccaace93bf323dea9790f35fe991a4a2Razvan A Lupusoru store = true; 27799ad7230ccaace93bf323dea9790f35fe991a4a2Razvan A Lupusoru has_modrm = true; 27899ad7230ccaace93bf323dea9790f35fe991a4a2Razvan A Lupusoru byte_operand = (*instr == 0x86); 27999ad7230ccaace93bf323dea9790f35fe991a4a2Razvan A Lupusoru break; 280706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break; 281706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x89: opcode << "mov"; store = true; has_modrm = true; break; 282706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break; 283706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x8B: opcode << "mov"; load = true; has_modrm = true; break; 284706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 285706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x0F: // 2 byte extended opcode 286706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 287706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers switch (*instr) { 2887caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0x10: case 0x11: 2897caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers if (prefix[0] == 0xF2) { 2907caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers opcode << "movsd"; 291fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 2927caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers } else if (prefix[0] == 0xF3) { 2937caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers opcode << "movss"; 294fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 2957caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers } else if (prefix[2] == 0x66) { 2967caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers opcode << "movupd"; 297fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 2987caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers } else { 2997caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers opcode << "movups"; 3007caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers } 3017caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers has_modrm = true; 302bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers src_reg_file = dst_reg_file = SSE; 3037caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers load = *instr == 0x10; 3047caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers store = !load; 3057caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers break; 3062c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru case 0x12: case 0x13: 3072c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru if (prefix[2] == 0x66) { 3082c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru opcode << "movlpd"; 3092c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 3102c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru } else if (prefix[0] == 0) { 3112c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru opcode << "movlps"; 3122c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru } 3132c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru has_modrm = true; 3142c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru src_reg_file = dst_reg_file = SSE; 3152c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru load = *instr == 0x12; 3162c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru store = !load; 3172c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru break; 3182c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru case 0x16: case 0x17: 3192c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru if (prefix[2] == 0x66) { 3202c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru opcode << "movhpd"; 3212c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 3222c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru } else if (prefix[0] == 0) { 3232c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru opcode << "movhps"; 3242c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru } 3252c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru has_modrm = true; 3262c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru src_reg_file = dst_reg_file = SSE; 3272c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru load = *instr == 0x16; 3282c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru store = !load; 3292c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru break; 3302c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru case 0x28: case 0x29: 3312c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru if (prefix[2] == 0x66) { 3322c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru opcode << "movapd"; 3332c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 3342c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru } else if (prefix[0] == 0) { 3352c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru opcode << "movaps"; 3362c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru } 3372c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru has_modrm = true; 3382c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru src_reg_file = dst_reg_file = SSE; 3392c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru load = *instr == 0x28; 3402c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru store = !load; 3412c498d1f28e62e81fbdb477ff93ca7454e7493d7Razvan A Lupusoru break; 342fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x2A: 343fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 344fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtpi2pd"; 345fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 346fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else if (prefix[0] == 0xF2) { 347fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtsi2sd"; 348fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 349fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else if (prefix[0] == 0xF3) { 350fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtsi2ss"; 351fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 352fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 353fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtpi2ps"; 354fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 355fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao load = true; 356fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 357fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = SSE; 358fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 359fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x2C: 360fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 361fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvttpd2pi"; 362fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 363fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else if (prefix[0] == 0xF2) { 364fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvttsd2si"; 365fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 366fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else if (prefix[0] == 0xF3) { 367fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvttss2si"; 368fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 369fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 370fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvttps2pi"; 371fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 372fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao load = true; 373fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 374fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao src_reg_file = SSE; 375fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 376fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x2D: 377fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 378fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtpd2pi"; 379fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 380fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else if (prefix[0] == 0xF2) { 381fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtsd2si"; 382fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 383fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else if (prefix[0] == 0xF3) { 384fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtss2si"; 385fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 386fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 387fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "cvtps2pi"; 388fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 389fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao load = true; 390fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 391fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao src_reg_file = SSE; 392fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 393fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x2E: 394fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "u"; 395fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao // FALLTHROUGH 396fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x2F: 397fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 398fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "comisd"; 399fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 400fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 401fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "comiss"; 402fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 403fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 404fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao load = true; 405fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao src_reg_file = dst_reg_file = SSE; 406fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 407706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x38: // 3 byte extended opcode 408fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell instr++; 409fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 410fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell switch (*instr) { 411fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0x40: 412fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pmulld"; 413fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 414fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 415fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 416fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 417fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 418fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell default: 419fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr); 420fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 421fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 422fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr); 423fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 424706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 425706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x3A: // 3 byte extended opcode 426fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell instr++; 427fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 428fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell switch (*instr) { 429fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0x14: 430fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pextrb"; 431fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 432fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 433fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell store = true; 434fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell dst_reg_file = SSE; 435fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell immediate_bytes = 1; 436fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 437fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0x16: 438fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pextrd"; 439fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 440fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 441fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell store = true; 442fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell dst_reg_file = SSE; 443fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell immediate_bytes = 1; 444fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 445fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell default: 446fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr); 447fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 448fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 449fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr); 450fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 451706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 452bd288c2c1206bc99fafebfb9120a83f13cf9723bRazvan A Lupusoru case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: 453bd288c2c1206bc99fafebfb9120a83f13cf9723bRazvan A Lupusoru case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: 454bd288c2c1206bc99fafebfb9120a83f13cf9723bRazvan A Lupusoru opcode << "cmov" << condition_codes[*instr & 0xF]; 455bd288c2c1206bc99fafebfb9120a83f13cf9723bRazvan A Lupusoru has_modrm = true; 456bd288c2c1206bc99fafebfb9120a83f13cf9723bRazvan A Lupusoru load = true; 457bd288c2c1206bc99fafebfb9120a83f13cf9723bRazvan A Lupusoru break; 458bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 459bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { 460bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers switch (*instr) { 461bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x50: opcode << "movmsk"; break; 462bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x51: opcode << "sqrt"; break; 463bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x52: opcode << "rsqrt"; break; 464bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x53: opcode << "rcp"; break; 465bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x54: opcode << "and"; break; 466bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x55: opcode << "andn"; break; 467bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x56: opcode << "or"; break; 468bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x57: opcode << "xor"; break; 469bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x58: opcode << "add"; break; 470bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x59: opcode << "mul"; break; 471bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x5C: opcode << "sub"; break; 472bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x5D: opcode << "min"; break; 473bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x5E: opcode << "div"; break; 474bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x5F: opcode << "max"; break; 475bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers default: LOG(FATAL) << "Unreachable"; 476bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 477bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (prefix[2] == 0x66) { 478bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "pd"; 479fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 480bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF2) { 481bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "sd"; 482fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 483bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF3) { 484bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "ss"; 485fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 486bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 487bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "ps"; 488bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 489bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers load = true; 490bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers has_modrm = true; 491bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers src_reg_file = dst_reg_file = SSE; 492bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers break; 493bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 494bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x5A: 495bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (prefix[2] == 0x66) { 496bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvtpd2ps"; 497fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 498bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF2) { 499bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvtsd2ss"; 500fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 501bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF3) { 502bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvtss2sd"; 503fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 504bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 505bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvtps2pd"; 506bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 507bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers load = true; 508bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers has_modrm = true; 509bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers src_reg_file = dst_reg_file = SSE; 510bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers break; 511bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x5B: 512bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (prefix[2] == 0x66) { 513bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvtps2dq"; 514fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 515bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF2) { 516bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "bad opcode F2 0F 5B"; 517bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF3) { 518bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvttps2dq"; 519fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 520bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 521bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "cvtdq2ps"; 522bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 523bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers load = true; 524bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers has_modrm = true; 525bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers src_reg_file = dst_reg_file = SSE; 526bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers break; 527d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru case 0x62: 528d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru if (prefix[2] == 0x66) { 529d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru src_reg_file = dst_reg_file = SSE; 530d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru prefix[2] = 0; // Clear prefix now. It has served its purpose as part of the opcode. 531d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru } else { 532d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru src_reg_file = dst_reg_file = MMX; 533d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru } 534d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru opcode << "punpckldq"; 535d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru load = true; 536d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru has_modrm = true; 537d3266bcc340d653e178e3ab9d74512c8db122eeeRazvan A Lupusoru break; 538bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x6E: 539bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (prefix[2] == 0x66) { 540bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers dst_reg_file = SSE; 541fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 542bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 543bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers dst_reg_file = MMX; 544bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 545fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "movd"; 546bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers load = true; 547bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers has_modrm = true; 548bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers break; 549bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers case 0x6F: 550bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (prefix[2] == 0x66) { 551fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 552bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "movdqa"; 553fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 554bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (prefix[0] == 0xF3) { 555fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 556bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "movdqu"; 557fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 558bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 559bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers dst_reg_file = MMX; 560bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers opcode << "movq"; 561bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 562bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers load = true; 563bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers has_modrm = true; 564bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers break; 565fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0x70: 566fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 567fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pshufd"; 568fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 569fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 570fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell store = true; 571fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 572fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell immediate_bytes = 1; 573fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else if (prefix[0] == 0xF2) { 574fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pshuflw"; 575fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[0] = 0; 576fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 577fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell store = true; 578fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 579fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell immediate_bytes = 1; 580fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 581fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F %02X'", *instr); 582fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 583fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 584fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x71: 585fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 586fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = SSE; 587fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 588fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 589fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = MMX; 590fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 591fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"}; 592fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao modrm_opcodes = x71_opcodes; 593fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao reg_is_opcode = true; 594fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 595fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao store = true; 596fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao immediate_bytes = 1; 597fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 598fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x72: 599fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 600fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = SSE; 601fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 602fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 603fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = MMX; 604fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 605fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"}; 606fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao modrm_opcodes = x72_opcodes; 607fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao reg_is_opcode = true; 608fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 609fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao store = true; 610fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao immediate_bytes = 1; 611fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 612fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x73: 613fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 614fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = SSE; 615fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 616fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 617fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao dst_reg_file = MMX; 618fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 619fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"}; 620fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao modrm_opcodes = x73_opcodes; 621fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao reg_is_opcode = true; 622fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 623fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao store = true; 624fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao immediate_bytes = 1; 625fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 626fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao case 0x7E: 627fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao if (prefix[2] == 0x66) { 628fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao src_reg_file = SSE; 629fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 630fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } else { 631fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao src_reg_file = MMX; 632fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao } 633fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao opcode << "movd"; 634fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao has_modrm = true; 635fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao store = true; 636fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao break; 637706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: 638706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: 639706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << "j" << condition_codes[*instr & 0xF]; 640706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers branch_bytes = 4; 641706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 6427caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: 6437caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: 6447caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers opcode << "set" << condition_codes[*instr & 0xF]; 6457caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers modrm_opcodes = NULL; 6467caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers reg_is_opcode = true; 6477caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers has_modrm = true; 6487caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers store = true; 6497caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers break; 6504708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell case 0xA4: 6514708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell opcode << "shld"; 6524708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell has_modrm = true; 6534708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell load = true; 6544708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell immediate_bytes = 1; 6554708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell break; 6564708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell case 0xAC: 6574708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell opcode << "shrd"; 6584708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell has_modrm = true; 6594708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell load = true; 6604708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell immediate_bytes = 1; 6614708dcd68eebf1173aef1097dad8ab13466059aaMark Mendell break; 662703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 0xAE: 663703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao if (prefix[0] == 0xF3) { 6645e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 665703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"}; 666703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao modrm_opcodes = xAE_opcodes; 667703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao reg_is_opcode = true; 668703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao has_modrm = true; 669703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao uint8_t reg_or_opcode = (instr[1] >> 3) & 7; 670703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao switch (reg_or_opcode) { 671703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 0: 672703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao prefix[1] = kFs; 673703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao load = true; 674703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 675703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 1: 676703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao prefix[1] = kGs; 677703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao load = true; 678703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 679703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 2: 680703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao prefix[1] = kFs; 681703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao store = true; 682703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 683703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 3: 684703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao prefix[1] = kGs; 685703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao store = true; 686703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 687703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao default: 688703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao load = true; 689703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 690703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao } 691703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao } else { 692703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"}; 693703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao modrm_opcodes = xAE_opcodes; 694703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao reg_is_opcode = true; 695703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao has_modrm = true; 696703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao load = true; 697703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao no_ops = true; 698703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao } 699703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 700f723f0cdc693f81581c0781fa472b1c85a8b42d6Mark Mendell case 0xAF: opcode << "imul"; has_modrm = true; load = true; break; 7018302576126efae240eb21c7545cda7982437bd26jeffhao case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break; 7027caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break; 7037caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break; 704854029c13351fd3a8f7794eb6c2c73af0fde8ac8jeffhao case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break; 705854029c13351fd3a8f7794eb6c2c73af0fde8ac8jeffhao case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break; 706fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xC5: 707fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 708fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pextrw"; 709fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 710fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 711fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell store = true; 712fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 713fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell immediate_bytes = 1; 714fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 715fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F %02X'", *instr); 716fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 717fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 71870b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko case 0xC7: 71970b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko static const char* x0FxC7_opcodes[] = { "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7" }; 72070b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko modrm_opcodes = x0FxC7_opcodes; 72170b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko has_modrm = true; 72270b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko reg_is_opcode = true; 72370b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko store = true; 72470b797d998f2a28e39f7d6ffc8a07c9cbc47da14Vladimir Marko break; 725a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: 726a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko opcode << "bswap"; 727a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko reg_in_opcode = true; 728a8b4caf7526b6b66a8ae0826bd52c39c66e3c714Vladimir Marko break; 729fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xDB: 730fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 731fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 732fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 733fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 734fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 735fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 736fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pand"; 737fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 738fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 739fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 740fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 741fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xD5: 742fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 743fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pmullw"; 744fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 745fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 746fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 747fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 748fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 749fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << StringPrintf("unknown opcode '0F %02X'", *instr); 750fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 751fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 752fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xEB: 753fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 754fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 755fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 756fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 757fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 758fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 759fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "por"; 760fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 761fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 762fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 763fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 764fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xEF: 765fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 766fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 767fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 768fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 769fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 770fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 771fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "pxor"; 772fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 773fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 774fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 775fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 776fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xF8: 777fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 778fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 779fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 780fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 781fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 782fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 783fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "psubb"; 784fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 785fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 786fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 787fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 788fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xF9: 789fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 790fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 791fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 792fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 793fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 794fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 795fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "psubw"; 796fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 797fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 798fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 799fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 800fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xFA: 801fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 802fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 803fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 804fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 805fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 806fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 807fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "psubd"; 808fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 809fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 810fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 811fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 812fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xFC: 813fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 814fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 815fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 816fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 817fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 818fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 819fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "paddb"; 820fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 821fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 822fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 823fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 824fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xFD: 825fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 826fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 827fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 828fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 829fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 830fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 831fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "paddw"; 832fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 833fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 834fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 835fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 836fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell case 0xFE: 837fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell if (prefix[2] == 0x66) { 838fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = SSE; 839fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 840fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } else { 841fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell src_reg_file = dst_reg_file = MMX; 842fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell } 843fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell opcode << "paddd"; 844fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell prefix[2] = 0; 845fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell has_modrm = true; 846fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell load = true; 847fe94578b63380f464c3abd5c156b7b31d068db6cMark Mendell break; 848706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers default: 849706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << StringPrintf("unknown opcode '0F %02X'", *instr); 850706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 851706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 852706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 853706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0x80: case 0x81: case 0x82: case 0x83: 854706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; 855706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers modrm_opcodes = x80_opcodes; 856706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers has_modrm = true; 857706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers reg_is_opcode = true; 858706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers store = true; 859706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers byte_operand = (*instr & 1) == 0; 860706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers immediate_bytes = *instr == 0x81 ? 4 : 1; 861706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 862703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 0x84: case 0x85: 863703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao opcode << "test"; 864703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao has_modrm = true; 865703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao load = true; 866703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao byte_operand = (*instr & 1) == 0; 867703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 8687caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0x8D: 8697caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers opcode << "lea"; 8707caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers has_modrm = true; 8717caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers load = true; 8727caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers break; 873703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao case 0x8F: 874703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao opcode << "pop"; 875703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao has_modrm = true; 876703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao reg_is_opcode = true; 877703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao store = true; 878703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao break; 8792bf31e67694da24a19fc1f328285cebb1a4b9964Mark Mendell case 0x99: 8802bf31e67694da24a19fc1f328285cebb1a4b9964Mark Mendell opcode << "cdq"; 8812bf31e67694da24a19fc1f328285cebb1a4b9964Mark Mendell break; 8824028a6c83a339036864999fdfd2855b012a9f1a7Mark Mendell case 0xAF: 8834028a6c83a339036864999fdfd2855b012a9f1a7Mark Mendell opcode << (prefix[2] == 0x66 ? "scasw" : "scasl"); 8844028a6c83a339036864999fdfd2855b012a9f1a7Mark Mendell break; 885706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: 886706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << "mov"; 887706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers immediate_bytes = 1; 888706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers reg_in_opcode = true; 889706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 890706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: 891706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << "mov"; 892706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers immediate_bytes = 4; 893706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers reg_in_opcode = true; 894706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 8957caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0xC0: case 0xC1: 896e296248a124ed8287b38a9225463696c18d84cd6jeffhao case 0xD0: case 0xD1: case 0xD2: case 0xD3: 8977caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers static const char* shift_opcodes[] = 8987caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"}; 8997caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers modrm_opcodes = shift_opcodes; 9007caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers has_modrm = true; 9017caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers reg_is_opcode = true; 9027caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers store = true; 90316b5c294c37460b51dc1f5296000cc80bbd33419Elliott Hughes immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0; 904e296248a124ed8287b38a9225463696c18d84cd6jeffhao cx = (*instr == 0xD2) || (*instr == 0xD3); 905e296248a124ed8287b38a9225463696c18d84cd6jeffhao byte_operand = (*instr == 0xC0); 9067caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers break; 907706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xC3: opcode << "ret"; break; 9080589ca9245849df238812444952c674e01361f2aElliott Hughes case 0xC7: 9090589ca9245849df238812444952c674e01361f2aElliott Hughes static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"}; 9100589ca9245849df238812444952c674e01361f2aElliott Hughes modrm_opcodes = c7_opcodes; 9110589ca9245849df238812444952c674e01361f2aElliott Hughes store = true; 9120589ca9245849df238812444952c674e01361f2aElliott Hughes immediate_bytes = 4; 9130589ca9245849df238812444952c674e01361f2aElliott Hughes has_modrm = true; 9140589ca9245849df238812444952c674e01361f2aElliott Hughes reg_is_opcode = true; 9150589ca9245849df238812444952c674e01361f2aElliott Hughes break; 9167caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0xCC: opcode << "int 3"; break; 917d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell case 0xD9: 918d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw", "fnstenv", "fnstcw"}; 919d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell modrm_opcodes = d9_opcodes; 920d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell store = true; 921d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell has_modrm = true; 922d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell reg_is_opcode = true; 923d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell break; 924614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru case 0xDB: 925614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru static const char* db_opcodes[] = {"fildl", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db"}; 926614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru modrm_opcodes = db_opcodes; 927614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru load = true; 928614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru has_modrm = true; 929614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru reg_is_opcode = true; 930614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru break; 931d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell case 0xDD: 932d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl", "fstpl", "frstor", "unknown-dd", "fnsave", "fnstsw"}; 933d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell modrm_opcodes = dd_opcodes; 934d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell store = true; 935d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell has_modrm = true; 936d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell reg_is_opcode = true; 937d19b55a05b52b7f7da9f894eba63ed03e2a62283Mark Mendell break; 938614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru case 0xDF: 939614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru static const char* df_opcodes[] = {"fild", "unknown-df", "unknown-df", "unknown-df", "unknown-df", "fildll", "unknown-df", "unknown-df"}; 940614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru modrm_opcodes = df_opcodes; 941614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru load = true; 942614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru has_modrm = true; 943614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru reg_is_opcode = true; 944614c2b4e219631e8c190fd9fd5d4d9cd343434e1Razvan A Lupusoru break; 9454028a6c83a339036864999fdfd2855b012a9f1a7Mark Mendell case 0xE3: opcode << "jecxz"; branch_bytes = 1; break; 9467caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers case 0xE8: opcode << "call"; branch_bytes = 4; break; 947706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xE9: opcode << "jmp"; branch_bytes = 4; break; 948706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xEB: opcode << "jmp"; branch_bytes = 1; break; 94977ae36b35d47393335bf5399cab9c91ccf08e88fjeffhao case 0xF5: opcode << "cmc"; break; 950174651dea03956e160a2cff0d842954823c49134jeffhao case 0xF6: case 0xF7: 951174651dea03956e160a2cff0d842954823c49134jeffhao static const char* f7_opcodes[] = {"test", "unknown-f7", "not", "neg", "mul edx:eax, eax *", "imul edx:eax, eax *", "div edx:eax, edx:eax /", "idiv edx:eax, edx:eax /"}; 952174651dea03956e160a2cff0d842954823c49134jeffhao modrm_opcodes = f7_opcodes; 953174651dea03956e160a2cff0d842954823c49134jeffhao has_modrm = true; 954174651dea03956e160a2cff0d842954823c49134jeffhao reg_is_opcode = true; 955174651dea03956e160a2cff0d842954823c49134jeffhao store = true; 956174651dea03956e160a2cff0d842954823c49134jeffhao immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; 957174651dea03956e160a2cff0d842954823c49134jeffhao break; 958706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers case 0xFF: 959706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"}; 960706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers modrm_opcodes = ff_opcodes; 961706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers has_modrm = true; 962706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers reg_is_opcode = true; 963706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers load = true; 964706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 965706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers default: 966706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << StringPrintf("unknown opcode '%02X'", *instr); 967706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers break; 968706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 969706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers std::ostringstream args; 970122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov // We force the REX prefix to be available for 64-bit target 971122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov // in order to dump addr (base/index) registers correctly. 972122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov uint8_t rex64 = supports_rex_ ? (rex | 0x40) : rex; 973706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (reg_in_opcode) { 974706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers DCHECK(!has_modrm); 975122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov // REX.W should be forced for 64-target and target-specific instructions (i.e., push or pop). 976122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov uint8_t rex_w = (supports_rex_ && target_specific) ? (rex | 0x48) : rex; 977122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpOpcodeReg(args, rex_w, *instr & 0x7); 978706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 979706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 98092301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes uint32_t address_bits = 0; 981706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (has_modrm) { 982706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t modrm = *instr; 983706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 984706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t mod = modrm >> 6; 985706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t reg_or_opcode = (modrm >> 3) & 7; 986706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t rm = modrm & 7; 987706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers std::ostringstream address; 988e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (mod == 0 && rm == 5) { 989e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (!supports_rex_) { // Absolute address. 990e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address_bits = *reinterpret_cast<const uint32_t*>(instr); 991e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address << StringPrintf("[0x%x]", address_bits); 992e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } else { // 64-bit RIP relative addressing. 993e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address << StringPrintf("[RIP + 0x%x]", *reinterpret_cast<const uint32_t*>(instr)); 994e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } 995706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr += 4; 996706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else if (rm == 4 && mod != 3) { // SIB 997706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t sib = *instr; 998706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 999e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov uint8_t scale = (sib >> 6) & 3; 1000706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t index = (sib >> 3) & 7; 1001706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers uint8_t base = sib & 7; 1002706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << "["; 1003706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (base != 5 || mod != 0) { 1004122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpBaseReg(address, rex64, base); 1005706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (index != 4) { 1006706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << " + "; 1007706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1008706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1009706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (index != 4) { 1010122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpIndexReg(address, rex64, index); 1011e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (scale != 0) { 1012e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address << StringPrintf(" * %d", 1 << scale); 1013706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1014706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1015e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (mod == 0) { 1016e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (base == 5) { 1017e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov if (index != 4) { 1018e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 1019e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } else { 1020e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit. 1021e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address_bits = *reinterpret_cast<const uint32_t*>(instr); 1022e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov address << StringPrintf("%d", address_bits); 1023e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } 1024e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov instr += 4; 1025e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } 1026e8861b30ac8b2b1ca49386f9c9218f1d6fedc511Vladimir Kostyukov } else if (mod == 1) { 1027706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr)); 1028706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 1029706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else if (mod == 2) { 1030706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 1031706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr += 4; 1032706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1033706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << "]"; 1034706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else { 1035bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (mod == 3) { 1036703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao if (!no_ops) { 1037122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpRmReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file); 1038703f2cd1f4d1eb5ab5c9792ca2de9ffb39378203jeffhao } 1039bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else { 1040706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << "["; 1041122113a8a233f824c014a8fe9d90626218c4dccaVladimir Kostyukov DumpBaseReg(address, rex64, rm); 1042bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers if (mod == 1) { 1043bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr)); 1044bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers instr++; 1045bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } else if (mod == 2) { 1046bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 1047bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers instr += 4; 1048bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers } 1049706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers address << "]"; 1050706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1051706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1052706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 10537caad77632ae121c9f64c488e3f8f710e2c4813dIan Rogers if (reg_is_opcode && modrm_opcodes != NULL) { 1054706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers opcode << modrm_opcodes[reg_or_opcode]; 1055706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1056706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (load) { 1057706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (!reg_is_opcode) { 1058bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file); 1059706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers args << ", "; 1060706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1061706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers DumpSegmentOverride(args, prefix[1]); 1062706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers args << address.str(); 1063706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else { 1064706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers DCHECK(store); 1065706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers DumpSegmentOverride(args, prefix[1]); 1066706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers args << address.str(); 1067706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (!reg_is_opcode) { 1068706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers args << ", "; 1069bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file); 1070706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1071706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1072706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1073706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (ax) { 1074fdffdf898f12d91765c7dbe7bcb1ccbbcd2b72d1jeffhao // If this opcode implicitly uses ax, ax is always the first arg. 1075bf989802bfcd0a0e1d27feb6b67b19cccb7b31e8Ian Rogers DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR); 1076706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1077e296248a124ed8287b38a9225463696c18d84cd6jeffhao if (cx) { 1078e296248a124ed8287b38a9225463696c18d84cd6jeffhao args << ", "; 1079e296248a124ed8287b38a9225463696c18d84cd6jeffhao DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR); 1080e296248a124ed8287b38a9225463696c18d84cd6jeffhao } 1081706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (immediate_bytes > 0) { 1082e296248a124ed8287b38a9225463696c18d84cd6jeffhao if (has_modrm || reg_in_opcode || ax || cx) { 1083706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers args << ", "; 1084706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1085706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (immediate_bytes == 1) { 1086706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr)); 1087706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 1088706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else { 1089706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers CHECK_EQ(immediate_bytes, 4u); 109067d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell if (prefix[2] == 0x66) { // Operand size override from 32-bit to 16-bit. 109167d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell args << StringPrintf("%d", *reinterpret_cast<const int16_t*>(instr)); 109267d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell instr += 2; 109367d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell } else { 109467d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr)); 109567d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell instr += 4; 109667d18be2a5bddbd8ee9ef144b34ccaeba08a1db2Mark Mendell } 1097706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1098706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else if (branch_bytes > 0) { 1099706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers DCHECK(!has_modrm); 1100706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers int32_t displacement; 1101706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers if (branch_bytes == 1) { 1102706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers displacement = *reinterpret_cast<const int8_t*>(instr); 1103706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr++; 1104706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } else { 1105706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers CHECK_EQ(branch_bytes, 4u); 1106706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers displacement = *reinterpret_cast<const int32_t*>(instr); 1107706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers instr += 4; 1108706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 110914178a99fd397737124e65d5ccb9446f85c5ca93Elliott Hughes args << StringPrintf("%+d (%p)", displacement, instr + displacement); 1110706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 1111dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers if (prefix[1] == kFs && !supports_rex_) { 111292301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes args << " ; "; 1113dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers Thread::DumpThreadOffset<4>(args, address_bits); 1114dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers } 1115dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers if (prefix[1] == kGs && supports_rex_) { 1116dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers args << " ; "; 1117dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers Thread::DumpThreadOffset<8>(args, address_bits); 111892301d97693ea52f5f6a9bc62d0c7fc611f87c7bElliott Hughes } 111928fa76d17d741238da86dbdb47f721ae97c9eac8Elliott Hughes std::stringstream hex; 1120706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers for (size_t i = 0; begin_instr + i < instr; ++i) { 112128fa76d17d741238da86dbdb47f721ae97c9eac8Elliott Hughes hex << StringPrintf("%02X", begin_instr[i]); 1122706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers } 11235e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers std::stringstream prefixed_opcode; 11245e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers switch (prefix[0]) { 11255e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers case 0xF0: prefixed_opcode << "lock "; break; 11265e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers case 0xF2: prefixed_opcode << "repne "; break; 11275e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers case 0xF3: prefixed_opcode << "repe "; break; 11285e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers case 0: break; 11295e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers default: LOG(FATAL) << "Unreachable"; 11305e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers } 11315e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers prefixed_opcode << opcode.str(); 11325e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers os << StringPrintf("%p: %22s \t%-7s ", begin_instr, hex.str().c_str(), 11335e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers prefixed_opcode.str().c_str()) 11345e588b3c9af58ef54dcdd2cf129472dbe923a5bfIan Rogers << args.str() << '\n'; 1135706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers return instr - begin_instr; 11367934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom} // NOLINT(readability/fn_size) 1137706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers 1138706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} // namespace x86 1139706a10ea53a32455c6b3ffc5e5e0e1f6f191ec2aIan Rogers} // namespace art 1140