日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

[转]两个经典的windbg调试案例,值得学习。

發(fā)布時(shí)間:2023/12/9 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转]两个经典的windbg调试案例,值得学习。 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

1. 調(diào)試Bug的神兵利器:通過(guò)WinDbg條件斷點(diǎn)收集Log

原文地址:http://blogs.msdn.com/yizhang/archive/2009/03/30/bug-windbg-log.aspx

調(diào)試Bug的神兵利器:通過(guò)WinDbg條件斷點(diǎn)收集Log

前段時(shí)間花了幾天一直在用WinDbg調(diào)試一個(gè)比較棘手的Bug。這個(gè)Bug是C# Team那邊發(fā)現(xiàn)的,他們的Testcase跑大概10分鐘左右會(huì)出一個(gè)在CLR內(nèi)部的ASSERT。比較難調(diào)試的主要原因在于ASSERT表明一個(gè)全局的數(shù)據(jù)結(jié)構(gòu)出現(xiàn)了問(wèn)題,本來(lái)不應(yīng)該用完的數(shù)組卻已經(jīng)用完了(因?yàn)榘凑赵O(shè)計(jì),這個(gè)數(shù)組是邊使用邊清理的,是不會(huì)用完的)。初步想到的有下面幾種方案來(lái)調(diào)試:

1. 設(shè)置數(shù)據(jù)斷點(diǎn)

2. 一步一步調(diào)試

3. 添加Log代碼

設(shè)置數(shù)據(jù)斷點(diǎn)的主要問(wèn)題是不太好確定到底是因?yàn)槭裁丛驅(qū)е碌臄?shù)據(jù)結(jié)構(gòu)問(wèn)題,而且因?yàn)槭菙?shù)組被用完,很難將是到底是哪一個(gè)數(shù)組元素的加入導(dǎo)致了數(shù)組被全部占用,因此無(wú)法通過(guò)設(shè)置數(shù)據(jù)斷點(diǎn)的方法來(lái)調(diào)試。一步一步的調(diào)試顯然也沒(méi)法解決問(wèn)題,因?yàn)檫@個(gè)Testcase本身要跑十分鐘,可以想象單步調(diào)試運(yùn)行十分鐘的程序會(huì)花費(fèi)多長(zhǎng)時(shí)間。因此兩個(gè)方案都被我否決。添加Log代碼其實(shí)是可以的,只是需要修改代碼,每次修改之后需要重新編譯代碼,然后需要在目標(biāo)機(jī)器上安裝,而且C#使用的CLR的Branch并非我們正在開發(fā)的Branch,需要重新下載源代碼,相對(duì)比較麻煩。最后為了解決這個(gè)問(wèn)題,我采取的方法是使用WinDbg的條件斷點(diǎn)+Log的方式。大致的方法如下:

第一步:在一個(gè)或者多個(gè)可疑處設(shè)置斷點(diǎn)

bu address “command”

bu是WinDbg中的設(shè)置Unresolved Breakpoints命令,用起來(lái)比較方便,我比較喜歡用。address就是你所要斷的代碼地址,可以是函數(shù)開始,也可以是某一行。Command非常重要,它表示了WinDbg在每次斷到address的時(shí)候都要執(zhí)行的命令,不同命令用分號(hào)隔開,如:

.echo [Function A]; dv this; kb; g

這幾條命令意思是:打印[Function A],打印this指針的值,打印當(dāng)前調(diào)用棧,然后繼續(xù)執(zhí)行。大家可以根據(jù)實(shí)際情況添加一些其他命令打印一些自己所需要的信息。通過(guò)上面這套命令打印的內(nèi)容大致如下:

[FunctionA]

this = 0xABCDEFG

module!FuncA

module!FuncB

module!FuncC

可以看出,這條斷點(diǎn)如果反復(fù)被斷,那么在WinDbg的命令窗口中便會(huì)把每次斷點(diǎn)被Hit的相關(guān)信息通過(guò)剛才定義的命令打印出來(lái)。如果定義了很多這樣的斷點(diǎn),那么在命令窗口中就會(huì)把整個(gè)程序執(zhí)行的情況打印出來(lái),起到Log的作用,而且可以顯示調(diào)用棧等信息,比一般的Log要強(qiáng)大許多。

第二步:設(shè)置Log

缺省情況下,WinDbg的Buffer大小是有限的,如果程序運(yùn)行時(shí)間比較長(zhǎng),那么Buffer可能會(huì)不夠,我們通過(guò)條件斷點(diǎn)打出的信息會(huì)被截?cái)唷P液?#xff0c;WinDbg提供了將命令窗口的內(nèi)容輸出到Log中的功能。選擇Edit->Open/Close Log File菜單項(xiàng),WinDbg會(huì)顯示如下對(duì)話框:

