public static void Rewrite( IPlatform platform, List <SsaTransform> ssts, ProgramDataFlow summaries, DecompilerEventListener eventListener) { CallRewriter crw = new CallRewriter(platform, summaries, eventListener); foreach (SsaTransform sst in ssts) { if (eventListener.IsCanceled()) { return; } var proc = sst.SsaState.Procedure; ProcedureFlow flow = crw.mpprocflow[proc]; flow.Dump(proc.Architecture); crw.EnsureSignature(sst.SsaState, proc.Frame, flow); } foreach (SsaTransform sst in ssts) { if (eventListener.IsCanceled()) { return; } crw.RewriteCalls(sst.SsaState); crw.RewriteReturns(sst.SsaState); crw.RemoveStatementsFromExitBlock(sst.SsaState); } }
public static void Rewrite( Program program, ProgramDataFlow summaries, DecompilerEventListener eventListener) { GlobalCallRewriter crw = new GlobalCallRewriter(program, summaries, eventListener); foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { return; } ProcedureFlow flow = crw.mpprocflow[proc]; flow.Dump(proc.Architecture); crw.AdjustLiveOut(flow); crw.EnsureSignature(proc, flow); crw.AddUseInstructionsForOutArguments(proc); } foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { return; } crw.RewriteCalls(proc); crw.RewriteReturns(proc); } }
public void Transform() { var ppr = new PtrPrimitiveReplacer(factory, store, program, eventListener); ppr.ReplaceAll(); var cpa = new ConstantPointerAnalysis(factory, store, program); cpa.FollowConstantPointers(); int iteration = 0; do { if (eventListener.IsCanceled()) { return; } ++iteration; if (iteration > 50) { eventListener.Warn( string.Format("Type transformer has looped {0} times, quitting prematurely.", iteration)); return; } Changed = false; visitedTypes.Clear(); foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) { return; } EquivalenceClass eq = tv.Class; if (eq.DataType != null) { DateTime start = DateTime.Now; eq.DataType = eq.DataType.Accept(this); DateTime end = DateTime.Now; if (eq.DataType is UnionType ut) { //trace.Verbose("= TT: took {2,4} msec to simplify {0} ({1})", tv.DataType, eq.DataType, (end - start).Milliseconds); } } if (tv.DataType != null) { tv.DataType = tv.DataType.Accept(this); } // Debug.Print("Transformed {0}:{1}", tv, tv.Class.DataType); } if (ppr.ReplaceAll()) { Changed = true; } if (NestedComplexTypeExtractor.ReplaceAll(factory, store)) { Changed = true; } } while (Changed); }
/// <summary> /// First find use of stack pointer at procedure exit block. /// Check if its definition is like 'sp_at_exit = sp_previous + offset' /// and 'sp_previous' is trashed (usually after indirect calls). We /// assume that stack pointer at the end ('sp_at_exit') is 'fp'. So /// 'sp_previous' is 'fp - offset'. So we replace definition of /// 'sp_previous' with 'fp - offset' /// </summary> public void BackpropagateStackPointer() { foreach (var spAtExit in FindStackUsesAtExit(ssa.Procedure)) { if (listener.IsCanceled()) return; BackpropagateStackPointer(spAtExit); } }
public void Transform() { foreach (var block in ssa.Procedure.ControlGraph.Blocks) { if (listener.IsCanceled()) return; ReplaceLongAdditions(block); } }
/// <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; }
public void Transform() { var ppr = new PtrPrimitiveReplacer(factory, store, program); ppr.ReplaceAll(eventListener); var cpa = new ConstantPointerAnalysis(factory, store, program); cpa.FollowConstantPointers(); int iteration = 0; do { if (eventListener.IsCanceled()) { return; } ++iteration; if (iteration > 50) { eventListener.Warn(new NullCodeLocation(""), string.Format("Type transformer has looped {0} times, quitting prematurely.", iteration)); return; } Changed = false; this.visitedTypes = new HashSet <DataType>(); foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) { return; } tvCur = tv; EquivalenceClass eq = tv.Class; if (eq.DataType != null) { eq.DataType = eq.DataType.Accept(this); } if (tv.DataType != null) { tv.DataType = tv.DataType.Accept(this); } // Debug.Print("Transformed {0}:{1}", tv, tv.Class.DataType); } if (ppr.ReplaceAll(eventListener)) { Changed = true; } if (NestedComplexTypeExtractor.ReplaceAll(factory, store)) { Changed = true; } } while (Changed); }
/// <summary> /// Computes intraprocedural liveness of the program <paramref name="p"/>, /// storing the results in <paramref name="procFlow"/>. /// </summary> /// <param name="p"></param> /// <param name="procFlow"></param> /// <returns></returns> public static RegisterLiveness Compute( Program p, ProgramDataFlow procFlow, DecompilerEventListener eventListener) { var live = new RegisterLiveness(p, procFlow, eventListener); Debug.WriteLineIf(trace.TraceError, "** Computing ByPass ****"); live.CurrentState = new ByPassState(p.Architecture); live.ProcessWorklist(); if (eventListener.IsCanceled()) { return(live); } Debug.WriteLineIf(trace.TraceError, "** Computing MayUse ****"); live.CurrentState = new MayUseState(); if (trace.TraceInfo) { live.Dump(); } live.ProcessWorklist(); if (eventListener.IsCanceled()) { return(live); } //$REVIEW: since we never use the liveinstate, can we get rid of the following // four statements? Debug.WriteLineIf(trace.TraceError, "** Computing LiveIn ****"); live.CurrentState = new LiveInState(); if (trace.TraceInfo) { live.Dump(); } live.ProcessWorklist(); if (eventListener.IsCanceled()) { return(live); } live.CompleteWork(); if (trace.TraceInfo) { live.Dump(); } return(live); }
public void RewriteProgram(Program program) { foreach (Procedure proc in program.Procedures.Values) { if (proc.Name == "register_tm_clones") //$DEBUG { proc.ToString(); } RewriteFormals(proc.Signature); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } try { stm.Instruction = stm.Instruction.Accept(this); } catch (Exception ex) { Debug.WriteLine( string.Format("Exception in TypedExpressionRewriter.RewriteProgram: {0} ({1})\r\n{2}", proc, ex.Message, ex.StackTrace)); // reset flags after error dereferenced = false; } } } }
public void CollectTypes() { CollectGlobalType(); CollectUserGlobalVariableTypes(); CollectImageSymbols(); int cProc = program.Procedures.Count; int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Collecting data types.", i++, cProc); CollectProcedureSignature(proc); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } try { this.stmCur = stm; stm.Instruction.Accept(this); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "An error occurred while processing the statement {0}.", stm); } } } }
public void CollectTypes() { desc.MeetDataType(program.Globals, factory.CreatePointer( factory.CreateStructureType(), program.Platform.PointerType.BitSize)); CollectUserGlobalVariableTypes(store.SegmentTypes); int cProc = program.Procedures.Count; int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Collecting data types.", i++, cProc); CollectProcedureSignature(proc); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } try { this.stmCur = stm; stm.Instruction.Accept(this); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "An error occurred while processing the statement {0}.", stm); } } } }
public void Transform() { SetInitialValues(); var wl = new WorkList <SsaIdentifier>(); wl.AddRange(ssa.Identifiers); while (wl.TryGetWorkItem(out var sid) && !listener.IsCanceled()) { var oldValue = ctx.GetValue(sid.Identifier); if (oldValue is InvalidConstant) { continue; } var newValue = Evaluate(sid); if (!cmp.Equals(oldValue, newValue)) { ctx.SetValue(sid.Identifier, newValue); foreach (var use in sid.Uses) { var uc = new InstructionUseCollector(); var uses = uc.CollectUses(use); wl.AddRange(uses.Keys.Select(id => ssa.Identifiers[id])); } } } }
public void CollectTypes() { desc.MeetDataType(program.Globals, factory.CreatePointer( factory.CreateStructureType(), program.Platform.PointerType.Size)); CollectSegmentTypes(); foreach (Procedure p in program.Procedures.Values) { proc = p; CollectProcedureSignature(p); foreach (Statement stm in p.Statements) { if (eventListener.IsCanceled()) { return; } try { stm.Instruction.Accept(this); } catch (Exception ex) { eventListener.Error( eventListener.CreateStatementNavigator(program, stm), ex, "An error occurred while processing the statement {0}.", stm); } } } }
public void RewriteProgram(Program program) { int cProc = program.Procedures.Count; int i = 0; foreach (Procedure proc in program.Procedures.Values) { eventListener.ShowProgress("Rewriting expressions.", i++, cProc); RewriteFormals(proc.Signature); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } try { stm.Instruction = stm.Instruction.Accept(this); } catch (Exception ex) { Debug.WriteLine( string.Format("Exception in TypedExpressionRewriter.RewriteProgram: {0} ({1})\r\n{2}", proc, ex.Message, ex.StackTrace)); // reset flags after error dereferenced = false; } } } }
/// <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) { 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."); } } WriteDecompilerProducts(); } eventListener.ShowStatus("Rewriting complete."); }
protected void ProcessQueue() { while (procQueue.Count > 0) { if (eventListener.IsCanceled()) { break; } var workitem = procQueue.Dequeue(); try { workitem.Process(); } catch (AddressCorrelatedException aex) { Error(aex.Address, "{0}", aex.Message); } catch (Exception ex) { Error(workitem.Address, "{0}", ex.Message); } if (cancelSvc != null && cancelSvc.IsCancellationRequested) { break; } } }
public void Build(Program program) { // Special case for the global variables. In essence, // a memory map of all the globals. var tvGlobals = store.EnsureExpressionTypeVariable(factory, program.Globals, "globals_t"); tvGlobals.OriginalDataType = program.Globals.DataType; EnsureSegmentTypeVariables(program.SegmentMap.Segments.Values); int cProc = program.Procedures.Count; int i = 0; foreach (Procedure proc in program.Procedures.Values) { if (listener.IsCanceled()) { return; } listener.ShowProgress("Gathering primitive datatypes from instructions.", i++, cProc); this.signature = proc.Signature; EnsureSignatureTypeVariables(this.signature); foreach (Statement stm in proc.Statements) { stmCur = stm; stm.Instruction.Accept(this); } } }
public void RewriteProgram(Program program) { foreach (Procedure proc in program.Procedures.Values) { RewriteFormals(proc.Signature); foreach (Statement stm in proc.Statements) { if (eventListener.IsCanceled()) { return; } Debug.Print("{0:X8} {1}", stm.LinearAddress, stm.Instruction); try { stm.Instruction = stm.Instruction.Accept(this); } catch (Exception ex) { Debug.WriteLine( string.Format("Exception in TypedExpressionRewriter.RewriteProgram: {0} ({1})\r\n{2}", proc, ex.Message, ex.StackTrace)); // reset flags after error dereferenced = false; } } } }
/// <summary> /// For each procedure, either use a user-supplied signature, /// or the predefined one. /// </summary> public void BuildSignatures(DecompilerEventListener listener) { foreach (var de in program.Procedures) { if (listener.IsCanceled()) break; BuildSignature(de.Key, de.Value); } }
/// <summary> /// Remove any links between nodes where the destination is /// a known call target. /// </summary> public void RemoveJumpsToKnownProcedures() { foreach (var calldest in this.procedures) { if (listener.IsCanceled()) { break; } if (!mpAddrToBlock.TryGetValue(calldest, out var node)) { continue; } var preds = sr.ICFG.Predecessors(node).ToList(); foreach (var p in preds) { sr.ICFG.RemoveEdge(p, node); } } }
/// <summary> /// For each procedure, either use a user-supplied signature, /// or the predefined one. /// </summary> public void BuildSignatures(DecompilerEventListener listener) { foreach (var de in program.Procedures) { if (listener.IsCanceled()) { break; } BuildSignature(de.Key, de.Value); } }
public static void Rewrite(Program program, DecompilerEventListener listener) { var crw = new CallRewriter(program); foreach (Procedure proc in program.Procedures.Values) { if (listener.IsCanceled()) break; crw.RewriteCalls(proc); crw.RewriteReturns(proc); } }
public static void Transform(Program program, DecompilerEventListener eventListener) { foreach (var proc in program.Procedures.Values) { if (eventListener.IsCanceled()) { return; } var abc = new AdjacentBranchCollector(proc, eventListener); abc.Transform(); } }
public static void Apply(Program program, DecompilerEventListener eventListener) { foreach (var block in program.Procedures.Values.SelectMany(p => p.ControlGraph.Blocks)) { if (eventListener.IsCanceled()) { break; } var ibdr = new IntraBlockDeadRegisters(); ibdr.Apply(block); } }
public void ProcessQueue() { while (queue.Count > 0) { if (listener.IsCanceled()) { return; } var wi = queue.Dequeue(); wi.Process(); } }
public void Transform() { // Find all blocks which end in branches whose conditional expression is constant. var constBranchBlocks = ssa.Procedure.ControlGraph.Blocks.Where(HasConstantBranch).ToHashSet(); if (constBranchBlocks.Count == 0) { return; } // Determine which blocks are unreachable based on the constant branches. var unreachableBlocks = constBranchBlocks.Select(UnreachableBlock).ToHashSet(); // Traverse the CFG of the procedure but don't enter unreachable blocks. var reachedBlocks = TraverseCfg(ssa.Procedure.EntryBlock, unreachableBlocks, new HashSet <Block>()); if (listener.IsCanceled()) { return; } // Compute the dead blocks. var deadBlocks = ssa.Procedure.ControlGraph.Blocks.Except(reachedBlocks).ToHashSet(); RemoveConstBranches(constBranchBlocks); if (listener.IsCanceled()) { return; } RemoveDeadBlocks(deadBlocks); if (listener.IsCanceled()) { return; } }
public static void Rewrite(Program program, DecompilerEventListener listener) { var crw = new CallRewriter(program); foreach (Procedure proc in program.Procedures.Values) { if (listener.IsCanceled()) { break; } crw.RewriteCalls(proc); crw.RewriteReturns(proc); } }
public void Transform() { do { //$PERFORMANCE: consider changing this to a work list, where // every time we process the Changed = false; foreach (Statement stm in ssa.Procedure.Statements.ToArray()) { if (eventListener.IsCanceled()) { return; } this.stmCur = stm; Transform(stm); } } while (Changed); }
public void Transform() { var wl = new WorkList <Block>(proc.ControlGraph.Blocks); while (wl.GetWorkItem(out Block block)) { if (listener.IsCanceled()) { return; } var c = DetermineCandidate(block); if (c == null) { continue; } FuseIntoPredecessor(c); // We may need to mutate the predecessor again. wl.Add(c.Predecessor); } }
public void Transform() { CollectLiveOutStorages(); DumpLiveOut(); bool change; do { if (eventListener.IsCanceled()) { return; } change = false; this.wl.AddRange(ssaStates); while (wl.TryGetWorkItem(out SsaState ssa)) { if (this.eventListener.IsCanceled()) { return; } var vp = new ValuePropagator(program.SegmentMap, ssa, program.CallGraph, dynamicLinker, eventListener); vp.Transform(); change |= RemoveUnusedDefinedValues(ssa, wl); //DataFlowAnalysis.DumpWatchedProcedure("After RemoveUnusedDefinedValues", ssa.Procedure); change |= RemoveLiveInStorages(ssa.Procedure, dataFlow[ssa.Procedure], wl); //DataFlowAnalysis.DumpWatchedProcedure("After RemoveLiveInStorages", ssa.Procedure); } } while (change); foreach (var proc in procToSsa.Keys) { var liveOut = CollectLiveOutStorages(proc); var flow = this.dataFlow[proc]; flow.BitsLiveOut = SummarizeStorageBitranges(flow.BitsLiveOut.Concat(liveOut)); flow.grfLiveOut = SummarizeFlagGroups(liveOut); } }
public static void Rewrite( Program program, ProgramDataFlow summaries, DecompilerEventListener eventListener) { GlobalCallRewriter crw = new GlobalCallRewriter(program, summaries, eventListener); foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) return; ProcedureFlow flow = crw.mpprocflow[proc]; flow.Dump(program.Architecture); crw.AdjustLiveOut(flow); crw.EnsureSignature(proc, flow); crw.AddUseInstructionsForOutArguments(proc); } foreach (Procedure proc in program.Procedures.Values) { if (eventListener.IsCanceled()) return; crw.RewriteCalls(proc); crw.RewriteReturns(proc); } }
public bool ReplaceAll(DecompilerEventListener eventListener) { changed = false; classesVisited = new HashSet <EquivalenceClass>(); this.eventListener = eventListener; // Replace the DataType of all the equivalence classes foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) { return(false); } EquivalenceClass eq = tv.Class; if (!classesVisited.Contains(eq)) { classesVisited.Add(eq); var dt = Replace(eq.DataType); eq.DataType = dt; } } // Replace the DataType of all the TypeVariables foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) { return(false); } tv.DataType = Replace(tv.DataType); } foreach (EquivalenceClass eq in classesVisited) { if (eventListener.IsCanceled()) { return(false); } if (eq != program.Globals.TypeVariable.Class && (eq.DataType is PrimitiveType || eq.DataType is VoidType || eq.DataType is EquivalenceClass || eq.DataType is CodeType)) { eq.DataType = null; changed = true; continue; } Pointer ptr = eq.DataType as Pointer; if (ptr != null) { eq.DataType = ptr.Pointee; changed = true; continue; } MemberPointer mp = eq.DataType as MemberPointer; if (mp != null) { eq.DataType = mp.Pointee; changed = true; } ArrayType array = eq.DataType as ArrayType; if (array != null) { eq.DataType = array.ElementType; changed = true; } } return(changed); }
public bool ReplaceAll() { changed = false; classesVisited.Clear(); // Replace the DataType of all the equivalence classes foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) { return(false); } EquivalenceClass eq = tv.Class; if (!classesVisited.Contains(eq)) { classesVisited.Add(eq); var dt = Replace(eq.DataType); eq.DataType = dt !; } } // Replace the DataType of all the TypeVariables foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) { return(false); } tv.DataType = Replace(tv.DataType) !; } foreach (EquivalenceClass eq in classesVisited) { if (eventListener.IsCanceled()) { return(false); } if (eq != program.Globals.TypeVariable !.Class && (eq.DataType is PrimitiveType || eq.DataType is VoidType || eq.DataType is EquivalenceClass || eq.DataType is CodeType)) { eq.DataType = null !; changed = true; continue; } if (eq.DataType is Pointer ptr) { eq.DataType = ptr.Pointee; changed = true; continue; } if (eq.DataType is MemberPointer mp) { eq.DataType = mp.Pointee; changed = true; } if (eq.DataType is ArrayType array) { eq.DataType = array.ElementType; changed = true; } } return(changed); }
public bool ReplaceAll(DecompilerEventListener eventListener) { changed = false; classesVisited = new HashSet<EquivalenceClass>(); // Replace the DataType of all the equivalence classes foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) return false; EquivalenceClass eq = tv.Class; if (!classesVisited.Contains(eq)) { classesVisited.Add(eq); var dt = Replace(eq.DataType); eq.DataType = dt; } } // Replace the DataType of all the TypeVariables foreach (TypeVariable tv in store.TypeVariables) { if (eventListener.IsCanceled()) return false; tv.DataType = Replace(tv.DataType); } foreach (EquivalenceClass eq in classesVisited) { if (eventListener.IsCanceled()) return false; if (eq != program.Globals.TypeVariable.Class && (eq.DataType is PrimitiveType || eq.DataType is VoidType || eq.DataType is EquivalenceClass || eq.DataType is CodeType)) { eq.DataType = null; changed = true; continue; } Pointer ptr = eq.DataType as Pointer; if (ptr != null) { eq.DataType = ptr.Pointee; changed = true; continue; } MemberPointer mp = eq.DataType as MemberPointer; if (mp != null) { eq.DataType = mp.Pointee; changed = true; } ArrayType array = eq.DataType as ArrayType; if (array != null) { eq.DataType = array.ElementType; changed = true; } } return changed; }