#工作空間 [Workspace]
工作空間被用來描述和存儲一個調試項目的屬性、參數以及調試器設置等信息,其功能類似於集成開發環境的項目文件。
具體包括:調試會話狀態(斷點、打開的源文件、用戶定義的別名等)、調試器設置(符號文件路徑、源文件路徑、可執行映像文件路徑等)和窗口布局狀態。
0. 基礎工作空間 [base workspace]
未載入任何的調試文件時使用默認的啟動環境。存放位置:HKEY_CURRENT_USER\Software\Microsoft\Windbg\Workspaces下Default二進制值。
1. User、Kernel、Dump、Explicit工作空間
存放在HKEY_CURRENT_USER\Software\Microsoft\Windbg\Workspaces的各子鍵中(如下圖)
子鍵User、Kernel、Dump用來保存用戶態調試、內核態調試、調試轉儲文件時,使用【Save Workspace】方式時默認的保存路徑。
子鍵Explicit則用來記錄使用【Save Workspace as】方式保存的命名工作空間。
對於【Attach to a Process】的方式,會使用User下的Default二進制值作為其工作空間,之后對工作空間所作的修改也會寫到該字段中。
注:有時會發現沒有某個子鍵,這是因為windbg還沒使用過該調試方式。
2. 其他說明
(1) windbg還提供另外一種保存方式【Save WorkSpace to File】,作用跟上面兩種的方式差不多,
只不過把工作空間以文件的形式保存到磁盤里,那么用戶就可以通過U盤或其它方式把工作空間的環境移植到其它機器上使用。
(2) 調試目標最后的工作空間為:基礎工作空間與其對應工作空間的求並所得的環境。
(3) 用windbg打開目標可執行文件【Open Executable】,若有默認的工作空間文件(在子鍵User下),會自動打開其對應默認的的工作空間文件。
要使用子鍵Explicit下目標文件的工作空間,必須先提前【Open WorkSpace】,然后再打開目標可執行文件。
(4) 在載入調試目標后改變了工作空間並保存,並不改變windbg的基礎工作空間,只改變調試目標對應的工作空間;
而只有在windbg還沒載入任何調試目標時改變並保存才會影響基礎工作空間。
#符號 [Symbol]
調試者接觸的二進制數據以及匯編代碼,如果沒有符號表文件的幫助,就無法知道這些數據代表什么變量、函數。
符號(symbol) :函數和變量的別名,編譯器通過符號修飾(Name Decoration)和 函數簽名(Function Signature)來實現全局唯一性。
函數符號含有返回值,函數名,函數參數等函數所有信息;變量符號含有類型和名稱信息。
通過不同的編譯選項,編譯器可以生成兩種截然不同的信息集合:私有符號(private symbol)和公有符號(public symbol)。
私有符號(private symbol)包含完整的調試信息,編譯選項:/Zi或/ZI。
公共函數和變量:在多個的編譯單元(源代碼文件)中可見的函數和變量。
私有函數和變量:用於描述除公共函數和變量以外的所有函數和變量,包括靜態函數、靜態和局部變量、函數參數)。
因此,為了能更方便讀懂二進制數據和匯編語言,需要獲取符號表文件,在windbg下使用的符號表文件一般是.PDB文件。
客戶端軟件存在於exe/dll中,這些二進制文件會調用操作系統的dll,這兩部分二進制文件的符號表文件都需要獲取。
客戶端軟件自己的符號表文件在構建程序的過程中產生;而操作系統dll的符號表文件可以通過設置windbg,根據需要自動從微軟符號服務器上下載。
#pdb(program Database )
0. pdb中包含的內容
符號表 |
函數和變量符號到地址的映射表(map文件實際就是一個文本格式的符號表)。 |
源文件和代碼行信息 |
二進制指令到代碼源文件代碼行的映射表。 |
類型信息 |
用於存儲每一個函數和變量的類型信息。對於變量或函數參數,類型信息能夠告訴調試器是整型還是字符串類型,或是用戶自定義類型。 對於函數,類型信息記載了參數的個數、調用轉換和返回值的類型。 |
FPO(frame pointer omission, 幀指針省略)
|
對於做了FPO優化的函數,FPO信息保存了一些數據來幫助調試器確定函數堆棧幀的大小, 幫助調試器查找函數的參數和本地變量,甚至在幀指針無效時也能工作。 如果沒有FPO信息,調試器無法正確顯示被優化的程序的調用堆棧。 |
編輯和繼續執行信息 |
用於幫助Visual Studio在調試時實現編輯和繼續執行的功能 |
在過去的十年中,微軟使用了幾種不同的格式(COFF、CodeView和應用的最廣泛的PDB格式)來存放調試信息。
格式 |
是否有文檔 |
存儲 |
公共函數和變量 |
私有函數和變量 |
源文件和代碼行信息 |
類型信息 |
FPO信息 |
編輯和繼續執行信息 |
COFF |
有 |
可執行文件中 |
+ |
- |
+ |
- |
+ |
- |
CodeView |
部分 |
可執行文件中 或.DBG文件中 |
+ |
+ |
+ |
+ |
+ |
- |
Program Database |
微軟沒有提供程序數據庫格式的文檔,只提供特殊的編程接口DbgHelp 和DIA來訪問它。 |
.PDB文件中 |
+ |
+ |
+ |
+ |
+ |
+ |
1. 在vc6下配置生成PDB文件
vc6的Debug配置,會在編譯時生成私有符號pdb文件;Release可通過如下配置來達到這一目的:
(1) 選擇Project->Setting菜單,打開工程設置對話框
(2) 在“Setting For:” 中選擇 “Win32 Release”(只設置Release版本即可,因為Debug版本默認生成PDB文件)
(3) 選擇標簽頁 “C/C++” ,在 “Debug info” 中選擇 “Line Numbers Only”(如果選擇Program Database則包含更多的符號信息)
(4) 選擇標簽頁 “Link” ,勾選 “Generate debug info”
(5) 在標簽頁 “Link” 中,選擇 “Category->Customize”,在這里填寫PDB文件的生成路徑
注:無論是Debug還是Release配置,VC6.0的Link選項需要將/pdbtype:sept改為/pdbtype:con, 否則生成的pdb文件中將不包含如自定義結構體,類等信息
更多關於vc6和vs的pdb編譯和鏈接選項信息,請參考:Windows程序調試系列: 使用VC++生成調試信息
2. 為vs下Release配置生成PDB文件
(1) 配置C/C++ >General>Debug Information Format 為 “Program Database(/Zi)”
(2) 配置C/C++ >Optimization>Optimization 為”Disabld(/Od)”
(3) 配置Linker>Debugging>Generate Debug Info 為”Yes/(DEBUG)”
3.在windbg下使用PDB文件
啟動windbg后,選擇 【Symbol File Path】,彈出 “Symbol Search Path” 對話框,輸入存放PDB文件的路徑。可以輸入多個路徑,路徑之間使用分號進行分隔。
如果此時正在調試程序,則對話框中的 “reload” 選擇框是可以選擇的,勾選后點擊“確定”。
4.使用Windows符號表服務器
為了方便調試,需要獲取Windows系統DLL的符號表文件。微軟公司提供了可以通過Internet訪問的符號表服務器。
經過設置,在調試過程中,windbg調試器會從符號表服務器自動下載調試所需的PDB文件,非常方便。
設置方法: 在 【Symbol Search Path】 對話框中加入下面的路徑:srv*D:\SystemSymbols*http://msdl.microsoft.com/download/symbols
其中: D:\SystemSymbols為存放符號的下載目錄
注1:48C58F3D11e000為對應版本dbghelp.dll的PE頭中記錄的時間日期戳和映像大小的組合(字節數)
timestamp與日期時間的在線轉換工具:http://tool.chinaz.com/Tools/unixtime.aspx
注2:6B19F261EE434AF59623D1791CE5A7D72為對應版本dbghelp.pdb的guid
另外,也可以使用windbg提供的symchk.exe工具提前下載某個dll及某個目錄下所有dll的pdb文件到本地
"C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" c:\windows\system32\user32.dll /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols //下載user32.dll的pdb到c:\symbols目錄中 "C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" c:\windows\system32\ /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols //下載system32下所有dll的pdb到c:\symbols目錄中 "C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" /r c:\windows\system32\ /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols //遞歸子目錄下載system32下所有dll的pdb到c:\symbols目錄中
5. 設置_NT_SYMBOL_PATH環境變量
設置系統環境變量“_NT_SYMBOL_PATH”,Visual Studio、windbg、SysinternalsSuite工具集的ProcessExplorer、ProcessMonitor等都會將該環境變量下的路徑添加到自己的Symbol File Path中
6.建立自己的符號表服務器
通過為產品建立自己的符號表服務器,就不需要關心復雜的版本問題。在調試過程中,windbg可以根據二進制文件(exe/dll)的哈希值,在符號表服務器上自動查找正確版本的PDB。
(1)建立一個共享文件夾,比如 “ \\server\symbols” ,然后將所有的PDB文件上傳到此處
(2)使用下面的命令上傳符號表文件
symstore add /r /f D:\MyOutput\chess.exe /s \\server\symbols /t "chess" /v "exe" /c "version build"
symstore add /r /f D:\MyOutput\chess.pdb /s \\server\symbols /t "chess" /v "pdb" /c "version build"
symstore add /r /f D:\MyOutput\chess.map /s \\server\symbols /t "chess" /v "map" /c "version build"
symstore 是windbg附帶的一個exe文件,存放於windbg安裝目錄下。需包含2個文件:symstore.exe、symsrv.dll
上述命令完成的功能是:將D:\MyOutput目錄下的chess.exe、chess.pdb、chess.map上傳到\\server\symbols目錄中。
產品的名稱是"chess",版本信息是"exe"、"pdb"、"map",備注說明是"version build"。
(3)在windbg的 【Symbol Search Path】對話框中添加新的路徑(路徑之間使用分號[;]分隔)\\server\symbols(關聯一個本地緩存目錄)
srv*D:\SystemSymbols*http://msdl.microsoft.com/download/symbols;srv*D:\ServerSymbols*\\server\symbols;f:\symbols
7. 查找函數符號名 -- 列出含CreateThread字樣的符號名
"D:\Program Files (x86)\windbg\dbh.exe" -s:srv*D:\Symbols\ms*http://msdl.microsoft.com/Download/Symbols -d C:\Windows\SysWOW64\kernel32.dll enum *CreateThread*
#使用windbg
0. Attach方式
啟動windbg,使用菜單【Attach to a Process】,可以選擇注入到現在正在運行的某個進程中。
注入到進程中后,進程被暫停執行,windbg處於可輸入命令狀態,但此時當前線程為windbg產生的線程。
按g繼續運行進程時,windbg會隨即銷毀該線程。
如果要觀察主線程堆棧,需要切換到主線程(0號線程)(在windbg命令窗口輸入這個命令,然后回車):
~0s
當程序出現CPU占用100%的情況時,通常可以使用這種方式進行注入,然后切換到占用CPU的線程,
同時根據需要使用單步跟蹤、設置斷點等手段,來判斷是何處的代碼導致CPU100%問題。
1. Open Executable方式
使用【Open Executable】方式,可以通過windbg啟動被調試程序。在這種方式下,被調試程序從啟動時刻起就在調試器的監控之下。
對於一些在程序啟動過程中產生的異常,可以使用這種方式進行調試。
2. Just in time Debugger 方式 (JIT)
當進程產生結構化異常時,如果進程不作處理,也沒有調試器在監控這個進程,那么windows就會調用默認的調試器來調試發生異常的進程。
通過把windbg設置為Just in time Debugger,可以在任意進程發生異常時自動調用windbg來進行調試。
在注冊表編輯器中修改下面的注冊表項:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug // 注:64位系統上的32位程序使用該注冊表項
Debugger鍵值修改為下面的取值 "D:\Tools\windbg.exe " -p %ld -e %ld
注1:將例中windbg.exe的路徑替換為本機windbg絕對路徑即可
注2:一般該值為:"C:\Windows\system32\vsjitdebugger.exe" -p %ld -e %ld
3. Dump文件
為了分析程序發生異常的原因,還可以借助Dump文件。
當異常發生時,把進程當前的信息保存到一個Dump文件中,再把該Dump文件發送給分析者,由分析者通過windbg進行分析。
Dump分類:
內核dump:(藍屏后,由系統生成)
1. 完全內存轉儲。這個文件比較大,和物理內存相當,包含了程序崩潰前系統及用戶模式下的所有信息。
2. 核心內存轉儲。這個文件大小約物理內存的三分之一,主要包含崩潰前系統內核的所有信息。一般為了分析內核錯誤,就選用這種文件。
3. 小內存轉儲(MiniDump)。保存內存前64KB的基本空間數據,主要包含crash進程及crash線程內核上下文信息,crash線程內核模式堆棧,加載的驅動和模塊等信息。
如果沒有禁用“Windows Error Reporting Service”服務,重啟后會彈出如下對話框來顯示一些藍屏相關的信息:
問題簽名: 問題事件名稱: BlueScreen OS 版本: 6.1.7601.2.1.0.256.48 區域設置 ID: 2052 有關該問題的其他信息: BCCode: 1000007e BCP1: FFFFFFFFC0000005 BCP2: FFFFF80004CCC0E4 BCP3: FFFFF88004993668 BCP4: FFFFF88004992EC0 OS Version: 6_1_7601 Service Pack: 1_0 Product: 256_1 有助於描述該問題的文件: C:\Windows\Minidump\060717-10280-01.dmp C:\Users\nicochen\AppData\Local\Temp\WER-41964-0.sysdata.xml 聯機閱讀隱私聲明: http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0804 如果無法獲取聯機隱私聲明,請脫機閱讀我們的隱私聲明: C:\Windows\system32\zh-CN\erofflps.txt
事件查看器中也記錄了那次致命錯誤
不同信息量的minidump:
(1)標准的minidump。包含了相對比較少的信息,適合在做在線分析:系統信息、加載的模塊(DLL)信息、進程信息和線程信息。
.dump /m c:\stardardMini.dmp(注:不指定/m和/f,/m為缺省選項)
(2) full dump。在內核模式下,生成完全內存轉儲;用戶模式下,最好不使用(/ma和/mf是更好的選擇,生成出的dump信息也更豐富一些)
.dump /f c:\fullMini.dmp
(3)帶有盡量多選項的minidump。包括完整的內存內容、句柄、未加載的模塊,等等。文件很大(本機和局域網環境適用)~
.dump /ma c:\bigMini.dmp(注:/ma等價於/mfFhut;/m的子參數包括:a,A,f,F,h,u,t,i,p,w,d,c,r,R ).dump命令詳細用法
下面列出六種生成Dump文件的方法:
(1)在產品代碼中加入自動生成Dump文件功能
使用下面的函數,可以生成一個Dump文件:
BOOL MiniDumpWriteDump (
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
這個函數定義在dbghelp.dll中,windbg安裝目錄中帶有這個dll,同時在sdk子目錄中提供了.h和.lib文件。
在進程捕捉結構化異常的地方,使用這個API生成一個Dump文件。
(2) 使用AdPlus生成Dump文件
windbg附帶了一個AdPlus的腳本,可以用於監控進程運行情況,並且可以在發生異常時把進程信息寫入到Dump文件中。
如果產品沒有自動生成Dump文件的功能,可以通過使用這個工具來彌補缺陷。
通過如下命令來使用AdPlus:
cscript D:\tools\windbg\adplus.vbs -crash -pn DebugTest.exe -o D:\CrashDumps
上述命令的意思是:監控當前運行的DebugTest.exe,如果發生了結構化異常,則生成一個Dump文件到D:\CrashDumps目錄中。
關於AdPlus更詳細的介紹請參閱:http://support.microsoft.com/kb/286350/zh-cn
(3) 使用windbg生成Dump文件
windbg可以通過命令生成mini-Dump文件:
.dump /mfh D:\CrashDumps\mydumpfile.dmp
(4) win7任務管理器 - 進程標簽頁 - 創建轉儲文件
(5) 使用vs2010以上版本生成 在調試狀態下[菜單]:調試 - 將轉儲另存為
(6) 第三方系統工具 如:最新版本的Process Explorer、proccump.exe命令行工具等
注意:
win32程序在64位操作系統上,需要生成dump時,應該生成32位的dump,否則windbg在獲取call stack時可能出錯,一些sos、psscor2等擴展無法讀取dump中的數據,一些命令在獲取dump中的信息也會受限。
對於32位dump,應該用x86版的windbg分析(無論是在32位還是64位操作系統上);64位dump,應該用在64位操作系統上使用x64版的windbg進行分析。
分析Dump文件
使用菜單【Open Crash Dump】打開Dump文件,然后打開堆棧觀察窗口,此時看到的堆棧可能不是異常發生時的堆棧。
通過如下命令切換到異常發生時的堆棧:
.ecxr
為了分析異常,可以通過下面的語句來獲取分析信息,幫助定位問題:
!analyze -v
#參考
http://www.debuginfo.com/resources.html
http://www.debuginfo.com/articles/debuginfomatch.html
http://www.debuginfo.com/articles/gendebuginfo.html
DbgHelp Functions: http://msdn.microsoft.com/en-us/library/ms679291(VS.85).aspx