/// <summary>
        /// Remove redundancies and add in-edge information
        /// </summary>
        private void Optimize(SortedList <ushort, CallGraphNode> nodes)
        {
            // Remove redundant jumps directly to the next block that is not rechable from any other
            for (int i = 0; i < nodes.Count; i++)
            {
                CallGraphNode node = nodes.Values[i];
                if ((node.NodeType == NodeType.OneBranch) && (node.OutEdges.Count == 1) && (node.OutEdges[0].InEdges.Count == 1))
                {
                    ICallGraphNode targetNode = (ICallGraphNode)node.OutEdges[0];

                    // Remove the jump instruction at the end of this node
                    node.Instructions.RemoveAt(node.Instructions.Count - 1);

                    // Add all the instructions in the next node
                    node.EndIP = targetNode.EndIP;
                    foreach (IInstruction instruction in targetNode.Instructions)
                    {
                        node.Instructions.Add(instruction);
                    }

                    // Remove the target node
                    nodes.Remove(targetNode.StartIP);
                    node.OutEdges.Clear();

                    ((List <IGraphNode>)node.OutEdges).AddRange(targetNode.OutEdges);

                    foreach (CallGraphNode n in targetNode.OutEdges)
                    {
                        n.InEdges.Remove(targetNode);
                        n.InEdges.Add(node);
                    }

                    // This node now becomes the type of the target node
                    node.NodeType = targetNode.NodeType;
                }
            }


            // First pass over block list removes redundant jumps of the form
            // (Un)Conditional-> Unconditional jump
            foreach (CallGraphNode node in nodes.Values)
            {
                if ((node.OutEdges.Count == 0) &&
                    ((node.NodeType == NodeType.OneBranch) || (node.NodeType == NodeType.TwoBranch)))
                {
                    for (int i = 0; i < node.OutEdges.Count; i++)
                    {
                        CallGraphNode newTargetNode = RemoveJump((CallGraphNode)node.OutEdges[i]);
                        node.OutEdges[i] = newTargetNode;
                        newTargetNode.InEdges.Add(node);
                    }
                }
            }

            // Next is a depth-first traversal merging any FallThrough node or
            // OneBranch node that fall through to a node with that as their only in-edge.
            MergeFallThrough();

            // Remove redundant nodes created by the optimizations
        }
