public StackView(TraceLog traceLog, StackSource stackSource, SymbolReader symbolReader) { _traceLog = traceLog; _rawStackSource = stackSource; _symbolReader = symbolReader; LookupWarmNGENSymbols(); }
public ExceptionViewModel(ExceptionTraceData data, TraceCallStack stack, SymbolReader reader) { _data = data; _stack = stack; _reader = reader; ProcessName = GetProcessName(); }
static SymbolReader CreateCore(PdbReaderContext pdbContext, Metadata metadata, DataReaderFactory pdbStream) { SymbolReader symReader = null; bool error = true; try { if (!pdbContext.HasDebugInfo) { return(null); } if ((pdbContext.Options & PdbReaderOptions.MicrosoftComReader) != 0 && pdbStream is not null && IsWindowsPdb(pdbStream.CreateReader())) { symReader = Dss.SymbolReaderWriterFactory.Create(pdbContext, metadata, pdbStream); } else { symReader = CreateManaged(pdbContext, metadata, pdbStream); } if (symReader is not null) { error = false; return(symReader); } }
/// <summary> /// Print data. Note that this method is called FROM DIFFERNET THREADS which means you need to properly /// lock any read-write data you access. It turns out Out.Writeline is already thread safe so /// there is nothing I have to do in this case. /// </summary> private static void Print(TraceEvent data, SymbolReader symbolReader) { // There are a lot of data collection start on entry that I don't want to see (but often they are quite handy if (data.Opcode == TraceEventOpcode.DataCollectionStart) { return; } // V3.5 runtimes don't log the stack and in fact don't event log the exception name (it shows up as an empty string) // Just ignore these as they are not that interesting. if (data is ExceptionTraceData && ((ExceptionTraceData)data).ExceptionType.Length == 0) { return; } if (!data.ProcessName.Contains("Samples")) { return; } Out.WriteLine("EVENT: {0}", data.ToString()); var callStack = data.CallStack(); if (callStack != null) { // Because symbol lookup is complex, error prone, and expensive TraceLog requires you to be explicit. // Here we look up names in this call stack using the symbol reader. ResolveNativeCode(callStack, symbolReader); Out.WriteLine("CALLSTACK: {0}", callStack.ToString()); } }
private static void ConvertToSpeedscope(string fileToConvert) { var symbolReader = new SymbolReader(System.IO.TextWriter.Null) { SymbolPath = SymbolPath.MicrosoftSymbolServerPath }; var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert); var eventLog = new TraceLog(etlxFilePath); try { var stackSource = new MutableTraceEventStackSource(eventLog) { OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks. }; var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader); computer.GenerateThreadTimeStacks(stackSource); var speedScopeFilePath = Path.ChangeExtension(fileToConvert, "speedscope.json"); SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, speedScopeFilePath); } finally { eventLog.Dispose(); if (File.Exists(etlxFilePath)) { File.Delete(etlxFilePath); } } }
public AllocationTickMemoryProfiler(TraceEventSession session, int pid, ProcessAllocationInfo allocations, bool verbose = false) { if (session == null) { throw new NullReferenceException(nameof(session)); } _session = session; if (allocations == null) { throw new NullReferenceException(nameof(allocations)); } _allocations = allocations; _pid = pid; _verbose = verbose; _symbolLookupMessages = new StringWriter(); // By default a symbol Reader uses whatever is in the _NT_SYMBOL_PATH variable. However you can override // if you wish by passing it to the SymbolReader constructor. Since we want this to work even if you // have not set an _NT_SYMBOL_PATH, so we add the Microsoft default symbol server path to be sure/ var symbolPath = new SymbolPath(SymbolPath.SymbolPathFromEnvironment).Add(SymbolPath.MicrosoftSymbolServerPath); _symbolReader = new SymbolReader(_symbolLookupMessages, symbolPath.ToString()); // By default the symbol reader will NOT read PDBs from 'unsafe' locations (like next to the EXE) // because hackers might make malicious PDBs. If you wish ignore this threat, you can override this // check to always return 'true' for checking that a PDB is 'safe'. _symbolReader.SecurityCheck = (path => true); }
private static void PrintStack(TraceCallStack callStack, SymbolReader symbolReader) { Out.WriteLine("STACKTRACE:"); while (callStack != null) { var method = callStack.CodeAddress.Method; var module = callStack.CodeAddress.ModuleFile; if (method != null) { // see if we can get line number information var lineInfo = ""; var sourceLocation = callStack.CodeAddress.GetSourceLine(symbolReader); if (sourceLocation != null) { lineInfo = string.Format(" AT: {0}({1})", Path.GetFileName(sourceLocation.SourceFile.BuildTimeFilePath), sourceLocation.LineNumber); } Out.WriteLine(" Method: {0}!{1}{2}", module.Name, method.FullMethodName, lineInfo); } else if (module != null) { Out.WriteLine(" Module: {0}!0x{1:x}", module.Name, callStack.CodeAddress.Address); } else { Out.WriteLine(" ?!0x{0:x}", callStack.CodeAddress.Address); } callStack = callStack.Caller; } }
internal AutomatedAnalysisExecutionContext(TraceLog traceLog, TextWriter textLog, SymbolReader symbolReader, AutomatedAnalysisIssueCollection issues) { TraceLog = traceLog; TextLog = textLog; SymbolReader = symbolReader; Issues = issues; }
// Method copied from https://github.com/dotnet/diagnostics/blob/2c23d3265dd8f642a8d6cf4bb8a135a5ff8b00c2/src/Tools/dotnet-trace/TraceFileFormatConverter.cs#L64 private static void ConvertToSpeedscope(string fileToConvert, string outputFilename, bool continueOnError = false) { var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert, null, new TraceLogOptions() { ContinueOnError = continueOnError }); using (var symbolReader = new SymbolReader(System.IO.TextWriter.Null) { SymbolPath = SymbolPath.MicrosoftSymbolServerPath }) using (var eventLog = new TraceLog(etlxFilePath)) { var stackSource = new MutableTraceEventStackSource(eventLog) { OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks. }; var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader) { IncludeEventSourceEvents = false // SpeedScope handles only CPU samples, events are not supported }; computer.GenerateThreadTimeStacks(stackSource); SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, outputFilename); } if (File.Exists(etlxFilePath)) { File.Delete(etlxFilePath); } }
public StackViewerSession(string filename, string stacktype, TraceLog tracelog, FilterParams filterParams, SymbolReader reader) { if (filename == null) { ThrowHelper.ThrowArgumentNullException(nameof(filename)); } if (stacktype == null) { ThrowHelper.ThrowArgumentNullException(nameof(stacktype)); } if (tracelog == null) { ThrowHelper.ThrowArgumentNullException(nameof(tracelog)); } if (filterParams == null) { ThrowHelper.ThrowArgumentNullException(nameof(filterParams)); } if (reader == null) { ThrowHelper.ThrowArgumentNullException(nameof(reader)); } this.Filename = filename; this.StackType = stacktype; this.FilterParams = filterParams; this.TraceLog = tracelog; this.reader = reader; this.Pending = true; }
private static void ConvertToSpeedscope(string fileToConvert, string outputFilename) { var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert); using (var symbolReader = new SymbolReader(System.IO.TextWriter.Null) { SymbolPath = SymbolPath.MicrosoftSymbolServerPath }) using (var eventLog = new TraceLog(etlxFilePath)) { var stackSource = new MutableTraceEventStackSource(eventLog) { OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks. }; var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader); computer.GenerateThreadTimeStacks(stackSource); SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, outputFilename); } if (File.Exists(etlxFilePath)) { File.Delete(etlxFilePath); } }
private string GetDacFile(ClrInfo clrInfo) { if (_dacFilePath == null) { Debug.Assert(!string.IsNullOrEmpty(clrInfo.DacInfo.FileName)); var analyzeContext = _serviceProvider.GetService <AnalyzeContext>(); string dacFilePath = null; if (!string.IsNullOrEmpty(analyzeContext.RuntimeModuleDirectory)) { dacFilePath = Path.Combine(analyzeContext.RuntimeModuleDirectory, clrInfo.DacInfo.FileName); if (File.Exists(dacFilePath)) { _dacFilePath = dacFilePath; } } if (_dacFilePath == null) { dacFilePath = clrInfo.LocalMatchingDac; if (!string.IsNullOrEmpty(dacFilePath) && File.Exists(dacFilePath)) { _dacFilePath = dacFilePath; } else if (SymbolReader.IsSymbolStoreEnabled()) { string dacFileName = Path.GetFileName(dacFilePath ?? clrInfo.DacInfo.FileName); if (dacFileName != null) { SymbolStoreKey key = null; if (clrInfo.ModuleInfo.BuildId != null) { IEnumerable <SymbolStoreKey> keys = ELFFileKeyGenerator.GetKeys( KeyTypeFlags.DacDbiKeys, clrInfo.ModuleInfo.FileName, clrInfo.ModuleInfo.BuildId, symbolFile: false, symbolFileName: null); key = keys.SingleOrDefault((k) => Path.GetFileName(k.FullPathName) == dacFileName); } else { // Use the coreclr.dll's id (timestamp/filesize) to download the the dac module. key = PEFileKeyGenerator.GetKey(dacFileName, clrInfo.ModuleInfo.TimeStamp, clrInfo.ModuleInfo.FileSize); } if (key != null) { // Now download the DAC module from the symbol server _dacFilePath = SymbolReader.GetSymbolFile(key); } } } if (_dacFilePath == null) { throw new FileNotFoundException($"Could not find matching DAC for this runtime: {clrInfo.ModuleInfo.FileName}"); } } _isDesktop = clrInfo.Flavor == ClrFlavor.Desktop; } return(_dacFilePath); }
/// <summary> /// Looks up symbols for all modules that have an inclusive count >= minCount. /// stackSource, if given, can be used to be the filter. If null, 'this' is used. /// If stackSource is given, it needs to use the same indexes for frames as 'this' /// </summary> public void LookupWarmSymbols(int minCount, SymbolReader reader, StackSource stackSource = null) { if (stackSource == null) { stackSource = this; } Debug.Assert(stackSource.CallFrameIndexLimit == this.CallFrameIndexLimit); Debug.Assert(stackSource.CallStackIndexLimit == this.CallStackIndexLimit); reader.Log.WriteLine("Resolving all symbols for modules with inclusive times > {0}", minCount); if ((reader.Flags & SymbolReaderFlags.CacheOnly) != 0) { reader.Log.WriteLine("Cache-Only set: will only look on the local machine."); } // Get a list of all the unique frames. We also keep track of unique stacks for efficiency var stackModuleLists = new ModuleList[stackSource.CallStackIndexLimit]; var stackCounts = new int[stackSource.CallStackIndexLimit]; var totalCount = 0; // Compute for each stack, the set of inclusive modules for that stack stackSource.ProduceSamples(delegate(StackSourceSample sample) { stackCounts[(int)sample.StackIndex]++; totalCount++; }); reader.Log.WriteLine("Got a total of {0} samples", totalCount); // for each stack in the trace, find the list of modules for that stack var moduleCounts = new int[TraceLog.ModuleFiles.MaxModuleFileIndex]; for (int i = 0; i < stackCounts.Length; i++) { var count = stackCounts[i]; if (count > 0) { var modules = GetModulesForStack(stackModuleLists, (StackSourceCallStackIndex)i); // Update the counts for each module in that stack. while (modules != null) { moduleCounts[(int)modules.Module.ModuleFileIndex] += count; modules = modules.Next; } } } // Now that we have an list of the inclusive counts of all frames. Find all stacks that meet the threshold for (int i = 0; i < moduleCounts.Length; i++) { if (moduleCounts[i] >= minCount) { var moduleFile = TraceLog.ModuleFiles[(ModuleFileIndex)i]; reader.Log.WriteLine("Resolving symbols (count={0}) for module {1} ", moduleCounts[i], moduleFile.FilePath); TraceLog.CallStacks.CodeAddresses.LookupSymbolsForModule(reader, moduleFile); } } reader.Log.WriteLine("Done Resolving all symbols for modules with inclusive times > {0}", minCount); }
public void SymbolsTest() { var m = new SymbolReader(@"C:\Symbols\coreclr.pdb"); var s = m.GetSymbol("g_pGCHeap"); Assert.NotNull(s); }
public void ValidCurrencySymbolTests(string currency) { // When bool actualResults = SymbolReader.IsSymbolValid(currency); // Then Assert.True(actualResults); }
public PortableSymbolModule(SymbolReader reader, Stream stream, string pdbFileName = "") : base(reader, pdbFileName) { _stream = stream; _provider = MetadataReaderProvider.FromPortablePdbStream(_stream); _metaData = _provider.GetMetadataReader(); InitializeFileToUrlMap(); }
/// <summary> /// Attempts to download/retrieve from cache the key. /// </summary> /// <param name="key">index of the file to retrieve</param> /// <returns>stream or null</returns> public SymbolStoreFile GetSymbolStoreFile(SymbolStoreKey key) { if (IsSymbolStoreEnabled) { return(SymbolReader.GetSymbolStoreFile(key)); } return(null); }
/// <summary> /// Process the data in 'dataFileName' printing the events and doing delta computation between 'MyFirstEvent' /// and 'MySecondEvent'. /// </summary> static void ProcessData(string dataFileName) { Out.WriteLine("************** Creating a ETLX file for {0}", dataFileName); // Note the OpenOrConvert will take an ETL file and generate an ETLX (right next to it) if it is out of date. // We TraceLogOptions gives you control over this conversion. Here we spew the log file to the console var traceLog = TraceLog.OpenOrConvert(dataFileName, new TraceLogOptions() { ConversionLog = Out }); Out.WriteLine("************** Done converting", Path.GetFileName(traceLog.FilePath)); // The OS process ID of this process var myProcessID = Process.GetCurrentProcess().Id; // Find myself in th trace. var simpleTraceLogProcess = traceLog.Processes.LastProcessWithID(myProcessID); Debug.Assert(simpleTraceLogProcess != null); // Resolve symbols for clr and ntdll using the standard Microsoft symbol server path. var symbolReader = new SymbolReader(Out, SymbolPath.MicrosoftSymbolServerPath); foreach (var module in simpleTraceLogProcess.LoadedModules) { if (module.Name == "clr" || module.Name == "ntdll" || module.Name == "mscorlib.ni") { traceLog.CodeAddresses.LookupSymbolsForModule(symbolReader, module.ModuleFile); } } // Source line lookup is verbose, so we don't send it to the console but to srcLookupLog (which we currently ignore) var srcLookupLog = new StringWriter(); var silentSymbolReader = new SymbolReader(srcLookupLog, SymbolPath.MicrosoftSymbolServerPath); silentSymbolReader.Options = SymbolReaderOptions.CacheOnly; // don't try to look things up on the network for source silentSymbolReader.SecurityCheck = (pdbPath) => true; // for this demo we trust any pdb location. This lets us find the PDB of the demo itself Out.WriteLine("******Looking for EXCEPTION EVENTS"); // Get all the exception events in foreach (var exceptionData in (simpleTraceLogProcess.EventsInProcess.ByEventType <ExceptionTraceData>())) { Out.WriteLine("Found an EXCEPTION event in SimpleTraceLog: Type: {0} Message: {1}", exceptionData.ExceptionType, exceptionData.ExceptionMessage); PrintStack(exceptionData.CallStack(), silentSymbolReader); } Out.WriteLine(); Out.WriteLine("******Looking for Microsoft-Demos-SimpleMonitor.Stop EVENTS"); foreach (var data in simpleTraceLogProcess.EventsInProcess) { if (data.ProviderName == "Microsoft-Demos-SimpleMonitor" && data.EventName == "Stop") { Out.WriteLine("Found an EVENTSOURCE event {0} at {1:f3} MSec into trace", data.EventName, data.TimeStampRelativeMSec); PrintStack(data.CallStack(), silentSymbolReader); } } }
public SourceLocation GetSourceLine(StackSourceFrameIndex frameIndex, SymbolReader reader) { uint codeAddressIndex = (uint)frameIndex - (uint)StackSourceFrameIndex.Start; if (codeAddressIndex >= m_log.CodeAddresses.MaxCodeAddressIndex) { return(null); } return(m_log.CodeAddresses.GetSourceLine(reader, (CodeAddressIndex)codeAddressIndex)); }
private string GetDacFile(ClrInfo clrInfo) { if (_dacFilePath == null) { string dac = clrInfo.LocalMatchingDac; if (dac != null && File.Exists(dac)) { _dacFilePath = dac; } else if (SymbolReader.IsSymbolStoreEnabled()) { string dacFileName = Path.GetFileName(dac ?? clrInfo.DacInfo.FileName); if (dacFileName != null) { SymbolStoreKey key = null; if (clrInfo.ModuleInfo.BuildId != null) { IEnumerable <SymbolStoreKey> keys = ELFFileKeyGenerator.GetKeys( KeyTypeFlags.ClrKeys, clrInfo.ModuleInfo.FileName, clrInfo.ModuleInfo.BuildId, symbolFile: false, symbolFileName: null); key = keys.SingleOrDefault((k) => Path.GetFileName(k.FullPathName) == dacFileName); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // We are opening a Linux dump on Windows // We need to use the Windows index and filename key = new SymbolStoreKey(key.Index.Replace("libmscordaccore.so", "mscordaccore.dll"), key.FullPathName.Replace("libmscordaccore.so", "mscordaccore.dll"), key.IsClrSpecialFile, key.PdbChecksums); } } else { // Use the coreclr.dll's id (timestamp/filesize) to download the the dac module. key = PEFileKeyGenerator.GetKey(dacFileName, clrInfo.ModuleInfo.TimeStamp, clrInfo.ModuleInfo.FileSize); } if (key != null) { // Now download the DAC module from the symbol server _dacFilePath = SymbolReader.GetSymbolFile(key); } } } if (_dacFilePath == null) { throw new FileNotFoundException($"Could not find matching DAC for this runtime: {clrInfo.ModuleInfo.FileName}"); } _isDesktop = clrInfo.Flavor == ClrFlavor.Desktop; } return(_dacFilePath); }
public static void Main(string [] args) { var EG = Test3(); var expansionRun = new ExpansionsionRun(EG); var EG2 = expansionRun.After; var c = new FromEbnfToBnf_ByCopying(EG2); var text = new SymbolReader("cad"); var pc = new RecursiveDescentParser(text); var res = pc.RecusiveDescent(c.Bnf ["S"]); Console.WriteLine(res); }
SymbolModule FindPdbForModule(ModuleInfo module) { if (module == null) { return(null); } string pdbName; Guid pdbGuid; int rev; using (PEFile pefile = new PEFile(new ReadVirtualStream(m_dataReader, (long)module.ImageBase, (long)module.FileSize), true)) if (!pefile.GetPdbSignature(out pdbName, out pdbGuid, out rev)) { return(null); } if (!File.Exists(pdbName)) { ISymbolNotification notification = DefaultSymbolNotification ?? new NullSymbolNotification(); pdbName = Path.GetFileName(pdbName); pdbName = SymbolReader.FindSymbolFilePath(pdbName, pdbGuid, rev, notification); if (string.IsNullOrEmpty(pdbName) || !File.Exists(pdbName)) { return(null); } } if (pdbName == null) { m_symbols[module] = null; return(null); } SymbolModule symbols = null; try { symbols = new SymbolModule(SymbolReader, pdbName); m_symbols[module] = symbols; } catch { m_symbols[module] = null; return(null); } return(symbols); }
public ProcessContext(AutomatedAnalysisExecutionContext executionContext, AutomatedAnalysisTraceProcess process) { _executionContext = executionContext; AutomatedAnalysisProcess = process; AutomatedAnalysisTraceLog traceLog = executionContext.Trace as AutomatedAnalysisTraceLog; if (traceLog != null) { Process = traceLog.TraceLog.Processes[(ProcessIndex)process.UniqueID]; } Issues = executionContext.Issues[process]; _symbolReader = executionContext.SymbolReader; }
public static MemoryGraph Create(string dllPath, SymbolReader symbolReader) { var ret = new MemoryGraph(1000); string pdbPath = symbolReader.FindSymbolFilePathForModule(dllPath); symbolReader.Log.WriteLine("Got PDB path {0}", pdbPath); NativeSymbolModule module = symbolReader.OpenNativeSymbolFile(pdbPath); List <Symbol> symbols = new List <Symbol>(); AddAllChildren(symbols, module.GlobalSymbol); symbols.Sort(); /****** Make a graph out of the symbols ******/ // Put all nodes under this root. var rootChildren = new GrowableArray <NodeIndex>(1000); // Create a node for each symbol uint lastRVA = 0; string lastName = "Header"; var empty = new GrowableArray <NodeIndex>(); foreach (var symbol in symbols) { var symRVA = symbol.RVA; int lastSize = (int)symRVA - (int)lastRVA; NodeTypeIndex typeIdx = ret.CreateType(lastName, null, lastSize); NodeIndex nodeIdx = ret.CreateNode(); ret.SetNode(nodeIdx, typeIdx, lastSize, empty); rootChildren.Add(nodeIdx); lastName = symbol.Name; lastRVA = symRVA; } // TODO FIX NOW dropping the last symbol. // Create the root node. NodeIndex rootIdx = ret.CreateNode(); NodeTypeIndex rootTypeIdx = ret.CreateType("METHODS"); ret.SetNode(rootIdx, rootTypeIdx, 0, rootChildren); ret.RootIndex = rootIdx; ret.AllowReading(); return(ret); }
static void ProcessData(string dataFileName, string processName) { Out.WriteLine("************** Creating a ETLX file for {0}", dataFileName); var traceLog = TraceLog.OpenOrConvert(dataFileName, new TraceLogOptions() { ConversionLog = Out }); Out.WriteLine("************** Done converting", Path.GetFileName(traceLog.FilePath)); var simpleTraceLogProcess = traceLog.Processes.LastProcessWithName(processName); Debug.Assert(simpleTraceLogProcess != null); // Resolve symbols for clr and ntdll using the standard Microsoft symbol server path. var symbolReader = new SymbolReader(Out, SymbolPath.MicrosoftSymbolServerPath); foreach (var module in simpleTraceLogProcess.LoadedModules) { if (module.Name == "clr" || module.Name == "ntdll" || module.Name == "mscorlib.ni") { traceLog.CodeAddresses.LookupSymbolsForModule(symbolReader, module.ModuleFile); } } // Source line lookup is verbose, so we don't send it to the console but to srcLookupLog (which we currently ignore) var srcLookupLog = new StringWriter(); var silentSymbolReader = new SymbolReader(srcLookupLog, SymbolPath.MicrosoftSymbolServerPath); silentSymbolReader.Options = SymbolReaderOptions.CacheOnly; // don't try to look things up on the network for source silentSymbolReader.SecurityCheck = (pdbPath) => true; // for this demo we trust any pdb location. This lets us find the PDB of the demo itself //Out.WriteLine("******Looking for SAMPLE PROFILE EVENTS"); //int count = 0; //foreach (var sample in simpleTraceLogProcess.EventsInProcess.ByEventType<SampledProfileTraceData>()) //{ // ++count; // PrintStack(sample.CallStack(), silentSymbolReader); //} //Out.WriteLine("******TOTAL {0} SAMPLE PROFILE EVENTS", count); //Out.WriteLine(); Out.WriteLine("******Looking for EXCEPTION EVENTS"); foreach (var exceptionData in (simpleTraceLogProcess.EventsInProcess.ByEventType <ExceptionTraceData>())) { Out.WriteLine("Found an EXCEPTION event in SimpleTraceLog: Type: {0} Message: {1}", exceptionData.ExceptionType, exceptionData.ExceptionMessage); PrintStack(exceptionData.CallStack(), silentSymbolReader); } Out.WriteLine(); }
private static void PrintStack(TraceCallStack callStack, SymbolReader symbolReader) { Out.WriteLine("STACKTRACE:"); while (callStack != null) { var method = callStack.CodeAddress.Method; var module = callStack.CodeAddress.ModuleFile; if (method != null) { // see if we can get line number information var lineInfo = ""; var sourceLocation = callStack.CodeAddress.GetSourceLine(symbolReader); if (sourceLocation != null) lineInfo = string.Format(" AT: {0}({1})", Path.GetFileName(sourceLocation.SourceFile.BuildTimeFilePath), sourceLocation.LineNumber); Out.WriteLine(" Method: {0}!{1}{2}", module.Name, method.FullMethodName, lineInfo); } else if (module != null) Out.WriteLine(" Module: {0}!0x{1:x}", module.Name, callStack.CodeAddress.Address); else Out.WriteLine(" ?!0x{0:x}", callStack.CodeAddress.Address); callStack = callStack.Caller; } }
/// <summary> /// Process the data in 'dataFileName' printing the events and doing delta computation between 'MyFirstEvent' /// and 'MySecondEvent'. /// </summary> static void ProcessData(string dataFileName) { Out.WriteLine("************** Creating a ETLX file for {0}", dataFileName); // Note the OpenOrConvert will take an ETL file and generate an ETLX (right next to it) if it is out of date. // We TraceLogOptions gives you control over this conversion. Here we spew the log file to the console var traceLog = TraceLog.OpenOrConvert(dataFileName, new TraceLogOptions() { ConversionLog = Out }); Out.WriteLine("************** Done converting", Path.GetFileName(traceLog.FilePath)); // The OS process ID of this process var myProcessID = Process.GetCurrentProcess().Id; // Find myself in th trace. var simpleTraceLogProcess = traceLog.Processes.LastProcessWithID(myProcessID); Debug.Assert(simpleTraceLogProcess != null); // Resolve symbols for clr and ntdll using the standard Microsoft symbol server path. var symbolReader = new SymbolReader(Out, SymbolPath.MicrosoftSymbolServerPath); foreach (var module in simpleTraceLogProcess.LoadedModules) { if (module.Name == "clr" || module.Name == "ntdll" || module.Name == "mscorlib.ni") traceLog.CodeAddresses.LookupSymbolsForModule(symbolReader, module.ModuleFile); } // Source line lookup is verbose, so we don't send it to the console but to srcLookupLog (which we currently ignore) var srcLookupLog = new StringWriter(); var silentSymbolReader = new SymbolReader(srcLookupLog, SymbolPath.MicrosoftSymbolServerPath); silentSymbolReader.Options = SymbolReaderOptions.CacheOnly; // don't try to look things up on the network for source silentSymbolReader.SecurityCheck = (pdbPath) => true; // for this demo we trust any pdb location. This lets us find the PDB of the demo itself Out.WriteLine("******Looking for EXCEPTION EVENTS"); // Get all the exception events in foreach (var exceptionData in (simpleTraceLogProcess.EventsInProcess.ByEventType<ExceptionTraceData>())) { Out.WriteLine("Found an EXCEPTION event in SimpleTraceLog: Type: {0} Message: {1}", exceptionData.ExceptionType, exceptionData.ExceptionMessage); PrintStack(exceptionData.CallStack(), silentSymbolReader); } Out.WriteLine(); Out.WriteLine("******Looking for Microsoft-Demos-SimpleMonitor.Stop EVENTS"); foreach (var data in simpleTraceLogProcess.EventsInProcess) { if (data.ProviderName == "Microsoft-Demos-SimpleMonitor" && data.EventName == "Stop") { Out.WriteLine("Found an EVENTSOURCE event {0} at {1:f3} MSec into trace", data.EventName, data.TimeStampRelativeMSec); PrintStack(data.CallStack(), silentSymbolReader); } } }
/// <summary> /// Print data. Note that this method is called FROM DIFFERNET THREADS which means you need to properly /// lock any read-write data you access. It turns out Out.Writeline is already thread safe so /// there is nothing I have to do in this case. /// </summary> static void Print(TraceEvent data, SymbolReader symbolReader) { // There are a lot of data collection start on entry that I don't want to see (but often they are quite handy if (data.Opcode == TraceEventOpcode.DataCollectionStart) return; // V3.5 runtimes don't log the stack and in fact don't event log the exception name (it shows up as an empty string) // Just ignore these as they are not that interesting. if (data is ExceptionTraceData && ((ExceptionTraceData) data).ExceptionType.Length == 0) return; Out.WriteLine("EVENT: {0}", data.ToString()); var callStack = data.CallStack(); if (callStack != null) { // Because symbol lookup is complex, error prone, and expensive TraceLog requires you to be explicit. // Here we look up names in this call stack using the symbol reader. ResolveNativeCode(callStack, symbolReader); Out.WriteLine("CALLSTACK: {0}", callStack.ToString()); } }
/// <summary> /// Because it is expensive and often unnecessary, lookup of native symbols needs to be explicitly requested. /// Here we do this for every frame in the stack. Note that this is not needed for JIT compiled managed code. /// </summary> static private void ResolveNativeCode(TraceCallStack callStack, SymbolReader symbolReader) { while (callStack != null) { var codeAddress = callStack.CodeAddress; if (codeAddress.Method == null) { var moduleFile = codeAddress.ModuleFile; if (moduleFile == null) Trace.WriteLine(string.Format("Could not find module for Address 0x{0:x}", codeAddress.Address)); else codeAddress.CodeAddresses.LookupSymbolsForModule(symbolReader, moduleFile); } callStack = callStack.Caller; } }
public static void Run() { var monitoringTimeSec = 10; Out.WriteLine("******************** RealTimeTraceLog DEMO (win8) ********************"); Out.WriteLine("This program Shows how to use the real-time support in TraceLog"); Out.WriteLine("We do this by showing how to monitor exceptions in real time "); Out.WriteLine(); Out.WriteLine("This code depends on a Feature of Windows 8.1 (combined user and kernel sessions)"); Out.WriteLine(); Out.WriteLine("Note that this support is currently experimental and subject to change"); Out.WriteLine(); Out.WriteLine("Monitoring .NET Module load and Exception events (with stacks)."); Out.WriteLine("Run some managed code (ideally that has exceptions) while the monitor is running."); Out.WriteLine(); if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62) { Out.WriteLine("This demo only works on Win8 / Win 2012 and above)"); return; } TraceEventSession session = null; // Set up Ctrl-C to stop both user mode and kernel mode sessions Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs cancelArgs) => { if (session != null) session.Dispose(); cancelArgs.Cancel = true; }; // Cause an exception to be thrown a few seconds in (so we have something interesting to look at) var exceptionGeneationTask = Task.Factory.StartNew(delegate { Thread.Sleep(3000); ThrowException(); }); Timer timer = null; // Create the new session to receive the events. // Because we are on Win 8 this single session can handle both kernel and non-kernel providers. using (session = new TraceEventSession("TraceLogSession")) { // Enable the events we care about for the kernel // For this instant the session will buffer any incoming events. // Enabling kernel events must be done before anything else. // This will fail on Win7. // // Note that if you turn on the KernelTraceEventParser.Keywords.Profile, you can also get stacks for CPU sampling // (every millisecond). (You can use the traceLogSource.Kernel.PerfInfoSample callback). Out.WriteLine("Enabling Image load, Process and Thread events. These are needed to look up native method names."); session.EnableKernelProvider( // KernelTraceEventParser.Keywords.Profile | // If you want CPU sampling events // KernelTraceEventParser.Keywords.ContextSwitch | // If you want context switch events // KernelTraceEventParser.Keywords.Thread | // If you want context switch events you also need thread start events. KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process, /****** The second parameter indicates which kernel events should have stacks *****/ // KernelTraceEventParser.Keywords.ImageLoad | // If you want Stacks image load (load library) events // KernelTraceEventParser.Keywords.Profile | // If you want Stacks for CPU sampling events // KernelTraceEventParser.Keywords.ContextSwitch | // If you want Stacks for context switch events KernelTraceEventParser.Keywords.None ); Out.WriteLine("Enabling CLR Exception and Load events (and stack for those events)"); // We are monitoring exception events (with stacks) and module load events (with stacks) session.EnableProvider( ClrTraceEventParser.ProviderGuid, TraceEventLevel.Informational, (ulong)(ClrTraceEventParser.Keywords.Jit | // Turning on JIT events is necessary to resolve JIT compiled code ClrTraceEventParser.Keywords.JittedMethodILToNativeMap | // This is needed if you want line number information in the stacks ClrTraceEventParser.Keywords.Loader | // You must include loader events as well to resolve JIT compiled code. ClrTraceEventParser.Keywords.Exception | // We want to see the exception events. ClrTraceEventParser.Keywords.Stack)); // And stacks on all CLR events where it makes sense. // The CLR events turned on above will let you resolve JIT compiled code as long as the JIT compilation // happens AFTER the session has started. To handle the case for JIT compiled code that was already // compiled we need to tell the CLR to dump 'Rundown' events for all existing JIT compiled code. We // do that here. Out.WriteLine("Enabling CLR Events to 'catch up' on JIT compiled code in running processes."); session.EnableProvider(ClrRundownTraceEventParser.ProviderGuid, TraceEventLevel.Informational, (ulong)(ClrTraceEventParser.Keywords.Jit | // We need JIT events to be rundown to resolve method names ClrTraceEventParser.Keywords.JittedMethodILToNativeMap | // This is needed if you want line number information in the stacks ClrTraceEventParser.Keywords.Loader | // As well as the module load events. ClrTraceEventParser.Keywords.StartEnumeration)); // This indicates to do the rundown now (at enable time) // Because we care about symbols in native code or NGEN images, we need a SymbolReader to decode them. // There is a lot of messages associated with looking up symbols, but we don't want to clutter up // The output by default, so we save it to an internal buffer you can ToString in debug code. // A real app should make this available somehow to the user, because sooner or later you DO need it. TextWriter SymbolLookupMessages = new StringWriter(); // TextWriter SymbolLookupMessages = Out; // If you want the symbol debug spew to go to the output, use this. // By default a symbol Reader uses whatever is in the _NT_SYMBOL_PATH variable. However you can override // if you wish by passing it to the SymbolReader constructor. Since we want this to work even if you // have not set an _NT_SYMBOL_PATH, so we add the Microsoft default symbol server path to be sure/ var symbolPath = new SymbolPath(SymbolPath.SymbolPathFromEnvironment).Add(SymbolPath.MicrosoftSymbolServerPath); SymbolReader symbolReader = new SymbolReader(SymbolLookupMessages, symbolPath.ToString()); Out.WriteLine("Open a real time TraceLog session (which understands how to decode stacks)."); using (TraceLogEventSource traceLogSource = TraceLog.CreateFromTraceEventSession(session)) { // We use this action in the particular callbacks below. Basically we pass in a symbol reader so we can decode the stack. // Often the symbol reader is a global variable instead. Action<TraceEvent> PrintEvent = ((TraceEvent data) => Print(data, symbolReader)); // We will print Exceptions and ModuleLoad events. (with stacks). traceLogSource.Clr.ExceptionStart += PrintEvent; traceLogSource.Clr.LoaderModuleLoad += PrintEvent; // traceLogSource.Clr.All += PrintEvent; // If you want to see stacks for various other kernel events, uncomment these (you also need to turn on the events above) traceLogSource.Kernel.PerfInfoSample += ((SampledProfileTraceData data) => Print(data, symbolReader)); // traceLogSource.Kernel.ImageLoad += ((ImageLoadTraceData data) => Print(data, symbolReader)); // process events until Ctrl-C is pressed or timeout expires Out.WriteLine("Waiting {0} sec for Events. Run managed code to see data. ", monitoringTimeSec); Out.WriteLine("Keep in mind there is a several second buffering delay"); // Set up a timer to stop processing after monitoringTimeSec timer = new Timer(delegate(object state) { Out.WriteLine("Stopped Monitoring after {0} sec", monitoringTimeSec); if (session != null) session.Dispose(); session = null; }, null, monitoringTimeSec * 1000, Timeout.Infinite); traceLogSource.Process(); } } Out.WriteLine("Finished"); if (timer != null) timer.Dispose(); // Turn off the timer. }