如何利用adplus來dump某個process的memory

來源:互聯網
上載者:User

前面提到了dump檔案能儲存進程狀態,方便分析。由於dump檔案記錄的是進程某一時刻的具體資訊,所以儲存dump的時機非常重要。比如程式崩潰,dump應該選在引發崩潰的指令執行時(也就是1st chance exception發生的時候)擷取,這樣分析dump的時候就能夠看到問題的直接原因。

Adplus是跟Windbg在同一個目錄的VBS指令碼。Adplus主要是用來抓取dump檔案。 詳細的資訊,可以參考Windbg協助檔案中關於adplus的協助。有下面一些常見用法:

假設我們的目標程式是test.exe:

假設test.exe運行一段時間崩潰,在test.exe啟動後崩潰前的這個時間段,運行下面的命令監視:

 Adplus –crash –pn test.exe –o C:\dumps

當test.exe發生2nd chance exception崩潰的時候,adplus在C:\dumps產生full dump檔案。當發生1st chance AV exception, 或者1st chance breakpoint exception的時候,adplus在C:\dumps產生mini dump檔案。

也可以用:

 Adplus –crash –pn test.exe –fullonfirst –o C:\dumps

差別在於,加上-fullonfirst參數後,無論是1st chance exception還是2nd chance exception,都會產生full dump檔案。
假如test.exe發生deadlock,或者memory leak,並不是crash,需要擷取任意時刻的一個dump,可以用下面的命令:

 Adplus –hang –pn test.exe –o C:\dumps

該命令立刻把test.exe的full dump 抓到C:\dumps下。

Adplus更靈活的方法就是用-c參數帶設定檔。在設定檔裡面,可以選擇exception發生的時間,產生的dump是mini dump還是full dump,還可以設定斷點等等。對於adplus各項參數的選用原則,在最後一章還會作進一步介紹。

案例分析:華生醫生(Dr. Watson)在什麼情況下不能記錄Dump檔案

問題描述

客戶聲稱用VC開發的程式偶爾會崩潰。為了擷取詳細資料,客戶啟用了Dr. Watson,以便程式崩潰的時候可以自動擷取dump檔案。但是問題再次發生後,Dr. Watson並沒有記錄dump檔案。

背景知識

dump檔案包含的是記憶體鏡像資訊。在Windows系統上,dump檔案分為核心dump和使用者態dump兩種。前者一般用來分析核心相關的問題,比如驅動程式;後者一般用來分析使用者態程式的問題。如果不作說明,本書後面所指的dump都表示使用者態dump。使用者態的dump又分成mini dump和full dump。前者尺寸小,只記錄一些常用資訊;後者則是把目標進程使用者態的所有內容都記錄下來。Windows提供了MiniDumpWriteDump API可供程式調用來產生mini dump。通過調試器和相關工具,可以抓取目標程式的full dump。拿到dump後,可以通過調試器檢查dump中的內容,比如call stack,memory,exception等等。關於dump和調試器的更詳細資料,後面會有更多介紹。跟Dr. Watson相關的文檔是:

 Description of the Dr. Watson for Windows (Drwtsn32.exe) Tool
http://support.microsoft.com/?id=308538
Specifying the Debugger for Unhandled User Mode Exceptions
http://support.microsoft.com/?id=121434
INFO: Choosing the Debugger That the System Will Spawn
http://support.microsoft.com/?id=103861

也就是說,通過設定註冊表中的AeDebug項,可以在程式崩潰後,選擇調試器進行調試。選擇Dr. Watson就可以直接產生dump檔案。

問題分析

回到這個問題,客戶並沒有擷取到dump檔案,可能性有兩個:

1. Dr. Watson工作不正常。
2. 客戶的程式根本沒有崩潰,不過是正常退出而已。

為了測試第1點,提供了如下的代碼給客戶測試:

int *p=0;
*p=0;

