3138 lines
87 KiB
C
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;
|
|
}
|