Windbg是跟visual studio差不多的一個調試器,可以用來調試非托管程式(native application),也可以調試托管程式(managed application)。它比VS強的地方是你可以使用它來調試Windows作業系統,是以它也被叫做kernel mode debugger,同樣為kernel mode debugger的調試器還有随着windbg一起安裝的kd.exe(隻不過這是一個指令行工具而已)。然而它在調試托管程式方面會比VS難用很多,當然如果你想看.NET程式的CLR内部結構,例如記憶體相關的資訊的話,使用windbg還是可以的。
本篇文章裡,以下面這個簡單的程式為例,我介紹一些在windbg中,調試托管程式常用的指令:
Nativedebug.cpp
#include "stdafx.h"
#include <tchar.h>
void Usage()
{
#ifdef _UNICODE
wprintf(L"[Usage]: nativedebug.exe <digital numbers>\n");
#else
printf("[Usage]: nativedebug.exe <digital numbers>\n");
#endif
}
int _tmain(int argc, _TCHAR* argv[])
int result = 0;
if ( argc != 2 )
{
Usage();
return -1;
}
result = _ttol(argv[1]);
wprintf(L"%s * %s = %d\n", argv[1], argv[1], result * result);
wprintf(L"Press any key to exit ...\n");
_getwch();
printf("%s * %s = %d\n", result * result);
printf("Press any key to exit ...\n");
_getch();
return 0;
編譯好了以後,運作windbg.exe,點選菜單中的“File”-“Open Executable”,在彈出的對話框中選擇nativedebug.exe。你應該可以看到類似下面的輸出,我使用綠色的字元注釋了各行輸出的含義:
#
# 注意黃色高亮的字型,它說明這個調試器是32位的調試器,隻能調試32位的程式,
# 如果你需要調試x64或者IA 64的程式,需要運作對應的調試器。
Microsoft (R) Windows Debugger Version 6.10.0003.233 X86
Copyright (c) Microsoft Corporation. All rights reserved.
# 這一行注明了被調試程式的指令行
CommandLine: E:\臨時文檔\Windbg教程\nativedebug\Debug\nativedebug.exe
# 下面這幾行說明目前沒有設定好符号檔案搜尋路徑,符号檔案在調試中比源檔案
# 還重要,關于符号檔案的說明和其重要性請參考我的另外一篇文章
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path. *
* Use .symfix to have the debugger choose a symbol path. *
* After setting your symbol path, use .reload to refresh symbol locations. *
# 可執行檔案搜尋路徑告訴了windbg在哪裡搜尋可執行檔案(也就是.exe和.dll檔案)
# 大部分情況下,windbg知道怎樣找到可執行檔案--從程式的啟動目錄,從PATH環境
# 變量裡面,從system32檔案夾裡面等等。是以大部分情況下,你不需要設定這個變量
# 然而在少數情況下,你需要使用.exepath設定它。請參看windbg幫助裡面的.exepath
# 的說明來了解。一種少數情況基本上我們用不到—是核心模式的調試,另外一種情況
# 是在調試使用者模式(user mode)mini dump檔案的時候需要指明。
Executable search path is:
# ModLoad: 指明了目前程式加載的其所依賴的 dll檔案,以及它們加載的位址。順便
# 說一句,windbg有的時候會使用這些資訊來将堆棧轉換到對應的函數上去。
ModLoad: 00950000 0096b000 nativedebug.exe
ModLoad: 77d80000 77f00000 ntdll.dll
ModLoad: 76070000 76170000 C:\Windows\syswow64\kernel32.dll
ModLoad: 77670000 776b4000 C:\Windows\syswow64\KERNELBASE.dll
ModLoad: 6ed80000 6eea4000 C:\Windows\WinSxS\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.30729.4148_none_2a4cbfc25558bcd3\MSVCR90D.dll
# 下面這一行說明了目前是什麼異常導緻程式中斷執行,是的 ,雖然我們剛剛啟動被
# 調試的程式,的确是一個異常—斷點異常導緻程式中斷執行。至于原因請參看我的
# 另外一篇文章:
# 另外,下面一行中,第一個括号裡面的是目前的線程ID,第二個括号指明了目前的異常
# 是第一次機會處理,還是第二次機會處理。First chance的含義請參看我的這篇文章:
(ec4.d7c): Break instruction exception - code 80000003 (first chance)
# 目前CPU中各個寄存器的值
eax=00000000 ebx=00000000 ecx=f2260000 edx=0016ddd8 esi=fffffffe edi=77da3bdc
eip=77e207ff esp=002df598 ebp=002df5c4 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
# 沒有symbol,是以在調試的時候比較麻煩,另外export symbol的含義在後一篇文章
# 中講
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
# 目前中斷時,程式正在執行的函數,以及其位置。
ntdll!LdrVerifyImageMatchesChecksum+0x6ce:
# 目前執行的指令(或者是下一條要執行的指令)。
77e207ff cc int 3
Windbg跟VS不同的地方是,windbg在啟動程式後,執行main函數之前,就中斷了,而VS卻是直接執行,原因是VS是一個整合的平台,你可以先在源代碼裡面設定好斷點,然後VS從源代碼編譯完程式後,啟動程式之前自動就可以把斷點設定好。而windbg隻是一個調試器,是以它需要給程式員設定斷點的機會,實際上所有的調試器的使用模式都是類似的。
因為沒有符号檔案,不好調試,是以需要先加載符号檔案。Windbg知道幾個符号檔案搜尋路徑(symbol path)――就是微軟的公開符号檔案伺服器,如果你想檢視你的程式在運作過程中使用了哪些windows的API和函數的話,可以使用它。執行下面的指令來使用這個檔案伺服器(不要忽略了前面的點号):
.symfix
上面的指令自動将symbol path設定為微軟的公開符号檔案伺服器位址,如果你在微軟内部混過,你會發現這個指令設定的路徑有點不同,噓……。
Sympath可以設定和檢視symbol的路徑,執行下面這個指令來檢視最新的符号檔案搜尋路徑:
.sympath
# 輸出結果
Symbol search path is: SRV**http://msdl.microsoft.com/download/symbols
設定好符号檔案搜尋路徑以後,接下來每次加載新的可執行(.exe或者.dll)檔案,windbg都會先在這些路徑裡面搜尋它的符号檔案,但是對于已經加載了的可執行檔案,例如ntdll.dll和kernel32.dll,我們需要手動重新加載,使用下面的指令來加載:
.reload
Reloading current modules
.....
這個時候,點選windbg菜單裡面的“View”-“Call Stack”,就可以看到堆棧了。因為我們還用到了MS CRT裡面的函數,即atoi,是以我們還需要VCRT的符号檔案。幸運的是,VS自帶了VCRT的私有符号檔案,這樣我們用下面的指令将這個符号檔案的檔案夾路徑添加到windbg的符号檔案搜尋路徑清單裡面來,注意後面的加号,如果不寫加号,就說明将搜尋路徑完全替換成新的:
.sympath+ C:\Windows\symbols\dll
Symbol search path is: SRV**http://msdl.microsoft.com/download/symbols;C:\Windows\symbols\dll
執行下面的指令看一下加載的結果(注意前面沒有點号):
lm
start end module name
00b60000 00b7b000 nativedebug (deferred)
6fef0000 70014000 MSVCR90D (private pdb symbols) D:\Debuggers\sym\msvcr90d.i386.pdb\EBEA784C96244F1E8F8D35E0391C898D1\msvcr90d.i386.pdb
76070000 76170000 kernel32 (deferred)
77670000 776b4000 KERNELBASE (deferred)
77d80000 77f00000 ntdll (pdb symbols) D:\Debuggers\sym\wntdll.pdb\E06BEA155E9748BEA818E2D0DD2FED952\wntdll.pdb
上面的輸出結果會在後文講到,至于如何設定斷點,以及在指令行裡面檢視堆棧,在後面講――寫文章還是蠻辛苦的。
本文轉自 donjuan 部落格園部落格,原文連結: http://www.cnblogs.com/killmyday/archive/2010/02/22/1671511.html ,如需轉載請自行聯系原作者