/// <summary> /// Split a block at address <paramref name="addr" />. /// </summary> /// <param name="block"></param> /// <param name="addr"></param> /// <returns></returns> private RtlBlock SplitBlock(RtlBlock block, Address addr) { var newBlock = new RtlBlock(addr, string.Format("l{0:X}", addr)) { IsValid = block.IsValid }; sr.ICFG.Nodes.Add(newBlock); newBlock.Instructions.AddRange( block.Instructions.Where(r => r.Address >= addr).OrderBy(r => r.Address)); foreach (var de in blockMap.Where(d => d.Key >= addr && d.Value == block).ToList()) { blockMap[de.Key] = newBlock; } block.Instructions.RemoveAll(r => r.Address >= addr); var succs = sr.ICFG.Successors(block).ToArray(); foreach (var s in succs) { AddEdge(newBlock, s); RemoveEdge(block, s); } AddEdge(block, newBlock); return(newBlock); }
/// <summary> /// Build the weakly connected component for a cluster by following /// both predecessors and successors in the graph. However, we never /// follow the predecessors of nodes that are marked directly called, /// and we never follow successors that are marked directly called /// (tail calls). /// </summary> /// <param name="node"></param> /// <param name="cluster"></param> /// <param name="nodesLeft"></param> private void BuildWCC( RtlBlock node, Cluster cluster, HashSet <RtlBlock> nodesLeft) { nodesLeft.Remove(node); cluster.Blocks.Add(node); foreach (var s in sr.ICFG.Successors(node)) { if (nodesLeft.Contains(s)) { // Only add if successor is not CALLed. if (!procedures.Contains(s.Address)) { BuildWCC(s, cluster, nodesLeft); } } } if (!procedures.Contains(node.Address)) { // Only backtrack through predecessors if the node // is not CALLed. foreach (var p in sr.ICFG.Predecessors(node)) { if (nodesLeft.Contains(p)) { BuildWCC(p, cluster, nodesLeft); } } } }
private void RemoveInvalidBlocks(ScanResults sr) { var revGraph = new DiGraph <RtlBlock>(); var invalid = new RtlBlock(null, "<invalid>"); revGraph.AddNode(invalid); foreach (var b in sr.ICFG.Nodes) { revGraph.AddNode(b); } foreach (var b in sr.ICFG.Nodes) { foreach (var s in sr.ICFG.Successors(b)) { revGraph.AddEdge(s, b); } if (!b.IsValid) { revGraph.AddEdge(invalid, b); } } // Find the transitive closure of invalid nodes. var invalidNodes = new DfsIterator <RtlBlock>(revGraph) .PreOrder(invalid) .ToList(); foreach (var n in invalidNodes.Where(nn => nn != invalid)) { sr.ICFG.RemoveNode(n); sr.DirectlyCalledAddresses.Remove(n.Address); // Debug.Print("Removed invalid node {0}", n.Address); // commented out as this becomes very verbose. } }
private void AddNode(RtlBlock block) { if (!sr.ICFG.Nodes.Contains(block)) { sr.ICFG.Nodes.Add(block); } }
public SliceState(BackwardSlicer slicer, RtlBlock block, int iInstr) { this.slicer = slicer; this.block = block; this.instrs = slicer.host.GetBlockInstructions(block).ToArray(); this.iInstr = iInstr; DumpBlock(BackwardSlicer.trace.TraceVerbose); }
private void RemoveBlockFromGraph(RtlBlock n) { //Debug.Print("Removing block: {0}", n.Address); blocks.Nodes.Remove(n); foreach (var i in n.Instructions) { RemoveDirectlyCalledAddress(i); } }
public BackwardSlicer(IBackWalkHost <RtlBlock, RtlInstruction> host, RtlBlock rtlBlock, ProcessorState state) { this.host = host; this.rtlBlock = rtlBlock; this.processorState = state; this.worklist = new WorkList <SliceState>(); this.visited = new HashSet <RtlBlock>(); this.cmp = new ExpressionValueComparer(); this.simp = new ExpressionSimplifier(host.SegmentMap, new EvalCtx(), null); }
public ISet <RtlBlock> GetAncestors(RtlBlock n) { var anc = new HashSet <RtlBlock>(); foreach (var p in blocks.Predecessors(n)) { GetAncestorsAux(p, n, anc); } return(anc); }
public HeuristicScanner( IServiceProvider services, Program program, IRewriterHost host, DecompilerEventListener eventListener) { this.Services = services; this.program = program; this.host = host; this.storageBinder = program.Architecture.CreateFrame(); this.eventListener = eventListener; this.invalidBlock = new RtlBlock(null !, "<invalid>"); this.binder = program.Architecture.CreateFrame(); }
/// <summary> /// Start a slice by examining any variables in the indirect jump /// <paramref name="indirectJump"/>, then start tracing instructions /// backwards beginning at instruction <paramref name="iInstr"/> in <paramref name="block"/>. /// </summary> /// <remarks> /// Any expressions discovered in this step become the "roots" /// of the backward slice. These roots are kept in the `Live` collection. /// </remarks> /// <param name="block">Basic block of instructions.</param> /// <param name="iInstr">Index into the instructions in <paramref name="block"/>.</param> /// <param name="indirectJump">Expression containing the target of the indirect call or jump.</param> /// <returns>If backward slicing should continue.</returns> public bool Start(RtlBlock block, int iInstr, Expression indirectJump) { this.state = new SliceState(this, block, iInstr); visited.Add(block); if (state.Start(indirectJump)) { worklist.Add(state); return(true); } else { return(false); } }
private ISet <RtlBlock> GetAncestorsAux( RtlBlock n, RtlBlock orig, ISet <RtlBlock> ancestors) { if (ancestors.Contains(n) || n == orig) { return(ancestors); } ancestors.Add(n); foreach (var p in blocks.Predecessors(n)) { GetAncestorsAux(p, orig, ancestors); } return(ancestors); }
public SliceState CreateNew(RtlBlock block, Address addrSucc) { var state = new SliceState(this.slicer, block, 0) { JumpTableFormat = this.JumpTableFormat, JumpTableIndex = this.JumpTableIndex, JumpTableIndexInterval = this.JumpTableIndexInterval, Live = new Dictionary <Expression, BackwardSlicerContext>(this.Live, this.Live.Comparer), ccNext = this.ccNext, invertCondition = this.invertCondition, addrSucc = addrSucc, blockCount = blockCount + 1 }; state.iInstr = state.instrs.Length - 1; return(state); }
/// <summary> /// Build Shingle blocks from the graph. An instruction can only be /// in one block at a time, so at each point in the graph where the /// successors > 1 or the predecessors > 1, we create a new node. /// </summary> /// <param name="instructions"></param> /// <returns></returns> public IcfgBuilder BuildBlocks(DiGraph <Address> graph) { // Remember, the graph is backwards! var activeBlocks = new List <RtlBlock>(); var allBlocks = new DiGraph <RtlBlock>(); var edges = new List <Tuple <RtlBlock, Address> >(); var mpBlocks = new Dictionary <Address, RtlBlock>(); var wl = sr.Instructions.Keys.ToSortedSet(); while (wl.Count > 0) { var addr = wl.First(); wl.Remove(addr); var instr = sr.Instructions[addr]; var label = program.NamingPolicy.BlockName(addr); var block = new RtlBlock(addr, label); block.Instructions.Add(instr); allBlocks.AddNode(block); mpBlocks.Add(addr, block); bool endBlockNow = false; bool terminateDeferred = false; bool addFallthroughEdge = false; bool addFallthroughEdgeDeferred = false; for (;;) { var addrInstrEnd = instr.Address + instr.Length; if ((instr.Class & DT) != 0) { if (MayFallThrough(instr)) { addFallthroughEdge = (instr.Class & DT) == T; addFallthroughEdgeDeferred = (instr.Class & DT) == DT; } var addrDst = DestinationAddress(instr); if (addrDst != null && (instr.Class & InstrClass.Call) == 0) { edges.Add(Tuple.Create(block, addrDst)); } if ((instr.Class & DT) == DT) { terminateDeferred = true; } else { endBlockNow = true; } } else if (instr.Class == InstrClass.Terminates) { endBlockNow = true; addFallthroughEdge = false; addFallthroughEdge = false; } else { endBlockNow = terminateDeferred; addFallthroughEdge = addFallthroughEdgeDeferred; addFallthroughEdgeDeferred = false; } if (sr.DirectlyCalledAddresses.Keys.Contains(addrInstrEnd) || sr.KnownProcedures.Contains(addrInstrEnd)) { // If control falls into what looks like a procedure, don't // add an edge. addFallthroughEdge = false; endBlockNow = true; } if (addFallthroughEdge) { edges.Add(Tuple.Create(block, addrInstrEnd)); } if (endBlockNow || !wl.Contains(addrInstrEnd) || !graph.Nodes.Contains(addrInstrEnd) || graph.Successors(addrInstrEnd).Count != 1) { //Debug.Print("addr: {0}, end {1}, term: {2}, wl: {3}, nodes: {4}, succ: {5}", // addr, // addrInstrEnd, // endBlockNow, // !wl.Contains(addrInstrEnd), // !graph.Nodes.Contains(addrInstrEnd), // graph.Nodes.Contains(addrInstrEnd) // ? graph.Successors(addrInstrEnd).Count // : 0); if (!endBlockNow && !addFallthroughEdge) { edges.Add(Tuple.Create(block, addrInstrEnd)); } break; } wl.Remove(addrInstrEnd); instr = sr.Instructions[addrInstrEnd]; block.Instructions.Add(instr); endBlockNow = terminateDeferred; } } return(new IcfgBuilder { Edges = edges, AddrToBlock = mpBlocks, Blocks = allBlocks, }); }
/// <summary> /// Recursively disassembles the range of addresses. /// <paramref name="proc"/>. /// </summary> /// <param name="addr"></param> /// <param name="proc"></param> /// <returns></returns> public RtlBlock Disassemble(Address addr) { var current = new RtlBlock(addr, string.Format("l{0:X}", addr)); var dasm = program.Architecture.CreateRewriter( program.CreateImageReader(addr), program.Architecture.CreateProcessorState(), //$TODO: use state from user. binder, host); foreach (var instr in dasm.TakeWhile(i => isAddrValid(i.Address))) { RtlBlock block; if (blockMap.TryGetValue(instr.Address, out block)) { // This instruction was already disassembled before. if (instr.Address.ToLinear() != block.Address.ToLinear()) { block = SplitBlock(block, instr.Address); } if (current.Instructions.Count == 0) { // Coincides exactly, return the old block. return(block); } else { // Fell into 'block' while disassembling // 'current'. Create a fall-though edge if (!sr.ICFG.Nodes.Contains(current)) { AddNode(current); } AddEdge(current, block); return(current); } } else { // Fresh instruction AddNode(current); current.Instructions.Add(instr); blockMap.Add(instr.Address, current); Address addrOp; switch (instr.Class) { case RtlClass.Invalid: case RtlClass.None: current.IsValid = false; return(current); case RtlClass.Linear: case RtlClass.Linear | RtlClass.Conditional: if (FallthroughToInvalid(instr)) { current.IsValid = false; return(current); } break; case RtlClass.Transfer | RtlClass.Call: addrOp = DestinationAddress(instr); if (addrOp != null) { if (program.SegmentMap.IsValidAddress(addrOp)) { int c; if (!sr.DirectlyCalledAddresses.TryGetValue(addrOp, out c)) { c = 0; } sr.DirectlyCalledAddresses[addrOp] = c + 1; } else { current.IsValid = false; } } if (FallthroughToInvalid(instr)) { current.IsValid = false; return(current); } // If assume calls terminate, stop scanning. if (assumeCallsDiverge) { return(current); } block = Disassemble(instr.Address + instr.Length); AddEdge(current, block); return(current); case RtlClass.Transfer: addrOp = DestinationAddress(instr); if (addrOp != null) { if (isAddrValid(addrOp)) { block = Disassemble(addrOp); AddEdge(current, block); return(current); } else { // Very verbose debugging statement disabled to speed up Reko. //Debug.Print("{0} jumps to invalid address", instr.Address); current.IsValid = false; } return(current); } return(current); case RtlClass.Transfer | RtlClass.Conditional: FallthroughToInvalid(instr); addrOp = DestinationAddress(instr); if (addrOp != null && program.SegmentMap.IsValidAddress(addrOp)) { block = Disassemble(addrOp); Debug.Assert(sr.ICFG.Nodes.Contains(block)); AddEdge(current, block); } block = Disassemble(instr.Address + instr.Length); AddEdge(current, block); return(current); default: throw new NotImplementedException( string.Format( "RTL class {0}.", instr.Class)); } } } AddNode(current); return(current); }
private void RemoveEdge(RtlBlock from, RtlBlock to) { sr.ICFG.RemoveEdge(from, to); }
private void AddEdge(RtlBlock from, RtlBlock to) { sr.ICFG.AddEdge(from, to); }
public RtlProcedure(RtlBlock entry, ISet <RtlBlock> blocks) { this.Entry = entry; this.Blocks = blocks; }
/// <summary> /// Splits a multiple entry cluster into separate sub-clusters by /// partitioning all the blocks into subsets where each subset is /// dominated by one of the original entries. /// </summary> /// <remarks> /// Many binaries contain cross-procedure jumps. If the target of /// those jumps is a single block with no successors, it is very /// likely an instance of a "shared exit node" pattern that many /// compilers+linkers emit. We handle that case separately. /// </remarks> /// <param name="cluster"></param> /// <returns></returns> public List <RtlProcedure> PartitionIntoSubclusters(Cluster cluster) { // Create a fake node that will serve as the parent of all the // existing entries. That node will be used to compute all // immediate dominators of all reachable blocks. var auxNode = new RtlBlock(null, "<root>"); sr.ICFG.AddNode(auxNode); var allEntries = cluster.Entries.Concat( cluster.Blocks .Where(b => sr.ICFG.Predecessors(b).Count == 0)) .Distinct() .OrderBy(b => b.Address) .ToList(); foreach (var entry in allEntries) { sr.ICFG.AddEdge(auxNode, entry); } var idoms = LTDominatorGraph <RtlBlock> .Create(sr.ICFG, auxNode); // DumpDominatorTrees(idoms); // Find all nodes whose immediate dominator is "<root>". // Those are the entries to new clusters and may contain blocks // that are shared between procedures in the source program. var newEntries = cluster.Blocks.Where(b => idoms[b] == auxNode).ToList(); var dominatedEntries = newEntries.ToDictionary(k => k, v => new HashSet <RtlBlock> { v }); // Partition the nodes in the cluster into categories depending on which // one of the newEntries they are dominated by. foreach (var b in cluster.Blocks) { if (dominatedEntries.ContainsKey(b)) { continue; // already there. } var n = b; for (;;) { var i = idoms[n]; if (i == null) { break; } if (dominatedEntries.ContainsKey(i)) { // If my idom is already in the set, add me too. dominatedEntries[i].Add(b); break; } n = i; } } // Now remove the fake node sr.ICFG.RemoveNode(auxNode); // Handle the special case with new entries that weren't there before, // and only consist of a linear sequence of blocks. Mark such nodes as "shared". // Later stages will copy these nodes into their respective procedures. foreach (var newEntry in dominatedEntries.Keys .Where(e => !cluster.Entries.Contains(e)).ToList()) { if (sr.ICFG.Successors(newEntry).Count == 0) { newEntry.IsSharedExitBlock = true; dominatedEntries.Remove(newEntry); } } return(dominatedEntries .OrderBy(e => e.Key.Address) .Select(e => new RtlProcedure(e.Key, e.Value)) .ToList()); }
/// <summary> /// Starting at <paramref name="start"/> /// </summary> /// <param name="start"></param> /// <returns></returns> public List <RtlBlock> LinearSequence(RtlBlock start) { return(new List <RtlBlock>()); }
private void RemoveBlockFromGraph(RtlBlock n) { //Debug.Print("Removing block: {0}", n.Address); blocks.Nodes.Remove(n); }