Поделиться через


Использование идентификаторов GUID для идентификаторов действий в трассировках ТРАССировки СОБЫТИЙ WINDOWS USB

В этом разделе содержатся сведения об идентификаторах GUID действий, о том, как добавить их в поставщики трассировки событий и просмотреть их в Netmon.

Драйверы в стеке драйверов USB (2.0 и 3.0) являются поставщиками трассировки событий Windows. В Windows 7 при записи трассировок событий из стека драйверов USB можно записывать трассировки от других поставщиков, таких как другие драйверы и приложения. Затем можно прочитать объединенный журнал (при условии, что вы создали средство синтаксического анализа Netmon для трассировок событий поставщика).

Начиная с Windows 8, вы можете связывать события между поставщиками (приложениями, клиентским драйвером и стеком драйверов USB) с помощью идентификаторов GUID действий. События от нескольких поставщиков могут быть связаны в Netmon, если события имеют один идентификатор GUID действия. Основываясь на этих идентификаторах GUID, Netmon может показать набор событий USB, которые были вызваны инструментированием действия на верхнем уровне.

При просмотре объединенных трассировок событий от других поставщиков в Netmon щелкните правой кнопкой мыши событие из приложения и выберите Поиск бесед —> NetEvent , чтобы просмотреть связанные события драйвера.

На этом изображении показаны связанные события из приложения, драйвера UMDF и Ucx01000.sys (одного из драйверов в стеке драйверов USB). Эти события имеют одинаковый GUID идентификатора действия.

Microsoft Network Monitor.

Добавление GUID идентификатора действия в приложение

Приложение может включать идентификаторы GUID действий путем вызова EventActivityIdControl. Дополнительные сведения см. в разделе Функции трассировки событий.

В этом примере кода показано, как приложение может задать GUID идентификатора действия и отправить его поставщику трассировки событий Windows , драйверу 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 , чтобы создать идентификатор действия (EVENT_ACTIVITY_CTRL_CREATE_ID), а затем задать его (EVENT_ACTIVITY_CTRL_SET_ID) для текущего потока. Приложение указывает этот GUID действия поставщику событий трассировки событий Windows, например драйверу пользовательского режима, путем отправки определяемого драйвером IOCTL (описанного в следующем разделе).

Поставщик событий должен опубликовать файл манифеста инструментирования (. ФАЙЛ MAN). При запуске компилятора сообщений (Mc.exe) создается файл заголовка, содержащий определения для поставщика событий, атрибутов событий, каналов и событий. В этом примере приложение вызывает EventWriteReadFail, определенные в созданном файле заголовка, для записи сообщений о событиях трассировки в случае сбоя.

Как задать GUID идентификатора действия в драйвере UMDF

Драйвер пользовательского режима создает и задает идентификаторы GUID идентификаторов действий путем вызова EventActivityIdControl , и вызовы аналогичны вызовам в приложении, как описано в предыдущем разделе. Эти вызовы добавляют GUID идентификатора действия в текущий поток, и этот идентификатор GUID действия используется всякий раз, когда поток регистрирует событие. Дополнительные сведения см. в разделе Использование идентификаторов действий.

В этом примере кода показано, как драйвер UMDF задает GUID идентификатора действия, который был создан и указан приложением с помощью 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;
}

Давайте посмотрим, как идентификатор GUID действия, созданный приложением, связывается с драйвером клиента среда выполнения платформы драйвера режима пользователя (UMDF). Когда драйвер получает запрос IOCTL от приложения, он копирует GUID в закрытый член. В какой-то момент приложение вызывает ReadFile для выполнения операции чтения. Платформа создает запрос и вызывает обработчик драйвера ForwardFormattedRequest. В обработчике драйвер задает ранее сохраненный GUID идентификатора действия в потоке, вызывая EventActivityIdControl и EventWriteReadFail для трассировки сообщений о событиях.

Примечание Драйвер UMDF также должен содержать файл заголовка, созданный с помощью файла манифеста инструментирования. Файл заголовка определяет макросы, такие как EventWriteReadFail, которые записывают сообщения трассировки.

Добавление GUID идентификатора действия в драйвер режима ядра

В режиме ядра драйвер может отслеживать сообщения в потоке, который исходит в пользовательском режиме, или потоке, создаваемом драйвером. В обоих случаях драйверу требуется ИДЕНТИФИКАТОР действия GUID потока.

Для трассировки сообщений драйвер должен получить дескриптор регистрации в качестве поставщика событий (см. etwRegister), а затем вызвать EtwWrite , указав GUID и сообщение о событии. Дополнительные сведения см. в статье Добавление трассировки событий в драйверы Kernel-Mode.

Если драйвер режима ядра обрабатывает запрос, созданный приложением или драйвером пользовательского режима, драйвер режима ядра не создает и не задает GUID идентификатора действия. Вместо этого диспетчер ввода-вывода обрабатывает большую часть распространения идентификаторов действий. Когда поток пользовательского режима инициирует запрос, диспетчер ввода-вывода создает IRP для запроса и автоматически копирует ИДЕНТИФИКАТОР действия текущего потока в новую IRP. Если драйвер режима ядра хочет отслеживать события в этом потоке, он должен получить GUID, вызвав IoGetActivityIdIrp, а затем вызвать EtwWrite.

Если драйвер режима ядра создает IRP с идентификатором GUID действия, драйвер может вызвать EtwActivityIdControl с EVENT_ACTIVITY_CTRL_CREATE_SET_ID для создания нового GUID. Затем драйвер может связать новый GUID с IRP, вызвав IoSetActivityIdIrp , а затем вызвав EtwWrite.

Идентификатор действия GUID передается вместе с IRP в следующие более низкие драйверы. Нижние драйверы могут добавлять сообщения трассировки в поток.