Crash Dump调试:Symbol Server/Source Server、PDB原理分析
Crash Dump调试:Symbol Server/Source Server、PDB原理分析
Crash Dump调试:Symbol Server/Source Server、PDB原理分析 - 知乎 (zhihu.com)
背景
- UE4引擎时不时要魔改编译。可能大一点的项目是难以避免的吧 ┓( ´∀` )┏
- 工程C++会自动编译,有持续集成平台做统一的编译和分发。这样可以不用每个人都编译引擎和工程C++了,代码安全性和开发效率能得到保障;
- 每当要调试别人发的Dump,就要满世界找dll,找符号,找代码;
目的
搭建符号服务器,调试分析Crash Dump。
如果你也有跟我一样的痛点,那接下来就来看看怎么解决吧。
接下来,我会先介绍怎么用,最后再说说原理和一些技巧。
搭建符号服务器(如已有请略过)
- 在编译机上安装WinDbg,后面需要用到其中的
symstore
和agestore
。
Download Debugging Tools for Windows - WinDbg - Windows drivers
注意安装这个版本:(这里才有我们需要的symstore
和agestore
)
安装好之后,应该可以在这里找到这两个工具,请根据机器的架构选用合适的版本。
2. 准备一个脚本,用symstore
把Binaries和PDB存入符号服务器,比如这样:
@echo off
rem 脚本传入参数(按顺序): <BIN_DIR>
setlocal EnableDelayedExpansion
rem echo BIN_DIR:%1rem SYMSTOREPATH 符号服务器地址
rem PRODUCT 你的产品名
rem VERSION 你产品的版本
rem COMMENT 你想加的注释
rem TIMEOUT_DAYS 清理多少天前的符号
rem SYMSTORE_EXE symstore的文件地址
rem AGESTORE_EXE agestore的文件地址
set SYMSTOREPATH=D:\SymbolStore
set PRODUCT="sakura"
set VERSION="0.0.0"
set COMMENT="none"
set TIMEOUT_DAYS=60
set SYMSTORE_EXE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symstore.exe"
set AGESTORE_EXE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\agestore.exe" -yset BIN_DIR=%~f1%SYMSTORE_EXE% > nul 2> nul
if [%ERRORLEVEL%] EQU [9009] (echo "symstore.exe 没找到,请包含它所在文件夹到PATH"exit /b 0
)echo ============== 清除旧符号 ==============
echo 清除%TIMEOUT_DAYS%天前的符号
%AGESTORE_EXE% -days=%TIMEOUT_DAYS% %SYMSTOREPATH%
echo.echo =============== 上传符号 ===============
echo ++ 本地上传目录: %BIN_DIR%
echo ++ 符号服务器: %SYMSTOREPATH%
echo.echo ++++++++
echo ++ 上传exe到符号服务器
%SYMSTORE_EXE% add /r /f %BIN_DIR%\*.exe /s %SYMSTOREPATH% /t %PRODUCT% /v %VERSION% /c %COMMENT%
echo.echo ++++++++
echo ++ 上传dll到符号服务器
%SYMSTORE_EXE% add /r /f %BIN_DIR%\*.dll /s %SYMSTOREPATH% /t %PRODUCT% /v %VERSION% /c %COMMENT%
echo.echo ++++++++
echo ++ 上传pdb到符号服务器
%SYMSTORE_EXE% add /r /f %BIN_DIR%\*.pdb /s %SYMSTOREPATH% /t %PRODUCT% /v %VERSION% /c %COMMENT%
echo.echo ++ 上传成功!!!!
echo.
在每次编译完之后,运行。
bat脚本会用agestore
自动清理过期的符号。
> upload_symbols.bat ...\UE4\Epic\Engine\Binaries
> upload_symbols.bat ...\UE4\Epic\Engine\Plugins
3. 设置好符号服务器的文件服务器,可以简单地用Samba协议(Windows共享文件夹)或者用IIS或者Apache弄一个。
在VS中设置符号服务器
以VS2019为例,在 工具->选项->调试->符号 把刚才的服务器地址(确保有访问权限)设置好:
小技巧:勾选Load only specified modules,可以显著加速调试载入module的时间。在需要查看符号时,再右键加载所需的module:
就能看到符号名字了:
参考官方文档:
https://docs.microsoft.com/en-us/windows/win32/debug/using-symstore
源码匹配
此时很可能因为pdb中的源码路径和你本地的不一致,导致找不到源码,如下图:
此时除了一个个地去找源码路径之外,有两种方法可以让VS自动定位到所需的源码:
- 在Solution设置中配置Debug Source Files查找路径。
这种方法简单但有局限,能应付大部分情况。如下图:
2. Source Server(推荐)
假如产生这个Dump的Binaries已经很旧了,源码已经被改的天翻地覆,除了在本地通过版本控制系统把代码手动还原回去,这种比较笨的办法之外,还有没有更好的做法呢?
又假如要调试的程序本地并没有全部代码,但想大致看一下问题出在哪(比如在QA机器上出现的Crash想准确分发给对应的工程师),有没有更好的做法呢?
有的,答案是Source Server。
Source Server配置方法
编译时:Source Indexing
概要:(以SVN为例)在编译完成后,上传符号之前,用svnindex.cmd
工具将版本控制信息写入PDB。
运行要求:
- Debugging Tools for Windows(在上面搭建符号服务器时已安装)
- ActiveState Perl(Indexing所需的工具,比如:svn.pm,用Perl运行)
- 准备svn.exe,并加入到PATH
在PDB生成出来后,上传符号前,执行下面的操作:
svnindex.cmd /source=<SVN ROOT> /symbols=<SYMBOL LOCATION> /debug
此时应该会看到PDB被修改了。
可以用pdbstr.exe检查被写入的内容:
pdbstr.exe -r -p:<PDB file> -s:srcsrv
此时的PDB将比编译生成的PDB多出一些信息。
PDB就准备完成了。
注意svnindex.cmd的source路径只能是SVN根目录。
调试时:从版本控制服务器自动下载源码
- 准备svn.exe,并加入到PATH;
- 在VS中启用Source Server的支持;
设置完成。
在调试Dump时,会提取PDB中的指令。这可能会带来代码注入风险。比如你调试一个未知来源的程序,自带PDB,这个PDB中是可以嵌入任意代码的。
VS会弹窗提醒。解决方法可以是:
修改svn.pm文件中的SVN_EXTRACT_CMD,将"cmd /c"删掉,直接执行svn.exe,而不是通过cmd.exe。
修改VS安装目录下的srcsrv.ini,将svn.exe加入[trusted command]:
[trusted commands]
svn.exe
至此,代码就可以自动从版本控制服务器上获取了。(^-^)V
代码会缓存到AppData下,不会自动清理,时间长了请自行手动清理。
VS Visualizer 配置
Visualizer 是VS 调试器的自定义可视化方式,比如UE4 里面的很多内置类型是的数据是不那么容易看到的,通常要通过一个Index 去某个表里做二次查询,这时候就可以通过Visualizer 去做可视化,方便调试。
参考资料
Source Server
Using a Source Server
Enable source server support
Source Server + Subversion = Easy Assembly Debugging
原理介绍
通过前面的操作,也基本能猜出个大概了。这篇文章写得挺详细的,我就不赘述了,只简单讲讲自己的理解:
搭建自己的符号服务器
PDB:
PDB里面记录了一系列的调试辅助信息,与Build的Binary一一对应。比如:
- publics and exports
- global symbols
- local symbols
- type data
- source files
- line numbers
最关键的,无非就是代码段地址,对应的源码路径、函数签名和行号。这样在调试的时候,就知道当前的代码地址,对应哪个代码的哪个函数的哪一行了。
DLL和PDB中会有相同的GUID,通过GUID在符号服务器上组织目录存放文件,调试时根据GUID来找对应的PDB下载。
Source Server重建索引时(重新执行`svnindex.cmd`)PDB文件会被修改(哪怕对应的Binary一点都不变,PDB中的索引日期也会变),但GUID会保持不变。
更新后的PDB会被symstore重新上传符号服务器(而不是相同跳过),会覆盖掉符号服务器上GUID相同的旧PDB,不会因此导致硬盘空间不足,但需要注意IO和流量问题。
Symbol Files - Win32 apps
Crash Dump:
Dump简单来说就是进程的内存镜像。把这个进程的虚拟内存(代码段、数据段、堆、栈、全局段等等)部分或者全部转储到磁盘文件,以便进行死后调试。
https://medium.com/@shoheiyokoyama/understanding-memory-layout-4ef452c2e709
User-Mode Dump Files - Windows drivers
其中,又分为Full Dump和Mini Dump,两者最大的区别在于Heap是否做转储。
因为Heap通常非常大,在UE4下动辄10GB以上。而其他内存段相对小很多,比如线程的Stack一般就是几MB。
所以,在Mini Dump下,因为Heap都被剔除了,所以在调试Dump时,看到的是???内存不可访问,比如UE4的FString内部是一个TArray,其字符串Data就是在Heap上的,所以调试Dump时都不可见。
那问题又来了,这样的Mini Dump有什么用呢?如果是因为资源问题导致的Crash,怎么知道是哪个资源呢?
小技巧:可以用在UE4程序后加命令行参数-fullcrashdump来告诉引擎,崩溃时生成Full Dump。这样就可以勉强弥补Mini Dump所带来的不足。
生成Dump
UE4程序Crash的时候会自动生成Dump,因为引擎中提供了Crash Handler:
但假如我想随意生成Dump呢?比如没有Crash而是假死了,怎么知道问题出在哪呢?
有很多种方式可以做到,我个人比较常用的是:
- 用VS Attach上去,然后Debug->Break All->Save Dump As。可以创建Mini Dump或者Full Dump;
- 用任务管理器,右键对应的进程->Create dump file。只能创建Full Dump;
其他的方法可以参考这里:
https://www.wintellect.com/how-to-capture-a-minidump-let-me-count-the-ways/
结束
感谢阅读!希望大家能有所收获,不正之处还请指教。
编辑于 2021-05-13 17:06
虚幻 4(游戏引擎)
Dump
软件调试
Crash Dump调试:Symbol Server/Source Server、PDB原理分析相关推荐
- 无法查找或打开 pdb 文件。_Crash Dump调试:Symbol Server/Source Server、PDB原理分析
背景 UE4引擎时不时要魔改编译.可能大一点的项目是难以避免的吧 ┓( ´∀` )┏ 工程C++会自动编译,有持续集成平台做统一的编译和分发.这样可以不用每个人都编译引擎和工程C++了,代码安全性和开 ...
- Source Server + Symbol Server
来自微软的symbol server解决方案: 参考: source server: http://msdn.microsoft.com/en-us/library/ms680641(VS.85).a ...
- stm32cubeIDE STLINK连接SWD接口调试,启动GDB server失败的处理
stm32cubeIDE STLINK连接SWD接口调试,启动GDB server失败的处理 报警提示 Failed to bind to port 61234, error code -1: No ...
- Crash内核调试手段
kdump简介 kdump是系统崩溃的时候,用来转储运行内存的一个工具. 系统一旦崩溃,内核就没法正常工作了,这个时候将由kdump提供一个用于捕获当前运行信息的内核, 该内核会将此时内存中的所有运行 ...
- Crash Dump Analysis 崩溃转储分析-摘抄翻译自深入解析windows操作系统
Almost every Windows user has heard of, if not experienced, the infamous "blue screen of death. ...
- Windows Error Reporting保存Crash Dump文件
1.Crash Dump文件 Crash Dump(后缀名为:.dmp)文件是进程的内存镜像,可以把程序运行时的状态完整的保存下来,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件 ...
- 【C++】在 Visual Studio 调试器中指定符号 (.pdb) 和源文件(转载自RSS翻译)
在 Visual Studio 调试器中指定符号 (.pdb) 和源文件 查找并指定符号文件和源文件:指定符号加载行为.使用符号和源服务器:自动或按需加载符号. 内容 查找符号 (.pdb) ...
- 高通u-boot关闭crash dump
在高通的u-boot中有这么一个功能,当系统以外挂死的情况下,重启进入u-boot之后会dump debug文件到tftp server上,这个文件看情况而定,可能会很大.这里可能会影响到我们客户的使 ...
- 【启用rabbitmq遇到的问题全】command not found /Crash dump is being written to: erl_crash.dump...done
启用 sudo rabbitmq-server -detached时遇到的问题: 当在终端执行:sudo rabbitmq-server -detached输入密码时提示 command not fo ...
最新文章
- ios请求php接口失败,laravel,php_iOS调用Laravel接口返回错误信息,laravel,php,ios - phpStudy...
- C语言再学习 -- 转义字符
- VTK:随机探针用法实战
- 地理必修一三大类岩石_高一地理必修一知识点总结归纳
- 多线程—Thread类及线程三种创建方式及对比
- 设计模式(十五):解释器模式
- 使用pymc3可能遇到的问题及解决方法
- vue怎么使用php调取数据,vue 数据操作
- 我连饭也顾不上HAO3GP整站源码
- 含有任意量词与存在量词的最值问题
- openstack虚拟机迁移live-migration中libvirt配置
- 查看登陆系统用户的信息的三种方法详解
- 显卡ai性能测试软件,让AI帮你自动超频 索泰RTX 2080Ti显卡性能测试
- python 12345构成不重复的三位数
- Factorization Machines 论文翻译
- 我收藏的阿里云盘资源,牛逼!!
- 设计手机APP界面的感想
- 基于 Vue+Spring 前后端分离管理系统ELAdmin
- Browser --- 更换bookmark、homepage及常见问题
- ol4通过ImageCanvas实现大量点的展示以及交互的实现