2013-10-23 41 views
2

我有一個使用本機插件的應用程序。我有我自己的這些插件的二進制格式。每個插件在運行時使用類似於將DLL映射到進程空間的方法加載。這意味着,每個插件都有自己的ImageBase,像.text.data這樣的部分的處理方式與傳統DLL相同。唯一不同的是插件的二進制格式(它不是PE文件)以及將插件映射到進程空間的加載程序代碼。ETW:通過現有供應商發送活動

現在我知道這個命令行做跟蹤時ETW:

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

會發出可用於跟蹤拍攝期間重建過程環境事件。也就是說,它會發出諸如「添加進程」,「將線程添加到進程」,「將DLL模塊添加到進程」等事件,以便像xperfview這樣的工具可以構建系統中進程狀態的虛擬環境並構建像當前進程樹一樣的信息。例如,這些事件是提供有關每個在之前或在跟蹤過程中加載的每個DLL的信息的ImageLoad事件。

當然,對於我的插件而言,這些ImageLoad事件不會生成,因爲它們在技術上並不是DLL(即,它們不是由與DLL相同的函數加載,儘管它們的功能相同)。這就是爲什麼像xperfview這樣的工具不知道它們在流程空間中的存在。

我想怎麼辦,是寫在我的插件加載代碼我自己EventWrites,並放出這些ImageLoad活動提供必要的信息,使xperfview,和類似的工具,可以解釋我的插件爲正常的DLL。我將填補像ImageBase必要的信息,ProcessIdImageSize

要做到這一點,我明白,我需要註冊事件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的東西?

回答

3

我想我找到了解決方案。

雖然我不知道如何通過現有提供者實時發送事件,但Windows 8公開了允許修改ETL跟蹤日誌的界面,因此可以將事件的ProviderId更改爲不同的值。有問題的界面是ITraceRelogger。你需要這些GUID:從Windows 8 SDK(c:\Program Files (x86)\Windows Kits\8.0\Include\um\relogger.h

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文件。原始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的ITraceRelogger來檢查可用的方法,這將允許您更改所需的事件屬性。我感興趣的方法是SetProviderId()

另外,請記住,MSDN指出,ITraceRelogger在Windows 7中可用。這不是我所經歷的 - 我無法在Windows 7中實例化此類,因此MSDN可能有關於此主題的錯誤信息。

+0

看來,安裝此更新後:http://support.microsoft.com/kb/2882822,你將能夠使用Win7中的這個類。 – antonone