在這個(gè)對(duì)話框里面輸入你想要保存的Log文件名即可。如果是添加新的內(nèi)容而不是覆蓋原有的,則勾上Append。

第三步:分析Log

當(dāng)獲得了Log信息之后,下一步就需要分析Log的內(nèi)容了,這是一件需要耐心、對(duì)數(shù)據(jù)的敏感、以及一點(diǎn)點(diǎn)運(yùn)氣的事情。分析的時(shí)候可能發(fā)現(xiàn)Log的信息不足,這時(shí)就需要添加新的斷點(diǎn)或者修改打印的信息,重新收集Log,再加以分析,直到Log信息足夠?yàn)橹埂_@時(shí)WinDbg設(shè)置條件斷點(diǎn)的優(yōu)勢(shì)就出來(lái)了,因?yàn)椴恍枰薷拇a,編譯代碼,部署代碼這樣的一個(gè)過(guò)程,而是只需要鍵入不同的命令而已。經(jīng)過(guò)幾次調(diào)整斷點(diǎn)位置和打印的信息并重新收集Log,我最終通過(guò)分析發(fā)現(xiàn)這個(gè)Bug是只有可能在特定情況下RCW沒(méi)有被GC,并且創(chuàng)建線程退出的時(shí)候才會(huì)出現(xiàn),具體的內(nèi)容因?yàn)樯婕暗?NET 4.0中還沒(méi)有發(fā)布的新功能,這里就不多說(shuō)了??梢钥吹?#xff0c;如果采用常規(guī)的方法,對(duì)于這種在特定的條件下才會(huì)重現(xiàn)的問(wèn)題是很難發(fā)現(xiàn)的。

總之,使用WinDbg來(lái)設(shè)置條件斷點(diǎn),打印相關(guān)信息,并且輸出到Log文件是一種非常強(qiáng)大的調(diào)試方法,可以調(diào)試一些非常復(fù)雜的Bug,而且具有不需要修改代碼的靈活性,可以自由定義自己想需要打印的信息和斷點(diǎn)設(shè)置的位置,主要的缺點(diǎn)是方法稍顯復(fù)雜,不過(guò)如果適應(yīng)了之后還是很方便的。我強(qiáng)烈推薦大家在遇到比較復(fù)雜的Bug的時(shí)候,可以嘗試使用一下這種方法,可能具有意想不到的效果哦。

?

?

如果一個(gè)程序跑10000次只失敗一次,你會(huì)怎么調(diào)試?

原址:http://blogs.msdn.com/yizhang/archive/2009/08/28/9887951.aspx

