rizin/librz/arch/isa/arm/arm_il64.c
wargio d47ceedbd3 Merge rz_asm and rz_analysis into one library but keep deprecated apis.
The tms320c64x has been merged into tms320.
2024-03-07 18:38:49 +08:00

3138 lines
87 KiB
C

// SPDX-FileCopyrightText: 2022 Florian Märkl <info@florianmaerkl.de>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_analysis.h>
#include <capstone/capstone.h>
#include "arm_cs.h"
#include "arm_accessors64.h"
// This source file is 64-bit specific, so avoid having to type 64 all the time:
#define IMM IMM64
#define REGID REGID64
#define ISIMM ISIMM64
#define ISREG ISREG64
#define ISMEM ISMEM64
#define OPCOUNT OPCOUNT64
#undef MEMDISP64 // the original one casts to ut64 which we don't want here
#define MEMDISP(x) insn->detail->CS_aarch64_.operands[x].mem.disp
#include <rz_il/rz_il_opbuilder_begin.h>
#include "arm_il_common.inc"
/**
* All regs available as global IL variables
*/
static const char *regs_bound[] = {
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
"nf", "zf", "cf", "vf",
NULL
};
/**
* IL for arm64 condition
* unconditional is returned as NULL (rather than true), for simpler code
*/
static RzILOpBool *cond(CS_aarch64_cc() c) {
switch (c) {
case CS_AARCH64CC(_EQ):
return VARG("zf");
case CS_AARCH64CC(_NE):
return INV(VARG("zf"));
case CS_AARCH64CC(_HS):
return VARG("cf");
case CS_AARCH64CC(_LO):
return INV(VARG("cf"));
case CS_AARCH64CC(_MI):
return VARG("nf");
case CS_AARCH64CC(_PL):
return INV(VARG("nf"));
case CS_AARCH64CC(_VS):
return VARG("vf");
case CS_AARCH64CC(_VC):
return INV(VARG("vf"));
case CS_AARCH64CC(_HI):
return AND(VARG("cf"), INV(VARG("zf")));
case CS_AARCH64CC(_LS):
return OR(INV(VARG("cf")), VARG("zf"));
case CS_AARCH64CC(_GE):
return INV(XOR(VARG("nf"), VARG("vf")));
case CS_AARCH64CC(_LT):
return XOR(VARG("nf"), VARG("vf"));
case CS_AARCH64CC(_GT):
return INV(OR(XOR(VARG("nf"), VARG("vf")), VARG("zf")));
case CS_AARCH64CC(_LE):
return OR(XOR(VARG("nf"), VARG("vf")), VARG("zf"));
default:
return NULL;
}
}
static CS_aarch64_reg() xreg(ut8 idx) {
// for some reason, the CS_AARCH64(_REG_X0)...CS_AARCH64(_REG_X30) enum values are not contiguous,
// so use switch here and let the compiler optimize:
switch (idx) {
case 0: return CS_AARCH64(_REG_X0);
case 1: return CS_AARCH64(_REG_X1);
case 2: return CS_AARCH64(_REG_X2);
case 3: return CS_AARCH64(_REG_X3);
case 4: return CS_AARCH64(_REG_X4);
case 5: return CS_AARCH64(_REG_X5);
case 6: return CS_AARCH64(_REG_X6);
case 7: return CS_AARCH64(_REG_X7);
case 8: return CS_AARCH64(_REG_X8);
case 9: return CS_AARCH64(_REG_X9);
case 10: return CS_AARCH64(_REG_X10);
case 11: return CS_AARCH64(_REG_X11);
case 12: return CS_AARCH64(_REG_X12);
case 13: return CS_AARCH64(_REG_X13);
case 14: return CS_AARCH64(_REG_X14);
case 15: return CS_AARCH64(_REG_X15);
case 16: return CS_AARCH64(_REG_X16);
case 17: return CS_AARCH64(_REG_X17);
case 18: return CS_AARCH64(_REG_X18);
case 19: return CS_AARCH64(_REG_X19);
case 20: return CS_AARCH64(_REG_X20);
case 21: return CS_AARCH64(_REG_X21);
case 22: return CS_AARCH64(_REG_X22);
case 23: return CS_AARCH64(_REG_X23);
case 24: return CS_AARCH64(_REG_X24);
case 25: return CS_AARCH64(_REG_X25);
case 26: return CS_AARCH64(_REG_X26);
case 27: return CS_AARCH64(_REG_X27);
case 28: return CS_AARCH64(_REG_X28);
case 29: return CS_AARCH64(_REG_X29);
case 30: return CS_AARCH64(_REG_X30);
case 31: return CS_AARCH64(_REG_SP);
case 32: return CS_AARCH64(_REG_XZR);
default:
rz_warn_if_reached();
return CS_AARCH64(_REG_INVALID);
}
}
static bool is_xreg(CS_aarch64_reg() reg) {
switch (reg) {
case CS_AARCH64(_REG_X0):
case CS_AARCH64(_REG_X1):
case CS_AARCH64(_REG_X2):
case CS_AARCH64(_REG_X3):
case CS_AARCH64(_REG_X4):
case CS_AARCH64(_REG_X5):
case CS_AARCH64(_REG_X6):
case CS_AARCH64(_REG_X7):
case CS_AARCH64(_REG_X8):
case CS_AARCH64(_REG_X9):
case CS_AARCH64(_REG_X10):
case CS_AARCH64(_REG_X11):
case CS_AARCH64(_REG_X12):
case CS_AARCH64(_REG_X13):
case CS_AARCH64(_REG_X14):
case CS_AARCH64(_REG_X15):
case CS_AARCH64(_REG_X16):
case CS_AARCH64(_REG_X17):
case CS_AARCH64(_REG_X18):
case CS_AARCH64(_REG_X19):
case CS_AARCH64(_REG_X20):
case CS_AARCH64(_REG_X21):
case CS_AARCH64(_REG_X22):
case CS_AARCH64(_REG_X23):
case CS_AARCH64(_REG_X24):
case CS_AARCH64(_REG_X25):
case CS_AARCH64(_REG_X26):
case CS_AARCH64(_REG_X27):
case CS_AARCH64(_REG_X28):
case CS_AARCH64(_REG_X29):
case CS_AARCH64(_REG_X30):
case CS_AARCH64(_REG_SP):
case CS_AARCH64(_REG_XZR):
return true;
default:
return false;
}
}
static ut8 wreg_idx(CS_aarch64_reg() reg) {
if (reg >= CS_AARCH64(_REG_W0) && reg <= CS_AARCH64(_REG_W30)) {
return reg - CS_AARCH64(_REG_W0);
}
if (reg == CS_AARCH64(_REG_WSP)) {
return 31;
}
if (reg == CS_AARCH64(_REG_WZR)) {
return 32;
}
rz_warn_if_reached();
return 0;
}
static bool is_wreg(CS_aarch64_reg() reg) {
return (reg >= CS_AARCH64(_REG_W0) && reg <= CS_AARCH64(_REG_W30)) || reg == CS_AARCH64(_REG_WSP) || reg == CS_AARCH64(_REG_WZR);
}
static CS_aarch64_reg() xreg_of_reg(CS_aarch64_reg() reg) {
if (is_wreg(reg)) {
return xreg(wreg_idx(reg));
}
return reg;
}
/**
* Variable name for a register given by cs
*/
static const char *reg_var_name(CS_aarch64_reg() reg) {
reg = xreg_of_reg(reg);
switch (reg) {
case CS_AARCH64(_REG_X0): return "x0";
case CS_AARCH64(_REG_X1): return "x1";
case CS_AARCH64(_REG_X2): return "x2";
case CS_AARCH64(_REG_X3): return "x3";
case CS_AARCH64(_REG_X4): return "x4";
case CS_AARCH64(_REG_X5): return "x5";
case CS_AARCH64(_REG_X6): return "x6";
case CS_AARCH64(_REG_X7): return "x7";
case CS_AARCH64(_REG_X8): return "x8";
case CS_AARCH64(_REG_X9): return "x9";
case CS_AARCH64(_REG_X10): return "x10";
case CS_AARCH64(_REG_X11): return "x11";
case CS_AARCH64(_REG_X12): return "x12";
case CS_AARCH64(_REG_X13): return "x13";
case CS_AARCH64(_REG_X14): return "x14";
case CS_AARCH64(_REG_X15): return "x15";
case CS_AARCH64(_REG_X16): return "x16";
case CS_AARCH64(_REG_X17): return "x17";
case CS_AARCH64(_REG_X18): return "x18";
case CS_AARCH64(_REG_X19): return "x19";
case CS_AARCH64(_REG_X20): return "x20";
case CS_AARCH64(_REG_X21): return "x21";
case CS_AARCH64(_REG_X22): return "x22";
case CS_AARCH64(_REG_X23): return "x23";
case CS_AARCH64(_REG_X24): return "x24";
case CS_AARCH64(_REG_X25): return "x25";
case CS_AARCH64(_REG_X26): return "x26";
case CS_AARCH64(_REG_X27): return "x27";
case CS_AARCH64(_REG_X28): return "x28";
case CS_AARCH64(_REG_X29): return "x29";
case CS_AARCH64(_REG_X30): return "x30";
case CS_AARCH64(_REG_SP): return "sp";
default: return NULL;
}
}
/**
* Get the bits of the given register or 0, if it is not known (e.g. not implemented yet)
*/
static ut32 reg_bits(CS_aarch64_reg() reg) {
if (is_xreg(reg) || reg == CS_AARCH64(_REG_XZR)) {
return 64;
}
if (is_wreg(reg) || reg == CS_AARCH64(_REG_WZR)) {
return 32;
}
return 0;
}
/**
* IL to read the given capstone reg
*/
static RzILOpBitVector *read_reg(CS_aarch64_reg() reg) {
if (reg == CS_AARCH64(_REG_XZR)) {
return U64(0);
}
if (reg == CS_AARCH64(_REG_WZR)) {
return U32(0);
}
const char *var = reg_var_name(reg);
if (!var) {
return NULL;
}
if (is_wreg(reg)) {
return UNSIGNED(32, VARG(var));
}
return VARG(var);
}
/**
* Perform an unsigned cast of v or adjust an already existing one
*/
static RzILOpBitVector *adjust_unsigned(ut32 bits, RZ_OWN RzILOpBitVector *v) {
if (v->code == RZ_IL_OP_CAST) {
// reuse any existing cast
v->op.cast.length = bits;
} else if (v->code != RZ_IL_OP_BITV || rz_bv_len(v->op.bitv.value) != bits) {
v = UNSIGNED(bits, v);
}
return v;
}
static RzILOpBitVector *reg_extend(ut32 dst_bits, CS_aarch64_extender() ext, RZ_OWN RzILOpBitVector *reg, ut32 v_bits) {
bool is_signed = false;
ut32 src_bits = v_bits;
switch (ext) {
case CS_AARCH64(_EXT_SXTB):
is_signed = true;
// fallthrough
case CS_AARCH64(_EXT_UXTB):
src_bits = 8;
break;
case CS_AARCH64(_EXT_SXTH):
is_signed = true;
// fallthrough
case CS_AARCH64(_EXT_UXTH):
src_bits = 16;
break;
case CS_AARCH64(_EXT_SXTW):
is_signed = true;
// fallthrough
case CS_AARCH64(_EXT_UXTW):
src_bits = 32;
break;
case CS_AARCH64(_EXT_SXTX):
is_signed = true;
// fallthrough
case CS_AARCH64(_EXT_UXTX):
src_bits = 64;
break;
default:
break;
}
if (dst_bits < src_bits && src_bits <= v_bits) {
// Just cast it down once.
if (reg->code == RZ_IL_OP_CAST) {
// Already a casted down register. Set new width.
reg->op.cast.length = dst_bits;
return reg;
}
return UNSIGNED(dst_bits, reg);
}
if (src_bits != v_bits) {
reg = adjust_unsigned(src_bits, reg);
}
if (dst_bits != src_bits) {
return is_signed ? SIGNED(dst_bits, reg) : UNSIGNED(dst_bits, reg);
}
return is_signed ? SIGNED(dst_bits, reg) : reg;
}
static RzILOpBitVector *apply_shift(CS_aarch64_shifter() sft, ut32 dist, RZ_OWN RzILOpBitVector *v) {
if (!dist) {
return v;
}
switch (sft) {
case CS_AARCH64(_SFT_LSL):
return SHIFTL0(v, UN(6, dist));
case CS_AARCH64(_SFT_LSR):
return SHIFTR0(v, UN(6, dist));
case CS_AARCH64(_SFT_ASR):
return SHIFTRA(v, UN(6, dist));
default:
return v;
}
}
#define REG(n) read_reg(REGID(n))
#define REGBITS(n) reg_bits(REGID(n))
#define MEMBASEID(x) insn->detail->CS_aarch64_.operands[x].mem.base
#define MEMBASE(x) read_reg(MEMBASEID(x))
/**
* IL to write a value to the given capstone reg
*/
static RzILOpEffect *write_reg(CS_aarch64_reg() reg, RZ_OWN RZ_NONNULL RzILOpBitVector *v) {
rz_return_val_if_fail(v, NULL);
const char *var = reg_var_name(reg);
if (!var) {
rz_il_op_pure_free(v);
return NULL;
}
if (is_wreg(reg)) {
v = UNSIGNED(64, v);
}
return SETG(var, v);
}
static RzILOpBitVector *arg_mem(RzILOpBitVector *base_plus_disp, CS_aarch64_op() * op) {
if (op->mem.index == CS_AARCH64(_REG_INVALID)) {
return base_plus_disp;
}
RzILOpBitVector *index = read_reg(op->mem.index);
index = reg_extend(64, op->ext, index, reg_bits(op->mem.index));
index = apply_shift(op->shift.type, op->shift.value, index);
return ADD(base_plus_disp, index);
}
/**
* IL to retrieve the value of the \p n -th arg of \p insn
* \p bits_inout Setting the backing variable to non-0 indicates that the result must have this bitness.
* This is necessary for immediate operands for example.
* In any case, if a value is returned, its bitness is written back into this storage.
*/
static RzILOpBitVector *arg(RZ_BORROW cs_insn *insn, size_t n, RZ_OUT ut32 *bits_inout) {
ut32 bits_requested = bits_inout ? *bits_inout : 0;
CS_aarch64_op() *op = &insn->detail->CS_aarch64_.operands[n];
switch (op->type) {
case CS_AARCH64(_OP_REG): {
if (!bits_requested) {
bits_requested = REGBITS(n);
if (!bits_requested) {
return NULL;
}
if (bits_inout) {
*bits_inout = bits_requested;
}
}
RzILOpBitVector *r = REG(n);
if (!r) {
return NULL;
}
return apply_shift(op->shift.type, op->shift.value, reg_extend(bits_requested, op->ext, r, REGBITS(n)));
}
case CS_AARCH64(_OP_IMM): {
if (!bits_requested) {
return NULL;
}
ut64 val = IMM(n);
if (op->shift.type == CS_AARCH64(_SFT_LSL)) {
val <<= op->shift.value;
}
return UN(bits_requested, val);
}
case CS_AARCH64(_OP_MEM): {
RzILOpBitVector *addr = MEMBASE(n);
#if CS_NEXT_VERSION >= 6
if (ISPOSTINDEX64()) {
return addr;
}
#endif
st64 disp = MEMDISP(n);
if (disp > 0) {
addr = ADD(addr, U64(disp));
} else if (disp < 0) {
addr = SUB(addr, U64(-disp));
}
return arg_mem(addr, &insn->detail->CS_aarch64_.operands[n]);
}
default:
break;
}
return NULL;
}
#define ARG(n, bits) arg(insn, n, bits)
/**
* zf := v == 0
* nf := msb v
*/
static RzILOpEffect *update_flags_zn(RzILOpBitVector *v) {
return SEQ2(
SETG("zf", IS_ZERO(v)),
SETG("nf", MSB(DUP(v))));
}
/**
* zf := v == 0
* nf := msb v
* cf := 0
* vf := 0
*/
static RzILOpEffect *update_flags_zn00(RzILOpBitVector *v) {
return SEQ3(
update_flags_zn(v),
SETG("cf", IL_FALSE),
SETG("vf", IL_FALSE));
}
/**
* Capstone: CS_AARCH64(_INS_ADD), CS_AARCH64(_INS_ADC), CS_AARCH64(_INS_SUB), CS_AARCH64(_INS_SBC)
* ARM: add, adds, adc, adcs, sub, subs, sbc, sbcs
*/
static RzILOpEffect *add_sub(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
bool is_sub = insn->id == CS_AARCH64(_INS_SUB) || insn->id == CS_AARCH64(_INS_SBC)
#if CS_API_MAJOR > 4
|| insn->id == CS_AARCH64(_INS_SUBS) || insn->id == CS_AARCH64(_INS_SBCS)
#endif
;
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *a = ARG(1, &bits);
RzILOpBitVector *b = ARG(2, &bits);
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
RzILOpBitVector *res = is_sub ? SUB(a, b) : ADD(a, b);
bool with_carry = false;
if (insn->id == CS_AARCH64(_INS_ADC)
#if CS_API_MAJOR > 4
|| insn->id == CS_AARCH64(_INS_ADCS)
#endif
) {
res = ADD(res, ITE(VARG("cf"), UN(bits, 1), UN(bits, 0)));
with_carry = true;
} else if (insn->id == CS_AARCH64(_INS_SBC)
#if CS_API_MAJOR > 4
|| insn->id == CS_AARCH64(_INS_SBCS)
#endif
) {
res = SUB(res, ITE(VARG("cf"), UN(bits, 0), UN(bits, 1)));
with_carry = true;
}
RzILOpEffect *set = write_reg(REGID(0), res);
bool update_flags = insn->detail->CS_aarch64_.update_flags;
if (update_flags) {
return SEQ6(
SETL("a", DUP(a)),
SETL("b", DUP(b)),
set,
SETG("cf", (is_sub ? sub_carry : add_carry)(VARL("a"), VARL("b"), with_carry, bits)),
SETG("vf", (is_sub ? sub_overflow : add_overflow)(VARL("a"), VARL("b"), REG(0))),
update_flags_zn(REG(0)));
}
return set;
}
/**
* Capstone: CS_AARCH64(_INS_ADR), CS_AARCH64(_INS_ADRP)
* ARM: adr, adrp
*/
static RzILOpEffect *adr(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
return write_reg(REGID(0), U64(IMM(1)));
}
/**
* Capstone: CS_AARCH64(_INS_AND), CS_AARCH64(_INS_EON), CS_AARCH64(_INS_EOR), CS_AARCH64(_INS_ORN), CS_AARCH64(_INS_AORR)
* ARM: and, eon, eor, orn, orr
*/
static RzILOpEffect *bitwise(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *a = ARG(1, &bits);
RzILOpBitVector *b = ARG(2, &bits);
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
RzILOpBitVector *res;
switch (insn->id) {
case CS_AARCH64(_INS_EOR):
res = LOGXOR(a, b);
break;
case CS_AARCH64(_INS_EON):
res = LOGXOR(a, LOGNOT(b));
break;
case CS_AARCH64(_INS_ORN):
res = LOGOR(a, LOGNOT(b));
break;
case CS_AARCH64(_INS_ORR):
res = LOGOR(a, b);
break;
default: // CS_AARCH64(_INS_AND)
res = LOGAND(a, b);
break;
}
RzILOpEffect *eff = write_reg(REGID(0), res);
if (!eff) {
return NULL;
}
if (insn->detail->CS_aarch64_.update_flags) {
return SEQ2(eff, update_flags_zn00(REG(0)));
}
return eff;
}
/**
* Capstone: CS_AARCH64(_INS_ASR), CS_AARCH64(_INS_LSL), CS_AARCH64(_INS_LSR), CS_AARCH64(_INS_ROR)
* ARM: asr, asrv, lsl, lslv, lsr, lsrv, ror, rorv
*/
static RzILOpEffect *shift(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *a = ARG(1, &bits);
if (!a) {
return NULL;
}
bits = bits == 32 ? 5 : 6; // cast to log2(bits) to perform exactly mod bits
RzILOpBitVector *b = ARG(2, &bits);
if (!b) {
rz_il_op_pure_free(a);
return NULL;
}
RzILOpBitVector *res;
switch (insn->id) {
case CS_AARCH64(_INS_ASR):
res = SHIFTRA(a, b);
break;
case CS_AARCH64(_INS_LSR):
res = SHIFTR0(a, b);
break;
case CS_AARCH64(_INS_ROR):
res = LOGOR(SHIFTR0(a, b), SHIFTL0(DUP(a), NEG(DUP(b))));
break;
#if CS_NEXT_VERSION >= 6
case AArch64_INS_EXTR:
if (insn->alias_id != AArch64_INS_ALIAS_ROR) {
return NULL;
}
b = ARG(3, &bits);
res = LOGOR(SHIFTR0(a, b), SHIFTL0(DUP(a), NEG(DUP(b))));
break;
#endif
default: // CS_AARCH64(_INS_LSL)
res = SHIFTL0(a, b);
break;
}
return write_reg(REGID(0), res);
}
/**
* Capstone: CS_AARCH64(_INS_B), CS_AARCH64(_INS_RET), CS_AARCH64(_INS_RETAA), CS_AARCH64(_INS_RETAB)
* ARM: b, b.cond, ret, retaa, retab
*/
static RzILOpEffect *branch(cs_insn *insn) {
RzILOpBitVector *a;
if (OPCOUNT() == 0) {
// for CS_AARCH64(_INS_RET) and similar
a = read_reg(CS_AARCH64(_REG_LR));
} else {
ut32 bits = 64;
a = ARG(0, &bits);
}
if (!a) {
return NULL;
}
RzILOpBool *c = cond(insn->detail->CS_aarch64_.cc);
if (c) {
return BRANCH(c, JMP(a), NOP());
}
return JMP(a);
}
/**
* Capstone: CS_AARCH64(_INS_BL), CS_AARCH64(_INS_BLR), CS_AARCH64(_INS_BLRAA), CS_AARCH64(_INS_BLRAAZ), CS_AARCH64(_INS_BLRAB), CS_AARCH64(_INS_BLRABZ)
* ARM: bl, blr, blraa, blraaz, blrab, blrabz
*/
static RzILOpEffect *bl(cs_insn *insn) {
ut32 bits = 64;
RzILOpBitVector *a = ARG(0, &bits);
if (!a) {
return NULL;
}
return SEQ2(
SETG("x30", U64(insn->address + 4)),
JMP(a));
}
/**
* Capstone: CS_AARCH64(_INS_BFM), CS_AARCH64(_INS_BFI), CS_AARCH64(_INS_BFXIL)
* ARM: bfm, bfc, bfi, bfxil
*/
static RzILOpEffect *bfm(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = 0;
RzILOpBitVector *a = ARG(0, &bits);
if (!a) {
return NULL;
}
if (ISIMM(1) && ISIMM(2)) {
// bfc
ut64 mask = rz_num_bitmask(IMM(2)) << RZ_MIN(63, IMM(1));
return write_reg(REGID(0), LOGAND(a, UN(bits, mask)));
}
RzILOpBitVector *b = ARG(1, &bits);
if (!b) {
return NULL;
}
#if CS_NEXT_VERSION < 6
ut64 mask_base = rz_num_bitmask(IMM(3));
ut64 mask = mask_base << RZ_MIN(63, IMM(2));
if (insn->id == CS_AARCH64(_INS_BFI)) {
return write_reg(REGID(0), LOGOR(LOGAND(a, UN(bits, ~mask)), SHIFTL0(LOGAND(b, UN(bits, mask_base)), UN(6, IMM(2)))));
}
// insn->id == CS_AARCH64(_INS_BFXIL)
return write_reg(REGID(0), LOGOR(LOGAND(a, UN(bits, ~mask_base)), SHIFTR0(LOGAND(b, UN(bits, mask)), UN(6, IMM(2)))));
#else
ut64 lsb = IMM(2);
ut64 width = IMM(3);
if (insn->alias_id == AArch64_INS_ALIAS_BFI) {
width += 1;
// TODO Mod depends on (sf && N) bits
lsb = -lsb % 32;
ut64 mask_base = rz_num_bitmask(width);
ut64 mask = mask_base << RZ_MIN(63, lsb);
return write_reg(REGID(0), LOGOR(LOGAND(a, UN(bits, ~mask)), SHIFTL0(LOGAND(b, UN(bits, mask_base)), UN(6, lsb))));
} else if (insn->alias_id == AArch64_INS_ALIAS_BFXIL) {
width = width - lsb + 1;
ut64 mask_base = rz_num_bitmask(width);
ut64 mask = mask_base << RZ_MIN(63, lsb);
return write_reg(REGID(0), LOGOR(LOGAND(a, UN(bits, ~mask_base)), SHIFTR0(LOGAND(b, UN(bits, mask)), UN(6, lsb))));
}
return NULL;
#endif
}
/**
* Capstone: CS_AARCH64(_INS_BIC), CS_AARCH64(_INS_BICS)
* ARM: bic, bics
*/
static RzILOpEffect *bic(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *a = ARG(1, &bits);
RzILOpBitVector *b = ARG(2, &bits);
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
RzILOpBitVector *res = LOGAND(a, LOGNOT(b));
RzILOpEffect *eff = NULL;
if (REGID(0) != CS_AARCH64(_REG_XZR) && REGID(0) != CS_AARCH64(_REG_WZR)) {
eff = write_reg(REGID(0), res);
if (!eff) {
return NULL;
}
res = NULL;
}
if (insn->detail->CS_aarch64_.update_flags) {
RzILOpEffect *eff1 = update_flags_zn00(res ? res : REG(0));
return eff ? SEQ2(eff, eff1) : eff1;
}
if (!eff) {
rz_il_op_pure_free(res);
}
return eff;
}
#if CS_API_MAJOR > 4
/**
* Capstone: CS_AARCH64(_INS_CAS), CS_AARCH64(_INS_CASA), CS_AARCH64(_INS_CASAL), CS_AARCH64(_INS_CASL),
* CS_AARCH64(_INS_CASB), CS_AARCH64(_INS_CASAB), CS_AARCH64(_INS_CASALB), CS_AARCH64(_INS_CASLB),
* CS_AARCH64(_INS_CASH), CS_AARCH64(_INS_CASAH), CS_AARCH64(_INS_CASALH), CS_AARCH64(_INS_CASLH):
* ARM: cas, casa, casal, casl, casb, casab, casalb, caslb, cash, casah, casalh, caslh
*/
static RzILOpEffect *cas(cs_insn *insn) {
if (!ISREG(0) || !ISMEM(2)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
switch (insn->id) {
case CS_AARCH64(_INS_CASB):
case CS_AARCH64(_INS_CASAB):
case CS_AARCH64(_INS_CASALB):
case CS_AARCH64(_INS_CASLB):
bits = 8;
break;
case CS_AARCH64(_INS_CASH):
case CS_AARCH64(_INS_CASAH):
case CS_AARCH64(_INS_CASALH):
case CS_AARCH64(_INS_CASLH):
bits = 16;
break;
default:
break;
}
RzILOpBitVector *addr = ARG(2, NULL);
RzILOpBitVector *cmpval = ARG(0, &bits);
RzILOpBitVector *newval = ARG(1, &bits);
RzILOpEffect *write_old_eff = write_reg(REGID(0), VARL("old"));
if (!addr || !cmpval || !newval || !write_old_eff) {
rz_il_op_pure_free(addr);
rz_il_op_pure_free(cmpval);
rz_il_op_pure_free(newval);
rz_il_op_effect_free(write_old_eff);
return NULL;
}
return SEQ3(
SETL("old", bits == 8 ? LOAD(addr) : LOADW(bits, addr)),
BRANCH(EQ(VARL("old"), cmpval), bits == 8 ? STORE(DUP(addr), newval) : STOREW(DUP(addr), newval), NULL),
write_old_eff);
}
/**
* Capstone: CS_AARCH64(_INS_CASP), CS_AARCH64(_INS_CASPA), CS_AARCH64(_INS_CASPAL), CS_AARCH64(_INS_CASPL)
* ARM: casp, caspa, caspal, caspl
*/
static RzILOpEffect *casp(cs_insn *insn) {
if (!ISREG(0) || !ISREG(1) || !ISMEM(4)) {
return NULL;
}
RzILOpBitVector *addr = ARG(4, NULL);
ut32 bits = 0;
RzILOpBitVector *cmpval0 = ARG(0, &bits);
RzILOpBitVector *cmpval1 = ARG(1, &bits);
RzILOpBitVector *newval0 = ARG(2, &bits);
RzILOpBitVector *newval1 = ARG(3, &bits);
RzILOpEffect *write_old0_eff = write_reg(REGID(0), VARL("old0"));
RzILOpEffect *write_old1_eff = write_reg(REGID(1), VARL("old1"));
if (!addr || !cmpval0 || !cmpval1 || !newval0 || !newval1 || !write_old0_eff || !write_old1_eff) {
rz_il_op_pure_free(addr);
rz_il_op_pure_free(cmpval0);
rz_il_op_pure_free(cmpval1);
rz_il_op_pure_free(newval0);
rz_il_op_pure_free(newval1);
rz_il_op_effect_free(write_old0_eff);
rz_il_op_effect_free(write_old1_eff);
return NULL;
}
return SEQ5(
SETL("old0", LOADW(bits, addr)),
SETL("old1", LOADW(bits, ADD(DUP(addr), U64(bits / 8)))),
BRANCH(AND(EQ(VARL("old0"), cmpval0), EQ(VARL("old1"), cmpval1)),
SEQ2(
STOREW(DUP(addr), newval0),
STOREW(ADD(DUP(addr), U64(bits / 8)), newval1)),
NULL),
write_old0_eff,
write_old1_eff);
}
#endif
/**
* Capstone: CS_AARCH64(_INS_CBZ), CS_AARCH64(_INS_CBNZ)
* ARM: cbz, cbnz
*/
static RzILOpEffect *cbz(cs_insn *insn) {
RzILOpBitVector *v = ARG(0, NULL);
ut32 bits = 64;
RzILOpBitVector *tgt = ARG(1, &bits);
if (!v || !tgt) {
rz_il_op_pure_free(v);
rz_il_op_pure_free(tgt);
return NULL;
}
return BRANCH(insn->id == CS_AARCH64(_INS_CBNZ) ? INV(IS_ZERO(v)) : IS_ZERO(v), JMP(tgt), NULL);
}
/**
* Capstone: CS_AARCH64(_INS_CMP), CS_AARCH64(_INS_CMN), CS_AARCH64(_INS_CCMP), CS_AARCH64(_INS_CCMN)
* ARM: cmp, cmn, ccmp, ccmn
*/
static RzILOpEffect *cmp(cs_insn *insn) {
ut32 bits = 0;
#if CS_NEXT_VERSION < 6
RzILOpBitVector *a = ARG(0, &bits);
RzILOpBitVector *b = ARG(1, &bits);
#else
RzILOpBitVector *a;
RzILOpBitVector *b;
if (insn->alias_id == AArch64_INS_ALIAS_CMP ||
insn->alias_id == AArch64_INS_ALIAS_CMN) {
// Reg at 0 is zero register
a = ARG(1, &bits);
b = ARG(2, &bits);
} else {
a = ARG(0, &bits);
b = ARG(1, &bits);
}
#endif
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
#if CS_NEXT_VERSION < 6
bool is_neg = insn->id == CS_AARCH64(_INS_CMN) || insn->id == CS_AARCH64(_INS_CCMN);
#else
bool is_neg = insn->alias_id == AArch64_INS_ALIAS_CMN || insn->id == CS_AARCH64(_INS_CCMN);
#endif
RzILOpEffect *eff = SEQ6(
SETL("a", a),
SETL("b", b),
SETL("r", is_neg ? ADD(VARL("a"), VARL("b")) : SUB(VARL("a"), VARL("b"))),
SETG("cf", (is_neg ? add_carry : sub_carry)(VARL("a"), VARL("b"), false, bits)),
SETG("vf", (is_neg ? add_overflow : sub_overflow)(VARL("a"), VARL("b"), VARL("r"))),
update_flags_zn(VARL("r")));
RzILOpBool *c = cond(insn->detail->CS_aarch64_.cc);
if (c) {
ut64 imm = IMM(2);
return BRANCH(c,
eff,
SEQ4(
SETG("nf", imm & (1 << 3) ? IL_TRUE : IL_FALSE),
SETG("zf", imm & (1 << 2) ? IL_TRUE : IL_FALSE),
SETG("cf", imm & (1 << 1) ? IL_TRUE : IL_FALSE),
SETG("vf", imm & (1 << 0) ? IL_TRUE : IL_FALSE)));
}
return eff;
}
/**
* Capstone: CS_AARCH64(_INS_CINC), CS_AARCH64(_INS_CSINC), CS_AARCH64(_INS_CINV), CS_AARCH64(_INS_CSINV), CS_AARCH64(_INS_CNEG), CS_AARCH64(_INS_CSNEG), CS_AARCH64(_INS_CSEL)
* ARM: cinc, csinc, cinv, csinv, cneg, csneg, csel
*/
static RzILOpEffect *csinc(cs_insn *insn) {
size_t dst_idx = 0;
size_t src0_idx = 1;
size_t src1_idx = OPCOUNT() > 2 ? 2 : 1;
if (!ISREG(dst_idx)) {
return NULL;
}
ut32 bits = REGBITS(dst_idx);
if (!bits) {
return NULL;
}
RzILOpBitVector *src0 = ARG(src0_idx, &bits);
if (!src0) {
return NULL;
}
#if CS_NEXT_VERSION < 6
RzILOpBool *c = cond(insn->detail->CS_aarch64_.cc);
#else
AArch64CC_CondCode cc;
if (insn->alias_id == AArch64_INS_ALIAS_CINV ||
insn->alias_id == AArch64_INS_ALIAS_CNEG ||
insn->alias_id == AArch64_INS_ALIAS_CINC) {
cc = AArch64CC_getInvertedCondCode(insn->detail->CS_aarch64_.cc);
} else {
cc = insn->detail->CS_aarch64_.cc;
}
RzILOpBool *c = cond(cc);
#endif
if (!c) {
// al/nv conditions, only possible in cs(inc|inv|neg)
return write_reg(REGID(dst_idx), src0);
}
RzILOpBitVector *src1 = ARG(src1_idx, &bits);
if (!src1) {
rz_il_op_pure_free(src0);
rz_il_op_pure_free(c);
return NULL;
}
RzILOpBitVector *res;
bool invert_cond = false;
switch (insn->id) {
case CS_AARCH64(_INS_CSEL):
invert_cond = true;
res = src1;
break;
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_CSINV):
invert_cond = true;
// fallthrough
case CS_AARCH64(_INS_CINV):
res = LOGNOT(src1);
break;
case CS_AARCH64(_INS_CSNEG):
invert_cond = true;
// fallthrough
case CS_AARCH64(_INS_CNEG):
res = NEG(src1);
break;
case CS_AARCH64(_INS_CSINC):
invert_cond = true;
#else
case CS_AARCH64(_INS_CSINV):
if (!insn->is_alias) {
invert_cond = true;
}
res = LOGNOT(src1);
break;
case CS_AARCH64(_INS_CSNEG):
if (!insn->is_alias) {
invert_cond = true;
}
res = NEG(src1);
break;
case CS_AARCH64(_INS_CSINC):
if (!insn->is_alias) {
invert_cond = true;
}
#endif
// fallthrough
default: // CS_AARCH64(_INS_CINC), CS_AARCH64(_INS_CSINC)
res = ADD(src1, UN(bits, 1));
break;
}
return write_reg(REGID(dst_idx), invert_cond ? ITE(c, src0, res) : ITE(c, res, src0));
}
/**
* Capstone: CS_AARCH64(_INS_CSET), CS_AARCH64(_INS_CSETM)
* ARM: cset, csetm
*/
static RzILOpEffect *cset(cs_insn *insn) {
if (!ISREG(0) || !REGBITS(0)) {
return NULL;
}
RzILOpBool *c = NULL;
#if CS_NEXT_VERSION < 6
c = cond(insn->detail->CS_aarch64_.cc);
#else
if (insn->alias_id == AArch64_INS_ALIAS_CSET ||
insn->alias_id == AArch64_INS_ALIAS_CSETM) {
c = cond(AArch64CC_getInvertedCondCode(insn->detail->CS_aarch64_.cc));
} else {
c = cond(insn->detail->CS_aarch64_.cc);
}
#endif
if (!c) {
return NULL;
}
ut32 bits = REGBITS(0);
#if CS_NEXT_VERSION < 6
return write_reg(REGID(0), ITE(c, SN(bits, insn->id == CS_AARCH64(_INS_CSETM) ? -1 : 1), SN(bits, 0)));
#else
return write_reg(REGID(0), ITE(c, SN(bits, insn->alias_id == AArch64_INS_ALIAS_CSETM ? -1 : 1), SN(bits, 0)));
#endif
}
/**
* Capstone: CS_AARCH64(_INS_CLS)
* ARM: cls
*/
static RzILOpEffect *cls(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = 0;
RzILOpBitVector *v = ARG(1, &bits);
if (!v) {
return NULL;
}
return SEQ5(
SETL("v", v),
SETL("i", SN(bits, -1)),
SETL("msb", MSB(VARL("v"))),
REPEAT(INV(XOR(MSB(VARL("v")), VARL("msb"))),
SEQ2(
SETL("v", SHIFTL(INV(VARL("msb")), VARL("v"), UN(6, 1))),
SETL("i", ADD(VARL("i"), UN(bits, 1))))),
write_reg(REGID(0), VARL("i")));
}
/**
* Capstone: CS_AARCH64(_INS_CLZ)
* ARM: clz
*/
static RzILOpEffect *clz(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = 0;
RzILOpBitVector *v = ARG(1, &bits);
if (!v) {
return NULL;
}
return SEQ4(
SETL("v", v),
SETL("i", UN(bits, bits)),
REPEAT(INV(IS_ZERO(VARL("v"))),
SEQ2(
SETL("v", SHIFTR0(VARL("v"), UN(6, 1))),
SETL("i", SUB(VARL("i"), UN(bits, 1))))),
write_reg(REGID(0), VARL("i")));
}
/**
* Capstone: CS_AARCH64(_INS_EXTR)
* ARM: extr
*/
static RzILOpEffect *extr(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *h = ARG(1, &bits);
RzILOpBitVector *l = ARG(2, &bits);
ut32 dist_bits = 6;
RzILOpBitVector *dist = ARG(3, &dist_bits);
if (!h || !l || !dist) {
rz_il_op_pure_free(h);
rz_il_op_pure_free(l);
rz_il_op_pure_free(dist);
return NULL;
}
return write_reg(REGID(0), UNSIGNED(bits, SHIFTR0(APPEND(h, l), dist)));
}
/**
* Capstone: ARM_INS_SVC
* ARM: svc
*/
static RzILOpEffect *svc(cs_insn *insn) {
return GOTO("svc");
}
static void label_svc(RzILVM *vm, RzILOpEffect *op) {
// stub, nothing to do here
}
/**
* Capstone: CS_AARCH64(_INS_HVC)
* ARM: hvc
*/
static RzILOpEffect *hvc(cs_insn *insn) {
return GOTO("hvc");
}
static void label_hvc(RzILVM *vm, RzILOpEffect *op) {
// stub, nothing to do here
}
static RzILOpEffect *load_effect(ut32 bits, bool is_signed, CS_aarch64_reg() dst_reg, RZ_OWN RzILOpBitVector *addr) {
RzILOpBitVector *val = bits == 8 ? LOAD(addr) : LOADW(bits, addr);
if (bits != 64) {
if (is_signed) {
if (is_wreg(dst_reg)) {
val = UNSIGNED(64, SIGNED(32, val));
} else {
val = SIGNED(64, val);
}
} else {
val = UNSIGNED(64, val);
}
}
dst_reg = xreg_of_reg(dst_reg);
return write_reg(dst_reg, val);
}
static RzILOpEffect *writeback(cs_insn *insn, size_t addr_op, RZ_BORROW RzILOpBitVector *addr) {
#if CS_NEXT_VERSION < 6
if (!insn->detail->CS_aarch64_.writeback || !is_xreg(MEMBASEID(addr_op))) {
#else
if (!insn->detail->writeback || !is_xreg(MEMBASEID(addr_op))) {
#endif
return NULL;
}
RzILOpBitVector *wbaddr = DUP(addr);
if (ISPOSTINDEX64()) {
// post-index
st64 disp = MEMDISP(addr_op);
if (disp > 0) {
wbaddr = ADD(wbaddr, U64(disp));
} else if (disp < 0) {
wbaddr = SUB(wbaddr, U64(-disp));
}
}
return write_reg(MEMBASEID(addr_op), wbaddr);
}
/**
* Capstone: CS_AARCH64(_INS_LDR), CS_AARCH64(_INS_LDRB), CS_AARCH64(_INS_LDRH), CS_AARCH64(_INS_LDRU), CS_AARCH64(_INS_LDRUB), CS_AARCH64(_INS_LDRUH),
* CS_AARCH64(_INS_LDRSW), CS_AARCH64(_INS_LDRSB), CS_AARCH64(_INS_LDRSH), CS_AARCH64(_INS_LDURSW), CS_AARCH64(_INS_LDURSB), CS_AARCH64(_INS_LDURSH),
* CS_AARCH64(_INS_LDAPR), CS_AARCH64(_INS_LDAPRB), CS_AARCH64(_INS_LDAPRH), CS_AARCH64(_INS_LDAPUR), CS_AARCH64(_INS_LDAPURB), CS_AARCH64(_INS_LDAPURH),
* CS_AARCH64(_INS_LDAPURSB), CS_AARCH64(_INS_LDAPURSH), CS_AARCH64(_INS_LDAPURSW), CS_AARCH64(_INS_LDAR), CS_AARCH64(_INS_LDARB), CS_AARCH64(_INS_LDARH),
* CS_AARCH64(_INS_LDAXP), CS_AARCH64(_INS_LDXP), CS_AARCH64(_INS_LDAXR), CS_AARCH64(_INS_LDAXRB), CS_AARCH64(_INS_LDAXRH),
* CS_AARCH64(_INS_LDLAR), CS_AARCH64(_INS_LDLARB), CS_AARCH64(_INS_LDLARH),
* CS_AARCH64(_INS_LDP), CS_AARCH64(_INS_LDNP), CS_AARCH64(_INS_LDPSW),
* CS_AARCH64(_INS_LDRAA), CS_AARCH64(_INS_LDRAB),
* CS_AARCH64(_INS_LDTR), CS_AARCH64(_INS_LDTRB), CS_AARCH64(_INS_LDTRH), CS_AARCH64(_INS_LDTRSW), CS_AARCH64(_INS_LDTRSB), CS_AARCH64(_INS_LDTRSH),
* CS_AARCH64(_INS_LDXR), CS_AARCH64(_INS_LDXRB), CS_AARCH64(_INS_LDXRH)
* ARM: ldr, ldrb, ldrh, ldru, ldrub, ldruh, ldrsw, ldrsb, ldrsh, ldursw, ldurwb, ldursh,
* ldapr, ldaprb, ldaprh, ldapur, ldapurb, ldapurh, ldapursb, ldapursh, ldapursw,
* ldaxp, ldxp, ldaxr, ldaxrb, ldaxrh, ldar, ldarb, ldarh,
* ldp, ldnp,
* ldtr, ldtrb, ldtrh, ldtrsw, ldtrsb, ldtrsh, ldxr, ldxrb, ldxrh
*/
static RzILOpEffect *ldr(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
bool pair = insn->id == CS_AARCH64(_INS_LDAXP) || insn->id == CS_AARCH64(_INS_LDXP) ||
insn->id == CS_AARCH64(_INS_LDP) || insn->id == CS_AARCH64(_INS_LDNP) || insn->id == CS_AARCH64(_INS_LDPSW);
if (pair && !ISREG(1)) {
return NULL;
}
ut32 bits = 64;
size_t addr_op = pair ? 2 : 1;
RzILOpBitVector *addr = ARG(addr_op, &bits);
if (!addr) {
return NULL;
}
CS_aarch64_reg() dst_reg = REGID(0);
ut64 loadsz;
bool is_signed = false;
switch (insn->id) {
case CS_AARCH64(_INS_LDRSB):
case CS_AARCH64(_INS_LDURSB):
case CS_AARCH64(_INS_LDTRSB):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDAPURSB):
#endif
is_signed = true;
// fallthrough
case CS_AARCH64(_INS_LDRB):
case CS_AARCH64(_INS_LDURB):
case CS_AARCH64(_INS_LDARB):
case CS_AARCH64(_INS_LDAXRB):
case CS_AARCH64(_INS_LDTRB):
case CS_AARCH64(_INS_LDXRB):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDLARB):
case CS_AARCH64(_INS_LDAPRB):
case CS_AARCH64(_INS_LDAPURB):
#endif
loadsz = 8;
break;
case CS_AARCH64(_INS_LDRSH):
case CS_AARCH64(_INS_LDURSH):
case CS_AARCH64(_INS_LDTRSH):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDAPURSH):
#endif
is_signed = true;
// fallthrough
case CS_AARCH64(_INS_LDRH):
case CS_AARCH64(_INS_LDURH):
case CS_AARCH64(_INS_LDARH):
case CS_AARCH64(_INS_LDAXRH):
case CS_AARCH64(_INS_LDTRH):
case CS_AARCH64(_INS_LDXRH):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDAPRH):
case CS_AARCH64(_INS_LDAPURH):
case CS_AARCH64(_INS_LDLARH):
#endif
loadsz = 16;
break;
case CS_AARCH64(_INS_LDRSW):
case CS_AARCH64(_INS_LDURSW):
case CS_AARCH64(_INS_LDPSW):
case CS_AARCH64(_INS_LDTRSW):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDAPURSW):
#endif
is_signed = true;
loadsz = 32;
break;
default:
// CS_AARCH64(_INS_LDR), CS_AARCH64(_INS_LDRU), CS_AARCH64(_INS_LDAPR), CS_AARCH64(_INS_LDAPUR), CS_AARCH64(_INS_LDAR), CS_AARCH64(_INS_LDAXR), CS_AARCH64(_INS_LDLAR),
// CS_AARCH64(_INS_LDP), CS_AARCH64(_INS_LDNP), CS_AARCH64(_INS_LDRAA), CS_AARCH64(_INS_LDRAB), CS_AARCH64(_INS_LDTR), CS_AARCH64(_INS_LDXR)
loadsz = is_wreg(dst_reg) ? 32 : 64;
break;
}
RzILOpEffect *eff = NULL;
if (pair) {
eff = SETL("addr", addr);
addr = VARL("addr");
}
RzILOpEffect *eff1 = load_effect(loadsz, is_signed, dst_reg, addr);
if (!eff1) {
return NULL;
}
eff = eff ? SEQ2(eff, eff1) : eff1;
if (pair) {
RzILOpEffect *eff1 = load_effect(loadsz, is_signed, REGID(1), ADD(DUP(addr), U64(loadsz / 8)));
if (!eff1) {
rz_il_op_effect_free(eff);
return NULL;
}
eff = SEQ2(eff, eff1);
}
RzILOpEffect *wb_eff = writeback(insn, addr_op, addr);
if (wb_eff) {
eff = SEQ2(eff, wb_eff);
}
return eff;
}
/**
* Capstone: CS_AARCH64(_INS_STR), CS_AARCH64(_INS_STUR), CS_AARCH64(_INS_STRB), CS_AARCH64(_INS_STURB), CS_AARCH64(_INS_STRH), CS_AARCH64(_INS_STURH),
* CS_AARCH64(_INS_STLLR), CS_AARCH64(_INS_STLLRB), CS_AARCH64(_INS_STLLRH), CS_AARCH64(_INS_STLR), CS_AARCH64(_INS_STLRB), CS_AARCH64(_INS_STLRH),
* CS_AARCH64(_INS_STLUR), CS_AARCH64(_INS_STLURB), CS_AARCH64(_INS_STLURH), CS_AARCH64(_INS_STP), CS_AARCH64(_INS_STXR), CS_AARCH64(_INS_STXRB),
* CS_AARCH64(_INS_STXRH), CS_AARCH64(_INS_STXP), CS_AARCH64(_INS_STLXR), CS_AARCH64(_INS_STLXRB). CS_AARCH64(_INS_STLXRH), CS_AARCH64(_INS_STLXP),
* CS_AARCH64(_INS_STNP), CS_AARCH64(_INS_STTR), CS_AARCH64(_INS_STTRB), CS_AARCH64(_INS_STTRH)
* ARM: str, stur, strb, sturb, strh, sturh, stllr, stllrb, stllrh, stlr, stlrb, stlrh, stlur, stlurb, stlurh, stp, stxr, stxrb,
* stxrh, stxp, stlxr, stlxrb. stlxrh, stlxp, stnp, sttr, sttrb, sttrh
*/
static RzILOpEffect *str(cs_insn *insn) {
if (!ISREG(0) || !REGBITS(0)) {
return NULL;
}
bool result = insn->id == CS_AARCH64(_INS_STXR) || insn->id == CS_AARCH64(_INS_STXRB) || insn->id == CS_AARCH64(_INS_STXRH) || insn->id == CS_AARCH64(_INS_STXP) ||
insn->id == CS_AARCH64(_INS_STLXR) || insn->id == CS_AARCH64(_INS_STLXRB) || insn->id == CS_AARCH64(_INS_STLXRH) || insn->id == CS_AARCH64(_INS_STLXP);
bool pair = insn->id == CS_AARCH64(_INS_STP) || insn->id == CS_AARCH64(_INS_STNP) || insn->id == CS_AARCH64(_INS_STXP) || insn->id == CS_AARCH64(_INS_STLXP);
size_t src_op = result ? 1 : 0;
size_t addr_op = (result ? 1 : 0) + 1 + (pair ? 1 : 0);
ut32 addr_bits = 64;
RzILOpBitVector *addr = ARG(addr_op, &addr_bits);
if (!addr) {
return NULL;
}
ut32 bits;
switch (insn->id) {
case CS_AARCH64(_INS_STRB):
case CS_AARCH64(_INS_STURB):
case CS_AARCH64(_INS_STLRB):
case CS_AARCH64(_INS_STXRB):
case CS_AARCH64(_INS_STLXRB):
case CS_AARCH64(_INS_STTRB):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_STLLRB):
case CS_AARCH64(_INS_STLURB):
#endif
bits = 8;
break;
case CS_AARCH64(_INS_STRH):
case CS_AARCH64(_INS_STURH):
case CS_AARCH64(_INS_STLRH):
case CS_AARCH64(_INS_STXRH):
case CS_AARCH64(_INS_STLXRH):
case CS_AARCH64(_INS_STTRH):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_STLLRH):
case CS_AARCH64(_INS_STLURH):
#endif
bits = 16;
break;
default:
// CS_AARCH64(_INS_STR), CS_AARCH64(_INS_STUR), CS_AARCH64(_INS_STLLR), CS_AARCH64(_INS_STLR), CS_AARCH64(_INS_STLUR), CS_AARCH64(_INS_STP),
// CS_AARCH64(_INS_STXR), CS_AARCH64(_INS_STXP), CS_AARCH64(_INS_STLXR), CS_AARCH64(_INS_STLXP), CS_AARCH64(_INS_STNP), CS_AARCH64(_INS_STTR)
bits = REGBITS(src_op);
if (!bits) {
rz_il_op_pure_free(addr);
return NULL;
}
break;
}
RzILOpBitVector *val = ARG(src_op, &bits);
if (!val) {
rz_il_op_pure_free(addr);
return NULL;
}
RzILOpBitVector *val2 = NULL;
if (pair) {
val2 = ARG(src_op + 1, &bits);
if (!val2) {
rz_il_op_pure_free(val);
rz_il_op_pure_free(addr);
return NULL;
}
}
RzILOpEffect *eff = bits == 8 ? STORE(addr, val) : STOREW(addr, val);
if (pair) {
RzILOpBitVector *addr2 = ADD(DUP(addr), U64(bits / 8));
eff = SEQ2(eff, bits == 8 ? STORE(addr2, val2) : STOREW(addr2, val2));
}
RzILOpEffect *wb_eff = writeback(insn, addr_op, addr);
if (wb_eff) {
eff = SEQ2(eff, wb_eff);
}
if (result) {
// always successful
RzILOpEffect *res_eff = write_reg(REGID(0), UN(REGBITS(0), 0));
if (!res_eff) {
rz_il_op_effect_free(eff);
return NULL;
}
eff = SEQ2(eff, res_eff);
}
return eff;
}
#if CS_API_MAJOR > 4
/**
* Capstone: CS_AARCH64(_INS_LDADD), CS_AARCH64(_INS_LDADDA), CS_AARCH64(_INS_LDADDAL), CS_AARCH64(_INS_LDADDL),
* CS_AARCH64(_INS_LDADDB), CS_AARCH64(_INS_LDADDAB), CS_AARCH64(_INS_LDADDALB), CS_AARCH64(_INS_LDADDLB),
* CS_AARCH64(_INS_LDADDH), CS_AARCH64(_INS_LDADDAH), CS_AARCH64(_INS_LDADDALH), CS_AARCH64(_INS_LDADDLH),
* CS_AARCH64(_INS_STADD), CS_AARCH64(_INS_STADDL), CS_AARCH64(_INS_STADDB), CS_AARCH64(_INS_STADDLB), CS_AARCH64(_INS_STADDH), CS_AARCH64(_INS_STADDLH),
* CS_AARCH64(_INS_LDCLRB), CS_AARCH64(_INS_LDCLRAB), CS_AARCH64(_INS_LDCLRALB), CS_AARCH64(_INS_LDCLRLB),
* CS_AARCH64(_INS_LDCLRH), CS_AARCH64(_INS_LDCLRAH), CS_AARCH64(_INS_LDCLRALH), CS_AARCH64(_INS_LDCLRLH)
* CS_AARCH64(_INS_LDCLR), CS_AARCH64(_INS_LDCLRA), CS_AARCH64(_INS_LDCLRAL), CS_AARCH64(_INS_LDCLRL),
* CS_AARCH64(_INS_STSETB), CS_AARCH64(_INS_STSETLB), CS_AARCH64(_INS_STSETH), CS_AARCH64(_INS_STSETLH), CS_AARCH64(_INS_STSET), CS_AARCH64(_INS_STSETL),
* CS_AARCH64(_INS_LDSETB), CS_AARCH64(_INS_LDSETAB), CS_AARCH64(_INS_LDSETALB), CS_AARCH64(_INS_LDSETLB),
* CS_AARCH64(_INS_LDSETH), CS_AARCH64(_INS_LDSETAH), CS_AARCH64(_INS_LDSETALH), CS_AARCH64(_INS_LDSETLH)
* CS_AARCH64(_INS_LDSET), CS_AARCH64(_INS_LDSETA), CS_AARCH64(_INS_LDSETAL), CS_AARCH64(_INS_LDSETL),
* CS_AARCH64(_INS_STSETB), CS_AARCH64(_INS_STSETLB), CS_AARCH64(_INS_STSETH), CS_AARCH64(_INS_STSETLH), CS_AARCH64(_INS_STSET), CS_AARCH64(_INS_STSETL),
* CS_AARCH64(_INS_LDSMAXB), CS_AARCH64(_INS_LDSMAXAB), CS_AARCH64(_INS_LDSMAXALB), CS_AARCH64(_INS_LDSMAXLB),
* CS_AARCH64(_INS_LDSMAXH), CS_AARCH64(_INS_LDSMAXAH), CS_AARCH64(_INS_LDSMAXALH), CS_AARCH64(_INS_LDSMAXLH)
* CS_AARCH64(_INS_LDSMAX), CS_AARCH64(_INS_LDSMAXA), CS_AARCH64(_INS_LDSMAXAL), CS_AARCH64(_INS_LDSMAXL),
* CS_AARCH64(_INS_STSMAXB), CS_AARCH64(_INS_STSMAXLB), CS_AARCH64(_INS_STSMAXH), CS_AARCH64(_INS_STSMAXLH), CS_AARCH64(_INS_STSMAX), CS_AARCH64(_INS_STSMAXL),
* CS_AARCH64(_INS_LDSMINB), CS_AARCH64(_INS_LDSMINAB), CS_AARCH64(_INS_LDSMINALB), CS_AARCH64(_INS_LDSMINLB),
* CS_AARCH64(_INS_LDSMINH), CS_AARCH64(_INS_LDSMINAH), CS_AARCH64(_INS_LDSMINALH), CS_AARCH64(_INS_LDSMINLH)
* CS_AARCH64(_INS_LDSMIN), CS_AARCH64(_INS_LDSMINA), CS_AARCH64(_INS_LDSMINAL), CS_AARCH64(_INS_LDSMINL),
* CS_AARCH64(_INS_STSMINB), CS_AARCH64(_INS_STSMINLB), CS_AARCH64(_INS_STSMINH), CS_AARCH64(_INS_STSMINLH), CS_AARCH64(_INS_STSMIN), CS_AARCH64(_INS_STSMINL),
* CS_AARCH64(_INS_LDUMAXB), CS_AARCH64(_INS_LDUMAXAB), CS_AARCH64(_INS_LDUMAXALB), CS_AARCH64(_INS_LDUMAXLB),
* CS_AARCH64(_INS_LDUMAXH), CS_AARCH64(_INS_LDUMAXAH), CS_AARCH64(_INS_LDUMAXALH), CS_AARCH64(_INS_LDUMAXLH)
* CS_AARCH64(_INS_LDUMAX), CS_AARCH64(_INS_LDUMAXA), CS_AARCH64(_INS_LDUMAXAL), CS_AARCH64(_INS_LDUMAXL),
* CS_AARCH64(_INS_STUMAXB), CS_AARCH64(_INS_STUMAXLB), CS_AARCH64(_INS_STUMAXH), CS_AARCH64(_INS_STUMAXLH), CS_AARCH64(_INS_STUMAX), CS_AARCH64(_INS_STUMAXL),
* CS_AARCH64(_INS_LDUMINB), CS_AARCH64(_INS_LDUMINAB), CS_AARCH64(_INS_LDUMINALB), CS_AARCH64(_INS_LDUMINLB),
* CS_AARCH64(_INS_LDUMINH), CS_AARCH64(_INS_LDUMINAH), CS_AARCH64(_INS_LDUMINALH), CS_AARCH64(_INS_LDUMINLH)
* CS_AARCH64(_INS_LDUMIN), CS_AARCH64(_INS_LDUMINA), CS_AARCH64(_INS_LDUMINAL), CS_AARCH64(_INS_LDUMINL),
* CS_AARCH64(_INS_STUMINB), CS_AARCH64(_INS_STUMINLB), CS_AARCH64(_INS_STUMINH), CS_AARCH64(_INS_STUMINLH), CS_AARCH64(_INS_STUMIN), CS_AARCH64(_INS_STUMINL)
* ARM: ldadd, ldadda, ldaddal, ldaddl, ldaddb, ldaddab, ldaddalb, ldaddlb, ldaddh, ldaddah, ldaddalh, ldaddlh,
* stadd, staddl, staddb, staddlb, stadd,
* ldclr, ldclra, ldclral, ldclrl, ldclrb, ldclrab, ldclralb, ldclrlb, ldclrh, ldclrah, ldclralh, ldclrlh,
* stclr, stclrl, stclrb, stclrlb, stclr,
* ldset, ldseta, ldsetal, ldsetl, ldsetb, ldsetab, ldsetalb, ldsetlb, ldseth, ldsetah, ldsetalh, ldsetlh,
* stset, stsetl, stsetb, stsetlb, stset,
* ldsmax, ldsmaxa, ldsmaxal, ldsmaxl, ldsmaxb, ldsmaxab, ldsmaxalb, ldsmaxlb, ldsmaxh, ldsmaxah, ldsmaxalh, ldsmaxlh,
* stsmax, stsmaxl, stsmaxb, stsmaxlb, stsmax,
* ldsmin, ldsmina, ldsminal, ldsminl, ldsminb, ldsminab, ldsminalb, ldsminlb, ldsminh, ldsminah, ldsminalh, ldsminlh,
* stsmin, stsminl, stsminb, stsminlb, stsmin,
* ldumax, ldumaxa, ldumaxal, ldumaxl, ldumaxb, ldumaxab, ldumaxalb, ldumaxlb, ldumaxh, ldumaxah, ldumaxalh, ldumaxlh,
* stumax, stumaxl, stumaxb, stumaxlb, stumax,
* ldumin, ldumina, lduminal, lduminl, lduminb, lduminab, lduminalb, lduminlb, lduminh, lduminah, lduminalh, lduminlh,
* stumin, stuminl, stuminb, stuminlb, stumin
*/
static RzILOpEffect *ldadd(cs_insn *insn) {
size_t addr_op = OPCOUNT() == 3 ? 2 : 1;
if (!ISMEM(addr_op)) {
return NULL;
}
CS_aarch64_reg() addend_reg = REGID(0);
ut64 loadsz;
enum {
OP_ADD,
OP_CLR,
OP_EOR,
OP_SET,
OP_SMAX,
OP_SMIN,
OP_UMAX,
OP_UMIN
} op = OP_ADD;
switch (insn->id) {
case CS_AARCH64(_INS_LDCLRB):
case CS_AARCH64(_INS_LDCLRAB):
case CS_AARCH64(_INS_LDCLRALB):
case CS_AARCH64(_INS_LDCLRLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STCLRB):
case CS_AARCH64(_INS_STCLRLB):
#endif
op = OP_CLR;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDEORB):
case CS_AARCH64(_INS_LDEORAB):
case CS_AARCH64(_INS_LDEORALB):
case CS_AARCH64(_INS_LDEORLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STEORB):
case CS_AARCH64(_INS_STEORLB):
#endif
op = OP_EOR;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDSETB):
case CS_AARCH64(_INS_LDSETAB):
case CS_AARCH64(_INS_LDSETALB):
case CS_AARCH64(_INS_LDSETLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSETB):
case CS_AARCH64(_INS_STSETLB):
#endif
op = OP_SET;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDSMAXB):
case CS_AARCH64(_INS_LDSMAXAB):
case CS_AARCH64(_INS_LDSMAXALB):
case CS_AARCH64(_INS_LDSMAXLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMAXB):
case CS_AARCH64(_INS_STSMAXLB):
#endif
op = OP_SMAX;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDSMINB):
case CS_AARCH64(_INS_LDSMINAB):
case CS_AARCH64(_INS_LDSMINALB):
case CS_AARCH64(_INS_LDSMINLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMINB):
case CS_AARCH64(_INS_STSMINLB):
#endif
op = OP_SMIN;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDUMAXB):
case CS_AARCH64(_INS_LDUMAXAB):
case CS_AARCH64(_INS_LDUMAXALB):
case CS_AARCH64(_INS_LDUMAXLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMAXB):
case CS_AARCH64(_INS_STUMAXLB):
#endif
op = OP_UMAX;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDUMINB):
case CS_AARCH64(_INS_LDUMINAB):
case CS_AARCH64(_INS_LDUMINALB):
case CS_AARCH64(_INS_LDUMINLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMINB):
case CS_AARCH64(_INS_STUMINLB):
#endif
op = OP_UMIN;
loadsz = 8;
break;
case CS_AARCH64(_INS_LDADDB):
case CS_AARCH64(_INS_LDADDAB):
case CS_AARCH64(_INS_LDADDALB):
case CS_AARCH64(_INS_LDADDLB):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STADDB):
case CS_AARCH64(_INS_STADDLB):
#endif
loadsz = 8;
break;
case CS_AARCH64(_INS_LDCLRH):
case CS_AARCH64(_INS_LDCLRAH):
case CS_AARCH64(_INS_LDCLRALH):
case CS_AARCH64(_INS_LDCLRLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STCLRH):
case CS_AARCH64(_INS_STCLRLH):
#endif
op = OP_CLR;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDEORH):
case CS_AARCH64(_INS_LDEORAH):
case CS_AARCH64(_INS_LDEORALH):
case CS_AARCH64(_INS_LDEORLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STEORH):
case CS_AARCH64(_INS_STEORLH):
#endif
op = OP_EOR;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDSETH):
case CS_AARCH64(_INS_LDSETAH):
case CS_AARCH64(_INS_LDSETALH):
case CS_AARCH64(_INS_LDSETLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSETH):
case CS_AARCH64(_INS_STSETLH):
#endif
op = OP_SET;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDSMAXH):
case CS_AARCH64(_INS_LDSMAXAH):
case CS_AARCH64(_INS_LDSMAXALH):
case CS_AARCH64(_INS_LDSMAXLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMAXH):
case CS_AARCH64(_INS_STSMAXLH):
#endif
op = OP_SMAX;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDSMINH):
case CS_AARCH64(_INS_LDSMINAH):
case CS_AARCH64(_INS_LDSMINALH):
case CS_AARCH64(_INS_LDSMINLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMINH):
case CS_AARCH64(_INS_STSMINLH):
#endif
op = OP_SMIN;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDUMAXH):
case CS_AARCH64(_INS_LDUMAXAH):
case CS_AARCH64(_INS_LDUMAXALH):
case CS_AARCH64(_INS_LDUMAXLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMAXH):
case CS_AARCH64(_INS_STUMAXLH):
#endif
op = OP_UMAX;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDUMINH):
case CS_AARCH64(_INS_LDUMINAH):
case CS_AARCH64(_INS_LDUMINALH):
case CS_AARCH64(_INS_LDUMINLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMINH):
case CS_AARCH64(_INS_STUMINLH):
#endif
op = OP_UMIN;
loadsz = 16;
break;
case CS_AARCH64(_INS_LDADDH):
case CS_AARCH64(_INS_LDADDAH):
case CS_AARCH64(_INS_LDADDALH):
case CS_AARCH64(_INS_LDADDLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STADDH):
case CS_AARCH64(_INS_STADDLH):
#endif
loadsz = 16;
break;
case CS_AARCH64(_INS_LDCLR):
case CS_AARCH64(_INS_LDCLRA):
case CS_AARCH64(_INS_LDCLRAL):
case CS_AARCH64(_INS_LDCLRL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STCLR):
case CS_AARCH64(_INS_STCLRL):
#endif
op = OP_CLR;
goto size_from_reg;
case CS_AARCH64(_INS_LDEOR):
case CS_AARCH64(_INS_LDEORA):
case CS_AARCH64(_INS_LDEORAL):
case CS_AARCH64(_INS_LDEORL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STEOR):
case CS_AARCH64(_INS_STEORL):
#endif
op = OP_EOR;
goto size_from_reg;
case CS_AARCH64(_INS_LDSET):
case CS_AARCH64(_INS_LDSETA):
case CS_AARCH64(_INS_LDSETAL):
case CS_AARCH64(_INS_LDSETL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSET):
case CS_AARCH64(_INS_STSETL):
#endif
op = OP_SET;
goto size_from_reg;
case CS_AARCH64(_INS_LDSMAX):
case CS_AARCH64(_INS_LDSMAXA):
case CS_AARCH64(_INS_LDSMAXAL):
case CS_AARCH64(_INS_LDSMAXL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMAX):
case CS_AARCH64(_INS_STSMAXL):
#endif
op = OP_SMAX;
goto size_from_reg;
case CS_AARCH64(_INS_LDSMIN):
case CS_AARCH64(_INS_LDSMINA):
case CS_AARCH64(_INS_LDSMINAL):
case CS_AARCH64(_INS_LDSMINL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMIN):
case CS_AARCH64(_INS_STSMINL):
#endif
op = OP_SMIN;
goto size_from_reg;
case CS_AARCH64(_INS_LDUMAX):
case CS_AARCH64(_INS_LDUMAXA):
case CS_AARCH64(_INS_LDUMAXAL):
case CS_AARCH64(_INS_LDUMAXL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMAX):
case CS_AARCH64(_INS_STUMAXL):
#endif
op = OP_UMAX;
goto size_from_reg;
case CS_AARCH64(_INS_LDUMIN):
case CS_AARCH64(_INS_LDUMINA):
case CS_AARCH64(_INS_LDUMINAL):
case CS_AARCH64(_INS_LDUMINL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMIN):
case CS_AARCH64(_INS_STUMINL):
#endif
op = OP_UMIN;
// fallthrough
size_from_reg:
default: // CS_AARCH64(_INS_LDADD), CS_AARCH64(_INS_LDADDA), CS_AARCH64(_INS_LDADDAL), CS_AARCH64(_INS_LDADDL), CS_AARCH64(_INS_STADD), CS_AARCH64(_INS_STADDL)
loadsz = is_wreg(addend_reg) ? 32 : 64;
break;
}
ut32 bits = 64;
RzILOpBitVector *addr = ARG(addr_op, &bits);
if (!addr) {
return NULL;
}
addend_reg = xreg_of_reg(addend_reg);
RzILOpEffect *ld_eff = NULL;
if (OPCOUNT() == 3) {
// LDADD... instead of STADD, which does not have a dst reg
if (!ISREG(1)) {
rz_il_op_pure_free(addr);
return NULL;
}
CS_aarch64_reg() dst_reg = REGID(1);
dst_reg = xreg_of_reg(dst_reg);
ld_eff = write_reg(dst_reg, loadsz != 64 ? UNSIGNED(64, VARL("old")) : VARL("old"));
if (!ld_eff) {
rz_il_op_pure_free(addr);
return NULL;
}
}
RzILOpBitVector *res = read_reg(addend_reg);
if (!res) {
rz_il_op_effect_free(ld_eff);
return NULL;
}
if (loadsz != 64) {
res = UNSIGNED(loadsz, res);
}
switch (op) {
case OP_CLR:
res = LOGAND(VARL("old"), LOGNOT(res));
break;
case OP_EOR:
res = LOGXOR(VARL("old"), res);
break;
case OP_SET:
res = LOGOR(VARL("old"), res);
break;
case OP_SMAX:
res = LET("r", res, ITE(SLE(VARL("old"), VARLP("r")), VARLP("r"), VARL("old")));
break;
case OP_SMIN:
res = LET("r", res, ITE(SLE(VARL("old"), VARLP("r")), VARL("old"), VARLP("r")));
break;
case OP_UMAX:
res = LET("r", res, ITE(ULE(VARL("old"), VARLP("r")), VARLP("r"), VARL("old")));
break;
case OP_UMIN:
res = LET("r", res, ITE(ULE(VARL("old"), VARLP("r")), VARL("old"), VARLP("r")));
break;
default: // OP_ADD
res = ADD(VARL("old"), res);
break;
}
RzILOpEffect *eff = SEQ2(
SETL("old", loadsz == 8 ? LOAD(addr) : LOADW(loadsz, addr)),
loadsz == 8 ? STORE(DUP(addr), res) : STOREW(DUP(addr), res));
if (ld_eff) {
eff = SEQ2(eff, ld_eff);
}
return eff;
}
#endif
/**
* Capstone: CS_AARCH64(_INS_MADD), CS_AARCH64(_INS_MSUB)
* ARM: madd, msub
*/
static RzILOpEffect *madd(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *ma = ARG(1, &bits);
RzILOpBitVector *mb = ARG(2, &bits);
RzILOpBitVector *addend = ARG(3, &bits);
if (!ma || !mb || !addend) {
return NULL;
}
RzILOpBitVector *res;
if (insn->id == CS_AARCH64(_INS_MSUB)) {
res = SUB(addend, MUL(ma, mb));
} else {
res = ADD(MUL(ma, mb), addend);
}
return write_reg(REGID(0), res);
}
/**
* Capstone: CS_AARCH64(_INS_MUL), CS_AARCH64(_INS_MNEG)
* ARM: mul, mneg
*/
static RzILOpEffect *mul(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *ma = ARG(1, &bits);
RzILOpBitVector *mb = ARG(2, &bits);
if (!ma || !mb) {
rz_il_op_pure_free(ma);
rz_il_op_pure_free(mb);
return NULL;
}
RzILOpBitVector *res = MUL(ma, mb);
#if CS_NEXT_VERSION < 6
if (insn->id == CS_AARCH64(_INS_MNEG)) {
res = NEG(res);
}
#else
if (insn->alias_id == AArch64_INS_ALIAS_MNEG) {
res = NEG(res);
}
#endif
return write_reg(REGID(0), res);
}
static RzILOpEffect *movn(cs_insn *insn);
/**
* Capstone: CS_AARCH64(_INS_MOV), CS_AARCH64(_INS_MOVZ)
* ARM: mov, movz
*/
static RzILOpEffect *mov(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
#if CS_NEXT_VERSION < 6
if (ISIMM(1) && IMM(1) == 0 && !strcmp(insn->mnemonic, "movn")) {
// Capstone bug making 0000a012 indistinguishable from 0000a052
// https://github.com/capstone-engine/capstone/issues/1857
return movn(insn);
}
#endif
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
#if CS_NEXT_VERSION < 6
RzILOpBitVector *src = ARG(1, &bits);
#else
RzILOpBitVector *src = NULL;
if ((insn->alias_id == AArch64_INS_ALIAS_MOV || insn->alias_id == AArch64_INS_ALIAS_MOVZ) &&
(REGID(1) == AArch64_REG_XZR || REGID(1) == AArch64_REG_WZR)) {
// Sometimes regs are ORed with the zero register for the MOV alias.
// Sometimes not.
src = ARG(2, &bits);
} else {
src = ARG(1, &bits);
}
#endif
if (!src) {
return NULL;
}
return write_reg(REGID(0), src);
}
/**
* Capstone: CS_AARCH64(_INS_MOVK)
* ARM: movk
*/
static RzILOpEffect *movk(cs_insn *insn) {
if (!ISREG(0) || !ISIMM(1)) {
return NULL;
}
ut32 bits = 0;
RzILOpBitVector *src = ARG(0, &bits);
if (!src) {
return NULL;
}
CS_aarch64_op() *op = &insn->detail->CS_aarch64_.operands[1];
ut32 shift = op->shift.type == CS_AARCH64(_SFT_LSL) ? op->shift.value : 0;
return write_reg(REGID(0), LOGOR(LOGAND(src, UN(bits, ~(0xffffull << shift))), UN(bits, ((ut64)op->imm) << shift)));
}
/**
* Capstone: CS_AARCH64(_INS_MOVN)
* ARM: movn
*/
static RzILOpEffect *movn(cs_insn *insn) {
if (!ISREG(0) || !ISIMM(1)) {
return NULL;
}
// The only case where the movn encoding should be disassembled as "movn" is
// when (IsZero(imm16) && hw != '00'), according to the "alias conditions" in the reference manual.
// Unfortunately, capstone v4 seems to always disassemble as movn, so we still have to implement this.
CS_aarch64_op() *op = &insn->detail->CS_aarch64_.operands[1];
ut32 shift = op->shift.type == CS_AARCH64(_SFT_LSL) ? op->shift.value : 0;
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
return write_reg(REGID(0), UN(bits, ~(((ut64)op->imm) << shift)));
}
/**
* Capstone: CS_AARCH64(_INS_MSR)
* ARM: msr
*/
static RzILOpEffect *msr(cs_insn *insn) {
CS_aarch64_op() *op = &insn->detail->CS_aarch64_.operands[0];
#if CS_NEXT_VERSION >= 6
if (op->type != CS_AARCH64(_OP_SYSREG) || (ut64)op->sysop.reg.sysreg != (ut64)CS_AARCH64(_SYSREG_NZCV)) {
return NULL;
}
#elif CS_API_MAJOR > 4 && CS_NEXT_VERSION < 6
if (op->type != CS_AARCH64(_OP_SYS) || (ut64)op->sys != (ut64)ARM64_SYSREG_NZCV) {
return NULL;
}
#else
if (op->type != CS_AARCH64(_OP_REG_MSR) || op->reg != 0xda10) {
return NULL;
}
#endif
ut32 bits = 0;
RzILOpBitVector *val = ARG(1, &bits);
if (!val) {
return NULL;
}
return SEQ4(
SETG("nf", INV(IS_ZERO(LOGAND(val, UN(bits, 1ull << 31))))),
SETG("zf", INV(IS_ZERO(LOGAND(DUP(val), UN(bits, 1ull << 30))))),
SETG("cf", INV(IS_ZERO(LOGAND(DUP(val), UN(bits, 1ull << 29))))),
SETG("vf", INV(IS_ZERO(LOGAND(DUP(val), UN(bits, 1ull << 28))))));
}
#if CS_API_MAJOR > 4
/**
* Capstone: CS_AARCH64(_INS_RMIF)
* ARM: rmif
*/
static RzILOpEffect *rmif(cs_insn *insn) {
if (!ISIMM(1) || !ISIMM(2)) {
return NULL;
}
ut32 bits = 64;
RzILOpBitVector *val = ARG(0, &bits);
if (!val) {
return NULL;
}
ut64 lsb = IMM(1);
ut64 mask = IMM(2);
RzILOpEffect *eff = NULL;
const char *flags[] = { "vf", "cf", "zf", "nf" };
for (size_t i = 0; i < RZ_ARRAY_SIZE(flags); i++) {
if (!(mask & (1ull << i))) {
continue;
}
if (eff) {
val = DUP(val);
}
RzILOpEffect *set = SETG(flags[i], INV(IS_ZERO(LOGAND(val, UN(bits, 1ull << ((i + lsb) % 64))))));
eff = eff ? SEQ2(set, eff) : set;
}
if (!eff) {
rz_il_op_pure_free(val);
}
return eff ? eff : NOP();
}
#endif
/**
* Capstone: CS_AARCH64(_INS_SBFX), CS_AARCH64(_INS_SBFIZ), CS_AARCH64(_INS_UBFX), CS_AARCH64(_INS_UBFIZ)
* ARM: sbfx, sbfiz, ubfx, ubfiz
*/
static RzILOpEffect *usbfm(cs_insn *insn) {
if (!ISREG(0) || !ISIMM(2) || !ISIMM(3)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *src = ARG(1, &bits);
if (!src) {
return NULL;
}
ut64 lsb = IMM(2);
ut64 width = IMM(3);
RzILOpBitVector *res;
#if CS_NEXT_VERSION < 6
if (insn->id == CS_AARCH64(_INS_SBFIZ) || insn->id == CS_AARCH64(_INS_UBFIZ)) {
res = SHIFTL0(UNSIGNED(width + lsb, src), UN(6, lsb));
} else {
// CS_AARCH64(_INS_SBFX), CS_AARCH64(_INS_UBFX)
res = UNSIGNED(width, SHIFTR0(src, UN(6, lsb)));
}
bool is_signed = insn->id == CS_AARCH64(_INS_SBFX) || insn->id == CS_AARCH64(_INS_SBFIZ);
#else
if (insn->alias_id == AArch64_INS_ALIAS_SBFIZ || insn->alias_id == AArch64_INS_ALIAS_UBFIZ) {
// TODO: modulo usage depends on N and SF bit.
// sf == 0 && N == 0 => mod 32.
// sf == 1 && N == 1 => mod 64.
width += 1;
lsb = -lsb % 64;
res = SHIFTL0(UNSIGNED(width + lsb, src), UN(6, lsb));
} else if (insn->alias_id == AArch64_INS_ALIAS_SBFX || insn->alias_id == AArch64_INS_ALIAS_UBFX) {
width = width - lsb + 1;
res = UNSIGNED(width, SHIFTR0(src, UN(6, lsb)));
} else if (insn->alias_id == AArch64_INS_ALIAS_LSL) {
// imms != 0x1f => mod 32
// imms != 0x3f => mod 64
ut32 m = IMM(3) != 0x1f ? 32 : 64;
return write_reg(REGID(0), SHIFTL0(src, UN(6, -IMM(2) % m)));
} else if (insn->alias_id == AArch64_INS_ALIAS_LSR) {
return write_reg(REGID(0), SHIFTR0(src, UN(6, IMM(2))));
} else if (insn->alias_id == AArch64_INS_ALIAS_ASR) {
return write_reg(REGID(0), SHIFTR(MSB(src), DUP(src), UN(6, IMM(2))));
} else {
return NULL;
}
bool is_signed = insn->alias_id == AArch64_INS_ALIAS_SBFX || insn->alias_id == AArch64_INS_ALIAS_SBFIZ;
#endif
res = LET("res", res, is_signed ? SIGNED(bits, VARLP("res")) : UNSIGNED(bits, VARLP("res")));
return write_reg(REGID(0), res);
}
/**
* Capstone: CS_AARCH64(_INS_MRS)
* ARM: mrs
*/
static RzILOpEffect *mrs(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
CS_aarch64_op() *op = &insn->detail->CS_aarch64_.operands[1];
#if CS_NEXT_VERSION >= 6
if (op->type != CS_AARCH64(_OP_SYSREG) || (ut64)op->sysop.reg.sysreg != (ut64)CS_AARCH64(_SYSREG_NZCV)) {
return NULL;
}
#elif CS_API_MAJOR > 4 && CS_NEXT_VERSION < 6
if (op->type != CS_AARCH64(_OP_SYS) || (ut64)op->sys != (ut64)ARM64_SYSREG_NZCV) {
return NULL;
}
#else
if (op->type != CS_AARCH64(_OP_REG_MRS) || op->reg != 0xda10) {
return NULL;
}
#endif
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
return write_reg(REGID(0),
LOGOR(ITE(VARG("nf"), UN(bits, 1ull << 31), UN(bits, 0)),
LOGOR(ITE(VARG("zf"), UN(bits, 1ull << 30), UN(bits, 0)),
LOGOR(ITE(VARG("cf"), UN(bits, 1ull << 29), UN(bits, 0)),
ITE(VARG("vf"), UN(bits, 1ull << 28), UN(bits, 0))))));
}
/**
* Capstone: CS_AARCH64(_INS_MVN), CS_AARCH64(_INS_NEG), CS_AARCH64(_INS_NEGS), CS_AARCH64(_INS_NGC), CS_AARCH64(_INS_NGCS)
* ARM: mvn, neg, negs, ngc, ngcs
*/
static RzILOpEffect *mvn(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = 0;
#if CS_NEXT_VERSION < 6
RzILOpBitVector *val = ARG(1, &bits);
#else
// Reg at 1 is zero register
RzILOpBitVector *val = ARG(2, &bits);
#endif
if (!val) {
return NULL;
}
RzILOpBitVector *res;
#if CS_NEXT_VERSION < 6
switch (insn->id) {
case CS_AARCH64(_INS_NEG):
case CS_AARCH64(_INS_NEGS):
res = NEG(val);
break;
case CS_AARCH64(_INS_NGC):
case CS_AARCH64(_INS_NGCS):
res = NEG(ADD(val, ITE(VARG("cf"), UN(bits, 0), UN(bits, 1))));
break;
default: // CS_AARCH64(_INS_MVN)
res = LOGNOT(val);
break;
}
#else
switch (insn->alias_id) {
case AArch64_INS_ALIAS_NEG:
case AArch64_INS_ALIAS_NEGS:
res = NEG(val);
break;
case AArch64_INS_ALIAS_NGC:
case AArch64_INS_ALIAS_NGCS:
res = NEG(ADD(val, ITE(VARG("cf"), UN(bits, 0), UN(bits, 1))));
break;
case AArch64_INS_ALIAS_MVN:
res = LOGNOT(val);
break;
default:
return NULL;
}
#endif
RzILOpEffect *set = write_reg(REGID(0), res);
if (!set) {
return NULL;
}
if (insn->detail->CS_aarch64_.update_flags) {
// MSVC pre-processor can't parse "#if CS_NEXT... SETG(...) ..." if it is inlined.
// So we define a variable here. Otherwise we get "error C2121".
#if CS_NEXT_VERSION < 6
RzILOpEffect *set_cf = SETG("cf", sub_carry(UN(bits, 0), VARL("b"), insn->id == CS_AARCH64(_INS_NGC), bits));
#else
RzILOpEffect *set_cf = SETG("cf", sub_carry(UN(bits, 0), VARL("b"), insn->alias_id == AArch64_INS_ALIAS_NGC, bits));
#endif
return SEQ5(
SETL("b", DUP(val)),
set,
set_cf,
SETG("vf", sub_overflow(UN(bits, 0), VARL("b"), REG(0))),
update_flags_zn(REG(0)));
}
return set;
}
/**
* Capstone: CS_AARCH64(_INS_RBIT)
* ARM: rbit
*/
static RzILOpEffect *rbit(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = 0;
RzILOpBitVector *v = ARG(1, &bits);
if (!v) {
return NULL;
}
RzILOpEffect *eff = write_reg(REGID(0), VARL("r"));
if (!eff) {
return NULL;
}
return SEQ5(
SETL("v", v),
SETL("i", UN(6, bits)),
SETL("r", UN(bits, 0x0)),
REPEAT(INV(IS_ZERO(VARL("v"))),
SEQ3(
SETL("i", SUB(VARL("i"), UN(6, 1))),
SETL("r", LOGOR(VARL("r"), ITE(LSB(VARL("v")), SHIFTL0(UN(bits, 1), VARL("i")), UN(bits, 0)))),
SETL("v", SHIFTR0(VARL("v"), UN(6, 1))))),
eff);
}
/**
* Capstone: CS_AARCH64(_INS_REV), CS_AARCH64(_INS_REV32), CS_AARCH64(_INS_REV16)
* ARM: rev, rev32, rev16
*/
static RzILOpEffect *rev(cs_insn *insn) {
if (!ISREG(0) || !ISREG(1)) {
return NULL;
}
ut32 dst_bits = REGBITS(0);
if (!dst_bits) {
return NULL;
}
CS_aarch64_reg() src_reg = xreg_of_reg(REGID(1));
ut32 container_bits = dst_bits;
if (insn->id == CS_AARCH64(_INS_REV32)) {
container_bits = 32;
} else if (insn->id == CS_AARCH64(_INS_REV16)) {
container_bits = 16;
}
RzILOpBitVector *src = read_reg(src_reg);
if (!src) {
return NULL;
}
RzILOpBitVector *res;
if (container_bits == 16) {
res = APPEND(
APPEND(
UNSIGNED(8, SHIFTR0(src, UN(6, 0x10))),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x18)))),
APPEND(
UNSIGNED(8, DUP(src)),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x8)))));
} else {
res = APPEND(
APPEND(
UNSIGNED(8, src),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x8)))),
APPEND(
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x10))),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x18)))));
}
if (dst_bits == 64) {
if (container_bits == 16) {
res = APPEND(
APPEND(
APPEND(
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x30))),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x38)))),
APPEND(
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x20))),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x28))))),
res);
} else {
RzILOpBitVector *high = APPEND(
APPEND(
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x20))),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x28)))),
APPEND(
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x30))),
UNSIGNED(8, SHIFTR0(DUP(src), UN(6, 0x38)))));
res = container_bits == 32 ? APPEND(high, res) : APPEND(res, high);
}
}
return write_reg(REGID(0), res);
}
/**
* Capstone: CS_AARCH64(_INS_SDIV)
* ARM: sdiv
*/
static RzILOpEffect *sdiv(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *a = ARG(1, &bits);
RzILOpBitVector *b = ARG(2, &bits);
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
return write_reg(REGID(0),
ITE(EQ(b, UN(bits, 0)), UN(bits, 0),
ITE(AND(EQ(a, UN(bits, 1ull << (bits - 1))), EQ(DUP(b), UN(bits, -1))),
UN(bits, 1ull << (bits - 1)),
SDIV(DUP(a), DUP(b)))));
}
/**
* Capstone: CS_AARCH64(_INS_UDIV)
* ARM: udiv
*/
static RzILOpEffect *udiv(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
ut32 bits = REGBITS(0);
if (!bits) {
return NULL;
}
RzILOpBitVector *a = ARG(1, &bits);
RzILOpBitVector *b = ARG(2, &bits);
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
return write_reg(REGID(0),
ITE(EQ(b, UN(bits, 0)), UN(bits, 0), DIV(a, DUP(b))));
}
#if CS_API_MAJOR > 4
/**
* Capstone: CS_AARCH64(_INS_SETF8), CS_AARCH64(_INS_SETF16)
* ARM: setf8, setf16
*/
static RzILOpEffect *setf(cs_insn *insn) {
if (!ISREG(0)) {
return NULL;
}
RzILOpBitVector *val = read_reg(xreg_of_reg(REGID(0)));
if (!val) {
return NULL;
}
ut32 bits = insn->id == CS_AARCH64(_INS_SETF16) ? 16 : 8;
return SEQ2(
SETG("vf", XOR(MSB(UNSIGNED(bits + 1, val)), MSB(UNSIGNED(bits, DUP(val))))),
update_flags_zn(UNSIGNED(bits, DUP(val))));
}
#endif
/**
* Capstone: CS_AARCH64(_INS_SMADDL), CS_AARCH64(_INS_SMSUBL), CS_AARCH64(_INS_UMADDL), CS_AARCH64(_INS_UMSUBL)
* ARM: smaddl, smsubl, umaddl, umsubl
*/
static RzILOpEffect *smaddl(cs_insn *insn) {
if (!ISREG(0) || REGBITS(0) != 64) {
return NULL;
}
ut32 bits = 32;
RzILOpBitVector *x = ARG(1, &bits);
RzILOpBitVector *y = ARG(2, &bits);
bits = 64;
RzILOpBitVector *addend = ARG(3, &bits);
if (!x || !y || !addend) {
rz_il_op_pure_free(x);
rz_il_op_pure_free(y);
rz_il_op_pure_free(addend);
return NULL;
}
bool is_signed = insn->id == CS_AARCH64(_INS_SMADDL) || insn->id == CS_AARCH64(_INS_SMSUBL);
RzILOpBitVector *res = MUL(is_signed ? SIGNED(64, x) : UNSIGNED(64, x), is_signed ? SIGNED(64, y) : UNSIGNED(64, y));
if (insn->id == CS_AARCH64(_INS_SMSUBL) || insn->id == CS_AARCH64(_INS_UMSUBL)) {
res = SUB(addend, res);
} else {
res = ADD(addend, res);
}
return write_reg(REGID(0), res);
}
/**
* Capstone: CS_AARCH64(_INS_SMULL), CS_AARCH64(_INS_SMNEGL), CS_AARCH64(_INS_UMULL), CS_AARCH64(_INS_UMNEGL)
* ARM: smull, smnegl, umull, umnegl
*/
static RzILOpEffect *smull(cs_insn *insn) {
if (!ISREG(0) || REGBITS(0) != 64) {
return NULL;
}
ut32 bits = 32;
RzILOpBitVector *x = ARG(1, &bits);
RzILOpBitVector *y = ARG(2, &bits);
if (!x || !y) {
rz_il_op_pure_free(x);
rz_il_op_pure_free(y);
return NULL;
}
#if CS_NEXT_VERSION < 6
bool is_signed = insn->id == CS_AARCH64(_INS_SMULL) || insn->id == CS_AARCH64(_INS_SMNEGL);
#else
bool is_signed = insn->alias_id == AArch64_INS_ALIAS_SMULL || insn->alias_id == AArch64_INS_ALIAS_SMNEGL;
#endif
RzILOpBitVector *res = MUL(is_signed ? SIGNED(64, x) : UNSIGNED(64, x), is_signed ? SIGNED(64, y) : UNSIGNED(64, y));
#if CS_NEXT_VERSION < 6
if (insn->id == CS_AARCH64(_INS_SMNEGL) || insn->id == CS_AARCH64(_INS_UMNEGL)) {
res = NEG(res);
}
#else
if (insn->alias_id == AArch64_INS_ALIAS_SMNEGL || insn->alias_id == AArch64_INS_ALIAS_UMNEGL) {
res = NEG(res);
}
#endif
return write_reg(REGID(0), res);
}
/**
* Capstone: CS_AARCH64(_INS_SMULH), CS_AARCH64(_INS_UMULH)
* ARM: smulh, umulh
*/
static RzILOpEffect *smulh(cs_insn *insn) {
if (!ISREG(0) || REGBITS(0) != 64) {
return NULL;
}
ut32 bits = 64;
RzILOpBitVector *x = ARG(1, &bits);
RzILOpBitVector *y = ARG(2, &bits);
if (!x || !y) {
rz_il_op_pure_free(x);
rz_il_op_pure_free(y);
return NULL;
}
bool is_signed = insn->id == CS_AARCH64(_INS_SMULH);
RzILOpBitVector *res = MUL(is_signed ? SIGNED(128, x) : UNSIGNED(128, x), is_signed ? SIGNED(128, y) : UNSIGNED(128, y));
return write_reg(REGID(0), UNSIGNED(64, SHIFTR0(res, UN(7, 64))));
}
#if CS_API_MAJOR > 4
/**
* Capstone: CS_AARCH64(_INS_SWP), CS_AARCH64(_INS_SWPA), CS_AARCH64(_INS_SWPAL), CS_AARCH64(_INS_SWPL),
* CS_AARCH64(_INS_SWPB), CS_AARCH64(_INS_SWPAB), CS_AARCH64(_INS_SWPALB), CS_AARCH64(_INS_SWPLB)
* CS_AARCH64(_INS_SWPH), CS_AARCH64(_INS_SWPAH), CS_AARCH64(_INS_SWPALH), CS_AARCH64(_INS_SWPLH)
* ARM: swp, swpa, swpal, swpl, swpb, swpab, swpalb, swplb, swph, swpah, swpalh, swplh
*/
static RzILOpEffect *swp(cs_insn *insn) {
if (!ISREG(0) || !ISREG(1)) {
return NULL;
}
ut32 bits;
switch (insn->id) {
case CS_AARCH64(_INS_SWPB):
case CS_AARCH64(_INS_SWPAB):
case CS_AARCH64(_INS_SWPALB):
case CS_AARCH64(_INS_SWPLB):
bits = 8;
break;
case CS_AARCH64(_INS_SWPH):
case CS_AARCH64(_INS_SWPAH):
case CS_AARCH64(_INS_SWPALH):
case CS_AARCH64(_INS_SWPLH):
bits = 16;
break;
default: // CS_AARCH64(_INS_SWP), CS_AARCH64(_INS_SWPA), CS_AARCH64(_INS_SWPAL), CS_AARCH64(_INS_SWPL):
bits = REGBITS(0);
if (!bits) {
return NULL;
}
break;
}
ut32 addr_bits = 64;
RzILOpBitVector *addr = ARG(2, &addr_bits);
if (!addr) {
return NULL;
}
RzILOpBitVector *store_val = ARG(0, &bits);
if (!addr || !store_val) {
rz_il_op_pure_free(addr);
rz_il_op_pure_free(store_val);
return NULL;
}
RzILOpEffect *store_eff = bits == 8 ? STORE(addr, store_val) : STOREW(addr, store_val);
CS_aarch64_reg() ret_reg = xreg_of_reg(REGID(1));
if (ret_reg == CS_AARCH64(_REG_XZR)) {
return store_eff;
}
RzILOpEffect *ret_eff = write_reg(ret_reg, bits != 64 ? UNSIGNED(64, VARL("ret")) : VARL("ret"));
if (!ret_eff) {
rz_il_op_effect_free(store_eff);
return NULL;
}
return SEQ3(
SETL("ret", bits == 8 ? LOAD(DUP(addr)) : LOADW(bits, DUP(addr))),
store_eff,
ret_eff);
}
#endif
/**
* Capstone: CS_AARCH64(_INS_SXTB), CS_AARCH64(_INS_SXTH), CS_AARCH64(_INS_SXTW), CS_AARCH64(_INS_UXTB), CS_AARCH64(_INS_UXTH)
* ARM: sxtb, sxth, sxtw, uxtb, uxth
*/
static RzILOpEffect *sxt(cs_insn *insn) {
if (!ISREG(0) || !REGBITS(0)) {
return NULL;
}
ut32 bits;
bool is_signed = true;
#if CS_NEXT_VERSION < 6
switch (insn->id) {
case CS_AARCH64(_INS_UXTB):
is_signed = false;
// fallthrough
case CS_AARCH64(_INS_SXTB):
bits = 8;
break;
case CS_AARCH64(_INS_UXTH):
is_signed = false;
// fallthrough
case CS_AARCH64(_INS_SXTH):
bits = 16;
break;
default: // CS_AARCH64(_INS_SXTW)
bits = 32;
break;
}
#else
switch (insn->alias_id) {
default:
return NULL;
case AArch64_INS_ALIAS_UXTB:
is_signed = false;
// fallthrough
case AArch64_INS_ALIAS_SXTB:
bits = 8;
break;
case AArch64_INS_ALIAS_UXTH:
is_signed = false;
// fallthrough
case AArch64_INS_ALIAS_SXTH:
bits = 16;
break;
case AArch64_INS_ALIAS_SXTW:
bits = 32;
break;
}
#endif
RzILOpBitVector *src = ARG(1, &bits);
if (!src) {
return NULL;
}
return write_reg(REGID(0), is_signed ? SIGNED(REGBITS(0), src) : UNSIGNED(REGBITS(0), src));
}
/**
* Capstone: CS_AARCH64(_INS_TBNZ), ARM64_TBZ
* ARM: tbnz, tbz
*/
static RzILOpEffect *tbz(cs_insn *insn) {
if (!ISIMM(1)) {
return NULL;
}
ut32 bits = 64;
RzILOpBitVector *src = ARG(0, &bits);
RzILOpBitVector *tgt = ARG(2, &bits);
if (!src || !tgt) {
rz_il_op_pure_free(src);
rz_il_op_pure_free(tgt);
return NULL;
}
RzILOpBool *c = LSB(SHIFTR0(src, UN(6, IMM(1))));
return insn->id == CS_AARCH64(_INS_TBNZ)
? BRANCH(c, JMP(tgt), NULL)
: BRANCH(c, NULL, JMP(tgt));
}
/**
* Capstone: CS_AARCH64(_INS_TST)
* ARM: tst
*/
static RzILOpEffect *tst(cs_insn *insn) {
ut32 bits = 0;
#if CS_NEXT_VERSION < 6
RzILOpBitVector *a = ARG(0, &bits);
RzILOpBitVector *b = ARG(1, &bits);
#else
// Operand 0 is the zero register the result is written to.
RzILOpBitVector *a = ARG(1, &bits);
RzILOpBitVector *b = ARG(2, &bits);
#endif
if (!a || !b) {
rz_il_op_pure_free(a);
rz_il_op_pure_free(b);
return NULL;
}
return update_flags_zn00(LOGAND(a, b));
}
/**
* Lift an AArch64 instruction to RzIL
*
* Currently unimplemented:
*
* FEAT_MTE/FEAT_MTE2/FEAT_MTE3: Memory Tagging Extension
* ------------------------------------------------------
* Plausible to represent by adding another memory with a 60bit keys and 4bit values to hold the memory tags.
* Instructions:
* - ADDG, SUBG, SUBP, SUBPS
* - CMPP
* - GMI
* - IRG
* - LDG, LDGM
* - ST2G, STZ2G
* - STG, STGM, STGP, STZG, STZGM
*
* FEAT_PAuth: Pointer Authentication
* ----------------------------------
* Extremely complex internal calculations. Different options to implement it include:
* - Fully implementing it in IL (probably theoretically possible, but may not be worth it)
* - Implementing the complex parts in uninterpreted functions and the simpler ones (e.g. stripping of auth bits) in IL.
* Might be a very good final solution since all data flow is correctly represented.
* - Implementing only stripping in IL and leaving everything else as nop.
* Might be useful as an interims solution to be able to strip pointers, but always unconditionally succeed authentication.
* Unimplemented Instructions:
* - AUTDA, AUTDZA
* - AUTDB, AUTDZB
* - AUTIA, AUTIA1716, AUTIASP, AUTIAZ, AUTIZA
* - AUTIB, AUTIB1716, AUTIBSP, AUTIBZ, AUTIZB
* - PACDA, PACDZA
* - PACDB, PACDZB
* - PACGA
* - PACIA, PACIA1716, PACIASP, PACIAZ, PACIZA
* - PACIB, PACIB1716, PACIBSP, PACIBZ, PACIZB
* - BLRAA, BLRAAZ, BLRAB, BLRABZ
* - BRAA, BRAAZ, BRAB, BRABZ
* - XPACD, XPACI, XPACLRI
* Stub-implemented Instructions:
* - LDRAA, LDRAB: currently behave like regular ldr
*
* Cache maintenance, tlb maintenance and address translation
* ----------------------------------------------------------
* - AT
* - CFP
* - CPP
* - SYS, SYSL
* - DC
* - DVP
* - IC
* - TLBI
*
* Miscellaneous
* -------------
* - BRK: causes a breakpoint instruction exception
* - BTI: FEAT_BTI/Branch Target Identification
* - CLREX: clears the local monitor
* - CRC32B, CRC32H, CRC32W, CRC32X, CRC32CB, CRC32CH, CRC32CW, CRC32CX: does crc32
* - CSDB, DMB, DSB, ESB, ISB, PSB CSYNC, PSSBB, SB, SSBB, TSB CSYNC: synchronization, memory barriers
* - DCPS1, DCPS2, DCPS3, DRPS, HLT: debug
* - ERET, ERETAA, ERETAB: exception return
* - SMC: secure monitor call
* - UDF: permanently undefined
*
* Not supported by capstone v4 or v5 at the time of writing
* ---------------------------------------------------------
* - AXFLAG, XAFLAG
* - FEAT_MTE (see above)
* - DGH
* - LD64B
* - ST64B
* - ST64BV
* - ST64BV0
* - WFET
*/
RZ_IPI RzILOpEffect *rz_arm_cs_64_il(csh *handle, cs_insn *insn) {
switch (insn->id) {
case CS_AARCH64(_INS_HINT):
case CS_AARCH64(_INS_PRFM):
case CS_AARCH64(_INS_PRFUM):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_NOP):
case CS_AARCH64(_INS_SEV):
case CS_AARCH64(_INS_SEVL):
case CS_AARCH64(_INS_WFE):
case CS_AARCH64(_INS_WFI):
case CS_AARCH64(_INS_YIELD):
#endif
return NOP();
case CS_AARCH64(_INS_ADD):
case CS_AARCH64(_INS_ADC):
case CS_AARCH64(_INS_SUB):
case CS_AARCH64(_INS_SBC):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_ADDS):
case CS_AARCH64(_INS_SUBS):
case CS_AARCH64(_INS_ADCS):
case CS_AARCH64(_INS_SBCS):
#endif
#if CS_NEXT_VERSION >= 6
if (insn->alias_id == AArch64_INS_ALIAS_MOV ||
insn->alias_id == AArch64_INS_ALIAS_MOVZ) {
return mov(insn);
} else if (insn->alias_id == AArch64_INS_ALIAS_CMP ||
insn->alias_id == AArch64_INS_ALIAS_CMN) {
return cmp(insn);
} else if (insn->alias_id == AArch64_INS_ALIAS_NEG ||
insn->alias_id == AArch64_INS_ALIAS_NGC ||
insn->alias_id == AArch64_INS_ALIAS_NEGS ||
insn->alias_id == AArch64_INS_ALIAS_NGCS) {
return mvn(insn);
}
#endif
return add_sub(insn);
case CS_AARCH64(_INS_ADR):
case CS_AARCH64(_INS_ADRP):
return adr(insn);
case CS_AARCH64(_INS_AND):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_ANDS):
#endif
case CS_AARCH64(_INS_EOR):
case CS_AARCH64(_INS_EON):
case CS_AARCH64(_INS_ORN):
case CS_AARCH64(_INS_ORR):
#if CS_NEXT_VERSION >= 6
if (insn->alias_id == AArch64_INS_ALIAS_MOV ||
insn->alias_id == AArch64_INS_ALIAS_MOVZ) {
return mov(insn);
} else if (insn->alias_id == AArch64_INS_ALIAS_TST) {
return tst(insn);
} else if (insn->alias_id == AArch64_INS_ALIAS_MVN) {
return mvn(insn);
}
#endif
return bitwise(insn);
case CS_AARCH64(_INS_ASR):
case CS_AARCH64(_INS_LSL):
case CS_AARCH64(_INS_LSR):
case CS_AARCH64(_INS_ROR):
return shift(insn);
case CS_AARCH64(_INS_B):
case CS_AARCH64(_INS_BR):
case CS_AARCH64(_INS_RET):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_BRAA):
case CS_AARCH64(_INS_BRAAZ):
case CS_AARCH64(_INS_BRAB):
case CS_AARCH64(_INS_BRABZ):
case CS_AARCH64(_INS_RETAA):
case CS_AARCH64(_INS_RETAB):
#endif
return branch(insn);
case CS_AARCH64(_INS_BL):
case CS_AARCH64(_INS_BLR):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_BLRAA):
case CS_AARCH64(_INS_BLRAAZ):
case CS_AARCH64(_INS_BLRAB):
case CS_AARCH64(_INS_BLRABZ):
#endif
return bl(insn);
case CS_AARCH64(_INS_BFM):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_BFI):
case CS_AARCH64(_INS_BFXIL):
#endif
return bfm(insn);
case CS_AARCH64(_INS_BIC):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_BICS):
#endif
return bic(insn);
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_CAS):
case CS_AARCH64(_INS_CASA):
case CS_AARCH64(_INS_CASAL):
case CS_AARCH64(_INS_CASL):
case CS_AARCH64(_INS_CASB):
case CS_AARCH64(_INS_CASAB):
case CS_AARCH64(_INS_CASALB):
case CS_AARCH64(_INS_CASLB):
case CS_AARCH64(_INS_CASH):
case CS_AARCH64(_INS_CASAH):
case CS_AARCH64(_INS_CASALH):
case CS_AARCH64(_INS_CASLH):
return cas(insn);
case CS_AARCH64(_INS_CASP):
case CS_AARCH64(_INS_CASPA):
case CS_AARCH64(_INS_CASPAL):
case CS_AARCH64(_INS_CASPL):
return casp(insn);
#endif
case CS_AARCH64(_INS_CBZ):
case CS_AARCH64(_INS_CBNZ):
return cbz(insn);
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_CMP):
case CS_AARCH64(_INS_CMN):
#endif
case CS_AARCH64(_INS_CCMP):
case CS_AARCH64(_INS_CCMN):
return cmp(insn);
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_CFINV):
return SETG("cf", INV(VARG("cf")));
#endif
case CS_AARCH64(_INS_CSINC):
case CS_AARCH64(_INS_CSINV):
case CS_AARCH64(_INS_CSNEG):
case CS_AARCH64(_INS_CSEL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_CINC):
case CS_AARCH64(_INS_CINV):
case CS_AARCH64(_INS_CNEG):
#else
if (insn->alias_id == AArch64_INS_ALIAS_CSET ||
insn->alias_id == AArch64_INS_ALIAS_CSETM) {
return cset(insn);
}
#endif
return csinc(insn);
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_CSET):
case CS_AARCH64(_INS_CSETM):
return cset(insn);
#endif
case CS_AARCH64(_INS_CLS):
return cls(insn);
case CS_AARCH64(_INS_CLZ):
return clz(insn);
case CS_AARCH64(_INS_EXTR):
#if CS_NEXT_VERSION >= 6
if (insn->alias_id == AArch64_INS_ALIAS_ROR) {
return shift(insn);
}
#endif
return extr(insn);
case CS_AARCH64(_INS_HVC):
return hvc(insn);
case CS_AARCH64(_INS_SVC):
return svc(insn);
case CS_AARCH64(_INS_LDR):
case CS_AARCH64(_INS_LDRB):
case CS_AARCH64(_INS_LDRH):
case CS_AARCH64(_INS_LDUR):
case CS_AARCH64(_INS_LDURB):
case CS_AARCH64(_INS_LDURH):
case CS_AARCH64(_INS_LDRSW):
case CS_AARCH64(_INS_LDRSB):
case CS_AARCH64(_INS_LDRSH):
case CS_AARCH64(_INS_LDURSW):
case CS_AARCH64(_INS_LDURSB):
case CS_AARCH64(_INS_LDURSH):
case CS_AARCH64(_INS_LDAR):
case CS_AARCH64(_INS_LDARB):
case CS_AARCH64(_INS_LDARH):
case CS_AARCH64(_INS_LDAXP):
case CS_AARCH64(_INS_LDXP):
case CS_AARCH64(_INS_LDAXR):
case CS_AARCH64(_INS_LDAXRB):
case CS_AARCH64(_INS_LDAXRH):
case CS_AARCH64(_INS_LDP):
case CS_AARCH64(_INS_LDNP):
case CS_AARCH64(_INS_LDPSW):
case CS_AARCH64(_INS_LDTR):
case CS_AARCH64(_INS_LDTRB):
case CS_AARCH64(_INS_LDTRH):
case CS_AARCH64(_INS_LDTRSW):
case CS_AARCH64(_INS_LDTRSB):
case CS_AARCH64(_INS_LDTRSH):
case CS_AARCH64(_INS_LDXR):
case CS_AARCH64(_INS_LDXRB):
case CS_AARCH64(_INS_LDXRH):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDAPR):
case CS_AARCH64(_INS_LDAPRB):
case CS_AARCH64(_INS_LDAPRH):
case CS_AARCH64(_INS_LDAPUR):
case CS_AARCH64(_INS_LDAPURB):
case CS_AARCH64(_INS_LDAPURH):
case CS_AARCH64(_INS_LDAPURSB):
case CS_AARCH64(_INS_LDAPURSH):
case CS_AARCH64(_INS_LDAPURSW):
case CS_AARCH64(_INS_LDLAR):
case CS_AARCH64(_INS_LDLARB):
case CS_AARCH64(_INS_LDLARH):
case CS_AARCH64(_INS_LDRAA):
case CS_AARCH64(_INS_LDRAB):
#endif
return ldr(insn);
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_LDADD):
case CS_AARCH64(_INS_LDADDA):
case CS_AARCH64(_INS_LDADDAL):
case CS_AARCH64(_INS_LDADDL):
case CS_AARCH64(_INS_LDADDB):
case CS_AARCH64(_INS_LDADDAB):
case CS_AARCH64(_INS_LDADDALB):
case CS_AARCH64(_INS_LDADDLB):
case CS_AARCH64(_INS_LDADDH):
case CS_AARCH64(_INS_LDADDAH):
case CS_AARCH64(_INS_LDADDALH):
case CS_AARCH64(_INS_LDADDLH):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STADD):
case CS_AARCH64(_INS_STADDL):
case CS_AARCH64(_INS_STADDB):
case CS_AARCH64(_INS_STADDLB):
case CS_AARCH64(_INS_STADDH):
case CS_AARCH64(_INS_STADDLH):
#endif
case CS_AARCH64(_INS_LDCLRB):
case CS_AARCH64(_INS_LDCLRAB):
case CS_AARCH64(_INS_LDCLRALB):
case CS_AARCH64(_INS_LDCLRLB):
case CS_AARCH64(_INS_LDCLRH):
case CS_AARCH64(_INS_LDCLRAH):
case CS_AARCH64(_INS_LDCLRALH):
case CS_AARCH64(_INS_LDCLRLH):
case CS_AARCH64(_INS_LDCLR):
case CS_AARCH64(_INS_LDCLRA):
case CS_AARCH64(_INS_LDCLRAL):
case CS_AARCH64(_INS_LDCLRL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STCLR):
case CS_AARCH64(_INS_STCLRL):
case CS_AARCH64(_INS_STCLRB):
case CS_AARCH64(_INS_STCLRLB):
case CS_AARCH64(_INS_STCLRH):
case CS_AARCH64(_INS_STCLRLH):
#endif
case CS_AARCH64(_INS_LDEORB):
case CS_AARCH64(_INS_LDEORAB):
case CS_AARCH64(_INS_LDEORALB):
case CS_AARCH64(_INS_LDEORLB):
case CS_AARCH64(_INS_LDEORH):
case CS_AARCH64(_INS_LDEORAH):
case CS_AARCH64(_INS_LDEORALH):
case CS_AARCH64(_INS_LDEORLH):
case CS_AARCH64(_INS_LDEOR):
case CS_AARCH64(_INS_LDEORA):
case CS_AARCH64(_INS_LDEORAL):
case CS_AARCH64(_INS_LDEORL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STEOR):
case CS_AARCH64(_INS_STEORL):
case CS_AARCH64(_INS_STEORB):
case CS_AARCH64(_INS_STEORLB):
case CS_AARCH64(_INS_STEORH):
case CS_AARCH64(_INS_STEORLH):
#endif
case CS_AARCH64(_INS_LDSETB):
case CS_AARCH64(_INS_LDSETAB):
case CS_AARCH64(_INS_LDSETALB):
case CS_AARCH64(_INS_LDSETLB):
case CS_AARCH64(_INS_LDSETH):
case CS_AARCH64(_INS_LDSETAH):
case CS_AARCH64(_INS_LDSETALH):
case CS_AARCH64(_INS_LDSETLH):
case CS_AARCH64(_INS_LDSET):
case CS_AARCH64(_INS_LDSETA):
case CS_AARCH64(_INS_LDSETAL):
case CS_AARCH64(_INS_LDSETL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSET):
case CS_AARCH64(_INS_STSETL):
case CS_AARCH64(_INS_STSETB):
case CS_AARCH64(_INS_STSETLB):
case CS_AARCH64(_INS_STSETH):
case CS_AARCH64(_INS_STSETLH):
#endif
case CS_AARCH64(_INS_LDSMAXB):
case CS_AARCH64(_INS_LDSMAXAB):
case CS_AARCH64(_INS_LDSMAXALB):
case CS_AARCH64(_INS_LDSMAXLB):
case CS_AARCH64(_INS_LDSMAXH):
case CS_AARCH64(_INS_LDSMAXAH):
case CS_AARCH64(_INS_LDSMAXALH):
case CS_AARCH64(_INS_LDSMAXLH):
case CS_AARCH64(_INS_LDSMAX):
case CS_AARCH64(_INS_LDSMAXA):
case CS_AARCH64(_INS_LDSMAXAL):
case CS_AARCH64(_INS_LDSMAXL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMAX):
case CS_AARCH64(_INS_STSMAXL):
case CS_AARCH64(_INS_STSMAXB):
case CS_AARCH64(_INS_STSMAXLB):
case CS_AARCH64(_INS_STSMAXH):
case CS_AARCH64(_INS_STSMAXLH):
#endif
case CS_AARCH64(_INS_LDSMINB):
case CS_AARCH64(_INS_LDSMINAB):
case CS_AARCH64(_INS_LDSMINALB):
case CS_AARCH64(_INS_LDSMINLB):
case CS_AARCH64(_INS_LDSMINH):
case CS_AARCH64(_INS_LDSMINAH):
case CS_AARCH64(_INS_LDSMINALH):
case CS_AARCH64(_INS_LDSMINLH):
case CS_AARCH64(_INS_LDSMIN):
case CS_AARCH64(_INS_LDSMINA):
case CS_AARCH64(_INS_LDSMINAL):
case CS_AARCH64(_INS_LDSMINL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STSMIN):
case CS_AARCH64(_INS_STSMINL):
case CS_AARCH64(_INS_STSMINB):
case CS_AARCH64(_INS_STSMINLB):
case CS_AARCH64(_INS_STSMINH):
case CS_AARCH64(_INS_STSMINLH):
#endif
case CS_AARCH64(_INS_LDUMAXB):
case CS_AARCH64(_INS_LDUMAXAB):
case CS_AARCH64(_INS_LDUMAXALB):
case CS_AARCH64(_INS_LDUMAXLB):
case CS_AARCH64(_INS_LDUMAXH):
case CS_AARCH64(_INS_LDUMAXAH):
case CS_AARCH64(_INS_LDUMAXALH):
case CS_AARCH64(_INS_LDUMAXLH):
case CS_AARCH64(_INS_LDUMAX):
case CS_AARCH64(_INS_LDUMAXA):
case CS_AARCH64(_INS_LDUMAXAL):
case CS_AARCH64(_INS_LDUMAXL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMAX):
case CS_AARCH64(_INS_STUMAXL):
case CS_AARCH64(_INS_STUMAXB):
case CS_AARCH64(_INS_STUMAXLB):
case CS_AARCH64(_INS_STUMAXH):
case CS_AARCH64(_INS_STUMAXLH):
#endif
case CS_AARCH64(_INS_LDUMINB):
case CS_AARCH64(_INS_LDUMINAB):
case CS_AARCH64(_INS_LDUMINALB):
case CS_AARCH64(_INS_LDUMINLB):
case CS_AARCH64(_INS_LDUMINH):
case CS_AARCH64(_INS_LDUMINAH):
case CS_AARCH64(_INS_LDUMINALH):
case CS_AARCH64(_INS_LDUMINLH):
case CS_AARCH64(_INS_LDUMIN):
case CS_AARCH64(_INS_LDUMINA):
case CS_AARCH64(_INS_LDUMINAL):
case CS_AARCH64(_INS_LDUMINL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_STUMIN):
case CS_AARCH64(_INS_STUMINL):
case CS_AARCH64(_INS_STUMINB):
case CS_AARCH64(_INS_STUMINLB):
case CS_AARCH64(_INS_STUMINH):
case CS_AARCH64(_INS_STUMINLH):
#endif
return ldadd(insn);
#endif
case CS_AARCH64(_INS_MADD):
case CS_AARCH64(_INS_MSUB):
#if CS_NEXT_VERSION >= 6
if (insn->alias_id == AArch64_INS_ALIAS_MUL ||
insn->alias_id == AArch64_INS_ALIAS_MNEG) {
return mul(insn);
}
#endif
return madd(insn);
case CS_AARCH64(_INS_MUL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_MNEG):
#endif
return mul(insn);
case CS_AARCH64(_INS_MOV):
case CS_AARCH64(_INS_MOVZ):
return mov(insn);
case CS_AARCH64(_INS_MOVK):
return movk(insn);
case CS_AARCH64(_INS_MOVN):
return movn(insn);
case CS_AARCH64(_INS_MSR):
return msr(insn);
case CS_AARCH64(_INS_MRS):
return mrs(insn);
case CS_AARCH64(_INS_NEG):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_MVN):
case CS_AARCH64(_INS_NGC):
case CS_AARCH64(_INS_NEGS):
case CS_AARCH64(_INS_NGCS):
#endif
return mvn(insn);
case CS_AARCH64(_INS_RBIT):
return rbit(insn);
case CS_AARCH64(_INS_REV):
case CS_AARCH64(_INS_REV32):
case CS_AARCH64(_INS_REV16):
return rev(insn);
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_RMIF):
return rmif(insn);
#endif
case CS_AARCH64(_INS_SBFM):
case CS_AARCH64(_INS_UBFM):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_SBFIZ):
case CS_AARCH64(_INS_SBFX):
case CS_AARCH64(_INS_UBFIZ):
case CS_AARCH64(_INS_UBFX):
#else
if (insn->alias_id == AArch64_INS_ALIAS_UXTH ||
insn->alias_id == AArch64_INS_ALIAS_UXTB ||
insn->alias_id == AArch64_INS_ALIAS_SXTH ||
insn->alias_id == AArch64_INS_ALIAS_SXTB ||
insn->alias_id == AArch64_INS_ALIAS_SXTW) {
return sxt(insn);
}
#endif
return usbfm(insn);
case CS_AARCH64(_INS_SDIV):
return sdiv(insn);
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_SETF8):
case CS_AARCH64(_INS_SETF16):
return setf(insn);
#endif
case CS_AARCH64(_INS_SMADDL):
case CS_AARCH64(_INS_SMSUBL):
case CS_AARCH64(_INS_UMADDL):
case CS_AARCH64(_INS_UMSUBL):
#if CS_NEXT_VERSION >= 6
if (insn->alias_id == AArch64_INS_ALIAS_SMULL ||
insn->alias_id == AArch64_INS_ALIAS_UMULL ||
insn->alias_id == AArch64_INS_ALIAS_SMNEGL ||
insn->alias_id == AArch64_INS_ALIAS_UMNEGL) {
return smull(insn);
}
#endif
return smaddl(insn);
case CS_AARCH64(_INS_SMULL):
case CS_AARCH64(_INS_UMULL):
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_SMNEGL):
case CS_AARCH64(_INS_UMNEGL):
#endif
return smull(insn);
case CS_AARCH64(_INS_SMULH):
case CS_AARCH64(_INS_UMULH):
return smulh(insn);
case CS_AARCH64(_INS_STR):
case CS_AARCH64(_INS_STUR):
case CS_AARCH64(_INS_STRB):
case CS_AARCH64(_INS_STURB):
case CS_AARCH64(_INS_STRH):
case CS_AARCH64(_INS_STURH):
case CS_AARCH64(_INS_STLR):
case CS_AARCH64(_INS_STLRB):
case CS_AARCH64(_INS_STLRH):
case CS_AARCH64(_INS_STP):
case CS_AARCH64(_INS_STNP):
case CS_AARCH64(_INS_STXR):
case CS_AARCH64(_INS_STXRB):
case CS_AARCH64(_INS_STXRH):
case CS_AARCH64(_INS_STXP):
case CS_AARCH64(_INS_STLXR):
case CS_AARCH64(_INS_STLXRB):
case CS_AARCH64(_INS_STLXRH):
case CS_AARCH64(_INS_STLXP):
case CS_AARCH64(_INS_STTR):
case CS_AARCH64(_INS_STTRB):
case CS_AARCH64(_INS_STTRH):
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_STLLR):
case CS_AARCH64(_INS_STLLRB):
case CS_AARCH64(_INS_STLLRH):
case CS_AARCH64(_INS_STLUR):
case CS_AARCH64(_INS_STLURB):
case CS_AARCH64(_INS_STLURH):
#endif
return str(insn);
#if CS_API_MAJOR > 4
case CS_AARCH64(_INS_SWP):
case CS_AARCH64(_INS_SWPA):
case CS_AARCH64(_INS_SWPAL):
case CS_AARCH64(_INS_SWPL):
case CS_AARCH64(_INS_SWPB):
case CS_AARCH64(_INS_SWPAB):
case CS_AARCH64(_INS_SWPALB):
case CS_AARCH64(_INS_SWPLB):
case CS_AARCH64(_INS_SWPH):
case CS_AARCH64(_INS_SWPAH):
case CS_AARCH64(_INS_SWPALH):
case CS_AARCH64(_INS_SWPLH):
return swp(insn);
#endif
case CS_AARCH64(_INS_SXTB):
case CS_AARCH64(_INS_SXTH):
case CS_AARCH64(_INS_SXTW):
case CS_AARCH64(_INS_UXTB):
case CS_AARCH64(_INS_UXTH):
return sxt(insn);
case CS_AARCH64(_INS_TBNZ):
case CS_AARCH64(_INS_TBZ):
return tbz(insn);
#if CS_NEXT_VERSION < 6
case CS_AARCH64(_INS_TST):
return tst(insn);
#endif
case CS_AARCH64(_INS_UDIV):
return udiv(insn);
default:
break;
}
return NULL;
}
#include <rz_il/rz_il_opbuilder_end.h>
RZ_IPI RzAnalysisILConfig *rz_arm_cs_64_il_config(bool big_endian) {
RzAnalysisILConfig *r = rz_analysis_il_config_new(64, big_endian, 64);
r->reg_bindings = regs_bound;
RzILEffectLabel *svc_label = rz_il_effect_label_new("svc", EFFECT_LABEL_SYSCALL);
svc_label->hook = label_svc;
rz_analysis_il_config_add_label(r, svc_label);
RzILEffectLabel *hvc_label = rz_il_effect_label_new("hvc", EFFECT_LABEL_SYSCALL);
hvc_label->hook = label_hvc;
rz_analysis_il_config_add_label(r, hvc_label);
return r;
}