diff options
| -rw-r--r-- | example/disasm/full.py | 37 | ||||
| -rw-r--r-- | example/expression/asm_to_ir.py | 6 | ||||
| -rw-r--r-- | example/expression/constant_propagation.py | 5 | ||||
| -rw-r--r-- | example/expression/graph_dataflow.py | 6 | ||||
| -rw-r--r-- | miasm/analysis/data_flow.py | 314 | ||||
| -rw-r--r-- | miasm/analysis/outofssa.py | 4 | ||||
| -rw-r--r-- | miasm/analysis/simplifier.py | 55 | ||||
| -rw-r--r-- | miasm/analysis/ssa.py | 24 | ||||
| -rw-r--r-- | miasm/arch/ppc/regs.py | 11 | ||||
| -rw-r--r-- | miasm/arch/ppc/sem.py | 35 | ||||
| -rw-r--r-- | miasm/ir/analysis.py | 6 | ||||
| -rw-r--r-- | miasm/jitter/arch/JitCore_ppc32_regs.h | 34 | ||||
| -rw-r--r-- | test/analysis/data_flow.py | 5 |
13 files changed, 368 insertions, 174 deletions
diff --git a/example/disasm/full.py b/example/disasm/full.py index a28d548e..d4fae867 100644 --- a/example/disasm/full.py +++ b/example/disasm/full.py @@ -9,7 +9,7 @@ from miasm.analysis.binary import Container from miasm.core.asmblock import log_asmblock, AsmCFG from miasm.core.interval import interval from miasm.analysis.machine import Machine -from miasm.analysis.data_flow import dead_simp, \ +from miasm.analysis.data_flow import \ DiGraphDefUse, ReachingDefinitions, \ replace_stack_vars, load_from_int, del_unused_edges from miasm.expression.simplifications import expr_simp @@ -213,7 +213,6 @@ if args.propagexpr: class IRADelModCallStack(ira): - def call_effects(self, addr, instr): assignblks, extra = super(IRADelModCallStack, self).call_effects(addr, instr) if not args.calldontmodstack: @@ -283,34 +282,6 @@ if args.gen_ir: if args.propagexpr: - class IRAOutRegs(ira): - def get_out_regs(self, block): - regs_todo = super(self.__class__, self).get_out_regs(block) - out = {} - for assignblk in block: - for dst in assignblk: - reg = self.ssa_var.get(dst, None) - if reg is None: - continue - if reg in regs_todo: - out[reg] = dst - return set(viewvalues(out)) - - # Add dummy dependency to uncover out regs assignment - 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 - - def is_addr_ro_variable(bs, addr, size): """ @@ -327,9 +298,6 @@ if args.propagexpr: return False return True - ir_arch_a = IRAOutRegs(mdis.loc_db) - - class CustomIRCFGSimplifierSSA(IRCFGSimplifierSSA): def do_simplify(self, ssa, head): modified = super(CustomIRCFGSimplifierSSA, self).do_simplify(ssa, head) @@ -345,14 +313,13 @@ if args.propagexpr: replace_stack_vars(self.ir_arch, ircfg) ircfg_simplifier = IRCFGSimplifierCommon(self.ir_arch) + ircfg_simplifier.deadremoval.add_expr_to_original_expr(ssa.ssa_variable_to_expr) ircfg_simplifier.simplify(ircfg, head) return ircfg - head = list(entry_points)[0] - ir_arch_a = IRAOutRegs(mdis.loc_db) simplifier = CustomIRCFGSimplifierSSA(ir_arch_a) ircfg = simplifier.simplify(ircfg_a, head) open('final.dot', 'w').write(ircfg.dot()) diff --git a/example/expression/asm_to_ir.py b/example/expression/asm_to_ir.py index 4bcbb05d..83eac728 100644 --- a/example/expression/asm_to_ir.py +++ b/example/expression/asm_to_ir.py @@ -8,7 +8,7 @@ from miasm.core import parse_asm from miasm.expression.expression import * from miasm.core import asmblock from miasm.arch.x86.ira import ir_a_x86_32 -from miasm.analysis.data_flow import dead_simp +from miasm.analysis.data_flow import DeadRemoval # First, asm code @@ -40,6 +40,8 @@ patches = asmblock.asm_resolve_final(mn_x86, asmcfg, loc_db) # Translate to IR ir_arch = ir_a_x86_32(loc_db) ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg) +deadrm = DeadRemoval(ir_arch) + # Display IR for lbl, irblock in viewitems(ircfg.blocks): @@ -48,7 +50,7 @@ for lbl, irblock in viewitems(ircfg.blocks): # Dead propagation open('graph.dot', 'w').write(ircfg.dot()) print('*' * 80) -dead_simp(ir_arch, ircfg) +deadrm(ircfg) open('graph2.dot', 'w').write(ircfg.dot()) # Display new IR diff --git a/example/expression/constant_propagation.py b/example/expression/constant_propagation.py index a6efbb46..36a548c5 100644 --- a/example/expression/constant_propagation.py +++ b/example/expression/constant_propagation.py @@ -9,7 +9,7 @@ from argparse import ArgumentParser from miasm.analysis.machine import Machine from miasm.analysis.binary import Container from miasm.analysis.cst_propag import propagate_cst_expr -from miasm.analysis.data_flow import dead_simp, \ +from miasm.analysis.data_flow import DeadRemoval, \ merge_blocks, remove_empty_assignblks from miasm.expression.simplifications import expr_simp @@ -29,6 +29,7 @@ cont = Container.from_stream(open(args.filename, 'rb')) mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db) ir_arch = machine.ira(mdis.loc_db) addr = int(args.address, 0) +deadrm = DeadRemoval(ir_arch) asmcfg = mdis.dis_multiblock(addr) ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg) @@ -42,7 +43,7 @@ if args.simplify: modified = True while modified: modified = False - modified |= dead_simp(ir_arch, ircfg) + modified |= deadrm(ircfg) modified |= remove_empty_assignblks(ircfg) modified |= merge_blocks(ircfg, entry_points) diff --git a/example/expression/graph_dataflow.py b/example/expression/graph_dataflow.py index c320fba0..e7386e9e 100644 --- a/example/expression/graph_dataflow.py +++ b/example/expression/graph_dataflow.py @@ -9,7 +9,7 @@ from miasm.expression.expression import get_expr_mem from miasm.analysis.data_analysis import intra_block_flow_raw, inter_block_flow from miasm.core.graph import DiGraph from miasm.ir.symbexec import SymbolicExecutionEngine -from miasm.analysis.data_flow import dead_simp +from miasm.analysis.data_flow import DeadRemoval parser = ArgumentParser("Simple expression use for generating dataflow graph") @@ -88,7 +88,7 @@ def gen_block_data_flow_graph(ir_arch, ircfg, ad, block_flow_cb): for irblock in viewvalues(ircfg.blocks): print(irblock) - dead_simp(ir_arch, ircfg) + deadrm(ircfg) irblock_0 = None @@ -140,6 +140,8 @@ print('ok') print('generating dataflow graph for:') ir_arch_analysis = machine.ira(mdis.loc_db) ircfg = ir_arch_analysis.new_ircfg_from_asmcfg(asmcfg) +deadrm = DeadRemoval(ir_arch_analysis) + for irblock in viewvalues(ircfg.blocks): print(irblock) diff --git a/miasm/analysis/data_flow.py b/miasm/analysis/data_flow.py index be0e4528..7bd6d72f 100644 --- a/miasm/analysis/data_flow.py +++ b/miasm/analysis/data_flow.py @@ -69,6 +69,8 @@ class ReachingDefinitions(dict): """ predecessor_state = {} for pred_lbl in self.ircfg.predecessors(block.loc_key): + if pred_lbl not in self.ircfg.blocks: + continue pred = self.ircfg.blocks[pred_lbl] for lval, definitions in viewitems(self.get_definitions(pred_lbl, len(pred))): predecessor_state.setdefault(lval, set()).update(definitions) @@ -201,81 +203,191 @@ class DiGraphDefUse(DiGraph): yield self.DotCellDescription(text="", attr={}) -def dead_simp_useful_assignblks(irarch, defuse, reaching_defs): - """Mark useful statements using previous reach analysis and defuse +class DeadRemoval(object): + """ + Do dead removal + """ - Source : Kennedy, K. (1979). A survey of data flow analysis techniques. - IBM Thomas J. Watson Research Division, Algorithm MK + def __init__(self, ir_arch, expr_to_original_expr=None): + self.ir_arch = ir_arch + if expr_to_original_expr is None: + expr_to_original_expr = {} + self.expr_to_original_expr = expr_to_original_expr - Return a set of triplets (block, assignblk number, lvalue) of - useful definitions - PRE: compute_reach(self) - """ - ircfg = reaching_defs.ircfg - useful = set() - - for block_lbl, block in viewitems(ircfg.blocks): - successors = ircfg.successors(block_lbl) - for successor in successors: - if successor not in ircfg.blocks: - keep_all_definitions = True - break - else: - keep_all_definitions = False - - # Block has a nonexistent successor or is a leaf - if keep_all_definitions or (len(successors) == 0): - valid_definitions = reaching_defs.get_definitions(block_lbl, - len(block)) - for lval, definitions in viewitems(valid_definitions): - if lval in irarch.get_out_regs(block) or keep_all_definitions: - for definition in definitions: - useful.add(AssignblkNode(definition[0], definition[1], lval)) - - # Force keeping of specific cases + def add_expr_to_original_expr(self, expr_to_original_expr): + self.expr_to_original_expr.update(expr_to_original_expr) + + def is_unkillable_destination(self, lval, rval): + if ( + lval.is_mem() or + self.ir_arch.IRDst == lval or + lval.is_id("exception_flags") or + rval.is_function_call() + ): + return True + return False + + def get_block_useful_destinations(self, block): + """ + Force keeping of specific cases + block: IRBlock instance + """ + useful = set() for index, assignblk in enumerate(block): for lval, rval in viewitems(assignblk): - if (lval.is_mem() or - irarch.IRDst == lval or - lval.is_id("exception_flags") or - rval.is_function_call()): - useful.add(AssignblkNode(block_lbl, index, lval)) + if self.is_unkillable_destination(lval, rval): + useful.add(AssignblkNode(block.loc_key, index, lval)) + return useful - # Useful nodes dependencies - for node in useful: - for parent in defuse.reachable_parents(node): - yield parent + def is_tracked_var(self, lval, variable): + new_lval = self.expr_to_original_expr.get(lval, lval) + return new_lval == variable + def find_definitions_from_worklist(self, worklist, ircfg): + """ + Find variables definition in @worklist by browsing the @ircfg + """ + locs_done = set() -def dead_simp(irarch, ircfg): - """ - Remove useless assignments. + defs = set() - This function is used to analyse relation of a * complete function * - This means the blocks under study represent a solid full function graph. + while worklist: + found = False + elt = worklist.pop() + if elt in locs_done: + continue + locs_done.add(elt) + variable, loc_key = elt + block = ircfg.get_block(loc_key) - Source : Kennedy, K. (1979). A survey of data flow analysis techniques. - IBM Thomas J. Watson Research Division, page 43 + if block is None: + # Consider no sources in incomplete graph + continue - @ircfg: IntermediateRepresentation instance - """ + for index, assignblk in reversed(list(enumerate(block))): + for dst, src in viewitems(assignblk): + if self.is_tracked_var(dst, variable): + defs.add(AssignblkNode(loc_key, index, dst)) + found = True + break + if found: + break - modified = False - reaching_defs = ReachingDefinitions(ircfg) - defuse = DiGraphDefUse(reaching_defs, deref_mem=True) - useful = set(dead_simp_useful_assignblks(irarch, defuse, reaching_defs)) - for block in list(viewvalues(ircfg.blocks)): - irs = [] - for idx, assignblk in enumerate(block): - new_assignblk = dict(assignblk) - for lval in assignblk: - if AssignblkNode(block.loc_key, idx, lval) not in useful: - del new_assignblk[lval] - modified = True - irs.append(AssignBlock(new_assignblk, assignblk.instr)) - ircfg.blocks[block.loc_key] = IRBlock(block.loc_key, irs) - return modified + if not found: + for predecessor in ircfg.predecessors(loc_key): + worklist.add((variable, predecessor)) + + return defs + + def find_out_regs_definitions_from_block(self, block, ircfg): + """ + Find definitions of out regs starting from @block + """ + worklist = set() + for reg in self.ir_arch.get_out_regs(block): + worklist.add((reg, block.loc_key)) + ret = self.find_definitions_from_worklist(worklist, ircfg) + return ret + + + def add_def_for_incomplete_leaf(self, block, ircfg, reaching_defs): + """ + Add valid definitions at end of @block plus out regs + """ + valid_definitions = reaching_defs.get_definitions( + block.loc_key, + len(block) + ) + worklist = set() + for lval, definitions in viewitems(valid_definitions): + for definition in definitions: + new_lval = self.expr_to_original_expr.get(lval, lval) + worklist.add((new_lval, block.loc_key)) + ret = self.find_definitions_from_worklist(worklist, ircfg) + useful = ret + useful.update(self.find_out_regs_definitions_from_block(block, ircfg)) + return useful + + def get_useful_assignments(self, ircfg, defuse, reaching_defs): + """ + Mark useful statements using previous reach analysis and defuse + + Return a set of triplets (block, assignblk number, lvalue) of + useful definitions + PRE: compute_reach(self) + + """ + + useful = set() + + for block_lbl, block in viewitems(ircfg.blocks): + block = ircfg.get_block(block_lbl) + if block is None: + # skip unknown blocks: won't generate dependencies + continue + + block_useful = self.get_block_useful_destinations(block) + useful.update(block_useful) + + + successors = ircfg.successors(block_lbl) + for successor in successors: + if successor not in ircfg.blocks: + keep_all_definitions = True + break + else: + keep_all_definitions = False + + if keep_all_definitions: + useful.update(self.add_def_for_incomplete_leaf(block, ircfg, reaching_defs)) + continue + + if len(successors) == 0: + useful.update(self.find_out_regs_definitions_from_block(block, ircfg)) + else: + continue + + + + # Useful nodes dependencies + for node in useful: + for parent in defuse.reachable_parents(node): + yield parent + + def do_dead_removal(self, ircfg): + """ + Remove useless assignments. + + This function is used to analyse relation of a * complete function * + This means the blocks under study represent a solid full function graph. + + Source : Kennedy, K. (1979). A survey of data flow analysis techniques. + IBM Thomas J. Watson Research Division, page 43 + + @ircfg: IntermediateRepresentation instance + """ + + modified = False + reaching_defs = ReachingDefinitions(ircfg) + defuse = DiGraphDefUse(reaching_defs, deref_mem=True) + useful = self.get_useful_assignments(ircfg, defuse, reaching_defs) + useful = set(useful) + for block in list(viewvalues(ircfg.blocks)): + irs = [] + for idx, assignblk in enumerate(block): + new_assignblk = dict(assignblk) + for lval in assignblk: + if AssignblkNode(block.loc_key, idx, lval) not in useful: + del new_assignblk[lval] + modified = True + irs.append(AssignBlock(new_assignblk, assignblk.instr)) + ircfg.blocks[block.loc_key] = IRBlock(block.loc_key, irs) + return modified + + def __call__(self, ircfg): + ret = self.do_dead_removal(ircfg) + return ret def _test_merge_next_block(ircfg, loc_key): @@ -680,6 +792,8 @@ class PropagateThroughExprId(object): else: # Check everyone but node_a.label and node_b.label for loc in nodes_to_do - set([node_a.label, node_b.label]): + if loc not in ssa.graph.blocks: + continue block = ssa.graph.blocks[loc] if self.has_propagation_barrier(block.assignblks): return True @@ -725,7 +839,10 @@ class PropagateThroughExprId(object): ircfg = ssa.graph def_dct = {} for node in ircfg.nodes(): - for index, assignblk in enumerate(ircfg.blocks[node]): + block = ircfg.blocks.get(node, None) + if block is None: + continue + for index, assignblk in enumerate(block): for dst, src in viewitems(assignblk): if not dst.is_id(): continue @@ -735,26 +852,6 @@ class PropagateThroughExprId(object): def_dct[dst] = node, index return def_dct - def phi_has_identical_sources(self, ssa, def_dct, var): - """ - If phi operation has identical source values, return it; else None - @ssa: SSADiGraph instance - @def_dct: dictionary linking variable to its assignment location - @var: Phi destination variable - """ - loc_key, index = def_dct[var] - sources = ssa.graph.blocks[loc_key][index][var] - assert sources.is_op('Phi') - sources_values = set() - for src in sources.args: - assert src in def_dct - loc_key, index = def_dct[src] - value = ssa.graph.blocks[loc_key][index][src] - sources_values.add(value) - if len(sources_values) != 1: - return None - return list(sources_values)[0] - def get_candidates(self, ssa, head, max_expr_depth): def_dct = self.get_var_definitions(ssa) defuse = SSADefUse.from_ssa(ssa) @@ -771,10 +868,6 @@ class PropagateThroughExprId(object): if node.var.is_mem(): continue if src.is_op('Phi'): - ret = self.phi_has_identical_sources(ssa, def_dct, node.var) - if ret: - to_replace[node.var] = ret - node_to_reg[node] = node.var continue to_replace[node.var] = src node_to_reg[node] = node.var @@ -891,7 +984,9 @@ class PropagateThroughExprMem(object): while todo: loc_key, index, mem_dst, mem_src = todo.pop() - block = ircfg.blocks[loc_key] + block = ircfg.blocks.get(loc_key, None) + if block is None: + continue assignblks = list(block) block_modified = False for i in range(index, len(block)): @@ -1254,7 +1349,9 @@ class DiGraphLiveness(DiGraph): self._blocks = {} # Add irblocks gen/kill for node in ircfg.nodes(): - irblock = ircfg.blocks[node] + irblock = ircfg.blocks.get(node, None) + if irblock is None: + continue irblockinfos = IRBlockLivenessInfos(irblock) self.add_node(irblockinfos.loc_key) self.blocks[irblockinfos.loc_key] = irblockinfos @@ -1357,7 +1454,9 @@ class DiGraphLiveness(DiGraph): todo = set(self.leaves()) while todo: node = todo.pop() - cur_block = self.blocks[node] + cur_block = self.blocks.get(node, None) + if cur_block is None: + continue modified = self.back_propagate_compute(cur_block) if not modified: continue @@ -1376,7 +1475,9 @@ class DiGraphLivenessIRA(DiGraphLiveness): """Add ircfg out regs""" for node in self.leaves(): - irblock = self.ircfg.blocks[node] + irblock = self.ircfg.blocks.get(node, None) + if irblock is None: + continue var_out = ir_arch_a.get_out_regs(irblock) irblock_liveness = self.blocks[node] irblock_liveness.infos[-1].var_out = var_out @@ -1454,18 +1555,24 @@ def update_phi_with_deleted_edges(ircfg, edges_to_del): @edges_to_del: edges to delete """ + + phi_locs_to_srcs = {} + for loc_src, loc_dst in edges_to_del: + phi_locs_to_srcs.setdefault(loc_dst, set()).add(loc_src) + modified = False blocks = dict(ircfg.blocks) - for loc_src, loc_dst in edges_to_del: + for loc_dst, loc_srcs in viewitems(phi_locs_to_srcs): block = ircfg.blocks[loc_dst] - assert block.assignblks + if not irblock_has_phi(block): + continue assignblks = list(block) assignblk = assignblks[0] out = {} for dst, phi_sources in viewitems(assignblk): if not phi_sources.is_op('Phi'): - out = assignblk - break + out[dst] = phi_sources + continue var_to_parents = get_phi_sources_parent_block( ircfg, loc_dst, @@ -1474,7 +1581,8 @@ def update_phi_with_deleted_edges(ircfg, edges_to_del): to_keep = set(phi_sources.args) for src in phi_sources.args: parents = var_to_parents[src] - if loc_src in parents: + remaining = parents.difference(loc_srcs) + if not remaining: to_keep.discard(src) modified = True assert to_keep @@ -1504,7 +1612,9 @@ def del_unused_edges(ircfg, heads): edges_to_del_1 = set() for node in ircfg.nodes(): successors = set(ircfg.successors(node)) - block = ircfg.blocks[node] + block = ircfg.blocks.get(node, None) + if block is None: + continue dst = block.dst possible_dsts = set(solution.value for solution in possible_values(dst)) if not all(dst.is_loc() for dst in possible_dsts): @@ -1528,6 +1638,8 @@ def del_unused_edges(ircfg, heads): for node in nodes_to_del: block = ircfg.blocks[node] ircfg.del_node(node) + del ircfg.blocks[node] + for assignblock in block: for dst in assignblock: deleted_vars.add(dst) @@ -1551,12 +1663,18 @@ class DiGraphLivenessSSA(DiGraphLivenessIRA): continue out = {} for sources in viewvalues(irblock[0]): + if not sources.is_op('Phi'): + # Some phi sources may have already been resolved to an + # expression + continue var_to_parents = get_phi_sources_parent_block(self, irblock.loc_key, sources.args) for var, var_parents in viewitems(var_to_parents): out.setdefault(var, set()).update(var_parents) self.loc_key_to_phi_parents[irblock.loc_key] = out def back_propagate_to_parent(self, todo, node, parent): + if parent not in self.blocks: + return parent_block = self.blocks[parent] cur_block = self.blocks[node] irblock = self.ircfg.blocks[node] diff --git a/miasm/analysis/outofssa.py b/miasm/analysis/outofssa.py index 497956be..c52b3250 100644 --- a/miasm/analysis/outofssa.py +++ b/miasm/analysis/outofssa.py @@ -149,7 +149,9 @@ class UnSSADiGraph(object): # walk in DFS over the dominator tree for loc_key in dominator_tree.walk_depth_first_forward(self.head): - irblock = ircfg.blocks[loc_key] + irblock = ircfg.blocks.get(loc_key, None) + if irblock is None: + continue # Create live index for phi new vars # They do not exist in the graph yet, so index is set to None diff --git a/miasm/analysis/simplifier.py b/miasm/analysis/simplifier.py index 8c448991..8e9005a8 100644 --- a/miasm/analysis/simplifier.py +++ b/miasm/analysis/simplifier.py @@ -8,7 +8,8 @@ from miasm.analysis.ssa import SSADiGraph from miasm.analysis.outofssa import UnSSADiGraph from miasm.analysis.data_flow import DiGraphLivenessSSA from miasm.expression.simplifications import expr_simp -from miasm.analysis.data_flow import dead_simp, \ +from miasm.ir.ir import AssignBlock, IRBlock +from miasm.analysis.data_flow import DeadRemoval, \ merge_blocks, remove_empty_assignblks, \ PropagateExprIntThroughExprId, PropagateThroughExprId, \ PropagateThroughExprMem, del_unused_edges @@ -83,6 +84,7 @@ class IRCFGSimplifierCommon(IRCFGSimplifier): def __init__(self, ir_arch, expr_simp=expr_simp): self.expr_simp = expr_simp super(IRCFGSimplifierCommon, self).__init__(ir_arch) + self.deadremoval = DeadRemoval(self.ir_arch) def init_passes(self): self.passes = [ @@ -114,7 +116,7 @@ class IRCFGSimplifierCommon(IRCFGSimplifier): @ircfg: IRCFG instance to simplify @head: Location instance of the ircfg head """ - modified = dead_simp(self.ir_arch, ircfg) + modified = self.deadremoval(ircfg) modified |= remove_empty_assignblks(ircfg) modified |= merge_blocks(ircfg, set([head])) return modified @@ -144,6 +146,7 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): self.propag_int = PropagateExprIntThroughExprId() self.propag_expr = PropagateThroughExprId() self.propag_mem = PropagateThroughExprMem() + self.deadremoval = DeadRemoval(self.ir_arch, self.all_ssa_vars) def get_forbidden_regs(self): """ @@ -168,8 +171,13 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): self.do_propagate_mem, self.do_propagate_expr, self.do_dead_simp_ssa, + self.do_remove_empty_assignblks, + self.do_del_unused_edges, + self.do_merge_blocks, ] + + def ircfg_to_ssa(self, ircfg, head): """ Apply the SSA transformation to @ircfg using it's @head @@ -217,8 +225,15 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): @head: Location instance of the graph head """ modified = self.propag_int.propagate(ssa, head) - modified |= ssa.graph.simplify(self.expr_simp) - modified |= del_unused_edges(ssa.graph, set([head])) + return modified + + @fix_point + def do_del_unused_edges(self, ssa, head): + """ + Del unused edges of the ssa graph + @head: Location instance of the graph head + """ + modified = del_unused_edges(ssa.graph, set([head])) return modified @fix_point @@ -228,8 +243,6 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): @head: Location instance of the graph head """ modified = self.propag_mem.propagate(ssa, head) - modified |= ssa.graph.simplify(self.expr_simp) - modified |= del_unused_edges(ssa.graph, set([head])) return modified @fix_point @@ -239,15 +252,31 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): @head: Location instance of the graph head """ modified = self.propag_expr.propagate(ssa, head) - modified |= ssa.graph.simplify(self.expr_simp) - modified |= del_unused_edges(ssa.graph, set([head])) + return modified + + @fix_point + def do_remove_empty_assignblks(self, ssa, head): + """ + Remove empty assignblks + @head: Location instance of the graph head + """ + modified = remove_empty_assignblks(ssa.graph) + return modified + + @fix_point + def do_merge_blocks(self, ssa, head): + """ + Merge blocks with one parent/son + @head: Location instance of the graph head + """ + modified = merge_blocks(ssa.graph, set([head])) return modified @fix_point def do_dead_simp_ssa(self, ssa, head): """ Apply: - - dead_simp + - deadrm - remove_empty_assignblks - del_unused_edges - merge_blocks @@ -257,10 +286,7 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): @ircfg: IRCFG instance to simplify @head: Location instance of the ircfg head """ - modified = dead_simp(self.ir_arch, ssa.graph) - modified |= remove_empty_assignblks(ssa.graph) - modified |= del_unused_edges(ssa.graph, set([head])) - modified |= merge_blocks(ssa.graph, set([head])) + modified = self.deadremoval(ssa.graph) return modified def do_simplify(self, ssa, head): @@ -285,6 +311,7 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): def simplify(self, ircfg, head): """ + Add access to "abi out regs" in each leaf block Apply SSA transformation to @ircfg Apply passes until reaching a fix point Apply out-of-ssa transformation @@ -295,9 +322,11 @@ class IRCFGSimplifierSSA(IRCFGSimplifierCommon): @ircfg: IRCFG instance to simplify @head: Location instance of the ircfg head """ + ssa = self.ircfg_to_ssa(ircfg, head) ssa = self.do_simplify_loop(ssa, head) ircfg = self.ssa_to_unssa(ssa, head) ircfg_simplifier = IRCFGSimplifierCommon(self.ir_arch) + ircfg_simplifier.deadremoval.add_expr_to_original_expr(self.all_ssa_vars) ircfg_simplifier.simplify(ircfg, head) return ircfg diff --git a/miasm/analysis/ssa.py b/miasm/analysis/ssa.py index 827be009..7f0b0f13 100644 --- a/miasm/analysis/ssa.py +++ b/miasm/analysis/ssa.py @@ -73,9 +73,6 @@ class SSA(object): # IRCFG instance self.ircfg = ircfg - # SSA blocks - self.blocks = {} - # stack for RHS self._stack_rhs = {} # stack for LHS @@ -120,7 +117,6 @@ class SSA(object): def reset(self): """Resets SSA transformation""" - self.blocks = {} self.expressions = {} self._stack_rhs = {} self._stack_lhs = {} @@ -427,12 +423,13 @@ class SSADiGraph(SSA): a set of IRBlocks in which the variable gets assigned """ + visited_loc = set() for loc_key in self.graph.walk_depth_first_forward(head): irblock = self.get_block(loc_key) if irblock is None: # Incomplete graph continue - + visited_loc.add(loc_key) # search for block's IR definitions/destinations for assignblk in irblock.assignblks: for dst in assignblk: @@ -443,6 +440,8 @@ class SSADiGraph(SSA): continue # map variable definition to blocks self.defs.setdefault(dst, set()).add(irblock.loc_key) + if visited_loc != set(self.graph.blocks): + raise RuntimeError("Cannot operate on a non connected graph") def _place_phi(self, head): """ @@ -608,9 +607,18 @@ class SSADiGraph(SSA): if irblock is None: continue 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 + if irblock_has_phi(irblock): + # If first block contains phi, we are updating an existing ssa form + # so update phi + assignblks = list(irblock.assignblks) + out = dict(assignblks[0]) + out.update(dict(assignblk)) + assignblks[0] = AssignBlock(out, assignblk.instr) + new_irblock = IRBlock(loc_key, assignblks) + else: + # insert at the beginning + new_irblock = IRBlock(loc_key, [assignblk] + list(irblock.assignblks)) + self.ircfg.blocks[loc_key] = new_irblock def _fix_no_def_var(self, head): """ diff --git a/miasm/arch/ppc/regs.py b/miasm/arch/ppc/regs.py index 97556931..4b710045 100644 --- a/miasm/arch/ppc/regs.py +++ b/miasm/arch/ppc/regs.py @@ -46,10 +46,19 @@ superregs_str = (["SPRG%d" % i for i in range(4)] + superregs_expr, superregs_init, superregs = gen_regs(superregs_str, globals(), 32) +mmuregs_str = (["SR%d" % i for i in range(16)] + + ["IBAT%dU" % i for i in range(4)] + + ["IBAT%dL" % i for i in range(4)] + + ["DBAT%dU" % i for i in range(4)] + + ["DBAT%dL" % i for i in range(4)] + + ["SDR1"]) +mmuregs_expr, mmuregs_init, mmuregs = gen_regs(mmuregs_str, + globals(), 32) + regs_flt_expr = [] all_regs_ids = (gpregs_expr + crfbitregs_expr + xerbitregs_expr + - xerbcreg_expr + otherregs_expr + superregs_expr + + xerbcreg_expr + otherregs_expr + superregs_expr + mmuregs_expr + [ exception_flags, spr_access, reserve, reserve_address ]) all_regs_ids_byname = dict([(x.name, x) for x in all_regs_ids]) all_regs_ids_init = [ExprId("%s_init" % x.name, x.size) for x in all_regs_ids] diff --git a/miasm/arch/ppc/sem.py b/miasm/arch/ppc/sem.py index 5e8e394c..fd6db8f3 100644 --- a/miasm/arch/ppc/sem.py +++ b/miasm/arch/ppc/sem.py @@ -10,9 +10,19 @@ from miasm.jitter.csts import * spr_dict = { 8: LR, 9: CTR, 18: DSISR, 19: DAR, - 22: DEC, 26: SRR0, 27: SRR1, + 22: DEC, 25: SDR1, 26: SRR0, 27: SRR1, 272: SPRG0, 273: SPRG0, 274: SPRG1, 275: SPRG2, 276: SPRG3, - 284: TBL, 285: TBU, 287: PVR, 1023: PIR + 284: TBL, 285: TBU, 287: PVR, + 528: IBAT0U, 529: IBAT0L, 530: IBAT1U, 531: IBAT1L, 532: IBAT2U, 533: IBAT2L, 534: IBAT3U, 535: IBAT3L, + 536: DBAT0U, 537: DBAT0L, 538: DBAT1U, 539: DBAT1L, 540: DBAT2U, 541: DBAT2L, 542: DBAT3U, 543: DBAT3L, + 1023: PIR +} + +sr_dict = { + 0: SR0, 1: SR1, 2: SR2, 3: SR3, + 4: SR4, 5: SR5, 6: SR6, 7: SR7, + 8: SR8, 9: SR9, 10: SR10, 11: SR11, + 12: SR12, 13: SR13, 14: SR14, 15: SR15 } crf_dict = dict((ExprId("CR%d" % i, 4), @@ -23,6 +33,7 @@ crf_dict = dict((ExprId("CR%d" % i, 4), ctx = { 'crf_dict': crf_dict, 'spr_dict': spr_dict, + 'sr_dict': sr_dict, 'expr': expr, } @@ -384,6 +395,22 @@ def mn_mtspr(ir, instr, arg1, arg2): SPR_ACCESS_IS_WRITE), 32)), ExprAssign(exception_flags, ExprInt(EXCEPT_SPR_ACCESS, 32)) ], [] +def mn_mtsr(ir, instr, sr, rs): + srid = sr.arg.arg + return [ ExprAssign(sr_dict[srid], rs) ], [] + +# TODO +#def mn_mtsrin(ir, instr, rs, rb): +# return [ ExprAssign(sr_dict[rb[0:3]], rs) ], [] + +def mn_mfsr(ir, instr, rd, sr): + srid = sr.arg.arg + return [ ExprAssign(rd, sr_dict[srid]) ], [] + +# TODO +#def mn_mfsrin(ir, instr, rd, rb): +# return [ ExprAssign(rd, sr_dict[rb[0:3]]) ], [] + def mn_do_mul(ir, instr, rd, ra, arg2): variant = instr.name[3:] if variant[-1] == '.': @@ -809,13 +836,13 @@ sem_dir = { 'MFCR': mn_do_mfcr, 'MFMSR': mn_mfmsr, 'MFSPR': mn_mfspr, - 'MFSR': mn_do_nop_warn, + 'MFSR': mn_mfsr, 'MFSRIN': mn_do_nop_warn, 'MFTB': mn_mfmsr, 'MTCRF': mn_mtcrf, 'MTMSR': mn_mtmsr, 'MTSPR': mn_mtspr, - 'MTSR': mn_do_nop_warn, + 'MTSR': mn_mtsr, 'MTSRIN': mn_do_nop_warn, 'NAND': mn_do_nand, 'NAND.': mn_do_nand, diff --git a/miasm/ir/analysis.py b/miasm/ir/analysis.py index 774e66f7..9aa61f59 100644 --- a/miasm/ir/analysis.py +++ b/miasm/ir/analysis.py @@ -5,7 +5,6 @@ import logging from miasm.ir.ir import IntermediateRepresentation, AssignBlock from miasm.expression.expression import ExprOp, ExprAssign -from miasm.analysis.data_flow import dead_simp as new_dead_simp_imp log = logging.getLogger("analysis") @@ -106,8 +105,3 @@ class ira(IntermediateRepresentation): def sizeof_pointer(self): "Return the size of a void* in bits" raise NotImplementedError("Abstract method") - - def dead_simp(self, ircfg): - """Deprecated: See miasm.analysis.data_flow.dead_simp()""" - warnings.warn('DEPRECATION WARNING: Please use miasm.analysis.data_flow.dead_simp(ira) instead of ira.dead_simp()') - new_dead_simp_imp(self, ircfg) diff --git a/miasm/jitter/arch/JitCore_ppc32_regs.h b/miasm/jitter/arch/JitCore_ppc32_regs.h index d15b5e51..a16d1e95 100644 --- a/miasm/jitter/arch/JitCore_ppc32_regs.h +++ b/miasm/jitter/arch/JitCore_ppc32_regs.h @@ -87,3 +87,37 @@ JITCORE_PPC_REG_EXPAND(PVR, 32) JITCORE_PPC_REG_EXPAND(DEC, 32) JITCORE_PPC_REG_EXPAND(TBL, 32) JITCORE_PPC_REG_EXPAND(TBU, 32) + +JITCORE_PPC_REG_EXPAND(SR0, 32) +JITCORE_PPC_REG_EXPAND(SR1, 32) +JITCORE_PPC_REG_EXPAND(SR2, 32) +JITCORE_PPC_REG_EXPAND(SR3, 32) +JITCORE_PPC_REG_EXPAND(SR4, 32) +JITCORE_PPC_REG_EXPAND(SR5, 32) +JITCORE_PPC_REG_EXPAND(SR6, 32) +JITCORE_PPC_REG_EXPAND(SR7, 32) +JITCORE_PPC_REG_EXPAND(SR8, 32) +JITCORE_PPC_REG_EXPAND(SR9, 32) +JITCORE_PPC_REG_EXPAND(SR10, 32) +JITCORE_PPC_REG_EXPAND(SR11, 32) +JITCORE_PPC_REG_EXPAND(SR12, 32) +JITCORE_PPC_REG_EXPAND(SR13, 32) +JITCORE_PPC_REG_EXPAND(SR14, 32) +JITCORE_PPC_REG_EXPAND(SR15, 32) +JITCORE_PPC_REG_EXPAND(IBAT0U, 32) +JITCORE_PPC_REG_EXPAND(IBAT0L, 32) +JITCORE_PPC_REG_EXPAND(IBAT1U, 32) +JITCORE_PPC_REG_EXPAND(IBAT1L, 32) +JITCORE_PPC_REG_EXPAND(IBAT2U, 32) +JITCORE_PPC_REG_EXPAND(IBAT2L, 32) +JITCORE_PPC_REG_EXPAND(IBAT3U, 32) +JITCORE_PPC_REG_EXPAND(IBAT3L, 32) +JITCORE_PPC_REG_EXPAND(DBAT0U, 32) +JITCORE_PPC_REG_EXPAND(DBAT0L, 32) +JITCORE_PPC_REG_EXPAND(DBAT1U, 32) +JITCORE_PPC_REG_EXPAND(DBAT1L, 32) +JITCORE_PPC_REG_EXPAND(DBAT2U, 32) +JITCORE_PPC_REG_EXPAND(DBAT2L, 32) +JITCORE_PPC_REG_EXPAND(DBAT3U, 32) +JITCORE_PPC_REG_EXPAND(DBAT3L, 32) +JITCORE_PPC_REG_EXPAND(SDR1, 32) diff --git a/test/analysis/data_flow.py b/test/analysis/data_flow.py index 259aca7c..98efecbe 100644 --- a/test/analysis/data_flow.py +++ b/test/analysis/data_flow.py @@ -5,7 +5,7 @@ from future.utils import viewitems from miasm.expression.expression import ExprId, ExprInt, ExprAssign, ExprMem from miasm.core.locationdb import LocationDB -from miasm.analysis.data_flow import * +from miasm.analysis.data_flow import DeadRemoval, ReachingDefinitions, DiGraphDefUse from miasm.ir.analysis import ira from miasm.ir.ir import IRBlock, AssignBlock @@ -82,6 +82,7 @@ class IRATest(ira): return set([self.ret_reg, self.sp]) IRA = IRATest(loc_db) +deadrm = DeadRemoval(IRA) # graph 1 : Simple graph with dead and alive variables @@ -696,7 +697,7 @@ for test_nb, test in enumerate([(G1_IRA, G1_EXP_IRA), defuse = DiGraphDefUse(reaching_defs, deref_mem=True) # # Simplify graph - dead_simp(IRA, g_ira) + deadrm(g_ira) # # Print simplified graph, for debug open("simp_graph_%02d.dot" % (test_nb+1), "w").write(g_ira.dot()) |