dis.h revision 643ac6d84030a2ec7e6d6f536f2b547a8a196858
/** @file
* DIS - The VirtualBox Disassembler.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
#ifndef ___VBox_dis_h
#define ___VBox_dis_h
#include <VBox/disopcode.h>
/**
* CPU mode flags (DISCPUSTATE::mode).
*/
typedef enum DISCPUMODE
{
DISCPUMODE_INVALID = 0,
/** hack forcing the size of the enum to 32-bits. */
DISCPUMODE_MAKE_32BIT_HACK = 0x7fffffff
} DISCPUMODE;
/** @name Prefix byte flags (DISCPUSTATE::prefix_rex).
* @{
*/
/** non-default address size. */
/** non-default operand size. */
/** lock prefix. */
/** segment prefix. */
/** rep(e) prefix (not a prefix, but we'll treat is as one). */
/** rep(e) prefix (not a prefix, but we'll treat is as one). */
/** REX prefix (64 bits) */
/** @} */
/** @name 64 bits prefix byte flags (DISCPUSTATE::prefix_rex).
* Requires VBox/disopcode.h.
* @{
*/
#define DISPREFIX_REX_OP_2_FLAGS(a) (a - OP_PARM_REX_START)
/** @} */
/** @name Operand type.
* @{
*/
#define DISOPTYPE_INVALID RT_BIT_32(0)
#define DISOPTYPE_RRM_DANGEROUS RT_BIT_32(14) /**< Some additional dangerous ones when recompiling raw r0. */
#define DISOPTYPE_RRM_DANGEROUS_16 RT_BIT_32(15) /**< Some additional dangerous ones when recompiling 16-bit raw r0. */
#define DISOPTYPE_FORCED_64_OP_SIZE RT_BIT_32(22) /**< Forced 64 bits operand size; regardless of prefix bytes */
#define DISOPTYPE_REXB_EXTENDS_OPREG RT_BIT_32(23) /**< REX.B extends the register field in the opcode byte */
#define DISOPTYPE_FORCED_32_OP_SIZE_X86 RT_BIT_32(25) /**< Forced 32 bits operand size; regardless of prefix bytes (only in 16 & 32 bits mode!) */
/** @} */
/** @name Parameter usage flags.
* @{
*/
#define DISUSE_BASE RT_BIT_64(0)
/** DS:ESI */
/** ES:EDI */
/** Mask of immediate use flags. */
#define DISUSE_IMMEDIATE ( DISUSE_IMMEDIATE8 \
/** Check if the use flags indicates an effective address. */
& ( DISUSE_BASE \
| DISUSE_INDEX \
| DISUSE_RIPDISPLACEMENT32) ))
/** @} */
/** @name 64-bit general register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_gen and DISOPPARAM::index.reg_gen.
* @note Safe to assume same values as the 16-bit and 32-bit general registers.
* @{
*/
#define DISGREG_RAX UINT8_C(0)
/** @} */
/** @name 32-bit general register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_gen and DISOPPARAM::index.reg_gen.
* @note Safe to assume same values as the 16-bit and 64-bit general registers.
* @{
*/
#define DISGREG_EAX UINT8_C(0)
/** @} */
/** @name 16-bit general register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_gen and DISOPPARAM::index.reg_gen.
* @note Safe to assume same values as the 32-bit and 64-bit general registers.
* @{
*/
#define DISGREG_AX UINT8_C(0)
/** @} */
/** @name 8-bit general register indexes.
* This mostly (?) matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_gen and DISOPPARAM::index.reg_gen.
* @{
*/
#define DISGREG_AL UINT8_C(0)
/** @} */
/** @name Segment registerindexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_seg.
* @{
*/
typedef enum
{
DISSELREG_ES = 0,
DISSELREG_CS = 1,
DISSELREG_SS = 2,
DISSELREG_DS = 3,
DISSELREG_FS = 4,
DISSELREG_GS = 5,
/** The usual 32-bit paranoia. */
DIS_SEGREG_32BIT_HACK = 0x7fffffff
} DISSELREG;
/** @} */
/** @name FPU register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_fp.
* @{
*/
#define DISFPREG_ST0 UINT8_C(0)
/** @} */
/** @name Control register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_ctrl.
* @{
*/
#define DISCREG_CR0 UINT8_C(0)
/** @} */
/** @name Debug register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_dbg.
* @{
*/
#define DISDREG_DR0 UINT8_C(0)
/** @} */
/** @name MMX register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_mmx.
* @{
*/
#define DISMREG_MMX0 UINT8_C(0)
/** @} */
/** @name SSE register indexes.
* This matches the AMD64 register encoding. It is found used in
* DISOPPARAM::base.reg_xmm.
* @{
*/
#define DISXREG_XMM0 UINT8_C(0)
/** @} */
/**
* Operand Parameter.
*/
typedef struct DISOPPARAM
{
/** A combination of DISUSE_XXX. */
union
{
} uDisp;
union
{
/** DISGREG_XXX. */
/** DISFPREG_XXX */
/** DISMREG_XXX. */
/** DISXREG_XXX. */
/** DISSELREG_XXX. */
/** TR0-TR7 (no defines for these). */
/** DISCREG_XXX */
/** DISDREG_XXX */
} base;
union
{
/** DISGREG_XXX. */
} index;
/** 2, 4 or 8. */
/** Parameter size. */
} DISOPPARAM;
/** Pointer to opcode parameter. */
typedef DISOPPARAM *PDISOPPARAM;
/** Pointer to opcode parameter. */
typedef const DISOPPARAM *PCDISOPPARAM;
/**
* Opcode descriptor.
*/
typedef struct DISOPCODE
{
#ifndef DIS_CORE_ONLY
const char *pszOpcode;
#endif
} DISOPCODE;
/** Pointer to const opcode. */
typedef const struct DISOPCODE *PCDISOPCODE;
/**
* Callback for reading opcode bytes.
*
* @param pDisState Pointer to the CPU state. The primary user argument
* can be retrived from DISCPUSTATE::pvUser. If
* more is required these can be passed in the
* subsequent slots.
* @param pbDst Pointer to output buffer.
* @param uSrcAddr The address to start reading at.
* @param cbToRead The number of bytes to read.
*/
typedef DECLCALLBACK(int) FNDISREADBYTES(PDISCPUSTATE pDisState, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead);
/** Pointer to a opcode byte reader. */
typedef FNDISREADBYTES *PFNDISREADBYTES;
/** Parser callback.
* @remark no DECLCALLBACK() here because it's considered to be internal (really, I'm too lazy to update all the functions). */
typedef unsigned FNDISPARSE(RTUINTPTR pu8CodeBlock, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);
/** Pointer to a disassembler parser function. */
typedef FNDISPARSE *PFNDISPARSE;
/** Pointer to a const disassembler parser function pointer. */
typedef PFNDISPARSE const *PCPFNDISPARSE;
/**
* The diassembler state and result.
*/
typedef struct DISCPUSTATE
{
/* Because of pvUser2, put the less frequently used bits at the top for
now. (Might be better off in the middle?) */
/* off: 0x060 (96) */
/** ModRM fields. */
union
{
/** Bitfield view */
struct
{
unsigned Rm : 4;
unsigned Reg : 4;
unsigned Mod : 2;
} Bits;
/** unsigned view */
unsigned u;
} ModRM;
/** SIB fields. */
union
{
/** Bitfield view */
struct
{
unsigned Base : 4;
unsigned Index : 4;
unsigned Scale : 2;
} Bits;
/** unsigned view */
unsigned u;
} SIB;
/* off: 0x06c (108) */
/** The CPU mode (DISCPUMODE). */
/** The addressing mode (DISCPUMODE). */
/** The operand mode (DISCPUMODE). */
/** Per instruction prefix settings. */
/* off: 0x070 (112) */
/** REX prefix value (64 bits only). */
/** Segment prefix value (DISSELREG). */
/** Last prefix byte (for SSE2 extension tables). */
/** First opcode byte of instruction. */
/* off: 0x074 (116) */
/** The size of the prefix bytes. */
/** The instruction size. */
/* off: 0x078 (120) */
/** Return code set by a worker function like the opcode bytes readers. */
/** Internal: instruction filter */
/* off: 0x080 (128) */
/** Internal: pointer to disassembly function table */
#if ARCH_BITS == 32
#endif
/** Pointer to the current instruction. */
#if ARCH_BITS == 32
#endif
/* off: 0x090 (144) */
/** The address of the instruction. */
/* off: 0x098 (152) */
/** Optional read function */
#if ARCH_BITS == 32
#endif
/* off: 0x0a0 (160) */
/** The instruction bytes. */
/* off: 0x0b0 (176) */
/** User data supplied as an argument to the APIs. */
void *pvUser;
#if ARCH_BITS == 32
#endif
/** User data that can be set prior to calling the API.
* @deprecated Please don't use this any more. */
void *pvUser2;
#if ARCH_BITS == 32
#endif
} DISCPUSTATE;
DISDECL(int) DISInstrToStrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
DISDECL(int) DISInstr(void const *pvInstr, DISCPUMODE enmCpuMode, PDISCPUSTATE pCpu, uint32_t *pcbInstr);
DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
/** @name Flags returned by DISQueryParamVal (DISQPVPARAMVAL::flags).
* @{
*/
/** @} */
/** @name Types returned by DISQueryParamVal (DISQPVPARAMVAL::flags).
* @{ */
/** @} */
typedef struct
{
union
{
struct
{
} farptr;
} val;
/** Pointer to opcode parameter value. */
typedef DISQPVPARAMVAL *PDISQPVPARAMVAL;
/** Indicates which parameter DISQueryParamVal should operate on. */
typedef enum DISQPVWHICH
{
DISQPVWHICH_DST = 1,
DISQPVWHAT_32_BIT_HACK = 0x7fffffff
} DISQPVWHICH;
DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PDISCPUSTATE pCpu, PDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype);
DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PDISCPUSTATE pCpu, PDISOPPARAM pParam, void **ppReg, size_t *pcbSize);
DISDECL(int) DISFetchRegSegEx(PCCPUMCTXCORE pCtx, DISSELREG sel, RTSEL *pVal, PCPUMSELREGHID *ppSelHidReg);
/**
* Try resolve an address into a symbol name.
*
* For use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx().
*
* @returns VBox status code.
* @retval VINF_SUCCESS on success, pszBuf contains the full symbol name.
* @retval VINF_BUFFER_OVERFLOW if pszBuf is too small the symbol name. The
* content of pszBuf is truncated and zero terminated.
* @retval VERR_SYMBOL_NOT_FOUND if no matching symbol was found for the address.
*
* @param pCpu Pointer to the disassembler CPU state.
* @param u32Sel The selector value. Use DIS_FMT_SEL_IS_REG, DIS_FMT_SEL_GET_VALUE,
* DIS_FMT_SEL_GET_REG to access this.
* @param uAddress The segment address.
* @param pszBuf Where to store the symbol name
* @param cchBuf The size of the buffer.
* @param poff If not a perfect match, then this is where the offset from the return
* symbol to the specified address is returned.
* @param pvUser The user argument.
*/
typedef DECLCALLBACK(int) FNDISGETSYMBOL(PCDISCPUSTATE pCpu, uint32_t u32Sel, RTUINTPTR uAddress, char *pszBuf, size_t cchBuf, RTINTPTR *poff, void *pvUser);
/** Pointer to a FNDISGETSYMBOL(). */
typedef FNDISGETSYMBOL *PFNDISGETSYMBOL;
/**
* Checks if the FNDISGETSYMBOL argument u32Sel is a register or not.
*/
/**
* Extracts the selector value from the FNDISGETSYMBOL argument u32Sel.
* @returns Selector value.
*/
/**
* Extracts the register number from the FNDISGETSYMBOL argument u32Sel.
* @returns USE_REG_CS, USE_REG_SS, USE_REG_DS, USE_REG_ES, USE_REG_FS or USE_REG_FS.
*/
/** @internal */
/** @internal */
/** @name Flags for use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx().
* @{
*/
/** Put the address to the right. */
#define DIS_FMT_FLAGS_ADDR_RIGHT RT_BIT_32(0)
/** Put the address to the left. */
/** Put the address in comments.
* For some assemblers this implies placing it to the right. */
/** Put the instruction bytes to the right of the disassembly. */
/** Put the instruction bytes to the left of the disassembly. */
/** Put the instruction bytes in comments.
* For some assemblers this implies placing the bytes to the right. */
/** Put the bytes in square brackets. */
/** Put spaces between the bytes. */
/** Display the relative +/- offset of branch instructions that uses relative addresses,
* and put the target address in parenthesis. */
/** Strict assembly. The assembly should, when ever possible, make the
* assembler reproduce the exact same binary. (Refers to the yasm
* strict keyword.) */
/** Checks if the given flags are a valid combination. */
#define DIS_FMT_FLAGS_IS_VALID(fFlags) \
&& ((fFlags) & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) != (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT) \
&& ( !((fFlags) & DIS_FMT_FLAGS_ADDR_COMMENT) \
&& ((fFlags) & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) != (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT) \
)
/** @} */
DISDECL(size_t) DISFormatYasmEx(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser);
DISDECL(size_t) DISFormatMasmEx(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser);
DISDECL(size_t) DISFormatGasEx( PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser);
/** @todo DISAnnotate(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, register reader, memory reader); */
#endif