2010-04-04 87 views
5

我在一個大型應用程序上工作,經常使用WinDbg來診斷基於客戶的DMP文件的問題。我已經爲WinDbg寫了一些小擴展,這些擴展已經證明對於從DMP文件中提取信息位非常有用。在我的擴展代碼中,我發現自己以相同的方式反覆引用C++類對象,一次又一次地,手動。例如:如何基於WinDbg擴展中的轉儲文件內存創建對象?

Address = GetExpression("somemodule!somesymbol"); 
ReadMemory(Address, &addressOfPtr, sizeof(addressOfPtr), &cb); 

// get the actual address 
ReadMemory(addressOfObj, &addressOfObj, sizeof(addressOfObj), &cb); 

ULONG offset; 
ULONG addressOfField; 

GetFieldOffset("somemodule!somesymbolclass", "somefield", &offset); 
ReadMemory(addressOfObj+offset, &addressOfField, sizeof(addressOfField), &cb); 

行之有效,但我已經寫了更多的擴展,具有更強大的功能(和訪問我們的應用DMP文件的更多複雜的對象),我渴望一個更好的解決方案。我當然可以訪問我們自己的應用程序的源代碼,所以我認爲應該有一種方法可以將對象從DMP文件中複製出來,並使用該內存在調試器擴展中創建一個實際對象,以便我可以調用函數通過鏈接來自我們的應用程序的DLL)。這可以幫助我省去手工從DMP中取出東西的麻煩。

這甚至可能嗎?我嘗試了一些顯而易見的事情,例如在擴展中創建一個新對象,然後直接從DMP文件中用一個大的ReadMemory覆蓋它。這似乎將數據放在正確的字段中,但是當我試圖調用一個函數時卻嚇壞了。我想我失去了一些東西......也許C++拉了一些我不知道的vtable時髦性?我的代碼看起來與此類似:

SomeClass* thisClass = SomeClass::New(); 
ReadMemory(addressOfObj, &(*thisClass), sizeof(*thisClass), &cb); 

後續:它看起來像從EngExtCpp可能ExtRemoteTyped是我想要的嗎?有沒有人成功使用過這個?我需要谷歌了一些示例代碼,但沒有多少運氣。

跟帖2:我追求這一調查的兩種不同的路線。
1)我期待到ExtRemoteTyped,但現在看來這個類是真的只是爲ReadMemory/GetFieldOffset調用一個幫手。是的,這將有助於加快ALOT的速度,但對於從DMP文件重新創建對象並沒有什麼幫助。儘管文檔很渺茫,所以我可能會誤解某些東西。 2)我也在考慮嘗試使用ReadMemory來使用DMP文件中的數據覆蓋在擴展中創建的對象。但是,我並沒有像上面那樣使用sizeof(* thisClass),而是認爲我只會挑選出數據元素,並保持vtable不變。

+0

偉大的問題PJ! – 2010-04-04 21:52:01

回答

1

有趣的想法,但這隻會對最簡單的對象的工作的希望。例如,如果對象包含指向其他對象(或vtable)的指針或引用,則這些對象不會很好地複製到新的地址空間。

但是,您可能會得到一個「代理」對象來工作,當您調用代理方法時,他們會對ReadMemory()進行適當的調用以獲取信息。這聽起來是相當不錯的工作,而且我認爲對於您想要代理的每個類而言,它必須是或多或少的自定義代碼集。這可能有更好的辦法,但那是我頭頂的東西。

+0

是的,我在想同樣的事情。我認爲指針不能很好地工作,除非我使用ReadMemory跟隨指針並複製了這些數據。但是我仍然可以在課堂上調用函數,不是嗎?你的意思是關於vtables不能很好地複製? – pj4533 2010-04-04 14:30:22

+0

@ pj4533:你可能可以在類上調用函數,但是如果類包含指針或引用,那麼這些函數將會找到一個非常糟糕的對象。你可能會擺脫你在POD類和其他一些簡單的類中所做的事情,但它會是非常可怕的東西。當然,您需要確保您構建調試器擴展的方式使對象佈局相同。 – 2010-04-04 22:24:31

+0

@ pj4533:通過vtables不能很好地複製,我的意思是任何具有虛函數的類中的vtable指針。它指向的是什麼相當於一個函數跳轉表,並且該表的位置將在調試對象和調試器進程中的不同地址處。 – 2010-04-04 22:26:27

0

我知道越來越內存轉儲一向以獲取用於診斷的方式,但它的ETW更多的方便,你得到的調用棧,其中包括信息的系統調用和用戶代碼沿着信息。 MS一直在爲包括Windows和VS.NET在內的所有產品做到這一點。

這是調試的一種非侵入性的方式。我已經做了相同的調試很長時間,現在用ETW,我能夠解決大多數客戶問題,而無需在調試器中花費大量時間。這是我的兩分錢。

+0

我真的沒有學到很多關於Windows事件跟蹤的知識。它似乎需要大量代碼修改(添加對事件跟蹤日誌API的調用)?對於我們的應用程序的所有不同版本來說,這是不可能的,更不用說我們現在仍然支持的多箇舊版本! – pj4533 2010-04-04 20:22:55

0

我對黑客WinDbg的一個GDI泄漏示蹤擴展名,當走近類似的東西。我在客戶端使用stl容器進行數據存儲,並需要一種方法來遍歷擴展中的數據。我最終使用ExtRemoteTyped直接在擴展端實現了需要的hash_map部分,這令人滿意,但花了我一段時間才弄清楚; o) Here是源代碼。

+0

這很有趣,但我認爲我的真正目標是能夠通過其他實用程序例程將對象從轉儲文件傳回,並將它們作爲對象類型進行處理(即:不是「遠程」派生類型) 。 – pj4533 2010-04-05 20:53:21

1

我剛剛聽完我的初始預感,並將dmp文件中的數據複製到一個新對象中。

class SomeClassRemote : public SomeClass 
{ 
protected: 
    SomeClassRemote (void); 
    SomeClassRemote (ULONG inRemoteAddress); 

public: 
    static SomeClassRemote *  New(ULONG inRemoteAddress); 
    virtual ~SomeClassRemote (void); 

private: 

    ULONG     m_Address; 

}; 

並在實施:我通過使遠程包裝對象作出這樣這更好

SomeClassRemote::SomeClassRemote (ULONG inRemoteAddress) 
{ 
    ULONG cb; 

    m_Address = inRemoteAddress; 

    // copy in all the data to the new object, skipping the virtual function tables 
    ReadMemory(inRemoteAddress + 0x4, (PVOID) ((ULONG)&(*this) +0x4), sizeof(SomeClass) - 4, &cb); 
} 

SomeClassRemote::SomeClassRemote(void) 
{ 
} 

SomeClassRemote::~SomeClassRemote(void) 
{ 
} 

SomeClassRemote* SomeClassRemote::New(ULONG inRemoteAddress) 
{ 
    SomeClassRemote*x = new SomeClassRemote(inRemoteAddress); 

    return (x); 
} 

這是基礎,但後來我根據需要添加特定的覆蓋,以抓住從更多信息dmp文件。這種技術允許我將這些新的遠程對象傳回原始源代碼中,以便在各種實用功能中處理,因爲它們是從原始類派生的。

確實像我這樣的SEEMS應該能夠以某種方式進行templatize ......但似乎總有某種原因,每個類的實現方式稍有不同,例如一些更復雜的對象有一對vtables,必須跳過。

相關問題