使用 WinDbg 還原 dmp 文件

一、前言

編程開發(fā)過程中難免遇到程序崩潰,本文主要說明怎么通過 WinDbg 工具來還原 dmp 文件,幫助大家快速定位問題原因。

新人一枚,僅記錄分享還原過程~ ??


二、WinDbg 的安裝與配置

2.1 下載 WinDbg

  1. 方式一:Windows SDK(傳統(tǒng)版)
    • 下載地址

    • 安裝時(shí)只勾選 "Debugging Tools for Windows"
  • 完整細(xì)節(jié),請(qǐng)點(diǎn)擊 這里
  1. 方式二:WinDbg Preview(新版,推薦)
    • 通過 Microsoft Store 安裝
    • 界面更現(xiàn)代,功能更完善

2.2 符號(hào)文件(Symbol)配置

1. 什么是符號(hào)文件(.pdb)

PDB(Program Database)文件是微軟定義的一種文件格式,用于存儲(chǔ)程序編譯時(shí)產(chǎn)生的調(diào)試信息。它是連接"二進(jìn)制可執(zhí)行文件"和"源代碼"之間的橋梁。

符號(hào)文件包含以下關(guān)鍵信息:

信息類型 說明
函數(shù)名稱 函數(shù)的原始名稱(而非編譯后的地址)
變量名稱 全局變量、局部變量、參數(shù)的名稱
類型信息 結(jié)構(gòu)體、類、枚舉的定義
源文件路徑 源代碼文件的路徑信息
行號(hào)映射 二進(jìn)制指令地址與源代碼行號(hào)的對(duì)應(yīng)關(guān)系

簡(jiǎn)單類比:符號(hào)文件就像一本"翻譯詞典",告訴調(diào)試器內(nèi)存地址 0x00401000 對(duì)應(yīng)的是哪個(gè)函數(shù)、哪一行代碼。


2. 為什么需要符號(hào)文件

沒有符號(hào)文件時(shí),調(diào)用棧顯示:

0012f8fc 004015a8 MyApp+0x1234        ← 只有模塊名+偏移,無法知道具體函數(shù)
0012f920 00401bc0 MyApp+0x15a8       
0012f944 00401ff4 MyApp+0x1bc0

加載符號(hào)文件后,調(diào)用棧變成:

0012f8fc 004015a8 MyApp!CUserManager::Login+0x56 [d:\src\usermanager.cpp @ 128]
0012f920 00401bc0 MyApp!CNetworkService::HandleRequest+0x78 [d:\src\network.cpp @ 256]
0012f944 00401ff4 MyApp!main+0x120 [d:\src\main.cpp @ 45]
對(duì)比項(xiàng) 無符號(hào)文件 有符號(hào)文件
函數(shù)定位 只有內(nèi)存地址 完整函數(shù)名
代碼行號(hào) 精確到行
變量查看 只有內(nèi)存值 變量名 + 類型 + 值
排查效率 低(可能需要數(shù)小時(shí)) 高(可能幾分鐘)

3. 配置微軟公共符號(hào)服務(wù)器

微軟提供了公共符號(hào)服務(wù)器,包含 Windows 系統(tǒng)組件(如 kernel32.dll、ntdll.dll)的符號(hào)文件。

方法一:在 WinDbg 中配置

WinDbg Preview(新版):

  1. 打開 WinDbg Preview
  2. 點(diǎn)擊菜單 Settings(設(shè)置圖標(biāo))
  3. Debugging settingsDefault symbol path 中填入:
srv*C:\Symbols*https://msdl.microsoft.com/download/symbols

