capstone-engine / capstone

Capstone disassembly/disassembler framework for ARM, ARM64 (ARMv8), Alpha, BPF, Ethereum VM, HPPA, LoongArch, M68K, M680X, Mips, MOS65XX, PPC, RISC-V(rv32G/rv64G), SH, Sparc, SystemZ, TMS320C64X, TriCore, Webassembly, XCore and X86.
http://www.capstone-engine.org
7.61k stars 1.56k forks source link

ARM: op.shift.value and op.mem.lshift differ for shifted index reg #1848

Open adamjseitz opened 2 years ago

adamjseitz commented 2 years ago

For the following ARM instruction's memory operand, capstone reports op.shift.value of 2, but op.mem.lshift of 0.

ldr r0, [r1, r2, lsl #2]

The header file seems to suggest that these values should be the same:

/// Instruction's operand referring to memory
/// This is associated with ARM_OP_MEM operand type above
typedef struct arm_op_mem {
        ...
    /// left-shift on index register, or 0 if irrelevant
    /// NOTE: this value can also be fetched via operand.shift.value
    int lshift;
} arm_op_mem;

This can be worked around by using op.shift.value, but I think the values should match.

I identified this bug on commit 9759b6e3f712e232ec19b4281d41220d4dea4a55, the latest on the next branch.


Sample code:

csh handle;
cs_insn *insn;
size_t count;

uint8_t buf[] = {
    0x02, 0x01, 0x91, 0xE7  // ldr r0, [r1, r2, lsl #2]
};

if (cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle) != CS_ERR_OK)
    return -1;

cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);

count = cs_disasm(handle, buf, sizeof(buf), 0, 0, &insn);
if (count > 0)
{
    for (size_t j=0; j<count; j++)
    {
        cs_detail *detail = insn[j].detail;
        for (size_t n=0; n<detail->arm.op_count; n++)
        {
            cs_arm_op *op = &(detail->arm.operands[n]);
            if (op->type != ARM_OP_MEM) {
                continue;
            }

            printf("op.shift.type:  %d\n", op->shift.type);
            printf("op.shift.value: %d\n", op->shift.value);
            printf("op.mem.lshift:  %d\n", op->mem.lshift);
        }
    }
    cs_free(insn, count);
}
cs_close(&handle);

Output:

op.shift.type:  2
op.shift.value: 2
op.mem.lshift:  0
LostBenjamin commented 2 years ago

I encountered the same issue. Please fix it.

bug reproduction:

from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB

cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
cs.detail = True
inst = list(cs.disasm(bytearray([0x57, 0xf8, 0x23, 0x00]), 0))[0]
print(inst.op_str)
op1 = inst.operands[1]
print(op1.mem.lshift)
print(op1.shift.value)