mirror of
https://github.com/capstone-engine/capstone.git
synced 2025-02-02 20:11:57 +00:00
Handle system operands in way more detail.
- Differentiates between banked and non-banked registers. - Saves the MSR mask. - PSR field bits are saved separately. - SYSm value is saved if possible.
This commit is contained in:
parent
2aa4eb559d
commit
34a239b3e6
@ -1083,7 +1083,6 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
MCOperand *Op = MCInst_getOperand(MI, OpNum);
|
||||
unsigned SpecRegRBit = (unsigned)MCOperand_getImm(Op) >> 4;
|
||||
unsigned Mask = (unsigned)MCOperand_getImm(Op) & 0xf;
|
||||
unsigned reg;
|
||||
bool IsOutReg = OpNum == 0;
|
||||
|
||||
if (ARM_getFeatureBits(MI->csh->mode, ARM_FeatureMClass)) {
|
||||
@ -1099,9 +1098,10 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
SYSm);
|
||||
if (TheReg && MClassSysReg_isInRequiredFeatures(
|
||||
TheReg, ARM_FeatureDSP)) {
|
||||
ARM_set_detail_op_sysreg(
|
||||
ARM_set_detail_op_sysop(
|
||||
MI, TheReg->sysreg.mclasssysreg,
|
||||
IsOutReg);
|
||||
ARM_OP_SYSREG, IsOutReg, Mask,
|
||||
SYSm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1113,9 +1113,10 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
ARMSysReg_lookupMClassSysRegAPSRNonDeprecated(
|
||||
SYSm);
|
||||
if (TheReg) {
|
||||
ARM_set_detail_op_sysreg(
|
||||
ARM_set_detail_op_sysop(
|
||||
MI, TheReg->sysreg.mclasssysreg,
|
||||
IsOutReg);
|
||||
ARM_OP_SYSREG, IsOutReg, Mask,
|
||||
SYSm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1123,14 +1124,14 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
TheReg = ARMSysReg_lookupMClassSysRegBy8bitSYSmValue(
|
||||
SYSm);
|
||||
if (TheReg) {
|
||||
ARM_set_detail_op_sysreg(
|
||||
ARM_set_detail_op_sysop(
|
||||
MI, TheReg->sysreg.mclasssysreg,
|
||||
IsOutReg);
|
||||
ARM_OP_SYSREG, IsOutReg, Mask, SYSm);
|
||||
return;
|
||||
}
|
||||
|
||||
if (MI->csh->detail)
|
||||
MCOperand_CreateImm0(MI, SYSm);
|
||||
ARM_set_detail_op_sysop(MI, SYSm, ARM_OP_SYSREG,
|
||||
IsOutReg, Mask, SYSm);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1140,34 +1141,45 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
default:
|
||||
assert(0 && "Unexpected mask value!");
|
||||
case 4:
|
||||
ARM_set_detail_op_sysreg(
|
||||
MI, ARM_MCLASSSYSREG_APSR_G, IsOutReg);
|
||||
ARM_set_detail_op_sysop(MI,
|
||||
ARM_MCLASSSYSREG_APSR,
|
||||
ARM_OP_SYSREG, IsOutReg,
|
||||
Mask, UINT16_MAX);
|
||||
return;
|
||||
case 8:
|
||||
ARM_set_detail_op_sysreg(
|
||||
ARM_set_detail_op_sysop(
|
||||
MI, ARM_MCLASSSYSREG_APSR_NZCVQ,
|
||||
IsOutReg);
|
||||
ARM_OP_SYSREG, IsOutReg, Mask,
|
||||
UINT16_MAX);
|
||||
return;
|
||||
case 12:
|
||||
ARM_set_detail_op_sysreg(
|
||||
ARM_set_detail_op_sysop(
|
||||
MI, ARM_MCLASSSYSREG_APSR_NZCVQG,
|
||||
IsOutReg);
|
||||
ARM_OP_SYSREG, IsOutReg, Mask,
|
||||
UINT16_MAX);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reg = 0;
|
||||
unsigned field = 0;
|
||||
if (Mask) {
|
||||
if (Mask & 8)
|
||||
reg += ARM_SYSREG_SPSR_F;
|
||||
field += SpecRegRBit ? ARM_FIELD_SPSR_F :
|
||||
ARM_FIELD_CPSR_F;
|
||||
if (Mask & 4)
|
||||
reg += ARM_SYSREG_SPSR_S;
|
||||
field += SpecRegRBit ? ARM_FIELD_SPSR_S :
|
||||
ARM_FIELD_CPSR_S;
|
||||
if (Mask & 2)
|
||||
reg += ARM_SYSREG_SPSR_X;
|
||||
field += SpecRegRBit ? ARM_FIELD_SPSR_X :
|
||||
ARM_FIELD_CPSR_X;
|
||||
if (Mask & 1)
|
||||
reg += ARM_SYSREG_SPSR_C;
|
||||
field += SpecRegRBit ? ARM_FIELD_SPSR_C :
|
||||
ARM_FIELD_CPSR_C;
|
||||
|
||||
ARM_set_detail_op_sysreg(MI, reg, IsOutReg);
|
||||
ARM_set_detail_op_sysop(MI, field,
|
||||
SpecRegRBit ? ARM_OP_SPSR :
|
||||
ARM_OP_CPSR,
|
||||
IsOutReg, Mask, UINT16_MAX);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1531,8 +1543,9 @@ static void add_cs_detail_general(MCInst *MI, arm_op_group op_group,
|
||||
const ARMBankedReg_BankedReg *TheReg =
|
||||
ARMBankedReg_lookupBankedRegByEncoding(Banked);
|
||||
bool IsOutReg = OpNum == 0;
|
||||
ARM_set_detail_op_sysreg(MI, TheReg->sysreg.bankedreg,
|
||||
IsOutReg);
|
||||
ARM_set_detail_op_sysop(MI, TheReg->sysreg.bankedreg,
|
||||
ARM_OP_BANKEDREG, IsOutReg, UINT8_MAX,
|
||||
Banked);
|
||||
break;
|
||||
}
|
||||
case ARM_OP_GROUP_SetendOperand: {
|
||||
@ -1951,12 +1964,30 @@ void ARM_set_detail_op_neon_lane(MCInst *MI, unsigned OpNum)
|
||||
}
|
||||
|
||||
/// Adds a System Register and increments op_count by one.
|
||||
void ARM_set_detail_op_sysreg(MCInst *MI, int SysReg, bool IsOutReg)
|
||||
/// @type ARM_OP_SYSREG, ARM_OP_BANKEDREG, ARM_OP_SYSM...
|
||||
/// @p Mask is the MSR mask or UINT8_MAX if not set.
|
||||
void ARM_set_detail_op_sysop(MCInst *MI, int Val, arm_op_type type,
|
||||
bool IsOutReg, uint8_t Mask, uint16_t Sysm)
|
||||
{
|
||||
if (!detail_is_set(MI))
|
||||
return;
|
||||
ARM_get_detail_op(MI, 0)->type = ARM_OP_SYSREG;
|
||||
ARM_get_detail_op(MI, 0)->reg = SysReg;
|
||||
ARM_get_detail_op(MI, 0)->type = type;
|
||||
switch (type) {
|
||||
default:
|
||||
assert(0 && "Unkown system operand type.");
|
||||
case ARM_OP_SYSREG:
|
||||
ARM_get_detail_op(MI, 0)->sysop.reg.mclasssysreg = Val;
|
||||
break;
|
||||
case ARM_OP_BANKEDREG:
|
||||
ARM_get_detail_op(MI, 0)->sysop.reg.bankedreg = Val;
|
||||
break;
|
||||
case ARM_OP_SPSR:
|
||||
case ARM_OP_CPSR:
|
||||
ARM_get_detail_op(MI, 0)->sysop.psr_bits = Val;
|
||||
break;
|
||||
}
|
||||
ARM_get_detail_op(MI, 0)->sysop.sysm = Sysm;
|
||||
ARM_get_detail_op(MI, 0)->sysop.msr_mask = Mask;
|
||||
ARM_get_detail_op(MI, 0)->access = IsOutReg ? CS_AC_WRITE : CS_AC_READ;
|
||||
ARM_inc_op_count(MI);
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ void ARM_insert_detail_op_reg_at(MCInst *MI, unsigned index, arm_reg Reg,
|
||||
void ARM_insert_detail_op_imm_at(MCInst *MI, unsigned index, int64_t Val,
|
||||
cs_ac_type access);
|
||||
void ARM_set_detail_op_reg(MCInst *MI, unsigned OpNum, arm_reg Reg);
|
||||
void ARM_set_detail_op_sysreg(MCInst *MI, int SysReg, bool IsOutReg);
|
||||
void ARM_set_detail_op_sysop(MCInst *MI, int SysReg, arm_op_type type,
|
||||
bool IsOutReg, uint8_t Mask, uint16_t Sysm);
|
||||
void ARM_set_detail_op_imm(MCInst *MI, unsigned OpNum, arm_op_type ImmType,
|
||||
int64_t Imm);
|
||||
void ARM_set_detail_op_float(MCInst *MI, unsigned OpNum, uint64_t Imm);
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "capstone/arm.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -70,9 +71,37 @@ void print_insn_detail_arm(csh handle, cs_insn *ins)
|
||||
case ARM_OP_SETEND:
|
||||
printf("\t\toperands[%u].type: SETEND = %s\n", i, op->setend == ARM_SETEND_BE? "be" : "le");
|
||||
break;
|
||||
case ARM_OP_SYSREG:
|
||||
printf("\t\toperands[%u].type: SYSREG = %s\n", i, cs_reg_name(handle, op->reg));
|
||||
case ARM_OP_SYSM:
|
||||
printf("\t\toperands[%u].type: SYSM = 0x%" PRIx16 "\n", i, op->sysop.sysm);
|
||||
printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask);
|
||||
break;
|
||||
case ARM_OP_SYSREG:
|
||||
printf("\t\toperands[%u].type: SYSREG = %s\n", i, cs_reg_name(handle, (uint32_t) op->sysop.reg.mclasssysreg));
|
||||
printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask);
|
||||
break;
|
||||
case ARM_OP_BANKEDREG:
|
||||
// FIXME: Printing the name is currenliy not supported if the encodings overlap
|
||||
// with system registers.
|
||||
printf("\t\toperands[%u].type: BANKEDREG = %" PRIu32 "\n", i, (uint32_t) op->sysop.reg.bankedreg);
|
||||
if (op->sysop.msr_mask != UINT8_MAX)
|
||||
printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask);
|
||||
case ARM_OP_SPSR:
|
||||
case ARM_OP_CPSR: {
|
||||
const char type = op->type == ARM_OP_SPSR ? 'S' : 'C';
|
||||
printf("\t\toperands[%u].type: %cPSR = ", i, type);
|
||||
uint16_t field = op->sysop.psr_bits;
|
||||
if ((field & ARM_FIELD_SPSR_F) || (field & ARM_FIELD_CPSR_F))
|
||||
printf("f");
|
||||
if ((field & ARM_FIELD_SPSR_S) || (field & ARM_FIELD_CPSR_S))
|
||||
printf("s");
|
||||
if ((field & ARM_FIELD_SPSR_X) || (field & ARM_FIELD_CPSR_X))
|
||||
printf("x");
|
||||
if ((field & ARM_FIELD_SPSR_C) || (field & ARM_FIELD_CPSR_C))
|
||||
printf("c");
|
||||
printf("\n");
|
||||
printf("\t\toperands[%u].type: MASK = %" PRIu8 "\n", i, op->sysop.msr_mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (op->neon_lane != -1) {
|
||||
|
@ -284,22 +284,22 @@ typedef enum MemBOpt {
|
||||
} arm_mem_bo_opt;
|
||||
|
||||
typedef enum {
|
||||
/// Special registers for MSR
|
||||
ARM_SYSREG_INVALID = 0,
|
||||
// SPSR* field flags can be OR combined
|
||||
ARM_FIELD_SPSR_C = 1,
|
||||
ARM_FIELD_SPSR_X = 2,
|
||||
ARM_FIELD_SPSR_S = 4,
|
||||
ARM_FIELD_SPSR_F = 8,
|
||||
|
||||
// SPSR* registers can be OR combined
|
||||
ARM_SYSREG_SPSR_C = 1,
|
||||
ARM_SYSREG_SPSR_X = 2,
|
||||
ARM_SYSREG_SPSR_S = 4,
|
||||
ARM_SYSREG_SPSR_F = 8,
|
||||
|
||||
// CPSR* registers can be OR combined
|
||||
ARM_SYSREG_CPSR_C = 16,
|
||||
ARM_SYSREG_CPSR_X = 32,
|
||||
ARM_SYSREG_CPSR_S = 64,
|
||||
ARM_SYSREG_CPSR_F = 128,
|
||||
} arm_sysreg_bits;
|
||||
// CPSR* field flags can be OR combined
|
||||
ARM_FIELD_CPSR_C = 16,
|
||||
ARM_FIELD_CPSR_X = 32,
|
||||
ARM_FIELD_CPSR_S = 64,
|
||||
ARM_FIELD_CPSR_F = 128,
|
||||
} arm_spsr_cspr_bits;
|
||||
|
||||
// From LLVM docs:
|
||||
// The values here come from B9.2.3 of the ARM ARM, where bits 4-0 are SysM field
|
||||
// and bit 5 is R.
|
||||
typedef enum {
|
||||
// generated content <ARMGenCSSystemOperandsEnum.inc:GET_ENUM_VALUES_BankedReg> begin
|
||||
// clang-format off
|
||||
@ -420,8 +420,12 @@ typedef enum arm_op_type {
|
||||
ARM_OP_PIMM = CS_OP_SPECIAL + 1, ///< P-Immediate (coprocessor registers)
|
||||
ARM_OP_SETEND = CS_OP_SPECIAL + 2, ///< operand for SETEND instruction
|
||||
ARM_OP_SYSREG = CS_OP_SPECIAL + 3, ///< MSR/MRS special register operand
|
||||
ARM_OP_VPRED_R = CS_OP_SPECIAL + 4, ///< Vector predicate. Leaves inactive lanes of output vector register unchanged.
|
||||
ARM_OP_VPRED_N = CS_OP_SPECIAL + 5, ///< Vector predicate. Don't preserved inactive lanes of output register.
|
||||
ARM_OP_BANKEDREG = CS_OP_SPECIAL + 4, ///< Banked register operand
|
||||
ARM_OP_SPSR = CS_OP_SPECIAL + 5, ///< Collection of SPSR bits
|
||||
ARM_OP_CPSR = CS_OP_SPECIAL + 6, ///< Collection of CPSR bits
|
||||
ARM_OP_SYSM = CS_OP_SPECIAL + 7, ///< Raw SYSm field
|
||||
ARM_OP_VPRED_R = CS_OP_SPECIAL + 8, ///< Vector predicate. Leaves inactive lanes of output vector register unchanged.
|
||||
ARM_OP_VPRED_N = CS_OP_SPECIAL + 9, ///< Vector predicate. Don't preserved inactive lanes of output register.
|
||||
ARM_OP_MEM = CS_OP_MEM, ///< Memory operand
|
||||
} arm_op_type;
|
||||
|
||||
@ -837,6 +841,13 @@ typedef struct arm_op_mem {
|
||||
int lshift;
|
||||
} arm_op_mem;
|
||||
|
||||
typedef struct {
|
||||
arm_sysop_reg reg; ///< The system or banked register.
|
||||
arm_spsr_cspr_bits psr_bits; ///< SPSR/CPSR bits.
|
||||
uint16_t sysm; ///< Raw SYSm field. UINT16_MAX if unset.
|
||||
uint8_t msr_mask; ///< Mask of MSR instructions. UINT8_MAX if invalid.
|
||||
} arm_sysop;
|
||||
|
||||
/// Instruction operand
|
||||
typedef struct cs_arm_op {
|
||||
int vector_index; ///< Vector Index for some vector operands (or -1 if irrelevant)
|
||||
@ -849,7 +860,8 @@ typedef struct cs_arm_op {
|
||||
arm_op_type type; ///< operand type
|
||||
|
||||
union {
|
||||
int reg; ///< register value for REG/SYSREG operand
|
||||
int reg; ///< register value for REG
|
||||
arm_sysop sysop; ///< System operand.
|
||||
int64_t imm; ///< immediate value for C-IMM, P-IMM or IMM operand
|
||||
int pred; ///< Predicate operand value.
|
||||
double fp; ///< floating point value for FP operand
|
||||
|
Loading…
x
Reference in New Issue
Block a user