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

            來吧,朋友!

            為C++瘋狂

            通往WinDbg的捷徑(二)

            [轉(zhuǎn)載]通往WinDbg的捷徑(二) 

            原文:http://www.debuginfo.com/articles/easywindbg2.html
            譯者:arhat
            時間:2006年4月14日
            關(guān)鍵詞:CDB WinDbg 

            保存 dumps 
            在我們調(diào)試不容易重現(xiàn)的問題時,可能想把應(yīng)用程序狀態(tài)的快照(內(nèi)存內(nèi)容,打開名柄的列表,等等)保存起來,以便日后分析。例如,當(dāng)我懷疑當(dāng)前的狀態(tài)可能包含我試圖解決的問題的關(guān)鍵點(diǎn),而想繼續(xù)運(yùn)行應(yīng)用程序來查看情形怎樣發(fā)展時,它就很有用了。有時候,我會做一系列的快照,一個接一個,以便稍后我能比較它們,查看在應(yīng)用程序運(yùn)行時有些數(shù)據(jù)結(jié)構(gòu)怎樣變化。當(dāng)我最終能重現(xiàn)這個問題時,我總是創(chuàng)建一個快照來確保我沒有因?yàn)槟承╁e誤(錯誤關(guān)閉了調(diào)試會話)而丟失有價值的信息。或許,大家不難猜到當(dāng)我說“快照”時,我真正的意思是“minidump”,因?yàn)閙inidump為隨時保存應(yīng)用程序的狀態(tài)提供了便利。
            下面是創(chuàng)建minidump的命令行示例:
              cdb -pv -pn myapp.exe -c ".dump /m c:\myapp.dmp;q"
            讓我們仔細(xì)看一下.dump命令。在上面的例子里,我們只用到這條命令的一個選項(xiàng)(/m),后面跟著minidump的文件名。用/m來指定minidump里應(yīng)當(dāng)包括哪種信息。最重要的(依我之見)/m選項(xiàng)的變量列在下表中:
            ---------------------------------------------------------------------------------------------------------------------------
            選項(xiàng)      描述                                                                                              例子
            ---------------------------------------------------------------------------------------------------------------------------
            /m        默認(rèn)就是這個選項(xiàng)。它創(chuàng)建標(biāo)準(zhǔn)的minidump,等同于MiniDumpNormal minidump類型。由此生成的minidump
                      一般很小,因此,如果你想通過慢速的網(wǎng)絡(luò)傳輸minidump,那么這個選項(xiàng)非常有用。但不幸地是,小體積的
                      minidump也意味著在大多數(shù)情況下,它包含的信息不足以進(jìn)行完整的分析(你可以在這篇文章里找到更多有
                      關(guān)minidump內(nèi)容的信息)。                                                                     dump /m c:\myapp.dmp
            ---------------------------------------------------------------------------------------------------------------------------
            /ma       帶所有可選項(xiàng)的Minidump(完整的內(nèi)存內(nèi)容,名柄,已卸載的模塊,等等),由此生成的minidump將非常
                      大。如果可以隨意使用磁盤空間,這個選項(xiàng)將非常適合本地調(diào)試。                               .dump /ma c:\myapp.dmp
            ---------------------------------------------------------------------------------------------------------------------------
            /mFhutwd  這個選項(xiàng)將生成帶數(shù)據(jù)段,非共享讀/寫內(nèi)存頁和其它有用信息的minidump。如果你想盡可能的收集信息,
                      但仍想使minidump保持小體積(并壓縮),就可以用這個選項(xiàng)。                                .dump /mFhutwd c:\myapp.dmp
            ---------------------------------------------------------------------------------------------------------------------------
            下面的命令生成包含所有信息的minidump:
              cdb -pv -pn myapp.exe -c ".dump /ma c:\myapp.dmp;q"
            如果我們想生成一個新minidump,并覆蓋已有的,該怎么辦呢?在默認(rèn)情況下,.dump命令不允許這樣做??它會抱怨文件已經(jīng)存在。為了改變默認(rèn)行為,覆蓋已存在的.dump文件,我們可以用/o選項(xiàng):
              cdb -pv -pn myapp.exe -c ".dump /ma /o c:\myapp.dmp;q"
            如果我們想生成一系列的minidump,一個接一個,那么它能很方便的為minidump命名,并使文件名反映生成minidump時的時間嗎。嗯,如果我們指定了/u選項(xiàng),.dump命令就可以自動為我們這樣做,這真是一個好消息,不是嗎?例如,下面的命令可以生成名為myapp_02CC_2006-01-28_04-11-18-171_0158.dmp的minidump(0158是進(jìn)程ID):
              cdb -pv -pn myapp.exe -c ".dump /m /u c:\myapp.dmp;q"
            .dump命令也支持其它有趣的選項(xiàng)(你可以在文檔里發(fā)現(xiàn)它們)。
            如果你想生成運(yùn)行在Visual Studio調(diào)試器下的進(jìn)程的minidump,我建議在生成dump前,先在Visual Studio里臨時禁用所有的斷點(diǎn)。如果沒有禁用斷點(diǎn),生成的minidump將包含Visual Studio調(diào)試器插入目標(biāo)進(jìn)程代碼里的斷點(diǎn)指令(int 3)。

            分析故障轉(zhuǎn)儲
            CDB也可以用于自動分析故障轉(zhuǎn)儲。當(dāng)我們分析故障轉(zhuǎn)儲時,通常會執(zhí)行同樣的操作,所以可以把這些操作自動化。什么樣的操作呢?這要看故障轉(zhuǎn)儲的類型。我把所有的故障轉(zhuǎn)儲分成兩大類:
            •  帶異常信息的故障轉(zhuǎn)儲
            •  不帶異常信息的故障轉(zhuǎn)儲
            當(dāng)應(yīng)用程序引發(fā)未經(jīng)處理的異常并調(diào)用just-in-time調(diào)試器(Dr. Watson,NTSD  , 或其它的調(diào)試器),或者用為未經(jīng)處理的異常定制的過濾器 生成minidump時,通常會生成帶異常信息的故障轉(zhuǎn)儲。通過寫入故障轉(zhuǎn)儲里的異常信息,我們可以確定異常的類型和發(fā)生時它在代碼里的位置。當(dāng)我們想為以后的分析生成進(jìn)程的快照時(例如,這方面的描述參見本文的前一部分“保存dumps”),通常手動生成不帶異常信息的故障轉(zhuǎn)儲。
            當(dāng)我們調(diào)試帶異常信息的故障轉(zhuǎn)儲時,通常想知道下面這些信息:
            •  異常在代碼中出現(xiàn)的位置(地址,源文件和行號)
            •  異常發(fā)生時的調(diào)用棧
            •  調(diào)用棧上一些或所有函數(shù)的參數(shù)值和局部變量
            WinDbg和CDB為調(diào)試故障轉(zhuǎn)儲提供了非常有用的命令??!analyze。這條命令分析故障轉(zhuǎn)儲里的異常信息,確定異常發(fā)生的位置,調(diào)用棧,并顯示詳細(xì)的報告。下面是這條命令的示例:
              cdb -z c:\myapp.dmp -logo out.txt -lines -c "!analyze -v;q"
            (-v選項(xiàng)要求!analyze輸出詳細(xì)的內(nèi)容)
            CrashDemo.cpp 例子演示了怎樣用定制的過濾器捕獲未經(jīng)處理的異常并生成minidumps。如果你編譯并運(yùn)行它,然后用上述的CDB命令分析生成的minidump,你將可以得到和下面類似的輸出內(nèi)容:
            0:001> !analyze -v
            *******************************************************************************
            *                                                                             *
            *                        Exception Analysis                                   *
            *                                                                             *
            *******************************************************************************

            FAULTING_IP: 
            CrashDemo!TestFunc+2e [c:\tests\crashdemo\crashdemo.cpp @ 124]
            004309de c70000000000     mov     dword ptr [eax],0x0

            EXCEPTION_RECORD:  ffffffff -- (.exr ffffffffffffffff)
            .exr ffffffffffffffff
            ExceptionAddress: 004309de (CrashDemo!TestFunc+0x0000002e)
            ExceptionCode: c0000005 (Access violation)
            ExceptionFlags: 00000000
            NumberParameters: 2
            Parameter[0]: 00000001
            Parameter[1]: 00000000
            Attempt to write to address 00000000

            DEFAULT_BUCKET_ID:  APPLICATION_FAULT

            PROCESS_NAME:  CrashDemo.exe

            ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory 
              at "0x%08lx". The memory could not be "%s".

            WRITE_ADDRESS:  00000000 

            BUGCHECK_STR:  ACCESS_VIOLATION

            LAST_CONTROL_TRANSFER:  from 0043096e to 004309de

            STACK_TEXT:
            006afe88 0043096e 00000000 00354130 00350001 CrashDemo!TestFunc+0x2e 
              [c:\tests\crashdemo\crashdemo.cpp @ 124]
            006aff6c 00430f31 00000000 52319518 00354130 CrashDemo!WorkerThread+0x5e 
              [c:\tests\crashdemo\crashdemo.cpp @ 115]
            006affa8 00430ea2 00000000 006affec 7c80b50b CrashDemo!_callthreadstartex+0x51 
              [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]
            006affb4 7c80b50b 00355188 00354130 00350001 CrashDemo!_threadstartex+0xa2 
              [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 331]
            006affec 00000000 00430e00 00355188 00000000 kernel32!BaseThreadStart+0x37


            FOLLOWUP_IP: 
            CrashDemo!TestFunc+2e [c:\tests\crashdemo\crashdemo.cpp @ 124]
            004309de c70000000000     mov     dword ptr [eax],0x0

            SYMBOL_STACK_INDEX:  0

            FOLLOWUP_NAME:  MachineOwner

            SYMBOL_NAME:  CrashDemo!TestFunc+2e

            MODULE_NAME:  CrashDemo

            IMAGE_NAME:  CrashDemo.exe

            DEBUG_FLR_IMAGE_TIMESTAMP:  43dc6ee7

            STACK_COMMAND:  .ecxr ; kb

            FAILURE_BUCKET_ID:  ACCESS_VIOLATION_CrashDemo!TestFunc+2e

            BUCKET_ID:  ACCESS_VIOLATION_CrashDemo!TestFunc+2e

            Followup: MachineOwner
            ---------
            注意用粗體表示的內(nèi)容。第一處報告了異常的地址和類型。第二外報告調(diào)用棧。第三處為我們提供了怎樣訪問保存在故障轉(zhuǎn)儲里的異常信息的額外信息。
            現(xiàn)在,我們知道異常發(fā)生的位置,甚至可以查看調(diào)用棧。那么,是得到函數(shù)的參數(shù)值及局部變量的時候了。在開始之前,讓我們注意!analyze報告中的第三處信息。這里再重復(fù)一下第三處所包含的內(nèi)容:
            STACK_COMMAND:  .ecxr ; kb
            對'kb'命令我們已經(jīng)不陌生了(它顯示調(diào)用棧)。但.ecxr是什么?這條命令要求調(diào)試器把當(dāng)前的內(nèi)容切換到保存在故障轉(zhuǎn)儲里的異常信息。我們執(zhí)行這條命令后,將能訪問異常拋出時調(diào)用棧和局部變量的值。
            在我們要求調(diào)試使用異常的上下文后,我們可以用'dv'命令顯示函數(shù)的參數(shù)值以及局部變量。因?yàn)槲覀兺ǔO氩榭凑{(diào)用棧上每一個函數(shù)的信息,因此,我們可以用'!for_each_frame dv /t'命令(/t選項(xiàng)要求'dv'顯示有用的類型信息)。(當(dāng)然,我們必須記住,使用優(yōu)化編譯時,在函數(shù)的整個生存期中,局部變量有可能會被取消,重注冊或被重用來保存其它的數(shù)據(jù),因此,可能會導(dǎo)致'dv'命令輸出錯誤的值)。
            下面是分析帶異常信息的故障轉(zhuǎn)儲的命令行示例:
              cdb -z c:\myapp.dmp -logo out.txt -lines -c "!analyze -v;.ecxr;!for_each_frame dv /t;q"
            下面是'!for_each_frame dv /t'命令輸出的例子:
            _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            00 006afe88 0043096e CrashDemo!TestFunc+0x2e [c:\tests\crashdemo\crashdemo.cpp @ 124]
            int * pParam = 0x00000000
            _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            01 006aff6c 00430f31 CrashDemo!WorkerThread+0x5e [c:\tests\crashdemo\crashdemo.cpp @ 115]
            void * lpParam = 0x00000000
            int * TempPtr = 0x00000000
            _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            02 006affa8 00430ea2 CrashDemo!_callthreadstartex+0x51 
              [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]
            struct _tiddata * ptd = 0x00355188
            _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            03 006affb4 7c80b50b CrashDemo!_threadstartex+0xa2 
              [f:\rtm\vctools\crt_bld\self_x86\crt\src\threadex.c @ 331]
            void * ptd = 0x00355188
            struct _tiddata * _ptd = 0x00000000
            _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            04 006affec 00000000 kernel32!BaseThreadStart+0x37
            Unable to enumerate locals, HRESULT 0x80004005
            Private symbols (symbols.pri) are required for locals.
            Type ".hh dbgerr005" for details.
            _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
            00 006afe88 0043096e CrashDemo!TestFunc+0x2e [c:\tests\crashdemo\crashdemo.cpp @ 124]
            如果minidump沒有包括目標(biāo)進(jìn)程內(nèi)存的完整內(nèi)容,那么只有當(dāng)調(diào)試器能正確發(fā)現(xiàn)被目標(biāo)進(jìn)程加載的、相同版本的可執(zhí)行模塊時,才能分析dump。在某些情形下,你必須幫助調(diào)試器定位這些模塊??通過指定模塊搜索路徑。關(guān)于模塊搜索路徑的詳細(xì)信息和相關(guān)內(nèi)容可以在這篇文章 中找到。

            現(xiàn)在,我們來處理不帶異常信息的故障轉(zhuǎn)儲。當(dāng)我們分析這樣的dump時,通常想知道所有線程的調(diào)用棧。下面是怎樣得到這些信息:
              cdb -z c:\myapp.dmp -logo out.txt -lines -c "~*kb;q"
            如果我們不知道故障轉(zhuǎn)儲是否包含異常信息,該怎么做呢?對于minidumps來說,我們可以用MiniDumpView 打印dump的內(nèi)容,查看它里面是否包含異常信息。對于過時的'full user dumps',或許唯一的選擇是,照現(xiàn)在的樣子啟動包含異常信息的dump,并查看!analyze是否報告了有意義的內(nèi)容。
            有一個有趣的特例??因?yàn)槲唇?jīng)處理的異常生成故障轉(zhuǎn)儲,但因?yàn)槟承┰驔]有包含異常信息是有可能的。在這種情形下,在下面過程的幫助下,仍可能找出異常發(fā)生的位置:
            1.  打印所有線程的調(diào)用棧(用前面提過的CDB命令)。
            2.  找出包含kernel32!UnhandledExceptionFilter函數(shù)調(diào)用棧的線程。
            3.  使用UnhandledExceptionFilter 函數(shù)的第一個參數(shù)(包含一個指向EXCEPTION_POINTERS 結(jié)構(gòu)的指針)的實(shí)際值。
            下面是EXCEPTION_POINTERS 結(jié)構(gòu)的聲明:
            typedef struct _EXCEPTION_POINTERS 
            {  
                PEXCEPTION_RECORD ExceptionRecord;  
                PCONTEXT ContextRecord;
            } EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
            如果我們知道這個結(jié)構(gòu)的地址,就能得到指向異常上下文的指針(保存在ContextRecord字段里),把它傳遞給.cxr命令,從而把調(diào)試器上下文切換到異常發(fā)生的位置。在.cxr命令執(zhí)行后,我們可以用'kb'命令得到異常發(fā)生時的調(diào)用棧。下面是一個例子:
            1.  打印所有線程的調(diào)用棧。
              cdb -z c:\myapp.dmp -logo out.txt -c "~*kb;q"
            0:000> ~*kb

            .  0  Id: 6c4.73c Suspend: 1 Teb: 7ffdf000 Unfrozen
            ChildEBP RetAddr  Args to Child              
            0012fdf8 7c90d85c 7c8023ed 00000000 0012fe2c ntdll!KiFastSystemCallRet
            0012fdfc 7c8023ed 00000000 0012fe2c 0012ff54 ntdll!NtDelayExecution+0xc
            0012fe54 7c802451 0036ee80 00000000 0012ff54 kernel32!SleepEx+0x61
            0012fe64 00430856 0036ee80 00330033 00300037 kernel32!Sleep+0xf
            0012ff54 00431702 00000001 00352ed0 00352fb0 CrashDemo!wmain+0x96
            0012ffb8 004314bd 0012fff0 7c816d4f 00330033 CrashDemo!__tmainCRTStartup+0x232
            0012ffc0 7c816d4f 00330033 00300037 7ffd9000 CrashDemo!wmainCRTStartup+0xd
            0012fff0 00000000 0042e5a5 00000000 00000000 kernel32!BaseProcessStart+0x23

               1  Id: 6c4.5cc Suspend: 1 Teb: 7ffde000 Unfrozen
            ChildEBP RetAddr  Args to Child              
            006af6e4 7c90e273 7c863130 d0000144 00000004 ntdll!KiFastSystemCallRet
            006af6e8 7c863130 d0000144 00000004 00000000 ntdll!NtRaiseHardError+0xc
            006af96c 00438951 006af9e0 5d343834 00000000 kernel32!UnhandledExceptionFilter+0x59c
            006af990 00430f2a c0000005 006af9e0 0044ad30 CrashDemo!_XcptFilter+0x61
            006af99c 0044ad30 00000000 00000000 00000000 CrashDemo!_callthreadstartex+0x7a
            006af9b0 00438c67 00430f13 0049a230 00000000 CrashDemo!_EH4_CallFilterFunc+0x12
            006af9e8 7c9037bf 006afad4 006aff98 006afaf0 CrashDemo!_except_handler4+0xb7
            006afa0c 7c90378b 006afad4 006aff98 006afaf0 ntdll!ExecuteHandler2+0x26
            006afabc 7c90eafa 00000000 006afaf0 006afad4 ntdll!ExecuteHandler+0x24
            006afabc 004309be 00000000 006afaf0 006afad4 ntdll!KiUserExceptionDispatcher+0xe
            006afe88 0043094e 00000000 00354130 00350001 CrashDemo!TestFunc+0x2e
            006aff6c 00430f01 00000000 647bff58 00354130 CrashDemo!WorkerThread+0x5e
            006affa8 00430e72 00000000 006affec 7c80b50b CrashDemo!_callthreadstartex+0x51
            006affb4 7c80b50b 00355188 00354130 00350001 CrashDemo!_threadstartex+0xa2
            006affec 00000000 00430dd0 00355188 00000000 kernel32!BaseThreadStart+0x37
            2.  改變調(diào)試器的上下文,得到異常的調(diào)用棧。
              cdb -z c:\myapp.dmp -logo out.txt -lines -c ".cxr dwo(0x006af9e0+4);kb;q"
            ('dwo'操作符返回保存在指定地址里的double word,并把它傳遞給.cxr命令)
            本篇文章后面提供的批處理文件(實(shí)際上是DumpStackCtx.bat)將簡化這個任務(wù)。
            還有另外的方法可以解決這個問題??你可以在這里 找到更多的信息。

            分析虛擬內(nèi)存
            當(dāng)我們想審查被調(diào)試進(jìn)程的虛擬內(nèi)存布局時,CDB可以協(xié)助Visual Studio調(diào)試器。下面的命令顯示進(jìn)程完整的虛擬內(nèi)存映射:
              cdb -pv -pn myapp.exe -logo out.txt -c "!vadump -v;q"
            (!vadump命令負(fù)責(zé)打印虛擬內(nèi)存映射,照常,用-v選項(xiàng)要求它顯示詳細(xì)的內(nèi)容)
            下面是!vadump輸出的例子:
            BaseAddress:       00040000
            AllocationBase:    00040000
            AllocationProtect: 00000004  PAGE_READWRITE
            RegionSize:        0002e000
            State:             00002000  MEM_RESERVE
            Type:              00020000  MEM_PRIVATE

            BaseAddress:       0006e000
            AllocationBase:    00040000
            AllocationProtect: 00000004  PAGE_READWRITE
            RegionSize:        00001000
            State:             00001000  MEM_COMMIT
            Protect:           00000104  PAGE_READWRITE + PAGE_GUARD
            Type:              00020000  MEM_PRIVATE

            BaseAddress:       0006f000
            AllocationBase:    00040000
            AllocationProtect: 00000004  PAGE_READWRITE
            RegionSize:        00011000
            State:             00001000  MEM_COMMIT
            Protect:           00000004  PAGE_READWRITE
            Type:              00020000  MEM_PRIVATE
            在Windows XP和Windows Server 2003上,CDB為審查虛擬內(nèi)存布局提供了一條更好的命令??!address。這條命令可以完成下面的任務(wù):
            •  顯示進(jìn)程的虛擬內(nèi)存映射(依我之見,比!vadump的輸出內(nèi)容更易閱讀)
            •  顯示有用的、虛擬內(nèi)存使用的統(tǒng)計(jì)數(shù)據(jù)
            •  確定指定的地址屬于哪種虛擬內(nèi)存區(qū)域(例如,它是屬于棧,堆,還是可執(zhí)行映象?)
            下面是怎樣用!address報告虛擬內(nèi)存映射的示例:
              cdb -pv -pn myapp.exe -logo out.txt -c "!address;q"
            下面顯示被線程的棧占用的內(nèi)存區(qū)域:
                00040000 : 00040000 - 0002e000
                                Type     00020000 MEM_PRIVATE
                                Protect  00000000 
                                State    00002000 MEM_RESERVE
                                Usage    RegionUsageStack
                                Pid.Tid  658.644
                           0006e000 - 00001000
                                Type     00020000 MEM_PRIVATE
                                Protect  00000104 PAGE_READWRITE | PAGE_GUARD
                                State    00001000 MEM_COMMIT
                                Usage    RegionUsageStack
                                Pid.Tid  658.644
                           0006f000 - 00011000
                                Type     00020000 MEM_PRIVATE
                                Protect  00000004 PAGE_READWRITE
                                State    00001000 MEM_COMMIT
                                Usage    RegionUsageStack
                                Pid.Tid  658.644
            注意,!address非常智能,可以報告屬于棧的線程的線程ID。
            在!address報告虛擬內(nèi)存區(qū)域之后,它也能報告有趣的、虛擬內(nèi)存使用的統(tǒng)計(jì)數(shù)據(jù):
            -------------------- Usage SUMMARY --------------------------
                TotSize   Pct(Tots) Pct(Busy)   Usage
               00838000 : 0.40%       27.96%      : RegionUsageIsVAD
               7e28c000 : 98.56%      0.00%       : RegionUsageFree
               01348000 : 0.94%       65.60%      : RegionUsageImage
               00040000 : 0.01%       0.85%       : RegionUsageStack
               00001000 : 0.00%       0.01%       : RegionUsageTeb
               001a0000 : 0.08%       5.53%       : RegionUsageHeap
               00000000 : 0.00%       0.00%       : RegionUsagePageHeap
               00001000 : 0.00%       0.01%       : RegionUsagePeb
               00001000 : 0.00%       0.01%       : RegionUsageProcessParametrs
               00001000 : 0.00%       0.01%       : RegionUsageEnvironmentBlock
                   Tot: 7fff0000 Busy: 01d64000

            -------------------- Type SUMMARY --------------------------
                TotSize   Pct(Tots) Usage
               7e28c000 : 98.56%     : <free>
               01348000 : 0.94%      : MEM_IMAGE
               007b6000 : 0.38%      : MEM_MAPPED
               00266000 : 0.12%      : MEM_PRIVATE

            -------------------- State SUMMARY --------------------------
                TotSize   Pct(Tots) Usage
               01647000 : 1.09%      : MEM_COMMIT
               7e28c000 : 98.56%     : MEM_FREE
               0071d000 : 0.35%      : MEM_RESERVE

            Largest free region: Base 01014000 - Size 59d5c000
            當(dāng)我們正在調(diào)試內(nèi)存泄露,以及想確定內(nèi)存泄露的類型(堆,棧,原始的虛擬內(nèi)存,等等)時,這些統(tǒng)計(jì)數(shù)據(jù)非常有用。通過最后一行,我們可以確定虛擬內(nèi)存中最大的空閑區(qū)域的大小,這在我們必須設(shè)計(jì)請求大量內(nèi)存的應(yīng)用程序時非常有幫助。
            如果你只想查看統(tǒng)計(jì)數(shù)據(jù),而不想看虛擬內(nèi)存映射,可以用-summary參數(shù):
              cdb -pv -pn myapp.exe -logo out.txt -c "!address -summary;q"
            如果我們想確定給定地址的虛擬內(nèi)存屬于哪種類型,可以把這個地址作為參數(shù)傳遞給!address命令。下面是一個例子:
            0:000> !address 0x000a2480;q
                000a0000 : 000a0000 - 000d7000
                                Type     00020000 MEM_PRIVATE
                                Protect  00000004 PAGE_READWRITE
                                State    00001000 MEM_COMMIT
                                Usage    RegionUsageHeap
                                Handle   000a0000

            搜索符號
            有時候,我們可能需要確定符號(函數(shù)或變量)的地址。如果我們知道準(zhǔn)確的符號名,可以把它輸入Visual Studio調(diào)試器的反匯編窗口,從中找出它對應(yīng)的地址。但是,假設(shè)我們忘了準(zhǔn)確的符號名呢?或者想找出名字上有相同規(guī)律的、一組符號的地址(例如,類的所有成員函數(shù))?CDB很容易解決這個問題??它提供'x'命令,可以列出匹配指定掩碼的所有符號名:
              x Module!Symbol
            下面的命令設(shè)法定位位于kernel32.dll 中的UnhandledExceptionFilter函數(shù)的地址:
              cdb -pv -pn notepad.exe -logo out.txt -c "x kernel32!UnhandledExceptionFilter;q"
            下面是輸出內(nèi)容:
            0:000> x kernel32!UnhandledExceptionFilter;q
            7c862b8a kernel32!UnhandledExceptionFilter = <no type information>
            'x'命令可以接受多個通配符,提供一些有用的選項(xiàng),可用于排序輸出內(nèi)容以及輸出符號的額外信息??你可以在WinDbg文檔里找到更多的信息。例如,下面的命令可以把我們在應(yīng)用程序的主可執(zhí)行模塊中定義的CmainFrame類所有的成員函數(shù)和統(tǒng)計(jì)數(shù)據(jù)列出來:
            0:000> x myapp!*CMainFrame*
            004542f8 MyApp!CMainFrame::classCMainFrame = struct CRuntimeClass
            00401100 MyApp!CMainFrame::`scalar deleting destructor' (void)
            004011a0 MyApp!CMainFrame::OnCreate (struct tagCREATESTRUCTW *)
            00401000 MyApp!CMainFrame::CreateObject (void)
            00401280 MyApp!CMainFrame::PreCreateWindow (struct tagCREATESTRUCTW *)
            00401070 MyApp!CMainFrame::GetRuntimeClass (void)
            00401120 MyApp!CMainFrame::~CMainFrame (void)
            00401090 MyApp!CMainFrame::CMainFrame (void)
            00401080 MyApp!CMainFrame::GetMessageMap (void)
            004578ec MyApp!CMainFrame::`RTTI Base Class Array' = <no type information>
            004578dc MyApp!CMainFrame::`RTTI Class Hierarchy Descriptor' = <no type information>
            004578c8 MyApp!CMainFrame::`RTTI Complete Object Locator' = <no type information>
            004579ec MyApp!CMainFrame::`RTTI Base Class Descriptor at (0,-1,0,64)' = <no type information>
            00461e94 MyApp!CMainFrame `RTTI Type Descriptor' = <no type information>
            00454354 MyApp!CMainFrame::`vftable' = <no type information>
            CDB也可以反著做??通過地址找符號,使用'ln'命令:
              ln Address
            下面是它的用法:
              cdb -pv -pn notepad.exe -logo out.txt -c "ln 0x77d491c8;q"
            下面是它的輸出內(nèi)容:
            0:000> ln 0x77d491c8;q
            (77d491c6)   USER32!GetMessageW+0x2   |  (77d49216)   USER32!CharUpperBuffW
            注意,我們不必指定符號的起始地址(在這個例子里,是函數(shù)),而可以用符號占用的地址范圍內(nèi)的任何地址。'ln'將找出符號,報告它的地址,另外還報告跟在指定內(nèi)容后面的地址和符號名。

            顯示數(shù)據(jù)結(jié)構(gòu)
            如果我們想研究數(shù)據(jù)結(jié)構(gòu)的內(nèi)容,通常會用Visual Studio的Watch,QuickWatch或其它類似的窗口。這些窗口允許我們查看結(jié)構(gòu)成員變量的類型和值。但是假設(shè)我們也需要知道結(jié)構(gòu)的精確布局,包括它的成員的偏移量?Visual Studio不提供易用的解決方法,但幸運(yùn)的是,CDB可以。在'dt'命令的幫助下,我們可以顯示數(shù)據(jù)結(jié)構(gòu)或類的精確布局。
            如果我們只想了解數(shù)據(jù)類型的布局,可以用下面這條命令:
              dt -b TypeName
            (-b選項(xiàng)啟用遞歸顯示,顯示結(jié)構(gòu)或類的成員類型的嵌入式數(shù)據(jù)結(jié)構(gòu))。
            下面是命令的示例:
              cdb -pv -pn myapp.exe -logo out.txt -c "dt -b CSymbolInfoPackage;q"
            下面是輸出內(nèi)容(在運(yùn)行SymFromAddr 應(yīng)用程序時得到的):
            0:000> dt /b CSymbolInfoPackage;q
               +0x000 si               : _SYMBOL_INFO
                  +0x000 SizeOfStruct     : Uint4B
                  +0x004 TypeIndex        : Uint4B
                  +0x008 Reserved         : Uint8B
                  +0x018 Index            : Uint4B
                  +0x01c Size             : Uint4B
                  +0x020 ModBase          : Uint8B
                  +0x028 Flags            : Uint4B
                  +0x030 Value            : Uint8B
                  +0x038 Address          : Uint8B
                  +0x040 Register         : Uint4B
                  +0x044 Scope            : Uint4B
                  +0x048 Tag              : Uint4B
                  +0x04c NameLen          : Uint4B
                  +0x050 MaxNameLen       : Uint4B
                  +0x054 Name             : Char
               +0x058 name             : Char
            如果你想顯示特殊變量的布局,可以把它的地址傳遞給'dt'命令:
              dt -b TypeName Address
            下面是例子:
              cdb -pv -pn myapp.exe -logo out.txt -c "dt -b CSymbolInfoPackage 0x0012f6d0;q"
            0:000> dt /b CSymbolInfoPackage 0x0012f6d0;q
               +0x000 si               : _SYMBOL_INFO
                  +0x000 SizeOfStruct     : 0x58
                  +0x004 TypeIndex        : 2
                  +0x008 Reserved         : 
                   [00] 0
                   [01] 0
                  +0x018 Index            : 1
                  +0x01c Size             : 0x428
                  +0x020 ModBase          : 0x400000
                  +0x028 Flags            : 0
                  +0x030 Value            : 0
                  +0x038 Address          : 0x411d30
                  +0x040 Register         : 0
                  +0x044 Scope            : 0
                  +0x048 Tag              : 5
                  +0x04c NameLen          : 0xe
                  +0x050 MaxNameLen       : 0x7d1
                  +0x054 Name             :  "S"
                   [00] 83 'S'
               +0x058 name             :  "SymbolInfo"
                [00] 83 'S'
                [01] 121 'y'
                [02] 109 'm'
                [03] 98 'b'
                [04] 111 'o'
                [05] 108 'l'
                [06] 73 'I'
                [07] 110 'n'
                [08] 102 'f'
                [09] 111 'o'
                [10] 0 ''
                [11] 0 ''
                [12] 0 ''
                [13] 0 ''
                [14] 0 ''
                [15] 0 ''
                [16] 0 ''
                [17] 0 ''
                ... 省略部分輸出內(nèi)容
                [1990] 0 ''
                [1991] 0 ''
                [1992] 0 ''
                [1993] 0 ''
                [1994] 0 ''
                [1995] 0 ''
                [1996] 0 ''
                [1997] -52 ''
                [1998] -52 ''
                [1999] -52 ''
                [2000] -52 ''
            注意,'dt'也顯示結(jié)構(gòu)成員變量的值。

            批處理文件
            我們已經(jīng)知道怎樣用CDB解決一些有趣的調(diào)試問題了。現(xiàn)在可以用它解決更多的問題了??用易用的批處理文件代替難記的CDB命令行。考慮我們在本文開始部分使用的命令行示例:
              cdb -pv -pn myapp.exe -logo out.txt -c "lm;q"
            這條命令中的大部分是固定的,用不著改變。唯一可變的部分是目標(biāo)信息(-pn myapp.exe),我們可能會用另外的可執(zhí)行文件名,或另外的附著方式(例如,通過進(jìn)程ID)替換它。
            下面介紹了怎樣用批處理文件代替這條命令:
              ; lm.bat
              cdb -pv %1 %2 -logo out.txt -c "lm;q"
            如果我們運(yùn)行這個批處理文件,通過進(jìn)程來得到已加載模塊的列表,可以用下面的方法:
            通過可執(zhí)行文件名附上進(jìn)程:
              lm -pn myapp.exe
            通過進(jìn)程ID附上進(jìn)程:
              lm -p 1234
            通過服務(wù)名附上進(jìn)程:
              lm -psn MyService
            打開故障轉(zhuǎn)儲文件:
              lm -z c:\myapp.dmp
            這條命令與具體的目標(biāo)無關(guān),只做同樣的事情??打印已加載模塊的列表。
            如果我們想為CDB命令指定另外的參數(shù),我們可以用同樣的方法。考慮下面用于顯示數(shù)據(jù)結(jié)構(gòu)布局的命令:
              cdb -pv -pn myapp.exe -logo out.txt -c "dt /b MyStruct;q"
            當(dāng)然,我們可能想使用任何數(shù)據(jù)類型運(yùn)行這條命令,而不僅僅是MyStruct。下面是怎樣做的示例:
              ; dt.bat
              cdb -pv %1 %2 -logo out.txt -c "dt /b %3;q"
            現(xiàn)在,我們可以象下面這樣運(yùn)行這條命令:
              dt -pn myapp.exe CTestClass
            或者象這樣:
              dt -p 1234 SYMBOL_INFO
            或者,也可以象這樣:
              dt -z c:\myapp.dmp EXCEPTION_POINTERS
            我們可以用同樣的方法處理其它的命令。你可以從這里 找到本文曾討論過的批處理文件。在以后,我準(zhǔn)備用另外有用的命令擴(kuò)充它。

            posted on 2009-07-09 13:26 yanghaibao 閱讀(409) 評論(0)  編輯 收藏 引用

            導(dǎo)航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統(tǒng)計(jì)

            常用鏈接

            留言簿

            隨筆分類

            隨筆檔案

            文章檔案

            收藏夾

            Good blogs

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            亚洲精品无码久久久久去q | 久久99热这里只有精品国产 | 久久男人AV资源网站| 久久久久18| 久久久久高潮综合影院| 精品久久久久中文字幕日本| 亚洲精品高清久久| 国产精品久久久香蕉| 国内精品久久久久久久97牛牛| 久久久久国产精品人妻| 97久久国产综合精品女不卡| 中文精品久久久久国产网址| 久久午夜电影网| 人妻精品久久无码区| 久久久久亚洲AV成人网人人网站 | 精品久久久久久综合日本| 亚洲欧洲精品成人久久奇米网| 国产精品9999久久久久| 国产精品99精品久久免费| 久久亚洲国产中v天仙www| 精品久久久久久久中文字幕| 人人狠狠综合久久亚洲| 久久精品一区二区国产| 国产精品青草久久久久福利99| 久久亚洲精品成人AV| 久久国产精品一区二区| 久久人人爽人人爽人人片AV麻豆| 欧美精品国产综合久久| 国产精品美女久久久久网| 久久国产免费直播| 色综合久久综精品| 伊人色综合九久久天天蜜桃| 亚洲AV无码久久| 色综合合久久天天综合绕视看| 免费精品国产日韩热久久| 久久夜色精品国产亚洲av| 久久久无码精品亚洲日韩按摩 | 久久久99精品成人片中文字幕| 亚洲国产另类久久久精品| 久久精品国产精品亚洲艾草网美妙 | 久久99精品久久久久久动态图|