Esempio n. 1
0
        private void VisitAssemblyGroup(
            InstrumentationContext context,
            InstrumentationResult result,
            IEnumerable <FileInfo> groupFiles)
        {
            var firstAssemblyFile = groupFiles.First();

            var instrumentedAssembly = _assemblyInstrumenter.InstrumentAssembly(
                context,
                firstAssemblyFile);

            if (instrumentedAssembly == null)
            {
                return;
            }

            foreach (var assemblyFile in groupFiles)
            {
                var pdbFile            = FileUtils.GetPdbFile(assemblyFile);
                var assemblyBackupFile = FileUtils.GetBackupFile(assemblyFile);
                var pdbBackupFile      = FileUtils.GetBackupFile(pdbFile);

                //Backup
                File.Copy(assemblyFile.FullName, assemblyBackupFile.FullName, true);
                File.Copy(pdbFile.FullName, pdbBackupFile.FullName, true);

                //Override assembly
                File.Copy(instrumentedAssembly.TempAssemblyFile, assemblyFile.FullName, true);
                File.Copy(instrumentedAssembly.TempPdbFile, pdbFile.FullName, true);

                //Copy instrumentation dependencies
                var assemblyDirectory = assemblyFile.Directory;

                var hitServicesPath    = Path.GetFileName(hitServicesAssembly.Location);
                var newHitServicesPath = Path.Combine(assemblyDirectory.FullName, hitServicesPath);
                if (!File.Exists(newHitServicesPath))
                {
                    File.Copy(hitServicesAssembly.Location, newHitServicesPath, true);
                    result.AddExtraAssembly(newHitServicesPath);
                }

                instrumentedAssembly.AddLocation(
                    assemblyFile.FullName,
                    assemblyBackupFile.FullName,
                    pdbFile.FullName,
                    pdbBackupFile.FullName
                    );

                var hitServicesAssemblyVersion = FileVersionInfo.GetVersionInfo(hitServicesAssembly.Location);
                foreach (var depsJsonFile in assemblyDirectory.GetFiles("*.deps.json"))
                {
                    DepsJsonUtils.PatchDepsJson(depsJsonFile, hitServicesAssemblyVersion.ProductVersion);
                }
            }

            result.AddInstrumentedAssembly(instrumentedAssembly);

            File.Delete(instrumentedAssembly.TempAssemblyFile);
            File.Delete(instrumentedAssembly.TempPdbFile);
        }
Esempio n. 2
0
        private void VisitAssemblyGroup(IEnumerable <string> assemblyFiles)
        {
            var firstAssemblyFile = assemblyFiles.First();

            var instrumentedAssembly = InstrumentAssemblyIfNecessary(firstAssemblyFile);

            if (instrumentedAssembly == null)
            {
                return;
            }

            foreach (var assemblyFile in assemblyFiles)
            {
                var pdbFile            = GetPdbFile(assemblyFile);
                var assemblyBackupFile = GetBackupFile(assemblyFile);
                var pdbBackupFile      = GetBackupFile(pdbFile);

                //Backup
                File.Copy(assemblyFile, assemblyBackupFile, true);
                File.Copy(pdbFile, pdbBackupFile, true);

                //Override assembly
                File.Copy(instrumentedAssembly.TempAssemblyFile, assemblyFile, true);
                File.Copy(instrumentedAssembly.TempPdbFile, pdbFile, true);

                //Copy instrumentation dependencies
                var assemblyDirectory = Path.GetDirectoryName(assemblyFile);

                foreach (var dependencyPath in instrumentationDependencies)
                {
                    var dependencyAssemblyName = Path.GetFileName(dependencyPath);
                    var newDependencyPath      = Path.Combine(assemblyDirectory, dependencyAssemblyName);
                    File.Copy(dependencyPath, newDependencyPath, true);
                    result.AddExtraAssembly(newDependencyPath);
                }

                instrumentedAssembly.AddLocation(
                    Path.GetFullPath(assemblyFile),
                    Path.GetFullPath(assemblyBackupFile),
                    Path.GetFullPath(pdbFile),
                    Path.GetFullPath(pdbBackupFile)
                    );

                foreach (var depsJsonFile in Directory.GetFiles(assemblyDirectory, "*.deps.json"))
                {
                    DepsJsonUtils.PatchDepsJson(depsJsonFile);
                }
            }

            result.AddInstrumentedAssembly(instrumentedAssembly);

            File.Delete(instrumentedAssembly.TempAssemblyFile);
            File.Delete(instrumentedAssembly.TempPdbFile);
        }
