• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            focus on linux, c/c++, lua

            Walking the callstack [譯文 part2]

            遍歷當(dāng)前線程的callstack

            x86的系統(tǒng)上(XP之前),是沒(méi)有一個(gè)直接的API用來(lái)獲得當(dāng)前線程的上下文的。當(dāng)時(shí)提倡的做法是在捕獲系統(tǒng)異常中來(lái)獲得。現(xiàn)在在我們的代碼中,我們實(shí)現(xiàn)了有效的獲取上下文的方法。默認(rèn)的情況下,我們是通過(guò)內(nèi)聯(lián)匯編代碼來(lái)獲取EIP,ESPEBP的值。如果你想使用我剛才提到的捕獲異常的方法來(lái)實(shí)現(xiàn)的話,那你就需要定義一個(gè)CURRENT_THREAD_VIA_EXCEPTION這樣的宏。但是我們應(yīng)該意識(shí)到,其實(shí)GET_CURRENT_CONTEXT也是一個(gè)宏,內(nèi)部也是使用了捕捉異常的原理。我們的函數(shù)都必須要能包含這些宏的聲明。

            XP開(kāi)始以及在x64IA64平臺(tái)上,目前已經(jīng)有API來(lái)獲得當(dāng)前線程的上下文,就是RtlCaptureContext.

            演示代碼7

            StackWalker sw;

            sw.ShowCallstack();

            在同一個(gè)進(jìn)程內(nèi)遍歷其他線程的callstack(略)

            遍歷另一個(gè)進(jìn)程內(nèi)的某線程callstack(略)

            (譯者注:由于時(shí)間原因,上述兩部分的翻譯暫時(shí)省略了,內(nèi)容也比較簡(jiǎn)單,只是調(diào)用了StackWalker的不同構(gòu)造函數(shù))

            重用StackWalk的實(shí)例

            重用StackWalk的實(shí)例是沒(méi)有任何問(wèn)題的,只要你想在同一個(gè)進(jìn)程內(nèi)遍歷callstack。如果你重復(fù)多次用到callstack的遍歷,我強(qiáng)烈你推薦重用一個(gè)實(shí)例。原因很簡(jiǎn)單:當(dāng)你創(chuàng)建一個(gè)新的實(shí)例的時(shí)候,symbol文件就要被重新加載一次,這個(gè)是非常耗時(shí)的。而且多個(gè)StackWalk跨線程工作也是不可靠的,因?yàn)?/span>dbghelp.dll不是線程安全的。綜上,在一個(gè)進(jìn)程中保持只有一個(gè)StackWalker實(shí)例是最合理的做法。

            Symbol的搜索路徑

            通常情況下,Symbol的搜索路徑(SymBuildPath SymUseSymSrv)主要是用來(lái)搜索這個(gè)文件dbghelp.dll。這個(gè)路徑通常包含一下目錄:

            1, szSymPath是否提供是可選擇的,如果提供的話,那么SymBuildPath會(huì)自動(dòng)生成。在szSymPath中每個(gè)路徑之間要用分號(hào)“;”來(lái)分開(kāi)。

            2, 當(dāng)前工作目錄

            3, 可執(zhí)行文件的目錄,如exel

            4, _NT_SYMBOL_PATH的環(huán)境變量

            5, _NT_ALTERNATE_SYMBOL_PATH的環(huán)境變量

            6, SYSTEMROOT的環(huán)境變量

            7, SYSTEMROOT\system32的環(huán)境變量

            8, MS符號(hào)服務(wù)器SRV*%SYSTEMDRIVE%\websymbols*http://msdl.microsoft.com/download/symbols

            符號(hào)服務(wù)器

            如果你想使用MS的公共信號(hào)服務(wù)器,你可以選擇安裝windbg(這樣symsrv.dll和最新dbghelp.dll會(huì)被自動(dòng)查詢到),你也可以選擇從網(wǎng)絡(luò)傳輸中獲取這些最新符號(hào),不過(guò)推薦前者,這樣就不會(huì)因?yàn)榫W(wǎng)絡(luò)故障而出現(xiàn)加載符號(hào)失敗。

            加載程式和符號(hào)

            為了能成功遍歷線程的callstackdbghelp.dll要獲得所有被加載模塊的信息。所有你需要通過(guò)SymLoadModule64這個(gè)API來(lái)注冊(cè)所有被加載的模塊,在注冊(cè)之前,第一步是枚舉出所有的模塊。

            win9x之后。利用ToolHelp32_API可以實(shí)現(xiàn)這個(gè)需求,需要用的API有,CreateToolhelp32SnapShotModule32FirstModule32Next。通常情況下這些API包含在kernel32.dll,但是在win9x的系統(tǒng)上,這些API包含在tlhelp32.dll中,所以在代碼中要做分支判斷。

            如果你是在NT4上干活的話,那么使用ToolHelp32-API只是一個(gè)夢(mèng)想。但是你可以使用PSAPI來(lái)取而代之。你需要使用到一下APIEnumProcessModules, GetModuleInformation, GetModuleBaseName, GetModuleFileNameEx


            遍歷當(dāng)前線程的
            callstack

            x86的系統(tǒng)上(XP之前),是沒(méi)有一個(gè)直接的API用來(lái)獲得當(dāng)前線程的上下文的。當(dāng)時(shí)提倡的做法是在捕獲系統(tǒng)異常中來(lái)獲得。現(xiàn)在在我們的代碼中,我們實(shí)現(xiàn)了有效的獲取上下文的方法。默認(rèn)的情況下,我們是通過(guò)內(nèi)聯(lián)匯編代碼來(lái)獲取EIP,ESPEBP的值。如果你想使用我剛才提到的捕獲異常的方法來(lái)實(shí)現(xiàn)的話,那你就需要定義一個(gè)CURRENT_THREAD_VIA_EXCEPTION這樣的宏。但是我們應(yīng)該意識(shí)到,其實(shí)GET_CURRENT_CONTEXT也是一個(gè)宏,內(nèi)部也是使用了捕捉異常的原理。我們的函數(shù)都必須要能包含這些宏的聲明。

            XP開(kāi)始以及在x64IA64平臺(tái)上,目前已經(jīng)有API來(lái)獲得當(dāng)前線程的上下文,就是RtlCaptureContext.

            演示代碼7

            StackWalker sw;

            sw.ShowCallstack();

            在同一個(gè)進(jìn)程內(nèi)遍歷其他線程的callstack(略)

            遍歷另一個(gè)進(jìn)程內(nèi)的某線程callstack(略)

            (譯者注:由于時(shí)間原因,上述兩部分的翻譯暫時(shí)省略了,內(nèi)容也比較簡(jiǎn)單,只是調(diào)用了StackWalker的不同構(gòu)造函數(shù))

            重用StackWalk的實(shí)例

            重用StackWalk的實(shí)例是沒(méi)有任何問(wèn)題的,只要你想在同一個(gè)進(jìn)程內(nèi)遍歷callstack。如果你重復(fù)多次用到callstack的遍歷,我強(qiáng)烈你推薦重用一個(gè)實(shí)例。原因很簡(jiǎn)單:當(dāng)你創(chuàng)建一個(gè)新的實(shí)例的時(shí)候,symbol文件就要被重新加載一次,這個(gè)是非常耗時(shí)的。而且多個(gè)StackWalk跨線程工作也是不可靠的,因?yàn)?/span>dbghelp.dll不是線程安全的。綜上,在一個(gè)進(jìn)程中保持只有一個(gè)StackWalker實(shí)例是最合理的做法。

            Symbol的搜索路徑

            通常情況下,Symbol的搜索路徑(SymBuildPath SymUseSymSrv)主要是用來(lái)搜索這個(gè)文件dbghelp.dll。這個(gè)路徑通常包含一下目錄:

            1, szSymPath是否提供是可選擇的,如果提供的話,那么SymBuildPath會(huì)自動(dòng)生成。在szSymPath中每個(gè)路徑之間要用分號(hào)“;”來(lái)分開(kāi)。

            2, 當(dāng)前工作目錄

            3, 可執(zhí)行文件的目錄,如exel

            4, _NT_SYMBOL_PATH的環(huán)境變量

            5, _NT_ALTERNATE_SYMBOL_PATH的環(huán)境變量

            6, SYSTEMROOT的環(huán)境變量

            7, SYSTEMROOT\system32的環(huán)境變量

            8, MS符號(hào)服務(wù)器SRV*%SYSTEMDRIVE%\websymbols*http://msdl.microsoft.com/download/symbols

            符號(hào)服務(wù)器

            如果你想使用MS的公共信號(hào)服務(wù)器,你可以選擇安裝windbg(這樣symsrv.dll和最新dbghelp.dll會(huì)被自動(dòng)查詢到),你也可以選擇從網(wǎng)絡(luò)傳輸中獲取這些最新符號(hào),不過(guò)推薦前者,這樣就不會(huì)因?yàn)榫W(wǎng)絡(luò)故障而出現(xiàn)加載符號(hào)失敗。

            加載程式和符號(hào)

            為了能成功遍歷線程的callstackdbghelp.dll要獲得所有被加載模塊的信息。所有你需要通過(guò)SymLoadModule64這個(gè)API來(lái)注冊(cè)所有被加載的模塊,在注冊(cè)之前,第一步是枚舉出所有的模塊。

            win9x之后。利用ToolHelp32_API可以實(shí)現(xiàn)這個(gè)需求,需要用的API有,CreateToolhelp32SnapShotModule32FirstModule32Next。通常情況下這些API包含在kernel32.dll,但是在win9x的系統(tǒng)上,這些API包含在tlhelp32.dll中,所以在代碼中要做分支判斷。

            如果你是在NT4上干活的話,那么使用ToolHelp32-API只是一個(gè)夢(mèng)想。但是你可以使用PSAPI來(lái)取而代之。你需要使用到一下APIEnumProcessModules, GetModuleInformation, GetModuleBaseName, GetModuleFileNameEx


            Dbghelp.dll

            下面就來(lái)隨便啰嗦幾句dbghelp.dll

            1, 首先,在MS,有兩個(gè)team在負(fù)責(zé)開(kāi)發(fā)dbghelp.dll,一個(gè)是os-team,另一個(gè)是debug-team。通常情況下,你會(huì)以為windbg提供的dbghelp.dll是最新的版本。但是有個(gè)問(wèn)題就是這兩個(gè)小組發(fā)布的dbghelp.dll的版本是不同的。舉個(gè)例子來(lái)說(shuō):xp-sp1dbghelp.dll版本是5.1.2600.11062002-08-29)。但是debug-team發(fā)布的6.0.0017.0版本時(shí)間卻是2002-04-31。(譯者注:寒,MS也會(huì)犯這種錯(cuò)誤)。這樣版本的發(fā)布就會(huì)有沖突,所以很難通過(guò)版本好來(lái)確定哪個(gè)更好,更有效。

            2, Winme/W2k開(kāi)始,system32目錄下面的dbghelp.dll文件是受保護(hù)的。所以如果你想成功遍歷callstack,,最好去下載個(gè)最新版本的dbghelp.dll放在你的exe目錄下面。否則在W2k上會(huì)導(dǎo)致一個(gè)問(wèn)題,就是,如果你想遍歷一個(gè)用VC7+編譯的工程就會(huì)出錯(cuò)。因?yàn)?/span>VC7+的編譯器生成的PDB格式文件不能被dbghelp.dll識(shí)別,這樣你就不會(huì)得到有效的callstack信息。總之,保險(xiǎn)起見(jiàn),不要使用 OSdbghelp.dll,去下載最新的dbghelp.dll來(lái)使用。(譯者注:我在論壇中看到很多人無(wú)法正確遍歷棧,都是dbghelp.dll的版本較老造成的。)

            3, V6.5.3.7版本的dbghelp.dll有個(gè)bug,或是說(shuō)StackWalk64函數(shù)的文檔發(fā)生了變化。文檔中描述:

            如果STACKFRAME64的兩個(gè)成員AddrPCAddrFrame沒(méi)有被初始化就作為參數(shù)傳給StackWalk64的話,那么這個(gè)函數(shù)在第一次被調(diào)用的時(shí)候就會(huì)失敗。而且,只有當(dāng)參數(shù)MachineType不是IAMGE_FILE_MACHINE_I386的時(shí)候,參數(shù)ContectRecord才要求被初始化。

            但是這個(gè)是錯(cuò)誤的。在x86上,當(dāng)你給ContextRecordNULL的時(shí)候,并不能獲得到callstack。以我的觀點(diǎn),這是比較大的文檔改動(dòng)。現(xiàn)在你既可以通過(guò)初始話AddrStack,也可以通過(guò)包含EIP,EBP,ESPContextRecord來(lái)成功獲取callstack

            Stackwalker的操作開(kāi)關(guān)

            你可以按照自己的需求來(lái)定義操作開(kāi)關(guān)

            演示代碼7

            typedef enum StackWalkOptions

            {

                // No addition info will be retrived

                // (only the address is available)

                RetrieveNone = 0,

                // Try to get the symbol-name

                RetrieveSymbol = 1,

                // Try to get the line for this symbol

                RetrieveLine = 2,

                // Try to retrieve the module-infos

                RetrieveModuleInfo = 4,

                // Also retrieve the version for the DLL/EXE

                RetrieveFileVersion = 8,

                // Contains all the abouve

                RetrieveVerbose = 0xF,

                // Generate a "good" symbol-search-path

                SymBuildPath = 0x10,

                // Also use the public Microsoft-Symbol-Server

                SymUseSymSrv = 0x20,

                // Contains all the abouve "Sym"-options

                SymAll = 0x30,

                // Contains all options (default)

                OptionsAll = 0x3F

            } StackWalkOptions;

             

            使用須知

            1, NT/Win9x:這個(gè)工程只支持StackWalk64這個(gè)API。如果你想在NT4/win9x上使用的話,你需要重新配置dbghelp.dll

            2, 當(dāng)前工程在遍歷過(guò)程中只支持ANSI名稱符,(譯者注:C++中沒(méi)看到過(guò)有人用中文命名的函數(shù)名,但java大有人在),當(dāng)然,如果你也可以選擇以unicode的編碼方式來(lái)編譯工程來(lái)解決中文函數(shù)名的問(wèn)題。

            3, NT4/win9x的平臺(tái)上,用“OpenThread”來(lái)打開(kāi)遠(yuǎn)程線程是不支持的,如果你想實(shí)現(xiàn),請(qǐng)參考Remote Library

            4, 遍歷混合模式的callstack(包含managedunmanaged)并不會(huì)返回unmanaged的函數(shù)。

            posted on 2010-10-20 10:22 zuhd 閱讀(610) 評(píng)論(0)  編輯 收藏 引用 所屬分類: c/c++

            亚洲级αV无码毛片久久精品 | 一本一本久久aa综合精品| 久久99精品久久久久久hb无码| 亚洲色欲久久久久综合网| 国产亚洲美女精品久久久| 国产精久久一区二区三区| 国产AⅤ精品一区二区三区久久| 精品国际久久久久999波多野| 精品无码久久久久久午夜| 91久久婷婷国产综合精品青草 | 色综合久久久久无码专区| 一本久道久久综合狠狠爱| 久久综合偷偷噜噜噜色| 久久久久久久91精品免费观看| 国产69精品久久久久观看软件| 国内精品伊人久久久久777| 亚洲欧美成人综合久久久| 久久精品人人做人人妻人人玩| avtt天堂网久久精品| 狠狠色婷婷综合天天久久丁香 | 久久播电影网| 亚洲国产精品成人久久蜜臀 | 欧美久久精品一级c片片| 久久国产精品免费一区| 久久久久久综合网天天| 久久精品国产99国产精品澳门| 久久高潮一级毛片免费| 无码AV波多野结衣久久| 国产成人无码精品久久久久免费 | 久久亚洲sm情趣捆绑调教| 久久精品天天中文字幕人妻 | 久久久精品国产sm调教网站| 久久精品国产99国产电影网| 无夜精品久久久久久| 久久久久久九九99精品| 性做久久久久久久久老女人 | 久久电影网一区| 亚洲国产日韩综合久久精品| 久久亚洲国产午夜精品理论片| 久久精品久久久久观看99水蜜桃| 日韩精品国产自在久久现线拍|