調試場景
遠程調試
使用WinDbg進行遠程調試是很容易的,而且有很多種可行的方法。在下文中,’調試服務器’指的是運行在你所要調試的遠程機器上的調試器。’調試客戶端’指的是控制當前會話的調試器。
· 使用調試器:你需要CDB, NTSD或者WinDbg已經安裝在遠程機器上。WinDbg客戶端可以連接到CDB, NTSD或者WinDbg中的任何一個作為服務器,反之亦然。在客戶端和服務器直接可以選擇TCP或者命名管道作為通訊協議。
o 在服務器端的啟動過程:
§ WinDbg –server npipe:pipe=pipename(注:可以允許多個客戶端連或
§ 從WinDbg內部: .server npipe:pipe=pipename(注,連接單個客戶端)
你可以用多種協議開啟不同的服務會話。并且可用密碼來保護一個會話。
o 從客戶端連接:
§ WinDbg -remote npipe:server=Server, pipe=PipeName[,password=Password]
§ 從WinDbg內部: File->Connect to Remote Session: for connection string, enter npipe:server=Server, pipe=PipeName [,password=Password]
· 使用Remote.exe: Remote.exe使用命名管道作為通訊的方式。如果你使用的是一個命令行接口的程序,比如KD,CDB或者NTSD。你可以使用remote.exe來遠程調試。注意:使用@q(不是q)來退出客戶端,不用關掉服務端。
o 要啟動一個服務端:
§ Remote.exe /s “cdp –p <pid>” test1
o 從客戶端連接:
§ Remote.exe /c <machinename> test1
上面的test1是我們所選擇的命名管道的名字。
服務端會顯示那個客戶端從那個服務器連接以及執行過的命令。你可以使用‘qq’命令來退出服務端;或者使用File->Exit來退出客戶端。另外,如果要進行遠程調試,你必須屬于遠程機器的”Debugger User”組并且服務器必須允許遠程連接。
即時調試
在WinDbg的文檔的”Enabling Postmorten Debugging”部分對此有很詳細的討論。簡而言之,你可以把WinDbg設置成默認的即時調試器,命令就是:Windbg –I。這個命令實際上是把注冊表中 HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug的鍵值設置成WinDbg。如果要把WinDbg設置成為默認的托管調試器,你需要顯示設置如下的注冊表鍵值:
- HKLM\Software\Microsoft\.NETFramework\DbgJITDebugLaunchSetting 設置成 2
- HKLM\Software\Microsoft\.NETFramework\DbgManagedDebugger 設置成Windbg.(注意其中的啟動參數設置)
通過JIT的設置,當一個應用程序在不是調試的狀態下拋出了未處理的異常之時,WinDbg就會被啟動。
64位調試
所有這些調試器均支持在AMD64和IA64上的64位調試環境。
托管應用程序的調試
WinDbg 6.3以后的版本支持在Widbey(VS2005和.net 2.0的內部開發代號) .net CLR托管調試。在文檔中針對托管調試有很好的討論。需要注意的是,對于托管程序來說,沒有剛才所說的PDB(譯注:托管代碼實際上也是有PDB的,但是這個PDB實際上記錄了C#代碼和IL代碼的對應關系以及相關的一些信息)的概念,因為所有的程序都是編譯成為ILASM。調試器通過CLR來查詢所需的附加信息。
有幾點需要注意:
你只能在托段函數的代碼被執行過至少一次之后才能設置斷點。只有這樣它才能被編譯成匯編代碼。記住以下的幾點:
o CLR有可能丟棄已經編譯好的代碼,所以函數的入口地址有可能改變。
o 同樣的代碼有可能被多次編譯,如果多個應用程序域沒有共享這段代碼的話。如果你設置了一個斷點,它就會被設置在當前線程(譯注:CLR的邏輯線程)所在的應用程序域內。
o 泛型的特殊實例可能導致同一個函數有不同的地址。.
-
數據存儲布局的復雜化以及對應的數據檢查:
- CLR可能會在運行的時候任意改變數據的存儲布局,所以一個結構體成員的偏移量可能會被改變掉. (譯注:實際上是在一個類型被加載的時候決定的數據布局,之后是不會改變的。)
- 一個類型的信息是在第一次使用的時候被加載,所以你可能不能夠查看一個數據成員如果它還沒有被使用過.
-
調試器命令的復雜化
o 當跟蹤托管代碼的時候,你會需要穿越大段的CLR自己的代碼比如JIT編譯器的代碼,原因可能是你第一次進入一個函數,或者是你在托管和非托管代碼之間進行切換。
調試Windows服務
使用WinDbg,你可以像調試其它應用程序那樣調試Windows服務程序。即可以通過附加進程的方法啟動Windows服務,也可以把WinDbg當作一個即時調試器,并且在代碼中調用DbgBreakPoint
或者 DebugBreak
,或者在
x86
機器上加入一條
int 3
匯編指令。
調試異常
一個調試器會得到兩次的異常通知-第一次在應用程序有機會處理異常之前(‘first chance exception’);如果應用程序沒有處理這個異常,這時候調試器就會有機會來處理異常(‘second-chance exception’)。如果調試器沒有處理二次機會的異常,應用程序就會退出。
.lastevent或者,!analyze –v命令會給你顯示異常的記錄以及異常拋出所在函數的堆棧跟蹤信息。
你也可以使用 .exr, .cxr以及 .ecxr命令來顯示異常和上下文記錄。同時需要注意的是,你也可以改變first-chance的處理選項。對應的命令就是: sxe, sxd, sxn和sxi。
WinDbg的功能
調試器擴展DLL
所謂的擴展指的是一些DLL,你可以用在調試器內調用并且執行一些自定義的命令。這些DLL必須實現一些特定的函數,并且要滿足一些需求,這樣才能被認為是一個擴展DLL。在下一篇文章內,我們將會了解到怎樣寫出一個擴展DLL。所謂的bang(!)命令就是從你的擴展DLL內執行的命令。注意這些DLL是被加載到調試器的進程空間內。
內存轉儲文件
你可以使用轉儲功能來取得一個進程的快照信息。一個mini-dump通常比較小,除非你使用了全內存的minidump(.dump /mf)。通常能夠轉儲句柄信息也是很有用的,命令是 .dump/mfh。一個小型轉儲通常包含了所有的線程的堆棧以及一個已被加載的模塊的列表。一個全轉儲包含了更多的信息,比如進程的堆。
崩潰轉儲分析
如果你的windows系統當機,那么它就會在一個文件中轉儲物理內存中的數據,以及所有的進程信息。可以通過Control Panel ->System->Advanced->’Startup and Recovery’來配置。你也可以首先把WinDbg配置成為一個即時調試器,然后就可以取得任意一個非正常終止的進程的轉儲(.dump)。注意,從轉儲文件中分析出代碼中的bug往往是一個復雜費力的過程。
使用以下的步驟來分析一個轉儲文件:
1) 在WinDbg內,通過 File->’Open Crash Dump’, 指向轉儲文件。
2) WinDgb會給你顯示應用程序崩潰之時所執行的指令。
3) 正確設置你的符號文件目錄和源代碼目錄。如果你不能夠匹配正確的符號文件,想要弄清楚程序的邏輯是非常困難的。如果你能夠把符號文件匹配到正確版本的源代碼,這是就應該很容易分析出Bug原因。注意,私有符號文件含有行號信息并且會盲目的顯示你源代碼中的對應行而不進行任何的檢查;如果你的源碼版本不對,那么你就不能夠看到匹配匯編代碼的正確源碼。如果你僅僅有公有的符號文件,你會看到最后一個被調用的函數(棧上的)。
注意調試驅動或者托管代碼是與此有很大不同的。參考《The Windows 2000 Device Driver Book》來獲得調試設備驅動的技術。
WinDbg的常用設置
符號文件與文件夾
如果想更有效的調試,你需要符號文件。符號文件可以是老式的COFF格式或者就是PDB格式。PDB就是程序數據庫文件并且包含了公有符號。這些調試器內,你可以使用一系列的地址來讓調試器尋找已經加載的二進制文件的符號。
操作系統的符號文件一般存儲在%SYSTEMDIR%Symbols目錄。驅動程序的符號文件(.DBG或.PDB)一般存儲在和驅動文件(.sys 文件)相同的目錄下。私有符號文件包含的信息包括:函數,局部以及全局變量,以及用來把匯編代碼和源代碼關聯起來的行號信息;對于客戶來說,符號文件一半是公有的-這些文件僅僅包括公有成員。
你可以通過File-Symbol File Path來設置符號文件目錄,或者使用 .sympath命令。如果想要添加到網絡上符號文件的引用,添加以下的內容到你的 .sympath
SRV*downstream_store*http://msdl.microsoft.com/download/symbols
使用的命令就是:
.sympath+ SRV*c:\tmp*http://msdl.microsoft.com/download/symbols
C:\tmp就是download_store,所需要的符號文件會被下載存儲至此。注意這個符號服務器僅僅開放了公有的符號文件。
當調試器把一個二進制文件(DLL或exe)的時候,他會檢查比如文件名,時間戳以及校驗值。如果你有符號信息,你就可以在調用棧上看到函數名和他們的參數。如果二進制文件和PDB文件都來自于你自己的應用程序,你就可以看到比如私有函數,局部變量以及類型這類額外的信息。
源代碼路徑
你可以通過File->Source File Path來設置源碼路徑,或者使用.srcpath命令。如果你設置了代碼的路徑,當你調試的時候,調試器會通過PDB文件的行號信息來顯示相匹配的源代碼。
斷點,跟蹤
· 通過bp命令或者工具欄上的斷點圖片來設置軟斷點。
· 通過代碼比如DbgBreakPoint() 或者 KdBreakPoint()來設置硬斷點。
· 在擴展DLL中使用跟蹤函數DbgPrint, KdPrint, OutputDebugString 來把輸出顯示在WinDbg的輸出窗口中。