/// <summary> /// Returns the list of path names to the NGEN pdbs for any NGEN image in 'etlFile' that has /// any samples in it. /// </summary> internal static List <string> GetNGenPdbs(string etlFile, SymbolReader symbolReader, TextWriter log) { // Generate the NGen images for any NGEN image needing symbolic information. var pdbFileList = new List <string>(100); foreach (var imageName in ETWTraceEventSource.GetModulesNeedingSymbols(etlFile)) { Debug.Assert(0 <= imageName.IndexOf(".ni.", StringComparison.OrdinalIgnoreCase)); var pdbName = symbolReader.GenerateNGenSymbolsForModule(imageName); if (pdbName != null) { pdbFileList.Add(pdbName); log.WriteLine("Found NGEN pdb {0}", pdbName); } } return(pdbFileList); }
/// <summary> /// Returns the list of path names to the NGEN pdbs for any NGEN image in 'etlFile' that has /// any samples in it. /// </summary> internal static List <string> GetNGenPdbs(string etlFile, SymbolReader symbolReader, TextWriter log) { // Generate the NGen images for any NGEN image needing symbolic information. var pdbFileList = new List <string>(100); foreach (var imageName in ETWTraceEventSource.GetModulesNeedingSymbols(etlFile)) { var sw = Stopwatch.StartNew(); var pdbName = symbolReader.GenerateNGenSymbolsForModule(imageName); if (pdbName != null) { pdbFileList.Add(pdbName); log.WriteLine("Found NGEN pdb {0}", pdbName); } log.WriteLine("NGEN PDB creation for {0} took {1:n2} Sec", imageName, sw.Elapsed.TotalSeconds); } return(pdbFileList); }
/// <summary> /// Create an ETWReloggerTraceEventSource that can takes its input from a variety of sources (either a single file, /// a set of files, or a real time ETW session (based on 'type'), and can write these events to a new ETW output /// file 'outputFileName. /// </summary> public ETWReloggerTraceEventSource(string fileOrSessionName, TraceEventSourceType type, string outputFileName) : base() { var version = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor; if (version < 62) { throw new NotSupportedException("System Tracing is only supported on Windows 8 and above."); } m_relogger = new CTraceRelogger(); if (type == TraceEventSourceType.FileOnly) { m_traceHandleForFirstStream = m_relogger.AddLogfileTraceStream(fileOrSessionName, IntPtr.Zero); } else if (type == TraceEventSourceType.Session) { m_traceHandleForFirstStream = m_relogger.AddRealtimeTraceStream(fileOrSessionName, IntPtr.Zero); } else { Debug.Assert(type == TraceEventSourceType.MergeAll); List <string> logFileNames = ETWTraceEventSource.GetMergeAllLogFiles(fileOrSessionName); bool first = true; foreach (var logFileName in logFileNames) { var handle = m_relogger.AddLogfileTraceStream(logFileName, IntPtr.Zero); if (first) { m_traceHandleForFirstStream = handle; first = false; } } } m_relogger.SetOutputFilename(outputFileName); m_myCallbacks = new ReloggerCallbacks(this); m_relogger.RegisterCallback(m_myCallbacks); }
/// <summary> /// Given an ETL file, returns a list of the full paths to DLLs that were loaded in the trace that need symbolic /// information (PDBs) so that the stack traces and CPU samples can be properly resolved. By default this only /// returns NGEN images since these are the ones that need to be resolved and generated at collection time. /// </summary> public static IEnumerable <string> GetModulesNeedingSymbols(string etlFile, ModuleSymbolOptions options = ModuleSymbolOptions.OnlyNGENImages) { var images = new List <ImageData>(300); var addressCounts = new Dictionary <Address, int>(); // Get the name of all DLLS (in the file, and the set of all address-process pairs in the file. using (var source = new ETWTraceEventSource(etlFile)) { source.Kernel.ImageGroup += delegate(ImageLoadTraceData data) { var fileName = data.FileName; if (fileName.IndexOf(".ni.", StringComparison.OrdinalIgnoreCase) < 0) { // READY_TO_RUN support generate PDBs for ready-to-run images. // TODO can rip this out when we don't package ready-to-run images var windowsIdx = fileName.IndexOf(@"\windows\", StringComparison.OrdinalIgnoreCase); if (0 <= windowsIdx && windowsIdx <= 2) { return; } if (!File.Exists(fileName)) { return; } try { using (var peFile = new PEFile.PEFile(fileName)) { if (!peFile.IsManagedReadyToRun) { return; } } } catch { return; } } var processId = data.ProcessID; images.Add(new ImageData(processId, fileName, data.ImageBase, data.ImageSize)); }; source.Kernel.StackWalkStack += delegate(StackWalkStackTraceData data) { if (data.ProcessID == 0) { return; } var processId = data.ProcessID; for (int i = 0; i < data.FrameCount; i++) { var address = (data.InstructionPointer(i) & 0xFFFFFFFFFFFF0000L) + ((Address)(processId & 0xFFFF)); addressCounts[address] = 1; } }; source.Clr.ClrStackWalk += delegate(ClrStackWalkTraceData data) { var processId = data.ProcessID; for (int i = 0; i < data.FrameCount; i++) { var address = (data.InstructionPointer(i) & 0xFFFFFFFFFFFF0000L) + ((Address)(processId & 0xFFFF)); addressCounts[address] = 1; } }; source.Kernel.PerfInfoSample += delegate(SampledProfileTraceData data) { if (data.ProcessID == 0) { return; } var processId = data.ProcessID; var address = (data.InstructionPointer & 0xFFFFFFFFFFFF0000L) + ((Address)(processId & 0xFFFF)); addressCounts[address] = 1; }; source.Process(); } // imageNames is a set of names that we want symbols for. var imageNames = new Dictionary <string, string>(100); foreach (var image in images) { if (!imageNames.ContainsKey(image.DllName)) { for (uint offset = 0; offset < (uint)image.Size; offset += 0x10000) { var key = image.BaseAddress + offset + (uint)(image.ProcessID & 0xFFFF); if (addressCounts.ContainsKey(key)) { imageNames[image.DllName] = image.DllName; break; } } } } // Find the PDBS for the given images. return(new List <string>(imageNames.Keys)); }