CLR小組中存在著大量的回歸測(cè)試,這些回歸測(cè)試會(huì)定期執(zhí)行來(lái)發(fā)現(xiàn)CLR中的Bug,Developer在Checkin之前,也需要執(zhí)行這些測(cè)試的一部分(大概是10小時(shí)左右,如果全部跑的話估計(jì)要好幾天)。這些測(cè)試對(duì)于保證CLR的質(zhì)量是至關(guān)重要的。有時(shí)候,這些測(cè)試會(huì)偶爾失敗,比如跑100次失敗大概一到兩次,有些極端的例子甚至是10000次才失敗一次。像這種問(wèn)題通常是很難調(diào)試的。在前面調(diào)試Bug的神兵利器:通過(guò)WinDbg條件斷點(diǎn)收集Log這篇文章中,我講到了如何通過(guò)條件斷點(diǎn)收集各種信息來(lái)判斷Bug究竟出在哪里。但是,這個(gè)方法還是不太管用,因?yàn)樗荒軌蚍磸?fù)執(zhí)行某個(gè)程序。下面我要講一種技巧可以用來(lái)調(diào)試類似這樣的問(wèn)題,這種技巧主要適用于下面幾種情況:

  • 在程序出錯(cuò)的時(shí)候,某些信息、狀態(tài)已經(jīng)丟失,無(wú)法通過(guò)當(dāng)前出錯(cuò)時(shí)候的狀態(tài)推斷出之前的狀態(tài)。說(shuō)的稍微具體一點(diǎn)就是,比如某個(gè)變量變成了NULL導(dǎo)致Access Violation,但是很難直接推斷出為什么這個(gè)變量變成了NULL
  • 程序運(yùn)行時(shí)間較長(zhǎng),很難直接單步調(diào)試
  • 程序較難修改加入打印代碼(比如加入新代碼并編譯非?;〞r(shí)間,或者該程序沒(méi)有源代碼
  • 該程序運(yùn)行次數(shù)較多的時(shí)候才能發(fā)現(xiàn)問(wèn)題,也就是說(shuō)問(wèn)題不是每次都出現(xiàn)
  • #2和#4決定了一步步調(diào)試基本上是不可能的。#1和#3則意味著我們必須得使用條件斷點(diǎn)來(lái)收集信息來(lái)判斷代碼的錯(cuò)誤,因?yàn)橹苯诱{(diào)試出錯(cuò)的位置是不可行的。下面了我來(lái)講一下如何用CDB(其實(shí)就是WinDbg的無(wú)UI版本,WinDbg=CDB+UI)來(lái)做到:

  • 反復(fù)執(zhí)行程序
  • 當(dāng)程序出錯(cuò)的時(shí)候自動(dòng)暫停
  • 通過(guò)條件斷點(diǎn)收集信息,只保留出錯(cuò)時(shí)候的那一次Log
  • 我們先假設(shè)我們需要調(diào)試的程序叫做Hello.exe,每次出問(wèn)題的現(xiàn)象是,調(diào)用某個(gè)函數(shù)Hello!Func()的時(shí)候,其參數(shù)arg為NULL。Arg這個(gè)變量是由某個(gè)全局變量g_arg傳入而來(lái)。我們可以通過(guò)硬件的數(shù)據(jù)斷點(diǎn)來(lái)查看每次將g_arg賦值為NULL的情況(當(dāng)然了,賦值為NULL并不代表是錯(cuò)誤,只有傳入Hello!Func的時(shí)候?yàn)镹ULL才是錯(cuò)誤)。程序一般要跑10000次才可能發(fā)現(xiàn)問(wèn)題。使用下面的命令行可以做到反復(fù)收集Func1(Func2、Func3因?yàn)轭愃?#xff0c;這里就不列出了)執(zhí)行時(shí)候的g_arg的值并放入Log文件中,并且如果發(fā)現(xiàn)調(diào)用Hello!Func的時(shí)候arg參數(shù)為NULL,則停止程序:

    for /L %i in (1, 1, 10000) DO CDB.exe -c "bu Hello!Func \".echo Inside Hello!Func; dv; .if (poi(arg)!=0) { g } \"; ba w4 Hello!g_arg \“.if (poi(Hello!g_arg)==0) { .echo g_arg changes to NULL; kb; }\”; g" -G -logo debug.log Hello.exe

    我們來(lái)簡(jiǎn)單分析一下:

  • 一開頭的For語(yǔ)句用于執(zhí)行CDB命令10000次,也就是調(diào)試Hello.exe一萬(wàn)次
  • -c命令指定讓CDB在程序開始的時(shí)候執(zhí)行下面的命令
  • bu Hello!Func “.echo Inside Hello!Func; dv; .if (poi(arg)!=0) { g }意思是每次Hello!Func被執(zhí)行的時(shí)候,打印Inside Hello!Func,之后打印所有局部變量和參數(shù)(包括arg),如果發(fā)現(xiàn)arg!=NULL,則繼續(xù)。注意上面命令中的\”是轉(zhuǎn)義符,代表真正的引號(hào),避免沖突。
  • ba w4 Hello!g_arg “.if (poi(Hello!g_arg)==0) { .echo g_arg changes to NULL; kb; }”意思是每次如果g_arg被修改成NULL,打印出Callstack
  • g命令表示讓程序開始執(zhí)行
  • -G:表示讓CDB忽略程序結(jié)束的時(shí)候的Breakpoint,避免CDB在運(yùn)行結(jié)束的時(shí)候停下,保證CDB可以持續(xù)執(zhí)行不需要人工干預(yù)
  • -logo debug.log:表示讓CDB把每次輸出的結(jié)果放入Debug.log中,并且每次都新建立文件,也就是說(shuō),會(huì)把上一次覆蓋。這正好是我們需要的,因?yàn)槲覀冊(cè)O(shè)置了一旦程序錯(cuò)誤則停止,那么這一次的Debug.log才是需要保留的
  • 除了用-c指定初始的命令之外,也可以使用-cf來(lái)指定一個(gè)文件包含任意條CDB命令,如果CDB命令較多,可以采用這種方法。

    本文說(shuō)道的方法是比較有效的,我自己曾經(jīng)使用過(guò)這種方法解決過(guò)不少比較棘手的問(wèn)題。如果碰到了此種需要運(yùn)行10000次才能重現(xiàn)問(wèn)題的Bug,不妨試一下本文的方法。

    轉(zhuǎn)載于:https://www.cnblogs.com/hhuai/archive/2010/03/01/1675383.html

    總結(jié)

    以上是生活随笔為你收集整理的[转]两个经典的windbg调试案例,值得学习。的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。