Esempio n. 3
0
        private void VisitAssemblyGroup(IEnumerable <string> assemblyFiles)
        {
            var firstAssemblyFile = assemblyFiles.First();

            var instrumentedAssembly = InstrumentAssemblyIfNecessary(firstAssemblyFile);

            if (instrumentedAssembly == null)
            {
                return;
            }

            foreach (var assemblyFile in assemblyFiles)
            {
                var pdbFile            = GetPdbFile(assemblyFile);
                var assemblyBackupFile = GetBackupFile(assemblyFile);
                var pdbBackupFile      = GetBackupFile(pdbFile);

                //Backup
                File.Copy(assemblyFile, assemblyBackupFile, true);
                File.Copy(pdbFile, pdbBackupFile, true);

                //Override assembly
                File.Copy(instrumentedAssembly.TempAssemblyFile, assemblyFile, true);
                File.Copy(instrumentedAssembly.TempPdbFile, pdbFile, true);

                //Copy instrumentation dependencies
                var assemblyDirectory        = Path.GetDirectoryName(assemblyFile);
                var miniCoverAssemblyPath    = typeof(HitService).GetTypeInfo().Assembly.Location;
                var miniCoverAssemblyName    = Path.GetFileName(miniCoverAssemblyPath);
                var newMiniCoverAssemblyPath = Path.Combine(assemblyDirectory, miniCoverAssemblyName);
                File.Copy(miniCoverAssemblyPath, newMiniCoverAssemblyPath, true);
                result.AddExtraAssembly(newMiniCoverAssemblyPath);

                instrumentedAssembly.AddLocation(
                    Path.GetFullPath(assemblyFile),
                    Path.GetFullPath(assemblyBackupFile),
                    Path.GetFullPath(pdbFile),
                    Path.GetFullPath(pdbBackupFile)
                    );
            }

            result.AddInstrumentedAssembly(instrumentedAssembly);

            File.Delete(instrumentedAssembly.TempAssemblyFile);
            File.Delete(instrumentedAssembly.TempPdbFile);
        }
Esempio n. 4
0
        /// <summary>
        /// An assembly group is a set of assemblies that are identical (the same file hash). This method makes sure we only instrument the first assembly in the group, to avoid unnecessary overhead.
        /// </summary>
        private void VisitAssemblyGroup(
            IInstrumentationContext context,
            InstrumentationResult result,
            IReadOnlyCollection <IFileInfo> assemblyFiles)
        {
            using (_logger.BeginScope("Checking assembly files {assemblies}", assemblyFiles.Select(f => f.FullName)))
            {
                var instrumentedAssembly = _assemblyInstrumenter.InstrumentAssemblyFile(
                    context,
                    assemblyFiles.First());

                if (instrumentedAssembly == null)
                {
                    return;
                }

                _logger.LogTrace("Temporary assembly file: {tempAssemblyFile}", instrumentedAssembly.TempAssemblyFile);
                _logger.LogTrace("Temporary PDB file: {tempPdbFile}", instrumentedAssembly.TempPdbFile);

                foreach (var assemblyFile in assemblyFiles)
                {
                    _logger.LogDebug("Instrumenting assembly file {assemblyFile}", assemblyFile.FullName);

                    if (_loadedAssemblyFiles.Contains(assemblyFile.FullName))
                    {
                        _logger.LogInformation("Skipping loaded assembly {assemblyFile}", assemblyFile.FullName);
                        continue;
                    }

                    var pdbFile            = FileUtils.GetPdbFile(assemblyFile);
                    var assemblyBackupFile = FileUtils.GetBackupFile(assemblyFile);
                    var pdbBackupFile      = FileUtils.GetBackupFile(pdbFile);

                    _logger.LogTrace("PDB file: {pdbFileName}", pdbFile.FullName);
                    _logger.LogTrace("Assembly backup file: {assemblyBackupFileName}", assemblyBackupFile.FullName);
                    _logger.LogTrace("PDB backup file: {pdbBackupFileName}", pdbBackupFile.FullName);

                    //Backup
                    _fileSystem.File.Copy(assemblyFile.FullName, assemblyBackupFile.FullName, true);
                    _fileSystem.File.Copy(pdbFile.FullName, pdbBackupFile.FullName, true);

                    //Override assembly
                    _fileSystem.File.Copy(instrumentedAssembly.TempAssemblyFile, assemblyFile.FullName, true);
                    _fileSystem.File.Copy(instrumentedAssembly.TempPdbFile, pdbFile.FullName, true);

                    //Copy instrumentation dependencies
                    var assemblyDirectory = assemblyFile.Directory;
                    _logger.LogTrace("Assembly directory: {assemblyDirectory}", assemblyDirectory.FullName);

                    var hitServicesPath    = Path.GetFileName(hitServicesAssembly.Location);
                    var newHitServicesPath = Path.Combine(assemblyDirectory.FullName, hitServicesPath);
                    _fileSystem.File.Copy(hitServicesAssembly.Location, newHitServicesPath, true);
                    result.AddExtraAssembly(newHitServicesPath);

                    instrumentedAssembly.AddLocation(
                        assemblyFile.FullName,
                        assemblyBackupFile.FullName,
                        pdbFile.FullName,
                        pdbBackupFile.FullName
                        );

                    var hitServicesAssemblyVersion = FileVersionInfo.GetVersionInfo(hitServicesAssembly.Location);
                    foreach (var depsJsonFile in assemblyDirectory.GetFiles("*.deps.json"))
                    {
                        _depsJsonUtils.PatchDepsJson(depsJsonFile, hitServicesAssemblyVersion.ProductVersion);
                    }
                }

                result.AddInstrumentedAssembly(instrumentedAssembly);

                _fileSystem.File.Delete(instrumentedAssembly.TempAssemblyFile);
                _fileSystem.File.Delete(instrumentedAssembly.TempPdbFile);
            }
        }
