/// <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); }
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; }
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; }
/// <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);