예제 #1
0
    def call_effects(self, ad, instr):
        call_assignblk = AssignBlock(
            [
                ExprAff(
                    self.ret_reg,
                    ExprOp(
                        'call_func_ret',
                        ad,
                        self.arch.regs.R0,
                        self.arch.regs.R1,
                        self.arch.regs.R2,
                        self.arch.regs.R3,
                    )
                ),
                ExprAff(
                    self.sp,
                    ExprOp('call_func_stack', ad, self.sp)
                ),
            ],
            instr
        )


        cond = instr.additional_info.cond
        if cond == 14: # COND_ALWAYS:
            return [call_assignblk], []

        # Call is a conditional instruction
        cond = tab_cond[cond]

        loc_next = self.get_next_loc_key(instr)
        loc_next_expr = ExprLoc(loc_next, 32)
        loc_do = self.loc_db.add_location()
        loc_do_expr = ExprLoc(loc_do, 32)
        dst_cond = ExprCond(cond, loc_do_expr, loc_next_expr)

        call_assignblks = [
            call_assignblk,
            AssignBlock([ExprAff(self.IRDst, loc_next_expr)], instr),
        ]
        e_do = IRBlock(loc_do, call_assignblks)
        assignblks_out = [
            AssignBlock([ExprAff(self.IRDst, dst_cond)], instr)
        ]
        return assignblks_out, [e_do]
예제 #2
0
 def _convert_phi(self):
     """Inserts corresponding phi functions inplace
     into IRBlock at the beginning"""
     for loc_key in self._phinodes:
         irblock = self.get_block(loc_key)
         assignblk = AssignBlock(self._phinodes[loc_key])
         # insert at the beginning
         new_irs = IRBlock(loc_key, [assignblk] + list(irblock.assignblks))
         self.ircfg.blocks[loc_key] = new_irs
예제 #3
0
파일: symbexec.py 프로젝트: sigalpes/miasm
 def as_assignblock(self):
     """Return the current state as an AssignBlock"""
     warnings.warn(
         'DEPRECATION WARNING: use "modified(ids=True, mems=True)" instead of as_assignblock'
     )
     out = []
     for dst, src in self.modified(ids=True, mems=True):
         out.append((dst, src))
     return AssignBlock(dict(out))
예제 #4
0
파일: unssa.py 프로젝트: hax0kartik/miasm
def gen_irblock(label, exprs_list):
    irs = []
    for exprs in exprs_list:
        if isinstance(exprs, AssignBlock):
            irs.append(exprs)
        else:
            irs.append(AssignBlock(exprs))

    irbl = IRBlock(label, irs)
    return irbl
예제 #5
0
 def call_effects(self, ad, instr):
     print hex(instr.offset), instr
     stk_before = idc.GetSpd(instr.offset)
     stk_after = idc.GetSpd(instr.offset + instr.l)
     stk_diff = stk_after - stk_before
     print hex(stk_diff)
     call_assignblk = AssignBlock([
         ExprAssign(self.ret_reg, ExprOp('call_func_ret', ad)),
         ExprAssign(self.sp, self.sp + ExprInt(stk_diff, self.sp.size))
     ], instr)
     return [call_assignblk], []
예제 #6
0
def gen_irblock(label, exprs_list):
    lines = [None for _ in xrange(len(exprs_list))]
    irs = []
    for exprs in exprs_list:
        if isinstance(exprs, AssignBlock):
            irs.append(exprs)
        else:
            irs.append(AssignBlock(exprs))

    irbl = IRBlock(label, irs, lines)
    return irbl
예제 #7
0
 def call_effects(self, ad):
     """
     Default simulation of a function call to @ad
     @ad: (Expr) address of the called function
     """
     return [
         AssignBlock([
             ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)),
             ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)),
         ])
     ]
예제 #8
0
파일: ira.py 프로젝트: sploving/miasm
 def call_effects(self, ad, instr):
     return [AssignBlock([ExprAff(self.ret_reg, ExprOp('call_func_ret', ad,
                                                       self.sp,
                                                       self.arch.regs.R3,
                                                       self.arch.regs.R4,
                                                       self.arch.regs.R5,
                                                       )),
                          ExprAff(self.sp, ExprOp('call_func_stack',
                                                  ad, self.sp)),
                         ],
                          instr
                        )]
예제 #9
0
파일: full.py 프로젝트: hax0kartik/miasm
 def call_effects(self, addr, instr):
     assignblks, extra = super(IRADelModCallStack, self).call_effects(addr, instr)
     if not args.calldontmodstack:
         return assignblks, extra
     out = []
     for assignblk in assignblks:
         dct = dict(assignblk)
         dct = {
             dst:src for (dst, src) in dct.iteritems() if dst != self.sp
         }
         out.append(AssignBlock(dct, assignblk.instr))
     return out, extra
