ETW: отправка события через существующего провайдера

У меня есть приложение, которое использует родные плагины. У меня есть свой собственный двоичный формат для этих плагинов. Каждый плагин загружается во время выполнения, используя метод, похожий на отображение DLL в пространство процесса. Это означает, что каждый плагин имеет свой собственный ImageBase, разделы, как .text или же .data обрабатываются так же, как обычные библиотеки DLL. Единственное, что отличается, это двоичный формат плагина (это не PE файл) и код загрузчика, который отображает плагин в пространство процесса.

Теперь я знаю, что ETW при выполнении трассировки с помощью этой командной строки:

xperf -on latency -stackwalk profile -buffersize 1024 -minbuffers 300 -start tracea1 -on Microsoft-Windows-Win32k:::'stack' 

будет генерировать события, которые могут быть использованы для восстановления среды процесса во время захвата трассировки. То есть он будет генерировать такие события, как "добавить процесс", "добавить поток в процесс", "добавить модуль DLL в процесс", чтобы такие инструменты, как xperfview может создавать виртуальную среду состояния процессов в системе и создавать информацию, подобную текущему дереву процессов. Эти события, например, события ImageLoad, которые предоставляют информацию о каждой DLL, которая загружается до или во время трассировки.

Конечно, для моих плагинов эти ImageLoad события не генерируются, потому что они не являются технически DLL (то есть не загружаются теми же функциями, что и DLL, хотя их функция одинакова). Вот почему такие инструменты, как xperfview не знаю об их существовании в пространстве процесса.

Я хотел бы написать свои собственные EventWrites в моем коде загрузчика плагинов и создать их ImageLoad события с необходимой информацией, так что xperfviewи подобные инструменты могут интерпретировать мои плагины как обычные библиотеки DLL. Я бы заполнил необходимую информацию, как ImageBase, ProcessId, ImageSize, так далее.

Для этого я понимаю, что мне нужно зарегистрировать событие MSNT_SystemTrace поставщик, который является владельцем ImageLoad события, создайте событие с такой структурой:

    <Data Name="ImageBase">0x7FEFDBD0000</Data>
    <Data Name="ImageSize">0x12D000</Data>
    <Data Name="ProcessId">     548</Data>
    ...
    <Data Name="Reserved0">       0</Data>
    <Data Name="DefaultBase">0x7FEFDBD0000</Data>

и выпустить событие.

Проблема в том, что я получаю ERROR_ACCESS_DENIED при попытке зарегистрировать другое MSNT_SystemTrace, что логично, так как этот провайдер уже существует.

Но это заставляет меня задавать вопрос, поддерживает ли ETW то, что я пытаюсь сделать?

1 ответ

Решение

Я думаю, что нашел решение.

Хотя я не знаю, как отправлять событие через существующего провайдера в режиме реального времени, Windows 8 предоставляет интерфейс, который позволяет изменять журналы трассировки ETL, поэтому можно изменить ProviderId события с другим значением. Интерфейс, о котором идет речь ITraceRelogger, Вам нужны эти направляющие:

EXTERN_GUID(CLSID_TraceRelogger, 0x7b40792d, 0x05ff, 0x44c4, 0x90, 0x58, 0xf4, 0x40, 0xc7, 0x1f, 0x17, 0xd4);
DEFINE_GUID(IID_ITraceRelogger, 0xF754AD43, 0x3BCC, 0x4286, 0x80, 0x09,0x9C, 0x5D, 0xA2, 0x14, 0xE8, 0x4E); // {F754AD43-3BCC-4286-8009-9C5DA214E84E}
DEFINE_GUID(IID_ITraceEventCallback, 0x3ED25501, 0x593F, 0x43E9, 0x8F, 0x38,0x3A, 0xB4, 0x6F, 0x5A, 0x4A, 0x52); // {3ED25501-593F-43E9-8F38-3AB46F5A4A52}

а также relogger.h файл из Windows 8 SDK (c:\Program Files (x86)\Windows Kits\8.0\Include\um\relogger.h). оригинал relogger.h кажется, что-то не работает, потому что он ссылается на некоторые внешние символы, но кажется, что нет никакого файла LIB, чтобы дополнить его. Я уверен, что вам удастся решить эту проблему, хотя!

Чтобы использовать его, просто создайте экземпляр:

ITraceRelogger *relog = NULL;
hres = CoCreateInstance(CLSID_TraceRelogger, 0, CLSCTX_INPROC_SERVER, IID_ITraceRelogger2, (LPVOID *)& relog);

добавить тебя input.etl а также output.etl файлы:

#include <windows.h>
#include <cguid.h>
#include <atlbase.h>
#include <comdef.h>
...
CComBSTR input = "input.etl";
CComBSTR output = "output.etl";
...
hres = relog->AddLogfileTraceStream(input, NULL, & trace);
...
hres = relog->SetOutputFilename(output);

Затем вам нужно зарегистрировать обратный вызов, который будет обрабатывать изменение события. Пример реализации обратного вызова события находится в конце этого ответа. Вот код о том, как использовать его с текущим ITraceRelogger:

EventCallback *ec = new EventCallback();
hres = relog->RegisterCallback(ec);
...
hres = relog->ProcessTrace();

Предупреждение:ProcessTrace() вернет ошибку, если вы не зарегистрировали никаких обратных вызовов.

Вот пример рабочего обратного вызова:

class EventCallback: public ITraceEventCallback {
private:
    DWORD ref_count;
    DWORD64 evno;

public:
    EventCallback() {
        ref_count = 0;
        evno = 0;
    }

    STDMETHODIMP QueryInterface(const IID& iid, void **obj) {
        if(iid == IID_IUnknown) {
            *obj = dynamic_cast<IUnknown *>(this);
        } else if(iid == IID_ITraceEventCallback) {
            *obj = dynamic_cast<ITraceEventCallback *>(this);
        } else {
            *obj = NULL;
            return E_NOINTERFACE;
        }

        return S_OK;
    }

    STDMETHODIMP_ (ULONG) AddRef(void) {
        return InterlockedIncrement(& ref_count);
    }

    STDMETHODIMP_ (ULONG) Release() {
        ULONG ucount = InterlockedDecrement(& ref_count);
        if(ucount == 0) {
            delete this;
        }

        return ucount;
    }

    HRESULT STDMETHODCALLTYPE OnBeginProcessTrace(ITraceEvent *HeaderEvent, ITraceRelogger *Relogger)   {
        return S_OK;
    }

    HRESULT STDMETHODCALLTYPE OnEvent(ITraceEvent *Event, ITraceRelogger *Relogger) {
        // Your main method.
        evno++;
        Relogger->Inject(Event);
    }


    HRESULT STDMETHODCALLTYPE OnFinalizeProcessTrace(ITraceRelogger *Relogger) {
        return S_OK;
    }
};

Relogger->Inject будет копировать текущий Event в выходной файл. Вы можете использовать MSDN для ITraceRelogger проверить наличие доступных методов, которые позволят вам изменить требуемые свойства события. Метод, который меня интересовал, был SetProviderId(),

Кроме того, имейте в виду, что MSDN утверждает, что ITraceRelogger доступно в Windows 7. Это не то, что я испытал - я не могу создать экземпляр этого класса в Windows 7, поэтому MSDN может иметь неверную информацию по этому вопросу.

Другие вопросы по тегам