Esempio n. 1
0
        /// <summary>Make sure there is a block boundary at the given method offset. If no
        /// split the block hosting the instruction at this offset in two separate blocks.
        /// </summary>
        /// <param name="startNode">Start node for the tree to be considered.</param>
        /// <param name="methodOffset">Offset to be considered.</param>
        internal static void EnsureBlockBoundary(CfgNode startNode, uint methodOffset)
        {
            BlockNode hostingNode = startNode.FindHostingNode(methodOffset, 1);

            if (null == hostingNode) { throw new REException(); }
            if (hostingNode.FirstCoveredOffset == methodOffset) { return; }
            hostingNode.Split(methodOffset);
            return;
        }
Esempio n. 2
0
        /// <summary></summary>
        /// <param name="method"></param>
        /// <param name="rootAstNode"></param>
        /// <returns></returns>
        internal static CfgNode BuildBasicTree(IMethod method, DalvikInstruction[] instructions,
            #if DBGCFG
            bool debugMethodCfg = false
            #endif
            )
        {
            CfgNode result =
            #if DBGCFG
                new CfgNode(debugMethodCfg);
            #else
                new CfgNode();
            #endif

            CreateBasicBlocks(result, method, instructions);
            EnsureExitNodeUniqueness(result);
            #if DBGCFG
            if (debugMethodCfg) { result.DumpGraph(); }
            #endif
            return result;
        }
Esempio n. 3
0
 /// <summary>Make sure the given parameter is not a null reference and
 /// at the same time is an entry node, otherwise throw an exception.</summary>
 /// <param name="entryNode">Candidate entry node.</param>
 private static void AssertEntryNodeParameter(CfgNode entryNode)
 {
     if (null == entryNode) { throw new ArgumentNullException(); }
     if (!entryNode.IsEntryNode) { throw new ArgumentException(); }
     return;
 }
Esempio n. 4
0
        /// <summary>Enumerate all node starting from the given entryNode in no
        /// particular order.</summary>
        /// <param name="entryNode">The entry node from the graph to be walked.</param>
        /// <returns>A node enumerable object.</returns>
        private static IEnumerable<CfgNode> EnumerateAllNodes(CfgNode entryNode)
        {
            AssertEntryNodeParameter(entryNode);
            List<CfgNode> pendingNodes = new List<CfgNode>();
            List<CfgNode> alreadyWalked = new List<CfgNode>();
            pendingNodes.Add(entryNode);

            while (0 < pendingNodes.Count) {
                CfgNode candidate = pendingNodes[0];
                pendingNodes.RemoveAt(0);
                if (alreadyWalked.Contains(candidate)) { continue; }
                yield return candidate;
                alreadyWalked.Add(candidate);
                if (null == candidate.Successors) { continue; }
                foreach (CfgNode targetNode in candidate.Successors) {
                    if (alreadyWalked.Contains(targetNode)) { continue; }
                    if (pendingNodes.Contains(targetNode)) { continue; }
                    pendingNodes.Add(targetNode);
                }
            }
        }
Esempio n. 5
0
        /// <summary>Make sure there is a single exit node in the graph whose start
        /// node is provided. This may lead to the creation of a new exit node.
        /// </summary>
        /// <param name="entryNode">The graph entry node.</param>
        private static void EnsureExitNodeUniqueness(CfgNode entryNode)
        {
            AssertEntryNodeParameter(entryNode);
            CfgNode addedExitNode = null;
            CfgNode exitNodeCandidate = null;

            foreach(CfgNode candidate in EnumerateAllNodes(entryNode)) {
                if (!candidate.IsExitNode) { continue; }
                if ((null != addedExitNode) && !object.ReferenceEquals(addedExitNode, candidate)) {
                    CfgNode.Link(candidate, addedExitNode);
                    continue;
                }
                if (null == exitNodeCandidate) {
                    exitNodeCandidate = candidate;
                    continue;
                }
                addedExitNode = new CfgNode();
                CfgNode.Link(candidate, addedExitNode);
                CfgNode.Link(exitNodeCandidate, addedExitNode);
                exitNodeCandidate = null;
            }
            return;
        }
