Ejemplo n.º 1
0
        /// <summary>
        /// Instrument the assembly.
        /// </summary>
        /// <returns>Termination mode of the processing.</returns>
        public static Phx.Term.Mode Process()
        {
            string currentAssembly = Application.Input.GetValue(null);

            // Create the log file with details about the basic blocks
            using (LogWriter log = new LogWriter(Path.ChangeExtension(currentAssembly, "Coverage.xml")))
            {
                log.Start();

                Phx.Output.WriteLine("Instrumenting code coverage for " + currentAssembly + " ...");
                log.StartAssembly(currentAssembly);

                // Get the architecture and runtime from the existing assembly
                Phx.PEModuleUnit oldModule = Phx.PEModuleUnit.Open(currentAssembly);
                Phx.Targets.Architectures.Architecture architecture = oldModule.Architecture;
                Phx.Targets.Runtimes.Runtime           runtime      = oldModule.Runtime;
#if VS2010
                string clrVersion = oldModule.ClrVersionString;
#endif
                oldModule.Close();
                oldModule.Delete();

                // Create an empty program to contain the instrumented code
                Phx.Lifetime    lifetime = Phx.Lifetime.New(Phx.LifetimeKind.Global, null);
                Phx.ProgramUnit program  = Phx.ProgramUnit.New(
                    lifetime,
                    null,
                    Phx.GlobalData.TypeTable,
                    architecture,
                    runtime);
                Phx.PEModuleUnit module = Phx.PEModuleUnit.New(
                    lifetime,
                    Phx.Name.New(lifetime, Path.GetFullPath(currentAssembly)),
                    program,
                    Phx.GlobalData.TypeTable,
                    architecture,
                    runtime);

                // Set to metadata version 2 if none was copied
#if VS2010
                if (clrVersion == null)
                {
                    clrVersion = PreferredClrVersion;
                    module.ClrVersionString = clrVersion;
                }
#endif

                // Dev10 Phoenix seems to require this fix
#if VS2010
                module.RaiseMsilOnly = true;
#endif

                // Create the phase list:
                // 1. For each function
                //    a. Raise the binary executable code to LIR
                //    b. Instrument function with code coverage calls
                //    c. Encode the instrumented code
                // 2. Emit the instrumented program as a binary
                Phx.Phases.PhaseConfiguration phases = Phx.Phases.PhaseConfiguration.New(lifetime, "CodeCoverage Phases");
                phases.PhaseList.AppendPhase(Phx.PE.ReaderPhase.New(phases));
                Phx.Phases.PhaseList functionPhases = Phx.PE.UnitListPhaseList.New(phases, Phx.PE.UnitListWalkOrder.PrePass);
                functionPhases.AppendPhase(Phx.PE.RaiseIRPhase.New(phases, Phx.FunctionUnit.LowLevelIRBeforeLayoutFunctionUnitState));
                functionPhases.AppendPhase(InstrumentPhase.New(phases, log));
                functionPhases.AppendPhase(EncodePhase.New(phases));
                functionPhases.AppendPhase(Phx.PE.DiscardIRPhase.New(phases));
                phases.PhaseList.AppendPhase(functionPhases);
                phases.PhaseList.AppendPhase(EmitPhase.New(phases));
                Phx.GlobalData.BuildPlugInPhases(phases);

                // Run Phoenix using our phases
                phases.PhaseList.DoPhaseList(module);

                // Close the log file
                log.EndAssembly();
                log.Close();
            }

            return(Phx.Term.Mode.Normal);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Dumps the DOT representation of the control-flow graph of the input function unit
        /// in a file (a DAG file labeled with the name of the function unit) that will be
        /// further processed by the GameTime Python scripts.
        /// </summary>
        ///
        /// <param name="functionUnit">Phoenix function unit whose control-flow graph is
        /// to be dumped.</param>
        /// <param name="sourceNodeId">ID of the BasicBlock in the control-flow
        /// graph to start the analysis from.</param>
        /// <param name="sinkNodeId">ID of the BasicBlock in the control-flow
        /// graph to end the analysis at.</param>
        /// <param name="config">Configuration object that contains
        /// GameTime configuration information.</param>
        /// <param name="projectConfig">ProjectConfiguration object that contains
        /// project configuration information.</param>
        public static void DumpCfgToFile(Phx.FunctionUnit functionUnit,
                                         uint sourceNodeId, uint sinkNodeId, Utilities.Configuration config,
                                         ProjectConfiguration projectConfig)
        {
            Console.Out.WriteLine("PHOENIX: Dumping a DOT representation of the " +
                                  "control-flow graph...");

            string funcName = GetFunctionName(functionUnit);

            Phx.Graphs.FlowGraph flowGraph = functionUnit.FlowGraph;
            Phx.Lifetime         lifetime  = functionUnit.Lifetime;

            if (projectConfig.debugConfig.DUMP_IR)
            {
                Console.Out.WriteLine("PHOENIX: Dumping IR...");

                string irFileName =
                    System.IO.Path.Combine(projectConfig.locationTempDir,
                                           config.TEMP_PHX_IR);
                StreamWriter irWriter = new StreamWriter(irFileName, true);
                irWriter.AutoFlush = true;

                foreach (Phx.Graphs.BasicBlock block in flowGraph.BasicBlocks)
                {
                    irWriter.WriteLine("*** BASIC BLOCK " + block.Id + " ***");
                    foreach (Phx.IR.Instruction instruction in block.Instructions)
                    {
                        irWriter.WriteLine(instruction);
                    }
                }

                irWriter.Close();
            }


            /* Perform a reachability analysis from the source node: determine
             * what nodes and edges can be reached from the source node. */
            Phx.BitVector.Sparse blocksVisitedFromSource = Phx.BitVector.Sparse.New(lifetime);
            Phx.BitVector.Sparse blocksToVisitFromSource = Phx.BitVector.Sparse.New(lifetime);
            Phx.BitVector.Sparse edgesVisitedFromSource  = Phx.BitVector.Sparse.New(lifetime);

            blocksToVisitFromSource.SetBit(sourceNodeId);
            /* TODO: Make more efficient. */
            while (!blocksToVisitFromSource.IsEmpty)
            {
                uint blockToVisitId = blocksToVisitFromSource.RemoveFirstBit();
                blocksVisitedFromSource.SetBit(blockToVisitId);

                Phx.Graphs.BasicBlock blockToVisit =
                    flowGraph.Node(blockToVisitId) as Phx.Graphs.BasicBlock;
                foreach (Phx.Graphs.FlowEdge edge in blockToVisit.SuccessorEdges)
                {
                    Phx.Graphs.BasicBlock successor = edge.SuccessorNode;

                    uint succId = successor.Id;
                    uint edgeId = edge.Id;

                    if (!blocksVisitedFromSource.GetBit(succId))
                    {
                        blocksToVisitFromSource.SetBit(succId);
                        edgesVisitedFromSource.SetBit(edgeId);
                    }
                }
            }

            /* Perform a backward reachability analysis from the sink node: determine
             * what nodes and edges can be reached from the sink node. */
            Phx.BitVector.Sparse blocksVisitedFromSink = Phx.BitVector.Sparse.New(lifetime);
            Phx.BitVector.Sparse blocksToVisitFromSink = Phx.BitVector.Sparse.New(lifetime);
            Phx.BitVector.Sparse edgesVisitedFromSink  = Phx.BitVector.Sparse.New(lifetime);

            blocksToVisitFromSink.SetBit(sinkNodeId);

            while (!blocksToVisitFromSink.IsEmpty)
            {
                uint blockToVisitId = blocksToVisitFromSink.RemoveFirstBit();
                blocksVisitedFromSink.SetBit(blockToVisitId);

                Phx.Graphs.BasicBlock blockToVisit =
                    flowGraph.Node(blockToVisitId) as Phx.Graphs.BasicBlock;
                foreach (Phx.Graphs.FlowEdge edge in blockToVisit.PredecessorEdges)
                {
                    Phx.Graphs.BasicBlock predecessor = edge.PredecessorNode;

                    uint predId = predecessor.Id;
                    uint edgeId = edge.Id;

                    if (!blocksVisitedFromSink.GetBit(predId))
                    {
                        blocksToVisitFromSink.SetBit(predId);
                        edgesVisitedFromSink.SetBit(edgeId);
                    }
                }
            }

            /* Determine which blocks and edges in the control-flow graph can be reached from
             * *both* the source and the sink: this is the section of the control-flow graph
             * that we are interested in. */
            blocksVisitedFromSource.And(blocksVisitedFromSink);
            edgesVisitedFromSource.And(edgesVisitedFromSink);

            uint numNodes = (uint)blocksVisitedFromSource.GetBitCount();
            uint numEdges = (uint)edgesVisitedFromSource.GetBitCount();

            uint numNewNodes = numNodes + numNodes;
            uint numNewEdges = numEdges + numNodes + 1;

            /* Mapping between old block IDs and new block IDs. */
            Dictionary <uint, uint> idMap = new Dictionary <uint, uint>();

            /* Create a writer to write the DAG in DOT format to a file. */
            string dagFileName =
                System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG);
            StreamWriter dagWriter = new StreamWriter(dagFileName);

            dagWriter.AutoFlush = true;

            /* Qualify the DAG. */
            dagWriter.WriteLine("digraph " + funcName + " {");

            uint newMappedBlockId = 1;
            uint newFakeBlockId   = numNodes + 1;

            foreach (Phx.Graphs.BasicBlock basicBlock in flowGraph.BasicBlocks)
            {
                uint blockId = basicBlock.Id;

                /* Is the block in the portion of the control-flow graph
                 * we are concerned about? */
                if (blocksVisitedFromSource.GetBit(blockId))
                {
                    uint mappedBlockId;
                    if (idMap.ContainsKey(blockId))
                    {
                        mappedBlockId = idMap[blockId];
                    }
                    else
                    {
                        idMap.Add(blockId, newMappedBlockId);
                        mappedBlockId = newMappedBlockId++;
                    }

                    /* Keep track of the edges that may be added to the resulting DAG. */
                    List <Pair <uint, uint> > edges = new List <Pair <uint, uint> >();

                    /* First edge that may be added to the DAG: it will be added
                     * if there are successors. */
                    edges.Add(new Pair <uint, uint>(mappedBlockId, newFakeBlockId));

                    List <Phx.Graphs.FlowEdge> reverseSuccessorList = new List <Phx.Graphs.FlowEdge>();
                    foreach (Phx.Graphs.FlowEdge edge in basicBlock.SuccessorEdges)
                    {
                        reverseSuccessorList.Add(edge);
                    }
                    reverseSuccessorList.Reverse();

                    foreach (Phx.Graphs.FlowEdge edge in reverseSuccessorList)
                    {
                        /* Is the block in the portion of the control-flow graph
                         * we are concerned about? */
                        Phx.Graphs.BasicBlock successor = edge.SuccessorNode;
                        uint succId = successor.Id;

                        if (blocksVisitedFromSource.GetBit(succId))
                        {
                            uint mappedSuccId;
                            if (idMap.ContainsKey(succId))
                            {
                                mappedSuccId = idMap[succId];
                            }
                            else
                            {
                                idMap.Add(succId, newMappedBlockId);
                                mappedSuccId = newMappedBlockId++;
                            }

                            /* Replace each BasicBlock with two edges,
                             * separated by a new, "fake" node. */
                            edges.Add(new Pair <uint, uint>(newFakeBlockId, mappedSuccId));
                        }
                    }

                    if (edges.Count > 1)
                    {
                        /* This node has successors in the "snipped" CFG. */
                        foreach (Pair <uint, uint> edge in edges)
                        {
                            dagWriter.WriteLine("  " + edge.First + " -> " + edge.Second + ";");
                        }

                        /* Generate the ID of a "fake" node corresponding to
                         * the next node, if any. */
                        newFakeBlockId++;
                    }
                }
            }

            /* Add a "dummy" edge from the sink. */
            dagWriter.WriteLine("  " + idMap[sinkNodeId] + " -> " + numNewNodes + ";");

            dagWriter.WriteLine("}");
            dagWriter.Close();

            /* Copy the mappings to a file. */
            string blockIdMapFile =
                System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG_ID_MAP);
            StreamWriter blockIdMapWriter = new StreamWriter(blockIdMapFile);

            blockIdMapWriter.AutoFlush = true;

            foreach (uint key in idMap.Keys)
            {
                uint blockVisitedId = key;
                uint newBlockId     = idMap[key];

                blockIdMapWriter.WriteLine(newBlockId + " " + blockVisitedId);
            }

            blockIdMapWriter.Close();
        }