Skip to content

Commit

Permalink
Handle system operands in way more detail.
Browse files Browse the repository at this point in the history
- Differentiates between banked and non-banked registers.
- Saves the MSR mask.
- PSR field bits are saved separately.
- SYSm value is saved if possible.
  • Loading branch information
Rot127 committed Jul 23, 2023
1 parent 09fea43 commit 23ac700
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 47 deletions.
83 changes: 57 additions & 26 deletions arch/ARM/ARMMapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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;
}
}
Expand All @@ -1113,24 +1113,25 @@ 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;
}
}

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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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);
}
Expand Down
3 changes: 2 additions & 1 deletion arch/ARM/ARMMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 30 additions & 1 deletion cstool/cstool_arm.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "capstone/arm.h"
#include <stdio.h>
#include <stdlib.h>

Expand Down Expand Up @@ -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_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, op->reg));
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) {
Expand Down
50 changes: 31 additions & 19 deletions include/capstone/arm.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,22 +284,22 @@ typedef enum MemBOpt {
} arm_mem_bo_opt;

typedef enum {
/// Special registers for MSR
ARM_SYSREG_INVALID = 0,

// 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;

// 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,

// 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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down

0 comments on commit 23ac700

Please sign in to comment.