WinDbg Classic(傳統(tǒng)版):

  1. 打開 WinDbg
  2. 菜單 FileSymbol File Path...(或按 Ctrl+S
  3. 在彈出的對(duì)話框中填入符號(hào)路徑
方法二:使用命令行配置

在 WinDbg 命令窗口中執(zhí)行:

.symfix C:\Symbols
.sympath+ srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
.reload
命令 說明
.symfix 快速設(shè)置為微軟符號(hào)服務(wù)器
.sympath+ 追加符號(hào)路徑(不覆蓋已有路徑)
.sympath 查看或設(shè)置符號(hào)路徑(覆蓋已有路徑)
.reload 重新加載符號(hào)
符號(hào)路徑格式解析
srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
 │      │                        │
 │      │                        └── 符號(hào)服務(wù)器 URL
 │      └── 本地緩存目錄(下載后保存在這里)
 └── 表示這是一個(gè)符號(hào)服務(wù)器路徑

4. 添加自己項(xiàng)目的符號(hào)文件路徑

除了微軟公共符號(hào),還需要添加自己項(xiàng)目編譯生成的 .pdb 文件路徑。

方法一:WinDbg 界面配置

在符號(hào)路徑中添加多個(gè)路徑,用分號(hào) ; 分隔:

D:\MyProject\bin\Release;srv*C:\Symbols*https://msdl.microsoft.com/download/symbols
方法二:命令行追加
.sympath+ D:\MyProject\bin\Release
.sympath+ D:\MyProject\bin\Debug
.reload
方法三:搭建私有符號(hào)服務(wù)器

對(duì)于團(tuán)隊(duì)協(xié)作,建議搭建內(nèi)部符號(hào)服務(wù)器:

srv*C:\Symbols*\\internal-server\symbols;srv*C:\Symbols*https://msdl.microsoft.com/download/symbols

?? 重要提示:.pdb 文件必須與 .exe/.dll 文件完全匹配(同一次編譯產(chǎn)生)。建議每次發(fā)布版本時(shí)保存對(duì)應(yīng)的 .pdb 文件。


5. 環(huán)境變量配置(_NT_SYMBOL_PATH

通過設(shè)置系統(tǒng)環(huán)境變量,可以讓所有調(diào)試工具(WinDbg、Visual Studio 等)共享符號(hào)配置。

配置步驟
  1. 打開 系統(tǒng)屬性高級(jí)環(huán)境變量
  2. 系統(tǒng)變量用戶變量 中新建變量:
    • 變量名:_NT_SYMBOL_PATH
    • 變量值:
    srv*C:\Symbols*https://msdl.microsoft.com/download/symbols;D:\MyProject\Symbols
    
或使用命令行設(shè)置(管理員權(quán)限)
setx _NT_SYMBOL_PATH "srv*C:\Symbols*https://msdl.microsoft.com/download/symbols" /M
驗(yàn)證配置

在命令提示符中執(zhí)行:

echo %_NT_SYMBOL_PATH%

2.3 源代碼路徑配置(可選)

1. 關(guān)聯(lián)源代碼以便定位具體代碼行

配置源代碼路徑后,WinDbg 可以:

  • 在分析時(shí)直接顯示對(duì)應(yīng)的源代碼
  • 支持源碼級(jí)單步調(diào)試
  • 快速跳轉(zhuǎn)到出錯(cuò)的具體代碼行

2. 配置方法

方法一:WinDbg 界面配置

WinDbg Preview:

  1. SettingsDebugging settingsDefault source path
  2. 填入源代碼根目錄路徑

WinDbg Classic:

  1. 菜單 FileSource File Path...(或按 Ctrl+P
  2. 填入源代碼路徑,多個(gè)路徑用分號(hào)分隔:
D:\MyProject\src;D:\MyProject\libs
方法二:命令行配置
.srcpath D:\MyProject\src
.srcpath+ D:\MyProject\libs
命令 說明
.srcpath 設(shè)置源代碼路徑(覆蓋已有)
.srcpath+ 追加源代碼路徑
.srcnoisy 1 開啟源碼加載詳細(xì)日志(調(diào)試用)
方法三:環(huán)境變量配置

設(shè)置 _NT_SOURCE_PATH 環(huán)境變量:

_NT_SOURCE_PATH=D:\MyProject\src;D:\MyProject\libs
源碼服務(wù)器(Source Server)

對(duì)于大型項(xiàng)目,可以配置源碼服務(wù)器,自動(dòng)從版本控制系統(tǒng)(Git、SVN)獲取對(duì)應(yīng)版本的源碼:

.srcfix

?? 提示:如果源代碼路徑與編譯時(shí)的路徑不同,可以使用 .srcpath 的映射功能:

.srcpath+ D:\NewPath=C:\OriginalPath

四、dmp 文件分析實(shí)戰(zhàn)

4.1 基礎(chǔ)分析命令

命令 說明 使用場(chǎng)景
!analyze -v 自動(dòng)分析崩潰原因 第一步必用,獲取崩潰概述
kb 顯示調(diào)用棧(帶參數(shù)) 查看崩潰時(shí)的函數(shù)調(diào)用鏈
kv 顯示調(diào)用棧(詳細(xì)) 需要更多調(diào)用信息時(shí)
kp 顯示調(diào)用棧(完整參數(shù)) 查看函數(shù)參數(shù)值
lm 列出加載的模塊 確認(rèn)模塊版本和加載狀態(tài)
.ecxr 切換到異常上下文 查看崩潰瞬間的狀態(tài)
r 查看寄存器 分析底層崩潰原因
!threads 查看所有線程 多線程問題分析
~*k 所有線程調(diào)用棧 查找問題線程
dv 顯示局部變量 查看變量值
dt 顯示數(shù)據(jù)類型 查看結(jié)構(gòu)體內(nèi)容

4.2 分析流程

第一步:將 .dmp文件拖到 WinDbg,然后在命令框輸入 Lmvm xxxx 獲取版本信息(必做)

獲取版本后去下載對(duì)應(yīng)的pdb文件

第二步:添加微軟符號(hào)文件路徑 和 對(duì)應(yīng)的sdk .pdb文件本地路徑(多個(gè)路徑使用 ; 分隔)

  • 點(diǎn)擊 File -> Symbol File Path ...
  • 添加符號(hào)路徑
//例如:
srv*E:\symbols*https://msdl.microsoft.com/download/symbols;D:\SDK\pdb\SDK_Pdb_Win64_12.8.0.16983

打開 dmp 文件后,首先執(zhí)行自動(dòng)分析命令:

!analyze -v

這個(gè)命令會(huì):

  • 識(shí)別崩潰類型
  • 顯示崩潰地址和原因
  • 提供可能的原因分析
  • 顯示關(guān)鍵的調(diào)用棧

輸出示例:

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 00007ff6e8c01234 (MyApp!CrashFunction+0x0000000000000044)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 0000000000000000
Attempt to read from address 0000000000000000

FAULTING_SOURCE_LINE:  d:\src\crash.cpp
FAULTING_SOURCE_FILE:  d:\src\crash.cpp
FAULTING_SOURCE_LINE_NUMBER:  42

STACK_TEXT:  
00000000`0014f8a0 00007ff6`e8c01234 MyApp!CrashFunction+0x44
00000000`0014f8d0 00007ff6`e8c02345 MyApp!CallerFunction+0x78
00000000`0014f900 00007ff6`e8c03456 MyApp!main+0x120

第三步:切換到異常上下文

.ecxr

這個(gè)命令將寄存器和調(diào)用棧切換到異常發(fā)生時(shí)的狀態(tài),確保后續(xù)分析基于正確的上下文。


第四步:查看詳細(xì)調(diào)用棧

kv

輸出示例:

 # Child-SP          RetAddr           Call Site
00 00000000`0014f8a0 00007ff6`e8c01234 MyApp!CrashFunction+0x44 [d:\src\crash.cpp @ 42]
01 00000000`0014f8d0 00007ff6`e8c02345 MyApp!CallerFunction+0x78 [d:\src\caller.cpp @ 128]
02 00000000`0014f900 00007ff6`e8c03456 MyApp!main+0x120 [d:\src\main.cpp @ 56]

調(diào)用棧閱讀技巧:

  • 從上到下閱讀:最上面是崩潰位置,越往下是更早的調(diào)用者
  • +0x44 表示在函數(shù)入口偏移 0x44 字節(jié)處
  • @ 42 表示源代碼第 42 行

第五步:定位問題模塊和函數(shù)

根據(jù)調(diào)用棧找到自己項(xiàng)目的代碼:

# 查看特定模塊信息
lm m MyApp

# 查看模塊的符號(hào)加載狀態(tài)
!lmi MyApp

第六步:查看局部變量和參數(shù)

# 查看當(dāng)前棧幀的局部變量
dv

# 切換棧幀后查看
.frame 1
dv

# 顯示變量類型
dv /t

# 查看特定變量
?? variableName

輸出示例:

0:000> dv
          this = 0x00000000`00000000    ← 空指針!
      userName = 0x00000000`1234abcd "test_user"
     errorCode = 0n-2147024891
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容