예제 #10
0
파일: symbexec.py 프로젝트: sicceer/miasm
    def apply_expr(self, expr):
        """Evaluate @expr and apply side effect if needed (ie. if expr is an
        assignment). Return the evaluated value"""

        # Update value if needed
        if isinstance(expr, m2_expr.ExprAff):
            ret = self.eval_expr(expr.src)
            self.eval_ir(AssignBlock([expr]))
        else:
            ret = self.eval_expr(expr)

        return ret
예제 #11
0
    def insert_parallel_copy(self):
        """
        Naive Out-of-SSA from CSSA (without coalescing for now)
        - Replace Phi
        - Create room for parallel copies in Phi's parents
        """
        ircfg = self.ssa.graph

        for irblock in ircfg.blocks.values():
            if not irblock_has_phi(irblock):
                continue

            # Replace Phi with Phi's dst = new_var
            parallel_copies = {}
            for dst in self.phi_destinations[irblock.loc_key]:
                new_var = self.phi_new_var[dst]
                parallel_copies[dst] = new_var

            assignblks = list(irblock)
            assignblks[0] = AssignBlock(parallel_copies, irblock[0].instr)
            new_irblock = IRBlock(irblock.loc_key, assignblks)
            ircfg.blocks[irblock.loc_key] = new_irblock

            # Insert new_var = src in each Phi's parent, at the end of the block
            parent_to_parallel_copies = {}
            parallel_copies = {}
            for dst in irblock[0]:
                new_var = self.phi_new_var[dst]
                for parent, src in self.phi_parent_sources[dst]:
                    parent_to_parallel_copies.setdefault(parent,
                                                         {})[new_var] = src

            for parent, parallel_copies in parent_to_parallel_copies.iteritems(
            ):
                parent = ircfg.blocks[parent]
                assignblks = list(parent)
                assignblks.append(
                    AssignBlock(parallel_copies, parent[-1].instr))
                new_irblock = IRBlock(parent.loc_key, assignblks)
                ircfg.blocks[parent.loc_key] = new_irblock
예제 #12
0
def gen_irblock(label, exprs_list):
    """ Returns an IRBlock.
    Used only for tests purpose
    """
    irs = []
    for exprs in exprs_list:
        if isinstance(exprs, AssignBlock):
            irs.append(exprs)
        else:
            irs.append(AssignBlock(exprs))

    irbl = IRBlock(label, irs)
    return irbl
예제 #13
0
파일: sem.py 프로젝트: manwefm/miasm
def casp(ir, instr, arg1, arg2, arg3):
    # XXX TODO: memory barrier
    e = []
    if arg1.size == 32:
        regs = gpregs32_expr
    else:
        regs = gpregs64_expr
    index1 = regs.index(arg1)
    index2 = regs.index(arg2)

    # TODO endianness
    comp_value = ExprCompose(regs[index1], regs[index1 + 1])
    new_value = ExprCompose(regs[index2], regs[index2 + 1])
    assert arg3.is_op('preinc')
    ptr = arg3.args[0]
    data = ExprMem(ptr, comp_value.size)

    loc_store = ExprLoc(ir.loc_db.add_location(), ir.IRDst.size)
    loc_do = 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(ExprOp("FLAG_EQ_CMP", data, comp_value), loc_do,
                     loc_store)))

    e_store = []
    e_store.append(ExprAssign(data, new_value))
    e_store.append(ExprAssign(ir.IRDst, loc_do))
    blk_store = IRBlock(loc_store.loc_key, [AssignBlock(e_store, instr)])

    e_do = []
    e_do.append(ExprAssign(regs[index1], data[:data.size / 2]))
    e_do.append(ExprAssign(regs[index1 + 1], data[data.size / 2:]))
    e_do.append(ExprAssign(ir.IRDst, loc_next))
    blk_do = IRBlock(loc_do.loc_key, [AssignBlock(e_do, instr)])

    return e, [blk_store, blk_do]
예제 #14
0
 def assignblk_to_irbloc(self, instr, assignblk):
     """
     Ensure IRDst is always set in the head @assignblk of the @instr
     @instr: an instruction instance
     @assignblk: Assignblk instance
     """
     new_assignblk = dict(assignblk)
     if self.ir_arch.IRDst not in assignblk:
         offset = instr.offset + instr.l
         dst = m2_expr.ExprInt(offset, self.ir_arch.IRDst.size)
         new_assignblk[self.ir_arch.IRDst] = dst
     irs = [AssignBlock(new_assignblk, instr)]
     return IRBlock(self.ir_arch.get_instr_label(instr), irs)