測試上面的代碼,Dr. Watson成功地擷取了dump檔案。也就是說,Dr. Watson工作是正常的。那看來客戶聲稱的崩潰可能並不是unhandled exception導致的。說不定在非預料情況下調用了ExitProcess,被客戶誤認為是崩潰。所以,抓取資訊不應該局限於unhandled exception,而應該檢查進程退出的原因。

當程式在Windbg調試器中退出的時候,系統會觸發調試器的進程退出訊息,可以在這個時候抓取dump來分析進程退出的原因。

如果讓客戶每次都先啟動Windbg,然後用Windbg啟動程式,操作起來很複雜。最好有一個自動的方法。Windows提供了讓指定程式隨調試器啟動的選項。設定註冊表後,當設定的進程啟動的時候,系統先啟動指定的調試器,然後把目標進程的地址和命令列作為參數傳遞給調試器,調試器再啟動目標進程調試。這個選項在無法手動從調試器中啟動程式的時候特別有用,比如調試先於使用者登入而啟動Windows Service程式,就必須使用這個方法:

How to debug Windows services
http://support.microsoft.com/?kbid=824344

有趣的是,好多惡意程式也通過這個方法來達到載入進程的目的。很多人把這個方法叫做IFEO 劫持(Image File Execution Option Hacking)。

在Windbg目錄下,有一個叫做adplus.vbs的指令碼可以方便地調用Windbg來擷取dump檔案。所以這裡可以借用這個指令碼:

How to use ADPlus to troubleshoot "hangs" and "crashes"
http://support.microsoft.com/kb/286350/EN-US/

指令碼的詳細說明可以參考adplus /?的協助。

新的做法

結合上面的資訊,具體做法是:

1. 在客戶機器的Image File Execution Options註冊表下面建立跟問題程式同名的鍵。
2. 在這個鍵的下面建立Debugger字串類型子鍵。
3. 設定Debugger= C:\Debuggers\autodump.bat。
4. 編輯C:\Debuggers\autodump.bat檔案的內容為如下:

cscript.exe C:\Debuggers\adplus.vbs -crash -o C:\dumps -quiet -sc %1

通過上面的設定,當程式啟動的時候,系統自動運行cscript.exe來執行adplus.vbs指令碼。Adplus.vbs指令碼的-sc參數指定需要啟動的目標進程路徑(路徑作為參數又系統傳入,bat檔案中的%1代表這個參數),-crash參數表示監視進程退出,-o參數指定dump檔案路徑,-quiet參數取消額外的提示。可以用notepad.exe作為小白鼠做一個實驗,看看關閉notepad.exe的時候,是否有dump產生。

根據上面的設定,問題再次發生後,C:\dumps目錄產生了兩個dump檔案。檔案名稱分別是:

PID-0__Spawned0__1st_chance_Process_Shut_Down__full_178C_DateTime_0928.dmp
PID-0__Spawned0__2nd_chance_CPlusPlusEH__full_178C_2006-06-21_DateTime_0928.dmp

注意看第二個的名字,這個名字表示發生2nd chance的C++ exception!開啟這個dump後找到了對應的call stack,發現的確是客戶忘記了catch潛在的C++異常。修改代碼添加對應的catch後,問題解決。

問題解決了,可是為什麼華生醫生(Dr. Watson)抓不到dump呢

當然疑問並沒有隨著問題的解決而結束。既然是unhandled exception導致的crash,為什麼Dr. Watson抓不到呢?首先建立兩個不同的程式來測試Dr. Watson的行為:

int _tmain(int argc, _TCHAR* argv[])
{
throw 1; 
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
int *p=0;
*p=0;
return 0;
}

果然,對於第一個程式,Dr. Watson並沒有儲存dump檔案。對於第二個,Dr. Watson工作正常。看來的確跟異常類型相關。

仔細回憶一下。當AeDebug下的Auto設定為0的時候,系統會彈出前面提到的紅色框框。對於上面這兩個程式,框框的內容是不一樣的。

在我這裡,看到的對話方塊分別是(對話方塊出現的時候用Ctrl+C儲存的資訊):

            

