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가 있습니다.

JJ151578.netmon_activity(ko-kr,VS.85).png

응용 프로그램에서 작업 ID GUID를 추가하는 방법

응용 프로그램은 EventActivityIdControl을 호출하여 작업 ID GUID를 포함할 수 있습니다. 자세한 내용은 이벤트 추적 함수를 참조하세요.

이 예제 코드는 응용 프로그램이 작업 ID GUID를 설정하고 ETW 공급자인 UMDF 드라이버에 보내는 방법을 보여 줍니다.


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)를 만든 다음 현재 스레드에 대해 작업 ID(EVENT_ACTIVITY_CTRL_SET_ID)를 설정합니다. 응용 프로그램은 드라이버 정의 IOCTL(다음 섹션에서 설명)을 보내서 사용자 모드 드라이버와 같은 ETW 이벤트 공급자에 대한 작업 GUID를 지정합니다.

이벤트 공급자는 계측 매니페스트 파일(.MAN 파일)을 게시해야 합니다. message compiler (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

Aruments:
    
    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를 private 멤버에 복사합니다. 특정 시점에 응용 프로그램이 ReadFile을 호출하여 읽기 작업을 수행합니다. 프레임워크는 요청을 만들고 드라이버 처리기 ForwardFormattedRequest를 호출합니다. 처리기에서 드라이버는 이벤트 메시지를 추적하기 위해 EventActivityIdControl 및 EventWriteReadFail을 호출하여 스레드에서 이전에 저장된 작업 ID GUID를 설정합니다.

참고  UMDF 드라이버에는 계측 매니페스트 파일을 통해 생성된 헤더 파일도 포함되어야 합니다. 헤더 파일은 추적 메시지를 쓰는 EventWriteReadFail과 같은 매크로를 정의합니다.

커널 모드 드라이버에서 작업 ID GUID를 추가하는 방법

커널 모드에서 드라이버는 사용자 모드에서 시작된 스레드 또는 드라이버가 만든 스레드에서 메시지를 추적할 수 있습니다. 두 가지 경우 모두 드라이버에는 스레드의 작업 ID GUID가 필요합니다.

메시지를 추적하기 위해 드라이버는 등록 핸들을 이벤트 공급자로 가져온 다음(EtwRegister 참조) GUID 및 이벤트 메시지를 지정하여 EtwWrite를 호출해야 합니다. 자세한 내용은 커널 모드 드라이버에 이벤트 추적 추가를 참조하세요.

커널 모드 드라이버가 응용 프로그램이나 사용자 모드 드라이버에서 생성된 요청을 처리하는 경우 커널 모드 드라이버는 작업 ID GUID를 만들고 설정하지 않습니다. 대신에 I/O 관리자가 대부분의 작업 ID 전파를 처리합니다. 사용자 모드 스레드가 요청을 시작하면 I/O 관리자가 요청에 대한 IRP를 만들고 자동으로 현재 스레드의 작업 ID GUID를 새 IRP로 복사합니다. 커널 모드 드라이버가 해당 스레드에서 이벤트를 추적하려면 IoGetActivityIdIrp를 호출하여 GUID를 가져온 다음 EtwWrite를 호출해야 합니다.

커널 모드 드라이버가 작업 ID GUID를 사용하여 IRP를 만들면 드라이버가 EtwActivityIdControl을 EVENT_ACTIVITY_CTRL_CREATE_SET_ID와 함께 호출하여 새 GUID를 생성할 수 있습니다. 그런 다음 드라이버가 IoSetActivityIdIrp를 호출하여 새 GUID를 IRP와 연결한 다음 EtwWrite를 호출할 수 있습니다.

작업 ID GUID는 IRP와 함께 다음 하위 드라이버로 전달됩니다. 하위 드라이버가 추적 메시지를 스레드에 추가할 수 있습니다.

관련 항목

Windows용 USB 이벤트 추적

 

 

표시:
© 2015 Microsoft