windows - ETW:通过现有提供者发出事件

标签 windows profiling etw xperf

我有一个使用 native 插件的应用程序。我对这些插件有自己的二进制格式。每个插件都是在运行时使用类似于将 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。我会填写必要的信息,例如 ImageBaseProcessIdImageSize 等。

为此,我知道我需要注册事件 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>

并发出事件。

问题是,当我尝试注册另一个 MSNT_SystemTrace 时,我收到了 ERROR_ACCESS_DENIED 消息,这是合乎逻辑的,因为该提供程序已经存在。

但这迫使我问一个问题,我正在尝试做的事情是否得到了 ETW 的支持?

最佳答案

我想我已经找到了解决方案。

虽然我不知道如何通过现有提供程序实时发出事件,但 Windows 8 公开了一个允许修改 ETL 跟踪日志的接口(interface),因此可以更改某个提供程序的 ProviderId事件为不同的值。有问题的接口(interface)是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}
来自 Windows 8 SDK 的

relogger.h 文件 (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.etloutput.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 for ITraceRelogger 检查是否有可用的方法来更改所需的事件属性。我感兴趣的方法是 SetProviderId()

另外,请记住,MSDN 指出,ITraceRelogger 在 Windows 7 中可用。这不是我的经历 - 我无法在 Windows 7 中实例化此类,因此 MSDN 可能会出现错误有关此主题的信息。

关于windows - ETW:通过现有提供者发出事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19535855/

相关文章:

c# - Windows Server 2019 上的 Xamarin 模拟器

java - 如何在 Windows 上卸载 IzPack 安装的应用程序?

java - 开发javaagents时如何运行测试?

MS SQL Server 跟踪日志的收集

c++ - 如何通过 C++ 访问硬盘驱动器的文件系统和扇区?

c# - 通过代码在 Windows 10 上启用平板电脑模式?

java - 如何在 Java WebStart (JNLP) 应用程序中获取多个 hprof 转储?

xcode - Xcode Instrument 的反汇编时间分析的可靠性

logging - 语义记录 : An item with the same key has already been added