---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Error!
Program: d:\xiongli\today\exceptioninject\debug\exceptioninject.exe
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
(Press Retry to debug the application)
---------------------------
Abort   Retry   Ignore  
---------------------------


---------------------------
exceptioninject.exe - Application Error
---------------------------
The instruction at "0x00411908" referenced memory at "0x00000000".
The memory could not be "written".

Click on OK to terminate the program
Click on CANCEL to debug the program
---------------------------
OK   Cancel  
---------------------------

兩者行為完全不一樣!如果做更多的測試,會發現對話方塊的細節還跟編譯模式release/debug 相關。

程式可以通過SetUnhandledExceptionFilter函數來修改unhanded exception的預設處理函數。這裡,C++運行庫在初始化CRT(C Runtime)的時候,傳入了CRT的處理函數 (msvcrt!CxxUnhandledExceptionFilter)。如果發生unhandled exception,該函數會判斷異常的號碼,如果是C++異常,就會彈出第一個對話方塊,否則就交給系統預設的處理函數(kernel32!UnhandledExceptionFilter)處理。第一種情況的call stack 如下:

USER32!MessageBoxA
MSVCR80D!__crtMessageBoxA
MSVCR80D!__crtMessageWindowA
MSVCR80D!_VCrtDbgReportA
MSVCR80D!_CrtDbgReportV
MSVCR80D!_CrtDbgReport
MSVCR80D!_NMSG_WRITE
MSVCR80D!abort
MSVCR80D!terminate
MSVCR80D!__CxxUnhandledExceptionFilter
kernel32!UnhandledExceptionFilter
MSVCR80D!_XcptFilter

第二種情況CRT交給系統處理。Callstack如下:

ntdll!KiFastSystemCallRet
ntdll!ZwRaiseHardError+0xc
kernel32!UnhandledExceptionFilter+0x4b4
release_crash!_XcptFilter+0x2e
release_crash!mainCRTStartup+0x1aa
release_crash!_except_handler3+0x61
ntdll!ExecuteHandler2+0x26
ntdll!ExecuteHandler+0x24
ntdll!KiUserExceptionDispatcher+0xe
release_crash!main+0x28
release_crash!mainCRTStartup+0x170
kernel32!BaseProcessStart+0x23

詳細的資訊可以參考:

SetUnhandledExceptionFilter
http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/debug/base/setunhandledexceptionfilter.asp
UnhandledExceptionFilter
http://msdn.microsoft.com/library/default.asp?
url=/library/en-us/debug/base/unhandledexceptionfilter.asp

上面觀察到的資訊能解釋Dr. Watson的行為嗎?看起來似乎有關係。為了進一步確認這個問題,可以通過下面的測試,使用Windbg代替Dr. Watson,看看是否可以擷取dump。如果僅僅換一個調試器就可以擷取dump,那說明問題是跟調試器相關,跟程式拋出的異常無關。具體做法是:
1. 運行drwtsn32.exe –i註冊Dr. Watson。
2. 開啟AeDebug註冊表,找到Debugger項,裡面應該是drwtsn32 -p %ld -e %ld -g。
3. 修改Debugger為: C:\debuggers\windbg.exe -p %ld -e %ld -c ".dump /mfh C:\myfile.dmp ;q"。
當unhanded exception發生後,系統會啟動windbg.exe作為調試器載入到目標進程。但是windbg.exe不會自動擷取dump,所以需要用-c參數來指定初始命令。命令之間可以用分開分割。這裡的.dump /mfh C:\myfile.dmp命令就是用來產生dump檔案的。接下來的q命令是讓windbg.exe在dump產生完畢後自動結束。用這個方法,對於unhandled C++ exception,windbg.exe是可以擷取dump檔案的。所以我認為Dr. Watson這個工具在擷取dump的時候是有缺陷的。研究的發現在:

http://eparg.spaces.msn.com/blog/cns!59BFC22C0E7E1A76!1213.entry

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.