You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
794 lines
22 KiB
794 lines
22 KiB
//===-- X86Disassembler.cpp - Disassembler for x86 and x86_64 -------------===// |
|
// |
|
// The LLVM Compiler Infrastructure |
|
// |
|
// This file is distributed under the University of Illinois Open Source |
|
// License. See LICENSE.TXT for details. |
|
// |
|
//===----------------------------------------------------------------------===// |
|
// |
|
// This file is part of the X86 Disassembler. |
|
// It contains code to translate the data produced by the decoder into |
|
// MCInsts. |
|
// Documentation for the disassembler can be found in X86Disassembler.h. |
|
// |
|
//===----------------------------------------------------------------------===// |
|
|
|
/* Capstone Disassembly Engine */ |
|
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */ |
|
|
|
#ifdef CAPSTONE_HAS_X86 |
|
|
|
#include "../../inttypes.h" // debug |
|
#include <string.h> |
|
|
|
#include "../../cs_priv.h" |
|
|
|
#include "X86Disassembler.h" |
|
#include "X86DisassemblerDecoderCommon.h" |
|
#include "X86DisassemblerDecoder.h" |
|
#include "../../MCInst.h" |
|
#include "../../utils.h" |
|
#include "X86Mapping.h" |
|
|
|
#define GET_REGINFO_ENUM |
|
#define GET_REGINFO_MC_DESC |
|
#include "X86GenRegisterInfo.inc" |
|
|
|
#define GET_INSTRINFO_ENUM |
|
#ifdef CAPSTONE_X86_REDUCE |
|
#include "X86GenInstrInfo_reduce.inc" |
|
#else |
|
#include "X86GenInstrInfo.inc" |
|
#endif |
|
|
|
// Fill-ins to make the compiler happy. These constants are never actually |
|
// assigned; they are just filler to make an automatically-generated switch |
|
// statement work. |
|
enum { |
|
X86_BX_SI = 500, |
|
X86_BX_DI = 501, |
|
X86_BP_SI = 502, |
|
X86_BP_DI = 503, |
|
X86_sib = 504, |
|
X86_sib64 = 505 |
|
}; |
|
|
|
// |
|
// Private code that translates from struct InternalInstructions to MCInsts. |
|
// |
|
|
|
/// translateRegister - Translates an internal register to the appropriate LLVM |
|
/// register, and appends it as an operand to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param reg - The Reg to append. |
|
static void translateRegister(MCInst *mcInst, Reg reg) |
|
{ |
|
#define ENTRY(x) X86_##x, |
|
uint8_t llvmRegnums[] = { |
|
ALL_REGS |
|
0 |
|
}; |
|
#undef ENTRY |
|
|
|
uint8_t llvmRegnum = llvmRegnums[reg]; |
|
MCOperand_CreateReg0(mcInst, llvmRegnum); |
|
} |
|
|
|
static const uint8_t segmentRegnums[SEG_OVERRIDE_max] = { |
|
0, // SEG_OVERRIDE_NONE |
|
X86_CS, |
|
X86_SS, |
|
X86_DS, |
|
X86_ES, |
|
X86_FS, |
|
X86_GS |
|
}; |
|
|
|
/// translateSrcIndex - Appends a source index operand to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param insn - The internal instruction. |
|
static bool translateSrcIndex(MCInst *mcInst, InternalInstruction *insn) |
|
{ |
|
unsigned baseRegNo; |
|
|
|
if (insn->mode == MODE_64BIT) |
|
baseRegNo = insn->prefixPresent[0x67] ? X86_ESI : X86_RSI; |
|
else if (insn->mode == MODE_32BIT) |
|
baseRegNo = insn->prefixPresent[0x67] ? X86_SI : X86_ESI; |
|
else { |
|
// assert(insn->mode == MODE_16BIT); |
|
baseRegNo = insn->prefixPresent[0x67] ? X86_ESI : X86_SI; |
|
} |
|
|
|
MCOperand_CreateReg0(mcInst, baseRegNo); |
|
|
|
MCOperand_CreateReg0(mcInst, segmentRegnums[insn->segmentOverride]); |
|
|
|
return false; |
|
} |
|
|
|
/// translateDstIndex - Appends a destination index operand to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param insn - The internal instruction. |
|
static bool translateDstIndex(MCInst *mcInst, InternalInstruction *insn) |
|
{ |
|
unsigned baseRegNo; |
|
|
|
if (insn->mode == MODE_64BIT) |
|
baseRegNo = insn->prefixPresent[0x67] ? X86_EDI : X86_RDI; |
|
else if (insn->mode == MODE_32BIT) |
|
baseRegNo = insn->prefixPresent[0x67] ? X86_DI : X86_EDI; |
|
else { |
|
// assert(insn->mode == MODE_16BIT); |
|
baseRegNo = insn->prefixPresent[0x67] ? X86_EDI : X86_DI; |
|
} |
|
|
|
MCOperand_CreateReg0(mcInst, baseRegNo); |
|
|
|
return false; |
|
} |
|
|
|
/// translateImmediate - Appends an immediate operand to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param immediate - The immediate value to append. |
|
/// @param operand - The operand, as stored in the descriptor table. |
|
/// @param insn - The internal instruction. |
|
static void translateImmediate(MCInst *mcInst, uint64_t immediate, |
|
const OperandSpecifier *operand, InternalInstruction *insn) |
|
{ |
|
OperandType type; |
|
|
|
type = (OperandType)operand->type; |
|
if (type == TYPE_RELv) { |
|
//isBranch = true; |
|
//pcrel = insn->startLocation + insn->immediateOffset + insn->immediateSize; |
|
switch (insn->displacementSize) { |
|
case 1: |
|
if (immediate & 0x80) |
|
immediate |= ~(0xffull); |
|
break; |
|
case 2: |
|
if (immediate & 0x8000) |
|
immediate |= ~(0xffffull); |
|
break; |
|
case 4: |
|
if (immediate & 0x80000000) |
|
immediate |= ~(0xffffffffull); |
|
break; |
|
case 8: |
|
break; |
|
default: |
|
break; |
|
} |
|
} // By default sign-extend all X86 immediates based on their encoding. |
|
else if (type == TYPE_IMM8 || type == TYPE_IMM16 || type == TYPE_IMM32 || |
|
type == TYPE_IMM64 || type == TYPE_IMMv) { |
|
uint32_t Opcode = MCInst_getOpcode(mcInst); |
|
switch (operand->encoding) { |
|
default: |
|
break; |
|
case ENCODING_IB: |
|
// Special case those X86 instructions that use the imm8 as a set of |
|
// bits, bit count, etc. and are not sign-extend. |
|
if ( |
|
#ifndef CAPSTONE_X86_REDUCE |
|
Opcode != X86_BLENDPSrri && |
|
Opcode != X86_BLENDPDrri && |
|
Opcode != X86_PBLENDWrri && |
|
Opcode != X86_MPSADBWrri && |
|
Opcode != X86_DPPSrri && |
|
Opcode != X86_DPPDrri && |
|
Opcode != X86_INSERTPSrr && |
|
Opcode != X86_VBLENDPSYrri && |
|
Opcode != X86_VBLENDPSYrmi && |
|
Opcode != X86_VBLENDPDYrri && |
|
Opcode != X86_VBLENDPDYrmi && |
|
Opcode != X86_VPBLENDWrri && |
|
Opcode != X86_VMPSADBWrri && |
|
Opcode != X86_VDPPSYrri && |
|
Opcode != X86_VDPPSYrmi && |
|
Opcode != X86_VDPPDrri && |
|
Opcode != X86_VINSERTPSrr && |
|
#endif |
|
Opcode != X86_INT) |
|
if(immediate & 0x80) |
|
immediate |= ~(0xffull); |
|
break; |
|
case ENCODING_IW: |
|
if(immediate & 0x8000) |
|
immediate |= ~(0xffffull); |
|
break; |
|
case ENCODING_ID: |
|
if(immediate & 0x80000000) |
|
immediate |= ~(0xffffffffull); |
|
break; |
|
case ENCODING_IO: |
|
break; |
|
} |
|
} |
|
|
|
switch (type) { |
|
case TYPE_XMM32: |
|
case TYPE_XMM64: |
|
case TYPE_XMM128: |
|
MCOperand_CreateReg0(mcInst, X86_XMM0 + ((uint32_t)immediate >> 4)); |
|
return; |
|
case TYPE_XMM256: |
|
MCOperand_CreateReg0(mcInst, X86_YMM0 + ((uint32_t)immediate >> 4)); |
|
return; |
|
case TYPE_XMM512: |
|
MCOperand_CreateReg0(mcInst, X86_ZMM0 + ((uint32_t)immediate >> 4)); |
|
return; |
|
case TYPE_REL8: |
|
if(immediate & 0x80) |
|
immediate |= ~(0xffull); |
|
break; |
|
case TYPE_REL32: |
|
case TYPE_REL64: |
|
if(immediate & 0x80000000) |
|
immediate |= ~(0xffffffffull); |
|
break; |
|
default: |
|
// operand is 64 bits wide. Do nothing. |
|
break; |
|
} |
|
|
|
MCOperand_CreateImm0(mcInst, immediate); |
|
|
|
if (type == TYPE_MOFFS8 || type == TYPE_MOFFS16 || |
|
type == TYPE_MOFFS32 || type == TYPE_MOFFS64) { |
|
MCOperand_CreateReg0(mcInst, segmentRegnums[insn->segmentOverride]); |
|
} |
|
} |
|
|
|
/// translateRMRegister - Translates a register stored in the R/M field of the |
|
/// ModR/M byte to its LLVM equivalent and appends it to an MCInst. |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param insn - The internal instruction to extract the R/M field |
|
/// from. |
|
/// @return - 0 on success; -1 otherwise |
|
static bool translateRMRegister(MCInst *mcInst, InternalInstruction *insn) |
|
{ |
|
if (insn->eaBase == EA_BASE_sib || insn->eaBase == EA_BASE_sib64) { |
|
//debug("A R/M register operand may not have a SIB byte"); |
|
return true; |
|
} |
|
|
|
switch (insn->eaBase) { |
|
case EA_BASE_NONE: |
|
//debug("EA_BASE_NONE for ModR/M base"); |
|
return true; |
|
#define ENTRY(x) case EA_BASE_##x: |
|
ALL_EA_BASES |
|
#undef ENTRY |
|
//debug("A R/M register operand may not have a base; " |
|
// "the operand must be a register."); |
|
return true; |
|
#define ENTRY(x) \ |
|
case EA_REG_##x: \ |
|
MCOperand_CreateReg0(mcInst, X86_##x); break; |
|
ALL_REGS |
|
#undef ENTRY |
|
default: |
|
//debug("Unexpected EA base register"); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
/// translateRMMemory - Translates a memory operand stored in the Mod and R/M |
|
/// fields of an internal instruction (and possibly its SIB byte) to a memory |
|
/// operand in LLVM's format, and appends it to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param insn - The instruction to extract Mod, R/M, and SIB fields |
|
/// from. |
|
/// @return - 0 on success; nonzero otherwise |
|
static bool translateRMMemory(MCInst *mcInst, InternalInstruction *insn) |
|
{ |
|
// Addresses in an MCInst are represented as five operands: |
|
// 1. basereg (register) The R/M base, or (if there is a SIB) the |
|
// SIB base |
|
// 2. scaleamount (immediate) 1, or (if there is a SIB) the specified |
|
// scale amount |
|
// 3. indexreg (register) x86_registerNONE, or (if there is a SIB) |
|
// the index (which is multiplied by the |
|
// scale amount) |
|
// 4. displacement (immediate) 0, or the displacement if there is one |
|
// 5. segmentreg (register) x86_registerNONE for now, but could be set |
|
// if we have segment overrides |
|
|
|
bool IndexIs512, IndexIs128, IndexIs256; |
|
int scaleAmount, indexReg; |
|
#ifndef CAPSTONE_X86_REDUCE |
|
uint32_t Opcode; |
|
#endif |
|
|
|
if (insn->eaBase == EA_BASE_sib || insn->eaBase == EA_BASE_sib64) { |
|
if (insn->sibBase != SIB_BASE_NONE) { |
|
switch (insn->sibBase) { |
|
#define ENTRY(x) \ |
|
case SIB_BASE_##x: \ |
|
MCOperand_CreateReg0(mcInst, X86_##x); break; |
|
ALL_SIB_BASES |
|
#undef ENTRY |
|
default: |
|
//debug("Unexpected sibBase"); |
|
return true; |
|
} |
|
} else { |
|
MCOperand_CreateReg0(mcInst, 0); |
|
} |
|
|
|
// Check whether we are handling VSIB addressing mode for GATHER. |
|
// If sibIndex was set to SIB_INDEX_NONE, index offset is 4 and |
|
// we should use SIB_INDEX_XMM4|YMM4 for VSIB. |
|
// I don't see a way to get the correct IndexReg in readSIB: |
|
// We can tell whether it is VSIB or SIB after instruction ID is decoded, |
|
// but instruction ID may not be decoded yet when calling readSIB. |
|
#ifndef CAPSTONE_X86_REDUCE |
|
Opcode = MCInst_getOpcode(mcInst); |
|
#endif |
|
IndexIs128 = ( |
|
#ifndef CAPSTONE_X86_REDUCE |
|
Opcode == X86_VGATHERDPDrm || |
|
Opcode == X86_VGATHERDPDYrm || |
|
Opcode == X86_VGATHERQPDrm || |
|
Opcode == X86_VGATHERDPSrm || |
|
Opcode == X86_VGATHERQPSrm || |
|
Opcode == X86_VPGATHERDQrm || |
|
Opcode == X86_VPGATHERDQYrm || |
|
Opcode == X86_VPGATHERQQrm || |
|
Opcode == X86_VPGATHERDDrm || |
|
Opcode == X86_VPGATHERQDrm || |
|
#endif |
|
false |
|
); |
|
IndexIs256 = ( |
|
#ifndef CAPSTONE_X86_REDUCE |
|
Opcode == X86_VGATHERQPDYrm || |
|
Opcode == X86_VGATHERDPSYrm || |
|
Opcode == X86_VGATHERQPSYrm || |
|
Opcode == X86_VGATHERDPDZrm || |
|
Opcode == X86_VPGATHERDQZrm || |
|
Opcode == X86_VPGATHERQQYrm || |
|
Opcode == X86_VPGATHERDDYrm || |
|
Opcode == X86_VPGATHERQDYrm || |
|
#endif |
|
false |
|
); |
|
IndexIs512 = ( |
|
#ifndef CAPSTONE_X86_REDUCE |
|
Opcode == X86_VGATHERQPDZrm || |
|
Opcode == X86_VGATHERDPSZrm || |
|
Opcode == X86_VGATHERQPSZrm || |
|
Opcode == X86_VPGATHERQQZrm || |
|
Opcode == X86_VPGATHERDDZrm || |
|
Opcode == X86_VPGATHERQDZrm || |
|
#endif |
|
false |
|
); |
|
|
|
if (IndexIs128 || IndexIs256 || IndexIs512) { |
|
unsigned IndexOffset = insn->sibIndex - |
|
(insn->addressSize == 8 ? SIB_INDEX_RAX:SIB_INDEX_EAX); |
|
SIBIndex IndexBase = IndexIs512 ? SIB_INDEX_ZMM0 : |
|
IndexIs256 ? SIB_INDEX_YMM0 : SIB_INDEX_XMM0; |
|
|
|
insn->sibIndex = (SIBIndex)(IndexBase + (insn->sibIndex == SIB_INDEX_NONE ? 4 : IndexOffset)); |
|
} |
|
|
|
if (insn->sibIndex != SIB_INDEX_NONE) { |
|
switch (insn->sibIndex) { |
|
default: |
|
//debug("Unexpected sibIndex"); |
|
return true; |
|
#define ENTRY(x) \ |
|
case SIB_INDEX_##x: \ |
|
indexReg = X86_##x; break; |
|
EA_BASES_32BIT |
|
EA_BASES_64BIT |
|
REGS_XMM |
|
REGS_YMM |
|
REGS_ZMM |
|
#undef ENTRY |
|
} |
|
} else { |
|
indexReg = 0; |
|
} |
|
|
|
scaleAmount = insn->sibScale; |
|
} else { |
|
switch (insn->eaBase) { |
|
case EA_BASE_NONE: |
|
if (insn->eaDisplacement == EA_DISP_NONE) { |
|
//debug("EA_BASE_NONE and EA_DISP_NONE for ModR/M base"); |
|
return true; |
|
} |
|
if (insn->mode == MODE_64BIT) { |
|
if (insn->prefix3 == 0x67) // address-size prefix overrides RIP relative addressing |
|
MCOperand_CreateReg0(mcInst, X86_EIP); |
|
else |
|
MCOperand_CreateReg0(mcInst, X86_RIP); // Section 2.2.1.6 |
|
} else { |
|
MCOperand_CreateReg0(mcInst, 0); |
|
} |
|
|
|
indexReg = 0; |
|
break; |
|
case EA_BASE_BX_SI: |
|
MCOperand_CreateReg0(mcInst, X86_BX); |
|
indexReg = X86_SI; |
|
break; |
|
case EA_BASE_BX_DI: |
|
MCOperand_CreateReg0(mcInst, X86_BX); |
|
indexReg = X86_DI; |
|
break; |
|
case EA_BASE_BP_SI: |
|
MCOperand_CreateReg0(mcInst, X86_BP); |
|
indexReg = X86_SI; |
|
break; |
|
case EA_BASE_BP_DI: |
|
MCOperand_CreateReg0(mcInst, X86_BP); |
|
indexReg = X86_DI; |
|
break; |
|
default: |
|
indexReg = 0; |
|
switch (insn->eaBase) { |
|
default: |
|
//debug("Unexpected eaBase"); |
|
return true; |
|
// Here, we will use the fill-ins defined above. However, |
|
// BX_SI, BX_DI, BP_SI, and BP_DI are all handled above and |
|
// sib and sib64 were handled in the top-level if, so they're only |
|
// placeholders to keep the compiler happy. |
|
#define ENTRY(x) \ |
|
case EA_BASE_##x: \ |
|
MCOperand_CreateReg0(mcInst, X86_##x); break; |
|
ALL_EA_BASES |
|
#undef ENTRY |
|
#define ENTRY(x) case EA_REG_##x: |
|
ALL_REGS |
|
#undef ENTRY |
|
//debug("A R/M memory operand may not be a register; " |
|
// "the base field must be a base."); |
|
return true; |
|
} |
|
} |
|
|
|
scaleAmount = 1; |
|
} |
|
|
|
MCOperand_CreateImm0(mcInst, scaleAmount); |
|
MCOperand_CreateReg0(mcInst, indexReg); |
|
MCOperand_CreateImm0(mcInst, insn->displacement); |
|
|
|
MCOperand_CreateReg0(mcInst, segmentRegnums[insn->segmentOverride]); |
|
|
|
return false; |
|
} |
|
|
|
/// translateRM - Translates an operand stored in the R/M (and possibly SIB) |
|
/// byte of an instruction to LLVM form, and appends it to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param operand - The operand, as stored in the descriptor table. |
|
/// @param insn - The instruction to extract Mod, R/M, and SIB fields |
|
/// from. |
|
/// @return - 0 on success; nonzero otherwise |
|
static bool translateRM(MCInst *mcInst, const OperandSpecifier *operand, |
|
InternalInstruction *insn) |
|
{ |
|
switch (operand->type) { |
|
case TYPE_R8: |
|
case TYPE_R16: |
|
case TYPE_R32: |
|
case TYPE_R64: |
|
case TYPE_Rv: |
|
case TYPE_MM: |
|
case TYPE_MM32: |
|
case TYPE_MM64: |
|
case TYPE_XMM: |
|
case TYPE_XMM32: |
|
case TYPE_XMM64: |
|
case TYPE_XMM128: |
|
case TYPE_XMM256: |
|
case TYPE_XMM512: |
|
case TYPE_VK1: |
|
case TYPE_VK8: |
|
case TYPE_VK16: |
|
case TYPE_DEBUGREG: |
|
case TYPE_CONTROLREG: |
|
return translateRMRegister(mcInst, insn); |
|
case TYPE_M: |
|
case TYPE_M8: |
|
case TYPE_M16: |
|
case TYPE_M32: |
|
case TYPE_M64: |
|
case TYPE_M128: |
|
case TYPE_M256: |
|
case TYPE_M512: |
|
case TYPE_Mv: |
|
case TYPE_M32FP: |
|
case TYPE_M64FP: |
|
case TYPE_M80FP: |
|
case TYPE_M16INT: |
|
case TYPE_M32INT: |
|
case TYPE_M64INT: |
|
case TYPE_M1616: |
|
case TYPE_M1632: |
|
case TYPE_M1664: |
|
case TYPE_LEA: |
|
return translateRMMemory(mcInst, insn); |
|
default: |
|
//debug("Unexpected type for a R/M operand"); |
|
return true; |
|
} |
|
} |
|
|
|
/// translateFPRegister - Translates a stack position on the FPU stack to its |
|
/// LLVM form, and appends it to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param stackPos - The stack position to translate. |
|
static void translateFPRegister(MCInst *mcInst, uint8_t stackPos) |
|
{ |
|
MCOperand_CreateReg0(mcInst, X86_ST0 + stackPos); |
|
} |
|
|
|
/// translateMaskRegister - Translates a 3-bit mask register number to |
|
/// LLVM form, and appends it to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param maskRegNum - Number of mask register from 0 to 7. |
|
/// @return - false on success; true otherwise. |
|
static bool translateMaskRegister(MCInst *mcInst, uint8_t maskRegNum) |
|
{ |
|
if (maskRegNum >= 8) { |
|
// debug("Invalid mask register number"); |
|
return true; |
|
} |
|
|
|
MCOperand_CreateReg0(mcInst, X86_K0 + maskRegNum); |
|
|
|
return false; |
|
} |
|
|
|
/// translateOperand - Translates an operand stored in an internal instruction |
|
/// to LLVM's format and appends it to an MCInst. |
|
/// |
|
/// @param mcInst - The MCInst to append to. |
|
/// @param operand - The operand, as stored in the descriptor table. |
|
/// @param insn - The internal instruction. |
|
/// @return - false on success; true otherwise. |
|
static bool translateOperand(MCInst *mcInst, const OperandSpecifier *operand, InternalInstruction *insn) |
|
{ |
|
switch (operand->encoding) { |
|
case ENCODING_REG: |
|
translateRegister(mcInst, insn->reg); |
|
return false; |
|
case ENCODING_WRITEMASK: |
|
return translateMaskRegister(mcInst, insn->writemask); |
|
CASE_ENCODING_RM: |
|
return translateRM(mcInst, operand, insn); |
|
case ENCODING_CB: |
|
case ENCODING_CW: |
|
case ENCODING_CD: |
|
case ENCODING_CP: |
|
case ENCODING_CO: |
|
case ENCODING_CT: |
|
//debug("Translation of code offsets isn't supported."); |
|
return true; |
|
case ENCODING_IB: |
|
case ENCODING_IW: |
|
case ENCODING_ID: |
|
case ENCODING_IO: |
|
case ENCODING_Iv: |
|
case ENCODING_Ia: |
|
translateImmediate(mcInst, insn->immediates[insn->numImmediatesTranslated++], operand, insn); |
|
return false; |
|
case ENCODING_SI: |
|
return translateSrcIndex(mcInst, insn); |
|
case ENCODING_DI: |
|
return translateDstIndex(mcInst, insn); |
|
case ENCODING_RB: |
|
case ENCODING_RW: |
|
case ENCODING_RD: |
|
case ENCODING_RO: |
|
case ENCODING_Rv: |
|
translateRegister(mcInst, insn->opcodeRegister); |
|
return false; |
|
case ENCODING_FP: |
|
translateFPRegister(mcInst, insn->modRM & 7); |
|
return false; |
|
case ENCODING_VVVV: |
|
translateRegister(mcInst, insn->vvvv); |
|
return false; |
|
case ENCODING_DUP: |
|
return translateOperand(mcInst, &insn->operands[operand->type - TYPE_DUP0], insn); |
|
default: |
|
//debug("Unhandled operand encoding during translation"); |
|
return true; |
|
} |
|
} |
|
|
|
static bool translateInstruction(MCInst *mcInst, InternalInstruction *insn) |
|
{ |
|
int index; |
|
|
|
if (!insn->spec) { |
|
//debug("Instruction has no specification"); |
|
return true; |
|
} |
|
|
|
MCInst_setOpcode(mcInst, insn->instructionID); |
|
|
|
// If when reading the prefix bytes we determined the overlapping 0xf2 or 0xf3 |
|
// prefix bytes should be disassembled as xrelease and xacquire then set the |
|
// opcode to those instead of the rep and repne opcodes. |
|
#ifndef CAPSTONE_X86_REDUCE |
|
if (insn->xAcquireRelease) { |
|
if (MCInst_getOpcode(mcInst) == X86_REP_PREFIX) |
|
MCInst_setOpcode(mcInst, X86_XRELEASE_PREFIX); |
|
else if (MCInst_getOpcode(mcInst) == X86_REPNE_PREFIX) |
|
MCInst_setOpcode(mcInst, X86_XACQUIRE_PREFIX); |
|
} |
|
#endif |
|
|
|
insn->numImmediatesTranslated = 0; |
|
|
|
for (index = 0; index < X86_MAX_OPERANDS; ++index) { |
|
if (insn->operands[index].encoding != ENCODING_NONE) { |
|
if (translateOperand(mcInst, &insn->operands[index], insn)) { |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
static int reader(const struct reader_info *info, uint8_t *byte, uint64_t address) |
|
{ |
|
if (address - info->offset >= info->size) |
|
// out of buffer range |
|
return -1; |
|
|
|
*byte = info->code[address - info->offset]; |
|
|
|
return 0; |
|
} |
|
|
|
// copy x86 detail information from internal structure to public structure |
|
static void update_pub_insn(cs_insn *pub, InternalInstruction *inter, uint8_t *prefixes) |
|
{ |
|
prefixes[0] = inter->prefix0; |
|
prefixes[1] = inter->prefix1; |
|
prefixes[2] = inter->prefix2; |
|
prefixes[3] = inter->prefix3; |
|
|
|
if (inter->vectorExtensionType != 0) |
|
memcpy(pub->detail->x86.opcode, inter->vectorExtensionPrefix, sizeof(pub->detail->x86.opcode)); |
|
else { |
|
if (inter->twoByteEscape) { |
|
if (inter->threeByteEscape) { |
|
pub->detail->x86.opcode[0] = inter->twoByteEscape; |
|
pub->detail->x86.opcode[1] = inter->threeByteEscape; |
|
pub->detail->x86.opcode[2] = inter->opcode; |
|
} else { |
|
pub->detail->x86.opcode[0] = inter->twoByteEscape; |
|
pub->detail->x86.opcode[1] = inter->opcode; |
|
} |
|
} else { |
|
pub->detail->x86.opcode[0] = inter->opcode; |
|
} |
|
} |
|
|
|
pub->detail->x86.rex = inter->rexPrefix; |
|
|
|
pub->detail->x86.addr_size = inter->addressSize; |
|
|
|
pub->detail->x86.modrm = inter->orgModRM; |
|
pub->detail->x86.sib = inter->sib; |
|
pub->detail->x86.disp = inter->displacement; |
|
|
|
pub->detail->x86.sib_index = x86_map_sib_index(inter->sibIndex); |
|
pub->detail->x86.sib_scale = inter->sibScale; |
|
pub->detail->x86.sib_base = x86_map_sib_base(inter->sibBase); |
|
} |
|
|
|
void X86_init(MCRegisterInfo *MRI) |
|
{ |
|
/* |
|
InitMCRegisterInfo(X86RegDesc, 234, |
|
RA, PC, |
|
X86MCRegisterClasses, 79, |
|
X86RegUnitRoots, 119, X86RegDiffLists, X86RegStrings, |
|
X86SubRegIdxLists, 7, |
|
X86SubRegIdxRanges, X86RegEncodingTable); |
|
*/ |
|
|
|
MCRegisterInfo_InitMCRegisterInfo(MRI, X86RegDesc, 234, |
|
0, 0, |
|
X86MCRegisterClasses, 79, |
|
0, 0, X86RegDiffLists, 0, |
|
X86SubRegIdxLists, 7, |
|
0); |
|
} |
|
|
|
// Public interface for the disassembler |
|
bool X86_getInstruction(csh ud, const uint8_t *code, size_t code_len, |
|
MCInst *instr, uint16_t *size, uint64_t address, void *_info) |
|
{ |
|
cs_struct *handle = (cs_struct *)(uintptr_t)ud; |
|
InternalInstruction insn; |
|
struct reader_info info; |
|
int ret; |
|
bool result; |
|
|
|
info.code = code; |
|
info.size = code_len; |
|
info.offset = address; |
|
|
|
memset(&insn, 0, offsetof(InternalInstruction, reader)); |
|
|
|
if (instr->flat_insn->detail) { |
|
instr->flat_insn->detail->x86.op_count = 0; |
|
instr->flat_insn->detail->x86.sse_cc = X86_SSE_CC_INVALID; |
|
instr->flat_insn->detail->x86.avx_cc = X86_AVX_CC_INVALID; |
|
instr->flat_insn->detail->x86.avx_sae = false; |
|
instr->flat_insn->detail->x86.avx_rm = X86_AVX_RM_INVALID; |
|
|
|
memset(instr->flat_insn->detail->x86.prefix, 0, sizeof(instr->flat_insn->detail->x86.prefix)); |
|
memset(instr->flat_insn->detail->x86.opcode, 0, sizeof(instr->flat_insn->detail->x86.opcode)); |
|
memset(instr->flat_insn->detail->x86.operands, 0, sizeof(instr->flat_insn->detail->x86.operands)); |
|
} |
|
|
|
if (handle->mode & CS_MODE_16) |
|
ret = decodeInstruction(&insn, |
|
reader, &info, |
|
address, |
|
MODE_16BIT); |
|
else if (handle->mode & CS_MODE_32) |
|
ret = decodeInstruction(&insn, |
|
reader, &info, |
|
address, |
|
MODE_32BIT); |
|
else |
|
ret = decodeInstruction(&insn, |
|
reader, &info, |
|
address, |
|
MODE_64BIT); |
|
|
|
if (ret) { |
|
*size = (uint16_t)(insn.readerCursor - address); |
|
|
|
return false; |
|
} else { |
|
*size = (uint16_t)insn.length; |
|
|
|
result = (!translateInstruction(instr, &insn)) ? true : false; |
|
if (result) { |
|
if (handle->detail) { |
|
update_pub_insn(instr->flat_insn, &insn, instr->x86_prefix); |
|
instr->imm_size = insn.immSize; |
|
} else { |
|
// still copy all prefixes |
|
instr->x86_prefix[0] = insn.prefix0; |
|
instr->x86_prefix[1] = insn.prefix1; |
|
instr->x86_prefix[2] = insn.prefix2; |
|
instr->x86_prefix[3] = insn.prefix3; |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
} |
|
|
|
#endif
|
|
|