예제 #15
0
    def apply_expr(self, expr):
        """Evaluate @expr and apply side effect if needed (ie. if expr is an
        assignment). Return the evaluated value"""

        # Eval expression
        to_eval = expr.src if isinstance(expr, m2_expr.ExprAff) else expr
        ret = self.expr_simp(self.eval_expr(to_eval))

        # Update value if needed
        if isinstance(expr, m2_expr.ExprAff):
            self.eval_ir(AssignBlock([m2_expr.ExprAff(expr.dst, ret)]))

        return ret
예제 #16
0
파일: unssa.py 프로젝트: hax0kartik/miasm
def add_out_reg_end(ir_arch_a, ircfg_a):
    # Add dummy dependency to uncover out regs affectation
    for loc in ircfg_a.leaves():
        irblock = ircfg_a.blocks.get(loc)
        if irblock is None:
            continue
        regs = {}
        for reg in ir_arch_a.get_out_regs(irblock):
            regs[reg] = reg
        assignblks = list(irblock)
        new_assiblk = AssignBlock(regs, assignblks[-1].instr)
        assignblks.append(new_assiblk)
        new_irblock = IRBlock(irblock.loc_key, assignblks)
        ircfg_a.blocks[loc] = new_irblock
예제 #17
0
파일: ssa.py 프로젝트: hax0kartik/miasm
 def remove_assign_eq(self):
     """
     Remove trivial expressions (a=a) in the current graph
     """
     for irblock in self.ssa.graph.blocks.values():
         assignblks = list(irblock)
         for i, assignblk in enumerate(assignblks):
             out = {}
             for dst, src in assignblk.iteritems():
                 if dst == src:
                     continue
                 out[dst] = src
             assignblks[i] = AssignBlock(out, assignblk.instr)
         self.ssa.graph.blocks[irblock.loc_key] = IRBlock(irblock.loc_key, assignblks)
예제 #18
0
def gen_irbloc(label, exprs_list):
    """ Returns an IRBlock with empty lines.
    Used only for tests purpose
    """
    lines = [None for _ in xrange(len(exprs_list))]
    irs = []
    for exprs in exprs_list:
        if isinstance(exprs, AssignBlock):
            irs.append(exprs)
        else:
            irs.append(AssignBlock(exprs))

    irbl = irbloc(label, irs, lines)
    return irbl
예제 #19
0
    def eval_updt_expr(self, expr):
        """
        Evaluate @expr and apply side effect if needed (ie. if expr is an
        assignment). Return the evaluated value
        """

        # Update value if needed
        if expr.is_aff():
            ret = self.eval_expr(expr.src)
            self.eval_updt_assignblk(AssignBlock([expr]))
        else:
            ret = self.eval_expr(expr)

        return ret
예제 #20
0
파일: codegen.py 프로젝트: sploving/miasm
 def assignblk_to_irbloc(self, instr, assignblk):
     """
     Ensure IRDst is always set in the head @assignblk of the @instr
     @instr: an instruction instance
     @assignblk: Assignblk instance
     """
     new_assignblk = dict(assignblk)
     if self.ir_arch.IRDst not in assignblk:
         offset = instr.offset + instr.l
         loc_key = self.ir_arch.loc_db.get_or_create_offset_location(offset)
         dst = ExprLoc(loc_key, self.ir_arch.IRDst.size)
         new_assignblk[self.ir_arch.IRDst] = dst
     irs = [AssignBlock(new_assignblk, instr)]
     return IRBlock(self.ir_arch.get_loc_key_for_instr(instr), irs)
예제 #21
0
파일: ira.py 프로젝트: trietptm/miasm
    def call_effects(self, ad, instr):
        call_assignblk = AssignBlock([
            ExprAff(
                self.ret_reg,
                ExprOp(
                    'call_func_ret',
                    ad,
                    self.arch.regs.A0,
                    self.arch.regs.A1,
                    self.arch.regs.A2,
                    self.arch.regs.A3,
                )),
        ], instr)

        return [call_assignblk], []
예제 #22
0
    def gen_equations(self):
        for irb in self.blocks.values():
            symbols_init = dict(self.arch.regs.all_regs_ids_init)

            sb = SymbolicExecutionEngine(self, dict(symbols_init))
            sb.emulbloc(irb)
            eqs = []
            for n_w in sb.symbols:
                v = sb.symbols[n_w]
                if n_w in symbols_init and symbols_init[n_w] == v:
                    continue
                eqs.append(ExprAff(n_w, v))
            print '*' * 40
            print irb
            irb.irs = [AssignBlock(eqs)]
예제 #23
0
    def call_effects(self, ad, instr):
        """Default modelisation of a function call to @ad. This may be used to:

        * insert dependencies to arguments (stack base, registers, ...)
        * add some side effects (stack clean, return value, ...)

        @ad: (Expr) address of the called function
        @instr: native instruction which is responsible of the call
        """

        return [AssignBlock(
            [ExprAff(self.ret_reg, ExprOp('call_func_ret', ad, self.sp)),
             ExprAff(self.sp, ExprOp(
                 'call_func_stack', ad, self.sp)),
             ])]
