private void UntangleProcedureScc(IList<Procedure> procs) { if (procs.Count == 1) { var proc = procs[0]; Aliases alias = new Aliases(proc, program.Architecture, flow); alias.Transform(); // Transform the procedure to SSA state. When encountering 'call' instructions, // they can be to functions already visited. If so, they have a "ProcedureFlow" // associated with them. If they have not been visited, or are computed destinations // (e.g. vtables) they will have no "ProcedureFlow" associated with them yet, in // which case the the SSA treats the call as a "hell node". var doms = proc.CreateBlockDominatorGraph(); var sst = new SsaTransform(flow, proc, doms); var ssa = sst.SsaState; // Propagate condition codes and registers. At the end, the hope is that // all statements like (x86) mem[esp_42+4] will have been converted to // mem[fp - 30]. We also hope that procedure constants kept in registers // are propagated to the corresponding call sites. var cce = new ConditionCodeEliminator(ssa.Identifiers, program.Platform); cce.Transform(); var vp = new ValuePropagator(ssa.Identifiers, proc); vp.Transform(); // Now compute SSA for the stack-based variables as well. That is: // mem[fp - 30] becomes wLoc30, while // mem[fp + 30] becomes wArg30. // This allows us to compute the dataflow of this procedure. sst.RenameFrameAccesses = true; sst.AddUseInstructions = true; sst.Transform(); // Propagate those newly discovered identifiers. vp.Transform(); // At this point, the computation of _actual_ ProcedureFlow should be possible. var tid = new TrashedRegisterFinder2(program.Architecture, flow, proc, ssa.Identifiers, this.eventListener); tid.Compute(); DeadCode.Eliminate(proc, ssa); // Build expressions. A definition with a single use can be subsumed // into the using expression. var coa = new Coalescer(proc, ssa); coa.Transform(); DeadCode.Eliminate(proc, ssa); var liv = new LinearInductionVariableFinder( proc, ssa.Identifiers, new BlockDominatorGraph(proc.ControlGraph, proc.EntryBlock)); liv.Find(); foreach (var de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } proc.Dump(true, false); //var opt = new OutParameterTransformer(proc, ssa.Identifiers); //opt.Transform(); DeadCode.Eliminate(proc, ssa); // Definitions with multiple uses and variables joined by PHI functions become webs. var web = new WebBuilder(proc, ssa.Identifiers, program.InductionVariables); web.Transform(); ssa.ConvertBack(false); } else { } }
private Procedure RunTest(string sExp, IProcessorArchitecture arch, Func<Procedure> mkProc) { var proc = mkProc(); progBuilder.ResolveUnresolved(); var ssa = new SsaTransform(pf, proc, proc.CreateBlockDominatorGraph()); var vp = new ValuePropagator(ssa.SsaState.Identifiers, proc); vp.Transform(); ssa.RenameFrameAccesses = true; ssa.AddUseInstructions = true; ssa.Transform(); vp.Transform(); var trf = new TrashedRegisterFinder2( arch, pf, proc, ssa.SsaState.Identifiers, NullDecompilerEventListener.Instance); var flow = trf.Compute(); var sw = new StringWriter(); sw.Write("Preserved: "); sw.WriteLine(string.Join(",", flow.Preserved.OrderBy(p => p.ToString()))); sw.Write("Trashed: "); sw.WriteLine(string.Join(",", flow.Trashed.OrderBy(p => p.ToString()))); if (flow.Constants.Count > 0) { sw.Write("Constants: "); sw.WriteLine(string.Join( ",", flow.Constants .OrderBy(kv => kv.Key.ToString()) .Select(kv => string.Format( "{0}:{1}", kv.Key, kv.Value)))); } var sActual = sw.ToString(); if (sActual != sExp) { proc.Dump(true, false); Debug.WriteLine(sActual); Assert.AreEqual(sExp, sActual); } pf.ProcedureFlows2.Add(proc, flow); return proc; }