Esempio n. 6
0
        /// <summary>Create basic blocks.</summary>
        /// <param name="rootNode">The root node of the graph.</param>
        /// <param name="method">The method which body is involved.</param>
        /// <param name="sparseInstructions">A sparse array of instructions to be analyzed.
        /// Some of the entries in this array are expected to be null references
        /// denoting no instruction starts at that particular offset within the method
        /// bytecode.</param>
        private static void CreateBasicBlocks(CfgNode rootNode, IMethod method,
            DalvikInstruction[] sparseInstructions)
        {
            #if DBGCFG
            List<CfgNode> methodNodes = new List<CfgNode>();
            #endif
            List<BlockNode> unreachableBlocks = new List<BlockNode>();
            BlockNode currentBlock = null;
            bool firstBlock = true;
            // An array that maps each bytecode byte to it's owning block if any.
            BlockNode[] blocksPerOffset = new BlockNode[method.ByteCodeSize];
            blocksPerOffset[0] = currentBlock;
            bool cfgDebuggingEnabled = rootNode.DebugEnabled;

            // Create basic blocks. These are set of consecutive instructions with
            // each instruction having a single successor that is the next instruction.
            foreach (DalvikInstruction scannedInstruction in sparseInstructions) {
                if (null == scannedInstruction) { continue; }
            #if DBGCFG
                if (cfgDebuggingEnabled) {
                    Console.WriteLine("@{0:X4} {1}", scannedInstruction.MethodRelativeOffset,
                        scannedInstruction.GetType().Name);
                }
            #endif
                if (null == currentBlock) {
                    // The previous instruction didn't fail in sequence. Either there is already a
                    // block defined for the current offset or we must create a new one.
                    currentBlock = blocksPerOffset[scannedInstruction.MethodRelativeOffset];
                    if (null == currentBlock) {
                        currentBlock = new BlockNode(cfgDebuggingEnabled);
            #if DBGCFG
                        methodNodes.Add(currentBlock);
            #endif
                        blocksPerOffset[scannedInstruction.MethodRelativeOffset] = currentBlock;
                        if (firstBlock) {
                            CfgNode.Link(rootNode, currentBlock);
            #if DBGCFG
                            Console.WriteLine("Created first block #{0}", currentBlock.NodeId);
            #endif
                            firstBlock = false;
                        }
                        else {
                            unreachableBlocks.Add(currentBlock);
            #if DBGCFG
                            AssertConsistency(blocksPerOffset, methodNodes);
                            if (cfgDebuggingEnabled) {
                                Console.WriteLine("Created unreachable block #{0}", currentBlock.NodeId);
                            }
            #endif
                        }
                    }
            #if DBGCFG
                    else {
                        if (cfgDebuggingEnabled) {
                            Console.WriteLine("Reusing block #{0}", currentBlock.NodeId);
                        }
                    }
            #endif
                }
                else {
                    // Last instruction failed in sequence. However we may have already defined a
                    // block for the current offset.
                    BlockNode alreadyDefined = blocksPerOffset[scannedInstruction.MethodRelativeOffset];

                    if (   (null != alreadyDefined)
                        && !object.ReferenceEquals(currentBlock, alreadyDefined))
                    {
            #if DBGCFG
                        if (cfgDebuggingEnabled) {
                            Console.WriteLine(
                                "Linking block #{0} to block #{1} and switching to the later",
                                currentBlock.NodeId, alreadyDefined.NodeId);
                        }
            #endif
                        // make the already defined the current block.
                        CfgNode.Link(currentBlock, alreadyDefined);
                        currentBlock = alreadyDefined;
                    }
            #if DBGCFG
                    else {
                        if (cfgDebuggingEnabled) {
                            Console.WriteLine("Continuing with block #{0}", currentBlock.NodeId);
                        }
                    }
            #endif
                }
                currentBlock.Bind(scannedInstruction);
                for(uint sizeIndex = 0; sizeIndex < scannedInstruction.InstructionSize; sizeIndex++) {
                    int offsetIndex = (int)(scannedInstruction.MethodRelativeOffset + sizeIndex);
                    if (   (null != blocksPerOffset[offsetIndex])
                        && !object.ReferenceEquals(blocksPerOffset[offsetIndex], currentBlock))
                    {
                        throw new ApplicationException();
                    }
                    blocksPerOffset[offsetIndex] = currentBlock;
            #if DBGCFG
                    AssertConsistency(blocksPerOffset, methodNodes);
            #endif
                }
                // Scan other targets if any.
                uint[] otherOffsets = scannedInstruction.AdditionalTargetMethodOffsets;
                if (null == otherOffsets) {
                    if (!scannedInstruction.ContinueInSequence) {
                        // Must switch to another block.
                        currentBlock = null;
                    }
                    continue;
                }

                // Must create a block for each possible target and link current
                // block to each of those blocks.
                for (int index = 0; index < otherOffsets.Length; index++) {
                    uint targetOffset = otherOffsets[index];
                    BlockNode targetBlock = blocksPerOffset[targetOffset];

                    if (null == targetBlock) {
                        // Block doesn't exists yet. Create and register it.
                        targetBlock = new BlockNode(currentBlock.DebugEnabled);
            #if DBGCFG
                        methodNodes.Add(targetBlock);
            #endif
                        blocksPerOffset[targetOffset] = targetBlock;
            #if DBGCFG
                        AssertConsistency(blocksPerOffset, methodNodes);
                        if (targetBlock.DebugEnabled) {
                            Console.WriteLine("Pre-registering block #{0} @{1:X4}",
                                targetBlock.NodeId, targetOffset);
                            Console.WriteLine("Linking block #{0} to block #{1}",
                                currentBlock.NodeId, targetBlock.NodeId);
                        }
            #endif
                        // Link current node and next one.
                        CfgNode.Link(currentBlock, targetBlock);
                        continue;
                    }
                    // The target block already exists albeit it may deserve a split.
                    // if (0 == targetOffset) { continue; }
                    BlockNode splitCandidate = targetBlock;
                    bool splitCandidateIsCurrentBlock =
                        object.ReferenceEquals(splitCandidate, currentBlock);
                    bool splitCandidateAlreadyAligned =
                        !object.ReferenceEquals(blocksPerOffset[targetOffset - 1], splitCandidate);
                    bool linkCurrentToSplitted = true;

                    try {
                        if (splitCandidateAlreadyAligned && !splitCandidateIsCurrentBlock) {
                            // The split candidate actually starts at target address
                            // and is not the current block. No split required.
                            continue;
                        }
                        // Need a split.
                        uint splitAt;
                        bool makeSplitResultCurrent;
                        if (!splitCandidateAlreadyAligned) {
                            splitAt = targetOffset;
                            makeSplitResultCurrent = false;
                        }
                        else {
                            // The target is the first instruction of current block. We
                            // split the last instruction from the current block.
                            if (!splitCandidateIsCurrentBlock) {
                                throw new AssertionException();
                            }
                            splitAt = scannedInstruction.MethodRelativeOffset;
                            linkCurrentToSplitted = false;
                            // From now on consider the newly created block to be the
                            // current one.
                            makeSplitResultCurrent = true;
                        }
            #if DBGCFG
                        if (targetBlock.DebugEnabled) {
                            Console.WriteLine("Spliting block #{0} @{1:X4}.",
                                splitCandidate.NodeId, splitAt);
                        }
            #endif
                        targetBlock = splitCandidate.Split(splitAt);
            #if DBGCFG
                        methodNodes.Add(targetBlock);
                        if (targetBlock.DebugEnabled) {
                            Console.WriteLine("New block #{0} created while spliting block #{1}.",
                                targetBlock.NodeId, splitCandidate.NodeId);
                        }
            #endif
                        if (makeSplitResultCurrent) {
                            currentBlock = targetBlock;
                        }
                        // Update offset to block mapping for new splited block. Also
                        // transfer instructions from existing block to split result.
                        for (int scannedOffset = (int)splitAt; scannedOffset < blocksPerOffset.Length; scannedOffset++) {
                            if (!object.ReferenceEquals(blocksPerOffset[scannedOffset], splitCandidate)) { break; }
                            blocksPerOffset[scannedOffset] = targetBlock;
                        }
            #if DBGCFG
                        AssertConsistency(blocksPerOffset, methodNodes);
            #endif
                    }
                    finally {
                        if (linkCurrentToSplitted) {
            #if DBGCFG
                            if ((null != currentBlock) && currentBlock.DebugEnabled) {
                                Console.WriteLine("Linking block #{0} to block #{1}",
                                    currentBlock.NodeId, targetBlock.NodeId);
                            }
            #endif
                            // Link current node and next one.
                            CfgNode.Link(currentBlock, targetBlock);
                        }
                        if (unreachableBlocks.Contains(targetBlock)) {
                            unreachableBlocks.Remove(targetBlock);
            #if DBGCFG
                            if (targetBlock.DebugEnabled) {
                                Console.WriteLine("Previously unreachable block #{0} now reachable.",
                                    targetBlock.NodeId);
                            }
            #endif
                        }
                    }
                }

                // Having other targets force a block reset AND the next instruction to be in
                // a separate block than the current one, provided the current instruction fails
                // in sequence.
                if (scannedInstruction.ContinueInSequence) {
                    uint nextInstructionOffset =
                        scannedInstruction.MethodRelativeOffset + scannedInstruction.InstructionSize;
                    BlockNode nextBlock = blocksPerOffset[nextInstructionOffset];
                    if (null == nextBlock) {
                        nextBlock = new BlockNode(currentBlock.DebugEnabled);
            #if DBGCFG
                        methodNodes.Add(nextBlock);
            #endif
                        blocksPerOffset[nextInstructionOffset] = nextBlock;
            #if DBGCFG
                        AssertConsistency(blocksPerOffset, methodNodes);
                        if (nextBlock.DebugEnabled) {
                            Console.WriteLine("Created next block #{0} @{1:X4}",
                                nextBlock.NodeId, nextInstructionOffset);
                            Console.WriteLine("Linking block #{0} to block #{1}",
                                currentBlock.NodeId, nextBlock.NodeId);
                        }
            #endif
                    }
                    // Link current node and next one.
                    CfgNode.Link(currentBlock, nextBlock);
                }
                // Next block will always be different from the current one.
                currentBlock = null;
            }
            #if DBGCFG
            if (cfgDebuggingEnabled) { Console.WriteLine("Basic blocks creation done."); }
            #endif
            // Link allunreachable blocks to the root node.
            foreach (BlockNode scannedBlock in unreachableBlocks) { CfgNode.Link(rootNode, scannedBlock); }
            return;
        }