Esempio n. 5
0
        private void VisitAssemblyGroup(
            InstrumentationContext context,
            InstrumentationResult result,
            IEnumerable <FileInfo> assemblyFiles)
        {
            using (_logger.BeginScope("Checking assembly files {assemblies}", assemblyFiles.Select(f => f.FullName), LogLevel.Information))
            {
                var instrumentedAssembly = _assemblyInstrumenter.InstrumentAssemblyFile(
                    context,
                    assemblyFiles.First());

                if (instrumentedAssembly == null)
                {
                    return;
                }

                foreach (var assemblyFile in assemblyFiles)
                {
                    if (_loadedAssemblyFiles.Contains(assemblyFile.FullName))
                    {
                        _logger.LogInformation("Skipping loaded assembly {assemblyFile}", assemblyFile.FullName);
                        continue;
                    }

                    var pdbFile            = FileUtils.GetPdbFile(assemblyFile);
                    var assemblyBackupFile = FileUtils.GetBackupFile(assemblyFile);
                    var pdbBackupFile      = FileUtils.GetBackupFile(pdbFile);

                    //Backup
                    File.Copy(assemblyFile.FullName, assemblyBackupFile.FullName, true);
                    File.Copy(pdbFile.FullName, pdbBackupFile.FullName, true);

                    //Override assembly
                    File.Copy(instrumentedAssembly.TempAssemblyFile, assemblyFile.FullName, true);
                    File.Copy(instrumentedAssembly.TempPdbFile, pdbFile.FullName, true);

                    //Copy instrumentation dependencies
                    var assemblyDirectory = assemblyFile.Directory;

                    var hitServicesPath    = Path.GetFileName(hitServicesAssembly.Location);
                    var newHitServicesPath = Path.Combine(assemblyDirectory.FullName, hitServicesPath);
                    File.Copy(hitServicesAssembly.Location, newHitServicesPath, true);
                    result.AddExtraAssembly(newHitServicesPath);

                    instrumentedAssembly.AddLocation(
                        assemblyFile.FullName,
                        assemblyBackupFile.FullName,
                        pdbFile.FullName,
                        pdbBackupFile.FullName
                        );

                    var hitServicesAssemblyVersion = FileVersionInfo.GetVersionInfo(hitServicesAssembly.Location);
                    foreach (var depsJsonFile in assemblyDirectory.GetFiles("*.deps.json"))
                    {
                        DepsJsonUtils.PatchDepsJson(depsJsonFile, hitServicesAssemblyVersion.ProductVersion);
                    }
                }

                result.AddInstrumentedAssembly(instrumentedAssembly);

                File.Delete(instrumentedAssembly.TempAssemblyFile);
                File.Delete(instrumentedAssembly.TempPdbFile);
            }
        }
