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); }
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); }
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); }
/// <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); } }
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); } }
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 }); } }