WinDBG调试dNet程序总结
生活随笔
收集整理的這篇文章主要介紹了
WinDBG调试dNet程序总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
WinDBG工具簡介
http://www.cnblogs.com/mashuping/archive/2009/03/28/1424168.html對于一般的程序不需要使用WinDBG工具去調試,使用MDBG就OK
使用WinDBG + SOS調試.Net程序的一般步驟
1. 加載進程和SOS擴展
? ? ? ?a. F6或者使用菜單Files –> Attach to a process…來Attach一個托管進程? ? ? ?b.使用命令.loadby sos mscorwks來加載SOS擴展(注意:.Net1.1時代的SOS擴展已經自帶于下載安裝的WinDBG中,從.Net2.0以后,SOS擴展已經自帶到.Net框架中:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\SOS.dll,為了不至于引起混淆,最好的方法
就是使用前面的loadby調試器元命令來讓WinDBG自己決定加載什么版本的SOS。 mscorwks表示.Net框架的工作站版本,現在我們安裝的.Net Framework都是該版本)
? ? ? ?c.加載SOS后,使用命令.chain來查看調試鏈中是否已經成功包含SOS擴展,如下圖的WinDBG輸出就表示已經成功的加載了SOS:
? ? ??
2. 查看進程加載的模塊并加載調試符號
? ? ? ?Attach到進程并順利加載SOS擴展后,我們可以使用lm命令來查看當前進程已經加載的模塊,WinDBG會列出一個模塊加載列表,這個列表非常有用,我們后面設置斷點,查看方法表和IL以及匯編代碼都需要使用到相應的Module Name。另外對于我們常用的情況:調
試IISHost的進程,由于進程的名字都是w3wp,我們需要區分出哪個進程才是我們想要調試的Application,這個時候我們就可以通過lm命令列出的加載模塊列表來判斷:
?
? ? ? ?接下來我們就可以根據Module Name來給對應的Module加載調試符號庫,由于在使用WinDBG進行調試的時候大多數時候我們都會查看匯編代碼,所以加載調試符號對于輔助我們更好的看懂匯編代碼和相關的變量命名是必須的,WinDBG默認會幫我們加載相關Module
的調試符號,我們也可以使用ld [ModuleName]來顯示的加載某一個Module的調試符號,例如ld BasicDebugDemo指定加載BasicDebugDemo這個Module的調試符號。
?
3. 準備就緒,開始調試
? ? ? ?經過1,2兩個步驟的準備,我們的調試環境已經準備好了,接下來就可以開始調試了,下面介紹一些重要的和常用的調試命令:? ? ? ?1) 根據調試符號庫的信息查看類或者方法在.Net執行引擎中的具體元信息,包括類的方法表地址,類在運行時的元信息(父類元信息地址,虛方法表地址等很多有用信息),這些信息是我們接下來調試的基礎!使用命令!name2ee [ModuleName] [ClassName or?
MehodName]來進行查看,例如:!name2ee BasicDebugDemo BasicDebugDemo.Program:
?? ? ? ?我們也可以使用!name2ee命令直接查看某個類方法的元信息:?
?
2) 有了上面得到的一個類的方法表的入口地址后,我們就可以使用!dumpmt [-md] [MethodTabel Address]來查看這個類中每一個方法的具體運行時信息(加帶md選項表示我們要查詢每一個方法聲明的入口地址),例如我們利用上面得到的00993030這個地址,!dumpmt –
md 00993030:
?
3) 另外我們通過上面的!name2ee命令除了拿到MehodTable的地址外,還拿到了Program這個Class的運行時元信息地址EEClass Address,所以我們可以通過!dumpclass [Class Address]來查看這個類中的具體內容(比如其中的靜態變量的地址等):
4) 上面提到了一個很重要的信息MehodDesc,得到這個MethodDesc有什么用呢?首先我們可以使用!dumpil [MethodDesc]來查看其編譯后的IL代碼:
5) 另外如果這個方法已經被JIT了,那么我們調用!dumpmd [MethodDesc]會得到下面的信息:
? ? ? ?接下來我們就可以使用!u [LocalCodeAddr]來查看生成的本地匯編代碼:
?
6) 上面能獲取的元信息我們基本上都獲取了,有了這些元信息(主要是代碼地址信息)我們要下斷點就很簡單了,我們有很多種方式來給我們的代碼的指定位置加上斷點P
? ? a.首先如果調試符號加載成功的話,我們可以直接使用很直觀的原始方法命名來給指定的方法入口處加上斷點:!bpmd [ModuleName] [MethodName],例如!bpmd BasicDebugDemo BasicDebugDemo.Program.CreateFooObject
? ? b.如果我們有MethodDesc,也可以直接使用!bpmd -md [MethodDesc]來給方法入口處加上斷點,例如!bpmd -md 0099301c
? ?c.我們上面看到了本地匯編代碼,所以我們也可以使用bp [CodeAddr]來給某個方法內部的某行代碼加上斷點。
? ?d.我們可以使用bl命令來列出所有已加載的斷點,也可以使用bc [BreakPoint ID]命令來刪除指定ID的斷點(用bl命令列出的斷點列表種有各個斷點的ID),或者使用bc *來刪除所有的斷點。
? ? e.斷點加載成功后,WinDBG會給出類似下面這樣的提示:
? ? ? ? ?Found 1 methods...
MethodDesc = 00993028
Adding pending breakpoints...
? ? f.當我們的斷點命中后,我們仍然可以像普通調試一樣來使用F10 Step Out單步執行,使用F11來Step Into單步執行。注意:這里的單步執行,都是指單步匯編代碼,而不是我們所寫的代碼。
7) 在命中斷點后我們就可以通過查看類命令來查看棧和堆中的變量的值以及當前的調用堆棧:
? a.使用!clrstack可以查看當前的條用堆棧,使用!clrstack –l可以查看當前調用堆棧以及其上的局部變量和值,使用!clrstack –p可以查看當前調用堆棧上的參數變量以及值,使用!clrstack –a可以查看當前堆棧上所有局部變量和參數變量以及值(格式為
StackAddress = ?StackValue)。!clrstack命令只會顯示托管代碼的調用堆棧,如果想查看完整的調用堆棧可以使用!dumpstack命令:
b.使用!dso命令可以查看堆棧上的所有對象
? c.使用!do [ObjectAddress]查看指定對象的具體內容:
?
8) 除了通過堆棧查看棧上的變量外,我們還可以直接通過!dumpheap來查看目前堆中的所有對象,但是由于一般情況下堆中存在的變量會非常的多(包含.Net框架里的很多預定義對象),所以直接使用!dumpheap得到的結果一般我們很難查看。大多數情況下,我們需要查
看的是堆中指定類型的對象,所以我們可以使用!dumpheap –type [ClassName]來查看指定類型的對象:
9)如何檢查內存泄漏?WinDBG SOS中有一個很有用的命令!GCRoot [ObjectAddress]可以幫助我們查看指定對象的引用情況,這個信息可以很好的幫助我們分析那些本應該沒有引用但卻一直還存在有效引用的對象,由此發現我們代碼中潛在的內存泄漏,同時我們也可以
觀察到哪些對象是目前沒有引用了,但是GC還沒有回收的:
?
4. 總結
1) WinDBG不是專門用于調試.Net程序的工具,它更偏向于底層,可用于內核和驅動調試。進行普通的.Net程序調試還是使用微軟專為.Net開發的調試工具MDBG更方便一些。但是WinDBG能看到更多的底層信息,對于某些特別疑難的問題調試有所幫助,例如內存泄漏等問題。
2) SOS擴展命令中最有用的命令是!help命令J,使用該命令可以列出所有可用的SOS擴展命令列表,使用!help [SOSCommandName]可以查看每一個具體擴展命名的詳細使用說明,例如!help dumpheap就可以查看!dumpheap這個擴展命名的具體使用方法。多多利用!help命名可以很快上手SOS。
3) WinDBG本身的資料可以參考 張銀奎 先生的《軟件調試》一書,另外在互聯網上也有非常多的WinDBG資料。
========
使用Windbg調試.Net應用程序
http://blog.csdn.net/kntao/article/details/70866161. 解決線上.NET應用程序的如下問題
崩潰CPU高
程序異常
程序Hang死
2. 安裝WinDbg
http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx3. 配置WinDbg
運行WinDbg->菜單->File->Symbol File Path->按照下面的方法設置_NT_SYMBOL_PATH變量:在彈出的框中輸入“C:\MyCodesSymbols; SRV*C:\MyLocalSymbols*http://msdl.microsoft.com/download/symbols”(按照這樣設置,WinDbg將先從本地文件夾C:\MyCodesSymbols中查找Symbol,如果找不到,則自動從MS的Symbol Server上下載Symbols)。另一種做法是
從這個Symbol下載地址中http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx,下載相應操作系統所需要的完整的Symbol安裝包,并進行安裝,
4. 利用WinDbg里的adplus來獲取dump文件
Dump文件是進程的內存鏡像。可以把程序的執行狀態通過調試器保存到dump文件中。在WinDbg安裝目錄里可以找到adplus.exe,把他拖入到命令行中,然后用命令
adplus.exe -hang -pn test.exe -o c:\dumps ?// 抓取當前的dump文件
adplus.exe -crash -pn test.exe -o c:\dumps ?// 監聽應用程序,當crash時,獲取dump文件
命令-pn :應用程序名,-p:應用程序pid,-odump文件輸出路徑
5. 利用WinDbg加載dump文件加載調試器
運行WinDbg->菜單->File->Open Cresh dump 打開dump文件,并加載.net調試器.loadby sos mscorwks ?.Net 3.5版本及以下
.loadby sos clr ?.Net 4.0
如果服務器的.Net版本與本機不匹配需要服務器版本的mscordacwks.dll文件
并設置.sympath = mscordacwks_x86_x86_2.0.50727.3607.dl
6. WinDbg的基本命令
help ?sos指令幫助!threads ?顯示所有線程
!dumpheap ?顯示托管堆的信息
!clrstack ?顯示調用棧
!dumpobj ?顯示一個對象的內容
!dumparray ?顯示數組
!syncblk ?顯示同步塊
!runaway ?顯示線程cpu時間
!gcroot ?跟蹤對象內存引用
!pe ?打印異常
7. WinDbg的使用
當我在Form中執行這段代碼:[csharp] view plain copy print?
public Form1(){ ?
? ? ? ? ? ? InitializeComponent(); ?
? ? ? ? ? ? AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); ?
? ? ? ? } ?
? ? private void UnhandledExceptionProc(object obj){ ?
? ? ? ? ? ? try { ?
? ? ? ? ? ? ? ? throw new Exception("1st chance"); ?
? ? ? ? ? ? } catch (Exception) { ?
? ? ? ? ? ? ? ? MessageBox.Show("after 1st"); ?
? ? ? ? ? ? } ?
? ? ? ? ? ? int d = 0; ?
? ? ? ? ? ? int n = 1 / d; ?
} ?
并活動dump文件
用windbg打開dump文件后輸入-pe:可以看到問題的所在。
異常如此重要,所以操作系統提供了對應的調試功能,可以使用調試器來檢視異常。異常發生后,操作系統在調用用戶態程序的異常處理函數前,會檢查當前用戶態程序是否有調試器加載。如果有,那么操作系統會首先把異常信息發送給調試器,讓調試器有觀察異常的
第一次機會,所以也叫做first chance exception,調試器處理完畢后,操作系統才讓用戶態程序來處理。
如果用戶態程序處理了這個異常,就沒調試器什么事了。否則,程序在unhandled exception崩潰前,操作系統會給調試器第二次觀察異常的機會,所以也叫做second chance exception。
《Windows用戶態程序高效排錯》
分析以下代碼:可以看出DummyObject 會占用很多內存,甚至導致內存溢出
[csharp]
private void MemeryLeakProc(object obj) ?
? ? { ?
? ? ? ? while (true) { ?
? ? ? ? ? ? for (int i = 0; i < 100 * 1024; i++) { ?
? ? ? ? ? ? ? ? DummyObject o = new DummyObject(); ?
? ? ? ? ? ? ? ? list.Add(o); ?
? ? ? ? ? ? } ?
? ? ? ? ? ? Thread.Sleep(1000); ?
? ? ? ? } ?
? ? } ?
windbg命令:!dumpheap –stat 統計堆棧內存
線程Hang住的常見原因
-線程池或工作線程集中在某個耗時的工作當中,或者被其他線程鎖住
核心問題,找到被hang住的線程
!threads
~*e!clrstack
!synblk
[csharp]
lock (syncRoot) { ?
? ? ? ? ? ? ? ? int tp; ?
? ? ? ? ? ? ? ? int io; ?
? ? ? ? ? ? ? ? //ThreadPool.GetMaxThreads(out tp, out io); ?
? ? ? ? ? ? ? ? for (int i = 0; i < 100; i++) { ?
? ? ? ? ? ? ? ? ? ? Thread hangThread = new Thread(HangProc); ?
? ? ? ? ? ? ? ? ? ? hangThread.Start(); ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? MessageBox.Show("Press to release lock"); ?
? ? ? ? ? ? } ?
[csharp]
? private void HangProc(object obj) ?
? { ?
? ?lock (syncRoot) { ?
? ? n = 0; ?
? ?} ?
? } ?
CPU高
-如果與業務量沒有提升,有線程在長時間的處理
核心問題,找到占用CPU的線程
!runaway
~*e!clrstack
?
線程死鎖出現的情況:
兩個鎖A,B,
一個線程已經拿到鎖A,申請鎖B,
另一個線程已經拿到鎖B,申請鎖A
核心問題:找到鎖定的線程
!threads
!syncblk
~*e!clrstack
?
?兩條指令可以解決大部分的問題
?!dumpheap –stat
?~*e!clrstack
?
========
WinDbg調試.NET程序入門
http://www.cnblogs.com/bluedoctor/p/4813125.html自從來到新公司遇到性能問題后,需要想辦法解決這個問題,但是一直沒有合適的性能分析工具,然后找到StevenChennet 大神幫忙,他用WinDbg工具遠程幫我分析了一個 dump文件,但是只看到鍵盤 “啪啪啪”,得到了結果,卻不是很清楚WinDbg神奇具體如何使用的
。結果,第二天,性能問題又來了,總不能每次勞煩大神駕到,所以不得不自己開始學習WinDbg,這里記錄一個入門過程。
1,首先,下載并安裝WinDbg程序
從下面的地址打開:https://msdn.microsoft.com/en-us/windows/hardware/hh852365
然后看到
Standalone Debugging Tools for Windows (WinDbg)
下載。
安裝好后,在開始-》Windows Kits文件夾下有 WinDbg(x86),WinDbg(x64) 兩個程序的快捷方式,如果你要調試
64位的程序,就用WinDbg(x64)。
2,創建內存轉儲文件
可以在任務管理器,進程-》創建轉儲文件 里面,得到當前進程的dump文件,我是用下面這個程序來生成轉儲文件的:Procdump
下載地址:https://technet.microsoft.com/en-us/sysinternals/dd996900.aspx
有關 ProDump程序的使用,可以參考下面2個博客文章:
High CPU Dump收集工具 - ProcDump使用方法
介紹一個好用的抓取dump的工具-ProcDump
在命令行,運行這個程序:
procdump -ma mydotNetApp.exe d:\myapp.dmp
運行后,將得到一個myapp.dmp 文件,如果這個文件是在本機生成的,那么VS2013可以直接打開這個文件并可以分析托管內存,但是,往往內存轉儲文件是 在服務器生成的,而服務器又很可能跟開發環境不一樣,所以才需要本文介紹的 WinDbg來調試。
3,配置調試環境
首先,打開我們剛才的轉儲文件,可以使用菜單命令打開:
File->Open Crash Dump...
打開后,會顯示程序當時運行所在的環境,此時,會提示符號文件沒有發現:
*** ERROR: Symbol file could not be found. ?Defaulted to export symbols for ntdll.dll -?
如果不配置,使用命令的時候會提示錯誤,比如:
復制代碼
0:000> .loadby sos clrjit
0:000> !tp
*** ERROR: Symbol file could not be found. ?Defaulted to export symbols for clr.dll -?
************* Symbol Loading Error Summary **************
Module name ? ? ? ? ? ?Error
clr ? ? ? ? ? ? ? ? ? ?PDB not found : e:\appserver\symbols\dll\clr.pdb
復制代碼
e:\appserver 是我的dmp文件所在的目錄,它默認是到symbols 子目錄去找符號文件去了。
然后,配置下使用此文件的調試環境。
在菜單命令 File->Symbol path... 打開對話框,選擇瀏覽,找到dmp文件所在目錄相關的程序文件目錄 E:\AppServer ,該目錄下面有程序相關的 exe,pdb 文件。
輸入下面的命令:
0:000> .sympath+ c:\symbols
Symbol search path is: E:\AppServer;c:\symbols
Expanded Symbol search path is: e:\appserver;c:\symbols
Error: Attempts to access 'c:\symbols' failed: 0x2 - 系統找不到指定的文件。
************* Symbol Path validation summary **************
Response ? ? ? ? ? ? ? ? ? ? ? ? Time (ms) ? ? Location
OK ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? E:\AppServer
Error?
復制代碼
這里不用管,這個文件夾后面可以生成。
0:000> .symfix
0:000> .symfix+ c:\symbols
0:000> .sympath
Symbol search path is: srv*
Expanded Symbol search path is: SRV*c:\symbols*http://msdl.microsoft.com/download/symbols
************* Symbol Path validation summary **************
Response ? ? ? ? ? ? ? ? ? ? ? ? Time (ms) ? ? Location
Deferred ?
這下對了。
執行下 reload命令:
0:000> .reload
................................................................
................................................................
............
接著執行下面:
0:000> .loadby sos clr
0:000> !tp
The version of SOS does not match the version of CLR you are debugging. ?Please
load the matching version of SOS for the version of CLR you are debugging.
CLR Version: 4.0.30319.296
SOS Version: 4.6.96.0
Failed to load data access DLL, 0x80004005
這里提示說SOS的版本更CLR不匹配,這里需要找到當時生成Dump文件所在的服務器上的 sos.dll,注意,因為服務器程序是64位的,所以必須在 .Net Framework64 目錄去找,同時把 mscordacwks.dll 文件一起拷貝過來(先暫時不用,下面馬上會講到)。
剛才這個命令執行后,我們驚喜的發現,c:\symbols 目錄自己創建了,并且下載了 clr.pdb等幾個目錄,這是再將剛才服務器上拷貝的 sos.dll, mscordacwks.dll ,放到本地機器的 c:\symbols 目錄下面。
再次執行這幾個命令:
0:000> .reload
................................................................
................................................................
............
0:000> .loadby sos clr
0:000> !tp
The version of SOS does not match the version of CLR you are debugging. ?Please
load the matching version of SOS for the version of CLR you are debugging.
CLR Version: 4.0.30319.296
SOS Version: 4.6.96.0
Failed to load data access DLL, 0x80004005
還是報錯,看來 sos.dll 沒有加載正確,用下面的命令:
0:000> .load c:\symbols\sos.dll
0:000> .loadby sos clr
0:000> !tp
這里load命令必須帶SOS.dll的路徑。加載了它,然后執行 .loadby sos clr ,表示調試.NET托管程序。
開始漫長的等待,程序窗口提示:
*BUSY*
Downloading symbols for [clr.pdb] /
等到相關的符號文件全部下載完畢,終于出現了久違的成功界面:
CPU utilization: 11%
Worker Thread: Total: 8 Running: 0 Idle: 8 MaxLimit: 32767 MinLimit: 8
Work Request in Queue: 0
--------------------------------------
Number of Timers: 14
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 16 CurrentLimit: 0 MaxLimit: 1000 MinLimit: 8
4,獲取幫助信息
有關WinDbg詳細的調試命名,可以參考下面文章:windbg調試命令?
http://www.cnblogs.com/kekec/archive/2012/12/02/2798020.html
或者,你也可以隨時用幫助,查看如何使用:
0:000> !help
-------------------------------------------------------------------------------
SOS is a debugger extension DLL designed to aid in the debugging of managed
programs. Functions are listed by category, then roughly in order of
importance. Shortcut names for popular functions are listed in parenthesis.
Type "!help <functionname>" for detailed info on that function.?
Object Inspection ? ? ? ? ? ? ? ? ?Examining code and stacks
----------------------------- ? ? ?-----------------------------
DumpObj (do) ? ? ? ? ? ? ? ? ? ? ? Threads
DumpArray (da) ? ? ? ? ? ? ? ? ? ? ThreadState
DumpStackObjects (dso) ? ? ? ? ? ? IP2MD
DumpHeap ? ? ? ? ? ? ? ? ? ? ? ? ? U
DumpVC ? ? ? ? ? ? ? ? ? ? ? ? ? ? DumpStack
GCRoot ? ? ? ? ? ? ? ? ? ? ? ? ? ? EEStack
ObjSize ? ? ? ? ? ? ? ? ? ? ? ? ? ?CLRStack
FinalizeQueue ? ? ? ? ? ? ? ? ? ? ?GCInfo
PrintException (pe) ? ? ? ? ? ? ? ?EHInfo
TraverseHeap ? ? ? ? ? ? ? ? ? ? ? BPMD?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?COMState
Examining CLR data structures ? ? ?Diagnostic Utilities
----------------------------- ? ? ?-----------------------------
DumpDomain ? ? ? ? ? ? ? ? ? ? ? ? VerifyHeap
EEHeap ? ? ? ? ? ? ? ? ? ? ? ? ? ? VerifyObj
Name2EE ? ? ? ? ? ? ? ? ? ? ? ? ? ?FindRoots
SyncBlk ? ? ? ? ? ? ? ? ? ? ? ? ? ?HeapStat
DumpMT ? ? ? ? ? ? ? ? ? ? ? ? ? ? GCWhere
DumpClass ? ? ? ? ? ? ? ? ? ? ? ? ?ListNearObj (lno)
DumpMD ? ? ? ? ? ? ? ? ? ? ? ? ? ? GCHandles
Token2EE ? ? ? ? ? ? ? ? ? ? ? ? ? GCHandleLeaks
EEVersion ? ? ? ? ? ? ? ? ? ? ? ? ?FinalizeQueue (fq)
DumpModule ? ? ? ? ? ? ? ? ? ? ? ? FindAppDomain
ThreadPool ? ? ? ? ? ? ? ? ? ? ? ? SaveModule
DumpAssembly ? ? ? ? ? ? ? ? ? ? ? ProcInfo?
DumpSigElem ? ? ? ? ? ? ? ? ? ? ? ?StopOnException (soe)
DumpRuntimeTypes ? ? ? ? ? ? ? ? ? DumpLog
DumpSig ? ? ? ? ? ? ? ? ? ? ? ? ? ?VMMap
RCWCleanupList ? ? ? ? ? ? ? ? ? ? VMStat
DumpIL ? ? ? ? ? ? ? ? ? ? ? ? ? ? MinidumpMode?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?AnalyzeOOM (ao)
Examining the GC history ? ? ? ? ? Other
----------------------------- ? ? ?-----------------------------
HistInit ? ? ? ? ? ? ? ? ? ? ? ? ? FAQ
HistRoot
HistObj
HistObjFind
HistClear
復制代碼
也可以使用 .help命令,這個不一樣,這里列出部分命令:
0:000> .help
. commands:
? ?.allow_exec_cmds [0|1] - control execution commands
? ?.allow_image_mapping [0|1] - control on-demand image file mapping
? ?.apply_dbp [<options>] - add current data breakpoint state to a
? ? ? ? ? ? ? ? ? ? ? ? ? ? register context
? ?.asm [<options>] - set disassembly options
? ?.asm- [<options>] - clear disassembly options
? ?.attach <proc> - attach to <proc> at next execution
? ?.block { <commands> } - brackets a set of commands for nested execution
? ?.break - break out of the enclosing loop
也可使用.hh命令:
?Use ".hh <command>" or open debugger.chm in the debuggers directory to get
detailed documentation on a command.
OK,有了dump文件生成,調試環境配置,還有幫助命令,現在總算是入門了。
========
Windows調試學習筆記:(二)WinDBG調試.NET程序示例
http://www.cnblogs.com/ceachy/p/WinDBG_Demo1.html好不容易把環境打好了,一定要試試牛刀。我創建了一個極其簡單的程序(如下)。
using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace ConsoleApplication1 {class Program{static void Main(string[] args){int a;string str;a = 5;str = a.ToString();Console.WriteLine(str);}} }
默認編譯成x86的輸出代碼,路徑是E:\Projects\Practise\ConsoleApplication1\ConsoleApplication1\bin\Debug。然后就開始調試的步驟了:
1、加載調試程序
啟動WinDBG以后,選擇“文件-選擇可執行文件。。。”,找到E:\Projects\Practise\ConsoleApplication1\ConsoleApplication1\bin\Debug目錄下的ConsoleApplication1.exe文件,單擊“打開”按鈕。這樣我們的調試目標程序已經打開了。
2、加載pdb文件
執行ld命令為ConsoleApplication1.exe程序集加載pdb文件:
0:000> ld ConsoleApplication1
*** WARNING: Unable to verify checksum for ConsoleApplication1.exe
Symbols loaded for ConsoleApplication1
3、加載SOS
基于以往失敗經驗,我們一開始就使用SXE命令:
0:000> sxe ld:clrjit
0:000> g
...
0:000> .loadby sos clr
4、設置斷點
我們是用BPMD命令設置斷點如下:
0:000> !bpmd ConsoleApplication1.exe ConsoleApplication1.Program.Main
Found 1 methods in module 00162ea4...
MethodDesc = 001637f8
Adding pending breakpoints...
5、檢查斷點是否停下來
輸入g讓被調試程序繼續執行,如果在斷點位置停下來了,就會顯示如下結果:
0:000> g
(6164.4fe0): CLR notification exception - code e0444143 (first chance)
JITTED ConsoleApplication1!ConsoleApplication1.Program.Main(System.String[])
Setting breakpoint: bp 00210070 [ConsoleApplication1.Program.Main(System.String[])]
Breakpoint 0 hit
eax=001637f8 ebx=00000000 ecx=0265ba00 edx=0035f150 esi=0060c7e0 edi=0035f0a0
eip=00210070 esp=0035f078 ebp=0035f084 iopl=0 ? ? ? ? nv up ei pl nz ac pe nc
cs=0023 ?ss=002b ?ds=002b ?es=002b ?fs=0053 ?gs=002b ? ? ? ? ? ? efl=00000216
00210070 55 ? ? ? ? ? ? ?push ? ?ebp
6、檢查堆棧
使用!clrstack命令檢查堆棧,記得加上-a參數:
0:000> !clrstack -a
OS Thread Id: 0x4fe0 (0)
Child SP IP ? ? ? Call Site
0035f078 00210070 ConsoleApplication1.Program.Main(System.String[]) [E:\Projects\Practise\ConsoleApplication1\ConsoleApplication1\Program.cs @ 11]
? ? PARAMETERS:
? ? ? ? args (<CLR reg>) = 0x0265ba00
? ? LOCALS:
? ? ? ? <no data>
? ? ? ? <no data>
0035f2a0 5dc321bb [GCFrame: 0035f2a0]?
這里已經能夠看到Main函數內部的一些情況了,比如args的地址。但是我們想看的a和str卻還沒有。這又兩個原因:1、它們不會顯示名字;2、它們還沒有被定義。
7、單步執行
不斷輸入p命令往下執行,并且不斷地檢查堆棧情況。我輸入9次以后出現了以下結果:
0:000> p
eax=00000000 ebx=00000000 ecx=0265ba00 edx=00000000 esi=0060c7e0 edi=0035f0a0
eip=00210091 esp=0035f064 ebp=0035f074 iopl=0 ? ? ? ? nv up ei pl zr na pe nc
cs=0023 ?ss=002b ?ds=002b ?es=002b ?fs=0053 ?gs=002b ? ? ? ? ? ? efl=00000246
00210091 90 ? ? ? ? ? ? ?nop
0:000> !clrstack -a
OS Thread Id: 0x4fe0 (0)
Child SP IP ? ? ? Call Site
0035f064 00210091 ConsoleApplication1.Program.Main(System.String[]) [E:\Projects\Practise\ConsoleApplication1\ConsoleApplication1\Program.cs @ 11]
? ? PARAMETERS:
? ? ? ? args (0x0035f070) = 0x0265ba00
? ? LOCALS:
? ? ? ? 0x0035f06c = 0x00000000
? ? ? ? 0x0035f068 = 0x00000000
0035f2a0 5dc321bb [GCFrame: 0035f2a0]?
這里LOCALS:下面的兩個就是a和str,但是它們下載還是沒有值。又執行2次p命令以后,a的值已經顯示出來了:
0:000> !clrstack -a
OS Thread Id: 0x4fe0 (0)
Child SP IP ? ? ? Call Site
0035f064 00210099 ConsoleApplication1.Program.Main(System.String[]) [E:\Projects\Practise\ConsoleApplication1\ConsoleApplication1\Program.cs @ 16]
? ? PARAMETERS:
? ? ? ? args (0x0035f070) = 0x0265ba00
? ? LOCALS:
? ? ? ? 0x0035f06c = 0x00000005
? ? ? ? 0x0035f068 = 0x00000000
0035f2a0 5dc321bb [GCFrame: 0035f2a0]?
繼續執行5次p命令之后,str的地址也顯示出來了:
0:000> !clrstack -a
OS Thread Id: 0x4fe0 (0)
Child SP IP ? ? ? Call Site
0035f064 002100aa ConsoleApplication1.Program.Main(System.String[]) [E:\Projects\Practise\ConsoleApplication1\ConsoleApplication1\Program.cs @ 18]
? ? PARAMETERS:
? ? ? ? args (0x0035f070) = 0x0265ba00
? ? LOCALS:
? ? ? ? 0x0035f06c = 0x00000005
? ? ? ? 0x0035f068 = 0x0265c06c
0035f2a0 5dc321bb [GCFrame: 0035f2a0]?
8、查看引用類型成員
str的地址顯示出來以后,我們就可以使用!dumpobj命令來查看它的值以及其他信息了:
0:000> !dumpobj 0x0265c06c
Name: ? ? ? ?System.String
MethodTable: 5d17fba0
EEClass: ? ? 5ceb8bb0
Size: ? ? ? ?16(0x10) bytes
File: ? ? ? ?C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: ? ? ?5
Fields:
? ? ? MT ? ?Field ? Offset ? ? ? ? ? ? ? ? Type VT ? ? Attr ? ?Value Name
5d182b6c ?4000103 ? ? ? ?4 ? ? ? ? System.Int32 ?1 instance ? ? ? ?1 m_stringLength
5d181fbc ?4000104 ? ? ? ?8 ? ? ? ? ?System.Char ?1 instance ? ? ? 35 m_firstChar
5d17fba0 ?4000105 ? ? ? ?8 ? ? ? ?System.String ?0 ? shared ? static Empty
? ? >> Domain:Value ?005d4d00:02651228 <<
從中我們看到字符串的值為"5",它的長度是1等等。
總結:
這里記錄的過于詳細了。
========
總結
以上是生活随笔為你收集整理的WinDBG调试dNet程序总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ArcGIS空间分析要点学习
- 下一篇: Windbg dump分析 学习总结