/// <summary>
        /// Get a symbol representing a function that takes an unsigned integer
        /// parameter.
        /// </summary>
        /// <param name="unit">Module calling the function.</param>
        /// <param name="assembly">Name of the assembly.</param>
        /// <param name="type">Name of the class.</param>
        /// <param name="method">Name of the function.</param>
        /// <returns>FunctionSymbol representing the function.</returns>
        private static Phx.Symbols.FunctionSymbol GetFunctionSymbol(Phx.PEModuleUnit unit, string assembly, string type, string method)
        {
            // Look the function up in the cache
            Phx.Symbols.FunctionSymbol functionSymbol = null;
            if (FunctionSymbols.TryGetValue(unit, out functionSymbol) && functionSymbol != null)
            {
                return(functionSymbol);
            }

            // Create symbols for the assemblies and types
            Phx.Symbols.AssemblySymbol assemblySymbol = GetAssemblySymbol(unit, assembly);
            Phx.Symbols.MsilTypeSymbol typeSymbol     = GetTypeSymbol(unit, type, assemblySymbol);

            // Build a symbol reference
            Phx.Types.FunctionTypeBuilder builder = Phx.Types.FunctionTypeBuilder.New(unit.TypeTable);
            builder.Begin();
            builder.CallingConventionKind = Phx.Types.CallingConventionKind.ClrCall;
            builder.AppendReturnParameter(unit.TypeTable.VoidType);
            builder.AppendParameter(unit.TypeTable.UInt32Type);

            // Create the function symbol
            Phx.Name name = Phx.Name.New(unit.Lifetime, method);
            functionSymbol = Phx.Symbols.FunctionSymbol.New(unit.SymbolTable, 0, name, builder.GetFunctionType(), Phx.Symbols.Visibility.GlobalReference);
            typeSymbol.InsertInLexicalScope(functionSymbol, name);

            // Create a type
            Phx.Types.AggregateType aggregate = Phx.Types.AggregateType.NewDynamicSize(unit.TypeTable, typeSymbol);
            aggregate.IsDefinition = false;
            aggregate.AppendMethodSymbol(functionSymbol);

            // Cache the function
            FunctionSymbols[unit] = functionSymbol;

            return(functionSymbol);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Write out the instrumented binary.
        /// </summary>
        /// <param name="unit">Instrumented unit.</param>
        protected override void Execute(Phx.Unit unit)
        {
            if (!unit.IsPEModuleUnit)
            {
                return;
            }

            // Write the instrumented binary
            Phx.PEModuleUnit executable = unit.AsPEModuleUnit;
            Phx.PE.Writer    writer     = Phx.PE.Writer.New(
                Phx.GlobalData.GlobalLifetime,
                Application.Output.GetValue(null),
                null, // Writing an instrumented PDB currently crashes
                executable,
                executable.SymbolTable,
                executable.Architecture,
                executable.Runtime);
            writer.Write();
        }
        /// <summary>
        /// Inject code coverage information into a function.
        /// </summary>
        /// <param name="unit">The function to instrument.</param>
        protected override void Execute(Phx.Unit unit)
        {
            // Only instrument MSIL functions
            if (!unit.IsFunctionUnit)
            {
                return;
            }
            Phx.FunctionUnit function = unit.AsFunctionUnit;
            if (!function.Architecture.NameString.Equals("Msil"))
            {
                return;
            }

            Phx.PEModuleUnit           module         = function.ParentUnit.AsPEModuleUnit;
            Phx.Symbols.FunctionSymbol functionSymbol = function.FunctionSymbol;
            Phx.Types.FunctionType     functionType   = functionSymbol.FunctionType;

            // Create the method signature
            List <string> parameterTypes = new List <string>();

            foreach (Phx.Types.Parameter parameter in functionType.UserDefinedParameters)
            {
                parameterTypes.Add(parameter.Type.ToString());
            }
            string methodName = string.Format(
                CultureInfo.InvariantCulture,
                "{0}({1})",
                functionSymbol.NameString,
                string.Join(", ", parameterTypes.ToArray()));

            // Build the control flow graph for the current function
            function.BuildFlowGraph();
            Phx.Graphs.FlowGraph flow = function.FlowGraph;

            // Log method details
            string typeName = (functionSymbol.EnclosingAggregateType != null) ?
                              functionSymbol.EnclosingAggregateType.TypeSymbol.NameString :
                              "<Module>";

            Log.StartMethod(
                methodName,
                typeName,
                flow.StartBlock.FirstInstruction.GetFileName(),
                flow.StartBlock.FirstInstruction.GetLineNumber());

            // Create a mapping of the disassembled from instructions to the
            // basic block IDs so we can use them for coverage viewing.
            Dictionary <Phx.IR.Instruction, uint> dissassembly = new Dictionary <Phx.IR.Instruction, uint>();

            // Instrument and log the blocks for the current function.
            Log.StartBlocks();
            foreach (Phx.Graphs.BasicBlock block in flow.BasicBlocks)
            {
                // Find the first real instruction in the block
                Phx.IR.Instruction first = null;
                foreach (Phx.IR.Instruction instruction in block.Instructions)
                {
                    // Save the instructions to be dumped later
                    dissassembly.Add(instruction, BlockCounter);

                    // Ignore instructions that aren't actually "real"
                    if (first == null && instruction.IsReal)
                    {
                        Phx.Common.Opcode opcode = instruction.Opcode as Phx.Common.Opcode;
                        if (opcode == Phx.Common.Opcode.ReturnFinally ||
                            opcode == Phx.Common.Opcode.Leave ||
                            opcode == Phx.Common.Opcode.Unreached ||
                            opcode == Phx.Common.Opcode.ExitTypeFilter)
                        {
                            continue;
                        }

                        first = instruction;
                    }
                }

                // Inject a code coverage visitor call before the first
                // instruction of the basic block
                if (first != null)
                {
                    // Log the basic block
                    Phx.IR.Instruction last = block.LastInstruction;
                    Log.StartBlock(
                        BlockCounter,
                        first.GetMsilOffset(),
                        first.GetFileName(),
                        first.GetLineNumber(),
                        first.GetColumnNumber(),
                        last.GetLineNumberEnd(),
                        last.GetColumnNumberEnd());

                    Phx.Symbols.FunctionSymbol coverageVisit = GetFunctionSymbol(module, CoverageVisitAssembly, CoverageVisitType, CoverageVisitMethod);
                    InjectCoverageCall(function, coverageVisit, BlockCounter, first);

#if LogBlockDissassembly
                    // Dump the disassembly for the current block
                    Log.StartBlockDisassembly();
                    foreach (Phx.IR.Instruction instruction in block.Instructions)
                    {
                        Log.WriteBlockDisassembly(
                            instruction.GetMsilOffset(),
                            instruction.ToString(),
                            BlockCounter);
                    }
                    Log.EndBlockDisassembly();
#endif

                    Log.EndBlock();
                }

                // Increment the number of basic blocks
                BlockCounter++;
            }

            function.DeleteFlowGraph();
            Log.EndBlocks();

            // Dump the disassembly for the current method
            Log.StartMethodDisassembly();
            foreach (KeyValuePair <Phx.IR.Instruction, uint> pair in dissassembly)
            {
                Log.WriteBlockDisassembly(
                    pair.Key.GetMsilOffset(),
                    pair.Key.ToString(),
                    pair.Value);
            }
            Log.EndMethodDisassembly();

            Log.EndMethod();
        }
Exemplo n.º 4
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);
        }