예제 #24
0
파일: ira.py 프로젝트: xxtxiaofeng/miasm
 def call_effects(self, ad, instr):
     call_assignblks = AssignBlock([
         ExprAssign(
             self.ret_reg,
             ExprOp(
                 'call_func_ret',
                 ad,
                 self.sp,
                 self.arch.regs.R3,
                 self.arch.regs.R4,
                 self.arch.regs.R5,
             )),
         ExprAssign(self.sp, ExprOp('call_func_stack', ad, self.sp)),
     ], instr)
     return [call_assignblks], []
예제 #25
0
    def del_dst_zr(self, instr, instr_ir, extra_ir):
        "Writes to zero register are discarded"
        regs_to_fix = [WZR, XZR]
        instr_ir = [expr for expr in instr_ir if expr.dst not in regs_to_fix]

        new_irblocks = []
        for irblock in extra_ir:
            irs = []
            for assignblk in irblock.irs:
                new_dsts = {dst:src for dst, src in assignblk.iteritems()
                                if dst not in regs_to_fix}
                irs.append(AssignBlock(new_dsts, assignblk.instr))
            new_irblocks.append(IRBlock(irblock.label, irs))

        return instr_ir, new_irblocks
예제 #26
0
파일: ssa.py 프로젝트: hax0kartik/miasm
    def remove_phi(self):
        """
        Remove phi operators in @ifcfg
        @ircfg: IRDiGraph instance
        """

        for irblock in self.ssa.graph.blocks.values():
            assignblks = list(irblock)
            out = {}
            for dst, src in assignblks[0].iteritems():
                if src.is_op('Phi'):
                    assert set([dst]) == set(src.args)
                    continue
                out[dst] = src
            assignblks[0] = AssignBlock(out, assignblks[0].instr)
            self.ssa.graph.blocks[irblock.loc_key] = IRBlock(irblock.loc_key, assignblks)
예제 #27
0
 def call_effects(self, ad, instr):
     call_assignblk = AssignBlock([
         ExprAff(
             self.ret_reg,
             ExprOp(
                 'call_func_ret',
                 ad,
                 self.sp,
                 self.arch.regs.RCX,
                 self.arch.regs.RDX,
                 self.arch.regs.R8,
                 self.arch.regs.R9,
             )),
         ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)),
     ], instr)
     return [call_assignblk], []
예제 #28
0
 def call_effects(self, ad):
     return [
         AssignBlock([
             ExprAff(
                 self.ret_reg,
                 ExprOp(
                     'call_func_ret',
                     ad,
                     self.sp,
                     self.arch.regs.RCX,
                     self.arch.regs.RDX,
                     self.arch.regs.R8,
                     self.arch.regs.R9,
                 )),
             ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)),
         ])
     ]
예제 #29
0
def load_from_int(ir_arch, bs, is_addr_ro_variable):
    """
    Replace memory read based on constant with static value
    @ir_arch: ira instance
    @bs: binstream instance
    @is_addr_ro_variable: callback(addr, size) to test memory candidate
    """

    modified = False
    for label, block in ir_arch.blocks.iteritems():
        assignblks = list()
        for assignblk in block:
            out = {}
            for dst, src in assignblk.iteritems():
                # Test src
                mems = get_memlookup(src, bs, is_addr_ro_variable)
                src_new = src
                if mems:
                    replace = {}
                    for mem in mems:
                        value = read_mem(bs, mem)
                        replace[mem] = value
                    src_new = src.replace_expr(replace)
                    if src_new != src:
                        modified = True
                # Test dst pointer if dst is mem
                if dst.is_mem():
                    ptr = dst.arg
                    mems = get_memlookup(ptr, bs, is_addr_ro_variable)
                    ptr_new = ptr
                    if mems:
                        replace = {}
                        for mem in mems:
                            value = read_mem(bs, mem)
                            replace[mem] = value
                        ptr_new = ptr.replace_expr(replace)
                        if ptr_new != ptr:
                            modified = True
                            dst = ExprMem(ptr_new, dst.size)
                out[dst] = src_new
            out = AssignBlock(out, assignblk.instr)
            assignblks.append(out)
        block = IRBlock(block.loc_key, assignblks)
        ir_arch.blocks[block.loc_key] = block
    return modified
예제 #30
0
파일: sem.py 프로젝트: manwefm/miasm
    def irbloc_fix_regs_for_mode(self, irblock, mode=64):
        irs = []
        for assignblk in irblock:
            new_assignblk = dict(assignblk)
            for dst, src in assignblk.iteritems():
                del (new_assignblk[dst])
                # Special case for 64 bits:
                # If destination is a 32 bit reg, zero extend the 64 bit reg
                if (isinstance(dst, ExprId) and dst.size == 32
                        and dst in replace_regs):
                    src = src.zeroExtend(64)
                    dst = replace_regs[dst].arg

                dst = self.expr_fix_regs_for_mode(dst)
                src = self.expr_fix_regs_for_mode(src)
                new_assignblk[dst] = src
            irs.append(AssignBlock(new_assignblk, assignblk.instr))
        return IRBlock(irblock.loc_key, irs)
