ULONG EtpStopEtwRundownSession( VOID ) { EtpRundownTraceProperties->LogFileNameOffset = 0; return ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP); }
ULONG StartDotNetTrace( __in PASMPAGE_CONTEXT Context, __out PTRACEHANDLE SessionHandle, __out PEVENT_TRACE_PROPERTIES *Properties ) { ULONG result; ULONG bufferSize; PEVENT_TRACE_PROPERTIES properties; TRACEHANDLE sessionHandle; bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + DotNetLoggerName.Length + sizeof(WCHAR); properties = PhAllocate(bufferSize); memset(properties, 0, sizeof(EVENT_TRACE_PROPERTIES)); properties->Wnode.BufferSize = bufferSize; properties->Wnode.ClientContext = 2; // System time clock resolution properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY; properties->LogFileNameOffset = 0; properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); result = StartTrace(&sessionHandle, DotNetLoggerName.Buffer, properties); if (result == 0) { *SessionHandle = sessionHandle; *Properties = properties; return 0; } else if (result == ERROR_ALREADY_EXISTS) { // Session already exists, so use that. Get the existing session handle. result = ControlTrace(0, DotNetLoggerName.Buffer, properties, EVENT_TRACE_CONTROL_QUERY); if (result != 0) { PhFree(properties); return result; } *SessionHandle = properties->Wnode.HistoricalContext; *Properties = properties; return 0; } else { PhFree(properties); return result; } }
AMDTResult tpCollectImpl::tpStopThreadProfile() { AMDTResult retVal = AMDT_STATUS_OK; ULONG status = ERROR_SUCCESS; //if (!tpIsProfileInitialized()) //{ // retVal = AMDT_ERROR_PROFILE_NOT_CONFIGURED; //} if (!tpIsProfileRunning()) { retVal = AMDT_ERROR_PROFILE_NOT_STARTED; } PEVENT_TRACE_PROPERTIES pSessionProperties = m_pSessionProperties; bool isCollectCStack = m_callstack; if (NULL == pSessionProperties) { retVal = AMDT_ERROR_INTERNAL; } //fprintf(stderr, "tpStopThreadProfile .. retVal(%lx), state(%u)\n", retVal, m_tpState); if (AMDT_STATUS_OK == retVal) { // To disable stack tracing, call this function with InformationClass set to TraceStackTracingInfo // and InformationLength set to 0 if (isCollectCStack) { status = TraceSetInformation(m_sessionHandle, TraceStackTracingInfo, NULL, 0); fprintf(stderr, "Disable stack tracing - TraceSetInformation() status(%lu)\n", status); } status = ControlTrace(m_sessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP); //fprintf(stderr, "ControlTrace(stop) status(%lu)\n", status); if (ERROR_SUCCESS != status) { // FIXME: what to do if it fails fprintf(stderr, "ControlTrace(stop) failed with %lu\n", status); } // TODO: set this only is top succeeds m_tpState = AMDT_THREAD_PROFILE_STATE_UNINITIALIZED; status = tpClear(); } return status; } // tpStopThreadProfile
FORCEINLINE VOID StopTraceListening ( __in TRACEHANDLE SessionHandle, __inout PTRACE_PROPERTIES Properties, __in TRACEHANDLE ConsumingHandle ) { ControlTrace(SessionHandle, LOGGER_NAME, &Properties->TraceProperties, EVENT_TRACE_CONTROL_STOP); CloseTrace(ConsumingHandle); }
ULONG EtpControlEtwSession( _In_ ULONG ControlCode ) { // If we have a session handle, we use that instead of the logger name. EtpTraceProperties->LogFileNameOffset = 0; // make sure it is 0, otherwise ControlTrace crashes return ControlTrace( EtpStartedSession ? EtpSessionHandle : 0, EtpStartedSession ? NULL : EtpActualKernelLoggerName->Buffer, EtpTraceProperties, ControlCode ); }
ULONG UpdateDotNetTraceInfo( _In_ PASMPAGE_QUERY_CONTEXT Context, _In_ BOOLEAN ClrV2 ) { static _EnableTraceEx EnableTraceEx_I = NULL; ULONG result; TRACEHANDLE sessionHandle; PEVENT_TRACE_PROPERTIES properties; PGUID guidToEnable; if (!EnableTraceEx_I) EnableTraceEx_I = PhGetModuleProcAddress(L"advapi32.dll", "EnableTraceEx"); if (!EnableTraceEx_I) return ERROR_NOT_SUPPORTED; result = StartDotNetTrace(&sessionHandle, &properties); if (result != 0) return result; if (!ClrV2) guidToEnable = &ClrRundownProviderGuid; else guidToEnable = &ClrRuntimeProviderGuid; EnableTraceEx_I( guidToEnable, NULL, sessionHandle, 1, TRACE_LEVEL_INFORMATION, CLR_LOADER_KEYWORD | CLR_STARTENUMERATION_KEYWORD, 0, 0, NULL ); result = ProcessDotNetTrace(Context); ControlTrace(sessionHandle, NULL, properties, EVENT_TRACE_CONTROL_STOP); PhFree(properties); return result; }
bool ETW::Stop() { if (isActive) { ULONG controlTraceResult = ControlTrace(openedHandle, KERNEL_LOGGER_NAME, sessionProperties, EVENT_TRACE_CONTROL_STOP); // ERROR_CTX_CLOSE_PENDING(7007L): The call was successful. The ProcessTrace function will stop after it has processed all real-time events in its buffers (it will not receive any new events). // ERROR_BUSY(170L): Prior to Windows Vista, you cannot close the trace until the ProcessTrace function completes. // ERROR_INVALID_HANDLE(6L): One of the following is true: TraceHandle is NULL. TraceHandle is INVALID_HANDLE_VALUE. ULONG closeTraceStatus = CloseTrace(openedHandle); // Wait for ProcessThread to finish WaitForSingleObject(processThreadHandle, INFINITE); BOOL wasThreadClosed = CloseHandle(processThreadHandle); isActive = false; return wasThreadClosed && closeTraceStatus == ERROR_SUCCESS && controlTraceResult == ERROR_SUCCESS; } return false; }
NTSTATUS UpdateDotNetTraceInfoThreadStart( _In_ PVOID Parameter ) { PASMPAGE_QUERY_CONTEXT context = Parameter; TRACEHANDLE sessionHandle; PEVENT_TRACE_PROPERTIES properties; PGUID guidToEnable; context->TraceResult = StartDotNetTrace(&sessionHandle, &properties); if (context->TraceResult != 0) return context->TraceResult; if (!context->TraceClrV2) guidToEnable = &ClrRundownProviderGuid; else guidToEnable = &ClrRuntimeProviderGuid; EnableTraceEx( guidToEnable, NULL, sessionHandle, 1, TRACE_LEVEL_INFORMATION, CLR_LOADER_KEYWORD | CLR_STARTENUMERATION_KEYWORD, 0, 0, NULL ); context->TraceResult = ProcessDotNetTrace(context); ControlTrace(sessionHandle, NULL, properties, EVENT_TRACE_CONTROL_STOP); PhFree(properties); return context->TraceResult; }
int __cdecl wmain() { CLASSIC_EVENT_ID EventId[2]; ULONG Status = ERROR_SUCCESS; TRACEHANDLE SessionHandle = 0; PEVENT_TRACE_PROPERTIES TraceProperties; BOOLEAN TraceStarted = FALSE; ULONG SystemTraceFlags[8]; PWSTR LoggerName = L"MyTrace"; HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); // // Allocate EVENT_TRACE_PROPERTIES structure and perform some // basic initialization. // // N.B. LoggerName will be populated during StartTrace call. // TraceProperties = AllocateTraceProperties(NULL, L"SystemTrace.etl"); if (TraceProperties == NULL) { Status = ERROR_OUTOFMEMORY; goto Exit; } // // Configure additinal trace settings. // TraceProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_SYSTEM_LOGGER_MODE; TraceProperties->Wnode.ClientContext = 1; // Use QueryPerformanceCounter for time stamps TraceProperties->MaximumFileSize = 100; // Limit file size to 100MB max TraceProperties->BufferSize = 512; // Use 512KB trace buffers TraceProperties->MinimumBuffers = 64; TraceProperties->MaximumBuffers = 128; // // Start trace session which can receive events from SystemTraceProvider. // Status = StartTrace(&SessionHandle, LoggerName, TraceProperties); if (Status != ERROR_SUCCESS) { wprintf(L"StartTrace() failed with %lu\n", Status); goto Exit; } TraceStarted = TRUE; // // Configure stack walking. In this example stack traces will be collected on // ImageLoad and ProcessCreate events. // // N.B. Stack tracing is configured before enabling event collection. // ZeroMemory(EventId, sizeof(EventId)); EventId[0].EventGuid = ImageLoadGuid; EventId[0].Type = EVENT_TRACE_TYPE_LOAD; EventId[1].EventGuid = ProcessGuid; EventId[1].Type = EVENT_TRACE_TYPE_START; Status = TraceSetInformation(SessionHandle, TraceStackTracingInfo, EventId, sizeof(EventId)); if (Status != ERROR_SUCCESS) { wprintf(L"TraceSetInformation(StackTracing) failed with %lu\n", Status); goto Exit; } // // Enable system events for Process, Thread and Loader groups. // ZeroMemory(SystemTraceFlags, sizeof(SystemTraceFlags)); SystemTraceFlags[0] = (EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_THREAD | EVENT_TRACE_FLAG_IMAGE_LOAD); Status = TraceSetInformation(SessionHandle, TraceSystemTraceEnableFlagsInfo, SystemTraceFlags, sizeof(SystemTraceFlags)); if (Status != ERROR_SUCCESS) { wprintf(L"TraceSetInformation(EnableFlags) failed with %lu\n", Status); goto Exit; } // // Collect trace for 30 seconds. // Sleep(30 * 1000); Exit: // // Stop tracing. // if (TraceStarted != FALSE) { Status = ControlTrace(SessionHandle, NULL, TraceProperties, EVENT_TRACE_CONTROL_STOP); if (Status != ERROR_SUCCESS) { wprintf(L"StopTrace() failed with %lu\n", Status); } } if (TraceProperties != NULL) { FreeTraceProperties(TraceProperties); } return Status; }
AMDTResult tpCollectImpl::tpStartThreadProfile() { AMDTResult retVal = AMDT_STATUS_OK; ULONG status; if (!tpIsProfileInitialized()) { retVal = AMDT_ERROR_PROFILE_NOT_CONFIGURED; } if (tpIsProfileRunning()) { retVal = AMDT_ERROR_PROFILE_ALREADY_STARTED; } PTRACEHANDLE pSessionHandle = &m_sessionHandle; PEVENT_TRACE_PROPERTIES pSessionProperties = m_pSessionProperties; bool isCollectCStack = m_callstack; if (NULL == pSessionProperties) { retVal = AMDT_ERROR_INTERNAL; } if (AMDT_STATUS_OK == retVal) { // Create the trace session. status = StartTrace(pSessionHandle, KERNEL_LOGGER_NAME, pSessionProperties); if (ERROR_SUCCESS == status) { // StartTrace succeeded. // Events in "NT Kernel Logger", // - EVENT_TRACE_FLAG_THREAD // - Supported Event Type // 1 - EVENT_TRACE_TYPE_START Start thread event. The Thread_V2_TypeGroup1 MOF class defines the // event data for this event // 2 - EVENT_TRACE_TYPE_END End thread event. The Thread_V2_TypeGroup1 MOF class defines the // event data for this event // 36 - Context switch event. The CSwitch MOF class defines the event data for this event // 50 - Ready thread event. The ReadyThread MOF class defines the event data for this event // // - EVENT_TRACE_FLAG_IMAGE_LOAD // - Supported Event Type // 10 - EVENT_TRACE_TYPE_LOAD Image load event. Generated when a DLL or executable file is loaded. // The provider generates only one event for the first time a given DLL is loaded. // The Image_Load MOF class defines the event data for this event // 2 - EVENT_TRACE_TYPE_END End thread event. Image unload event. Generated when a DLL or executable // file is unloaded. The provider generates only one event for the last time a given DLL is unloaded. // The Image_Load MOF class defines the event data for this event // // - EVENT_TRACE_FLAG_CSWITCH // - Enables the following *Thread* event type - CSWITCH // FIXME: Do i need to enable EVENT_TRACE_FLAG_THREAD or just enabling EVENT_TRACE_FLAG_CSWITCH is enough? // // StackWalk_Event class will have the stack data // https://msdn.microsoft.com/en-us/library/windows/desktop/dd392323(v=vs.85).aspx // CLASSIC_EVENT_ID traceCSForClasses[] = { { PerfInfoGuid, 46, { 0 } }, // { ThreadGuid, 36, { 0 } }, // { ThreadGuid, 50, { 0 } } }; if (isCollectCStack) { CLASSIC_EVENT_ID traceCallStackForClasses[] = { //{ g_threadGuid, 1, { 0 } }, // Start Thread Event //{ g_threadGuid, 2, { 0 } }, // End Thread Event { g_threadGuid, 36, { 0 } }, // Context Switch Event //{ g_threadGuid, 50, { 0 } } // Ready Thread Event }; status = TraceSetInformation(*pSessionHandle, TraceStackTracingInfo, traceCallStackForClasses, sizeof(traceCallStackForClasses)); if (ERROR_SUCCESS != status) { retVal = AMDT_ERROR_INTERNAL; fprintf(stderr, "TraceSetInformation() status(%lu)\n", status); } } } else if (ERROR_ALREADY_EXISTS == status) { retVal = AMDT_ERROR_PROFILE_SESSION_EXISTS; fprintf(stderr, "The NT Kernel Logger session is already in use.\n"); // TODO: Use ControlTrace() to update status = ControlTraceW(0, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_UPDATE); fprintf(stderr, "ControlTraceW status(%lu).\n", status); if (ERROR_SUCCESS == status) { retVal = AMDT_STATUS_OK; } else { // FIXME: just for testing purpose status = ControlTrace(m_sessionHandle, KERNEL_LOGGER_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP); } } else { retVal = AMDT_ERROR_INTERNAL; fprintf(stderr, "StartTrace() failed with %lu\n", status); } } if (AMDT_STATUS_OK == retVal) { m_tpState = AMDT_THREAD_PROFILE_STATE_STARTED; } return retVal; } // tpStartThreadProfile