/*++ Copyright (c) 2001-2002 Microsoft Corporation Module Name: uletw.c Abstract: This module contains code for WDM WMI Irps and wrapper functions to send trace events to ETW. Author: Melur Raghuraman (mraghu) 14-Feb-2001 Revision History: --*/ #include "precomp.h" #include "uletwp.h" // // Private globals. // LONG g_UlEtwTraceEnable = 0; TRACEHANDLE g_UlEtwLoggerHandle = 0; #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, UlEtwInitLog ) #pragma alloc_text( PAGE, UlEtwUnRegisterLog ) #pragma alloc_text( PAGE, UlEtwRegisterGuids ) #pragma alloc_text( PAGE, UlEtwEnableLog ) #pragma alloc_text( PAGE, UlEtwDisableLog ) #pragma alloc_text( PAGE, UlEtwDispatch ) #endif // ALLOC_PRAGMA #if 0 NOT PAGEABLE -- UlEtwTraceEvent NOT PAGEABLE -- UlEtwGetTraceEnableFlags #endif // // Public functions. // // // Private functions. // // // Public functions. // /***************************************************************************++ Routine Description: This is the routine in which we call IoWMIRegistrationControl to register for ETW logging. Arguments: pDeviceObject - Supplies a pointer to the target device object. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlEtwInitLog( IN PDEVICE_OBJECT pDeviceObject ) { NTSTATUS status; // // Register wtih ETW // status = IoWMIRegistrationControl(pDeviceObject, WMIREG_ACTION_REGISTER); if (!NT_SUCCESS(status)) { UlTrace(ETW, ( "UlEtwInitLog: IoWMIRegistrationControl failed with %x\n", status )); } return status; } /***************************************************************************++ Routine Description: This is the routine in which we call IoWMIRegistrationControl to Unregister from ETW logging. Arguments: pDeviceObject - Supplies a pointer to the target device object. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlEtwUnRegisterLog( IN PDEVICE_OBJECT pDeviceObject ) { NTSTATUS status; // // Register with ETW. // status = IoWMIRegistrationControl(pDeviceObject, WMIREG_ACTION_DEREGISTER); if (!NT_SUCCESS(status)) { UlTrace(ETW, ( "UlEtwUnRegisterLog: Failed to unregister for ETW support\n" )); } return status; } /***************************************************************************++ Routine Description: This function handles ETW GUID registration. Arguments: EtwRegInfo etwRegInfoSize, pReturnSize Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlEtwRegisterGuids( IN PWMIREGINFO EtwRegInfo, IN ULONG etwRegInfoSize, IN PULONG pReturnSize ) { // // Register a Control Guid as a Trace Guid. // ULONG SizeNeeded; PWMIREGGUIDW EtwRegGuidPtr; ULONG GuidCount; ULONG RegistryPathSize; ULONG MofResourceSize; PUCHAR ptmp; #if DBG GUID UlTestGuid = {0xdd5ef90a, 0x6398, 0x47a4, 0xad, 0x34, 0x4d, 0xce, 0xcd, 0xef, 0x79, 0x5f}; ASSERT(IsEqualGUID(&UlControlGuid, &UlTestGuid)); #endif *pReturnSize = 0; GuidCount = 1; // // Allocate WMIREGINFO for controlGuid + GuidCount. // RegistryPathSize = sizeof(REGISTRY_UL_INFORMATION) - sizeof(WCHAR) + sizeof(USHORT); MofResourceSize = sizeof(UL_TRACE_MOF_FILE) - sizeof(WCHAR) + sizeof(USHORT); SizeNeeded = sizeof(WMIREGINFOW) + GuidCount * sizeof(WMIREGGUIDW) + RegistryPathSize + MofResourceSize; if (SizeNeeded > etwRegInfoSize) { *((PULONG)EtwRegInfo) = SizeNeeded; *pReturnSize = sizeof(ULONG); return STATUS_BUFFER_TOO_SMALL; } RtlZeroMemory(EtwRegInfo, SizeNeeded); EtwRegInfo->BufferSize = SizeNeeded; EtwRegInfo->GuidCount = GuidCount; EtwRegInfo->RegistryPath = sizeof(WMIREGINFOW) + GuidCount * sizeof(WMIREGGUIDW); EtwRegInfo->MofResourceName = EtwRegInfo->RegistryPath + RegistryPathSize; EtwRegGuidPtr = &EtwRegInfo->WmiRegGuid[0]; EtwRegGuidPtr->Guid = UlControlGuid; EtwRegGuidPtr->Flags |= WMIREG_FLAG_TRACED_GUID; EtwRegGuidPtr->Flags |= WMIREG_FLAG_TRACE_CONTROL_GUID; EtwRegGuidPtr->InstanceCount = 0; EtwRegGuidPtr->InstanceInfo = 0; ptmp = (PUCHAR)&EtwRegInfo->WmiRegGuid[1]; *((PUSHORT)ptmp) = sizeof(REGISTRY_UL_INFORMATION) - sizeof(WCHAR); ptmp += sizeof(USHORT); RtlCopyMemory(ptmp, REGISTRY_UL_INFORMATION, sizeof(REGISTRY_UL_INFORMATION) - sizeof(WCHAR) ); ptmp = (PUCHAR)EtwRegInfo + EtwRegInfo->MofResourceName; *((PUSHORT)ptmp) = sizeof(UL_TRACE_MOF_FILE) - sizeof(WCHAR); ptmp += sizeof(USHORT); RtlCopyMemory(ptmp, UL_TRACE_MOF_FILE, sizeof(UL_TRACE_MOF_FILE) - sizeof(WCHAR) ); *pReturnSize = SizeNeeded; return(STATUS_SUCCESS); } NTSTATUS UlEtwEnableLog( IN PVOID Buffer, IN ULONG BufferSize ) { PWNODE_HEADER Wnode=NULL; ASSERT(Buffer); ASSERT(BufferSize >= sizeof(WNODE_HEADER)); Wnode = (PWNODE_HEADER)Buffer; if (BufferSize >= sizeof(WNODE_HEADER)) { ULONG Level; g_UlEtwLoggerHandle = Wnode->HistoricalContext; Level = (ULONG) WmiGetLoggerEnableLevel ( g_UlEtwLoggerHandle ); if (Level > ULMAX_TRACE_LEVEL) { Level = ULMAX_TRACE_LEVEL; } g_UlEtwTraceEnable = (1 << Level); } return STATUS_SUCCESS; } NTSTATUS UlEtwDisableLog( ) { g_UlEtwTraceEnable = 0; g_UlEtwLoggerHandle = 0; return(STATUS_SUCCESS); } NTSTATUS UlEtwDispatch( IN PDEVICE_OBJECT pDO, IN PIRP Irp ) { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); ULONG BufferSize = irpSp->Parameters.WMI.BufferSize; PVOID Buffer = irpSp->Parameters.WMI.Buffer; ULONG ReturnSize = 0; NTSTATUS status = STATUS_SUCCESS; UNREFERENCED_PARAMETER(pDO); switch (irpSp->MinorFunction) { case IRP_MN_REGINFO: { status = UlEtwRegisterGuids( (PWMIREGINFO) Buffer, BufferSize, &ReturnSize); Irp->IoStatus.Information = ReturnSize; Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); break; } case IRP_MN_ENABLE_EVENTS: { status = UlEtwEnableLog( Buffer, BufferSize ); Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); break; } case IRP_MN_DISABLE_EVENTS: { status = UlEtwDisableLog(); Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); break; } default: { status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_NO_INCREMENT ); break; } } return status; } /***************************************************************************++ Routine Description: This is the routine that is called to log a trace event with ETW logger. Arguments: pGuid - Supplies a pointer to the Guid of the event EventType - Type of the event being logged. ... - List of arguments to be logged with this event These are in pairs of PVOID - ptr to argument ULONG - size of argument and terminated by a pointer to NULL, length of zero pair Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlEtwTraceEvent( IN LPCGUID pGuid, IN ULONG EventType, ... ) { NTSTATUS status; UL_ETW_TRACE_EVENT UlEvent; ULONG i; va_list ArgList; PVOID source; SIZE_T len; RtlZeroMemory(& UlEvent, sizeof(EVENT_TRACE_HEADER)); va_start(ArgList, EventType); for (i = 0; i < MAX_MOF_FIELDS; i ++) { source = va_arg(ArgList, PVOID); if (source == NULL) break; len = va_arg(ArgList, SIZE_T); if (len == 0) break; UlEvent.MofField[i].DataPtr = (ULONGLONG) source; UlEvent.MofField[i].Length = (ULONG) len; } va_end(ArgList); UlEvent.Header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR | WNODE_FLAG_USE_GUID_PTR; UlEvent.Header.Size = (USHORT) (sizeof(EVENT_TRACE_HEADER) + (i * sizeof(MOF_FIELD))); UlEvent.Header.Class.Type = (UCHAR) EventType; UlEvent.Header.GuidPtr = (ULONGLONG)pGuid; ((PWNODE_HEADER)&UlEvent)->HistoricalContext = g_UlEtwLoggerHandle; status = IoWMIWriteEvent((PVOID)&UlEvent); #if DBG if (!NT_SUCCESS(status) ) { UlTrace(ETW, ("UL: TraceEvent ErrorCode %x EventType %x\n", status, EventType)); } #endif // DBG return status; } ULONG UlEtwGetTraceEnableFlags( VOID ) { return WmiGetLoggerEnableFlags ( g_UlEtwLoggerHandle ); }