• <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]

            遍歷當前線程的callstack

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

            XP開始以及在x64IA64平臺上,目前已經有API來獲得當前線程的上下文,就是RtlCaptureContext.。

            演示代碼7

            StackWalker sw;

            sw.ShowCallstack();

            在同一個進程內遍歷其他線程的callstack(略)

            遍歷另一個進程內的某線程callstack(略)

            (譯者注:由于時間原因,上述兩部分的翻譯暫時省略了,內容也比較簡單,只是調用了StackWalker的不同構造函數)

            重用StackWalk的實例

            重用StackWalk的實例是沒有任何問題的,只要你想在同一個進程內遍歷callstack。如果你重復多次用到callstack的遍歷,我強烈你推薦重用一個實例。原因很簡單:當你創建一個新的實例的時候,symbol文件就要被重新加載一次,這個是非常耗時的。而且多個StackWalk跨線程工作也是不可靠的,因為dbghelp.dll不是線程安全的。綜上,在一個進程中保持只有一個StackWalker實例是最合理的做法。

            Symbol的搜索路徑

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

            1, szSymPath是否提供是可選擇的,如果提供的話,那么SymBuildPath會自動生成。在szSymPath中每個路徑之間要用分號“;”來分開。

            2, 當前工作目錄

            3, 可執行文件的目錄,如exel

            4, _NT_SYMBOL_PATH的環境變量

            5, _NT_ALTERNATE_SYMBOL_PATH的環境變量

            6, SYSTEMROOT的環境變量

            7, SYSTEMROOT\system32的環境變量

            8, MS符號服務器SRV*%SYSTEMDRIVE%\websymbols*http://msdl.microsoft.com/download/symbols

            符號服務器

            如果你想使用MS的公共信號服務器,你可以選擇安裝windbg(這樣symsrv.dll和最新dbghelp.dll會被自動查詢到),你也可以選擇從網絡傳輸中獲取這些最新符號,不過推薦前者,這樣就不會因為網絡故障而出現加載符號失敗。

            加載程式和符號

            為了能成功遍歷線程的callstack,dbghelp.dll要獲得所有被加載模塊的信息。所有你需要通過SymLoadModule64這個API來注冊所有被加載的模塊,在注冊之前,第一步是枚舉出所有的模塊。

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

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


            遍歷當前線程的
            callstack

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

            XP開始以及在x64IA64平臺上,目前已經有API來獲得當前線程的上下文,就是RtlCaptureContext.。

            演示代碼7

            StackWalker sw;

            sw.ShowCallstack();

            在同一個進程內遍歷其他線程的callstack(略)

            遍歷另一個進程內的某線程callstack(略)

            (譯者注:由于時間原因,上述兩部分的翻譯暫時省略了,內容也比較簡單,只是調用了StackWalker的不同構造函數)

            重用StackWalk的實例

            重用StackWalk的實例是沒有任何問題的,只要你想在同一個進程內遍歷callstack。如果你重復多次用到callstack的遍歷,我強烈你推薦重用一個實例。原因很簡單:當你創建一個新的實例的時候,symbol文件就要被重新加載一次,這個是非常耗時的。而且多個StackWalk跨線程工作也是不可靠的,因為dbghelp.dll不是線程安全的。綜上,在一個進程中保持只有一個StackWalker實例是最合理的做法。

            Symbol的搜索路徑

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

            1, szSymPath是否提供是可選擇的,如果提供的話,那么SymBuildPath會自動生成。在szSymPath中每個路徑之間要用分號“;”來分開。

            2, 當前工作目錄

            3, 可執行文件的目錄,如exel

            4, _NT_SYMBOL_PATH的環境變量

            5, _NT_ALTERNATE_SYMBOL_PATH的環境變量

            6, SYSTEMROOT的環境變量

            7, SYSTEMROOT\system32的環境變量

            8, MS符號服務器SRV*%SYSTEMDRIVE%\websymbols*http://msdl.microsoft.com/download/symbols

            符號服務器

            如果你想使用MS的公共信號服務器,你可以選擇安裝windbg(這樣symsrv.dll和最新dbghelp.dll會被自動查詢到),你也可以選擇從網絡傳輸中獲取這些最新符號,不過推薦前者,這樣就不會因為網絡故障而出現加載符號失敗。

            加載程式和符號

            為了能成功遍歷線程的callstack,dbghelp.dll要獲得所有被加載模塊的信息。所有你需要通過SymLoadModule64這個API來注冊所有被加載的模塊,在注冊之前,第一步是枚舉出所有的模塊。

            win9x之后。利用ToolHelp32_API可以實現這個需求,需要用的API有,CreateToolhelp32SnapShot,Module32FirstModule32Next。通常情況下這些API包含在kernel32.dll,但是在win9x的系統上,這些API包含在tlhelp32.dll中,所以在代碼中要做分支判斷。

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


            Dbghelp.dll

            下面就來隨便啰嗦幾句dbghelp.dll

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

            2, Winme/W2k開始,system32目錄下面的dbghelp.dll文件是受保護的。所以如果你想成功遍歷callstack,,最好去下載個最新版本的dbghelp.dll放在你的exe目錄下面。否則在W2k上會導致一個問題,就是,如果你想遍歷一個用VC7+編譯的工程就會出錯。因為VC7+的編譯器生成的PDB格式文件不能被dbghelp.dll識別,這樣你就不會得到有效的callstack信息??傊?,保險起見,不要使用 OSdbghelp.dll,去下載最新的dbghelp.dll來使用。(譯者注:我在論壇中看到很多人無法正確遍歷棧,都是dbghelp.dll的版本較老造成的。)

            3, V6.5.3.7版本的dbghelp.dll有個bug,或是說StackWalk64函數的文檔發生了變化。文檔中描述:

            如果STACKFRAME64的兩個成員AddrPCAddrFrame沒有被初始化就作為參數傳給StackWalk64的話,那么這個函數在第一次被調用的時候就會失敗。而且,只有當參數MachineType不是IAMGE_FILE_MACHINE_I386的時候,參數ContectRecord才要求被初始化。

            但是這個是錯誤的。在x86上,當你給ContextRecordNULL的時候,并不能獲得到callstack。以我的觀點,這是比較大的文檔改動?,F在你既可以通過初始話AddrStack,也可以通過包含EIP,EBP,ESPContextRecord來成功獲取callstack

            Stackwalker的操作開關

            你可以按照自己的需求來定義操作開關

            演示代碼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:這個工程只支持StackWalk64這個API。如果你想在NT4/win9x上使用的話,你需要重新配置dbghelp.dll

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

            3, NT4/win9x的平臺上,用“OpenThread”來打開遠程線程是不支持的,如果你想實現,請參考Remote Library。

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

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

            国产美女久久精品香蕉69| 久久精品国产亚洲AV不卡| 久久久噜噜噜www成人网| 国内精品久久九九国产精品| 亚洲狠狠综合久久| 亚洲欧洲久久久精品| 久久精品无码午夜福利理论片 | 99精品国产免费久久久久久下载| 久久精品中文无码资源站| 久久99国产精一区二区三区| 尹人香蕉久久99天天拍| 久久综合香蕉国产蜜臀AV| 久久精品亚洲乱码伦伦中文| 久久婷婷五月综合97色| 久久婷婷色香五月综合激情| 91精品日韩人妻无码久久不卡| 久久人人爽人人爽人人片AV高清| 国产A级毛片久久久精品毛片| 东方aⅴ免费观看久久av| 色99久久久久高潮综合影院| 久久久久一区二区三区| 久久久噜噜噜www成人网| 三级三级久久三级久久| 久久艹国产| 国产亚洲美女精品久久久| 韩国无遮挡三级久久| 精品免费久久久久久久| 久久精品国产日本波多野结衣| 色播久久人人爽人人爽人人片aV| 国产成人无码精品久久久免费| 77777亚洲午夜久久多喷| 久久精品中文闷骚内射| 久久无码人妻一区二区三区| 久久人人爽人人爽人人爽| 国产精品久久久久久久app| 狠狠色丁香久久婷婷综合图片 | 国产精品成人99久久久久 | 久久成人小视频| 亚洲精品乱码久久久久久 | 97久久综合精品久久久综合| 日韩精品久久久久久免费|