Esempio n. 7
0
 private void AddLink(CfgNode linked, ref List<CfgNode> collection)
 {
     if (null == collection) { collection = new List<CfgNode>(); }
     if (collection.Contains(linked)) { return; }
     collection.Add(linked);
     // TODO : Prevent loops.
     return;
 }
Esempio n. 8
0
 /// <summary>Transfer the successors of this node to the given one. This is for
 /// use during node splits. The receiving node must not have any successor yet.</summary>
 /// <param name="to">The receiving node.</param>
 protected void TransferSuccessors(CfgNode to)
 {
     if (null != to._successors) { throw new InvalidOperationException(); }
     if (null == this._successors) { return; }
     to._successors = this._successors;
     this._successors = null;
     // Must also adjust predecessors in successors.
     foreach (CfgNode target in to._successors) {
         List<CfgNode> targetPredecessors = target._predecessors;
         int targetPredecessorsCount = targetPredecessors.Count;
         bool replacementFound = false;
         for (int index = 0; index < targetPredecessorsCount; index++) {
             if (!object.ReferenceEquals(this, targetPredecessors[index])) {
                 continue;
             }
             replacementFound = true;
             targetPredecessors[index] = to;
             break;
         }
         if (!replacementFound) { throw new ApplicationException(); }
     }
     return;
 }
Esempio n. 9
0
        internal static void Link(CfgNode predecessor, CfgNode successor)
        {
            if (object.ReferenceEquals(predecessor, successor)) {
                throw new InvalidOperationException();
            }
#if DBGCFG
            if (   (null != predecessor)
                && (null != successor)
                && (predecessor.DebugEnabled || successor.DebugEnabled))
            {
                Console.WriteLine("[{0}] -> [{1}]", predecessor.NodeId, successor.NodeId);
            }
#endif
            predecessor.AddLink(successor, ref predecessor._successors);
            successor.AddLink(predecessor, ref successor._predecessors);
            return;
        }