private void InstrumentModule() { using (var stream = new FileStream(_module, FileMode.Open, FileAccess.ReadWrite)) using (var resolver = new DefaultAssemblyResolver()) { resolver.AddSearchDirectory(Path.GetDirectoryName(_module)); var parameters = new ReaderParameters { ReadSymbols = true, AssemblyResolver = resolver }; if (_isCoreLibrary) { parameters.MetadataImporterProvider = new CoreLibMetadataImporterProvider(); } using (var module = ModuleDefinition.ReadModule(stream, parameters)) { var containsAppContext = module.GetType(nameof(System), nameof(AppContext)) != null; var types = module.GetTypes(); AddCustomModuleTrackerToModule(module); var sourceLinkDebugInfo = module.CustomDebugInformations.FirstOrDefault(c => c.Kind == CustomDebugInformationKind.SourceLink); if (sourceLinkDebugInfo != null) { _result.SourceLink = ((SourceLinkDebugInformation)sourceLinkDebugInfo).Content; } foreach (TypeDefinition type in types) { var actualType = type.DeclaringType ?? type; if (!actualType.CustomAttributes.Any(IsExcludeAttribute) // Instrumenting Interlocked which is used for recording hits would cause an infinite loop. && (!_isCoreLibrary || actualType.FullName != "System.Threading.Interlocked") && !InstrumentationHelper.IsTypeExcluded(_module, actualType.FullName, _excludeFilters) && InstrumentationHelper.IsTypeIncluded(_module, actualType.FullName, _includeFilters)) { InstrumentType(type); } } // Fixup the custom tracker class constructor, according to all instrumented types if (_customTrackerRegisterUnloadEventsMethod == null) { _customTrackerRegisterUnloadEventsMethod = new MethodReference( nameof(ModuleTrackerTemplate.RegisterUnloadEvents), module.TypeSystem.Void, _customTrackerTypeDef); } Instruction lastInstr = _customTrackerClassConstructorIl.Body.Instructions.Last(); if (!containsAppContext) { // For "normal" cases, where the instrumented assembly is not the core library, we add a call to // RegisterUnloadEvents to the static constructor of the generated custom tracker. Due to static // initialization constraints, the core library is handled separately below. _customTrackerClassConstructorIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Call, _customTrackerRegisterUnloadEventsMethod)); } _customTrackerClassConstructorIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Ldc_I4, _result.HitCandidates.Count)); _customTrackerClassConstructorIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Newarr, module.TypeSystem.Int32)); _customTrackerClassConstructorIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Stsfld, _customTrackerHitsArray)); _customTrackerClassConstructorIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Ldstr, _result.HitsFilePath)); _customTrackerClassConstructorIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Stsfld, _customTrackerHitsFilePath)); if (containsAppContext) { // Handle the core library by instrumenting System.AppContext.OnProcessExit to directly call // the UnloadModule method of the custom tracker type. This avoids loops between the static // initialization of the custom tracker and the static initialization of the hosting AppDomain // (which for the core library case will be instrumented code). var eventArgsType = new TypeReference(nameof(System), nameof(EventArgs), module, module.TypeSystem.CoreLibrary); var customTrackerUnloadModule = new MethodReference(nameof(ModuleTrackerTemplate.UnloadModule), module.TypeSystem.Void, _customTrackerTypeDef); customTrackerUnloadModule.Parameters.Add(new ParameterDefinition(module.TypeSystem.Object)); customTrackerUnloadModule.Parameters.Add(new ParameterDefinition(eventArgsType)); var appContextType = new TypeReference(nameof(System), nameof(AppContext), module, module.TypeSystem.CoreLibrary); var onProcessExitMethod = new MethodReference("OnProcessExit", module.TypeSystem.Void, appContextType).Resolve(); var onProcessExitIl = onProcessExitMethod.Body.GetILProcessor(); lastInstr = onProcessExitIl.Body.Instructions.Last(); onProcessExitIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Ldnull)); onProcessExitIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Ldnull)); onProcessExitIl.InsertBefore(lastInstr, Instruction.Create(OpCodes.Call, customTrackerUnloadModule)); } module.Write(stream, new WriterParameters { WriteSymbols = true }); } } }
public void TestIsTypeExcludedWithoutFilter() { var result = _instrumentationHelper.IsTypeExcluded("Module.dll", "a.b.Dto", new string[0]); Assert.False(result); }
public void TestIsTypeExcludedWithFilter(string filter) { var result = InstrumentationHelper.IsTypeExcluded("Module.dll", "a.b.Dto", new[] { filter }); Assert.True(result); }