【问题标题】:ETW: Emitting an event through an existing providerETW:通过现有提供者发出事件
【发布时间】:2013-11-01 09:14:28
【问题描述】:

我有一个使用本机插件的应用程序。这些插件我有自己的二进制格式。每个插件在运行时使用类似于将 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 profiling etw xperf


    【解决方案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}
    

    和来自 Windows 8 SDK (c:\Program Files (x86)\Windows Kits\8.0\Include\um\relogger.h) 的 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-&gt;Inject 会将当前的Event 复制到输出文件中。您可以使用 ITraceRelogger 的 MSDN 来检查允许您更改所需事件属性的可用方法。我感兴趣的方法是SetProviderId()

    另外,请记住 MSDN 声明,ITraceRelogger 在 Windows 7 中可用。这不是我所经历的——我无法在 Windows 7 中实例化这个类,因此 MSDN 可能有关于这个主题的错误信息。

    【讨论】:

    猜你喜欢
    • 2015-06-30
    • 2012-11-01
    • 2019-06-03
    • 2015-02-05
    • 2017-07-06
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 1970-01-01
    相关资源
    最近更新 更多