diff options
| -rw-r--r-- | example/expression/access_c.py | 4 | ||||
| -rw-r--r-- | example/symbol_exec/depgraph.py | 4 | ||||
| -rw-r--r-- | miasm2/analysis/data_flow.py | 7 | ||||
| -rw-r--r-- | miasm2/analysis/depgraph.py | 6 | ||||
| -rw-r--r-- | miasm2/arch/aarch64/sem.py | 10 | ||||
| -rw-r--r-- | miasm2/arch/mips32/ira.py | 10 | ||||
| -rw-r--r-- | miasm2/arch/mips32/jit.py | 12 | ||||
| -rw-r--r-- | miasm2/arch/x86/ira.py | 4 | ||||
| -rw-r--r-- | miasm2/arch/x86/jit.py | 27 | ||||
| -rw-r--r-- | miasm2/arch/x86/sem.py | 12 | ||||
| -rw-r--r-- | miasm2/ir/analysis.py | 14 | ||||
| -rw-r--r-- | miasm2/ir/ir.py | 235 | ||||
| -rw-r--r-- | miasm2/jitter/codegen.py | 255 | ||||
| -rw-r--r-- | miasm2/jitter/jitcore_python.py | 18 | ||||
| -rw-r--r-- | miasm2/jitter/llvmconvert.py | 39 | ||||
| -rw-r--r-- | miasm2/jitter/vm_mngr_py.c | 2 | ||||
| -rw-r--r-- | miasm2/os_dep/win_api_x86_32.py | 1 | ||||
| -rw-r--r-- | test/analysis/data_flow.py | 8 | ||||
| -rw-r--r-- | test/analysis/depgraph.py | 5 | ||||
| -rw-r--r-- | test/ir/ir.py | 46 | ||||
| -rwxr-xr-x | test/ir/symbexec.py | 3 | ||||
| -rwxr-xr-x | test/test_all.py | 1 |
22 files changed, 447 insertions, 276 deletions
diff --git a/example/expression/access_c.py b/example/expression/access_c.py index eabc3770..923a3331 100644 --- a/example/expression/access_c.py +++ b/example/expression/access_c.py @@ -109,8 +109,8 @@ def get_funcs_arg0(ctx, ira, lbl_head): element = ira.arch.regs.RSI for irb, index in find_call(ira): - line = irb.lines[index] - print 'Analysing references from:', hex(line.offset), line + instr = irb.irs[index].instr + print 'Analysing references from:', hex(instr.offset), instr g_list = g_dep.get(irb.label, set([element]), index, set([lbl_head])) for dep in g_list: emul_result = dep.emul(ctx) diff --git a/example/symbol_exec/depgraph.py b/example/symbol_exec/depgraph.py index 0b971b15..56ca3f82 100644 --- a/example/symbol_exec/depgraph.py +++ b/example/symbol_exec/depgraph.py @@ -75,8 +75,8 @@ dg = DependencyGraph(ir_arch, implicit=args.implicit, target_addr = int(args.target_addr, 0) current_block = list(ir_arch.getby_offset(target_addr))[0] line_nb = 0 -for line_nb, line in enumerate(current_block.lines): - if line.offset == target_addr: +for line_nb, assignblk in enumerate(current_block.irs): + if assignblk.instr.offset == target_addr: break # Enumerate solutions diff --git a/miasm2/analysis/data_flow.py b/miasm2/analysis/data_flow.py index b9764daa..dc1bf6ae 100644 --- a/miasm2/analysis/data_flow.py +++ b/miasm2/analysis/data_flow.py @@ -2,6 +2,7 @@ from collections import namedtuple from miasm2.core.graph import DiGraph +from miasm2.ir.ir import AssignBlock class ReachingDefinitions(dict): """ @@ -247,6 +248,8 @@ def dead_simp(ir_a): useful = set(dead_simp_useful_instrs(defuse, reaching_defs)) for block in ir_a.blocks.itervalues(): for idx, assignblk in enumerate(block.irs): - for lval in assignblk.keys(): + new_assignblk = dict(assignblk) + for lval in assignblk: if InstrNode(block.label, idx, lval) not in useful: - del assignblk[lval] + del new_assignblk[lval] + block.irs[idx] = AssignBlock(new_assignblk, assignblk.instr) diff --git a/miasm2/analysis/depgraph.py b/miasm2/analysis/depgraph.py index bab4d2bc..d1ac13c8 100644 --- a/miasm2/analysis/depgraph.py +++ b/miasm2/analysis/depgraph.py @@ -263,12 +263,12 @@ class DependencyResult(DependencyState): for line_nb, elements in sorted(line2elements.iteritems()): if max_line is not None and line_nb >= max_line: break - assignblk = AssignBlock() + assignmnts = {} for element in elements: if element in irb.irs[line_nb]: # constants, label, ... are not in destination - assignblk[element] = irb.irs[line_nb][element] - assignblks.append(assignblk) + assignmnts[element] = irb.irs[line_nb][element] + assignblks.append(AssignBlock(assignmnts)) return IRBlock(irb.label, assignblks) diff --git a/miasm2/arch/aarch64/sem.py b/miasm2/arch/aarch64/sem.py index e9eaffc8..599cdc98 100644 --- a/miasm2/arch/aarch64/sem.py +++ b/miasm2/arch/aarch64/sem.py @@ -777,9 +777,10 @@ class ir_aarch64l(IntermediateRepresentation): return m2_expr.ExprAff(dst, src) def irbloc_fix_regs_for_mode(self, irbloc, mode=64): - for assignblk in irbloc.irs: - for dst, src in assignblk.items(): - del(assignblk[dst]) + for idx, assignblk in enumerate(irbloc.irs): + 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 @@ -791,7 +792,8 @@ class ir_aarch64l(IntermediateRepresentation): dst = self.expr_fix_regs_for_mode(dst) src = self.expr_fix_regs_for_mode(src) - assignblk[dst] = src + new_assignblk[dst] = src + irbloc.irs[idx] = AssignBlock(new_assignblk, assignblk.instr) if irbloc.dst is not None: irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst) diff --git a/miasm2/arch/mips32/ira.py b/miasm2/arch/mips32/ira.py index 92af5cc5..a2eab4fb 100644 --- a/miasm2/arch/mips32/ira.py +++ b/miasm2/arch/mips32/ira.py @@ -31,18 +31,18 @@ class ir_a_mips32l(ir_mips32l, ira): if expr_is_label(lr_val): lr_val = ExprInt(lr_val.name.offset, 32) - line = block.lines[-2] - if lr_val.arg != line.offset + 8: + instr = block.irs[-2].instr + if lr_val.arg != instr.offset + 8: raise ValueError("Wrong arg") # CALL lbl = block.get_next() new_lbl = self.gen_label() - irs = self.call_effects(pc_val, line) + irs = self.call_effects(pc_val, instr) irs.append(AssignBlock([ExprAff(self.IRDst, - ExprId(lbl, size=self.pc.size))])) + ExprId(lbl, size=self.pc.size))], + instr)) nblock = IRBlock(new_lbl, irs) - nblock.lines = [line] * len(irs) self.blocks[new_lbl] = nblock irb.dst = ExprId(new_lbl, size=self.pc.size) diff --git a/miasm2/arch/mips32/jit.py b/miasm2/arch/mips32/jit.py index bfa9c5fd..9b46589f 100644 --- a/miasm2/arch/mips32/jit.py +++ b/miasm2/arch/mips32/jit.py @@ -5,6 +5,7 @@ from miasm2.core import asmblock from miasm2.core.utils import pck32, upck32 from miasm2.arch.mips32.sem import ir_mips32l, ir_mips32b from miasm2.jitter.codegen import CGen +from miasm2.ir.ir import AssignBlock import miasm2.expression.expression as m2_expr log = logging.getLogger('jit_mips32') @@ -43,18 +44,21 @@ class mipsCGen(CGen): if not instr.breakflow(): continue for irblock in irblocks: - for assignblock in irblock.irs: + for idx, assignblock in enumerate(irblock.irs): if self.ir_arch.pc not in assignblock: continue + new_assignblock = dict(assignblock) # Add internal branch destination - assignblock[self.delay_slot_dst] = assignblock[ + new_assignblock[self.delay_slot_dst] = assignblock[ self.ir_arch.pc] - assignblock[self.delay_slot_set] = m2_expr.ExprInt(1, 32) + new_assignblock[self.delay_slot_set] = m2_expr.ExprInt(1, 32) # Replace IRDst with next instruction - assignblock[self.ir_arch.IRDst] = m2_expr.ExprId( + new_assignblock[self.ir_arch.IRDst] = m2_expr.ExprId( self.ir_arch.get_next_instr(instr)) irblock.dst = m2_expr.ExprId( self.ir_arch.get_next_instr(instr)) + irblock.irs[idx] = AssignBlock(new_assignblock, assignblock.instr) + return irblocks_list def gen_finalize(self, block): diff --git a/miasm2/arch/x86/ira.py b/miasm2/arch/x86/ira.py index 1fcaaa52..d0bebfb6 100644 --- a/miasm2/arch/x86/ira.py +++ b/miasm2/arch/x86/ira.py @@ -53,7 +53,9 @@ class ir_a_x86_64(ir_x86_64, ir_a_x86_16): )), ExprAff(self.sp, ExprOp('call_func_stack', ad, self.sp)), - ])] + ], + instr + )] def sizeof_char(self): return 8 diff --git a/miasm2/arch/x86/jit.py b/miasm2/arch/x86/jit.py index ef1f162b..e64c610b 100644 --- a/miasm2/arch/x86/jit.py +++ b/miasm2/arch/x86/jit.py @@ -140,6 +140,33 @@ class jitter_x86_32(jitter): get_arg_n_systemv = get_stack_arg + # fastcall + @named_arguments + def func_args_fastcall(self, n_args): + args_regs = ['ECX', 'EDX'] + ret_ad = self.pop_uint32_t() + args = [] + for i in xrange(n_args): + args.append(self.get_arg_n_fastcall(i)) + return ret_ad, args + + def func_prepare_fastcall(self, ret_addr, *args): + args_regs = ['ECX', 'EDX'] + self.push_uint32_t(ret_addr) + for i in xrange(min(len(args), len(args_regs))): + setattr(self.cpu, args_regs[i], args[i]) + remaining_args = args[len(args_regs):] + for arg in reversed(remaining_args): + self.push_uint32_t(arg) + + def get_arg_n_fastcall(self, index): + args_regs = ['ECX', 'EDX'] + if index < len(args_regs): + return getattr(self.cpu, args_regs[index]) + return self.get_stack_arg(index - len(args_regs)) + + + class jitter_x86_64(jitter): C_Gen = x86_64_CGen diff --git a/miasm2/arch/x86/sem.py b/miasm2/arch/x86/sem.py index 98866e65..0312891b 100644 --- a/miasm2/arch/x86/sem.py +++ b/miasm2/arch/x86/sem.py @@ -21,7 +21,7 @@ from miasm2.expression.simplifications import expr_simp from miasm2.arch.x86.regs import * from miasm2.arch.x86.arch import mn_x86, repeat_mn, replace_regs from miasm2.expression.expression_helper import expr_cmps, expr_cmpu -from miasm2.ir.ir import IntermediateRepresentation, IRBlock +from miasm2.ir.ir import IntermediateRepresentation, IRBlock, AssignBlock from miasm2.core.sembuilder import SemBuilder import math import struct @@ -4602,9 +4602,10 @@ class ir_x86_16(IntermediateRepresentation): return m2_expr.ExprAff(dst, src) def irbloc_fix_regs_for_mode(self, irbloc, mode=64): - for assignblk in irbloc.irs: - for dst, src in assignblk.items(): - del assignblk[dst] + for idx, assignblk in enumerate(irbloc.irs): + 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 mode == 64: @@ -4615,7 +4616,8 @@ class ir_x86_16(IntermediateRepresentation): dst = replace_regs[64][dst].arg dst = self.expr_fix_regs_for_mode(dst, mode) src = self.expr_fix_regs_for_mode(src, mode) - assignblk[dst] = src + new_assignblk[dst] = src + irbloc.irs[idx] = AssignBlock(new_assignblk, assignblk.instr) if irbloc.dst is not None: irbloc.dst = self.expr_fix_regs_for_mode(irbloc.dst, mode) diff --git a/miasm2/ir/analysis.py b/miasm2/ir/analysis.py index 5c5193c9..1d9310fc 100644 --- a/miasm2/ir/analysis.py +++ b/miasm2/ir/analysis.py @@ -39,11 +39,11 @@ class ira(IntermediateRepresentation): @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)), - ])] + assignblk = AssignBlock({ + self.ret_reg: ExprOp('call_func_ret', ad, self.sp), + self.sp: ExprOp('call_func_stack', ad, self.sp)}, + instr) + return [assignblk] def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_update): """Replace function call with corresponding call effects, @@ -53,7 +53,6 @@ class ira(IntermediateRepresentation): call_effects = self.call_effects(instr.args[0], instr) for assignblk in call_effects: irb_cur.irs.append(assignblk) - irb_cur.lines.append(instr) return None def gen_equations(self): @@ -70,8 +69,7 @@ class ira(IntermediateRepresentation): eqs.append(ExprAff(n_w, v)) print '*' * 40 print irb - irb.irs = [eqs] - irb.lines = [None] + irb.irs = [AssignBlock(eqs)] def sizeof_char(self): "Return the size of a char in bits" diff --git a/miasm2/ir/ir.py b/miasm2/ir/ir.py index f8ac6722..caf2c0ed 100644 --- a/miasm2/ir/ir.py +++ b/miasm2/ir/ir.py @@ -29,19 +29,41 @@ from miasm2.core.asmblock import AsmSymbolPool, expr_is_label, AsmLabel, \ from miasm2.core.graph import DiGraph -class AssignBlock(dict): +class AssignBlock(object): + """Represent parallel IR assignment, such as: + EAX = EBX + EBX = EAX - def __init__(self, irs=None): - """@irs seq""" + Also provides common manipulation on this assignments + """ + __slots__ = ["_assigns", "_instr"] + + def __init__(self, irs=None, instr=None): + """Create a new AssignBlock + @irs: (optional) sequence of ExprAff, or dictionnary dst (Expr) -> src + (Expr) + @instr: (optional) associate an instruction with this AssignBlock + + """ if irs is None: irs = [] - super(AssignBlock, self).__init__() + self._instr = instr + self._assigns = {} # ExprAff.dst -> ExprAff.src - for expraff in irs: - # Concurrent assignments are handled in __setitem__ - self[expraff.dst] = expraff.src + # Concurrent assignments are handled in _set + if hasattr(irs, "iteritems"): + for dst, src in irs.iteritems(): + self._set(dst, src) + else: + for expraff in irs: + self._set(expraff.dst, expraff.src) - def __setitem__(self, dst, src): + @property + def instr(self): + """Return the associated instruction, if any""" + return self._instr + + def _set(self, dst, src): """ Special cases: * if dst is an ExprSlice, expand it to affect the full Expression @@ -64,7 +86,7 @@ class AssignBlock(dict): else: new_dst, new_src = dst, src - if new_dst in self and isinstance(new_src, m2_expr.ExprCompose): + if new_dst in self._assigns and isinstance(new_src, m2_expr.ExprCompose): if not isinstance(self[new_dst], m2_expr.ExprCompose): # prev_RAX = 0x1122334455667788 # input_RAX[0:8] = 0x89 @@ -103,7 +125,51 @@ class AssignBlock(dict): args = [expr for (expr, _, _) in args] new_src = m2_expr.ExprCompose(*args) - super(AssignBlock, self).__setitem__(new_dst, new_src) + self._assigns[new_dst] = new_src + + def __setitem__(self, dst, src): + raise RuntimeError('AssignBlock is immutable') + + def __getitem__(self, key): + return self._assigns[key] + + def __contains__(self, key): + return key in self._assigns + + def iteritems(self): + for dst, src in self._assigns.iteritems(): + yield dst, src + + def itervalues(self): + for src in self._assigns.itervalues(): + yield src + + def keys(self): + return self._assigns.keys() + + def values(self): + return self._assigns.values() + + def __iter__(self): + for dst in self._assigns: + yield dst + + def __delitem__(self, _): + raise RuntimeError('AssignBlock is immutable') + + def update(self, _): + raise RuntimeError('AssignBlock is immutable') + + def __eq__(self, other): + if self.keys() != other.keys(): + return False + return all(other[dst] == src for dst, src in self.iteritems()) + + def __len__(self): + return len(self._assigns) + + def get(self, key, default): + return self._assigns.get(key, default) @staticmethod def get_modified_slice(dst, src): @@ -152,7 +218,7 @@ class AssignBlock(dict): def __str__(self): out = [] - for dst, src in sorted(self.iteritems()): + for dst, src in sorted(self._assigns.iteritems()): out.append("%s = %s" % (dst, src)) return "\n".join(out) @@ -161,6 +227,18 @@ class AssignBlock(dict): @dst: Expr instance""" return m2_expr.ExprAff(dst, self[dst]) + def simplify(self, simplifier): + """Return a new AssignBlock with expression simplified + @simplifier: ExpressionSimplifier instance""" + new_assignblk = {} + for dst, src in self.iteritems(): + if dst == src: + continue + src = simplifier(src) + dst = simplifier(dst) + new_assignblk[dst] = src + return AssignBlock(irs=new_assignblk, instr=self.instr) + class IRBlock(object): """Intermediate representation block object. @@ -168,19 +246,15 @@ class IRBlock(object): Stand for an intermediate representation basic block. """ - def __init__(self, label, irs, lines=None): + def __init__(self, label, irs): """ @label: AsmLabel of the IR basic block @irs: list of AssignBlock - @lines: list of native instructions """ assert isinstance(label, AsmLabel) - if lines is None: - lines = [] self.label = label self.irs = irs - self.lines = lines self.except_automod = True self._dst = None self._dst_linenb = None @@ -207,15 +281,15 @@ class IRBlock(object): if self._dst_linenb is None: self._get_dst() - assignblk = self.irs[self._dst_linenb] - for dst in assignblk: + new_assignblk = dict(self.irs[self._dst_linenb]) + for dst in new_assignblk: if isinstance(dst, m2_expr.ExprId) and dst.name == "IRDst": - del assignblk[dst] - assignblk[dst] = value + new_assignblk[dst] = value # Sanity check is already done in _get_dst break self._dst = value - + instr = self.irs[self._dst_linenb].instr + self.irs[self._dst_linenb] = AssignBlock(new_assignblk, instr) dst = property(_get_dst, _set_dst) @property @@ -262,7 +336,7 @@ class irbloc(IRBlock): def __init__(self, label, irs, lines=None): warnings.warn('DEPRECATION WARNING: use "IRBlock" instead of "irblock"') - super(irbloc, self).__init__(label, irs, lines) + super(irbloc, self).__init__(label, irs) class DiGraphIR(DiGraph): @@ -349,54 +423,55 @@ class IntermediateRepresentation(object): def get_ir(self, instr): raise NotImplementedError("Abstract Method") - def instr2ir(self, l): - ir_bloc_cur, extra_assignblk = self.get_ir(l) - assignblk = AssignBlock(ir_bloc_cur) + def instr2ir(self, instr): + ir_bloc_cur, extra_assignblk = self.get_ir(instr) for irb in extra_assignblk: - irb.irs = map(AssignBlock, irb.irs) + irs = [] + for assignblk in irb.irs: + irs.append(AssignBlock(assignblk, instr)) + irb.irs = irs + assignblk = AssignBlock(ir_bloc_cur, instr) return assignblk, extra_assignblk - def get_label(self, ad): + def get_label(self, addr): """Transforms an ExprId/ExprInt/label/int into a label - @ad: an ExprId/ExprInt/label/int""" - - if (isinstance(ad, m2_expr.ExprId) and - isinstance(ad.name, AsmLabel)): - ad = ad.name - if isinstance(ad, m2_expr.ExprInt): - ad = int(ad) - if isinstance(ad, (int, long)): - ad = self.symbol_pool.getby_offset_create(ad) - elif isinstance(ad, AsmLabel): - ad = self.symbol_pool.getby_name_create(ad.name) - return ad - - def get_bloc(self, ad): + @addr: an ExprId/ExprInt/label/int""" + + if (isinstance(addr, m2_expr.ExprId) and + isinstance(addr.name, AsmLabel)): + addr = addr.name + if isinstance(addr, m2_expr.ExprInt): + addr = int(addr) + if isinstance(addr, (int, long)): + addr = self.symbol_pool.getby_offset_create(addr) + elif isinstance(addr, AsmLabel): + addr = self.symbol_pool.getby_name_create(addr.name) + return addr + + def get_bloc(self, addr): """Returns the irbloc associated to an ExprId/ExprInt/label/int - @ad: an ExprId/ExprInt/label/int""" + @addr: an ExprId/ExprInt/label/int""" - label = self.get_label(ad) + label = self.get_label(addr) return self.blocks.get(label, None) - def add_instr(self, l, ad=0, gen_pc_updt=False): - b = AsmBlock(self.gen_label()) - b.lines = [l] - self.add_bloc(b, gen_pc_updt) + def add_instr(self, line, addr=0, gen_pc_updt=False): + block = AsmBlock(self.gen_label()) + block.lines = [line] + self.add_bloc(block, gen_pc_updt) def getby_offset(self, offset): out = set() for irb in self.blocks.values(): - for l in irb.lines: - if l.offset <= offset < l.offset + l.l: + for assignblk in irb.irs: + instr = assignblk.instr + if instr.offset <= offset < instr.offset + instr.l: out.add(irb) return out - def gen_pc_update(self, c, l): - c.irs.append(AssignBlock([m2_expr.ExprAff(self.pc, - m2_expr.ExprInt(l.offset, - self.pc.size) - )])) - c.lines.append(l) + def gen_pc_update(self, irblock, instr): + irblock.irs.append(AssignBlock({self.pc: m2_expr.ExprInt(instr.offset, self.pc.size)}, + instr)) def pre_add_instr(self, block, instr, irb_cur, ir_blocks_all, gen_pc_updt): """Function called before adding an instruction from the the native @block to @@ -439,11 +514,8 @@ class IntermediateRepresentation(object): self.gen_pc_update(irb_cur, instr) irb_cur.irs.append(assignblk) - irb_cur.lines.append(instr) if ir_blocks_extra: - for irblock in ir_blocks_extra: - irblock.lines = [instr] * len(irblock.irs) ir_blocks_all += ir_blocks_extra irb_cur = None return irb_cur @@ -460,28 +532,28 @@ class IntermediateRepresentation(object): for instr in block.lines: if irb_cur is None: label = self.get_instr_label(instr) - irb_cur = IRBlock(label, [], []) + irb_cur = IRBlock(label, []) ir_blocks_all.append(irb_cur) irb_cur = self.add_instr_to_irblock(block, instr, irb_cur, ir_blocks_all, gen_pc_updt) self.post_add_bloc(block, ir_blocks_all) return ir_blocks_all - def expr_fix_regs_for_mode(self, e, *args, **kwargs): - return e + def expr_fix_regs_for_mode(self, expr, *args, **kwargs): + return expr - def expraff_fix_regs_for_mode(self, e, *args, **kwargs): - return e + def expraff_fix_regs_for_mode(self, expr, *args, **kwargs): + return expr def irbloc_fix_regs_for_mode(self, irbloc, *args, **kwargs): return - def is_pc_written(self, b): + def is_pc_written(self, block): all_pc = self.arch.pc.values() - for irs in b.irs: - for ir in irs: - if ir.dst in all_pc: - return ir + for irs in block.irs: + for assignblk in irs: + if assignblk.dst in all_pc: + return assignblk return None def set_empty_dst_to_next(self, block, ir_blocks): @@ -495,8 +567,8 @@ class IntermediateRepresentation(object): else: dst = m2_expr.ExprId(next_lbl, self.pc.size) - irblock.irs.append(AssignBlock([m2_expr.ExprAff(self.IRDst, dst)])) - irblock.lines.append(irblock.lines[-1]) + irblock.irs.append(AssignBlock({self.IRDst: dst}, + irblock.irs[-1].instr)) def post_add_bloc(self, block, ir_blocks): self.set_empty_dst_to_next(block, ir_blocks) @@ -516,12 +588,12 @@ class IntermediateRepresentation(object): def gen_label(self): # TODO: fix hardcoded offset - l = self.symbol_pool.gen_label() - return l + label = self.symbol_pool.gen_label() + return label def get_next_label(self, instr): - l = self.symbol_pool.getby_offset_create(instr.offset + instr.l) - return l + label = self.symbol_pool.getby_offset_create(instr.offset + instr.l) + return label def simplify_blocs(self): for irblock in self.blocks.values(): @@ -596,15 +668,14 @@ class IntermediateRepresentation(object): Gen irbloc digraph """ self._graph = DiGraphIR(self.blocks) - for lbl, b in self.blocks.iteritems(): + for lbl, block in self.blocks.iteritems(): self._graph.add_node(lbl) - dst = self.dst_trackback(b) - for d in dst: - if isinstance(d, m2_expr.ExprInt): - d = m2_expr.ExprId( - self.symbol_pool.getby_offset_create(int(d))) - if expr_is_label(d): - self._graph.add_edge(lbl, d.name) + for dst in self.dst_trackback(block): + if dst.is_int(): + dst_lbl = self.symbol_pool.getby_offset_create(int(dst)) + dst = m2_expr.ExprId(dst_lbl) + if expr_is_label(dst): + self._graph.add_edge(lbl, dst.name) @property def graph(self): diff --git a/miasm2/jitter/codegen.py b/miasm2/jitter/codegen.py index 09a6fecf..e91f3505 100644 --- a/miasm2/jitter/codegen.py +++ b/miasm2/jitter/codegen.py @@ -1,5 +1,9 @@ +""" +Module to generate C code for a given native @block +""" + import miasm2.expression.expression as m2_expr -from miasm2.ir.ir import IRBlock +from miasm2.ir.ir import IRBlock, AssignBlock from miasm2.ir.translators import Translator from miasm2.core.asmblock import expr_is_label, AsmBlockBad, AsmLabel @@ -131,17 +135,22 @@ class CGen(object): def assignblk_to_irbloc(self, instr, assignblk): """ Ensure IRDst is always set in the head @assignblk of the @instr - @assignblk: Assignblk instance @instr: an instruction instance + @assignblk: Assignblk instance """ + new_assignblk = dict(assignblk) if self.ir_arch.IRDst not in assignblk: - assignblk[self.ir_arch.IRDst] = m2_expr.ExprInt( - instr.offset + instr.l, - self.ir_arch.IRDst.size) - - return IRBlock(self.ir_arch.get_instr_label(instr), [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) def block2assignblks(self, block): + """ + Return the list of irblocks for a native @block + @block: AsmBlock + """ irblocks_list = [] for instr in block.lines: assignblk_head, assignblks_extra = self.ir_arch.instr2ir(instr) @@ -155,16 +164,13 @@ class CGen(object): irblocks_list.append(irblocks) return irblocks_list - def gen_mem_prefetch(self, assignblk, mems_to_prefetch): - out = [] - for expr, prefetcher in sorted(mems_to_prefetch.iteritems()): - str_src = self.id_to_c(expr) - str_dst = self.id_to_c(prefetcher) - out.append('%s = %s;' % (str_dst, str_src)) - assignblk.C_prefetch = out - return out - def add_local_var(self, dst_var, dst_index, expr): + """ + Add local varaible used to store temporay result + @dst_var: dictionnary of Expr -> local_var_expr + @dst_index : dictionnary of size -> local var count + @expr: Expression source + """ size = expr.size if size < 8: size = 8 @@ -176,17 +182,51 @@ class CGen(object): dst_var[expr] = dst return dst - def gen_assignments(self, assignblk, prefetchers): - out_var = [] - out_main = [] - out_mem = [] - out_updt = [] + def get_mem_prefetch(self, assignblk): + """ + Generate temporary variables used to fetch memory used in the @assignblk + Return a dictionnary: ExprMem -> temporary variable + @assignblk: AssignBlock instance + """ + mem_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0} + mem_var = {} + + # Prefetch memory read + for expr in assignblk.get_r(mem_read=True): + if not isinstance(expr, m2_expr.ExprMem): + continue + var_num = mem_index[expr.size] + mem_index[expr.size] += 1 + var = m2_expr.ExprId( + "prefetch_%.2d_%.2d" % (expr.size, var_num), expr.size) + mem_var[expr] = var + + # Generate memory prefetch + return mem_var + + def gen_c_assignments(self, assignblk): + """ + Return C informations used to generate the C code of the @assignblk + @assignblk: an AssignBlock instance + """ + c_var = [] + c_main = [] + c_mem = [] + c_updt = [] + c_prefetch = [] - dst_index = {8: 0, 16: 0, 32: 0, 64: 0} + dst_index = {8: 0, 16: 0, 32: 0, 64: 0, 128:0} dst_var = {} + prefetchers = self.get_mem_prefetch(assignblk) + + for expr, prefetcher in sorted(prefetchers.iteritems()): + str_src = self.id_to_c(expr) + str_dst = self.id_to_c(prefetcher) + c_prefetch.append('%s = %s;' % (str_dst, str_src)) + for var in prefetchers.itervalues(): - out_var.append("uint%d_t %s;" % (var.size, var)) + c_var.append("uint%d_t %s;" % (var.size, var)) for dst, src in sorted(assignblk.iteritems()): src = src.replace_expr(prefetchers) @@ -196,10 +236,10 @@ class CGen(object): new_dst = self.add_local_var(dst_var, dst_index, dst) if dst in self.ir_arch.arch.regs.regs_flt_expr: # Dont mask float affectation - out_main.append( + c_main.append( '%s = (%s);' % (self.id_to_c(new_dst), self.id_to_c(src))) else: - out_main.append( + c_main.append( '%s = (%s)&0x%X;' % (self.id_to_c(new_dst), self.id_to_c(src), SIZE_TO_MASK[src.size])) @@ -207,48 +247,17 @@ class CGen(object): ptr = dst.arg.replace_expr(prefetchers) new_dst = m2_expr.ExprMem(ptr, dst.size) str_dst = self.id_to_c(new_dst).replace('MEM_LOOKUP', 'MEM_WRITE') - out_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src))) + c_mem.append('%s, %s);' % (str_dst[:-1], self.id_to_c(src))) else: raise ValueError("Unknown dst") for dst, new_dst in dst_var.iteritems(): if dst is self.ir_arch.IRDst: continue - out_updt.append('%s = %s;' % (self.id_to_c(dst), self.id_to_c(new_dst))) - out_var.append("uint%d_t %s;" % (new_dst.size, new_dst)) - - assignblk.C_var = out_var - assignblk.C_main = out_main - assignblk.C_mem = out_mem - assignblk.C_updt = out_updt + c_updt.append('%s = %s;' % (self.id_to_c(dst), self.id_to_c(new_dst))) + c_var.append("uint%d_t %s;" % (new_dst.size, new_dst)) - def gen_c_assignblk(self, assignblk): - mem_read, mem_write = False, False - - mem_index = {8: 0, 16: 0, 32: 0, 64: 0} - mem_var = {} - prefetch_index = {8: 0, 16: 0, 32: 0, 64: 0} - - # Prefetch memory read - for expr in assignblk.get_r(mem_read=True): - if not isinstance(expr, m2_expr.ExprMem): - continue - mem_read = True - var_num = mem_index[expr.size] - mem_index[expr.size] += 1 - var = m2_expr.ExprId( - "prefetch_%.2d_%.2d" % (expr.size, var_num), expr.size) - mem_var[expr] = var - - # Check if assignblk can write mem - mem_write = any(isinstance(expr, m2_expr.ExprMem) - for expr in assignblk.get_w()) - - assignblk.mem_write = mem_write - assignblk.mem_read = mem_read - - # Generate memory prefetch - return mem_var + return c_prefetch, c_var, c_main, c_mem, c_updt def gen_check_memory_exception(self, address): dst = self.dst_to_c(address) @@ -313,12 +322,12 @@ class CGen(object): return out - def gen_pre_code(self, attrib): + def gen_pre_code(self, instr_attrib): out = [] - if attrib.log_mn: - out.append('printf("%.8X %s\\n");' % (attrib.instr.offset, - attrib.instr)) + if instr_attrib.log_mn: + out.append('printf("%.8X %s\\n");' % (instr_attrib.instr.offset, + instr_attrib.instr)) return out def gen_post_code(self, attrib): @@ -357,7 +366,7 @@ class CGen(object): """ Generate code for possible @dst2index. - @attrib: an Attributs instance + @attrib: an Attributes instance @instr_offsets: list of instructions offsets @dst2index: link from destination to index """ @@ -377,54 +386,57 @@ class CGen(object): continue out.append('\tcase %d:' % index) + out += self.gen_goto_code(attrib, instr_offsets, dst) out.append('\t\tbreak;') out.append('};') return out - def gen_c_code(self, assignblk, c_dst): + def gen_c_code(self, attrib, c_dst, c_assignmnts): """ - Generate the C code for @assignblk. - @assignblk: an Assignblk instance + Generate the C code for assignblk. + @attrib: Attributes instance @c_dst: irdst C code """ + + c_prefetch, c_var, c_main, c_mem, c_updt = c_assignmnts out = [] out.append("{") out.append("// var") - out += assignblk.C_var + out += c_var out.append("// Prefetch") - out += assignblk.C_prefetch + out += c_prefetch out.append("// Dst") out += c_dst out.append("// Main") - out += assignblk.C_main + out += c_main out.append("// Check op/mem exceptions") # Check memory access if assignblk has memory read - if assignblk.C_prefetch: - out += self.gen_check_memory_exception(assignblk.instr_addr) + if c_prefetch: + out += self.gen_check_memory_exception(attrib.instr.offset) # Check if operator raised exception flags - if assignblk.op_set_exception: - out += self.gen_check_cpu_exception(assignblk.instr_addr) + if attrib.op_set_exception: + out += self.gen_check_cpu_exception(attrib.instr.offset) out.append("// Mem updt") - out += assignblk.C_mem + out += c_mem out.append("// Check exception Mem write") # Check memory write exceptions - if assignblk.mem_write: - out += self.gen_check_memory_exception(assignblk.instr_addr) + if attrib.mem_write: + out += self.gen_check_memory_exception(attrib.instr.offset) out.append("// Updt") - out += assignblk.C_updt + out += c_updt out.append("// Checks exception") # Check post assignblk exception flags - if assignblk.set_exception: - out += self.gen_check_cpu_exception(assignblk.instr_addr) + if attrib.set_exception: + out += self.gen_check_cpu_exception(attrib.instr.offset) out.append("}") @@ -436,29 +448,27 @@ class CGen(object): return any(operator.startswith(except_op) for except_op in self.IMPLICIT_EXCEPTION_OP) - def get_caracteristics(self, irblock): + def get_caracteristics(self, assignblk, attrib): """ - Get the carateristics of each assignblk in the @irblock - @irblock: an irbloc instance + Set the carateristics in @attrib according to the @assignblk + @assignblk: an AssignBlock instance + @attrib: an Attributes instance """ - for assignblk in irblock.irs: - assignblk.mem_read, assignblk.mem_write = False, False - assignblk.op_set_exception = False - # Check explicit exception raising - assignblk.set_exception = self.ir_arch.arch.regs.exception_flags in assignblk - - element_read = assignblk.get_r(mem_read=True) - # Check implicit exception raising - assignblk.op_set_exception = any(self.is_exception_operator(operator) - for elem in assignblk.values() - for operator in m2_expr.get_expr_ops(elem)) - # Check mem read - assignblk.mem_read = any(isinstance(expr, m2_expr.ExprMem) - for expr in element_read) - # Check mem write - assignblk.mem_write = any(isinstance(dst, m2_expr.ExprMem) - for dst in assignblk) + # Check explicit exception raising + attrib.set_exception = self.ir_arch.arch.regs.exception_flags in assignblk + + element_read = assignblk.get_r(mem_read=True) + # Check implicit exception raising + attrib.op_set_exception = any(self.is_exception_operator(operator) + for elem in assignblk.values() + for operator in m2_expr.get_expr_ops(elem)) + # Check mem read + attrib.mem_read = any(isinstance(expr, m2_expr.ExprMem) + for expr in element_read) + # Check mem write + attrib.mem_write = any(isinstance(dst, m2_expr.ExprMem) + for dst in assignblk) def get_attributes(self, instr, irblocks, log_mn=False, log_regs=False): """ @@ -469,17 +479,24 @@ class CGen(object): @log_regs: generate code to log registers states """ - attrib = Attributes(log_mn, log_regs) + instr_attrib = Attributes() + instr_attrib.instr = instr + irblocks_attributes = [] for irblock in irblocks: + attributes = [] + irblocks_attributes.append(attributes) for assignblk in irblock.irs: - self.get_caracteristics(irblock) - attrib.mem_read |= assignblk.mem_read - attrib.mem_write |= assignblk.mem_write - attrib.set_exception |= assignblk.set_exception - attrib.op_set_exception |= assignblk.op_set_exception - attrib.instr = instr - return attrib + attrib = Attributes(log_mn, log_regs) + attributes.append(attrib) + self.get_caracteristics(assignblk, attrib) + attrib.instr = instr + instr_attrib.mem_read |= attrib.mem_read + instr_attrib.mem_write |= attrib.mem_write + instr_attrib.op_set_exception |= attrib.op_set_exception + instr_attrib.set_exception |= attrib.set_exception + + return instr_attrib, irblocks_attributes def gen_bad_block(self): """ @@ -503,12 +520,11 @@ class CGen(object): lbl_start = self.ir_arch.symbol_pool.getby_offset_create(instr_offsets[0]) return (self.CODE_INIT % self.label_to_jitlabel(lbl_start)).split("\n"), instr_offsets - def gen_irblock(self, attrib, instr_offsets, instr, irblock): + def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock): """ Generate the C code for an @irblock - @instr: the current instruction to translate @irblock: an irbloc instance - @attrib: an Attributs instance + @attributes: an Attributes instance list """ out = [] @@ -518,17 +534,14 @@ class CGen(object): c_dst, dst2index = self.gen_assignblk_dst(irblock.dst) else: c_dst = [] - assignblk.instr_addr = instr.offset - prefetchers = self.gen_c_assignblk(assignblk) - self.gen_mem_prefetch(assignblk, prefetchers) - self.gen_assignments(assignblk, prefetchers) - out += self.gen_c_code(assignblk, c_dst) + c_assignmnts = self.gen_c_assignments(assignblk) + out += self.gen_c_code(attributes[index], c_dst, c_assignmnts) if dst2index: out.append("// Set irdst") # Gen goto on irdst set - out += self.gen_dst_goto(attrib, instr_offsets, dst2index) + out += self.gen_dst_goto(instr_attrib, instr_offsets, dst2index) return out @@ -556,7 +569,7 @@ class CGen(object): out, instr_offsets = self.gen_init(block) for instr, irblocks in zip(block.lines, irblocks_list): - attrib = self.get_attributes(instr, irblocks, log_mn, log_regs) + instr_attrib, irblocks_attributes = self.get_attributes(instr, irblocks, log_mn, log_regs) for index, irblock in enumerate(irblocks): self.ir_arch.irbloc_fix_regs_for_mode( @@ -569,8 +582,8 @@ class CGen(object): out.append("%-40s // %.16X %s" % (self.label_to_jitlabel(irblock.label) + ":", instr.offset, instr)) if index == 0: - out += self.gen_pre_code(attrib) - out += self.gen_irblock(attrib, instr_offsets, instr, irblock) + out += self.gen_pre_code(instr_attrib) + out += self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, irblock) out += self.gen_finalize(block) return ['\t' + line for line in out] diff --git a/miasm2/jitter/jitcore_python.py b/miasm2/jitter/jitcore_python.py index cbd582ab..6d954aae 100644 --- a/miasm2/jitter/jitcore_python.py +++ b/miasm2/jitter/jitcore_python.py @@ -72,18 +72,18 @@ class JitCore_Python(jitcore.JitCore): exec_engine.update_engine_from_cpu() # Execute current ir bloc - for ir, line in zip(irb.irs, irb.lines): - + for assignblk in irb.irs: + instr = assignblk.instr # For each new instruction (in assembly) - if line.offset not in offsets_jitted: + if instr.offset not in offsets_jitted: # Test exceptions vmmngr.check_invalid_code_blocs() vmmngr.check_memory_breakpoint() if vmmngr.get_exception(): exec_engine.update_cpu_from_engine() - return line.offset + return instr.offset - offsets_jitted.add(line.offset) + offsets_jitted.add(instr.offset) # Log registers values if self.log_regs: @@ -92,21 +92,21 @@ class JitCore_Python(jitcore.JitCore): # Log instruction if self.log_mn: - print "%08x %s" % (line.offset, line) + print "%08x %s" % (instr.offset, instr) # Check for exception if (vmmngr.get_exception() != 0 or cpu.get_exception() != 0): exec_engine.update_cpu_from_engine() - return line.offset + return instr.offset # Eval current instruction (in IR) - exec_engine.eval_ir(ir) + exec_engine.eval_ir(assignblk) # Check for exceptions which do not update PC exec_engine.update_cpu_from_engine() if (vmmngr.get_exception() & csts.EXCEPT_DO_NOT_UPDATE_PC != 0 or cpu.get_exception() > csts.EXCEPT_NUM_UPDT_EIP): - return line.offset + return instr.offset vmmngr.check_invalid_code_blocs() vmmngr.check_memory_breakpoint() diff --git a/miasm2/jitter/llvmconvert.py b/miasm2/jitter/llvmconvert.py index b2e1e957..e7a1d6bc 100644 --- a/miasm2/jitter/llvmconvert.py +++ b/miasm2/jitter/llvmconvert.py @@ -1003,10 +1003,10 @@ class LLVMFunction(): # Reactivate object caching self.main_stream = current_main_stream - def gen_pre_code(self, attributes): - if attributes.log_mn: - self.printf("%.8X %s\n" % (attributes.instr.offset, - attributes.instr)) + def gen_pre_code(self, instr_attrib): + if instr_attrib.log_mn: + self.printf("%.8X %s\n" % (instr_attrib.instr.offset, + instr_attrib.instr)) def gen_post_code(self, attributes): if attributes.log_regs: @@ -1110,19 +1110,20 @@ class LLVMFunction(): self.set_ret(dst) - def gen_irblock(self, attrib, instr, instr_offsets, irblock): + def gen_irblock(self, instr_attrib, attributes, instr_offsets, irblock): """ Generate the code for an @irblock - @instr: the current instruction to translate - @irblock: an irbloc instance - @attrib: an Attributs instance + @instr_attrib: an Attributs instance or the instruction to translate + @attributes: list of Attributs corresponding to irblock assignments @instr_offsets: offset of all asmblock's instructions + @irblock: an irblock instance """ case2dst = None case_value = None + instr = instr_attrib.instr - for assignblk in irblock.irs: + for index, assignblk in enumerate(irblock.irs): # Enable cache self.main_stream = True self.expr_cache = {} @@ -1141,12 +1142,12 @@ class LLVMFunction(): values[dst] = self.add_ir(src) # Check memory access exception - if assignblk.mem_read: + if attributes[index].mem_read: self.check_memory_exception(instr.offset, restricted_exception=True) # Check operation exception - if assignblk.op_set_exception: + if attributes[index].op_set_exception: self.check_cpu_exception(instr.offset, restricted_exception=True) # Update the memory @@ -1155,7 +1156,7 @@ class LLVMFunction(): self.affect(src, dst) # Check memory write exception - if assignblk.mem_write: + if attributes[index].mem_write: self.check_memory_exception(instr.offset, restricted_exception=True) @@ -1165,14 +1166,14 @@ class LLVMFunction(): self.affect(src, dst) # Check post assignblk exception flags - if assignblk.set_exception: + if attributes[index].set_exception: self.check_cpu_exception(instr.offset, restricted_exception=True) # Destination assert case2dst is not None if len(case2dst) == 1: # Avoid switch in this common case - self.gen_jump2dst(attrib, instr_offsets, case2dst.values()[0]) + self.gen_jump2dst(instr_attrib, instr_offsets, case2dst.values()[0]) else: current_bbl = self.builder.basic_block @@ -1184,7 +1185,7 @@ class LLVMFunction(): bbl = self.append_basic_block(name) case2bbl[case] = bbl self.builder.position_at_start(bbl) - self.gen_jump2dst(attrib, instr_offsets, dst) + self.gen_jump2dst(instr_attrib, instr_offsets, dst) # Jump on the correct output self.builder.position_at_end(current_bbl) @@ -1311,8 +1312,8 @@ class LLVMFunction(): for instr, irblocks in zip(asmblock.lines, irblocks_list): - attrib = codegen.get_attributes(instr, irblocks, self.log_mn, - self.log_regs) + instr_attrib, irblocks_attributes = codegen.get_attributes(instr, irblocks, self.log_mn, + self.log_regs) # Pre-create basic blocks for irblock in irblocks: @@ -1328,8 +1329,8 @@ class LLVMFunction(): self.builder.position_at_end(self.get_basic_bloc_by_label(name)) if index == 0: - self.gen_pre_code(attrib) - self.gen_irblock(attrib, instr, instr_offsets, irblock) + self.gen_pre_code(instr_attrib) + self.gen_irblock(instr_attrib, irblocks_attributes[index], instr_offsets, irblock) # Gen finalize (see codegen::CGen) is unrecheable, except with delayslot self.gen_finalize(asmblock, codegen) diff --git a/miasm2/jitter/vm_mngr_py.c b/miasm2/jitter/vm_mngr_py.c index b53e098a..4436add2 100644 --- a/miasm2/jitter/vm_mngr_py.c +++ b/miasm2/jitter/vm_mngr_py.c @@ -619,7 +619,7 @@ static PyMethodDef VmMngr_methods[] = { {"get_mem", (PyCFunction)vm_get_mem, METH_VARARGS, "get_mem(addr, size) -> Get the memory content at @address of @size bytes"}, {"add_memory_page",(PyCFunction)vm_add_memory_page, METH_VARARGS, - "add_memory_page(address, access, size [, cmt]) -> Maps a memory page at @address of @size bytes with protection @access\n" + "add_memory_page(address, access, content [, cmt]) -> Maps a memory page at @address of len(@content) bytes containing @content with protection @access\n" "@cmt is a comment linked to the memory page"}, {"add_memory_breakpoint",(PyCFunction)vm_add_memory_breakpoint, METH_VARARGS, "add_memory_breakpoint(address, size, access) -> Add a memory breakpoint at @address of @size bytes with @access type"}, diff --git a/miasm2/os_dep/win_api_x86_32.py b/miasm2/os_dep/win_api_x86_32.py index 265bad86..d9c659d3 100644 --- a/miasm2/os_dep/win_api_x86_32.py +++ b/miasm2/os_dep/win_api_x86_32.py @@ -1786,6 +1786,7 @@ def ntdll_LdrGetProcedureAddress(jitter): fname = jitter.get_str_ansi(p_src) ad = winobjs.runtime_dll.lib_get_add_func(args.libbase, fname) + jitter.add_breakpoint(ad, jitter.handle_lib) jitter.vm.set_mem(args.p_ad, pck32(ad)) diff --git a/test/analysis/data_flow.py b/test/analysis/data_flow.py index 1784f87f..2c24773a 100644 --- a/test/analysis/data_flow.py +++ b/test/analysis/data_flow.py @@ -32,10 +32,11 @@ LBL4 = AsmLabel("lbl4") LBL5 = AsmLabel("lbl5") LBL6 = AsmLabel("lbl6") +IRDst = ExprId('IRDst', 32) +dummy = ExprId('dummy', 32) def gen_irblock(label, exprs_list): - lines = [None for _ in xrange(len(exprs_list))] irs = [] for exprs in exprs_list: if isinstance(exprs, AssignBlock): @@ -43,7 +44,8 @@ def gen_irblock(label, exprs_list): else: irs.append(AssignBlock(exprs)) - irbl = IRBlock(label, irs, lines) + irs.append(AssignBlock({IRDst:dummy})) + irbl = IRBlock(label, irs) return irbl @@ -67,7 +69,7 @@ class IRATest(ira): def __init__(self, symbol_pool=None): arch = Arch() super(IRATest, self).__init__(arch, 32, symbol_pool) - self.IRDst = pc + self.IRDst = IRDst self.ret_reg = r def get_out_regs(self, _): diff --git a/test/analysis/depgraph.py b/test/analysis/depgraph.py index 005ab32c..63313861 100644 --- a/test/analysis/depgraph.py +++ b/test/analysis/depgraph.py @@ -50,10 +50,9 @@ LBL5 = AsmLabel("lbl5") LBL6 = AsmLabel("lbl6") def gen_irblock(label, exprs_list): - """ Returns an IRBlock with empty lines. + """ Returns an IRBlock. Used only for tests purpose """ - lines = [None for _ in xrange(len(exprs_list))] irs = [] for exprs in exprs_list: if isinstance(exprs, AssignBlock): @@ -61,7 +60,7 @@ def gen_irblock(label, exprs_list): else: irs.append(AssignBlock(exprs)) - irbl = IRBlock(label, irs, lines) + irbl = IRBlock(label, irs) return irbl diff --git a/test/ir/ir.py b/test/ir/ir.py new file mode 100644 index 00000000..5c428a94 --- /dev/null +++ b/test/ir/ir.py @@ -0,0 +1,46 @@ +from miasm2.expression.expression import * +from miasm2.ir.ir import AssignBlock +from miasm2.expression.simplifications import expr_simp + +id_a = ExprId("a") +id_b = ExprId("b") +int0 = ExprInt(0, id_a.size) + +# Test AssignBlock +## Constructors +assignblk1 = AssignBlock([ExprAff(id_a, id_b)]) +assignblk2 = AssignBlock({id_a: id_b}) + +## Equality +assignblk1_bis = AssignBlock([ExprAff(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") + +## Basic APIs +assert assignblk1.get_r() == set([id_b]) +assert assignblk1.get_w() == set([id_a]) +assert assignblk1.get_rw() == {id_a: set([id_b])} +assert assignblk1.keys() == [id_a] +assert dict(assignblk1) == {id_a: id_b} +assert assignblk1[id_a] == id_b + +## Simplify +assignblk3 = AssignBlock({id_a: id_b - id_b}) +assert assignblk3[id_a] != int0 +assignblk4 = assignblk3.simplify(expr_simp) +assert assignblk3[id_a] != int0 +assert assignblk4[id_a] == int0 diff --git a/test/ir/symbexec.py b/test/ir/symbexec.py index bd28c4ee..e2bd411f 100755 --- a/test/ir/symbexec.py +++ b/test/ir/symbexec.py @@ -63,8 +63,7 @@ class TestSymbExec(unittest.TestCase): # apply_change / eval_ir / apply_expr ## x = a (with a = 0x0) - assignblk = AssignBlock() - assignblk[id_x] = id_a + assignblk = AssignBlock({id_x:id_a}) e.eval_ir(assignblk) self.assertEqual(e.apply_expr(id_x), addr0) diff --git a/test/test_all.py b/test/test_all.py index 48ce76ba..d2c3e5e2 100755 --- a/test/test_all.py +++ b/test/test_all.py @@ -245,6 +245,7 @@ for script in ["modint.py", ## IR for script in ["symbexec.py", + "ir.py", ]: testset += RegressionTest([script], base_dir="ir") |