Partilhar via


Usando GUIDs de ID de atividade em rastreamentos DE ETW USB

Este tópico fornece informações sobre GUIDs de ID de Atividade, como adicionar esses GUIDs nos provedores de rastreamento de eventos e exibi-los no Netmon.

Os drivers na pilha do driver USB (2.0 e 3.0) são provedores de rastreamento de eventos ETW. No Windows 7, ao capturar rastreamentos de eventos da pilha de driver USB, você pode capturar rastreamentos de outros provedores, como outros drivers e aplicativos. Em seguida, você pode ler o log combinado (supondo que você tenha criado um analisador netmon para os rastreamentos de eventos do provedor).

Começando no Windows 8, você pode associar eventos entre provedores (de aplicativos, driver de cliente e pilha de driver USB) usando GUIDs de ID de atividade. Eventos de vários provedores podem ser associados no Netmon quando os eventos têm o mesmo GUID de ID de atividade. Com base nesses GUIDs, o Netmon pode mostrar o conjunto de eventos USB resultantes de uma atividade instrumentada em uma camada superior.

Ao exibir rastreamentos de eventos combinados de outros provedores no Netmon, clique com o botão direito do mouse em um evento de um aplicativo e escolha Localizar Conversas -> NetEvent para ver eventos de driver associados.

Esta imagem mostra eventos relacionados de um aplicativo, driver UMDF e Ucx01000.sys (um dos drivers na pilha de driver USB). Esses eventos têm o mesmo GUID de ID de atividade.

monitor de rede da Microsoft.

Como adicionar um GUID de ID de atividade em um aplicativo

Um aplicativo pode incluir GUIDs de ID de atividade chamando EventActivityIdControl. Para obter mais informações, consulte Funções de rastreamento de eventos.

Este código de exemplo mostra como um aplicativo pode definir um GUID de ID de atividade e enviá-lo para o provedor ETW, um driver 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());

          ...

}

No exemplo anterior, um aplicativo chama EventActivityIdControl para criar uma ID de atividade (EVENT_ACTIVITY_CTRL_CREATE_ID) e, em seguida, defini-la (EVENT_ACTIVITY_CTRL_SET_ID) para o thread atual. O aplicativo especifica esse GUID de atividade para o provedor de eventos ETW, como um driver de modo de usuário, enviando um IOCTL definido pelo driver (descrito na próxima seção).

O provedor de eventos deve publicar um arquivo de manifesto de instrumentação (. Arquivo MAN). Executando o compilador de mensagens (Mc.exe), um arquivo de cabeçalho é gerado que contém definições para o provedor de eventos, atributos de evento, canais e eventos. No exemplo, o aplicativo chama EventWriteReadFail, que são definidos no arquivo de cabeçalho gerado, para gravar mensagens de evento de rastreamento em caso de falha.

Como definir o GUID da ID da atividade em um driver UMDF

Um driver de modo de usuário cria e define GUIDs de ID de atividade chamando EventActivityIdControl e as chamadas são semelhantes à maneira como um aplicativo os chama, conforme descrito na seção anterior. Essas chamadas adicionam o GUID da ID de atividade ao thread atual e esse GUID de ID de atividade é usado sempre que o thread registra um evento. Para obter mais informações, consulte Usando identificadores de atividade.

Este código de exemplo mostra como um driver UMDF define o GUID de ID de atividade que foi criado e especificado pelo aplicativo por meio de um IOCTL.

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

Vamos ver como o GUID da ID de atividade que foi criado pelo aplicativo é associado a um driver de cliente umDF ( User-Mode Driver Framework ). Quando o driver recebe a solicitação IOCTL do aplicativo, ele copia o GUID em um membro privado. Em algum momento, o aplicativo chama ReadFile para executar uma operação de leitura. A estrutura cria uma solicitação e invoca o manipulador do driver, ForwardFormattedRequest. No manipulador, o driver define o GUID da ID da atividade armazenada anteriormente no thread chamando EventActivityIdControl e EventWriteReadFail para rastrear mensagens de evento.

Nota O driver UMDF também deve incluir o arquivo de cabeçalho gerado por meio do arquivo de manifesto de instrumentação. O arquivo de cabeçalho define macros como EventWriteReadFail que gravam mensagens de rastreamento.

Como adicionar GUID de ID de atividade em um driver no modo kernel

No modo kernel, um driver pode rastrear mensagens no thread originado no modo de usuário ou em um thread que o driver cria. Nesses dois casos, o driver requer o GUID de ID de atividade do thread.

Para rastrear mensagens, o driver deve obter o identificador de registro como um provedor de eventos (consulte EtwRegister) e, em seguida, chamar EtwWrite especificando o GUID e a mensagem de evento. Para obter mais informações, consulte Adicionar rastreamento de eventos para drivers de modo kernel.

Se o driver do modo kernel manipular uma solicitação que foi criada por um aplicativo ou um driver de modo de usuário, o driver do modo kernel não criará e definirá um GUID de ID de atividade. Em vez disso, o gerente de E/S manipula a maior parte da propagação da ID da atividade. Quando um thread no modo de usuário inicia uma solicitação, o gerenciador de E/S cria um IRP para a solicitação e copia automaticamente o GUID de ID de atividade do thread atual para o novo IRP. Se o driver do modo kernel quiser rastrear eventos nesse thread, ele deverá obter o GUID chamando IoGetActivityIdIrp e, em seguida, chamar EtwWrite.

Se o driver do modo kernel criar um IRP com um GUID de ID de atividade, o driver poderá chamar EtwActivityIdControl com EVENT_ACTIVITY_CTRL_CREATE_SET_ID para gerar um novo GUID. Em seguida, o driver pode associar o novo GUID ao IRP chamando IoSetActivityIdIrp e, em seguida, chamar EtwWrite.

O GUID da ID da atividade é passado junto com o IRP para os próximos drivers inferiores. Os drivers inferiores podem adicionar suas mensagens de rastreamento ao thread.