Enhance shift value and types of shift instructions. (#2638)

* Enhance shift value and types of shift instructions.

Shifts via registers now save the register id in cs_arch64_op.shift.value
and set the shift type accordingly.

* Sort table
This commit is contained in:
Rot127 2025-03-09 14:11:53 +00:00 committed by GitHub
parent cd282ef593
commit bb2f657973
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 365 additions and 6 deletions

View File

@ -369,12 +369,52 @@ static void AArch64_check_updates_flags(MCInst *MI)
#endif // CAPSTONE_DIET
}
static aarch64_shifter id_to_shifter(unsigned Opcode) {
switch (Opcode) {
default:
return AARCH64_SFT_INVALID;
case AArch64_RORVXr:
case AArch64_RORVWr:
return AARCH64_SFT_ROR_REG;
case AArch64_LSRVXr:
case AArch64_LSRVWr:
return AARCH64_SFT_LSR_REG;
case AArch64_LSLVXr:
case AArch64_LSLVWr:
return AARCH64_SFT_LSL_REG;
case AArch64_ASRVXr:
case AArch64_ASRVWr:
return AARCH64_SFT_ASR_REG;
}
}
static void add_non_alias_details(MCInst *MI)
{
unsigned Opcode = MCInst_getOpcode(MI);
switch (Opcode) {
default:
break;
case AArch64_RORVXr:
case AArch64_RORVWr:
case AArch64_LSRVXr:
case AArch64_LSRVWr:
case AArch64_LSLVXr:
case AArch64_LSLVWr:
case AArch64_ASRVXr:
case AArch64_ASRVWr:
if (AArch64_get_detail(MI)->op_count != 3) {
return;
}
CS_ASSERT_RET(AArch64_get_detail_op(MI, -1)->type == AARCH64_OP_REG);
// The shift by register instructions don't set the shift value properly.
// Correct it here.
uint64_t shift = AArch64_get_detail_op(MI, -1)->reg;
cs_aarch64_op *op1 = AArch64_get_detail_op(MI, -2);
op1->shift.type = id_to_shifter(Opcode);
op1->shift.value = shift;
AArch64_dec_op_count(MI);
break;
case AArch64_FCMPDri:
case AArch64_FCMPEDri:
case AArch64_FCMPEHri:
@ -573,6 +613,19 @@ static void AArch64_add_not_defined_ops(MCInst *MI, const SStream *OS)
switch (MI->flat_insn->alias_id) {
default:
return;
case AARCH64_INS_ALIAS_ROR:
if (AArch64_get_detail(MI)->op_count != 3) {
return;
}
// The ROR alias doesn't set the shift value properly.
// Correct it here.
bool reg_shift = AArch64_get_detail_op(MI, -1)->type == AARCH64_OP_REG;
uint64_t shift = reg_shift ? AArch64_get_detail_op(MI, -1)->reg : AArch64_get_detail_op(MI, -1)->imm;
cs_aarch64_op *op1 = AArch64_get_detail_op(MI, -2);
op1->shift.type = reg_shift ? AARCH64_SFT_ROR_REG : AARCH64_SFT_ROR;
op1->shift.value = shift;
AArch64_dec_op_count(MI);
break;
case AARCH64_INS_ALIAS_FMOV:
if (AArch64_get_detail_op(MI, -1)->type == AARCH64_OP_FP) {
break;
@ -1042,6 +1095,12 @@ void AArch64_reg_access(const cs_insn *insn, cs_regs regs_read,
default:
break;
}
if (op->shift.type >= AARCH64_SFT_LSL_REG) {
if (!arr_exist(regs_read, read_count, op->shift.value)) {
regs_read[read_count] = (uint16_t)op->shift.value;
read_count++;
}
}
}
*regs_read_count = read_count;

View File

@ -7,6 +7,11 @@ AARCH64_SFT_MSL = 2
AARCH64_SFT_LSR = 3
AARCH64_SFT_ASR = 4
AARCH64_SFT_ROR = 5
AARCH64_SFT_LSL_REG = 6
AARCH64_SFT_MSL_REG = 7
AARCH64_SFT_LSR_REG = 8
AARCH64_SFT_ASR_REG = 9
AARCH64_SFT_ROR_REG = 10
AARCH64_EXT_INVALID = 0
AARCH64_EXT_UXTB = 1

View File

@ -18,6 +18,8 @@ extern "C" {
#endif
/// AArch64 shift type
/// Those values do not correspond to the bit values encoded
/// in the instruction.
typedef enum aarch64_shifter {
AARCH64_SFT_INVALID = 0,
AARCH64_SFT_LSL = 1,
@ -25,6 +27,11 @@ typedef enum aarch64_shifter {
AARCH64_SFT_LSR = 3,
AARCH64_SFT_ASR = 4,
AARCH64_SFT_ROR = 5,
AARCH64_SFT_LSL_REG = 6,
AARCH64_SFT_MSL_REG = 7,
AARCH64_SFT_LSR_REG = 8,
AARCH64_SFT_ASR_REG = 9,
AARCH64_SFT_ROR_REG = 10,
} aarch64_shifter;
/// AArch64 extender type
@ -2813,7 +2820,10 @@ typedef struct cs_aarch64_op {
AArch64Layout_VectorLayout vas; ///< Vector Arrangement Specifier
struct {
aarch64_shifter type; ///< shifter type of this operand
unsigned int value; ///< shifter value of this operand
/// Shift value of this operand.
/// If the type indicates a shift with a register this value should be
/// interpreted as aarch64_reg.
unsigned int value;
} shift;
aarch64_extender ext; ///< extender type of this operand
aarch64_op_type type; ///< operand type

View File

@ -25,6 +25,11 @@ typedef enum {
ARM64_SFT_LSR = AARCH64_SFT_LSR,
ARM64_SFT_ASR = AARCH64_SFT_ASR,
ARM64_SFT_ROR = AARCH64_SFT_ROR,
ARM64_SFT_LSL_REG = AARCH64_SFT_LSL_REG,
ARM64_SFT_MSL_REG = AARCH64_SFT_MSL_REG,
ARM64_SFT_LSR_REG = AARCH64_SFT_LSR_REG,
ARM64_SFT_ASR_REG = AARCH64_SFT_ASR_REG,
ARM64_SFT_ROR_REG = AARCH64_SFT_ROR_REG,
} arm64_shifter;
typedef enum {

View File

@ -289,11 +289,16 @@ static const cs_enum_id_map cs_enum_map[] = {
{ .str = "AARCH64_OP_TLBI", .val = AARCH64_OP_TLBI },
{ .str = "AARCH64_OP_TSB", .val = AARCH64_OP_TSB },
{ .str = "AARCH64_SFT_ASR", .val = AARCH64_SFT_ASR },
{ .str = "AARCH64_SFT_ASR_REG", .val = AARCH64_SFT_ASR_REG },
{ .str = "AARCH64_SFT_INVALID", .val = AARCH64_SFT_INVALID },
{ .str = "AARCH64_SFT_LSL", .val = AARCH64_SFT_LSL },
{ .str = "AARCH64_SFT_LSL_REG", .val = AARCH64_SFT_LSL_REG },
{ .str = "AARCH64_SFT_LSR", .val = AARCH64_SFT_LSR },
{ .str = "AARCH64_SFT_LSR_REG", .val = AARCH64_SFT_LSR_REG },
{ .str = "AARCH64_SFT_MSL", .val = AARCH64_SFT_MSL },
{ .str = "AARCH64_SFT_MSL_REG", .val = AARCH64_SFT_MSL_REG },
{ .str = "AARCH64_SFT_ROR", .val = AARCH64_SFT_ROR },
{ .str = "AARCH64_SFT_ROR_REG", .val = AARCH64_SFT_ROR_REG },
{ .str = "AARCH64_SME_OP_INVALID", .val = AARCH64_SME_OP_INVALID },
{ .str = "AARCH64_SME_OP_TILE", .val = AARCH64_SME_OP_TILE },
{ .str = "AARCH64_SME_OP_TILE_VEC", .val = AARCH64_SME_OP_TILE_VEC },
@ -316,6 +321,10 @@ static const cs_enum_id_map cs_enum_map[] = {
{ .str = "AArch64CC_VS", .val = AArch64CC_VS },
{ .str = "ALPHA_OP_IMM", .val = ALPHA_OP_IMM },
{ .str = "ALPHA_OP_REG", .val = ALPHA_OP_REG },
{ .str = "ARC_GRP_BRANCH_RELATIVE", .val = ARC_GRP_BRANCH_RELATIVE },
{ .str = "ARC_GRP_CALL", .val = ARC_GRP_CALL },
{ .str = "ARC_GRP_JUMP", .val = ARC_GRP_JUMP },
{ .str = "ARC_GRP_RET", .val = ARC_GRP_RET },
{ .str = "ARC_OP_IMM", .val = ARC_OP_IMM },
{ .str = "ARC_OP_REG", .val = ARC_OP_REG },
{ .str = "ARMCC_AL", .val = ARMCC_AL },
@ -466,10 +475,6 @@ static const cs_enum_id_map cs_enum_map[] = {
{ .str = "Alpha_GRP_CALL", .val = Alpha_GRP_CALL },
{ .str = "Alpha_GRP_ENDING", .val = Alpha_GRP_ENDING },
{ .str = "Alpha_GRP_JUMP", .val = Alpha_GRP_JUMP },
{ .str = "ARC_GRP_JUMP", .val = ARC_GRP_JUMP },
{ .str = "ARC_GRP_CALL", .val = ARC_GRP_CALL },
{ .str = "ARC_GRP_RET", .val = ARC_GRP_RET },
{ .str = "ARC_GRP_BRANCH_RELATIVE", .val = ARC_GRP_BRANCH_RELATIVE },
{ .str = "BPF_EXT_LEN", .val = BPF_EXT_LEN },
{ .str = "BPF_GRP_ALU", .val = BPF_GRP_ALU },
{ .str = "BPF_GRP_CALL", .val = BPF_GRP_CALL },
@ -1671,4 +1676,4 @@ static const cs_enum_id_map cs_enum_map[] = {
.val = 0xffffff }, // For testing
};
#endif // TEST_MAPPING_H
#endif // TEST_MAPPING_H

View File

@ -869,3 +869,278 @@ test_cases:
regs_read: [ zt0, z30, z31 ]
regs_write: [ z19, z23, z27, z31 ]
groups: [ HasSME2p1, HasSME_LUTv2 ]
-
input:
bytes: [0x41,0x7c,0x82,0x13]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "ror w1, w2, #31"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_ROR
shift_value: 31
regs_read: [ w2 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x7c,0x1f,0x53]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "lsr w1, w2, #31"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_LSR
shift_value: 31
regs_read: [ w2 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x7c,0x1f,0x13]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "asr w1, w2, #31"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_ASR
shift_value: 31
regs_read: [ w2 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x00,0x01,0x53]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "lsl w1, w2, #31"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_LSL
shift_value: 31
regs_read: [ w2 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x2c,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "ror w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_ROR_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x24,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "lsr w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_LSR_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x28,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "asr w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_ASR_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x20,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "lsl w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_LSL_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x2c,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "ror w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_ROR_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x24,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "lsr w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_LSR_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]
-
input:
bytes: [0x41,0x28,0xc3,0x1a]
arch: "CS_ARCH_AARCH64"
options: [ CS_OPT_DETAIL ]
address: 0x0
expected:
insns:
-
asm_text: "asr w1, w2, w3"
details:
aarch64:
operands:
-
type: AARCH64_OP_REG
reg: w1
access: CS_AC_WRITE
-
type: AARCH64_OP_REG
reg: w2
access: CS_AC_READ
shift_type: AARCH64_SFT_ASR_REG
shift_value: 207 # Absolute number of W3 enum value. Might change with an update.
regs_read: [ w2, w3 ]
regs_write: [ w1 ]