Example #1
0
        /// <summary>
        /// We wrap this because sadly the PMC suppport is private, so we have to do it a different way if that is present.
        /// </summary>
        int StartKernelTrace(
            out UInt64 TraceHandle,
            TraceEventNativeMethods.EVENT_TRACE_PROPERTIES* properties,
            TraceEventNativeMethods.STACK_TRACING_EVENT_ID* stackTracingEventIds,
            int cStackTracingEventIds)
        {
            //bool needExtensions = false;  // SLAB fix
            if ((((KernelTraceEventParser.Keywords)properties->EnableFlags) & KernelTraceEventParser.Keywords.PMCProfile) != 0)
                throw new ApplicationException("CPU Counter profiling not supported.");

            properties->EnableFlags = properties->EnableFlags & (uint)~KernelTraceEventParser.Keywords.NonOSKeywords;
            return TraceEventNativeMethods.StartKernelTrace(out TraceHandle, properties, stackTracingEventIds, cStackTracingEventIds);
        }
Example #2
0
        private bool InsureStarted(TraceEventNativeMethods.EVENT_TRACE_PROPERTIES* properties = null)
        {
            if (!m_Create)
                throw new NotSupportedException("Can not enable providers on a session you don't create directly");

            // Already initialized, nothing to do.  
            if (m_SessionHandle != TraceEventNativeMethods.INVALID_HANDLE_VALUE)
                return false;

            var propertiesBuff = stackalloc byte[PropertiesSize];
            if (properties == null)
                properties = GetProperties(propertiesBuff);
            bool ret = false;

            int retCode = TraceEventNativeMethods.StartTraceW(out m_SessionHandle, m_SessionName, properties);
            if (retCode == 0xB7)      // STIERR_HANDLEEXISTS
            {
                ret = true;
                Stop();
                m_Stopped = false;
                Thread.Sleep(100);  // Give it some time to stop. 
                retCode = TraceEventNativeMethods.StartTraceW(out m_SessionHandle, m_SessionName, properties);
            }
            if (retCode == 5 && Environment.OSVersion.Version.Major > 5)      // On Vista and we get a 'Accessed Denied' message
                throw new UnauthorizedAccessException("Error Starting ETW:  Access Denied (Administrator rights required to start ETW)");
            Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(retCode));
            return ret;
        }
Example #3
0
        private static List<ProviderDataItem> GetProviderFields(Guid providerGuid, TraceEventNativeMethods.EVENT_FIELD_TYPE fieldType)
        {
            var ret = new List<ProviderDataItem>();

            int buffSize = 0;
            var hr = TraceEventNativeMethods.TdhEnumerateProviderFieldInformation(ref providerGuid, fieldType, null, ref buffSize);
            if (hr != 122)
                return ret;     // TODO FIX NOW Do I want to simply return nothing or give a more explicit error? 
            Debug.Assert(hr == 122);     // ERROR_INSUFFICIENT_BUFFER 

            var buffer = stackalloc byte[buffSize];
            var fieldsDesc = (TraceEventNativeMethods.PROVIDER_FIELD_INFOARRAY*)buffer;
            hr = TraceEventNativeMethods.TdhEnumerateProviderFieldInformation(ref providerGuid, fieldType, fieldsDesc, ref buffSize);
            if (hr != 0)
                throw new InvalidOperationException("TdhEnumerateProviderFieldInformation failed.");       // TODO better error message

            var fields = (TraceEventNativeMethods.PROVIDER_FIELD_INFO*)&fieldsDesc[1];
            for (int i = 0; i < fieldsDesc->NumberOfElements; i++)
            {
                var field = new ProviderDataItem();
                field.Name = new string((char*)&buffer[fields[i].NameOffset]);
                field.Description = new string((char*)&buffer[fields[i].DescriptionOffset]);
                field.Value = fields[i].Value;
                ret.Add(field);
            }

            return ret;
        }
