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:
Rot127 2023-07-23 08:54:56 -05:00
parent 2aa4eb559d
commit 34a239b3e6
4 changed files with 119 additions and 46 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {

View File

@ -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