Esempio n. 6
0
        private void InstrumentAssembly(string assemblyFile)
        {
            var pdbFile = Path.ChangeExtension(assemblyFile, "pdb");

            if (!File.Exists(pdbFile))
            {
                return;
            }

            if (assemblyFile.EndsWith("uninstrumented.dll"))
            {
                return;
            }

            var assemblyBackupFile = Path.ChangeExtension(assemblyFile, "uninstrumented.dll");

            if (File.Exists(assemblyBackupFile))
            {
                File.Copy(assemblyBackupFile, assemblyFile, true);
            }

            var pdbBackupFile = Path.ChangeExtension(pdbFile, "uninstrumented.pdb");

            if (File.Exists(pdbBackupFile))
            {
                File.Copy(pdbBackupFile, pdbFile, true);
            }

            if (!HasSourceFiles(assemblyFile))
            {
                return;
            }

            if (IsInstrumented(assemblyFile))
            {
                throw new Exception($"Assembly \"{assemblyFile}\" is already instrumented");
            }

            Console.WriteLine($"Instrumenting assembly \"{assemblyFile}\"");

            File.Copy(assemblyFile, assemblyBackupFile, true);
            File.Copy(pdbFile, pdbBackupFile, true);

            var assemblyDirectory = Path.GetDirectoryName(assemblyFile);

            var resolver = new DefaultAssemblyResolver();

            resolver.AddSearchDirectory(assemblyDirectory);

            using (var assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyBackupFile, new ReaderParameters {
                ReadSymbols = true, AssemblyResolver = resolver
            }))
            {
                var instrumentedAssembly = result.AddInstrumentedAssembly(
                    assemblyDefinition.Name.Name,
                    Path.GetFullPath(assemblyBackupFile),
                    Path.GetFullPath(assemblyFile),
                    Path.GetFullPath(pdbBackupFile),
                    Path.GetFullPath(pdbFile)
                    );

                var instrumentedConstructor = typeof(InstrumentedAttribute).GetConstructors().First();
                var instrumentedReference   = assemblyDefinition.MainModule.ImportReference(instrumentedConstructor);
                assemblyDefinition.CustomAttributes.Add(new CustomAttribute(instrumentedReference));

                var miniCoverAssemblyPath    = typeof(HitService).GetTypeInfo().Assembly.Location;
                var miniCoverAssemblyName    = Path.GetFileName(miniCoverAssemblyPath);
                var newMiniCoverAssemblyPath = Path.Combine(assemblyDirectory, miniCoverAssemblyName);
                File.Copy(miniCoverAssemblyPath, newMiniCoverAssemblyPath, true);
                result.AddExtraAssembly(newMiniCoverAssemblyPath);

                CreateAssemblyInit(assemblyDefinition);

                var hitMethodInfo      = typeof(HitService).GetMethod("Hit");
                var hitMethodReference = assemblyDefinition.MainModule.ImportReference(hitMethodInfo);

                var methods = assemblyDefinition.GetAllMethods();

                var documentsGroups = methods
                                      .SelectMany(m => m.DebugInformation.SequencePoints, (m, s) => new
                {
                    Method        = m,
                    SequencePoint = s,
                    Document      = s.Document
                })
                                      .GroupBy(j => j.Document)
                                      .ToArray();

                foreach (var documentGroup in documentsGroups)
                {
                    var sourceRelativePath = GetSourceRelativePath(documentGroup.Key.Url);
                    if (sourceRelativePath == null)
                    {
                        continue;
                    }

                    if (documentGroup.Key.FileHasChanged())
                    {
                        Console.WriteLine($"Ignoring modified file \"{documentGroup.Key.Url}\"");
                        continue;
                    }

                    var fileLines = File.ReadAllLines(documentGroup.Key.Url);

                    var methodGroups = documentGroup
                                       .GroupBy(j => j.Method, j => j.SequencePoint)
                                       .ToArray();

                    foreach (var methodGroup in methodGroups)
                    {
                        var ilProcessor = methodGroup.Key.Body.GetILProcessor();

                        ilProcessor.Body.SimplifyMacros();

                        var instructions = methodGroup.Key.Body.Instructions.ToDictionary(i => i.Offset);

                        foreach (var sequencePoint in methodGroup)
                        {
                            var code = ExtractCode(fileLines, sequencePoint);
                            if (code == null || code == "{" || code == "}")
                            {
                                continue;
                            }

                            var instruction = instructions[sequencePoint.Offset];

                            // if the previous instruction is a Prefix instruction then this instruction MUST go with it.
                            // we cannot put an instruction between the two.
                            if (instruction.Previous != null && instruction.Previous.OpCode.OpCodeType == OpCodeType.Prefix)
                            {
                                return;
                            }

                            var instructionId = ++id;

                            instrumentedAssembly.AddInstruction(sourceRelativePath, new InstrumentedInstruction
                            {
                                Id             = instructionId,
                                StartLine      = sequencePoint.StartLine,
                                EndLine        = sequencePoint.EndLine,
                                StartColumn    = sequencePoint.StartColumn,
                                EndColumn      = sequencePoint.EndColumn,
                                Assembly       = assemblyDefinition.Name.Name,
                                Class          = methodGroup.Key.DeclaringType.FullName,
                                Method         = methodGroup.Key.Name,
                                MethodFullName = methodGroup.Key.FullName,
                                Instruction    = instruction.ToString()
                            });

                            InstrumentInstruction(instructionId, instruction, hitMethodReference, methodGroup.Key, ilProcessor);
                        }

                        ilProcessor.Body.OptimizeMacros();
                    }
                }

                assemblyDefinition.Write(assemblyFile, new WriterParameters {
                    WriteSymbols = true
                });
            }
        }