miasm/arch/arm/sem.py
from builtins import range
from future.utils import viewitems, viewvalues
from miasm.expression.expression import *
from miasm.expression.simplifications import expr_simp
from miasm.ir.ir import Lifter, IRBlock, AssignBlock
from miasm.arch.arm.arch import mn_arm, mn_armt
from miasm.arch.arm.regs import *
from miasm.jitter.csts import EXCEPT_DIV_BY_ZERO, EXCEPT_INT_XX
coproc_reg_dict = {
("p15", "c0", 0, "c0", 0): MIDR,
("p15", "c0", 0, "c0", 1): CTR,
("p15", "c0", 0, "c0", 2): TCMTR,
("p15", "c0", 0, "c0", 3): TLBTR,
("p15", "c0", 0, "c0", 4): MIDR,
("p15", "c0", 0, "c0", 5): MPIDR,
("p15", "c0", 0, "c0", 6): REVIDR,
("p15", "c0", 0, "c0", 7): MIDR,
("p15", "c0", 0, "c1", 0): ID_PFR0,
("p15", "c0", 0, "c1", 1): ID_PFR1,
("p15", "c0", 0, "c1", 2): ID_DFR0,
("p15", "c0", 0, "c1", 3): ID_AFR0,
("p15", "c0", 0, "c1", 4): ID_MMFR0,
("p15", "c0", 0, "c1", 5): ID_MMFR1,
("p15", "c0", 0, "c1", 6): ID_MMFR2,
("p15", "c0", 0, "c1", 7): ID_MMFR3,
("p15", "c0", 0, "c2", 0): ID_ISAR0,
("p15", "c0", 0, "c2", 1): ID_ISAR1,
("p15", "c0", 0, "c2", 2): ID_ISAR2,
("p15", "c0", 0, "c2", 3): ID_ISAR3,
("p15", "c0", 0, "c2", 4): ID_ISAR4,
("p15", "c0", 0, "c2", 5): ID_ISAR5,
("p15", "c0", 1, "c0", 0): CCSIDR,
("p15", "c0", 1, "c0", 1): CLIDR,
("p15", "c0", 1, "c0", 7): AIDR,
("p15", "c0", 2, "c0", 0): CSSELR,
("p15", "c0", 4, "c0", 0): VPIDR,
("p15", "c0", 4, "c0", 5): VMPIDR,
("p15", "c1", 0, "c0", 0): SCTLR,
("p15", "c1", 0, "c0", 1): ACTLR,
("p15", "c1", 0, "c0", 2): CPACR,
("p15", "c1", 0, "c1", 0): SCR,
("p15", "c1", 0, "c1", 1): SDER,
("p15", "c1", 0, "c1", 2): NSACR,
("p15", "c1", 4, "c0", 0): HSCTLR,
("p15", "c1", 4, "c0", 1): HACTLR,
("p15", "c1", 4, "c1", 0): HCR,
("p15", "c1", 4, "c1", 1): HDCR,
("p15", "c1", 4, "c1", 2): HCPTR,
("p15", "c1", 4, "c1", 3): HSTR,
("p15", "c1", 4, "c1", 7): HACR,
# TODO: TTBRO/TTBR1 64-bit
("p15", "c2", 0, "c0", 0): TTBR0,
("p15", "c2", 0, "c0", 1): TTBR1,
("p15", "c2", 0, "c0", 2): TTBCR,
("p15", "c2", 4, "c0", 2): HTCR,
("p15", "c2", 4, "c1", 2): VTCR,
# TODO: HTTBR, VTTBR
("p15", "c3", 0, "c0", 0): DACR,
("p15", "c5", 0, "c0", 0): DFSR,
("p15", "c5", 0, "c0", 1): IFSR,
("p15", "c5", 0, "c1", 0): ADFSR,
("p15", "c5", 0, "c1", 1): AIFSR,
("p15", "c5", 4, "c1", 0): HADFSR,
("p15", "c5", 4, "c1", 1): HAIFSR,
("p15", "c5", 4, "c2", 0): HSR,
("p15", "c6", 0, "c1", 0): DFAR,
("p15", "c6", 0, "c1", 2): IFAR,
("p15", "c6", 4, "c0", 0): HDFAR,
("p15", "c6", 4, "c0", 2): HIFAR,
("p15", "c6", 4, "c0", 4): HPFAR,
("p15", "c7", 0, "c1", 0): ICIALLUIS,
("p15", "c7", 0, "c1", 6): BPIALLIS,
("p15", "c7", 0, "c4", 0): PAR,
# TODO: PAR 64-bit
("p15", "c7", 0, "c5", 0): ICIALLU,
("p15", "c7", 0, "c5", 1): ICIMVAU,
("p15", "c7", 0, "c5", 4): CP15ISB,
("p15", "c7", 0, "c5", 6): BPIALL,
("p15", "c7", 0, "c5", 7): BPIMVA,
("p15", "c7", 0, "c6", 1): DCIMVAC,
("p15", "c7", 0, "c6", 2): DCISW,
("p15", "c7", 0, "c8", 0): ATS1CPR,
("p15", "c7", 0, "c8", 1): ATS1CPW,
("p15", "c7", 0, "c8", 2): ATS1CUR,
("p15", "c7", 0, "c8", 3): ATS1CUW,
("p15", "c7", 0, "c8", 4): ATS12NSOPR,
("p15", "c7", 0, "c8", 5): ATS12NSOPW,
("p15", "c7", 0, "c8", 6): ATS12NSOUR,
("p15", "c7", 0, "c8", 7): ATS12NSOUW,
("p15", "c7", 0, "c10", 1): DCCMVAC,
("p15", "c7", 0, "c10", 2): DCCSW,
("p15", "c7", 0, "c10", 4): CP15DSB,
("p15", "c7", 0, "c10", 5): CP15DMB,
("p15", "c7", 0, "c11", 1): DCCMVAU,
("p15", "c7", 0, "c14", 1): DCCIMVAC,
("p15", "c7", 0, "c14", 2): DCCISW,
("p15", "c7", 4, "c8", 0): ATS1HR,
("p15", "c7", 4, "c8", 1): ATS1HW,
("p15", "c8", 0, "c3", 0): TLBIALLIS,
("p15", "c8", 0, "c3", 1): TLBIMVAIS,
("p15", "c8", 0, "c3", 2): TLBIASIDIS,
("p15", "c8", 0, "c3", 3): TLBIMVAAIS,
("p15", "c8", 0, "c5", 0): ITLBIALL,
("p15", "c8", 0, "c5", 1): ITLBIMVA,
("p15", "c8", 0, "c5", 2): ITLBIASID,
("p15", "c8", 0, "c6", 0): DTLBIALL,
("p15", "c8", 0, "c6", 1): DTLBIMVA,
("p15", "c8", 0, "c6", 2): DTLBIASID,
("p15", "c8", 0, "c7", 0): TLBIALL,
("p15", "c8", 0, "c7", 1): TLBIMVA,
("p15", "c8", 0, "c7", 2): TLBIASID,
("p15", "c8", 0, "c7", 3): TLBIMVAA,
("p15", "c8", 4, "c3", 0): TLBIALLHIS,
("p15", "c8", 4, "c3", 1): TLBIMVAHIS,
("p15", "c8", 4, "c3", 4): TLBIALLNSNHIS,
("p15", "c8", 4, "c7", 0): TLBIALLH,
("p15", "c8", 4, "c7", 1): TLBIMVAH,
("p15", "c8", 4, "c7", 2): TLBIALLNSNH,
("p15", "c9", 0, "c12", 0): PMCR,
("p15", "c9", 0, "c12", 1): PMCNTENSET,
("p15", "c9", 0, "c12", 2): PMCNTENCLR,
("p15", "c9", 0, "c12", 3): PMOVSR,
("p15", "c9", 0, "c12", 4): PMSWINC,
("p15", "c9", 0, "c12", 5): PMSELR,
("p15", "c9", 0, "c12", 6): PMCEID0,
("p15", "c9", 0, "c12", 7): PMCEID1,
("p15", "c9", 0, "c13", 0): PMCCNTR,
("p15", "c9", 0, "c13", 1): PMXEVTYPER,
("p15", "c9", 0, "c13", 2): PMXEVCNTR,
("p15", "c9", 0, "c14", 0): PMUSERENR,
("p15", "c9", 0, "c14", 1): PMINTENSET,
("p15", "c9", 0, "c14", 2): PMINTENCLR,
("p15", "c9", 0, "c14", 3): PMOVSSET,
("p15", "c10", 0, "c2", 0): PRRR, # ALIAS MAIR0
("p15", "c10", 0, "c2", 1): NMRR, # ALIAS MAIR1
("p15", "c10", 0, "c3", 0): AMAIR0,
("p15", "c10", 0, "c3", 1): AMAIR1,
("p15", "c10", 4, "c2", 0): HMAIR0,
("p15", "c10", 4, "c2", 1): HMAIR1,
("p15", "c10", 4, "c3", 0): HAMAIR0,
("p15", "c10", 4, "c3", 1): HAMAIR1,
("p15", "c12", 0, "c0", 0): VBAR,
("p15", "c12", 0, "c0", 1): MVBAR,
("p15", "c12", 0, "c1", 0): ISR,
("p15", "c12", 4, "c0", 0): HVBAR,
("p15", "c13", 0, "c0", 0): FCSEIDR,
("p15", "c13", 0, "c0", 1): CONTEXTIDR,
("p15", "c13", 0, "c0", 2): TPIDRURW,
("p15", "c13", 0, "c0", 3): TPIDRURO,
("p15", "c13", 0, "c0", 4): TPIDRPRW,
("p15", "c13", 4, "c0", 2): HTPIDR,
("p15", "c14", 0, "c0", 0): CNTFRQ,
# TODO: CNTPCT 64-bit
("p15", "c14", 0, "c1", 0): CNTKCTL,
("p15", "c14", 0, "c2", 0): CNTP_TVAL,
("p15", "c14", 0, "c2", 1): CNTP_CTL,
("p15", "c14", 0, "c3", 0): CNTV_TVAL,
("p15", "c14", 0, "c3", 1): CNTV_CTL,
# TODO: CNTVCT, CNTP_CVAL, CNTV_CVAL, CNTVOFF 64-bit
("p15", "c14", 4, "c1", 0): CNTHCTL,
("p15", "c14", 4, "c2", 0): CNTHP_TVAL,
("p15", "c14", 4, "c2", 0): CNTHP_CTL
# TODO: CNTHP_CVAL 64-bit
}
# liris.cnrs.fr/~mmrissa/lib/exe/fetch.php?media=armv7-a-r-manual.pdf
EXCEPT_SOFT_BP = (1 << 1)
EXCEPT_PRIV_INSN = (1 << 17)
# CPSR: N Z C V
def update_flag_zf(a):
return [ExprAssign(zf, ExprOp("FLAG_EQ", a))]
def update_flag_zf_eq(a, b):
return [ExprAssign(zf, ExprOp("FLAG_EQ_CMP", a, b))]
def update_flag_nf(arg):
return [
ExprAssign(
nf,
ExprOp("FLAG_SIGN_SUB", arg, ExprInt(0, arg.size))
)
]
def update_flag_zn(a):
e = []
e += update_flag_zf(a)
e += update_flag_nf(a)
return e
# Instructions which use shifter's carry flag: ANDS, BICS, EORS, MOVS/RRX, MVNS, ORNS (TODO), ORRS, TEQ, TST
def compute_rrx_carry(operation):
"""
Returns a tuple (result, carry) corresponding to the RRX computation
@operation: The ExprOp operation
"""
new_cf = operation.args[0][:1]
res = ExprCompose(operation.args[0][1:], cf)
return res, new_cf
# XXX TODO: set cf if ROT imm in argument
def check_ops_msb(a, b, c):
if not a or not b or not c or a != b or a != c:
raise ValueError('bad ops size %s %s %s' % (a, b, c))
def update_flag_add_cf(op1, op2):
"Compute cf in @op1 + @op2"
return [ExprAssign(cf, ExprOp("FLAG_ADD_CF", op1, op2))]
def update_flag_add_of(op1, op2):
"Compute of in @op1 + @op2"
return [ExprAssign(of, ExprOp("FLAG_ADD_OF", op1, op2))]
def update_flag_sub_cf(op1, op2):
"Compute CF in @op1 - @op2"
return [ExprAssign(cf, ExprOp("FLAG_SUB_CF", op1, op2) ^ ExprInt(1, 1))]
def update_flag_sub_of(op1, op2):
"Compute OF in @op1 - @op2"
return [ExprAssign(of, ExprOp("FLAG_SUB_OF", op1, op2))]
def update_flag_arith_add_co(arg1, arg2):
e = []
e += update_flag_add_cf(arg1, arg2)
e += update_flag_add_of(arg1, arg2)
return e
def update_flag_arith_add_zn(arg1, arg2):
"""
Compute zf and nf flags for (arg1 + arg2)
"""
e = []
e += update_flag_zf_eq(arg1, -arg2)
e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, -arg2))]
return e
def update_flag_arith_sub_co(arg1, arg2):
"""
Compute cf and of flags for (arg1 - arg2)
"""
e = []
e += update_flag_sub_cf(arg1, arg2)
e += update_flag_sub_of(arg1, arg2)
return e
def update_flag_arith_sub_zn(arg1, arg2):
"""
Compute zf and nf flags for (arg1 - arg2)
"""
e = []
e += update_flag_zf_eq(arg1, arg2)
e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUB", arg1, arg2))]
return e
def update_flag_zfaddwc_eq(arg1, arg2, arg3):
return [ExprAssign(zf, ExprOp("FLAG_EQ_ADDWC", arg1, arg2, arg3))]
def update_flag_zfsubwc_eq(arg1, arg2, arg3):
return [ExprAssign(zf, ExprOp("FLAG_EQ_SUBWC", arg1, arg2, arg3))]
def update_flag_arith_addwc_zn(arg1, arg2, arg3):
"""
Compute znp flags for (arg1 + arg2 + cf)
"""
e = []
e += update_flag_zfaddwc_eq(arg1, arg2, arg3)
e += [ExprAssign(nf, ExprOp("FLAG_SIGN_ADDWC", arg1, arg2, arg3))]
return e
def update_flag_arith_subwc_zn(arg1, arg2, arg3):
"""
Compute znp flags for (arg1 - (arg2 + cf))
"""
e = []
e += update_flag_zfsubwc_eq(arg1, arg2, arg3)
e += [ExprAssign(nf, ExprOp("FLAG_SIGN_SUBWC", arg1, arg2, arg3))]
return e
def update_flag_addwc_cf(op1, op2, op3):
"Compute cf in @res = @op1 + @op2 + @op3"
return [ExprAssign(cf, ExprOp("FLAG_ADDWC_CF", op1, op2, op3))]
def update_flag_addwc_of(op1, op2, op3):
"Compute of in @res = @op1 + @op2 + @op3"
return [ExprAssign(of, ExprOp("FLAG_ADDWC_OF", op1, op2, op3))]
def update_flag_arith_addwc_co(arg1, arg2, arg3):
e = []
e += update_flag_addwc_cf(arg1, arg2, arg3)
e += update_flag_addwc_of(arg1, arg2, arg3)
return e
def update_flag_subwc_cf(op1, op2, op3):
"Compute cf in @res = @op1 + @op2 + @op3"
return [ExprAssign(cf, ExprOp("FLAG_SUBWC_CF", op1, op2, op3) ^ ExprInt(1, 1))]
def update_flag_subwc_of(op1, op2, op3):
"Compute of in @res = @op1 + @op2 + @op3"
return [ExprAssign(of, ExprOp("FLAG_SUBWC_OF", op1, op2, op3))]
def update_flag_arith_subwc_co(arg1, arg2, arg3):
e = []
e += update_flag_subwc_cf(arg1, arg2, arg3)
e += update_flag_subwc_of(arg1, arg2, arg3)
return e
# Utility function for flag computation when it depends on the mode
def isThumb(lifter):
return isinstance(lifter, (Lifter_Armtl, Lifter_Armtb))
def get_dst(a):
if a == PC:
return PC
return None
# instruction definition ##############
def adc(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = b, c
r = b + c + cf.zeroExtend(32)
if instr.name == 'ADCS' and a != PC:
e += update_flag_arith_addwc_zn(arg1, arg2, cf)
e += update_flag_arith_addwc_co(arg1, arg2, cf)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def add(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = b, c
r = b + c
if instr.name == 'ADDS' and a != PC:
e += update_flag_arith_add_zn(arg1, arg2)
e += update_flag_arith_add_co(arg1, arg2)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def l_and(ir, instr, a, b, c=None):
setflags = (instr.name == 'ANDS') and a != PC
if c is None:
b, c = a, b
if c.is_op():
e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
# get back the result
c = e.pop(0).src
else:
e = []
extra_ir = []
r = b & c
if setflags:
e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', b, c))]
e += update_flag_nf(r)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, extra_ir
def sub(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = b - c
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def subs(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = b, c
r = b - c
e += update_flag_arith_sub_zn(arg1, arg2)
e += update_flag_arith_sub_co(arg1, arg2)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def eor(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = b ^ c
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def eors(ir, instr, a, b, c=None):
setflags = a != PC
if c is None:
b, c = a, b
if c.is_op():
e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
# get back the result
c = e.pop(0).src
else:
e = []
extra_ir = []
arg1, arg2 = b, c
r = arg1 ^ arg2
e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))]
e += update_flag_nf(r)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, extra_ir
def rsb(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = c, b
r = arg1 - arg2
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def rsbs(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = c, b
r = arg1 - arg2
e += update_flag_arith_sub_zn(arg1, arg2)
e += update_flag_arith_sub_co(arg1, arg2)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def sbc(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = b, c
r = arg1 - (arg2 + (~cf).zeroExtend(32))
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def sbcs(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = b, c
r = arg1 - (arg2 + (~cf).zeroExtend(32))
e += update_flag_arith_subwc_zn(arg1, arg2, ~cf)
e += update_flag_arith_subwc_co(arg1, arg2, ~cf)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def rsc(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = c, b
r = arg1 - (arg2 + (~cf).zeroExtend(32))
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def rscs(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = c, b
r = arg1 - (arg2 + (~cf).zeroExtend(32))
e += update_flag_arith_subwc_zn(arg1, arg2, ~cf)
e += update_flag_arith_subwc_co(arg1, arg2, ~cf)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def tst(ir, instr, a, b):
setflags = a != PC
if b.is_op():
e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags)
# get back the result
b = e.pop(0).src
else:
e = []
extra_ir = []
arg1, arg2 = a, b
r = arg1 & arg2
e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', arg1, arg2))]
e += update_flag_nf(r)
return e, extra_ir
def teq(ir, instr, a, b, c=None):
setflags = a != PC
if b.is_op():
e, extra_ir = _shift_rotate_tpl(ir, instr, a, b, onlyCarry=setflags)
# get back the result
b = e.pop(0).src
else:
e = []
extra_ir = []
if c is None:
b, c = a, b
arg1, arg2 = b, c
r = arg1 ^ arg2
e += [ExprAssign(zf, ExprOp('FLAG_EQ_CMP', arg1, arg2))]
e += update_flag_nf(r)
return e, extra_ir
def l_cmp(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
arg1, arg2 = b, c
e += update_flag_arith_sub_zn(arg1, arg2)
e += update_flag_arith_sub_co(arg1, arg2)
return e, []
def cmn(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
arg1, arg2 = b, c
e += update_flag_arith_add_zn(arg1, arg2)
e += update_flag_arith_add_co(arg1, arg2)
return e, []
def orr(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = b | c
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def orn(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = ~(b | c)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def orrs(ir, instr, a, b, c=None):
setflags = a != PC
if c is None:
b, c = a, b
if c.is_op():
e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
# get back the result
c = e.pop(0).src
else:
e = []
extra_ir = []
arg1, arg2 = b, c
r = arg1 | arg2
e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
e += update_flag_nf(r)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, extra_ir
def mov(ir, instr, a, b):
if b.is_op():
return _shift_rotate_tpl(ir, instr, a, b, setflags=False)
# TODO handle cf
e = [ExprAssign(a, b)]
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, b))
return e, []
def movt(ir, instr, a, b):
r = a | b << ExprInt(16, 32)
e = [ExprAssign(a, r)]
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def _shift_rotate_tpl(ir, instr, dst, shift_operation, setflags=False, is_not=False, onlyCarry=False):
"""
Template to generate a shift/rotate
A temporary basic block is generated to handle 0-shift
@dst: destination
@shift_operation: the shift/rotate operation (ExprOp)
@setflags: (optional) if set, flags are updated (ZNC)
@onlyCarry: (optional) if set, Z and N flags won't be updated except if setflags is set.
@is_not: (optional) if set, behaves as MVN/MVNS
"""
op = shift_operation.op
# Compute carry (+ result for rrx)
if op == 'rrx':
res, new_cf = compute_rrx_carry(shift_operation)
shifter = ExprInt(1, 8)
elif op in ['<<', '>>', 'a>>']:
shifter = shift_operation.args[1]
if setflags or onlyCarry:
new_cf = ExprOp(op, shift_operation.args[0], shifter - ExprInt(1, size=shifter.size))
left = op[-1] == '<'
new_cf = new_cf.msb() if left else new_cf[:1]
res = shift_operation
elif op == '>>>':
shifter = shift_operation.args[1]
if setflags or onlyCarry:
new_cf = shift_operation.msb()
res = shift_operation
else:
raise NotImplementedError(f"Unknown shift / rotate operation : {op}")
# NOT the result and use it for ZN flags computations
if is_not:
res ^= ExprInt(-1, res.size)
# Build basic blocks
e_do = []
e = [ExprAssign(dst, res)]
if setflags:
e += update_flag_zn(res)
if setflags or onlyCarry:
e_do += [ExprAssign(cf, expr_simp(new_cf))]
# Don't generate conditional shifter on constant
if shifter.is_int():
if shifter.is_int(0):
# assignement + flags if setflags except cf
return (e, [])
else:
# assignement + flags if setflags
return (e + e_do, [])
loc_do, loc_do_expr = ir.gen_loc_key_and_expr(ir.IRDst.size)
loc_skip = ir.get_next_loc_key(instr)
loc_skip_expr = ExprLoc(loc_skip, ir.IRDst.size)
isPC = get_dst(dst)
if isPC is not None:
# Not really a Loc in this case
loc_skip_expr = res
e_do.append(ExprAssign(ir.IRDst, loc_skip_expr))
e.append(ExprAssign(
ir.IRDst, ExprCond(shifter, loc_do_expr, loc_skip_expr)))
return (e, [IRBlock(ir.loc_db, loc_do, [AssignBlock(e_do, instr)])])
def movs(ir, instr, a, b):
e = []
# handle shift / rotate
if b.is_op():
return _shift_rotate_tpl(ir, instr, a, b, setflags=a != PC)
e.append(ExprAssign(a, b))
# TODO handle cf
e += [ExprAssign(zf, ExprOp('FLAG_EQ', b))]
e += update_flag_nf(b)
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, b))
return e, []
def mvn(ir, instr, a, b):
if b.is_op():
return _shift_rotate_tpl(ir, instr, a, b, setflags=False, is_not=True)
r = b ^ ExprInt(-1, 32)
# TODO handle cf
e = [ExprAssign(a, r)]
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def mvns(ir, instr, a, b):
if b.is_op():
return _shift_rotate_tpl(ir, instr, a, b, setflags= a != PC, is_not=True)
e = []
r = b ^ ExprInt(-1, 32)
e.append(ExprAssign(a, r))
# TODO handle cf
e += [ExprAssign(zf, ExprOp('FLAG_EQ', r))]
e += update_flag_nf(r)
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def mrs(ir, instr, a, b):
e = []
if b.is_id('CPSR_cxsf'):
out = []
out.append(ExprInt(0x10, 28))
out.append(of)
out.append(cf)
out.append(zf)
out.append(nf)
e.append(ExprAssign(a, ExprCompose(*out)))
else:
raise NotImplementedError("MRS not implemented")
return e, []
def msr(ir, instr, a, b):
e = []
if a.is_id('CPSR_cf'):
e.append(ExprAssign(nf, b[31:32]))
e.append(ExprAssign(zf, b[30:31]))
e.append(ExprAssign(cf, b[29:30]))
e.append(ExprAssign(of, b[28:29]))
else:
raise NotImplementedError("MSR not implemented")
return e, []
def neg(ir, instr, a, b):
e = []
r = - b
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def negs(ir, instr, a, b):
return subs(ir, instr, a, ExprInt(0, b.size), b)
def bic(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = b & (c ^ ExprInt(-1, 32))
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def bics(ir, instr, a, b, c=None):
setflags = a != PC
if c is None:
b, c = a, b
if c.is_op():
e, extra_ir = _shift_rotate_tpl(ir, instr, a, c, onlyCarry=setflags)
# get back the result
c = e.pop(0).src
else:
e = []
extra_ir = []
tmp1, tmp2 = b, ~c
r = tmp1 & tmp2
e += [ExprAssign(zf, ExprOp('FLAG_EQ_AND', tmp1, tmp2))]
e += update_flag_nf(r)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, extra_ir
def sdiv(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
loc_except = ExprId(ir.loc_db.add_location(), ir.IRDst.size)
loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except)))
do_except = []
do_except.append(ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size)))
do_except.append(ExprAssign(ir.IRDst, loc_next))
blk_except = IRBlock(ir.loc_db, loc_except.loc_key, [AssignBlock(do_except, instr)])
r = ExprOp("sdiv", b, c)
do_div = []
do_div.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
do_div.append(ExprAssign(ir.IRDst, r))
do_div.append(ExprAssign(ir.IRDst, loc_next))
blk_div = IRBlock(ir.loc_db, loc_div.loc_key, [AssignBlock(do_div, instr)])
return e, [blk_div, blk_except]
def udiv(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
loc_div = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
loc_except = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
loc_next = ExprLoc(ir.get_next_loc_key(instr), ir.IRDst.size)
e.append(ExprAssign(ir.IRDst, ExprCond(c, loc_div, loc_except)))
do_except = []
do_except.append(ExprAssign(exception_flags, ExprInt(EXCEPT_DIV_BY_ZERO, exception_flags.size)))
do_except.append(ExprAssign(ir.IRDst, loc_next))
blk_except = IRBlock(ir.loc_db, loc_except.loc_key, [AssignBlock(do_except, instr)])
r = ExprOp("udiv", b, c)
do_div = []
do_div.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
do_div.append(ExprAssign(ir.IRDst, r))
do_div.append(ExprAssign(ir.IRDst, loc_next))
blk_div = IRBlock(ir.loc_db, loc_div.loc_key, [AssignBlock(do_div, instr)])
return e, [blk_div, blk_except]
def mla(ir, instr, a, b, c, d):
e = []
r = (b * c) + d
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def mlas(ir, instr, a, b, c, d):
e = []
r = (b * c) + d
e += update_flag_zn(r)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def mls(ir, instr, a, b, c, d):
e = []
r = d - (b * c)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def mul(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = b * c
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def muls(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = b * c
e += update_flag_zn(r)
e.append(ExprAssign(a, r))
dst = get_dst(a)
if dst is not None:
e.append(ExprAssign(ir.IRDst, r))
return e, []
def umull(ir, instr, a, b, c, d):
e = []
r = c.zeroExtend(64) * d.zeroExtend(64)
e.append(ExprAssign(a, r[0:32]))
e.append(ExprAssign(b, r[32:64]))
# r15/IRDst not allowed as output
return e, []
def umlal(ir, instr, a, b, c, d):
e = []
r = c.zeroExtend(64) * d.zeroExtend(64) + ExprCompose(a, b)
e.append(ExprAssign(a, r[0:32]))
e.append(ExprAssign(b, r[32:64]))
# r15/IRDst not allowed as output
return e, []
def smull(ir, instr, a, b, c, d):
e = []
r = c.signExtend(64) * d.signExtend(64)
e.append(ExprAssign(a, r[0:32]))
e.append(ExprAssign(b, r[32:64]))
# r15/IRDst not allowed as output
return e, []
def smlal(ir, instr, a, b, c, d):
e = []
r = c.signExtend(64) * d.signExtend(64) + ExprCompose(a, b)
e.append(ExprAssign(a, r[0:32]))
e.append(ExprAssign(b, r[32:64]))
# r15/IRDst not allowed as output
return e, []
def b(ir, instr, a):
e = []
e.append(ExprAssign(PC, a))
e.append(ExprAssign(ir.IRDst, a))
return e, []
def bl(ir, instr, a):
e = []
l = ExprInt(instr.offset + instr.l, 32)
e.append(ExprAssign(PC, a))
e.append(ExprAssign(ir.IRDst, a))
e.append(ExprAssign(LR, l))
return e, []
def bx(ir, instr, a):
e = []
e.append(ExprAssign(PC, a))
e.append(ExprAssign(ir.IRDst, a))
return e, []
def blx(ir, instr, a):
e = []
l = ExprInt(instr.offset + instr.l, 32)
e.append(ExprAssign(PC, a))
e.append(ExprAssign(ir.IRDst, a))
e.append(ExprAssign(LR, l))
return e, []
def st_ld_r(ir, instr, a, a2, b, store=False, size=32, s_ext=False, z_ext=False):
e = []
wb = False
postinc = False
b = b.ptr
if isinstance(b, ExprOp):
if b.op == "wback":
wb = True
b = b.args[0]
if b.op == "postinc":
postinc = True
if isinstance(b, ExprOp) and b.op in ["postinc", 'preinc']:
# XXX TODO CHECK
base, off = b.args[0], b.args[1] # ExprInt(size/8, 32)
else:
base, off = b, ExprInt(0, 32)
if postinc:
ad = base
else:
ad = base + off
# PC base lookup uses PC 4 byte alignment
ad = ad.replace_expr({PC: PC & ExprInt(0xFFFFFFFC, 32)})
dmem = False
if size in [8, 16]:
if store:
a = a[:size]
m = ExprMem(ad, size=size)
elif s_ext:
m = ExprMem(ad, size=size).signExtend(a.size)
elif z_ext:
m = ExprMem(ad, size=size).zeroExtend(a.size)
else:
raise ValueError('unhandled case')
elif size == 32:
m = ExprMem(ad, size=size)
elif size == 64:
assert a2 is not None
m = ExprMem(ad, size=32)
dmem = True
size = 32
else:
raise ValueError('the size DOES matter')
dst = None
if store:
e.append(ExprAssign(m, a))
if dmem:
e.append(ExprAssign(ExprMem(ad + ExprInt(4, 32), size=size), a2))
else:
if a == PC:
dst = PC
e.append(ExprAssign(ir.IRDst, m))
e.append(ExprAssign(a, m))
if dmem:
e.append(ExprAssign(a2, ExprMem(ad + ExprInt(4, 32), size=size)))
# XXX TODO check multiple write cause by wb
if wb or postinc:
e.append(ExprAssign(base, base + off))
return e, []
def ldr(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=False)
def ldrd(ir, instr, a, b, c=None):
if c is None:
a2 = ir.arch.regs.all_regs_ids[ir.arch.regs.all_regs_ids.index(a) + 1]
else:
a2 = b
b = c
return st_ld_r(ir, instr, a, a2, b, store=False, size=64)
def l_str(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=True)
def l_strd(ir, instr, a, b, c=None):
if c is None:
a2 = ir.arch.regs.all_regs_ids[ir.arch.regs.all_regs_ids.index(a) + 1]
else:
a2 = b
b = c
return st_ld_r(ir, instr, a, a2, b, store=True, size=64)
def ldrb(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=False, size=8, z_ext=True)
def ldrsb(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=False, size=8, s_ext=True, z_ext=False)
def strb(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=True, size=8)
def ldrh(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=False, size=16, z_ext=True)
def strh(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=True, size=16, z_ext=True)
def ldrsh(ir, instr, a, b):
return st_ld_r(ir, instr, a, None, b, store=False, size=16, s_ext=True, z_ext=False)
def st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=False):
e = []
wb = False
dst = None
if isinstance(a, ExprOp) and a.op == 'wback':
wb = True
a = a.args[0]
if isinstance(b, ExprOp) and b.op == 'sbit':
b = b.args[0]
regs = b.args
base = a
if updown:
step = 4
else:
step = -4
regs = regs[::-1]
if postinc:
pass
else:
base += ExprInt(step, 32)
for i, r in enumerate(regs):
ad = base + ExprInt(i * step, 32)
if store:
e.append(ExprAssign(ExprMem(ad, 32), r))
else:
e.append(ExprAssign(r, ExprMem(ad, 32)))
if r == PC:
e.append(ExprAssign(ir.IRDst, ExprMem(ad, 32)))
# XXX TODO check multiple write cause by wb
if wb:
if postinc:
e.append(ExprAssign(a, base + ExprInt(len(regs) * step, 32)))
else:
e.append(ExprAssign(a, base + ExprInt((len(regs) - 1) * step, 32)))
if store:
pass
else:
assert(isinstance(b, ExprOp) and b.op == "reglist")
return e, []
def ldmia(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=False, postinc=True, updown=True)
def ldmib(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=True)
def ldmda(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=False, postinc=True, updown=False)
def ldmdb(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=False, postinc=False, updown=False)
def stmia(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=True, postinc=True, updown=True)
def stmib(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=True, postinc=False, updown=True)
def stmda(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=True, postinc=True, updown=False)
def stmdb(ir, instr, a, b):
return st_ld_m(ir, instr, a, b, store=True, postinc=False, updown=False)
def svc(ir, instr, a):
e = []
except_int = EXCEPT_INT_XX
e.append(ExprAssign(exception_flags, ExprInt(except_int, 32)))
e.append(ExprAssign(interrupt_num, a))
return e, []
def und(ir, instr, a, b):
# XXX TODO implement
e = []
return e, []
def lsr(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
return _shift_rotate_tpl(ir, instr, a, b >> c, setflags=False)
def lsrs(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
return _shift_rotate_tpl(ir, instr, a, b >> c, setflags= a != PC)
def asr(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = ExprOp("a>>", b, c)
return _shift_rotate_tpl(ir, instr, a, r, setflags=False)
def asrs(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
r = ExprOp("a>>", b, c)
return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC)
def lsl(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
return _shift_rotate_tpl(ir, instr, a, b << c, setflags=False)
def lsls(ir, instr, a, b, c=None):
e = []
if c is None:
b, c = a, b
if c.is_op('rrx'):
c, _ = compute_rrx_carry(c)
return _shift_rotate_tpl(ir, instr, a, b << c, setflags= a != PC)
def rors(ir, instr, a, b):
e = []
r = ExprOp(">>>", a, b)
return _shift_rotate_tpl(ir, instr, a, r, setflags= a != PC)
def push(ir, instr, a):
e = []
regs = list(a.args)
for i in range(len(regs)):
r = SP + ExprInt(-4 * len(regs) + 4 * i, 32)
e.append(ExprAssign(ExprMem(r, 32), regs[i]))
r = SP + ExprInt(-4 * len(regs), 32)
e.append(ExprAssign(SP, r))
return e, []
def pop(ir, instr, a):
e = []
regs = list(a.args)
dst = None
for i in range(len(regs)):
r = SP + ExprInt(4 * i, 32)
e.append(ExprAssign(regs[i], ExprMem(r, 32)))
if regs[i] == ir.pc:
dst = ExprMem(r, 32)
r = SP + ExprInt(4 * len(regs), 32)
e.append(ExprAssign(SP, r))
if dst is not None:
e.append(ExprAssign(ir.IRDst, dst))
return e, []
def cbz(ir, instr, a, b):
e = []
loc_next = ir.get_next_loc_key(instr)
loc_next_expr = ExprLoc(loc_next, 32)
e.append(ExprAssign(ir.IRDst, ExprCond(a, loc_next_expr, b)))
return e, []
def cbnz(ir, instr, a, b):
e = []
loc_next = ir.get_next_loc_key(instr)
loc_next_expr = ExprLoc(loc_next, 32)
e.append(ExprAssign(ir.IRDst, ExprCond(a, b, loc_next_expr)))
return e, []
def uxtb(ir, instr, a, b):
e = []
r = b[:8].zeroExtend(32)
e.append(ExprAssign(a, r))
dst = None
if PC in a.get_r():
dst = PC
e.append(ExprAssign(ir.IRDst, r))
return e, []
def uxth(ir, instr, a, b):
e = []
r = b[:16].zeroExtend(32)
e.append(ExprAssign(a, r))
dst = None
if PC in a.get_r():
dst = PC
e.append(ExprAssign(ir.IRDst, r))
return e, []
def sxtb(ir, instr, a, b):
e = []
r = b[:8].signExtend(32)
e.append(ExprAssign(a, r))
dst = None
if PC in a.get_r():
dst = PC
e.append(ExprAssign(ir.IRDst, r))
return e, []
def sxth(ir, instr, a, b):
e = []
r = b[:16].signExtend(32)
e.append(ExprAssign(a, r))
dst = None
if PC in a.get_r():
dst = PC
e.append(ExprAssign(ir.IRDst, r))
return e, []
def ubfx(ir, instr, a, b, c, d):
e = []
c = int(c)
d = int(d)
r = b[c:c+d].zeroExtend(32)
e.append(ExprAssign(a, r))
dst = None
if PC in a.get_r():
dst = PC
e.append(ExprAssign(ir.IRDst, r))
return e, []
def bfc(ir, instr, a, b, c):
e = []
start = int(b)
stop = start + int(c)
out = []
last = 0
if start:
out.append(a[:start])
last = start
if stop - start:
out.append(ExprInt(0, 32)[last:stop])
last = stop
if last < 32:
out.append(a[last:])
r = ExprCompose(*out)
e.append(ExprAssign(a, r))
dst = None
if PC in a.get_r():
dst = PC
e.append(ExprAssign(ir.IRDst, r))
return e, []
def pld(ir, instr, a):
e = []
return e, []
def pldw(ir, instr, a):
e = []
return e, []
def clz(ir, instr, a, b):
e = []
e.append(ExprAssign(a, ExprOp('cntleadzeros', b)))
return e, []
def uxtab(ir, instr, a, b, c):
e = []
e.append(ExprAssign(a, b + (c & ExprInt(0xff, 32))))
return e, []
def uxtah(ir, instr, a, b, c):
e = []
e.append(ExprAssign(a, b + (c & ExprInt(0xffff, 32))))
return e, []
def bkpt(ir, instr, a):
e = []
e.append(ExprAssign(exception_flags, ExprInt(EXCEPT_SOFT_BP, 32)))
e.append(ExprAssign(bp_num, a))
return e, []
def _extract_s16(arg, part):
if part == 'B': # bottom 16 bits
return arg[0:16]
elif part == 'T': # top 16 bits
return arg[16:32]
def smul(ir, instr, a, b, c):
e = []
e.append(ExprAssign(a, _extract_s16(b, instr.name[4]).signExtend(32) * _extract_s16(c, instr.name[5]).signExtend(32)))
return e, []
def smulw(ir, instr, a, b, c):
e = []
prod = b.signExtend(48) * _extract_s16(c, instr.name[5]).signExtend(48)
e.append(ExprAssign(a, prod[16:48]))
return e, [] # signed most significant 32 bits of the 48-bit result
def tbb(ir, instr, a):
e = []
dst = PC + ExprInt(2, 32) * a.zeroExtend(32)
e.append(ExprAssign(PC, dst))
e.append(ExprAssign(ir.IRDst, dst))
return e, []
def tbh(ir, instr, a):
e = []
dst = PC + ExprInt(2, 32) * a.zeroExtend(32)
e.append(ExprAssign(PC, dst))
e.append(ExprAssign(ir.IRDst, dst))
return e, []
def smlabb(ir, instr, a, b, c, d):
e = []
result = (b[:16].signExtend(32) * c[:16].signExtend(32)) + d
e.append(ExprAssign(a, result))
return e, []
def smlabt(ir, instr, a, b, c, d):
e = []
result = (b[:16].signExtend(32) * c[16:32].signExtend(32)) + d
e.append(ExprAssign(a, result))
return e, []
def smlatb(ir, instr, a, b, c, d):
e = []
result = (b[16:32].signExtend(32) * c[:16].signExtend(32)) + d
e.append(ExprAssign(a, result))
return e, []
def smlatt(ir, instr, a, b, c, d):
e = []
result = (b[16:32].signExtend(32) * c[16:32].signExtend(32)) + d
e.append(ExprAssign(a, result))
return e, []
def uadd8(ir, instr, a, b, c):
e = []
sums = []
ges = []
for i in range(0, 32, 8):
sums.append(b[i:i+8] + c[i:i+8])
ges.append((b[i:i+8].zeroExtend(9) + c[i:i+8].zeroExtend(9))[8:9])
e.append(ExprAssign(a, ExprCompose(*sums)))
for i, value in enumerate(ges):
e.append(ExprAssign(ge_regs[i], value))
return e, []
def sel(ir, instr, a, b, c):
e = []
cond = nf ^ of ^ ExprInt(1, 1)
parts = []
for i in range(4):
parts.append(ExprCond(ge_regs[i], b[i*8:(i+1)*8], c[i*8:(i+1)*8]))
result = ExprCompose(*parts)
e.append(ExprAssign(a, result))
return e, []
def rev(ir, instr, a, b):
e = []
result = ExprCompose(b[24:32], b[16:24], b[8:16], b[:8])
e.append(ExprAssign(a, result))
return e, []
def rev16(ir, instr, a, b):
e = []
result = ExprCompose(b[8:16], b[:8], b[24:32], b[16:24])
e.append(ExprAssign(a, result))
return e, []
def nop(ir, instr):
e = []
return e, []
def dsb(ir, instr, a):
# XXX TODO
e = []
return e, []
def isb(ir, instr, a):
# XXX TODO
e = []
return e, []
def cpsie(ir, instr, a):
# XXX TODO
e = []
return e, []
def cpsid(ir, instr, a):
# XXX TODO
e = []
return e, []
def wfe(ir, instr):
# XXX TODO
e = []
return e, []
def wfi(ir, instr):
# XXX TODO
e = []
return e, []
def adr(ir, instr, arg1, arg2):
e = []
e.append(ExprAssign(arg1, (PC & ExprInt(0xfffffffc, 32)) + arg2))
return e, []
def pkhbt(ir, instr, arg1, arg2, arg3):
e = []
e.append(
ExprAssign(
arg1,
ExprCompose(
arg2[:16],
arg3[16:]
)
)
)
return e, []
def pkhtb(ir, instr, arg1, arg2, arg3):
e = []
e.append(
ExprAssign(
arg1,
ExprCompose(
arg3[:16],
arg2[16:]
)
)
)
return e, []
def mrc(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6):
e = []
sreg = (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6))
if sreg in coproc_reg_dict:
e.append(ExprAssign(arg3, coproc_reg_dict[sreg]))
else:
raise NotImplementedError("Unknown coprocessor register: %s %s %d %s %d" % (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6)))
return e, []
def mcr(ir, insr, arg1, arg2, arg3, arg4, arg5, arg6):
e = []
sreg = (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6))
if sreg in coproc_reg_dict:
e.append(ExprAssign(coproc_reg_dict[sreg], arg3))
else:
raise NotImplementedError("Unknown coprocessor register: %s %s %d %s %d" % (str(arg1), str(arg4), int(arg2), str(arg5), int(arg6)))
return e, []
COND_EQ = 0
COND_NE = 1
COND_CS = 2
COND_CC = 3
COND_MI = 4
COND_PL = 5
COND_VS = 6
COND_VC = 7
COND_HI = 8
COND_LS = 9
COND_GE = 10
COND_LT = 11
COND_GT = 12
COND_LE = 13
COND_AL = 14
COND_NV = 15
cond_dct = {
COND_EQ: "EQ",
COND_NE: "NE",
COND_CS: "CS",
COND_CC: "CC",
COND_MI: "MI",
COND_PL: "PL",
COND_VS: "VS",
COND_VC: "VC",
COND_HI: "HI",
COND_LS: "LS",
COND_GE: "GE",
COND_LT: "LT",
COND_GT: "GT",
COND_LE: "LE",
COND_AL: "AL",
# COND_NV: "NV",
}
cond_dct_inv = dict((name, num) for num, name in viewitems(cond_dct))
"""
Code Meaning (for cmp or subs) Flags Tested
eq Equal. Z==1
ne Not equal. Z==0
cs or hs Unsigned higher or same (or carry set). C==1
cc or lo Unsigned lower (or carry clear). C==0
mi Negative. The mnemonic stands for "minus". N==1
pl Positive or zero. The mnemonic stands for "plus". N==0
vs Signed overflow. The mnemonic stands for "V set". V==1
vc No signed overflow. The mnemonic stands for "V clear". V==0
hi Unsigned higher. (C==1) && (Z==0)
ls Unsigned lower or same. (C==0) || (Z==1)
ge Signed greater than or equal. N==V
lt Signed less than. N!=V
gt Signed greater than. (Z==0) && (N==V)
le Signed less than or equal. (Z==1) || (N!=V)
al (or omitted) Always executed. None tested.
"""
tab_cond = {COND_EQ: ExprOp("CC_EQ", zf),
COND_NE: ExprOp("CC_NE", zf),
COND_CS: ExprOp("CC_U>=", cf ^ ExprInt(1, 1)), # inv cf
COND_CC: ExprOp("CC_U<", cf ^ ExprInt(1, 1)), # inv cf
COND_MI: ExprOp("CC_NEG", nf),
COND_PL: ExprOp("CC_POS", nf),
COND_VS: ExprOp("CC_sOVR", of),
COND_VC: ExprOp("CC_sNOOVR", of),
COND_HI: ExprOp("CC_U>", cf ^ ExprInt(1, 1), zf), # inv cf
COND_LS: ExprOp("CC_U<=", cf ^ ExprInt(1, 1), zf), # inv cf
COND_GE: ExprOp("CC_S>=", nf, of),
COND_LT: ExprOp("CC_S<", nf, of),
COND_GT: ExprOp("CC_S>", nf, of, zf),
COND_LE: ExprOp("CC_S<=", nf, of, zf),
}
def is_pc_written(ir, instr_ir):
all_pc = viewvalues(ir.mn.pc)
for ir in instr_ir:
if ir.dst in all_pc:
return True, ir.dst
return False, None
def add_condition_expr(ir, instr, cond, instr_ir, extra_ir):
if cond == COND_AL:
return instr_ir, extra_ir
if not cond in tab_cond:
raise ValueError('unknown condition %r' % cond)
cond = tab_cond[cond]
loc_next = ir.get_next_loc_key(instr)
loc_next_expr = ExprLoc(loc_next, 32)
loc_do = ir.loc_db.add_location()
loc_do_expr = ExprLoc(loc_do, 32)
dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr)
assert(isinstance(instr_ir, list))
has_irdst = False
for e in instr_ir:
if e.dst == ir.IRDst:
has_irdst = True
break
if not has_irdst:
instr_ir.append(ExprAssign(ir.IRDst, loc_next_expr))
e_do = IRBlock(ir.loc_db, loc_do, [AssignBlock(instr_ir, instr)])
e = [ExprAssign(ir.IRDst, dst_cond)]
return e, [e_do] + extra_ir
mnemo_func = {}
mnemo_func_cond = {}
mnemo_condm0 = {'add': add,
'sub': sub,
'eor': eor,
'and': l_and,
'rsb': rsb,
'adc': adc,
'sbc': sbc,
'rsc': rsc,
'tst': tst,
'teq': teq,
'cmp': l_cmp,
'cmn': cmn,
'orr': orr,
'mov': mov,
'movt': movt,
'bic': bic,
'mvn': mvn,
'neg': neg,
'sdiv': sdiv,
'udiv': udiv,
'mrc': mrc,
'mcr': mcr,
'mul': mul,
'umull': umull,
'umlal': umlal,
'smull': smull,
'smlal': smlal,
'mla': mla,
'ldr': ldr,
'ldrd': ldrd,
'ldrsb': ldrsb,
'str': l_str,
'strd': l_strd,
'b': b,
'bl': bl,
'svc': svc,
'und': und,
'bx': bx,
'ldrh': ldrh,
'strh': strh,
'ldrsh': ldrsh,
'ldsh': ldrsh,
'uxtb': uxtb,
'uxth': uxth,
'sxtb': sxtb,
'sxth': sxth,
'ubfx': ubfx,
'bfc': bfc,
'rev': rev,
'rev16': rev16,
'clz': clz,
'uxtab': uxtab,
'uxtah': uxtah,
'bkpt': bkpt,
'smulbb': smul,
'smulbt': smul,
'smultb': smul,
'smultt': smul,
'smulwt': smulw,
'smulwb': smulw,
'pkhtb': pkhtb,
'pkhbt': pkhbt,
}
mnemo_condm1 = {'adds': add,
'subs': subs,
'eors': eors,
'ands': l_and,
'rsbs': rsbs,
'adcs': adc,
'sbcs': sbcs,
'rscs': rscs,
'orrs': orrs,
'movs': movs,
'bics': bics,
'mvns': mvns,
'mrs': mrs,
'msr': msr,
'negs': negs,
'muls': muls,
'mls': mls,
'mlas': mlas,
'blx': blx,
'ldrb': ldrb,
'ldsb': ldrsb,
'strb': strb,
}
mnemo_condm2 = {'ldmia': ldmia,
'ldmib': ldmib,
'ldmda': ldmda,
'ldmdb': ldmdb,
'ldmfa': ldmda,
'ldmfd': ldmia,
'ldmea': ldmdb,
'ldmed': ldmib, # XXX
'stmia': stmia,
'stmib': stmib,
'stmda': stmda,
'stmdb': stmdb,
'stmfa': stmib,
'stmed': stmda,
'stmfd': stmdb,
'stmea': stmia,
}
mnemo_nocond = {'lsr': lsr,
'lsrs': lsrs,
'lsl': lsl,
'lsls': lsls,
'rors': rors,
'push': push,
'pop': pop,
'asr': asr,
'asrs': asrs,
'cbz': cbz,
'cbnz': cbnz,
'pld': pld,
'pldw': pldw,
'tbb': tbb,
'tbh': tbh,
'nop': nop,
'dsb': dsb,
'isb': isb,
'cpsie': cpsie,
'cpsid': cpsid,
'wfe': wfe,
'wfi': wfi,
'adr': adr,
'orn': orn,
'smlabb': smlabb,
'smlabt': smlabt,
'smlatb': smlatb,
'smlatt': smlatt,
'uadd8': uadd8,
'sel': sel,
}
mn_cond_x = [mnemo_condm0,
mnemo_condm1,
mnemo_condm2]
for index, mn_base in enumerate(mn_cond_x):
for mn, mf in viewitems(mn_base):
for cond, cn in viewitems(cond_dct):
if cond == COND_AL:
cn = ""
cn = cn.lower()
if index == 0:
mn_mod = mn + cn
else:
mn_mod = mn[:-index] + cn + mn[-index:]
# print mn_mod
mnemo_func_cond[mn_mod] = cond, mf
for name, mf in viewitems(mnemo_nocond):
mnemo_func_cond[name] = COND_AL, mf
def split_expr_dst(ir, instr_ir):
out = []
dst = None
for i in instr_ir:
if i.dst == ir.pc:
out.append(i)
dst = ir.pc # i.src
else:
out.append(i)
return out, dst
def get_mnemo_expr(ir, instr, *args):
if not instr.name.lower() in mnemo_func_cond:
raise ValueError('unknown mnemo %s' % instr)
cond, mf = mnemo_func_cond[instr.name.lower()]
instr_ir, extra_ir = mf(ir, instr, *args)
instr, extra_ir = add_condition_expr(ir, instr, cond, instr_ir, extra_ir)
return instr, extra_ir
get_arm_instr_expr = get_mnemo_expr
class arminfo(object):
mode = "arm"
# offset
class Lifter_Arml(Lifter):
def __init__(self, loc_db):
Lifter.__init__(self, mn_arm, "l", loc_db)
self.pc = PC
self.sp = SP
self.IRDst = ExprId('IRDst', 32)
self.addrsize = 32
def mod_pc(self, instr, instr_ir, extra_ir):
# fix PC (+8 for arm)
pc_fixed = {self.pc: ExprInt(instr.offset + 8, 32)}
for i, expr in enumerate(instr_ir):
dst, src = expr.dst, expr.src
if dst != self.pc:
dst = dst.replace_expr(pc_fixed)
src = src.replace_expr(pc_fixed)
instr_ir[i] = ExprAssign(dst, src)
for idx, irblock in enumerate(extra_ir):
extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
if expr != self.pc else expr,
lambda expr: expr.replace_expr(pc_fixed))
def get_ir(self, instr):
args = instr.args
# ir = get_mnemo_expr(self, self.name.lower(), *args)
if len(args) and isinstance(args[-1], ExprOp):
if (args[-1].op in ['<<', '>>', '<<a', 'a>>', '<<<', '>>>'] and
isinstance(args[-1].args[-1], ExprId)):
args[-1] = ExprOp(args[-1].op,
args[-1].args[0],
args[-1].args[-1][:8].zeroExtend(32))
instr_ir, extra_ir = get_mnemo_expr(self, instr, *args)
self.mod_pc(instr, instr_ir, extra_ir)
return instr_ir, extra_ir
def parse_itt(self, instr):
name = instr.name
assert name.startswith('IT')
name = name[1:]
out = []
for hint in name:
if hint == 'T':
out.append(0)
elif hint == "E":
out.append(1)
else:
raise ValueError("IT name invalid %s" % instr)
return out, instr.args[0]
def do_it_block(self, loc, index, block, assignments, gen_pc_updt):
instr = block.lines[index]
it_hints, it_cond = self.parse_itt(instr)
cond_num = cond_dct_inv[it_cond.name]
cond_eq = tab_cond[cond_num]
if not index + len(it_hints) <= len(block.lines):
raise NotImplementedError("Split IT block non supported yet")
ir_blocks_all = []
# Gen dummy irblock for IT instr
loc_next = self.get_next_loc_key(instr)
dst = ExprAssign(self.IRDst, ExprLoc(loc_next, 32))
dst_blk = AssignBlock([dst], instr)
assignments.append(dst_blk)
irblock = IRBlock(self.loc_db, loc, assignments)
ir_blocks_all.append([irblock])
loc = loc_next
assignments = []
for hint in it_hints:
irblocks = []
index += 1
instr = block.lines[index]
# Add conditional jump to current irblock
loc_do = self.loc_db.add_location()
loc_next = self.get_next_loc_key(instr)
if hint:
local_cond = ~cond_eq
else:
local_cond = cond_eq
dst = ExprAssign(self.IRDst, ExprCond(local_cond, ExprLoc(loc_do, 32), ExprLoc(loc_next, 32)))
dst_blk = AssignBlock([dst], instr)
assignments.append(dst_blk)
irblock = IRBlock(self.loc_db, loc, assignments)
irblocks.append(irblock)
it_instr_irblocks = []
assignments = []
loc = loc_do
split = self.add_instr_to_current_state(
instr, block, assignments,
it_instr_irblocks, gen_pc_updt
)
if split:
raise NotImplementedError("Unsupported instr in IT block (%s)" % instr)
if it_instr_irblocks:
assert len(it_instr_irblocks) == 1
it_instr_irblocks = it_instr_irblocks.pop()
# Remove flags assignment if instr != [CMP, CMN, TST]
if instr.name not in ["CMP", "CMN", "TST"]:
# Fix assignments
out = []
for assignment in assignments:
assignment = AssignBlock(
{
dst: src for (dst, src) in viewitems(assignment)
if dst not in [zf, nf, of, cf]
},
assignment.instr
)
out.append(assignment)
assignments = out
# Fix extra irblocksx
new_irblocks = []
for irblock in it_instr_irblocks:
out = []
for tmp_assignment in irblock:
assignment = AssignBlock(
{
dst: src for (dst, src) in viewitems(assignment)
if dst not in [zf, nf, of, cf]
},
assignment.instr
)
out.append(assignment)
new_irblock = IRBlock(self.loc_db, irblock.loc_key, out)
new_irblocks.append(new_irblock)
it_instr_irblocks = new_irblocks
irblocks += it_instr_irblocks
dst = ExprAssign(self.IRDst, ExprLoc(loc_next, 32))
dst_blk = AssignBlock([dst], instr)
assignments.append(dst_blk)
irblock = IRBlock(self.loc_db, loc, assignments)
irblocks.append(irblock)
loc = loc_next
assignments = []
ir_blocks_all.append(irblocks)
return index, ir_blocks_all
def add_asmblock_to_ircfg(self, block, ircfg, gen_pc_updt=False):
"""
Add a native block to the current IR
@block: native assembly block
@gen_pc_updt: insert PC update effects between instructions
"""
it_hints = None
it_cond = None
label = block.loc_key
assignments = []
ir_blocks_all = []
index = -1
while index + 1 < len(block.lines):
index += 1
instr = block.lines[index]
if label is None:
assignments = []
label = self.get_loc_key_for_instr(instr)
if instr.name.startswith("IT"):
index, irblocks_it = self.do_it_block(label, index, block, assignments, gen_pc_updt)
for irblocks in irblocks_it:
ir_blocks_all += irblocks
label = None
continue
split = self.add_instr_to_current_state(
instr, block, assignments,
ir_blocks_all, gen_pc_updt
)
if split:
ir_blocks_all.append(IRBlock(self.loc_db, label, assignments))
label = None
assignments = []
if label is not None:
ir_blocks_all.append(IRBlock(self.loc_db, label, assignments))
new_ir_blocks_all = self.post_add_asmblock_to_ircfg(block, ircfg, ir_blocks_all)
for irblock in new_ir_blocks_all:
ircfg.add_irblock(irblock)
return new_ir_blocks_all
class Lifter_Armb(Lifter_Arml):
def __init__(self, loc_db):
Lifter.__init__(self, mn_arm, "b", loc_db)
self.pc = PC
self.sp = SP
self.IRDst = ExprId('IRDst', 32)
self.addrsize = 32
class Lifter_Armtl(Lifter_Arml):
def __init__(self, loc_db):
Lifter.__init__(self, mn_armt, "l", loc_db)
self.pc = PC
self.sp = SP
self.IRDst = ExprId('IRDst', 32)
self.addrsize = 32
def mod_pc(self, instr, instr_ir, extra_ir):
# fix PC (+4 for thumb)
pc_fixed = {self.pc: ExprInt(instr.offset + 4, 32)}
for i, expr in enumerate(instr_ir):
dst, src = expr.dst, expr.src
if dst != self.pc:
dst = dst.replace_expr(pc_fixed)
src = src.replace_expr(pc_fixed)
instr_ir[i] = ExprAssign(dst, src)
for idx, irblock in enumerate(extra_ir):
extra_ir[idx] = irblock.modify_exprs(lambda expr: expr.replace_expr(pc_fixed) \
if expr != self.pc else expr,
lambda expr: expr.replace_expr(pc_fixed))
class Lifter_Armtb(Lifter_Armtl):
def __init__(self, loc_db):
Lifter.__init__(self, mn_armt, "b", loc_db)
self.pc = PC
self.sp = SP
self.IRDst = ExprId('IRDst', 32)
self.addrsize = 32