Windbg教程-调试非托管程序的基本命令上
Windbg是跟visual studio差不多的一個調試器,可以用來調試非托管程序(native application),也可以調試托管程序(managed application)。它比VS強的地方是你可以使用它來調試Windows操作系統,因此它也被叫做kernel mode debugger,同樣為kernel mode debugger的調試器還有隨著windbg一起安裝的kd.exe(只不過這是一個命令行工具而已)。然而它在調試托管程序方面會比VS難用很多,當然如果你想看.NET程序的CLR內部結構,例如內存相關的信息的話,使用windbg還是可以的。
Windbg與VS在調試方面最大的區別是,Windbg是采用命令驅動,而VS是采用良好的用戶界面(UI)驅動。粗看起來,好像windbg是可以通過類似批處理的方式來實現一些調試步驟自動化(的確是這樣的,會在后續的文章中講到),可能你會感覺windbg功能會比VS強一些。實際上VS也提供了宏支持,你可以編寫宏來控制VS的調試過程—請參考我以前的文章Visual Studio調試之斷點技巧篇。
本篇文章里,以下面這個簡單的程序為例,我介紹一些在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]); #ifdef?_UNICODE ???????? wprintf(L"%s * %s = %d\n", argv[1], argv[1], result * result); ???????? wprintf(L"Press any key to exit ...\n"); ???????? _getwch(); #else ???????? printf("%s * %s = %d\n", result * result); ???????? printf("Press any key to exit ...\n"); ???????? _getch(); #endif ? ?????????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 # #?下面這幾行說明當前沒有設置好符號文件搜索路徑,符號文件在調試中比源文件 #?還重要,關于符號文件的說明和其重要性請參考我的另外一篇文章 # ????????????????????Visual Studio調試之符號文件 # 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 # #?下面這一行說明了當前是什么異常導致程序中斷執行,是的?,雖然我們剛剛啟動被 #?調試的程序,的確是一個異常—斷點異常導致程序中斷執行。至于原因請參看我的 #?另外一篇文章: #?????????????????Visual Studio調試之斷點基礎篇 #?另外,下面一行中,第一個括號里面的是當前的線程ID,第二個括號指明了當前的異常 #?是第一次機會處理,還是第二次機會處理。First chance的含義請參看我的這篇文章: #??????????????????Visual Studio調試之避免單步跟蹤調試模式 (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
上面的輸出結果會在后文講到,至于如何設置斷點,以及在命令行里面查看堆棧,在后面講――寫文章還是蠻辛苦的。
總結
以上是生活随笔為你收集整理的Windbg教程-调试非托管程序的基本命令上的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 给网游写一个挂吧(四) – 调用游戏函数
- 下一篇: Windbg教程-调试非托管程序的基本命