Ejemplo n.º 2
0
        private void MakeNode(ushort targetIp, SortedList <ushort, CallGraphNode> nodes)
        {
            CallGraphNode newNode;

            if (!nodes.TryGetValue(targetIp, out newNode))
            {
                newNode = new CallGraphNode(targetIp);
                nodes.Add(targetIp, newNode);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Finds the immediate dominator of each node in the graph
        /// This is based on the findImmedDom function of the Control.C file
        /// in the dcc source code which is in turn an adapted version
        /// of the dominators algorithm by Hecht and Ullman; finds
        /// immediate dominators only.
        /// Note graph should be reducible
        /// </summary>
        private void FindImmediateDominators()
        {
            for (int currentIndex = 0; currentIndex < _depthFirstSearchLast.Length; currentIndex++)
            {
                CallGraphNode currentNode = _depthFirstSearchLast[currentIndex];

                for (int j = 0; j < currentNode.InEdges.Count; j++)
                {
                    int predecessorIndex = currentNode.InEdges[j].DepthFirstSearchLastNumber;
                    if (predecessorIndex < currentIndex)
                    {
                        currentNode.ImmediateDominatorNumber = CommonDominator(currentNode.ImmediateDominatorNumber, predecessorIndex);
                    }
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Performs a depth first traversal of the call graph and labels each node with its
        /// postion in the traversal
        /// </summary>
        /// <param name="node"></param>
        /// <param name="firstNumber"></param>
        /// <param name="lastNumber"></param>
        private void DepthFirstTraverse(CallGraphNode node, ref int lastNumber)
        {
            node.Traversed = true;

            foreach (CallGraphNode childNode in node.OutEdges)
            {
                // Traverse the child node if it has not already been traversed
                if (!childNode.Traversed)
                {
                    DepthFirstTraverse(childNode, ref lastNumber);
                }
            }

            node.DepthFirstSearchLastNumber     = lastNumber;
            _depthFirstSearchLast[lastNumber--] = node;
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Recursive procedure to tag nodes that belong to the case described by
 /// the list l, head and tail (dfsLast index to first and exit node of the
 /// case).
 /// </summary>
 /// <param name="node"></param>
 /// <param name="l"></param>
 /// <param name="head"></param>
 /// <param name="tail"></param>
 private static void TagNodesInCase(CallGraphNode node, ICollection <IGraphNode> l, ICallGraphNode head, IGraphNode tail)
 {
     node.Traversed = true;
     if ((node != tail) && (node.Instructions.Count > 0) && (node.Instructions[node.Instructions.Count - 1].OpCode != OpCodeTable.Switch) && l.Contains(node))
     {
         l.Add(node);
         node.CaseHead = head;
         for (int i = 0; i < node.OutEdges.Count; i++)
         {
             if (!((CallGraphNode)node.OutEdges[i]).Traversed)
             {
                 TagNodesInCase((CallGraphNode)node.OutEdges[i], l, head, tail);
             }
         }
     }
 }
        private static bool LinkContinuationNode(CallGraphNode node, SortedList <ushort, CallGraphNode> nodes)
        {
            int index = nodes.IndexOfValue(node) + 1;

            if (index == nodes.Count)
            {
                return(false);
            }

            IGraphNode targetNode = nodes.Values[index];

            node.OutEdges.Add(targetNode);
            targetNode.InEdges.Add(node);

            return(true);
        }
Ejemplo n.º 7
0
        private CallGraphNode SplitNode(ushort ip, NodeType type)
        {
            foreach (CallGraphNode node in _nodes)
            {
                if ((node.StartIP <= ip) && (node.EndIP >= ip))
                {
                    // Found the node
                    CallGraphNode newNode = new CallGraphNode(ip, new List <IInstruction>());
                    newNode.NodeType = node.NodeType;
                    node.NodeType    = type;

                    // Move the instructions
                    int i = 0;
                    while ((node.Instructions.Count > i) && (node.Instructions[i].IP < ip))
                    {
                        i++;
                    }

                    while (node.Instructions.Count > i)
                    {
                        newNode.Instructions.Add(node.Instructions[i]);
                        node.Instructions.RemoveAt(i);
                    }

                    // Move the out edges from the existing node to the new node
                    foreach (CallGraphNode outNode in node.OutEdges)
                    {
                        newNode.OutEdges.Add(outNode);

                        outNode.InEdges.Remove(node);
                        outNode.InEdges.Add(newNode);
                    }
                    node.OutEdges.Clear();

                    // Link the two nodes
                    node.OutEdges.Add(newNode);
                    newNode.InEdges.Add(node);

                    // Add the new node after the existing node into the node list
                    _nodes.Insert(_nodes.IndexOf(node) + 1, newNode);

                    return(node);
                }
            }

            throw new ApplicationException("Exception clause out of IP range");
        }
        private static void LinkNode(IGraphNode node, IDictionary <ushort, CallGraphNode> nodes, ushort targetIP)
        {
            CallGraphNode targetNode;

            if (nodes.TryGetValue(targetIP, out targetNode))
            {
                node.OutEdges.Add(targetNode);
                targetNode.InEdges.Add(node);
            }
            else
            {
                // Create a new empty node at the IP
                IList <IInstruction> instructions = new List <IInstruction>();
                instructions.Add(OpCodeTable.GetInstruction(OpCodes.Nop, targetIP, null));
                CallGraphNode emptyNode = new CallGraphNode(instructions);
                nodes.Add(targetIP, emptyNode);
                node.OutEdges.Add(emptyNode);
                emptyNode.InEdges.Add(node);
            }
        }
Ejemplo n.º 9
0
        private void TraverseExceptionTree(TryHandler tryHandler)
        {
            // Find the right node to add the try node before
            CallGraphNode tryNode     = SplitNode((ushort)tryHandler.TryStartIp, tryHandler.Type);
            CallGraphNode handlerNode = SplitNode((ushort)tryHandler.HandlerStartIp, NodeType.FallThrough);
            CallGraphNode followNode  = SplitNode((ushort)tryHandler.HandlerEndIp, NodeType.FallThrough);

            tryNode.HandlerNode = (ICallGraphNode)handlerNode.OutEdges[0];
            tryNode.FollowNode  = (ICallGraphNode)followNode.OutEdges[0];

            // Split the children
            foreach (TryHandler childTryHandler in tryHandler.NestedTry.Values)
            {
                TraverseExceptionTree(childTryHandler);
            }

            foreach (TryHandler childTryHandler in tryHandler.NestedHandler.Values)
            {
                TraverseExceptionTree(childTryHandler);
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// If the node is just a jump then replace the node with its target
        /// </summary>
        /// <param name="node">The node that is just a jump instruction.</param>
        /// <returns>The node that the jump instruction jumped to.</returns>
        private static CallGraphNode RemoveJump(CallGraphNode node)
        {
            while ((node.NodeType == NodeType.OneBranch) && (node.EndIP - node.StartIP == 1))
            {
                if (!node.Traversed)
                {
                    node.Traversed = true;
                    if (node.InEdges.Count == 1)
                    {
                        // Remove this node from the parents nodes out edges
                        node.InEdges[0].OutEdges.Remove(node);

                        // Remove this node from the child nodes in edges
                        node.OutEdges[0].InEdges.Remove(node);
                    }
                }

                node = (CallGraphNode)node.OutEdges[0];
            }

            return(node);
        }
Ejemplo n.º 11
0
        public ControlFlowGraph(NetMethodBody body, Module module, Type[] genericTypeArguments, Type[] genericMethodArguments)
        {
            // Convert the byte code into instruction objects
            ushort ip = 0;

            byte[] il = body.GetILAsByteArray();

            List <IInstruction> instructions = new List <IInstruction>();

            while (ip < il.Length)
            {
                instructions.Add(OpCodeTable.GetInstruction(il, ref ip, module, genericTypeArguments, genericMethodArguments));
            }

            // Iterate the instructions building a list of call graph nodes
            SortedList <ushort, CallGraphNode> nodes = new SortedList <ushort, CallGraphNode>();
            CallGraphNode node = new CallGraphNode(0);

            nodes.Add(0, node);

            int          index       = 0;
            IInstruction instruction = instructions[index];

            do
            {
                Console.Write(instruction);

                // Create the nodes that this instruction branches to
                switch (instruction.OpCode.FlowControl)
                {
                case FlowControl.Branch:
                {
                    if ((instruction.OpCode != OpCodes.Leave) &&
                        (instruction.OpCode != OpCodes.Leave_S))
                    {
                        // Direct branch to a new instruction that is not a leave instruction from a try-catch block.
                        // Create a call graph node for the target of the branch.
                        MakeNode((ushort)instruction.Argument, nodes);

                        Console.Write(" <-- Branch {0:x4}", instruction.Argument);
                    }

                    break;
                }

                case FlowControl.Cond_Branch:
                {
                    if (instruction.OpCode.Value == OpCodes.Switch.Value)
                    {
                        // Conditional branch to n-blocks
                        foreach (ushort switchTargetIp in (ushort[])instruction.Argument)
                        {
                            MakeNode(switchTargetIp, nodes);
                        }
                    }
                    else
                    {
                        // Conditional branch to two blocks
                        MakeNode((ushort)instruction.Argument, nodes);

                        Console.WriteLine("Making " + instruction.Argument);
                    }

                    // Set the next instruction of a branch to also be a target
                    MakeNode(instructions[index + 1].IP, nodes);
                    Console.Write(" <-- If Node {0:x4}", instruction.Argument);
                    break;
                }

                case FlowControl.Return:
                    // Set the next instruction of a branch to also be a target
                    Console.Write(" <-- Exit Node");
                    break;

                case FlowControl.Throw:
                    // End of graph
                    Console.Write(" <-- Throw Node");
                    break;

                case FlowControl.Break:
                case FlowControl.Call:
                case FlowControl.Meta:
                case FlowControl.Next:
#pragma warning disable 612,618
                case FlowControl.Phi:
#pragma warning restore 612,618
                    // Add the continuation link
                    //node.NodeType = NodeType.FallThrough;
                    //MakeNode(ip, node, nodes);
                    break;
                }

                Console.WriteLine();

                // Get the next instruction
                index++;
                if (index < instructions.Count)
                {
                    instruction = instructions[index];

                    // Find the node to add the next instruction to
                    CallGraphNode nextNode;
                    if (nodes.TryGetValue(instruction.IP, out nextNode))
                    {
                        /*if (node.NodeType == NodeType.FallThrough)
                         * {
                         *      Console.Write("added fall through link ");
                         *      node.OutEdges.Add(nextNode);
                         *      nextNode.InEdges.Add(node);
                         * }*/



                        node = nextNode;

                        Console.Write("New Node --> ");
                    }
                }
            } while (index < instructions.Count);

            Console.WriteLine();

            // Iterate the instructions a second time adding them to the correct nodes
            //CallGraphNode node;
            node = nodes[0];
            for (index = 0; index < instructions.Count; index++)
            {
                instruction = instructions[index];

                if (index > 0)
                {
                    CallGraphNode nextNode;
                    if (nodes.TryGetValue(instruction.IP, out nextNode))
                    {
                        if (node.OutEdges.Count == 0)
                        {
                            Console.WriteLine("ff");
                            node.NodeType = NodeType.FallThrough;
                            LinkNode(node, nextNode);
                        }
                        Console.Write("--" + node.OutEdges.Count + "--");
                        node = nextNode;
                        Console.Write("new node ");
                    }
                }

                Console.WriteLine(instruction);
                node.Instructions.Add(instruction);

                // Create the nodes that this instruction branches to
                switch (instruction.OpCode.FlowControl)
                {
                case FlowControl.Branch:
                {
                    if ((instruction.OpCode != OpCodes.Leave) &&
                        (instruction.OpCode != OpCodes.Leave_S))
                    {
                        // Direct branch to a new instruction that is not a leave instruction from a try-catch block.
                        // Create a call graph node for the target of the branch.
                        node.NodeType = NodeType.OneBranch;
                        LinkNode(node, nodes[(ushort)instruction.Argument]);

                        Console.Write(" <-- Branch {0:x4}", instruction.Argument);
                    }

                    break;
                }

                case FlowControl.Cond_Branch:
                {
                    if (instruction.OpCode.Value == OpCodes.Switch.Value)
                    {
                        // Conditional branch to n-blocks
                        node.NodeType = NodeType.MultiBranch;
                        foreach (ushort switchTargetIp in (ushort[])instruction.Argument)
                        {
                            LinkNode(node, nodes[switchTargetIp]);
                        }
                    }
                    else
                    {
                        // Conditional branch to two blocks
                        node.NodeType = NodeType.TwoBranch;
                        LinkNode(node, nodes[(ushort)instruction.Argument]);
                        Console.Write("Linking " + instruction.Argument);
                    }

                    // Set the next instruction of a branch to also be a target
                    LinkNode(node, nodes[instructions[index + 1].IP]);
                    Console.Write(" <-- If Node {0:x4}", instruction.Argument);
                    break;
                }

                case FlowControl.Return:
                    // Set the next instruction of a branch to also be a target
                    node.NodeType = NodeType.Exit;
                    Console.Write(" <-- Exit Node");
                    break;

                case FlowControl.Throw:
                    // End of graph
                    node.NodeType = NodeType.Throw;
                    Console.Write(" <-- Throw Node");
                    break;
                }
            }



            // Copy the nodes to a simple list
            _nodes.AddRange(nodes.Values);

            Console.WriteLine();
            Console.WriteLine(_nodes.Count);
            foreach (CallGraphNode n in _nodes)
            {
                Console.WriteLine(n.StartIP + " " + n.NodeType + " " + n.OutEdges.Count);
            }

            CheckGraph();

            // Add the exception information - build a sorted tree of clauses
            SortedList <int, TryHandler> clauses = new SortedList <int, TryHandler>();
            foreach (ExceptionHandlingClause clause in body.ExceptionHandlingClauses)
            {
                Add(new TryHandler(clause), clauses);
            }

            foreach (TryHandler clause in clauses.Values)
            {
                TraverseExceptionTree(clause);
            }

            // Find the root node -- This fails when there are multiple try statements on the first instruction
            for (int i = 0; i < _nodes.Count; i++)
            {
                if (_nodes[i].StartIP == 0)
                {
                    _rootNode = _nodes[i];
                    break;
                }
            }

            if (_rootNode == null)
            {
                throw new ApplicationException("Unable to find a root node");
            }

            CheckGraph();

            // Remove redundancies and add in-edge information
            Optimize();

            CheckGraph();

            // Visit the graph in depth first order and label the nodes
            _depthFirstSearchLast = new CallGraphNode[_nodes.Count];
            int last = _nodes.Count - 1;
            DepthFirstTraverse(_rootNode, ref last);

            // Find the immediate dominators of each node
            FindImmediateDominators();

            // Check the graph for reducibility
            FindDerivedSequence();

            // Work out the graphs back edges
            DetermineBackEdges();

            ResetTraversal();
            StructureCases();
            StructureLoops();
            StructureIfs();
            ResetTraversal();
        }
Ejemplo n.º 12
0
 private void LinkNode(CallGraphNode sourceNode, CallGraphNode targetNode)
 {
     // Link the nodes
     sourceNode.OutEdges.Add(targetNode);
     targetNode.InEdges.Add(sourceNode);
 }
        /// <summary>
        /// Construct a control flow graph out of the method body
        /// </summary>
        /// <param name="instructions"></param>
        public ControlFlowGraph(SortedList <ushort, IInstruction> instructions)
        {
            // Iterate the list of instructions building a list of call graph nodes
            SortedList <ushort, CallGraphNode> nodes = new SortedList <ushort, CallGraphNode>();
            List <IInstruction> nodeInstructions     = new List <IInstruction>();

            foreach (IInstruction instruction in instructions.Values)
            {
                if ((instruction.IsTarget) && (nodeInstructions.Count > 0))
                {
                    // This is the start of a block.  Create the previous block
                    CallGraphNode callGraphNode = new CallGraphNode(nodeInstructions);
                    nodes.Add(callGraphNode.StartIP, callGraphNode);
                    nodeInstructions = new List <IInstruction>();
                }

                nodeInstructions.Add(instruction);
            }

            // Add the last node to the list
            if (nodeInstructions.Count > 0)
            {
                CallGraphNode callGraphNode = new CallGraphNode(nodeInstructions);
                nodes.Add(callGraphNode.StartIP, callGraphNode);
            }

            // Link the list of nodes
            for (int i = 0; i < nodes.Count; i++)
            {
                CallGraphNode node = nodes.Values[i];

                // Examine the last instruction to determine how to link this node to others
                IInstruction instruction = node.Instructions[node.Instructions.Count - 1];

                switch (instruction.OpCode.FlowControl)
                {
                case FlowControl.Branch:
                    // Direct branch to a new block
                    node.NodeType = NodeType.OneBranch;
                    LinkNode(node, nodes, (ushort)instruction.Argument);
                    break;

                case FlowControl.Cond_Branch:
                    if (instruction.OpCode.Value == OpCodes.Switch.Value)
                    {
                        // Conditional branch to n-blocks
                        node.NodeType = NodeType.MultiBranch;
                        foreach (ushort switchTargetIp in (ushort[])instruction.Argument)
                        {
                            LinkNode(node, nodes, switchTargetIp);
                        }
                    }
                    else
                    {
                        // Conditional branch to two blocks
                        node.NodeType = NodeType.TwoBranch;
                        LinkNode(node, nodes, (ushort)instruction.Argument);
                    }

                    // Add the continuation link
                    LinkContinuationNode(node, nodes);
                    break;

                case FlowControl.Return:
                    node.NodeType = NodeType.Exit;
                    break;

                case FlowControl.Throw:
                    node.NodeType = NodeType.Throw;
                    // End of graph
                    break;

                case FlowControl.Break:
                case FlowControl.Call:
                case FlowControl.Meta:
                case FlowControl.Next:
#pragma warning disable 612,618
                case FlowControl.Phi:
#pragma warning restore 612,618
                    // Add the continuation link
                    node.NodeType = LinkContinuationNode(node, nodes) ? NodeType.FallThrough : NodeType.ExitBlock;
                    break;

                default:
                    throw new ApplicationException("Unexpected flow control type in instruction " + instruction.OpCode.Name);
                }
            }

            _rootNode = nodes.Values[0];
            _nodes    = nodes;

            CheckGraph();

            // Remove redundancies and add in-edge information
            Optimize(nodes);

            IList <IGraphNode> ln = new List <IGraphNode>();
            foreach (CallGraphNode n in _nodes.Values)
            {
                ln.Add(n);
            }
            PrintGraph(ln);

            CheckGraph();

            // Visit the graph in depth first order and label the nodes
            _depthFirstSearchLast  = new CallGraphNode[nodes.Count];
            _depthFirstSearchFirst = new CallGraphNode[nodes.Count];
            int first = 0;
            int last  = nodes.Count - 1;
            DepthFirstTraverse(_rootNode, ref first, ref last);

            // Find the immediate dominators of each node
            FindImmediateDominators();

            // Check the graph for reducibility
            FindDerivedSequence();

            // Work out the graphs back edges
            DetermineBackEdges();

            ResetTraversal();
            StructureCases();
            StructureLoops();
            StructureIfs();
        }