diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 19:50:13 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2024-03-05 20:34:34 -0500 |
| commit | e093c21ed880ac3eb72119be15093ee04f8ce299 (patch) | |
| tree | 9f720ebdc0ae415734b1199ed341668c69710a94 /arch/armv7/thumb2_disasm/disassembler.h | |
| parent | 0609276712622908254065546102381466033141 (diff) | |
Move architecture modules into the API repo
Diffstat (limited to 'arch/armv7/thumb2_disasm/disassembler.h')
| -rw-r--r-- | arch/armv7/thumb2_disasm/disassembler.h | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/arch/armv7/thumb2_disasm/disassembler.h b/arch/armv7/thumb2_disasm/disassembler.h new file mode 100644 index 00000000..2348ea93 --- /dev/null +++ b/arch/armv7/thumb2_disasm/disassembler.h @@ -0,0 +1,299 @@ +#pragma once + +#include "armv7.h" + +//***************************************************************************** +// defines, values +//***************************************************************************** + +/* architectures */ +#define ARCH_ARMv4T 0 +#define ARCH_ARMv5T 1 +#define ARCH_ARMv6 2 +#define ARCH_ARMv7 4 +#define ARCH_ARMv7_R 8 +#define ARCH_ARMv6T2 16 +#define ARCH_ThumbEE 32 +#define ARCH_SECURITY_EXTENSIONS 0x40 +#define ARCH_ARMv7_WITH_MP 0x80 /* eg: PLDW */ +#define ARCH_ADVSIMD 0x100 /* vst, vld, etc. */ +#define ARCH_VFPv2 0x200 +#define ARCH_VFPv3 0x400 + +/* decompose statuses */ +#define STATUS_OK 0 +#define STATUS_NO_BIT_MATCH 1 /* travelled along the graph and hit a + contradiction */ +#define STATUS_ARCH_UNSUPPORTED 2 /* an encoding match was found, but is not + supported on the requested architecture */ +#define STATUS_UNDEFINED 4 /* */ +#define STATUS_BUFFER_TOO_SMALL 8 + +/* instruction flags */ +#define FLAG_NONE 0 +#define FLAG_UNPREDICTABLE 1 +#define FLAG_NOTPERMITTED 2 /* eg: instruction decodes ok, but not allowed in if-then block */ +#define FLAG_ADDRMODE_AMBIGUITY 3 + +enum SRType { SRType_ERROR=-1, SRType_LSL=0, SRType_LSR, SRType_ASR, SRType_ROR, SRType_RRX }; +enum COND { COND_EQ=0, COND_NE, COND_CS, COND_CC, COND_MI, COND_PL, COND_VS, + COND_VC, COND_HI, COND_LS, COND_GE, COND_LT, COND_GT, COND_LE, COND_AL }; + +/* is in "if then" block? */ +#define IFTHEN_UNKNOWN 0 +#define IFTHEN_YES 1 +#define IFTHEN_NO 2 +#define IFTHENLAST_UNKNOWN 0 +#define IFTHENLAST_YES 1 +#define IFTHENLAST_NO 2 + +/* instruction sets */ +#define INSTRSET_THUMB 0 /* 16-bit thumb instructions only (introduced in ARMv4T) */ +#define INSTRSET_THUMB2 1 /* 16-bit and 32-bit instructions (introduced in ARMv6T2) */ +#define INSTRSET_THUMBEE 2 /* defined in ARMv7 */ + +/* addressing modes */ +/* these index the instruction format strings */ +#define ADDRMODE_OFFSET 0 /* eaddr = base reg + offset, base reg unchanged, like [<Rn>,<offset>] */ +#define ADDRMODE_PREINDEX 1 /* eaddr = base reg + offset, base reg CHANGED, like [<Rn>,<offset>]! */ +#define ADDRMODE_POSTINDEX 2 /* eaddr = base reg, base reg CHANGED, like [<Rn>], <offset> */ +#define ADDRMODE_UNINDEXED 3 /* eaddr = base reg */ +#define ADDRMODE_ADVSIMD_0 0 +#define ADDRMODE_ADVSIMD_1 1 +#define ADDRMODE_ADVSIMD_2 2 +#define ADDRMODE_UNSPECIFIED 255 + +#define IS_FIELD_PRESENT(s, elem) (!!((s)->fields_mask[(elem) >> 6] & (1LL << ((elem) & 63)))) + +#define MAX_FORMAT_OPERANDS 8 + +/* these append some specifier text on the opcode */ +#define INSTR_FORMAT_FLAG_CONDITIONAL 1 +#define INSTR_FORMAT_FLAG_OPTIONAL_STATUS 2 +#define INSTR_FORMAT_FLAG_EFFECT 4 +#define INSTR_FORMAT_FLAG_MASK 8 +#define INSTR_FORMAT_FLAG_WIDE 0x10 +#define INSTR_FORMAT_FLAG_INCREMENT_AFTER 0x20 +#define INSTR_FORMAT_FLAG_AMODE 0x40 +#define INSTR_FORMAT_FLAG_NEON_SIZE 0x80 +#define INSTR_FORMAT_FLAG_VFP_DATA_SIZE 0x100 +#define INSTR_FORMAT_FLAG_NEON_TYPE_SIZE 0x200 +#define INSTR_FORMAT_FLAG_NEON_SINGLE_SIZE 0x400 +#define INSTR_FORMAT_FLAG_F16 0x800 +#define INSTR_FORMAT_FLAG_F32 0x1000 +#define INSTR_FORMAT_FLAG_F64 0x2000 + +#define VFP_DATA_SIZE_S8 0 +#define VFP_DATA_SIZE_S16 1 +#define VFP_DATA_SIZE_S32 2 +#define VFP_DATA_SIZE_S64 3 + +#define VFP_DATA_SIZE_F32 3 +#define VFP_DATA_SIZE_F64 4 + +#define VFP_DATA_SIZE_U8 4 +#define VFP_DATA_SIZE_U16 5 +#define VFP_DATA_SIZE_U32 6 +#define VFP_DATA_SIZE_U64 7 + +#define VFP_DATA_SIZE_I8 0 +#define VFP_DATA_SIZE_I16 1 +#define VFP_DATA_SIZE_I32 2 +#define VFP_DATA_SIZE_I64 3 +#define VFP_DATA_SIZE_I_F32 4 + +#define VFP_DATA_SIZE_F32S32 0 +#define VFP_DATA_SIZE_F32U32 1 +#define VFP_DATA_SIZE_S32F32 2 +#define VFP_DATA_SIZE_U32F32 3 + +#define VFP_DATA_SIZE_32 8 + +//***************************************************************************** +// structs and types +//***************************************************************************** + +enum instruction_operand_format_type +{ + OPERAND_FORMAT_END, + OPERAND_FORMAT_MEMORY_ONE_REG, + OPERAND_FORMAT_MEMORY_ONE_REG_IMM, + OPERAND_FORMAT_MEMORY_ONE_REG_NEG_IMM, + OPERAND_FORMAT_MEMORY_ONE_REG_ADD_IMM, + OPERAND_FORMAT_MEMORY_ONE_REG_OPTIONAL_IMM, + OPERAND_FORMAT_MEMORY_ONE_REG_OPTIONAL_ADD_IMM, + OPERAND_FORMAT_MEMORY_ONE_REG_ALIGNED, + OPERAND_FORMAT_MEMORY_TWO_REG, + OPERAND_FORMAT_MEMORY_TWO_REG_SHIFT, + OPERAND_FORMAT_MEMORY_TWO_REG_LSL_ONE, + OPERAND_FORMAT_MEMORY_SP_IMM, + OPERAND_FORMAT_MEMORY_SP_OPTIONAL_IMM, + OPERAND_FORMAT_MEMORY_PC, + OPERAND_FORMAT_FPSCR, + OPERAND_FORMAT_IMM, + OPERAND_FORMAT_IMM64, + OPERAND_FORMAT_OPTIONAL_IMM, + OPERAND_FORMAT_ADD_IMM, + OPERAND_FORMAT_OPTIONAL_ADD_IMM, + OPERAND_FORMAT_ZERO, + OPERAND_FORMAT_REG, + OPERAND_FORMAT_REG_FP, /* s0..s32, d0..d31, q0..q15 */ + OPERAND_FORMAT_REG_INDEX, + OPERAND_FORMAT_SP, + OPERAND_FORMAT_PC, + OPERAND_FORMAT_LR, + OPERAND_FORMAT_COPROC, + OPERAND_FORMAT_COPROC_REG, + OPERAND_FORMAT_SINGLE_REGISTERS, + OPERAND_FORMAT_REGISTERS, + OPERAND_FORMAT_REGISTERS_INDEXED, + OPERAND_FORMAT_LIST, + OPERAND_FORMAT_ENDIAN, + OPERAND_FORMAT_SHIFT, + OPERAND_FORMAT_IFLAGS, + OPERAND_FORMAT_FIRSTCOND, + OPERAND_FORMAT_LABEL, + OPERAND_FORMAT_SPEC_REG, + OPERAND_FORMAT_NEON_SIZE, + OPERAND_FORMAT_BARRIER_OPTION, + OPERAND_FORMAT_RT_MRC, + OPERAND_FORMAT_ROTATION +}; + +enum instruction_operand_writeback +{ + WRITEBACK_NO, + WRITEBACK_YES, + WRITEBACK_OPTIONAL +}; + +/* "inspired" from capstone */ +enum instruction_group +{ + INSN_GROUP_UNKNOWN = 0, /* so memset() will initialize to this default */ + INSN_GROUP_JUMP, + INSN_GROUP_CRYPTO, + INSN_GROUP_DATABARRIER, + INSN_GROUP_DIVIDE, + INSN_GROUP_FPARMV8, + INSN_GROUP_MULTPRO, + INSN_GROUP_NEON, + INSN_GROUP_T2EXTRACTPACK, + INSN_GROUP_THUMB2DSP, + INSN_GROUP_TRUSTZONE, + INSN_GROUP_V4T, + INSN_GROUP_V5T, + INSN_GROUP_V5TE, + INSN_GROUP_V6, + INSN_GROUP_V6T2, + INSN_GROUP_V7, + INSN_GROUP_V8, + INSN_GROUP_VFP2, + INSN_GROUP_VFP3, + INSN_GROUP_VFP4, + INSN_GROUP_ARM, + INSN_GROUP_MCLASS, + INSN_GROUP_NOTMCLASS, + INSN_GROUP_THUMB, + INSN_GROUP_THUMB1ONLY, + INSN_GROUP_THUMB2, + INSN_GROUP_PREV8, + INSN_GROUP_FPVMLX, + INSN_GROUP_MULOPS, + INSN_GROUP_CRC, + INSN_GROUP_DPVFP, + INSN_GROUP_V6M, +}; + +/* the decomp->text function GetInstructionText will process these and in + general emit: + + 1) TEXT token for prefix (if it exists) + 2) ???? token(s) (depending on type) + 3) TEXT token for suffix (if it exists) +*/ +struct instruction_operand_format +{ + /* what type of operand format is this? + eg: OPERAND_FORMAT_REG, OPERAND_FORMAT_REGISTERS, etc. */ + instruction_operand_format_type type; + + /* each operand can refer to up to 2 fields */ + enum decomp_field field0, field1; + + /* text that's prepended and appended, eg "#" or "{","}" */ + const char *prefix, *suffix; + + /* where or not there's writeback (usually indicated by '!' in format) */ + instruction_operand_writeback writeback; +}; + +struct instruction_format +{ + const char* operation; + uint32_t operationFlags; + instruction_operand_format operands[MAX_FORMAT_OPERANDS]; + size_t operandCount; +}; + +struct decomp_request +{ + uint16_t instr_word16; + uint32_t instr_word32; + + /* architecture, like ARCH_ARMv4T */ + uint8_t arch; + /* instruction set */ + uint8_t instrSet; + + /* in if-then block? is last? */ + uint8_t inIfThen; + uint8_t inIfThenLast; + + /* disassembly of some instructions affected by APSR.C */ + uint8_t carry_in; + + uint32_t addr; +}; + +struct decomp_result +{ + /* the result of the decomposition eg: STATUS_OK */ + uint8_t status; + + /* extra flags to decorate instruction eg: FLAG_UNPREDICTABLE */ + uint32_t flags; + + /* addressing mode of mem access instructions */ + uint8_t addrMode; + + /* instruction group */ + uint8_t group; + + /* instruction size in bits: 16 or 32 */ + uint8_t instrSize; + + /* values of the fields */ + uint32_t fields[FIELD_MAX]; + /* bit set if field present */ + uint64_t fields_mask[(FIELD_MAX + 63) / 64]; + + const instruction_format* formats; + size_t formatCount; + + const instruction_format* format; + armv7::Operation mnem; + + uint32_t pc; +}; + +//***************************************************************************** +// function prototypes +//***************************************************************************** + +extern int thumb_decompose(struct decomp_request *, struct decomp_result *result); +extern const char* get_thumb_condition_name(uint32_t cond); +extern bool thumb_has_writeback(struct decomp_result* result); +extern std::string get_thumb_operation_name(struct decomp_result* result); +extern int get_reg_name(int reg_idx, char *reg_name); + |
