public EtwDeserializer(string fileName)
        {
            this.MethodILNativeMap    = new Dictionary <ulong, ManagedMethodILToNativeMapping>();
            this.ImageToDebugInfoMap  = new Dictionary <ProcessImageId, DbgId>();
            this.ManagedModuleInfoMap = new Dictionary <ProcessModuleId, ManagedModuleInfo>();
            this.ImageLoadMap         = new Dictionary <uint, List <ImageInfo> >();
            this.MethodLoadMap        = new Dictionary <uint, List <ManagedMethodInfo> >();
            this.Stacks             = new List <StackInfo>();
            this.Frames             = new List <Frame>();
            this.Samples            = new List <StackSourceSample>();
            this.PseudoFrames       = new List <string>();
            this.EventStacks        = new Dictionary <int, StackEventType>();
            this.ProcessIdToNameMap = new Dictionary <uint, string>();
            var fileSessions = new EVENT_TRACE_LOGFILEW[1];
            var handles      = new ulong[1];

            unsafe
            {
                fileSessions[0] = new EVENT_TRACE_LOGFILEW
                {
                    LogFileName         = fileName,
                    EventRecordCallback = this.Deserialize,
                    BufferCallback      = this.BufferCallback,
                    LogFileMode         = Etw.PROCESS_TRACE_MODE_EVENT_RECORD | Etw.PROCESS_TRACE_MODE_RAW_TIMESTAMP
                };
            }

            handles[0] = Etw.OpenTrace(ref fileSessions[0]);

            unchecked
            {
                if (handles[0] == (ulong)~0)
                {
                    switch (Marshal.GetLastWin32Error())
                    {
                    case 0x57:
                        throw new Exception($"ERROR: For file: {fileName} Windows returned 0x57 -- The Logfile parameter is NULL.");

                    case 0xA1:
                        throw new Exception($"ERROR: For file: {fileName} Windows returned 0xA1 -- The specified path is invalid.");

                    case 0x5:
                        throw new Exception($"ERROR: For file: {fileName} Windows returned 0x5 -- Access is denied.");

                    default:
                        throw new Exception($"ERROR: For file: {fileName} Windows returned an unknown error.");
                    }
                }
            }

            this.perfFreq = fileSessions[0].LogfileHeader.PerfFreq;

            this.pidEipToFrameIndexTable        = new Dictionary <Frame, int>();
            this.stackIndexTable                = new Dictionary <StackInfo, int>();
            this.threadPseudoFrameMappingTable  = new Dictionary <uint, int>();
            this.processPseudoFrameMappingTable = new Dictionary <uint, int>();
            this.callerIdsNeedingUpdates        = new HashSet <int>();
            this.samplesTimeStampMap            = new Dictionary <CorrelatedStackEvent, int>();
            this.etwProviderInfoMap             = new Dictionary <EtwProviderInfo, StackEventType>();

            EtwDeserializerEventSource.Logger.BeginProcessTrace();
            Etw.ProcessTrace(handles, (uint)handles.Length, IntPtr.Zero, IntPtr.Zero);
            EtwDeserializerEventSource.Logger.EndProcessTrace();

            Etw.CloseTrace(handles[0]);

            unsafe
            {
                fileSessions[0] = new EVENT_TRACE_LOGFILEW
                {
                    LogFileName         = fileName,
                    EventRecordCallback = this.Deserialize2ndPass,
                    BufferCallback      = this.BufferCallback,
                    LogFileMode         = Etw.PROCESS_TRACE_MODE_EVENT_RECORD | Etw.PROCESS_TRACE_MODE_RAW_TIMESTAMP
                };
            }

            handles[0] = Etw.OpenTrace(ref fileSessions[0]);

            EtwDeserializerEventSource.Logger.BeginProcessTrace();
            Etw.ProcessTrace(handles, (uint)handles.Length, IntPtr.Zero, IntPtr.Zero);
            EtwDeserializerEventSource.Logger.EndProcessTrace();

            Etw.CloseTrace(handles[0]);

            GC.KeepAlive(fileSessions);

            EtwDeserializerEventSource.Logger.BeginMapProcessIdToNames();

            foreach (var pseudoFrameInfo in this.processPseudoFrameMappingTable)
            {
                this.PseudoFrames[pseudoFrameInfo.Value] = this.ProcessIdToNameMap.TryGetValue(pseudoFrameInfo.Key, out var processName) ? $"Process {processName} ({pseudoFrameInfo.Key})" : $"Process ({pseudoFrameInfo.Key})";
            }

            foreach (var pseudoFrameInfo in this.threadPseudoFrameMappingTable)
            {
                this.PseudoFrames[pseudoFrameInfo.Value] = $"Thread ({pseudoFrameInfo.Key})";
            }

            EtwDeserializerEventSource.Logger.EndMapProcessIdToNames();

            this.pidEipToFrameIndexTable        = null;
            this.stackIndexTable                = null;
            this.threadPseudoFrameMappingTable  = null;
            this.processPseudoFrameMappingTable = null;
            this.samplesTimeStampMap            = null;
            this.etwProviderInfoMap             = null;

            this.PseudoFramesStartOffset = this.Frames.Count;

            EtwDeserializerEventSource.Logger.BeginFixupCallerIndices();

            foreach (var callerId in this.callerIdsNeedingUpdates)
            {
                var frameIndex = this.Frames.Count;
                var stack      = this.Stacks[callerId];
                this.Stacks[callerId] = new StackInfo(stack.CallerID, frameIndex);
                this.Frames.Add(new Frame((uint)stack.FrameID, 0));  // hack alert: we reuse the pid field as a pseudo frame id
            }

            this.callerIdsNeedingUpdates = null;

            EtwDeserializerEventSource.Logger.EndFixupCallerIndices();

            EtwDeserializerEventSource.Logger.BeginSortImages();

            foreach (var elem in this.ImageLoadMap.Values)
            {
                elem.Sort();
            }

            EtwDeserializerEventSource.Logger.EndSortImages();

            EtwDeserializerEventSource.Logger.BeginSortMethods();

            foreach (var elem in this.MethodLoadMap.Values)
            {
                elem.Sort();
            }

            EtwDeserializerEventSource.Logger.EndSortMethods();

            EtwDeserializerEventSource.Logger.BeginPopulateInstructionPointers();

            var frames = this.Frames;

            foreach (var frame in frames)
            {
                if (this.ImageLoadMap.TryGetValue(frame.ProcessId, out var imageList))
                {
                    var eip    = frame.InstructionPointer;
                    var result = RangeBinarySearch(imageList, eip);
                    if (result >= 0)
                    {
                        imageList[result].InstructionPointers.Add(eip);
                    }
                }
            }

            /* special process */
            var pidZeroList = this.ImageLoadMap[0];

            foreach (var frame in frames)
            {
                var eip    = frame.InstructionPointer;
                var result = RangeBinarySearch(pidZeroList, eip);
                if (result >= 0)
                {
                    // add eips encountered in other processes to this one.
                    // we do this so when we lookup pdbs we have all eips
                    // for these images
                    pidZeroList[result].InstructionPointers.Add(eip);
                }
            }

            EtwDeserializerEventSource.Logger.EndPopulateInstructionPointers();
        }
Exemple #2
0
 internal static extern UInt64 OpenTrace([In][Out] ref EVENT_TRACE_LOGFILEW Logfile);