我有一个使用本机插件的应用程序。我有自己的二进制格式这些插件。每个插件在运行时使用类似于将DLL映射到进程的方法加载。空间。这意味着,每个插件都有自己的ImageBase
,像.text
或.data
这样的部分的处理方式与传统的DLL相同。唯一不同的是插件的二进制格式(它不是PE
文件)和将插件映射到进程空间的加载器代码。
现在我知道ETW在执行此命令行的跟踪时:
xperf -on latency -stackwalk profile -buffersize 1024 -minbuffers 300 -start tracea1 -on Microsoft-Windows-Win32k:::'stack'
将发出可用于在跟踪捕获期间重建过程环境的事件。也就是说,它会发出类似"添加进程","添加线程到进程","将DLL模块添加到进程"等事件,以便像{等工具{1}}可以构建系统中进程状态的虚拟环境,并构建当前进程树之类的信息。例如,这些事件是ImageLoad个事件,它们提供有关在跟踪之前或跟踪期间加载的每个DLL的信息。
当然,对于我的插件,这些xperfview
事件不会生成,因为它们不是技术上的DLL(即,不是由与DLL相同的函数加载,尽管它们的功能相同)。这就是为什么像ImageLoad
这样的工具不知道它们在过程空间中的存在的原因。
我想做的是在我的插件加载器代码中编写自己的EventWrites,并使用必要的信息发出这些xperfview
事件,以便ImageLoad
和类似的工具,可以将我的插件解释为普通的DLL。我会填写必要的信息,例如xperfview
,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
,这是合乎逻辑的,因为此提供商已经存在。
但这迫使我提出这个问题,即使是ETW也支持我试图做的事情?
答案 0 :(得分:3)
我想我找到了解决方案。
虽然我不知道如何通过现有提供程序实时发出事件,但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(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.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声明,{7}在Windows 7中可用。这不是我所经历的 - 我无法在Windows 7中实例化此类,因此MSDN可能有关于此的错误信息主题。