cc682/NetRoc
http://netroc682.spaces.live.com/
調(diào)試器操作(用戶模式)
本節(jié)包含以下主題:
被創(chuàng)建的進(jìn)程行為
控制進(jìn)程和線程
重新附加到目標(biāo)進(jìn)程
調(diào)試托管代碼
被創(chuàng)建進(jìn)程的行為
由調(diào)試器創(chuàng)建的進(jìn)程(也稱為產(chǎn)生的進(jìn)程)的行為和不是調(diào)試器創(chuàng)建的進(jìn)程有輕微不同。
調(diào)試器創(chuàng)建的進(jìn)程使用特殊的調(diào)試堆,而不是使用標(biāo)準(zhǔn)的堆API。在Microsoft Windows XP和之后版本W(wǎng)indows中,可以通過_NO_DEBUG_HEAP 環(huán)境變量或 -hd命令行選項強(qiáng)制子進(jìn)程使用標(biāo)準(zhǔn)堆。
同樣,由于子目標(biāo)程序是調(diào)試器的子進(jìn)程,所以繼承了調(diào)試器的權(quán)限。這種權(quán)限可能使得目標(biāo)進(jìn)程能做一些通常情況下不能進(jìn)行的操作。例如,目標(biāo)進(jìn)程可能可以影響其它被保護(hù)的進(jìn)程。
控制進(jìn)程和線程
當(dāng)進(jìn)行用戶模式調(diào)試時,可以激活、顯示、凍結(jié)、解凍、掛起、恢復(fù)進(jìn)程和線程。
當(dāng)前正被調(diào)試的進(jìn)程稱為當(dāng)前活動進(jìn)程。類似的,當(dāng)前調(diào)試器正在控制的線程稱為當(dāng)前線程或活動線程。很多調(diào)試器命令的行為由當(dāng)前進(jìn)程和當(dāng)前線程決定。
調(diào)試開始時,當(dāng)前進(jìn)程是調(diào)試器附加到的進(jìn)程或因為異常中斷到調(diào)試器的進(jìn)程。同樣,當(dāng)前線程是當(dāng)調(diào)試器附加到進(jìn)程時的線程或產(chǎn)生異常的線程。但是,可以利用調(diào)試器改變當(dāng)前線程和進(jìn)程,也可以分別凍結(jié)或解凍線程。
在內(nèi)核模式調(diào)試下,不使用本節(jié)描述的方法來控制線程和進(jìn)程。關(guān)于在內(nèi)核模式下操作進(jìn)程和線程的更多信息,查看改變上下文。
顯示進(jìn)程和線程
使用如下方法顯示進(jìn)程和線程信息:
設(shè)置當(dāng)前進(jìn)程和當(dāng)前線程
使用如下方法改變當(dāng)前進(jìn)程和線程:
凍結(jié)和掛起線程
調(diào)試器可以通過掛起或凍結(jié)線程來改變它的執(zhí)行。這兩種操作有一些不同的地方。
每個線程都有一個關(guān)聯(lián)的掛起計數(shù)(suspend count)。如果這個數(shù)字是大于等于1,則系統(tǒng)不會運(yùn)行該線程。如果計數(shù)小于等于0,系統(tǒng)會在適當(dāng)?shù)臅r機(jī)運(yùn)行該線程。
一般來說,每個線程的掛起計數(shù)都是0。當(dāng)調(diào)試器附加到進(jìn)程時,會將它的所有線程的掛起計數(shù)加1。如果調(diào)試器停止對進(jìn)程的附加,會將所有掛起計數(shù)減1。當(dāng)調(diào)試器執(zhí)行進(jìn)程時,會臨時將所有的掛起計數(shù)減少1。
使用下面一些方法可以用調(diào)試器控制任何一個線程的掛起計數(shù):
一般用這些命令來將指定線程的掛起計數(shù)從1加到2。當(dāng)調(diào)試器執(zhí)行或停止附加進(jìn)程時,該線程由于掛起計數(shù)為1,即使進(jìn)程中其他線程都開始執(zhí)行,該線程仍然保持掛起。
在進(jìn)行非侵入式調(diào)試時也可以掛起線程。
調(diào)試器也可以凍結(jié)線程。該行為和以某些方式掛起線程類似。但是,"凍結(jié)"僅僅是一種調(diào)試器設(shè)置。Windows系統(tǒng)不會知道該線程有任何不同點(diǎn)。
默認(rèn)情況下,所有線程都是非凍結(jié)的。當(dāng)調(diào)試器運(yùn)行進(jìn)程時,被凍結(jié)的線程不會運(yùn)行。但是,當(dāng)調(diào)試器停止對該進(jìn)程的附加時,所有線程都會變?yōu)榉莾鼋Y(jié)狀態(tài)。
使用下面一些方法來凍結(jié)和解凍各個線程:
在任何情況下,當(dāng)調(diào)試器中斷目標(biāo)時,該進(jìn)程中的所有線程永遠(yuǎn)不會被執(zhí)行。線程的掛起計數(shù)僅在調(diào)試器運(yùn)行進(jìn)程或者停止進(jìn)程附加時有效。凍結(jié)狀態(tài)僅在調(diào)試器運(yùn)行進(jìn)程時有效。
其他命令中的線程和進(jìn)程
在很多其他命令中也可以指定進(jìn)程或線程。更多信息,查看各個命令的主題。
在很多命令和擴(kuò)展命令前都可以加上~e?(Thread-Specific Command) 限定詞。該限定詞使得命令對指定線程起作用。在想對一個以上線程使用某個命令時它非常有用。例如,下面的命令對被調(diào)使得所有線程使用!gle 擴(kuò)展命令。
~*e?!gle?
多系統(tǒng)
調(diào)試器可以同一時刻附加到多個目標(biāo)。當(dāng)這些處理包含不止一臺計算機(jī)上的dump文件或活動目標(biāo)時,調(diào)試器的每個行為都以一個系統(tǒng)、進(jìn)程和線程為基準(zhǔn)。關(guān)于這類調(diào)試的更多信息,查看調(diào)試多個目標(biāo)。
重新附加到目標(biāo)程序
如果調(diào)試器在用戶模式調(diào)試時凍結(jié)了,或因為其他原因停止響應(yīng)(即崩潰),可以將一個新調(diào)試器附加到已存在的進(jìn)程上。
注意??該方法僅在Microsoft Windows XP和之后版本W(wǎng)indows中支持。該方法不管進(jìn)程是調(diào)試器創(chuàng)建的還是附加上去的,也不管是否使用了-pd選項。
使用以下步驟來重新將調(diào)試器附加到目標(biāo)程序:
- 對目標(biāo)程序確認(rèn)進(jìn)程ID。
-
打開一個新的CDB或WinDbg。使用-pe命令行選項。
Debugger?-pe?-p?PID?
也可以使用其他命令行選項。
可以在一個靜止的調(diào)試器中使用.attach?(Attach to Process) 命令和-e選項。
- 附加完成后,結(jié)束原來的調(diào)試器進(jìn)程。
- 如果進(jìn)程沒有正常響應(yīng),可能是因為掛起計數(shù)太高。可以使用~m?(Resume Thread) 命令來減少掛起計數(shù)。關(guān)于掛起計數(shù)的更多信息,查看控制進(jìn)程和線程。
如果原來的調(diào)試器還在正常工作,該方法可能無效。兩個調(diào)試器會競爭調(diào)試事件,并且Windows操作系統(tǒng)沒有必要將所有調(diào)試事件都通知新調(diào)試器。
如果原來的調(diào)試器在附加新調(diào)試器之前就已經(jīng)結(jié)束,目標(biāo)程序也會被結(jié)束掉。 (但是,如果調(diào)試器以-pd選項附加上去并正常結(jié)束,目標(biāo)程序會繼續(xù)運(yùn)行。這種情況下,第二個調(diào)試器可以不使用-pe選項附加到目標(biāo)程序。)
如果已經(jīng)在調(diào)試一個進(jìn)程并想停止附加,但保持進(jìn)程在調(diào)試狀態(tài)凍結(jié),可以使用.abandon?(Abandon Process) 命令。該命令之后,任何Windows調(diào)試器都可以用本主題描述的方法重新附加到進(jìn)程上。
調(diào)試托管代碼
WinDbg、CDB和NTSD也可以對包含托管代碼的目標(biāo)程序進(jìn)行有限制的調(diào)試。
介紹托管代碼
托管代碼是和Microsoft .NET 公用語言運(yùn)行時(CLR)一同執(zhí)行的代碼。.NET CLR 管理程序的原始代碼和數(shù)據(jù),并且提供類似垃圾回收和平臺無關(guān)代碼這樣的高級支持。
需要該運(yùn)行時的編譯后代碼稱為托管代碼。不需要該運(yùn)行時的代碼成為非托管代碼。只包含托管代碼的應(yīng)用程序稱為托管應(yīng)用程序。
托管的.NET應(yīng)用程序可以在支持.NET CLR 的任何平臺上運(yùn)行,因為編譯器生成的二進(jìn)制代碼是平臺無關(guān)的。托管程序中的二進(jìn)制代碼是Microsoft中間語言(Microsoft intermediate language (MSIL))。這種二進(jìn)制代碼還包含對象信息和其他引用(稱為元數(shù)據(jù))。
托管應(yīng)用程序和傳統(tǒng)的應(yīng)用程序有所不同,因為很多程序執(zhí)行的細(xì)節(jié)是在運(yùn)行時決定的,例如數(shù)據(jù)結(jié)構(gòu)如何分布和本地代碼如何生成和使用。當(dāng)這種程序執(zhí)行的時候,運(yùn)行時決定程序運(yùn)行的數(shù)據(jù)使用和代碼使用,生成和平臺相關(guān)的本地代碼。從MSIL產(chǎn)生本地代碼的過程稱為托管或just-in-time (JIT) 編譯(有時也稱JITting)。運(yùn)行時用來進(jìn)行這種翻譯的組件成為JIT編譯器。
當(dāng)JIT編譯器為某個方法編譯了MSIL后,該方法的存根被編譯后代碼的地址取代。不管之后這個方法什么時候被調(diào)用,執(zhí)行的都是本地代碼,而JIT編譯器不需要再重復(fù)這個步驟。
構(gòu)建托管代碼
可以使用各個軟件廠商提供的各個編譯器來構(gòu)建托管代碼。特別是,Microsoft Visual Studio .NET可以使用4種不同語言來生成托管代碼:
- 帶托管擴(kuò)展的C++
- C#
- Visual Basic
- JScript
默認(rèn)的,Microsoft Visual C++ .NET不會構(gòu)建托管應(yīng)用程序。必須通過圖形界面或命令行開關(guān)來指定這樣的構(gòu)建。
調(diào)試托管代碼
可以使用Sos.dll 擴(kuò)展來調(diào)試托管代碼。該擴(kuò)展在Windows調(diào)試工具包安裝目錄的\clr10 子目錄下。
要使用該擴(kuò)展,可以加載它之后輸入!clr10\sos.help。
該命令會列出所有可用的擴(kuò)展命令和它們的參數(shù)。