Example #4
0
        /// <summary>
        /// Given a mask of kernel flags, set the array stackTracingIds of size stackTracingIdsMax to match.
        /// It returns the number of entries in stackTracingIds that were filled in.
        /// </summary>
        private unsafe int SetStackTraceIds(KernelTraceEventParser.Keywords stackCapture, TraceEventNativeMethods.STACK_TRACING_EVENT_ID* stackTracingIds, int stackTracingIdsMax)
        {
            int curID = 0;

            // PerfInfo (sample profiling)
            if ((stackCapture & KernelTraceEventParser.Keywords.Profile) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PerfInfoTaskGuid;
                stackTracingIds[curID].Type = 0x2e;     // Sample Profile
                curID++;
            }

            // PCM sample profiling
            if ((stackCapture & KernelTraceEventParser.Keywords.PMCProfile) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PerfInfoTaskGuid;
                stackTracingIds[curID].Type = 0x2f;     // PMC Sample Profile
                curID++;
            }

            if ((stackCapture & KernelTraceEventParser.Keywords.SystemCall) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PerfInfoTaskGuid;
                stackTracingIds[curID].Type = 0x33;     // SysCall
                curID++;
            }
            // Thread
            if ((stackCapture & KernelTraceEventParser.Keywords.Thread) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.ThreadTaskGuid;
                stackTracingIds[curID].Type = 0x01;     // Thread Create
                curID++;
            }

            if ((stackCapture & KernelTraceEventParser.Keywords.ContextSwitch) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.ThreadTaskGuid;
                stackTracingIds[curID].Type = 0x24;     // Context Switch
                curID++;
            }

            if ((stackCapture & KernelTraceEventParser.Keywords.Dispatcher) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.ThreadTaskGuid;
                stackTracingIds[curID].Type = 0x32;     // Ready Thread
                curID++;
            }

            // Image
            if ((stackCapture & KernelTraceEventParser.Keywords.ImageLoad) != 0)
            {
                // Confirm this is not ImageTaskGuid
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.ProcessTaskGuid;
                stackTracingIds[curID].Type = 0x0A;     // Image Load
                curID++;
            }

            // Process
            if ((stackCapture & KernelTraceEventParser.Keywords.Process) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.ProcessTaskGuid;
                stackTracingIds[curID].Type = 0x01;     // Process Create
                curID++;
            }

            // Disk
            if ((stackCapture & KernelTraceEventParser.Keywords.DiskIOInit) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.DiskIoTaskGuid;
                stackTracingIds[curID].Type = 0x0c;     // Read Init
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.DiskIoTaskGuid;
                stackTracingIds[curID].Type = 0x0d;     // Write Init
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.DiskIoTaskGuid;
                stackTracingIds[curID].Type = 0x0f;     // Flush Init
                curID++;
            }

            // Virtual Alloc
            if ((stackCapture & KernelTraceEventParser.Keywords.VirtualAlloc) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.VirtualAllocTaskGuid;
                stackTracingIds[curID].Type = 0x62;     // Flush Init
                curID++;
            }

            // Hard Faults
            if ((stackCapture & KernelTraceEventParser.Keywords.MemoryHardFaults) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PageFaultTaskGuid;
                stackTracingIds[curID].Type = 0x20;     // Hard Fault
                curID++;
            }

            // Page Faults 
            if ((stackCapture & KernelTraceEventParser.Keywords.MemoryPageFaults) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PageFaultTaskGuid;
                stackTracingIds[curID].Type = 0x0A;     // Transition Fault
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PageFaultTaskGuid;
                stackTracingIds[curID].Type = 0x0B;     // Demand zero Fault
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PageFaultTaskGuid;
                stackTracingIds[curID].Type = 0x0C;     // Copy on Write Fault
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PageFaultTaskGuid;
                stackTracingIds[curID].Type = 0x0D;     // Guard Page Fault
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.PageFaultTaskGuid;
                stackTracingIds[curID].Type = 0x0E;     // Hard Page Fault
                curID++;

                // TODO these look interesting.  
                // ! %02 49 ! Pagefile Mapped Section Create
                // ! %02 69 ! Pagefile Backed Image Mapping
                // ! %02 71 ! Contiguous Memory Generation
            }

            if ((stackCapture & KernelTraceEventParser.Keywords.FileIOInit) != 0)
            {
                // TODO allow stacks only on open and close;
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.FileIoTaskGuid;
                stackTracingIds[curID].Type = 0x40;     // Create
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.FileIoTaskGuid;
                stackTracingIds[curID].Type = 0x41;     // Cleanup
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.FileIoTaskGuid;
                stackTracingIds[curID].Type = 0x42;     // Close
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.FileIoTaskGuid;
                stackTracingIds[curID].Type = 0x43;     // Read
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.FileIoTaskGuid;
                stackTracingIds[curID].Type = 0x44;     // Write
                curID++;
            }

            if ((stackCapture & KernelTraceEventParser.Keywords.Registry) != 0)
            {
                stackTracingIds[curID].EventGuid = KernelTraceEventParser.RegistryTaskGuid;
                stackTracingIds[curID].Type = 0x0A;     // NtCreateKey
                curID++;

                stackTracingIds[curID].EventGuid = KernelTraceEventParser.RegistryTaskGuid;
                stackTracingIds[curID].Type = 0x0B;     // NtOpenKey
                curID++;

            }

            // TODO put these in for advanced procedure calls.  
            //! %1A 21 ! ALPC: SendMessage
            //! %1A 22 ! ALPC: ReceiveMessage
            //! %1A 23 ! ALPC: WaitForReply
            //! %1A 24 ! ALPC: WaitForNewMessage
            //! %1A 25 ! ALPC: UnWait

            // I don't have heap or threadpool.  

            // Confirm we did not overflow.  
            Debug.Assert(curID <= stackTracingIdsMax);
            return curID;
        }
        private void RawDispatch(TraceEventNativeMethods.EVENT_RECORD* rawData)
        {
            Debug.Assert(rawData->EventHeader.HeaderType == 0);     // if non-zero probably old-style ETW header
            TraceEvent anEvent = Lookup(rawData);

            // Keep in mind that for UnhandledTraceEvent 'PrepForCallback' has NOT been called, which means the
            // opcode, guid and eventIds are not correct at this point.  The ToString() routine WILL call
            // this so if that is in your debug window, it will have this side effect (which is good and bad)
            // Looking at rawData will give you the truth however. 
            anEvent.DebugValidate();

            // TODO FIX NOW, can we be more efficient?
            if (sessionStartTimeQPC == 0)
                sessionStartTimeQPC = rawData->EventHeader.TimeStamp;

            if (anEvent.FixupETLData != null)
                anEvent.FixupETLData();
            Dispatch(anEvent);
        }
        private void RawDispatchClassic(TraceEventNativeMethods.EVENT_RECORD* eventData)
        {
            // TODO not really a EVENT_RECORD on input, but it is a pain to be type-correct.  
            TraceEventNativeMethods.EVENT_TRACE* oldStyleHeader = (TraceEventNativeMethods.EVENT_TRACE*)eventData;
            eventData = convertedHeader;

            eventData->EventHeader.Size = (ushort)sizeof(TraceEventNativeMethods.EVENT_TRACE_HEADER);
            // HeaderType
            eventData->EventHeader.Flags = TraceEventNativeMethods.EVENT_HEADER_FLAG_CLASSIC_HEADER;

            // TODO Figure out if there is a marker that is used in the WOW for the classic providers 
            // right now I assume they are all the same as the machine.  
            if (pointerSize == 8)
                eventData->EventHeader.Flags |= TraceEventNativeMethods.EVENT_HEADER_FLAG_64_BIT_HEADER;
            else
                eventData->EventHeader.Flags |= TraceEventNativeMethods.EVENT_HEADER_FLAG_32_BIT_HEADER;

            // EventProperty
            eventData->EventHeader.ThreadId = oldStyleHeader->Header.ThreadId;
            eventData->EventHeader.ProcessId = oldStyleHeader->Header.ProcessId;
            eventData->EventHeader.TimeStamp = oldStyleHeader->Header.TimeStamp;
            eventData->EventHeader.ProviderId = oldStyleHeader->Header.Guid;            // ProviderId = TaskId
            // ID left 0
            eventData->EventHeader.Version = (byte)oldStyleHeader->Header.Version;
            // Channel
            eventData->EventHeader.Level = oldStyleHeader->Header.Level;
            eventData->EventHeader.Opcode = oldStyleHeader->Header.Type;
            // Task
            // Keyword
            eventData->EventHeader.KernelTime = oldStyleHeader->Header.KernelTime;
            eventData->EventHeader.UserTime = oldStyleHeader->Header.UserTime;
            // ActivityID

            eventData->BufferContext = oldStyleHeader->BufferContext;
            // ExtendedDataCount
            eventData->UserDataLength = (ushort)oldStyleHeader->MofLength;
            // ExtendedData
            eventData->UserData = oldStyleHeader->MofData;
            // UserContext 

            RawDispatch(eventData);
        }
 internal static extern int TdhGetEventMapInformation(
     TraceEventNativeMethods.EVENT_RECORD* pEvent,
     string pMapName,
     EVENT_MAP_INFO* info,
     ref int infoSize
 );
 internal static extern int TdhGetEventInformation(
     TraceEventNativeMethods.EVENT_RECORD* pEvent,
     uint TdhContextCount,
     void* pTdhContext,
     byte* pBuffer,
     int* pBufferSize);