/// <summary> /// Extracts structured program constructs out of snarled goto nests, if possible. /// Since procedures are now independent of each other, this analysis /// is done one procedure at a time. /// </summary> public void StructureProgram() { foreach (var program in project.Programs) { int i = 0; foreach (Procedure proc in program.Procedures.Values) { try { eventListener.ShowProgress("Rewriting procedures to high-level language.", i, program.Procedures.Values.Count); ++i; Console.WriteLine("rewriting: {0}", proc); IStructureAnalysis sa = new StructureAnalysis(proc); sa.Structure(); } catch (Exception e) { eventListener.Error( eventListener.CreateProcedureNavigator(program, proc), e, "An error occurred while rewriting procedure to high-level language."); } } WriteDecompilerProducts(); } eventListener.ShowStatus("Rewriting complete."); }
/// <summary> /// Extracts structured program constructs out of snarled goto nests, if possible. /// Since procedures are now independent of each other, this analysis /// is done one procedure at a time. /// </summary> public void StructureProgram() { if (project is null) { return; } foreach (var program in project.Programs) { int i = 0; foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { return; } try { eventListener.ShowProgress("Rewriting procedures to high-level language.", i, program.Procedures.Values.Count); ++i; IStructureAnalysis sa = new StructureAnalysis(eventListener, program, proc); sa.Structure(); } catch (Exception e) { eventListener.Error( eventListener.CreateProcedureNavigator(program, proc), e, "An error occurred while rewriting procedure to high-level language."); } } } project.FireScriptEvent(ScriptEvent.OnProgramDecompiled); WriteDecompilerProducts(); eventListener.ShowStatus("Rewriting complete."); }
/// <summary> /// Processes procedures individually, building complex expression /// trees out of the simple, close-to-the-machine code generated by /// the disassembly. /// </summary> /// <param name="rl"></param> public void BuildExpressionTrees() { eventListener.ShowProgress("Building expressions.", 0, program.Procedures.Count); foreach (var sst in this.ssts) { var ssa = sst.SsaState; try { DumpWatchedProcedure("Before expression coalescing", ssa.Procedure); // Procedures should be untangled from each other. Now process // each one separately. DeadCode.Eliminate(ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(ssa); coa.Transform(); DeadCode.Eliminate(ssa); var vp = new ValuePropagator(program.SegmentMap, ssa, program.CallGraph, dynamicLinker, eventListener); vp.Transform(); DumpWatchedProcedure("After expression coalescing", ssa.Procedure); var liv = new LinearInductionVariableFinder( ssa, new BlockDominatorGraph( ssa.Procedure.ControlGraph, ssa.Procedure.EntryBlock)); liv.Find(); foreach (var de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } DeadCode.Eliminate(ssa); DumpWatchedProcedure("After strength reduction", ssa.Procedure); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(program, ssa, program.InductionVariables, eventListener); web.Transform(); ssa.ConvertBack(false); DumpWatchedProcedure("After data flow analysis", ssa.Procedure); } catch (Exception ex) { eventListener.Error( eventListener.CreateProcedureNavigator(program, ssa.Procedure), ex, "An internal error occurred while building the expressions of {0}", ssa.Procedure.Name); } eventListener.Advance(1); } }
/// <summary> /// Executes the core of the analysis /// </summary> /// <remarks> /// The algorithm visits nodes in post-order in each iteration. This /// means that all descendants of a node will be visited (and /// hence had the chance to be reduced) before the node itself. /// The algorithm’s behavior when visiting node _n_ /// depends on hether the region at _n_ /// is acyclic (has no loop) or not. For an acyclic region, the /// algorithm tries to match the subgraph /// at _n_to an acyclic schemas (3.2). If there is no match, /// and the region is a switch candidate, then it attempts to /// refine the region at _n_ into a switch region. /// /// If _n_ is cyclic, the algorithm /// compares the region at _n_ to the cyclic schemata. /// If this fails, it refines _n_ into a loop (3.6). /// /// If both matching and refinement do not make progress, the /// current node _n_ is then skipped for the current iteration of /// the algorithm. If there is an iteration in which all /// nodes are skipped, i.e., the algorithm makes no progress, then /// the algorithm employs a last resort refinement (3.7) to /// ensure that progress can be made in the next iteration. /// </remarks> public Region Execute() { var result = BuildRegionGraph(proc); this.regionGraph = result.Item1; this.entry = result.Item2; int iterations = 0; int oldCount; int newCount; do { if (eventListener.IsCanceled()) break; ++iterations; if (iterations > 1000) { eventListener.Warn( eventListener.CreateProcedureNavigator(program, proc), "Structure analysis stopped making progress, quitting. Please report this issue at https://github.com/uxmal/reko"); DumpGraph(); break; } oldCount = regionGraph.Nodes.Count; this.doms = new DominatorGraph<Region>(this.regionGraph, result.Item2); this.unresolvedCycles = new Queue<Tuple<Region, ISet<Region>>>(); this.unresolvedNoncycles = new Queue<Tuple<Region, ISet<Region>>>(); var postOrder = new DfsIterator<Region>(regionGraph).PostOrder(entry).ToList(); bool didReduce = false; foreach (var n in postOrder) { Probe(); didReduce = false; do { if (eventListener.IsCanceled()) break; didReduce = ReduceAcyclic(n); if (!didReduce && IsCyclic(n)) { didReduce = ReduceCyclic(n); } } while (didReduce); } newCount = regionGraph.Nodes.Count; if (newCount == oldCount && newCount > 1) { // Didn't make any progress this round, // try refining unstructured regions ProcessUnresolvedRegions(); } } while (regionGraph.Nodes.Count > 1); return entry; }
/// <summary> /// Processes procedures individually, building complex expression /// trees out of the simple, close-to-the-machine code generated by /// the disassembly. /// </summary> /// <param name="rl"></param> public void BuildExpressionTrees() { eventListener.ShowProgress("Building expressions.", 0, program.Procedures.Count); foreach (var sst in this.ssts !) { var ssa = sst.SsaState; try { if (program.User.AggressiveBranchRemoval) { // This ends up being very aggressive and doesn't replicate the original // binary code. See discussion on https://github.com/uxmal/reko/issues/932 DumpWatchedProcedure("urb", "Before unreachable block removal", ssa.Procedure); var urb = new UnreachableBlockRemover(ssa, eventListener); urb.Transform(); } DumpWatchedProcedure("precoa", "Before expression coalescing", ssa.Procedure); // Procedures should be untangled from each other. Now process // each one separately. DeadCode.Eliminate(ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(ssa); coa.Transform(); DeadCode.Eliminate(ssa); var vp = new ValuePropagator(program.SegmentMap, ssa, program.CallGraph, dynamicLinker, eventListener); vp.Transform(); DumpWatchedProcedure("postcoa", "After expression coalescing", ssa.Procedure); var liv = new LinearInductionVariableFinder( ssa, new BlockDominatorGraph( ssa.Procedure.ControlGraph, ssa.Procedure.EntryBlock)); liv.Find(); foreach (var de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } DeadCode.Eliminate(ssa); DumpWatchedProcedure("sr", "After strength reduction", ssa.Procedure); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(program, ssa, program.InductionVariables, eventListener); web.Transform(); ssa.ConvertBack(false); DumpWatchedProcedure("dfa", "After data flow analysis", ssa.Procedure); } catch (Exception ex) { eventListener.Error( eventListener.CreateProcedureNavigator(program, ssa.Procedure), ex, "An internal error occurred while building the expressions of {0}", ssa.Procedure.Name); } eventListener.Advance(1); } }