예제 #31
0
파일: ir.py 프로젝트: commial/miasm
from miasm2.expression.expression import *
from miasm2.ir.ir import AssignBlock
from miasm2.expression.simplifications import expr_simp

id_a = ExprId("a", 32)
id_b = ExprId("b", 32)
int0 = ExprInt(0, id_a.size)

# Test AssignBlock
## Constructors
assignblk1 = AssignBlock([ExprAssign(id_a, id_b)])
assignblk2 = AssignBlock({id_a: id_b})

## Equality
assignblk1_bis = AssignBlock([ExprAssign(id_a, id_b)])
assert assignblk1 == assignblk1_bis
assert assignblk1 == assignblk2

## Immutability
try:
    assignblk1[id_a] = id_a
except RuntimeError:
    pass
else:
    raise RuntimeError("An error was expected")
try:
    del assignblk1[id_a]
except RuntimeError:
    pass
else:
    raise RuntimeError("An error was expected")
예제 #32
0
파일: symbexec.py 프로젝트: jbcayrou/miasm
    def test_ClassDef(self):
        from miasm2.expression.expression import ExprInt32, ExprId, ExprMem, \
            ExprCompose, ExprAff
        from miasm2.arch.x86.sem import ir_x86_32
        from miasm2.ir.symbexec import symbexec
        from miasm2.ir.ir import AssignBlock

        addrX = ExprInt32(-1)
        addr0 = ExprInt32(0)
        addr1 = ExprInt32(1)
        addr8 = ExprInt32(8)
        addr9 = ExprInt32(9)
        addr20 = ExprInt32(20)
        addr40 = ExprInt32(40)
        addr50 = ExprInt32(50)
        mem0 = ExprMem(addr0)
        mem1 = ExprMem(addr1, 8)
        mem8 = ExprMem(addr8)
        mem9 = ExprMem(addr9)
        mem20 = ExprMem(addr20)
        mem40v = ExprMem(addr40,  8)
        mem40w = ExprMem(addr40, 16)
        mem50v = ExprMem(addr50,  8)
        mem50w = ExprMem(addr50, 16)
        id_x = ExprId('x')
        id_y = ExprId('y', 8)
        id_a = ExprId('a')
        id_eax = ExprId('eax_init')

        e = symbexec(ir_x86_32(),
                     {mem0: id_x, mem1: id_y, mem9: id_x,
                      mem40w: id_x[:16], mem50v: id_y,
                      id_a: addr0, id_eax: addr0})
        self.assertEqual(e.find_mem_by_addr(addr0), mem0)
        self.assertEqual(e.find_mem_by_addr(addrX), None)
        self.assertEqual(e.eval_expr(ExprMem(addr1 - addr1)), id_x)
        self.assertEqual(e.eval_expr(ExprMem(addr1, 8)), id_y)
        self.assertEqual(e.eval_expr(ExprMem(addr1 + addr1)), ExprCompose(
            id_x[16:32], ExprMem(ExprInt32(4), 16)))
        self.assertEqual(e.eval_expr(mem8), ExprCompose(
            id_x[0:24], ExprMem(ExprInt32(11), 8)))
        self.assertEqual(e.eval_expr(mem40v), id_x[:8])
        self.assertEqual(e.eval_expr(mem50w), ExprCompose(
            id_y, ExprMem(ExprInt32(51), 8)))
        self.assertEqual(e.eval_expr(mem20), mem20)
        e.func_read = lambda x: x
        self.assertEqual(e.eval_expr(mem20), mem20)
        self.assertEqual(set(e.modified()), set(e.symbols))
        self.assertRaises(
            KeyError, e.symbols.__getitem__, ExprMem(ExprInt32(100)))
        self.assertEqual(e.apply_expr(id_eax), addr0)
        self.assertEqual(e.apply_expr(ExprAff(id_eax, addr9)), addr9)
        self.assertEqual(e.apply_expr(id_eax), addr9)

        # apply_change / eval_ir / apply_expr

        ## x = a (with a = 0x0)
        assignblk = AssignBlock()
        assignblk[id_x] = id_a
        e.eval_ir(assignblk)
        self.assertEqual(e.apply_expr(id_x), addr0)

        ## x = a (without replacing 'a' with 0x0)
        e.apply_change(id_x, id_a)
        self.assertEqual(e.apply_expr(id_x), id_a)

        ## x = a (with a = 0x0)
        self.assertEqual(e.apply_expr(assignblk.dst2ExprAff(id_x)), addr0)
        self.assertEqual(e.apply_expr(id_x), addr0)
