/// <summary> /// Remove any UseInstructions in the exit block of the procedure that /// can be proved to be dead out. /// </summary> /// <param name="ssa">SSA of the procedure whose exit block is to be examined.</param> /// <param name="wl">Worklist of SSA states.</param> /// <returns>True if any change was made to SSA.</returns> public bool RemoveUnusedDefinedValues(SsaState ssa, WorkList <SsaState> wl) { bool change = false; trace.Verbose("UVR: {0}", ssa.Procedure.Name); var(deadStms, deadStgs) = FindDeadStatementsInExitBlock(ssa, this.dataFlow[ssa.Procedure].BitsLiveOut); // Remove 'use' statements that are known to be dead from the exit block. foreach (var stm in deadStms) { trace.Verbose("UVR: {0}, deleting {1}", ssa.Procedure.Name, stm.Instruction); ssa.DeleteStatement(stm); change = true; } // If any instructions were removed, update the callers. if (!ssa.Procedure.Signature.ParametersValid && deadStms.Count > 0) { DeadCode.Eliminate(ssa); foreach (Statement stm in program.CallGraph.CallerStatements(ssa.Procedure)) { if (!(stm.Instruction is CallInstruction ci)) { continue; } var ssaCaller = this.procToSsa[stm.Block.Procedure]; if (RemoveDeadCallDefinitions(ssaCaller, ci, deadStgs)) { wl.Add(ssaCaller); } } } return(change); }
/// <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> /// This callback is called from the SccFinder, which passes it a list /// of Procedures that form a SCC. /// </summary> /// <param name="procs"></param> private void UntangleProcedureScc(IList <Procedure> procs) { this.sccProcs = procs.ToHashSet(); flow.CreateFlowsFor(procs); // Convert all procedures in the SCC to SSA form and perform // value propagation. var ssts = procs.Select(ConvertToSsa).ToArray(); this.ssts.AddRange(ssts); DumpWatchedProcedure("After extra stack vars", ssts); // At this point, the computation of ProcedureFlow is possible. var trf = new TrashedRegisterFinder(program, flow, ssts, this.eventListener); trf.Compute(); // New stack based variables may be available now. foreach (var sst in ssts) { var vp = new ValuePropagator(program.SegmentMap, sst.SsaState, program.CallGraph, dynamicLinker, this.eventListener); vp.Transform(); sst.RenameFrameAccesses = true; sst.Transform(); DumpWatchedProcedure("After extra stack vars", sst.SsaState.Procedure); } foreach (var ssa in ssts.Select(sst => sst.SsaState)) { RemoveImplicitRegistersFromHellNodes(ssa); var sac = new SegmentedAccessClassifier(ssa); sac.Classify(); var prj = new ProjectionPropagator(ssa, sac); prj.Transform(); DumpWatchedProcedure("After projection propagation", ssa.Procedure); } var uid = new UsedRegisterFinder(flow, procs, this.eventListener); foreach (var sst in ssts) { var ssa = sst.SsaState; RemovePreservedUseInstructions(ssa); DeadCode.Eliminate(ssa); uid.ComputeLiveIn(ssa, true); var procFlow = flow[ssa.Procedure]; RemoveDeadArgumentsFromCalls(ssa.Procedure, procFlow, ssts); DumpWatchedProcedure("After dead call argument removal", ssa.Procedure); } eventListener.Advance(procs.Count); }
/// <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() { int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Building complex expressions.", i, program.Procedures.Values.Count); ++i; try { var larw = new LongAddRewriter(proc, program.Architecture); larw.Transform(); Aliases alias = new Aliases(proc, program.Architecture, flow); alias.Transform(); var doms = new DominatorGraph <Block>(proc.ControlGraph, proc.EntryBlock); var sst = new SsaTransform(flow, proc, importResolver, doms); var ssa = sst.SsaState; var cce = new ConditionCodeEliminator(ssa.Identifiers, program.Platform); cce.Transform(); //var cd = new ConstDivisionImplementedByMultiplication(ssa); //cd.Transform(); DeadCode.Eliminate(proc, ssa); var vp = new ValuePropagator(program.Architecture, ssa.Identifiers, proc); vp.Transform(); 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 (KeyValuePair <LinearInductionVariable, LinearInductionVariableContext> de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } 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); } catch (StatementCorrelatedException stex) { eventListener.Error( eventListener.CreateBlockNavigator(program, stex.Statement.Block), stex, "An error occurred during data flow analysis."); } catch (Exception ex) { eventListener.Error( new NullCodeLocation(proc.Name), ex, "An error occurred during data flow analysis."); } } }
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, importResolver, 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(program.Architecture, 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(); } //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 { throw new NotImplementedException(); } }
/// <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() { int i = 0; foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { break; } eventListener.ShowProgress("Building complex expressions.", i, program.Procedures.Values.Count); ++i; try { var sst = BuildSsaTransform(proc); var ssa = sst.SsaState; var fuser = new UnalignedMemoryAccessFuser(ssa); fuser.Transform(); var vp = new ValuePropagator(program.SegmentMap, ssa, importResolver, eventListener); sst.RenameFrameAccesses = true; var icrw = new IndirectCallRewriter(program, ssa, eventListener); while (!eventListener.IsCanceled() && icrw.Rewrite()) { vp.Transform(); sst.Transform(); } var cce = new ConditionCodeEliminator(ssa, program.Platform); cce.Transform(); //var cd = new ConstDivisionImplementedByMultiplication(ssa); //cd.Transform(); DeadCode.Eliminate(proc, ssa); vp.Transform(); 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); vp.Transform(); var liv = new LinearInductionVariableFinder( proc, ssa.Identifiers, new BlockDominatorGraph(proc.ControlGraph, proc.EntryBlock)); liv.Find(); foreach (KeyValuePair <LinearInductionVariable, LinearInductionVariableContext> de in liv.Contexts) { var str = new StrengthReduction(ssa, de.Key, de.Value); str.ClassifyUses(); str.ModifyUses(); } 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); } catch (StatementCorrelatedException stex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stex.Statement), stex, "An error occurred during data flow analysis."); } catch (Exception ex) { eventListener.Error( new NullCodeLocation(proc.Name), ex, "An error occurred during data flow analysis."); } } }
/// <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); } }