Ejemplo n.º 1
0
 public bool EnableKernelProvider(KernelTraceEventParser.Keywords flags)
 {
     return EnableKernelProvider(flags, KernelTraceEventParser.Keywords.None);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// #EnableKernelProvider
        /// Enable the kernel provider for the session. If the session must be called 'NT Kernel Session'.   
        /// <param name="flags">
        /// Specifies the particular kernel events of interest</param>
        /// <param name="stackCapture">
        /// Specifies which events should have their eventToStack traces captured too (VISTA+ only)</param>
        /// <returns>Returns true if the session had existed before and is now restarted</returns>
        /// </summary>
        public unsafe bool EnableKernelProvider(KernelTraceEventParser.Keywords flags, KernelTraceEventParser.Keywords stackCapture)
        {
            bool systemTraceProvider = false;
            var version = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor;
            if (m_SessionName != KernelTraceEventParser.KernelSessionName)
            {
                systemTraceProvider = true;
                if (version < 62)
                    throw new NotSupportedException("System Tracing is only supported on Windows 8 and above.");
            }
            else
            {
                if (m_SessionHandle != TraceEventNativeMethods.INVALID_HANDLE_VALUE)
                    throw new Exception("The kernel provider must be enabled as the only provider.");
                if (version < 60)
                    throw new NotSupportedException("Kernel Event Tracing is only supported on Windows 6.0 (Vista) and above.");
            }

            // The Profile event requires the SeSystemProfilePrivilege to succeed, so set it.  
            if ((flags & (KernelTraceEventParser.Keywords.Profile | KernelTraceEventParser.Keywords.PMCProfile)) != 0)
            {
                TraceEventNativeMethods.SetSystemProfilePrivilege();
                // TODO FIX NOW never fails.  
                if (CpuSampleIntervalMSec != 1)
                {
                    if (!TraceEventNativeMethods.CanSetCpuSamplingRate())
                        throw new ApplicationException("Changing the CPU sampling rate is currently not supported on this OS.");
                }
                var cpu100ns = (CpuSampleIntervalMSec * 10000.0 + .5);
                // The API seems to have an upper bound of 1 second.  
                if (cpu100ns >= int.MaxValue || ((int)cpu100ns) > 10000000)
                    throw new ApplicationException("CPU Sampling rate is too high.");
                var succeeded = TraceEventNativeMethods.SetCpuSamplingRate((int)cpu100ns);       // Always try to set, since it may not be the default
                if (!succeeded && CpuSampleIntervalMSec != 1.0F)
                    throw new InvalidOperationException("Can't set CPU sampling to " + CpuSampleIntervalMSec.ToString("f3") + "Msec.");
            }

            var propertiesBuff = stackalloc byte[PropertiesSize];
            var properties = GetProperties(propertiesBuff);

            // Initialize the stack collecting information
            const int stackTracingIdsMax = 96;
            int numIDs = 0;
            var stackTracingIds = stackalloc TraceEventNativeMethods.STACK_TRACING_EVENT_ID[stackTracingIdsMax];
            if (stackCapture != KernelTraceEventParser.Keywords.None)
                numIDs = SetStackTraceIds(stackCapture, stackTracingIds, stackTracingIdsMax);

            bool ret = false;
            int dwErr;
            try
            {
                if (systemTraceProvider)
                {
                    properties->LogFileMode = properties->LogFileMode | TraceEventNativeMethods.EVENT_TRACE_SYSTEM_LOGGER_MODE;
                    InsureStarted(properties);

                    dwErr = TraceEventNativeMethods.TraceSetInformation(m_SessionHandle,
                                                                        TraceEventNativeMethods.TRACE_INFO_CLASS.TraceStackTracingInfo,
                                                                        stackTracingIds,
                                                                        (numIDs * sizeof(TraceEventNativeMethods.STACK_TRACING_EVENT_ID)));
                    Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(dwErr));

                    ulong* systemTraceFlags = stackalloc ulong[1];
                    systemTraceFlags[0] = (ulong)(flags & ~KernelTraceEventParser.Keywords.NonOSKeywords);
                    dwErr = TraceEventNativeMethods.TraceSetInformation(m_SessionHandle,
                                                                        TraceEventNativeMethods.TRACE_INFO_CLASS.TraceSystemTraceEnableFlagsInfo,
                                                                        systemTraceFlags,
                                                                        sizeof(ulong));
                    Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(dwErr));
                    ret = true;
                }
                else
                {
                    properties->Wnode.Guid = KernelTraceEventParser.ProviderGuid;
                    properties->EnableFlags = (uint)flags;

                    dwErr = StartKernelTrace(out m_SessionHandle, properties, stackTracingIds, numIDs);
                    if (dwErr == 0xB7) // STIERR_HANDLEEXISTS
                    {
                        ret = true;
                        Stop();
                        m_Stopped = false;
                        Thread.Sleep(100);  // Give it some time to stop. 
                        dwErr = StartKernelTrace(out m_SessionHandle, properties, stackTracingIds, numIDs);
                    }
                }
            }
            catch (BadImageFormatException)
            {
                // We use a small native DLL called KernelTraceControl that needs to be 
                // in the same directory as the EXE that used TraceEvent.dll.  Unlike IL
                // Native DLLs are specific to a processor type (32 or 64 bit) so the easiestC:\Users\vancem\Documents\etw\traceEvent\TraceEventSession.cs
                // way to insure this is that the EXE that uses TraceEvent is built for 32 bit
                // and that you use the 32 bit version of KernelTraceControl.dll
                throw new BadImageFormatException("Could not load KernelTraceControl.dll (likely 32-64 bit process mismatch)");
            }
            catch (DllNotFoundException)
            {
                // In order to start kernel session, we need a support DLL called KernelTraceControl.dll
                // This DLL is available by downloading the XPERF.exe tool (see 
                // http://msdn.microsoft.com/en-us/performance/cc825801.aspx for instructions)
                // It is recommended that you get the 32 bit version of this (it works on 64 bit machines)
                // and build your EXE that uses TraceEvent to launch as a 32 bit application (This is
                // the default for VS 2010 projects).  
                throw new DllNotFoundException("KernelTraceControl.dll missing from distribution.");
            }
            if (dwErr == 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(dwErr));
            m_IsActive = true;

            if (version >= 62 && StackCompression)
                TraceEventNativeMethods.EnableStackCaching(m_SessionHandle);
            return ret;
        }
Ejemplo n.º 3
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;
        }