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.
579 lines
15 KiB
579 lines
15 KiB
10 months ago
|
// Copyright (C) 2004, Matt Conover (mconover@gmail.com)
|
||
|
//
|
||
|
// WARNING:
|
||
|
// I wouldn't recommend changing any flags like OP_*, ITYPE_*, or *_MASK
|
||
|
// aside from those marked as UNUSED. This is because the flags parts of
|
||
|
// the flags are architecture independent and other are left to specific
|
||
|
// architectures to define, so unless you understand the relationships
|
||
|
// between them, I would leave them as is.
|
||
|
|
||
|
#ifndef DISASM_H
|
||
|
#define DISASM_H
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include "misc.h"
|
||
|
|
||
|
typedef signed char S8;
|
||
|
typedef unsigned char U8;
|
||
|
typedef signed short S16;
|
||
|
typedef unsigned short U16;
|
||
|
typedef signed long S32;
|
||
|
typedef unsigned long U32;
|
||
|
typedef LONG64 S64;
|
||
|
typedef ULONG64 U64;
|
||
|
|
||
|
#ifdef SPEEDY
|
||
|
// On Visual Studio 6, making the internal functions inline makes compiling take forever
|
||
|
#define INTERNAL static _inline
|
||
|
#define INLINE _inline
|
||
|
#else
|
||
|
#define INTERNAL static
|
||
|
#define INLINE
|
||
|
#endif
|
||
|
|
||
|
#define VALID_INSTRUCTION(i) ((i) && !((i)->ErrorOccurred))
|
||
|
#define NEXT_INSTRUCTION(i) ((i)->Address + (i)->Length)
|
||
|
#define DISASM_ARCH_TYPE(dis) ((dis)->ArchType)
|
||
|
#define INS_ARCH_TYPE(ins) DISASM_ARCH_TYPE((ins)->Disassembler)
|
||
|
|
||
|
// NOTE: these should be as big set to the maximum of the supported architectures
|
||
|
#define MAX_PREFIX_LENGTH 15
|
||
|
#define MAX_OPERAND_COUNT 3
|
||
|
#define MAX_INSTRUCTION_LENGTH 25
|
||
|
#define MAX_OPCODE_LENGTH 3
|
||
|
#define MAX_OPCODE_DESCRIPTION 256
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
// Code branch
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define MAX_CODE_REFERENCE_COUNT 3
|
||
|
|
||
|
typedef struct _CODE_BRANCH
|
||
|
{
|
||
|
U64 Addresses[MAX_CODE_REFERENCE_COUNT]; // NULL if multiple to addresses
|
||
|
U32 Count;
|
||
|
U8 IsLoop : 1;
|
||
|
U8 IsCall : 1; // branch if false
|
||
|
U8 IsIndirect : 1; // call/jmp [Address]
|
||
|
U8 AddressOffset: 5;
|
||
|
struct _INSTRUCTION_OPERAND *Operand; // the operand containg the address
|
||
|
} CODE_BRANCH;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
// Data references
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define MAX_DATA_REFERENCE_COUNT 3
|
||
|
|
||
|
typedef struct _DATA_REFERENCE
|
||
|
{
|
||
|
U64 Addresses[MAX_DATA_REFERENCE_COUNT]; // NULL if multiple to addresses
|
||
|
U32 Count;
|
||
|
ULONG_PTR DataSize;
|
||
|
struct _INSTRUCTION_OPERAND *Operand; // the operand containg the address
|
||
|
} DATA_REFERENCE;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////
|
||
|
// Instruction
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// Instruction types (bits 0-7)
|
||
|
// Instruction groups (bits 8-26)
|
||
|
//
|
||
|
#define ITYPE_EXEC_OFFSET (1<<8)
|
||
|
#define ITYPE_ARITH_OFFSET (1<<9)
|
||
|
#define ITYPE_LOGIC_OFFSET (1<<10)
|
||
|
#define ITYPE_STACK_OFFSET (1<<11)
|
||
|
#define ITYPE_TESTCOND_OFFSET (1<<12)
|
||
|
#define ITYPE_LOAD_OFFSET (1<<13)
|
||
|
#define ITYPE_ARRAY_OFFSET (1<<14)
|
||
|
#define ITYPE_BIT_OFFSET (1<<15)
|
||
|
#define ITYPE_FLAG_OFFSET (1<<16)
|
||
|
#define ITYPE_FPU_OFFSET (1<<17)
|
||
|
#define ITYPE_TRAPS_OFFSET (1<<18)
|
||
|
#define ITYPE_SYSTEM_OFFSET (1<<19)
|
||
|
#define ITYPE_OTHER_OFFSET (1<<20)
|
||
|
#define ITYPE_UNUSED1_OFFSET (1<<21)
|
||
|
#define ITYPE_UNUSED2_OFFSET (1<<22)
|
||
|
#define ITYPE_UNUSED3_OFFSET (1<<23)
|
||
|
#define ITYPE_UNUSED4_OFFSET (1<<24)
|
||
|
#define ITYPE_UNUSED5_OFFSET (1<<25)
|
||
|
#define ITYPE_UNUSED6_OFFSET (1<<26)
|
||
|
#define ITYPE_EXT_UNUSED1 (1<<27)
|
||
|
#define ITYPE_EXT_UNUSED2 (1<<28)
|
||
|
#define ITYPE_EXT_UNUSED3 (1<<29)
|
||
|
#define ITYPE_EXT_UNUSED4 (1<<30)
|
||
|
#define ITYPE_EXT_UNUSED5 (1<<31)
|
||
|
|
||
|
//
|
||
|
// X86-specific flags (bits 27-31)
|
||
|
//
|
||
|
|
||
|
#define ITYPE_EXT_64 ITYPE_EXT_UNUSED1 // Use index 1 if in 64-bit mode and 0 otherwise
|
||
|
#define ITYPE_EXT_MODRM ITYPE_EXT_UNUSED2 // ModRM byte may extend the opcode
|
||
|
#define ITYPE_EXT_SUFFIX ITYPE_EXT_UNUSED3 // byte after ModRM/SIB/displacement is the third opcode
|
||
|
#define ITYPE_EXT_PREFIX ITYPE_EXT_UNUSED4 // prefix
|
||
|
#define ITYPE_EXT_FPU ITYPE_EXT_UNUSED5 // FPU instructions require special handling
|
||
|
|
||
|
#define ITYPE_3DNOW_OFFSET ITYPE_UNUSED1_OFFSET
|
||
|
#define ITYPE_MMX_OFFSET ITYPE_UNUSED2_OFFSET
|
||
|
#define ITYPE_SSE_OFFSET ITYPE_UNUSED3_OFFSET
|
||
|
#define ITYPE_SSE2_OFFSET ITYPE_UNUSED4_OFFSET
|
||
|
#define ITYPE_SSE3_OFFSET ITYPE_UNUSED5_OFFSET
|
||
|
|
||
|
//
|
||
|
// Instruction types
|
||
|
//
|
||
|
|
||
|
#define ITYPE_TYPE_MASK 0x7FFFFFFF
|
||
|
#define ITYPE_GROUP_MASK 0x7FFFFF00
|
||
|
|
||
|
typedef enum _INSTRUCTION_TYPE
|
||
|
{
|
||
|
// ITYPE_EXEC group
|
||
|
ITYPE_EXEC = ITYPE_EXEC_OFFSET,
|
||
|
ITYPE_BRANCH,
|
||
|
ITYPE_BRANCHCC, // conditional (not necessarily just flags)
|
||
|
ITYPE_CALL,
|
||
|
ITYPE_CALLCC, // conditional (not necessarily just flags)
|
||
|
ITYPE_RET,
|
||
|
ITYPE_LOOPCC,
|
||
|
|
||
|
// ITYPE_ARITH group
|
||
|
ITYPE_ARITH = ITYPE_ARITH_OFFSET,
|
||
|
ITYPE_XCHGADD,
|
||
|
ITYPE_ADD,
|
||
|
ITYPE_SUB,
|
||
|
ITYPE_MUL,
|
||
|
ITYPE_DIV,
|
||
|
ITYPE_INC,
|
||
|
ITYPE_DEC,
|
||
|
ITYPE_SHL,
|
||
|
ITYPE_SHR,
|
||
|
ITYPE_ROL,
|
||
|
ITYPE_ROR,
|
||
|
|
||
|
// ITYPE_LOGIC group
|
||
|
ITYPE_LOGIC=ITYPE_LOGIC_OFFSET,
|
||
|
ITYPE_AND,
|
||
|
ITYPE_OR,
|
||
|
ITYPE_XOR,
|
||
|
ITYPE_NOT,
|
||
|
ITYPE_NEG,
|
||
|
|
||
|
// ITYPE_STACK group
|
||
|
ITYPE_STACK=ITYPE_STACK_OFFSET,
|
||
|
ITYPE_PUSH,
|
||
|
ITYPE_POP,
|
||
|
ITYPE_PUSHA,
|
||
|
ITYPE_POPA,
|
||
|
ITYPE_PUSHF,
|
||
|
ITYPE_POPF,
|
||
|
ITYPE_ENTER,
|
||
|
ITYPE_LEAVE,
|
||
|
|
||
|
// ITYPE_TESTCOND group
|
||
|
ITYPE_TESTCOND=ITYPE_TESTCOND_OFFSET,
|
||
|
ITYPE_TEST,
|
||
|
ITYPE_CMP,
|
||
|
|
||
|
// ITYPE_LOAD group
|
||
|
ITYPE_LOAD=ITYPE_LOAD_OFFSET,
|
||
|
ITYPE_MOV,
|
||
|
ITYPE_MOVCC, // conditional
|
||
|
ITYPE_LEA,
|
||
|
ITYPE_XCHG,
|
||
|
ITYPE_XCHGCC, // conditional
|
||
|
|
||
|
// ITYPE_ARRAY group
|
||
|
ITYPE_ARRAY=ITYPE_ARRAY_OFFSET,
|
||
|
ITYPE_STRCMP,
|
||
|
ITYPE_STRLOAD,
|
||
|
ITYPE_STRMOV,
|
||
|
ITYPE_STRSTOR,
|
||
|
ITYPE_XLAT,
|
||
|
|
||
|
// ITYPE_BIT group
|
||
|
ITYPE_BIT=ITYPE_BIT_OFFSET,
|
||
|
ITYPE_BITTEST,
|
||
|
ITYPE_BITSET,
|
||
|
ITYPE_BITCLR,
|
||
|
|
||
|
// ITYPE_FLAG group
|
||
|
// PF = parify flag
|
||
|
// ZF = zero flag
|
||
|
// OF = overflow flag
|
||
|
// DF = direction flag
|
||
|
// SF = sign flag
|
||
|
ITYPE_FLAG=ITYPE_FLAG_OFFSET,
|
||
|
// clear
|
||
|
ITYPE_CLEARCF,
|
||
|
ITYPE_CLEARZF,
|
||
|
ITYPE_CLEAROF,
|
||
|
ITYPE_CLEARDF,
|
||
|
ITYPE_CLEARSF,
|
||
|
ITYPE_CLEARPF,
|
||
|
// set
|
||
|
ITYPE_SETCF,
|
||
|
ITYPE_SETZF,
|
||
|
ITYPE_SETOF,
|
||
|
ITYPE_SETDF,
|
||
|
ITYPE_SETSF,
|
||
|
ITYPE_SETPF,
|
||
|
// toggle
|
||
|
ITYPE_TOGCF,
|
||
|
ITYPE_TOGZF,
|
||
|
ITYPE_TOGOF,
|
||
|
ITYPE_TOGDF,
|
||
|
ITYPE_TOGSF,
|
||
|
ITYPE_TOGPF,
|
||
|
|
||
|
// ITYPE_FPU group
|
||
|
ITYPE_FPU=ITYPE_FPU_OFFSET,
|
||
|
ITYPE_FADD,
|
||
|
ITYPE_FSUB,
|
||
|
ITYPE_FMUL,
|
||
|
ITYPE_FDIV,
|
||
|
ITYPE_FCOMP,
|
||
|
ITYPE_FEXCH,
|
||
|
ITYPE_FLOAD,
|
||
|
ITYPE_FLOADENV,
|
||
|
ITYPE_FSTORE,
|
||
|
ITYPE_FSTOREENV,
|
||
|
ITYPE_FSAVE,
|
||
|
ITYPE_FRESTORE,
|
||
|
ITYPE_FMOVCC,
|
||
|
|
||
|
ITYPE_UNUSED1=ITYPE_UNUSED1_OFFSET,
|
||
|
ITYPE_UNUSED2=ITYPE_UNUSED2_OFFSET,
|
||
|
ITYPE_UNUSED3=ITYPE_UNUSED3_OFFSET,
|
||
|
|
||
|
// ITYPE_MMX group
|
||
|
ITYPE_MMX=ITYPE_MMX_OFFSET,
|
||
|
ITYPE_MMX_MOV,
|
||
|
ITYPE_MMX_ADD,
|
||
|
ITYPE_MMX_SUB,
|
||
|
ITYPE_MMX_MUL,
|
||
|
ITYPE_MMX_DIV,
|
||
|
ITYPE_MMX_AND,
|
||
|
ITYPE_MMX_OR,
|
||
|
ITYPE_MMX_XOR,
|
||
|
ITYPE_MMX_CMP,
|
||
|
|
||
|
// ITYPE_SSE group
|
||
|
ITYPE_SSE=ITYPE_SSE_OFFSET,
|
||
|
ITYPE_SSE_MOV,
|
||
|
ITYPE_SSE_ADD,
|
||
|
ITYPE_SSE_SUB,
|
||
|
ITYPE_SSE_MUL,
|
||
|
ITYPE_SSE_DIV,
|
||
|
ITYPE_SSE_AND,
|
||
|
ITYPE_SSE_OR,
|
||
|
ITYPE_SSE_XOR,
|
||
|
ITYPE_SSE_CMP,
|
||
|
|
||
|
// ITYPE_SSE2 group
|
||
|
ITYPE_SSE2=ITYPE_SSE2_OFFSET,
|
||
|
ITYPE_SSE2_MOV,
|
||
|
ITYPE_SSE2_ADD,
|
||
|
ITYPE_SSE2_SUB,
|
||
|
ITYPE_SSE2_MUL,
|
||
|
ITYPE_SSE2_DIV,
|
||
|
ITYPE_SSE2_AND,
|
||
|
ITYPE_SSE2_OR,
|
||
|
ITYPE_SSE2_XOR,
|
||
|
ITYPE_SSE2_CMP,
|
||
|
|
||
|
// ITYPE_SSE3 group
|
||
|
ITYPE_SSE3=ITYPE_SSE3_OFFSET,
|
||
|
ITYPE_SSE3_MOV,
|
||
|
ITYPE_SSE3_ADD,
|
||
|
ITYPE_SSE3_SUB,
|
||
|
ITYPE_SSE3_MUL,
|
||
|
ITYPE_SSE3_DIV,
|
||
|
ITYPE_SSE3_AND,
|
||
|
ITYPE_SSE3_OR,
|
||
|
ITYPE_SSE3_XOR,
|
||
|
ITYPE_SSE3_CMP,
|
||
|
|
||
|
// ITYPE_3DNOW group
|
||
|
ITYPE_3DNOW=ITYPE_3DNOW_OFFSET,
|
||
|
ITYPE_3DNOW_ADD,
|
||
|
ITYPE_3DNOW_SUB,
|
||
|
ITYPE_3DNOW_MUL,
|
||
|
ITYPE_3DNOW_DIV,
|
||
|
ITYPE_3DNOW_CMP,
|
||
|
ITYPE_3DNOW_XCHG,
|
||
|
|
||
|
// ITYPE_TRAP
|
||
|
ITYPE_TRAPS=ITYPE_TRAPS_OFFSET,
|
||
|
ITYPE_TRAP, // generate trap
|
||
|
ITYPE_TRAPCC, // conditional trap gen
|
||
|
ITYPE_TRAPRET, // return from trap
|
||
|
ITYPE_BOUNDS, // gen bounds trap
|
||
|
ITYPE_DEBUG, // gen breakpoint trap
|
||
|
ITYPE_TRACE, // gen single step trap
|
||
|
ITYPE_INVALID, // gen invalid instruction
|
||
|
ITYPE_OFLOW, // gen overflow trap
|
||
|
|
||
|
// ITYPE_SYSTEM group
|
||
|
ITYPE_SYSTEM=ITYPE_SYSTEM_OFFSET,
|
||
|
ITYPE_HALT, // halt machine
|
||
|
ITYPE_IN, // input form port
|
||
|
ITYPE_OUT, // output to port
|
||
|
ITYPE_CPUID, // identify cpu
|
||
|
ITYPE_SETIF, // allow interrupts
|
||
|
ITYPE_CLEARIF, // block interrupts
|
||
|
ITYPE_SYSCALL,
|
||
|
ITYPE_SYSCALLRET,
|
||
|
|
||
|
// ITYPE_OTHER group
|
||
|
ITYPE_OTHER = ITYPE_OTHER_OFFSET,
|
||
|
ITYPE_NOP,
|
||
|
ITYPE_BCDCONV, // convert to/from BCD
|
||
|
ITYPE_SZCONV // convert size of operand
|
||
|
} INSTRUCTION_TYPE;
|
||
|
|
||
|
//
|
||
|
// Operand flags
|
||
|
//
|
||
|
|
||
|
// Type = bits 0-6 (these are mutually exclusive -- bits 0-6 will always be a power of 2))
|
||
|
#define OPTYPE_NONE 0x00
|
||
|
#define OPTYPE_IMM 0x01 // immediate value
|
||
|
#define OPTYPE_OFFSET 0x02 // relative offset
|
||
|
#define OPTYPE_FLOAT 0x03 // floating point
|
||
|
#define OPTYPE_BCD 0x04
|
||
|
#define OPTYPE_STRING 0x05
|
||
|
#define OPTYPE_SPECIAL 0x06
|
||
|
#define OPTYPE_MASK 0x7F
|
||
|
|
||
|
// Flags = bits 7-23 (these can be combinations)
|
||
|
// These are used in the X86 opcode table
|
||
|
#define OP_REG (1<<7) // 0x80
|
||
|
#define OP_SIGNED (1<<8)
|
||
|
#define OP_SYS (1<<9) // parameter is an index into some system structure
|
||
|
#define OP_CONDR (1<<10)
|
||
|
#define OP_CONDW (1<<11)
|
||
|
#define OP_UNUSED (1<<12)
|
||
|
#define OP_SRC (1<<13) // operand is source operand
|
||
|
#define OP_DST (1<<14) // operand is destination operand
|
||
|
#define OP_EXEC (1<<15) // operand is executed
|
||
|
|
||
|
#define OP_CONDE OP_CONDR
|
||
|
#define OP_COND_EXEC (OP_CONDE|OP_EXEC) // executed only if the pre-conditions are met
|
||
|
#define OP_COND_SRC (OP_CONDR|OP_SRC) // set only if pre-conditions are met
|
||
|
#define OP_COND_DST (OP_CONDW|OP_DST) // set only if pre-conditions are met
|
||
|
#define OP_COND (OP_CONDR|OP_CONDW)
|
||
|
|
||
|
// Bits 16-31 are available for use outside of the opcode table, but they can only
|
||
|
// be used in INSTRUCTION_OPERAND.Flags, they may conflit with the architecture specific
|
||
|
// operands. For example, bits 16-31 are used in X86 for AMODE_* and OPTYPE_*
|
||
|
#define OP_ADDRESS (1<<16)
|
||
|
#define OP_LOCAL (1<<17)
|
||
|
#define OP_PARAM (1<<18)
|
||
|
#define OP_GLOBAL (1<<19)
|
||
|
#define OP_FAR (1<<20)
|
||
|
#define OP_IPREL (1<<21)
|
||
|
|
||
|
//
|
||
|
// X86-specific flags (bits 27-31)
|
||
|
//
|
||
|
#define OP_MSR (OP_SYS|OP_UNUSED)
|
||
|
|
||
|
//
|
||
|
// Other architecture flags
|
||
|
//
|
||
|
#define OP_DELAY OP_UNUSED // delayed instruction (e.g., delayed branch that executes after the next instruction)
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
// Architectures
|
||
|
/////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
typedef enum _ARCHITECTURE_TYPE
|
||
|
{
|
||
|
ARCH_UNKNOWN=0,
|
||
|
|
||
|
// x86-based
|
||
|
ARCH_X86, // 32-bit x86
|
||
|
ARCH_X86_16, // 16-bit x86
|
||
|
ARCH_X64, // AMD64 and Intel EMD64
|
||
|
|
||
|
// everything else
|
||
|
ARCH_ALPHA,
|
||
|
ARCH_ARM,
|
||
|
ARCH_DOTNET,
|
||
|
ARCH_EFI,
|
||
|
ARCH_IA64,
|
||
|
ARCH_M68K,
|
||
|
ARCH_MIPS,
|
||
|
ARCH_PPC,
|
||
|
ARCH_SH3,
|
||
|
ARCH_SH4,
|
||
|
ARCH_SPARC,
|
||
|
ARCH_THUMB
|
||
|
|
||
|
} ARCHITECTURE_TYPE;
|
||
|
|
||
|
typedef BOOL (*INIT_INSTRUCTION)(struct _INSTRUCTION *Instruction);
|
||
|
typedef void (*DUMP_INSTRUCTION)(struct _INSTRUCTION *Instruction, BOOL ShowBytes, BOOL Verbose);
|
||
|
typedef BOOL (*GET_INSTRUCTION)(struct _INSTRUCTION *Instruction, U8 *Address, U32 Flags);
|
||
|
typedef U8 *(*FIND_FUNCTION_BY_PROLOGUE)(struct _INSTRUCTION *Instruction, U8 *StartAddress, U8 *EndAddress, U32 Flags);
|
||
|
|
||
|
typedef struct _ARCHITECTURE_FORMAT_FUNCTIONS
|
||
|
{
|
||
|
INIT_INSTRUCTION InitInstruction;
|
||
|
DUMP_INSTRUCTION DumpInstruction;
|
||
|
GET_INSTRUCTION GetInstruction;
|
||
|
FIND_FUNCTION_BY_PROLOGUE FindFunctionByPrologue;
|
||
|
} ARCHITECTURE_FORMAT_FUNCTIONS;
|
||
|
|
||
|
typedef struct _ARCHITECTURE_FORMAT
|
||
|
{
|
||
|
ARCHITECTURE_TYPE Type;
|
||
|
ARCHITECTURE_FORMAT_FUNCTIONS *Functions;
|
||
|
} ARCHITECTURE_FORMAT;
|
||
|
|
||
|
#define DISASSEMBLER_INITIALIZED 0x1234566F
|
||
|
#define INSTRUCTION_INITIALIZED 0x1234567F
|
||
|
|
||
|
#include "disasm_x86.h"
|
||
|
|
||
|
typedef struct DECLSPEC_ALIGN(16) _S128
|
||
|
{
|
||
|
U64 Low;
|
||
|
S64 High;
|
||
|
} S128;
|
||
|
typedef struct DECLSPEC_ALIGN(16) _U128
|
||
|
{
|
||
|
U64 Low;
|
||
|
U64 High;
|
||
|
} U128;
|
||
|
|
||
|
typedef struct _INSTRUCTION_OPERAND
|
||
|
{
|
||
|
U32 Flags;
|
||
|
U8 Type : 6;
|
||
|
U8 Unused : 2;
|
||
|
U16 Length;
|
||
|
|
||
|
|
||
|
// If non-NULL, this indicates the target address of the instruction (e.g., a branch or
|
||
|
// a displacement with no base register). However, this address is only reliable if the
|
||
|
// image is mapped correctly (e.g., the executable is mapped as an image and fixups have
|
||
|
// been applied if it is not at its preferred image base).
|
||
|
//
|
||
|
// If disassembling a 16-bit DOS application, TargetAddress is in the context of
|
||
|
// X86Instruction->Segment. For example, if TargetAddress is the address of a code branch,
|
||
|
// it is in the CS segment (unless X86Instruction->HasSegmentOverridePrefix is set). If
|
||
|
// TargetAddress is a data pointer, it is in the DS segment (unless
|
||
|
// X86Instruction->HasSegmentOverridePrefix is set)
|
||
|
U64 TargetAddress;
|
||
|
U32 Register;
|
||
|
|
||
|
union
|
||
|
{
|
||
|
// All 8/16/32-bit operands are extended to 64-bits automatically
|
||
|
// If you want to downcast, check whether Flags & OP_SIGNED is set
|
||
|
// Like this:
|
||
|
// U32 GetOperand32(OPERAND *Operand)
|
||
|
// {
|
||
|
// if (Operand->Flags & OP_SIGNED) return (S32)Operand->Value_S64;
|
||
|
// else return (U32)Operand->Value_U64;
|
||
|
//}
|
||
|
U64 Value_U64;
|
||
|
S64 Value_S64;
|
||
|
U128 Value_U128;
|
||
|
U128 Float128;
|
||
|
U8 Float80[80];
|
||
|
U8 BCD[10];
|
||
|
};
|
||
|
} INSTRUCTION_OPERAND;
|
||
|
|
||
|
typedef struct _INSTRUCTION
|
||
|
{
|
||
|
U32 Initialized;
|
||
|
struct _DISASSEMBLER *Disassembler;
|
||
|
|
||
|
char String[MAX_OPCODE_DESCRIPTION];
|
||
|
U8 StringIndex;
|
||
|
U64 VirtualAddressDelta;
|
||
|
|
||
|
U32 Groups; // ITYPE_EXEC, ITYPE_ARITH, etc. -- NOTE groups can be OR'd together
|
||
|
INSTRUCTION_TYPE Type; // ITYPE_ADD, ITYPE_RET, etc. -- NOTE there is only one possible type
|
||
|
|
||
|
U8 *Address;
|
||
|
U8 *OpcodeAddress;
|
||
|
U32 Length;
|
||
|
|
||
|
U8 Prefixes[MAX_PREFIX_LENGTH];
|
||
|
U32 PrefixCount;
|
||
|
|
||
|
U8 LastOpcode; // last byte of opcode
|
||
|
U8 OpcodeBytes[MAX_OPCODE_LENGTH];
|
||
|
U32 OpcodeLength; // excludes any operands and prefixes
|
||
|
|
||
|
INSTRUCTION_OPERAND Operands[MAX_OPERAND_COUNT];
|
||
|
U32 OperandCount;
|
||
|
|
||
|
X86_INSTRUCTION X86;
|
||
|
|
||
|
DATA_REFERENCE DataSrc;
|
||
|
DATA_REFERENCE DataDst;
|
||
|
CODE_BRANCH CodeBranch;
|
||
|
|
||
|
// Direction depends on which direction the stack grows
|
||
|
// For example, on x86 a push results in StackChange < 0 since the stack grows down
|
||
|
// This is only relevant if (Group & ITYPE_STACK) is true
|
||
|
//
|
||
|
// If Groups & ITYPE_STACK is set but StackChange = 0, it means that the change
|
||
|
// couldn't be determined (non-constant)
|
||
|
LONG StackChange;
|
||
|
|
||
|
// Used to assist in debugging
|
||
|
// If set, the current instruction is doing something that requires special handling
|
||
|
// For example, popf can cause tracing to be disabled
|
||
|
|
||
|
U8 StringAligned : 1; // internal only
|
||
|
U8 NeedsEmulation : 1; // instruction does something that re
|
||
|
U8 Repeat : 1; // instruction repeats until some condition is met (e.g., REP prefix on X86)
|
||
|
U8 ErrorOccurred : 1; // set if instruction is invalid
|
||
|
U8 AnomalyOccurred : 1; // set if instruction is anomalous
|
||
|
U8 LastInstruction : 1; // tells the iterator callback it is the last instruction
|
||
|
U8 CodeBlockFirst: 1;
|
||
|
U8 CodeBlockLast : 1;
|
||
|
} INSTRUCTION;
|
||
|
|
||
|
typedef struct _DISASSEMBLER
|
||
|
{
|
||
|
U32 Initialized;
|
||
|
ARCHITECTURE_TYPE ArchType;
|
||
|
ARCHITECTURE_FORMAT_FUNCTIONS *Functions;
|
||
|
INSTRUCTION Instruction;
|
||
|
U32 Stage1Count; // GetInstruction called
|
||
|
U32 Stage2Count; // Opcode fully decoded
|
||
|
U32 Stage3CountNoDecode; // made it through all checks when DISASM_DECODE is not set
|
||
|
U32 Stage3CountWithDecode; // made it through all checks when DISASM_DECODE is set
|
||
|
} DISASSEMBLER;
|
||
|
|
||
|
#define DISASM_DISASSEMBLE (1<<1)
|
||
|
#define DISASM_DECODE (1<<2)
|
||
|
#define DISASM_SUPPRESSERRORS (1<<3)
|
||
|
#define DISASM_SHOWFLAGS (1<<4)
|
||
|
#define DISASM_ALIGNOUTPUT (1<<5)
|
||
|
#define DISASM_DISASSEMBLE_MASK (DISASM_ALIGNOUTPUT|DISASM_SHOWBYTES|DISASM_DISASSEMBLE)
|
||
|
|
||
|
BOOL InitDisassembler(DISASSEMBLER *Disassembler, ARCHITECTURE_TYPE Architecture);
|
||
|
void CloseDisassembler(DISASSEMBLER *Disassembler);
|
||
|
INSTRUCTION *GetInstruction(DISASSEMBLER *Disassembler, U64 VirtualAddress, U8 *Address, U32 Flags);
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
#endif // DISASM_H
|