예제 #33
0
파일: symbexec.py 프로젝트: guedou/miasm
    def test_ClassDef(self):
        from miasm2.expression.expression import ExprInt, ExprId, ExprMem, \
            ExprCompose, ExprAff
        from miasm2.arch.x86.sem import ir_x86_32
        from miasm2.ir.symbexec import SymbolicExecutionEngine
        from miasm2.ir.ir import AssignBlock


        id_x = ExprId('x', 32)
        id_a = ExprId('a', 32)
        id_b = ExprId('b', 32)
        id_c = ExprId('c', 32)
        id_d = ExprId('d', 32)
        id_e = ExprId('e', 64)

        sb = SymbolicExecutionEngine(ir_x86_32(),
                                    {
                                        ExprMem(ExprInt(0x4, 32), 8): ExprInt(0x44, 8),
                                        ExprMem(ExprInt(0x5, 32), 8): ExprInt(0x33, 8),
                                        ExprMem(ExprInt(0x6, 32), 8): ExprInt(0x22, 8),
                                        ExprMem(ExprInt(0x7, 32), 8): ExprInt(0x11, 8),

                                        ExprMem(ExprInt(0x20, 32), 32): id_x,

                                        ExprMem(ExprInt(0x40, 32), 32): id_x,
                                        ExprMem(ExprInt(0x44, 32), 32): id_a,

                                        ExprMem(ExprInt(0x54, 32), 32): ExprInt(0x11223344, 32),

                                        ExprMem(id_a, 32): ExprInt(0x11223344, 32),
                                        id_a: ExprInt(0, 32),
                                        id_b: ExprInt(0, 32),

                                        ExprMem(id_c, 32): ExprMem(id_d + ExprInt(0x4, 32), 32),
                                        ExprMem(id_c + ExprInt(0x4, 32), 32): ExprMem(id_d + ExprInt(0x8, 32), 32),

                                    })


        self.assertEqual(sb.eval_expr(ExprInt(1, 32)-ExprInt(1, 32)), ExprInt(0, 32))

        ## Test with unknown mem + integer
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0, 32), 32)), ExprMem(ExprInt(0, 32), 32))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(1, 32), 32)), ExprCompose(ExprMem(ExprInt(1, 32), 24), ExprInt(0x44, 8)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(2, 32), 32)), ExprCompose(ExprMem(ExprInt(2, 32), 16), ExprInt(0x3344, 16)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(3, 32), 32)), ExprCompose(ExprMem(ExprInt(3, 32), 8), ExprInt(0x223344, 24)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(4, 32), 32)), ExprInt(0x11223344, 32))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(5, 32), 32)), ExprCompose(ExprInt(0x112233, 24), ExprMem(ExprInt(8, 32), 8)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(6, 32), 32)), ExprCompose(ExprInt(0x1122, 16), ExprMem(ExprInt(8, 32), 16)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(7, 32), 32)), ExprCompose(ExprInt(0x11, 8), ExprMem(ExprInt(8, 32), 24)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(8, 32), 32)), ExprMem(ExprInt(8, 32), 32))

        ## Test with unknown mem + integer
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x50, 32), 32)), ExprMem(ExprInt(0x50, 32), 32))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x51, 32), 32)), ExprCompose(ExprMem(ExprInt(0x51, 32), 24), ExprInt(0x44, 8)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x52, 32), 32)), ExprCompose(ExprMem(ExprInt(0x52, 32), 16), ExprInt(0x3344, 16)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x53, 32), 32)), ExprCompose(ExprMem(ExprInt(0x53, 32), 8), ExprInt(0x223344, 24)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x54, 32), 32)), ExprInt(0x11223344, 32))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x55, 32), 32)), ExprCompose(ExprInt(0x112233, 24), ExprMem(ExprInt(0x58, 32), 8)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x56, 32), 32)), ExprCompose(ExprInt(0x1122, 16), ExprMem(ExprInt(0x58, 32), 16)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x57, 32), 32)), ExprCompose(ExprInt(0x11, 8), ExprMem(ExprInt(0x58, 32), 24)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x58, 32), 32)), ExprMem(ExprInt(0x58, 32), 32))



        ## Test with unknown mem + id
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1D, 32), 32)), ExprCompose(ExprMem(ExprInt(0x1D, 32), 24), id_x[:8]))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1E, 32), 32)), ExprCompose(ExprMem(ExprInt(0x1E, 32), 16), id_x[:16]))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1F, 32), 32)), ExprCompose(ExprMem(ExprInt(0x1F, 32), 8), id_x[:24]))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x20, 32), 32)), id_x)
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x21, 32), 32)), ExprCompose(id_x[8:], ExprMem(ExprInt(0x24, 32), 8)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x22, 32), 32)), ExprCompose(id_x[16:], ExprMem(ExprInt(0x24, 32), 16)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x23, 32), 32)), ExprCompose(id_x[24:], ExprMem(ExprInt(0x24, 32), 24)))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x24, 32), 32)), ExprMem(ExprInt(0x24, 32), 32))


        ## Partial read
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(4, 32), 8)), ExprInt(0x44, 8))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x20, 32), 8)), id_x[:8])
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x23, 32), 8)), id_x[24:])


        ## Merge
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x40, 32), 64)), ExprCompose(id_x, id_a))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x42, 32), 32)), ExprCompose(id_x[16:], id_a[:16]))

        # Merge memory
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x100, 32), 32)), ExprMem(ExprInt(0x100, 32), 32))
        self.assertEqual(sb.eval_expr(ExprMem(id_c + ExprInt(0x2, 32), 32)), ExprMem(id_d  + ExprInt(0x6, 32), 32))

        ## Func read
        def custom_func_read(mem):
            if mem == ExprMem(ExprInt(0x1000, 32), 32):
                return id_x
            return mem

        sb.func_read = custom_func_read

        ## Unmodified read
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(4, 32), 8)), ExprInt(0x44, 8))

        ## Modified read
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x1000, 32), 32)), id_x)


        ## Apply_change / eval_ir / apply_expr

        ## x = a (with a = 0x0)
        assignblk = AssignBlock({id_x:id_a})
        sb.eval_updt_assignblk(assignblk)
        self.assertEqual(sb.eval_expr(id_x), ExprInt(0, 32))

        ## x = a (without replacing 'a' with 0x0)
        sb.apply_change(id_x, id_a)
        self.assertEqual(sb.eval_expr(id_x), id_a)

        ## x = a (with a = 0x0)
        self.assertEqual(sb.eval_updt_expr(assignblk.dst2ExprAff(id_x)), ExprInt(0, 32))
        self.assertEqual(sb.eval_expr(id_x), ExprInt(0, 32))
        self.assertEqual(sb.eval_updt_expr(id_x), ExprInt(0, 32))

        sb.dump()

        ## state
        reads = set()
        for dst, src in sb.modified():
            reads.update(ExprAff(dst, src).get_r())

        self.assertEqual(reads, set([
            id_x, id_a,
            ExprMem(id_d + ExprInt(0x4, 32), 32),
            ExprMem(id_d + ExprInt(0x8, 32), 32),
        ]))

        # Erase low id_x byte with 0xFF
        sb.apply_change(ExprMem(ExprInt(0x20, 32), 8), ExprInt(0xFF, 8))
        state = dict(sb.modified(ids=False))
        self.assertEqual(state[ExprMem(ExprInt(0x20, 32), 8)], ExprInt(0xFF, 8))
        self.assertEqual(state[ExprMem(ExprInt(0x21, 32), 24)], id_x[8:32])

        # Erase high id_x byte with 0xEE
        sb.apply_change(ExprMem(ExprInt(0x23, 32), 8), ExprInt(0xEE, 8))

        state = dict(sb.modified(ids=False))
        self.assertEqual(state[ExprMem(ExprInt(0x20, 32), 8)], ExprInt(0xFF, 8))
        self.assertEqual(state[ExprMem(ExprInt(0x21, 32), 16)], id_x[8:24])
        self.assertEqual(state[ExprMem(ExprInt(0x23, 32), 8)], ExprInt(0xEE, 8))

        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x22, 32), 32)), ExprCompose(id_x[16:24], ExprInt(0xEE, 8), ExprMem(ExprInt(0x24, 32), 16)))

        # Erase low byte of 0x11223344 with 0xFF at 0x54
        sb.apply_change(ExprMem(ExprInt(0x54, 32), 8), ExprInt(0xFF, 8))

        # Erase low byte of 0x11223344 with 0xFF at id_a
        sb.apply_change(ExprMem(id_a + ExprInt(0x1, 32), 8), ExprInt(0xFF, 8))
        state = dict(sb.modified(ids=False))
        self.assertEqual(state[ExprMem(id_a + ExprInt(0x1, 32), 8)], ExprInt(0xFF, 8))
        self.assertEqual(state[ExprMem(id_a + ExprInt(0x2, 32), 16)], ExprInt(0x1122, 16))

        # Write uint32_t at 0xFFFFFFFE
        sb.apply_change(ExprMem(ExprInt(0xFFFFFFFE, 32), 32), ExprInt(0x11223344, 32))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0, 32), 16)), ExprInt(0x1122, 16))

        # Revert memory to original value at 0x42
        sb.apply_change(ExprMem(ExprInt(0x42, 32), 32), ExprMem(ExprInt(0x42, 32), 32))
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0x42, 32), 32)), ExprMem(ExprInt(0x42, 32), 32))

        # Revert memory to original value at c + 0x2
        sb.apply_change(ExprMem(id_c + ExprInt(0x2, 32), 32), ExprMem(id_c + ExprInt(0x2, 32), 32))
        self.assertEqual(sb.eval_expr(ExprMem(id_c + ExprInt(0x2, 32), 32)), ExprMem(id_c + ExprInt(0x2, 32), 32))

        # Test del symbol
        del sb.symbols[id_a]
        sb.dump()
        del sb.symbols[ExprMem(id_a, 8)]
        print "*"*40, 'Orig:'
        sb.dump()

        sb_cp = sb.symbols.copy()
        print "*"*40, 'Copy:'
        sb_cp.dump()

        # Add symbol at address limit
        sb.apply_change(ExprMem(ExprInt(0xFFFFFFFE, 32), 32), id_c)
        sb.dump()
        found = False
        for dst, src in sb.symbols.iteritems():
            if dst == ExprMem(ExprInt(0xFFFFFFFE, 32), 32) and src == id_c:
                found = True
        assert found


        # Add symbol at address limit
        sb.apply_change(ExprMem(ExprInt(0x7FFFFFFE, 32), 32), id_c)
        sb.dump()
        found = False
        for dst, src in sb.symbols.iteritems():
            if dst == ExprMem(ExprInt(0x7FFFFFFE, 32), 32) and src == id_c:
                found = True
        assert found



        # Add truncated symbol at address limit
        sb.apply_change(ExprMem(ExprInt(0xFFFFFFFC, 32), 64), id_e)
        # Revert parts of memory
        sb.apply_change(ExprMem(ExprInt(0xFFFFFFFC, 32), 16), ExprMem(ExprInt(0xFFFFFFFC, 32), 16))
        sb.apply_change(ExprMem(ExprInt(0x2, 32), 16), ExprMem(ExprInt(0x2, 32), 16))
        sb.dump()
        found = False
        for dst, src in sb.symbols.iteritems():
            if dst == ExprMem(ExprInt(0xFFFFFFFE, 32), 32) and src == id_e[16:48]:
                found = True
        assert found


        sb_empty = SymbolicExecutionEngine(ir_x86_32(), {})
        sb_empty.dump()


        # Test memory full
        print 'full'
        arch_addr8 = ir_x86_32()
        # Hack to obtain tiny address space
        arch_addr8.addrsize = 5
        sb_addr8 = SymbolicExecutionEngine(arch_addr8, {})
        sb_addr8.dump()
        # Fulfill memory
        sb_addr8.apply_change(ExprMem(ExprInt(0, 5), 256), ExprInt(0, 256))
        sb_addr8.dump()
        variables = sb_addr8.symbols.items()
        assert variables == [(ExprMem(ExprInt(0, 5), 256), ExprInt(0, 256))]

        print sb_addr8.symbols.symbols_mem

        sb_addr8.apply_change(ExprMem(ExprInt(0x5, 5), 256), ExprInt(0x123, 256))
        sb_addr8.dump()
        variables = sb_addr8.symbols.items()
        assert variables == [(ExprMem(ExprInt(0x5, 5), 256), ExprInt(0x123, 256))]
        print sb_addr8.symbols.symbols_mem

        print 'dump'
        sb_addr8.symbols.symbols_mem.dump()


        sb.dump()
        try:
            del sb.symbols.symbols_mem[ExprMem(ExprInt(0xFFFFFFFF, 32), 32)]
        except KeyError:
            # ok
            pass
        else:
            raise RuntimeError("Should raise error!")


        del sb.symbols.symbols_mem[ExprMem(ExprInt(0xFFFFFFFF, 32), 16)]
        sb.dump()
        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0xFFFFFFFE, 32), 32)),
                         ExprCompose(id_e[16:24], ExprMem(ExprInt(0xFFFFFFFF, 32), 16), id_e[40:48]))
        sb.symbols.symbols_mem.delete_partial(ExprMem(ExprInt(0xFFFFFFFF, 32), 32))

        self.assertEqual(sb.eval_expr(ExprMem(ExprInt(0xFFFFFFFE, 32), 32)),
                         ExprCompose(id_e[16:24], ExprMem(ExprInt(0xFFFFFFFF, 32), 24)))

        sb.dump()

        assert ExprMem(ExprInt(0xFFFFFFFE, 32), 8) in sb.symbols
        assert ExprMem(ExprInt(0xFFFFFFFE, 32), 32) not in sb.symbols
        assert sb.symbols.symbols_mem.contains_partial(ExprMem(ExprInt(0xFFFFFFFE, 32), 32))
        assert not sb.symbols.symbols_mem.contains_partial(ExprMem(ExprInt(0xFFFFFFFF, 32), 8))

        assert sb_addr8.symbols.keys() == [ExprMem(ExprInt(0x5, 5), 256)]