High performance tracer class which enables method enter/leave tracing with duration and other features.
        public ISymbolReader LoadPdbForModule(ModuleDefinition module)
        {
            using (Tracer t = new Tracer(myType, "LoadPdbForModule"))
            {
                string fileName = module.Assembly.MainModule.FullyQualifiedName;
                t.Info("Module file name: {0}", fileName);
                ISymbolReader reader = null;

                if (!this.myFile2PdbMap.TryGetValue(fileName, out reader))
                {
                    if (this.myFailedPdbs.Contains(fileName))
                    {
                        t.Warning("This pdb could not be successfully downloaded");
                        return reader;
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        try
                        {
                            reader = this.myPdbFactory.GetSymbolReader(module, fileName);
                            this.myFile2PdbMap[fileName] = reader;
                            break;
                        }
                        catch (Exception ex)
                        {
                            t.Error(Level.L3, ex, "Pdb did not match or it is not present");

                            string pdbFileName = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".pdb");
                            try
                            {
                                File.Delete(pdbFileName);
                            }
                            catch (Exception delex)
                            {
                                t.Error(Level.L2, delex, "Could not delete pdb {0}", pdbFileName);
                            }

                            // When we have symbol server we try to make us of it for matches.
                            if (String.IsNullOrEmpty(this.mySymbolServer))
                            {
                                break;
                            }

                            t.Info("Try to download pdb from symbol server {0}", this.mySymbolServer);
                            bool bDownloaded = this.myDownLoader.DownloadPdbs(new FileQuery(fileName), this.mySymbolServer);
                            t.Info("Did download pdb {0} from symbol server with return code: {1}", fileName, bDownloaded);

                            if (bDownloaded == false || i == 1) // second try did not work out as well
                            {
                                this.myFailedPdbs.Add(fileName);
                                break;
                            }
                        }
                    }
                }

                return reader;
            }
        }
        public static AssemblyDefinition LoadCecilAssembly(string fileName, bool immediateLoad = false, bool? readSymbols = null)
        {
            using (var t = new Tracer(Level.L5, myType, "LoadCecilAssembly"))
            {
                var pdbPath = Path.ChangeExtension(fileName, "pdb");
                var tryReadSymbols = readSymbols ?? File.Exists(pdbPath);
                var fileInfo = new FileInfo(fileName);
                if (fileInfo.Length == 0)
                {
                    t.Info("File {0} has zero byte length", fileName);
                    return null;
                }

                try
                {
                    var readingMode = immediateLoad ? ReadingMode.Immediate : ReadingMode.Deferred;
                    var assemblyResolver = new DefaultAssemblyResolver();
                    assemblyResolver.AddSearchDirectory(fileInfo.Directory.FullName);
                    var readerParameters = new ReaderParameters { ReadSymbols = tryReadSymbols, ReadingMode = readingMode, AssemblyResolver = assemblyResolver };
                    var assemblyDef = AssemblyDefinition.ReadAssembly(fileName, readerParameters);

                    // Managed C++ assemblies are not supported by Mono Cecil
                    if (IsManagedCppAssembly(assemblyDef))
                    {
                        t.Info("File {0} is a managed C++ assembly", fileName);
                        return null;
                    }

                    return assemblyDef;
                }
                catch (BadImageFormatException) // Ignore invalid images
                {
                }
                catch (IndexOutOfRangeException)
                {
                    t.Info("File {0} is a managed C++ assembly", fileName);
                }
                catch (NullReferenceException) // ignore managed c++ targets
                {
                    t.Info("File {0} is a managed C++ assembly", fileName);
                }
                catch (ArgumentOutOfRangeException)
                {
                    t.Info("File {0} is a managed C++ assembly", fileName);
                }
                catch (Exception ex)
                {
                    t.Error(Level.L1, "Could not read assembly {0}: {1}", fileName, ex);
                }

                return null;
            }
        }
        /// <summary>
        ///     Patch after the pdb was downloaded the drive letter to match the pdb files with the source files
        /// </summary>
        /// <param name="downLoadThreadCount">Down load thread count.</param>
        public PdbDownLoader(int downLoadThreadCount)
        {
            using (var t = new Tracer(myType, "PdbDownLoader"))
            {
                this.FailedPdbs = new List<string>();
                if (downLoadThreadCount <= 0)
                {
                    throw new ArgumentException("The download thread count cannot be <= 0");
                }

                this.myDownLoadThreadCount = downLoadThreadCount;
                t.Info("Download thread count is {0}", this.myDownLoadThreadCount);
            }
        }
        public WhoUsesType(UsageQueryAggregator aggregator, List<TypeDefinition> funcArgTypes) : base(aggregator)
        {
            using (var t = new Tracer(Level.L5, myType, "WhoUsesType"))
            {
                if (funcArgTypes == null)
                {
                    throw new ArgumentNullException("funcArgTypes");
                }

                this.mySearchArgTypes = funcArgTypes;

                foreach (var funcArgType in funcArgTypes)
                {
                    t.Info("Adding search type {0}", new LazyFormat(() => funcArgType.Print()));
                    this.myArgSearchTypeNames.Add(funcArgType.Name);
                    this.Aggregator.AddVisitScope(funcArgType.Module.Assembly.Name.Name);
                    new WhoAccessesField(aggregator, notConst.GetMatchingFields(funcArgType));
                }
            }
        }
 private void DeleteOldPdb(string binaryName)
 {
     using (var t = new Tracer(Level.L5, myType, "DeleteOldPdb"))
     {
         var pdbFile = GetPdbNameFromBinaryName(binaryName);
         t.Info("Try to delete pdb {0} for binary {1}", pdbFile, binaryName);
         try
         {
             File.Delete(pdbFile);
         }
         catch (FileNotFoundException ex)
         {
             t.Error(ex, "No old pdb file did exist");
         }
         catch (Exception ex)
         {
             t.Error(ex, "Could not delete old pdb file");
         }
     }
 }
        /// <summary>
        ///     Downloads the pdbs from the symbol server.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="symbolServer">The symbol server name.</param>
        /// <param name="downloadDir">The download directory. Can be null.</param>
        /// <returns>
        ///     true if all symbols could be downloaded. False otherwise.
        /// </returns>
        public bool DownloadPdbs(FileQuery query, string symbolServer, string downloadDir)
        {
            using (var t = new Tracer(myType, "DownloadPdbs"))
            {
                var lret = SymChkExecutor.bCanStartSymChk;
                var currentFailCount = this.FailedPdbs.Count;

                var fileQueue = query.EnumerateFiles;
                var aggregator = new BlockingQueueAggregator<string>(fileQueue);

                Action<string> downLoadPdbThread = (string fileName) =>
                {
                    var pdbFileName = GetPdbNameFromBinaryName(fileName);

                    // delete old pdb to ensure that the new matching pdb is really downloaded. Symchk does not replace existing but not matching pdbs.
                    try
                    {
                        File.Delete(pdbFileName);
                    }
                    catch
                    {
                    }

                    if (!this.Executor.DownLoadPdb(fileName, symbolServer, downloadDir))
                    {
                        lock (this.FailedPdbs)
                        {
                            this.FailedPdbs.Add(Path.GetFileName(fileName));
                        }
                    }
                    else
                    {
                        lock (this.FailedPdbs)
                        {
                            this.SucceededPdbCount++;
                        }
                    }
                };

                var dispatcher = new WorkItemDispatcher<string>(this.myDownLoadThreadCount, downLoadPdbThread, "Pdb Downloader", aggregator, WorkItemOptions.AggregateExceptions);

                try
                {
                    dispatcher.Dispose();
                }
                catch (AggregateException ex)
                {
                    t.Error(ex, "Got error during pdb download");
                    lret = false;
                }

                if (this.FailedPdbs.Count > currentFailCount)
                {
                    t.Warning("The failed pdb count has increased by {0}", this.FailedPdbs.Count - currentFailCount);
                    lret = false;
                }

                return lret;
            }
        }
 public void AddMatch(FieldDefinition field, MatchContext context)
 {
     using (var t = new Tracer(myType, "AddMatch_Field"))
     {
         t.Info("Add field {0} {1} defined in {2}", field.DeclaringType.FullName, field.Name, field.DeclaringType.Module.Assembly.Name);
         this.AddMatch(field.DeclaringType.Module.Assembly);
         var declType = (TypeDefinition)field.DeclaringType;
         var fileLine = new KeyValuePair<string, int>("", 0);
         if (this.myPdbReader != null)
         {
             fileLine = this.myPdbReader.GetFileLine(declType);
         }
         this.FieldMatches.Add(new QueryResult<FieldDefinition>(field, fileLine.Key, fileLine.Value, context));
     }
 }
        public void AddMatch(TypeDefinition typeDef, MatchContext context)
        {
            using (var t = new Tracer(myType, "AddMatch_Type"))
            {
                t.Info("Add type {0} defined in {1}", typeDef.FullName, typeDef.Module.Assembly.Name);
                this.AddMatch(typeDef.Module.Assembly);
                var fileLine = new KeyValuePair<string, int>("", 0);
                if (this.myPdbReader != null)
                {
                    fileLine = this.myPdbReader.GetFileLine(typeDef);
                }

                this.TypeMatches.Add(new QueryResult<TypeDefinition>(typeDef, fileLine.Key, fileLine.Value, context));
            }
        }
 public void AddMatch(Instruction ins, MethodDefinition method, bool bSearchForward, MatchContext context)
 {
     using (var t = new Tracer(myType, "AddMatch_Instruction"))
     {
         t.Info("Add match for instruction {0} in method {1} SearchForward {2}", ins, method, bSearchForward);
         var queryResult = this.GetResultWithFileLineIfEnabled(ins, method, bSearchForward, context);
         this.AddMatch(method.DeclaringType.Module.Assembly);
         this.MethodMatches.Add(queryResult);
     }
 }
        /// <summary>
        ///     Analyzes the specified assembly.
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        public void Analyze(AssemblyDefinition assembly)
        {
            using (var t = new Tracer(myType, "Analyze"))
            {
                if (this.myAssemblyReferencesOfInterest.Count == 0 && this.myVisitors.Count > 0)
                {
                    throw new InvalidOperationException("Assembly reference list is empty. The check if the current assembly does reference one of the assemblies can therefore never succeed.  Please call AddVisitScope(string dllName) within your Query ctor or on the Aggregator itself before analysing assemblies. The check is done to prevent searching inside assemblies which do not use parts of other assemblies for performance reasons.");
                }

                t.Info("Analyzing assembly {0}", assembly.Name);
                foreach (ModuleDefinition mod in assembly.Modules)
                {
                    // skip assemblies which do not reference the given assembly
                    // but do include itself into query
                    if (!this.ModuleReferencesAssemblyOrSelf(mod))
                    {
                        t.Info("Current assembly does not reference any assemblies that are checked. Skip other checks.");
                        continue;
                    }

                    foreach (var type in this.myTypeQuery.GetTypes(assembly))
                    {
                        this.myVisitors.ForEach(vis => vis.VisitType(type));

                        foreach (var field in FieldQuery.AllFieldsIncludingCompilerGenerated.GetMatchingFields(type))
                        {
                            this.myVisitors.ForEach(vis => vis.VisitField(field));
                        }

                        foreach (var method in MethodQuery.AllMethods.GetMethods(type))
                        {
                            if (method.HasBody)
                            {
                                this.myVisitors.ForEach(vis => vis.VisitMethodBody(method.Body));
                                if (method.Body.Variables != null)
                                {
                                    this.myVisitors.ForEach(vis => vis.VisitLocals(method.Body.Variables, method));
                                }
                            }
                            this.myVisitors.ForEach(vis => vis.VisitMethod(method));
                        }
                    }

                    if (this.myPdbReader != null)
                    {
                        this.myPdbReader.ReleasePdbForModule(mod);
                    }
                }
            }
        }
        /// <summary>
        /// Get for a specific IL instruction the matching file and line.
        /// </summary>
        /// <param name="ins"></param>
        /// <param name="method"></param>
        /// <param name="bSearchForward">Search the next il instruction first if set to true for the line number from the pdb. If nothing is found we search backward.</param>
        /// <returns></returns>
        public KeyValuePair<string, int> GetFileLine(Instruction ins, MethodDefinition method, bool bSearchForward)
        {
            using (Tracer t = new Tracer(myType, "GetFileLine"))
            {
                t.Info("Try to get file and line info for {0} {1} forwardSearch {2}", method.DeclaringType.FullName, method.Name, bSearchForward);

                var symReader = this.LoadPdbForModule(method.DeclaringType.Module);
                if (symReader != null && method.Body != null)
                {
                    Instruction current = ins;

                    if (bSearchForward)
                    {
                        current = this.GetILInstructionWithLineNumber(ins, true);
                        if (current == null)
                        {
                            current = this.GetILInstructionWithLineNumber(ins, false);
                        }
                    }
                    else
                    {
                        current = this.GetILInstructionWithLineNumber(ins, false);
                        if (current == null)
                        {
                            current = this.GetILInstructionWithLineNumber(ins, true);
                        }
                    }

                    if (current != null)
                    {
                        return new KeyValuePair<string, int>(this.PatchDriveLetter(current.SequencePoint.Document.Url), current.SequencePoint.StartLine);
                    }
                }
                else
                {
                    t.Info("No symbol reader present or method has no body");
                }

                return new KeyValuePair<string, int>("", 0);
            }
        }