Partilhar via


Usando GUIDs de ID de atividade em rastreamentos 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 de drivers USB (2.0 e 3.0) são provedores de rastreamento de eventos ETW. No Windows 7, ao capturar registos de eventos da pilha de drivers USB, pode-se capturar registos de outros fornecedores, como outros drivers e aplicações. Em seguida, você pode ler o log combinado (supondo que você tenha criado um analisador Netmon para os rastreamentos de eventos do seu provedor).

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

Ao visualizar 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 os eventos de driver associados.

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

Microsoft Network Monitor.

Como adicionar um GUID de ID de atividade num aplicativo

Uma aplicação 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 (. MAN). Ao executar o compilador de mensagens (Mc.exe), é gerado um arquivo de cabeçalho que contém definições para o provedor de eventos, atributos de eventos, 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 de ID de 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 as chama, conforme descrito na seção anterior. Essas chamadas adicionam o GUID de atividade à tarefa atual, e esse GUID de atividade é usado sempre que a tarefa 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 de ID de atividade que foi criado pelo aplicativo é associado a um driver de cliente User-Mode Driver Framework (UMDF). 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 de ID de atividade armazenado anteriormente no thread chamando EventActivityIdControl e EventWriteReadFail para rastrear mensagens de eventos.

Observação O driver UMDF também deve incluir o ficheiro de cabeçalho que é gerado a partir do ficheiro 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 num driver em modo kernel

No modo kernel, um driver pode rastrear mensagens no thread que se origina no modo de usuário ou um thread que o driver cria. Em ambos os 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 do evento. Para obter mais informações, consulte Adicionar rastreamento de eventos aos Kernel-Mode drivers.

Se o driver em modo de kernel processa uma solicitação que foi criada por uma aplicação ou um driver em modo de usuário, o driver em modo de kernel não cria e define um GUID de ID de atividade. Em vez disso, o gestor de E/S lida com a maior parte da propagação do identificador de atividade. Quando um thread de modo de usuário inicia uma solicitação, o gerente 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 de modo kernel quiser rastrear eventos nesse thread, ele deve obter o GUID chamando IoGetActivityIdIrpe, em seguida, chame EtwWrite.

Se o driver de 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. O driver pode então associar o novo GUID ao IRP ao chamar IoSetActivityIdIrp e, em seguida, chamar EtwWrite.

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