USB ETW 추적에서 활동 ID GUID 사용
이 항목에서는 활동 ID GUID, 이벤트 추적 공급자에 해당 GUID를 추가하고 Netmon에서 보는 방법에 대한 정보를 제공합니다.
USB 드라이버 스택(2.0 및 3.0 모두)의 드라이버는 ETW 이벤트 추적 공급자입니다. Windows 7에서는 USB 드라이버 스택에서 이벤트 추적을 캡처하는 동안 다른 드라이버 및 애플리케이션과 같은 다른 공급자의 추적을 캡처할 수 있습니다. 그런 다음 결합된 로그를 읽을 수 있습니다(공급자의 이벤트 추적에 대한 Netmon 파서가 만들어진 것으로 가정).
Windows 8 시작하여 활동 ID GUID를 사용하여 공급자(애플리케이션, 클라이언트 드라이버 및 USB 드라이버 스택)에서 이벤트를 연결할 수 있습니다. 이벤트가 동일한 활동 ID GUID를 갖는 경우 여러 공급자의 이벤트를 Netmon에 연결할 수 있습니다. 이러한 GUID에 따라 Netmon은 상층에서 계측된 활동으로 인해 발생한 USB 이벤트 집합을 표시할 수 있습니다.
Netmon에서 다른 공급자의 결합된 이벤트 추적을 보는 동안 애플리케이션에서 이벤트를 마우스 오른쪽 단추로 클릭하고 대화 찾기 -> NetEvent 를 선택하여 연결된 드라이버 이벤트를 확인합니다.
이 이미지는 애플리케이션, UMDF 드라이버 및 Ucx01000.sys(USB 드라이버 스택의 드라이버 중 하나)의 관련 이벤트를 보여 줍니다. 이러한 이벤트에는 동일한 활동 ID GUID가 있습니다.
애플리케이션에서 활동 ID GUID를 추가하는 방법
애플리케이션은 EventActivityIdControl을 호출하여 활동 ID GUID를 포함할 수 있습니다. 자세한 내용은 이벤트 추적 기능을 참조하세요.
이 예제 코드는 애플리케이션이 활동 ID GUID를 설정하고 UMDF 드라이버인 ETW 공급자에게 보내는 방법을 보여 드립니다.
EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, &activityIdStruct.ActivityId);
EventActivityIdControl(EVENT_ACTIVITY_CTRL_SET_ID, &activityIdStruct.ActivityId);
if (!DeviceIoControl(hRead,
IOCTL_OSRUSBFX2_SET_ACTIVITY_ID,
&activityIdStruct, // Ptr to InBuffer
sizeof(activityIdStruct), // Length of InBuffer
NULL, // Ptr to OutBuffer
0, // Length of OutBuffer
NULL, // BytesReturned
0)) // Ptr to Overlapped structure
{
wprintf(L"Failed to set activity ID - error %d\n", GetLastError());
}
...
success = ReadFile(hRead, pinBuf, G_ReadLen, (PULONG) &nBytesRead, NULL);
if(success == 0)
{
wprintf(L"ReadFile failed - error %d\n", GetLastError());
EventWriteReadFail(0, GetLastError());
...
}
앞의 예제에서 애플리케이션은 EventActivityIdControl 을 호출하여 활동 ID(EVENT_ACTIVITY_CTRL_CREATE_ID)를 만든 다음 현재 스레드에 대해 설정(EVENT_ACTIVITY_CTRL_SET_ID)합니다. 애플리케이션은 드라이버 정의 IOCTL(다음 섹션에서 설명)을 전송하여 사용자 모드 드라이버와 같은 ETW 이벤트 공급자에 대한 활동 GUID를 지정합니다.
이벤트 공급자는 계측 매니페스트 파일()을 게시해야 합니다. MAN 파일). 메시지 컴파일러(Mc.exe)를 실행하면 이벤트 공급자, 이벤트 특성, 채널 및 이벤트에 대한 정의가 포함된 헤더 파일이 생성됩니다. 이 예제에서 애플리케이션은 생성된 헤더 파일에 정의된 EventWriteReadFail을 호출하여 오류가 발생할 경우 추적 이벤트 메시지를 작성합니다.
UMDF 드라이버에서 활동 ID GUID를 설정하는 방법
사용자 모드 드라이버는 EventActivityIdControl 을 호출하여 활동 ID GUID를 만들고 설정하며, 호출은 이전 섹션에서 설명한 대로 애플리케이션이 호출하는 방식과 유사합니다. 이러한 호출은 현재 스레드에 활동 ID GUID를 추가하고 스레드가 이벤트를 기록할 때마다 해당 활동 ID GUID가 사용됩니다. 자세한 내용은 활동 식별자 사용을 참조하세요.
이 예제 코드는 UMDF 드라이버가 IOCTL을 통해 애플리케이션에서 만들고 지정한 활동 ID GUID를 설정하는 방법을 보여줍니다.
VOID
STDMETHODCALLTYPE
CMyControlQueue::OnDeviceIoControl(
_In_ IWDFIoQueue *FxQueue,
_In_ IWDFIoRequest *FxRequest,
_In_ ULONG ControlCode,
_In_ SIZE_T InputBufferSizeInBytes,
_In_ SIZE_T OutputBufferSizeInBytes
)
/*++
Routine Description:
DeviceIoControl dispatch routine
Arguments:
FxQueue - Framework Queue instance
FxRequest - Framework Request instance
ControlCode - IO Control Code
InputBufferSizeInBytes - Lenth of input buffer
OutputBufferSizeInBytes - Lenth of output buffer
Always succeeds DeviceIoIoctl
Return Value:
VOID
--*/
{
...
switch (ControlCode)
{
....
case IOCTL_OSRUSBFX2_SET_ACTIVITY_ID:
{
if (InputBufferSizeInBytes < sizeof(UMDF_ACTIVITY_ID))
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
else
{
FxRequest->GetInputMemory(&memory );
}
if (SUCCEEDED(hr))
{
buffer = memory->GetDataBuffer(&bigBufferCb);
memory->Release();
m_Device->SetActivityId(&((PUMDF_ACTIVITY_ID)buffer)->ActivityId);
hr = S_OK;
}
break;
}
}
}
VOID
SetActivityId(
LPCGUID ActivityId
)
{
CopyMemory(&m_ActivityId, ActivityId, sizeof(m_ActivityId));
}
void
CMyReadWriteQueue::ForwardFormattedRequest(
_In_ IWDFIoRequest* pRequest,
_In_ IWDFIoTarget* pIoTarget
)
{
...
pRequest->SetCompletionCallback(
pCompletionCallback,
NULL
);
...
hrSend = pRequest->Send(pIoTarget,
0, //flags
0); //timeout
...
if (FAILED(hrSend))
{
contextHr = pRequest->RetrieveContext((void**)&pRequestContext);
if (SUCCEEDED(contextHr)) {
EventActivityIdControl(EVENT_ACTIVITY_CTRL_SET_ID, &pRequestContext->ActivityId);
if (pRequestContext->RequestType == RequestTypeRead)
{
EventWriteReadFail(m_Device, hrSend);
}
delete pRequestContext;
}
pRequest->CompleteWithInformation(hrSend, 0);
}
return;
}
애플리케이션에서 만든 활동 ID GUID가 UMDF( 사용자 모드 드라이버 프레임워크 ) 클라이언트 드라이버와 연결되는 방법을 살펴보겠습니다. 드라이버가 애플리케이션에서 IOCTL 요청을 받으면 프라이빗 멤버에 GUID를 복사합니다. 어떤 시점에서 애플리케이션은 ReadFile 을 호출하여 읽기 작업을 수행합니다. 프레임워크는 요청을 만들고 드라이버의 처리기 ForwardFormattedRequest를 호출합니다. 처리기에서 드라이버는 EventActivityIdControl 및 EventWriteReadFail을 호출하여 이벤트 메시지를 추적하여 스레드에서 이전에 저장된 활동 ID GUID를 설정합니다.
참고 UMDF 드라이버는 계측 매니페스트 파일을 통해 생성된 헤더 파일도 포함해야 합니다. 헤더 파일은 추적 메시지를 작성하는 EventWriteReadFail과 같은 매크로를 정의합니다.
커널 모드 드라이버에서 활동 ID GUID를 추가하는 방법
커널 모드에서 드라이버는 사용자 모드에서 시작되는 스레드 또는 드라이버가 만드는 스레드에서 메시지를 추적할 수 있습니다. 두 경우 모두 드라이버에 스레드의 활동 ID GUID가 필요합니다.
메시지를 추적하려면 드라이버가 이벤트 공급자로 등록 핸들을 가져온 다음( EtwRegister 참조) GUID 및 이벤트 메시지를 지정하여 EtwWrite 를 호출해야 합니다. 자세한 내용은 Kernel-Mode 드라이버에 이벤트 추적 추가를 참조하세요.
커널 모드 드라이버가 애플리케이션 또는 사용자 모드 드라이버에서 만든 요청을 처리하는 경우 커널 모드 드라이버는 활동 ID GUID를 만들고 설정하지 않습니다. 대신 I/O 관리자는 대부분의 활동 ID 전파를 처리합니다. 사용자 모드 스레드가 요청을 시작하면 I/O 관리자는 요청에 대한 IRP를 만들고 현재 스레드의 활동 ID GUID를 새 IRP에 자동으로 복사합니다. 커널 모드 드라이버가 해당 스레드에서 이벤트를 추적하려는 경우 IoGetActivityIdIrp를 호출하여 GUID를 받은 다음 EtwWrite를 호출해야 합니다.
커널 모드 드라이버가 활동 ID GUID를 사용하여 IRP를 만드는 경우 드라이버는 EVENT_ACTIVITY_CTRL_CREATE_SET_ID 사용하여 EtwActivityIdControl 을 호출하여 새 GUID를 생성할 수 있습니다. 그런 다음, 드라이버는 IoSetActivityIdIrp 를 호출한 다음 EtwWrite를 호출하여 새 GUID를 IRP와 연결할 수 있습니다.
활동 ID GUID는 IRP와 함께 다음 하위 드라이버에 전달됩니다. 낮은 드라이버는 스레드에 추적 메시지를 추가할 수 있습니다.