Exemple #1
0
        /// <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);
        }
Exemple #2
0
 /// <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);
             }
         }
     }
 }
Exemple #3
0
        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.
            }
        }
Exemple #4
0
 private void AddNode(RtlBlock block)
 {
     if (!sr.ICFG.Nodes.Contains(block))
     {
         sr.ICFG.Nodes.Add(block);
     }
 }
Exemple #5
0
 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);
     }
 }
Exemple #7
0
 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);
 }
Exemple #8
0
        public ISet <RtlBlock> GetAncestors(RtlBlock n)
        {
            var anc = new HashSet <RtlBlock>();

            foreach (var p in blocks.Predecessors(n))
            {
                GetAncestorsAux(p, n, anc);
            }
            return(anc);
        }
Exemple #9
0
 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();
 }
Exemple #10
0
 /// <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);
     }
 }
Exemple #11
0
 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);
 }
Exemple #12
0
        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);
        }
Exemple #13
0
        /// <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,
            });
        }
Exemple #14
0
        /// <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);
        }
Exemple #15
0
 private void RemoveEdge(RtlBlock from, RtlBlock to)
 {
     sr.ICFG.RemoveEdge(from, to);
 }
Exemple #16
0
 private void AddEdge(RtlBlock from, RtlBlock to)
 {
     sr.ICFG.AddEdge(from, to);
 }
Exemple #17
0
 public RtlProcedure(RtlBlock entry, ISet <RtlBlock> blocks)
 {
     this.Entry  = entry;
     this.Blocks = blocks;
 }
Exemple #18
0
        /// <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());
        }
Exemple #19
0
 /// <summary>
 /// Starting at <paramref name="start"/>
 /// </summary>
 /// <param name="start"></param>
 /// <returns></returns>
 public List <RtlBlock> LinearSequence(RtlBlock start)
 {
     return(new List <RtlBlock>());
 }
Exemple #20
0
 private void RemoveBlockFromGraph(RtlBlock n)
 {
     //Debug.Print("Removing block: {0}", n.Address);
     blocks.Nodes.Remove(n);
 }