Crash Dump调试:Symbol Server/Source Server、PDB原理分析

Crash Dump调试:Symbol Server/Source Server、PDB原理分析 - 知乎 (zhihu.com)

背景

  1. UE4引擎时不时要魔改编译。可能大一点的项目是难以避免的吧 ┓( ´∀` )┏
  2. 工程C++会自动编译,有持续集成平台做统一的编译和分发。这样可以不用每个人都编译引擎和工程C++了,代码安全性和开发效率能得到保障;
  3. 每当要调试别人发的Dump,就要满世界找dll,找符号,找代码;

目的

搭建符号服务器,调试分析Crash Dump。

如果你也有跟我一样的痛点,那接下来就来看看怎么解决吧。

接下来,我会先介绍怎么用,最后再说说原理和一些技巧。


搭建符号服务器(如已有请略过)

  1. 在编译机上安装WinDbg,后面需要用到其中的symstoreagestore

Download Debugging Tools for Windows - WinDbg - Windows drivers

注意安装这个版本:(这里才有我们需要的symstoreagestore

安装好之后,应该可以在这里找到这两个工具,请根据机器的架构选用合适的版本。

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自动定位到所需的源码:

  1. 在Solution设置中配置Debug Source Files查找路径。

这种方法简单但有局限,能应付大部分情况。如下图:

2. Source Server(推荐)

假如产生这个Dump的Binaries已经很旧了,源码已经被改的天翻地覆,除了在本地通过版本控制系统把代码手动还原回去,这种比较笨的办法之外,还有没有更好的做法呢?
又假如要调试的程序本地并没有全部代码,但想大致看一下问题出在哪(比如在QA机器上出现的Crash想准确分发给对应的工程师),有没有更好的做法呢?

有的,答案是Source Server。

Source Server配置方法

编译时:Source Indexing

概要:(以SVN为例)在编译完成后,上传符号之前,用svnindex.cmd工具将版本控制信息写入PDB。

运行要求:

  1. Debugging Tools for Windows(在上面搭建符号服务器时已安装)
  2. ActiveState Perl(Indexing所需的工具,比如:svn.pm,用Perl运行)
  3. 准备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根目录。

调试时:从版本控制服务器自动下载源码

  1. 准备svn.exe,并加入到PATH;
  2. 在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原理分析相关推荐

  1. 无法查找或打开 pdb 文件。_Crash Dump调试:Symbol Server/Source Server、PDB原理分析

    背景 UE4引擎时不时要魔改编译.可能大一点的项目是难以避免的吧 ┓( ´∀` )┏ 工程C++会自动编译,有持续集成平台做统一的编译和分发.这样可以不用每个人都编译引擎和工程C++了,代码安全性和开 ...

  2. Source Server + Symbol Server

    来自微软的symbol server解决方案: 参考: source server: http://msdn.microsoft.com/en-us/library/ms680641(VS.85).a ...

  3. stm32cubeIDE STLINK连接SWD接口调试,启动GDB server失败的处理

    stm32cubeIDE STLINK连接SWD接口调试,启动GDB server失败的处理 报警提示 Failed to bind to port 61234, error code -1: No ...

  4. Crash内核调试手段

    kdump简介 kdump是系统崩溃的时候,用来转储运行内存的一个工具. 系统一旦崩溃,内核就没法正常工作了,这个时候将由kdump提供一个用于捕获当前运行信息的内核, 该内核会将此时内存中的所有运行 ...

  5. Crash Dump Analysis 崩溃转储分析-摘抄翻译自深入解析windows操作系统

    Almost every Windows user has heard of, if not experienced, the infamous "blue screen of death. ...

  6. Windows Error Reporting保存Crash Dump文件

    1.Crash Dump文件 Crash Dump(后缀名为:.dmp)文件是进程的内存镜像,可以把程序运行时的状态完整的保存下来,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件 ...

  7. 【C++】在 Visual Studio 调试器中指定符号 (.pdb) 和源文件(转载自RSS翻译)

     在 Visual Studio 调试器中指定符号 (.pdb) 和源文件 查找并指定符号文件和源文件:指定符号加载行为.使用符号和源服务器:自动或按需加载符号.  内容 查找符号 (.pdb) ...

  8. 高通u-boot关闭crash dump

    在高通的u-boot中有这么一个功能,当系统以外挂死的情况下,重启进入u-boot之后会dump debug文件到tftp server上,这个文件看情况而定,可能会很大.这里可能会影响到我们客户的使 ...

  9. 【启用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 ...

最新文章

  1. ios请求php接口失败,laravel,php_iOS调用Laravel接口返回错误信息,laravel,php,ios - phpStudy...
  2. C语言再学习 -- 转义字符
  3. VTK:随机探针用法实战
  4. 地理必修一三大类岩石_高一地理必修一知识点总结归纳
  5. 多线程—Thread类及线程三种创建方式及对比
  6. 设计模式(十五):解释器模式
  7. 使用pymc3可能遇到的问题及解决方法
  8. vue怎么使用php调取数据,vue 数据操作
  9. 我连饭也顾不上HAO3GP整站源码
  10. 含有任意量词与存在量词的最值问题
  11. openstack虚拟机迁移live-migration中libvirt配置
  12. 查看登陆系统用户的信息的三种方法详解
  13. 显卡ai性能测试软件,让AI帮你自动超频 索泰RTX 2080Ti显卡性能测试
  14. python 12345构成不重复的三位数
  15. Factorization Machines 论文翻译
  16. 我收藏的阿里云盘资源,牛逼!!
  17. 设计手机APP界面的感想
  18. 基于 Vue+Spring 前后端分离管理系统ELAdmin
  19. Browser --- 更换bookmark、homepage及常见问题
  20. ol4通过ImageCanvas实现大量点的展示以及交互的实现

热门文章

  1. VelocityTracker的简单使用
  2. C语言入门篇之五行道法(五)(类型转换、三目运算符)
  3. 数据中心逃离北京雾都
  4. 2022年亚马逊营销:5个超好用的数据分析工具
  5. 爬虫大战之智联data
  6. 如何系统学习ElasticSearch、Kibana、Logstash:死磕 Elasticsearch 方法论(初学者必看)
  7. 几年的放纵,换来的可能就是一生的卑微和坎坷。
  8. MySQL的MVCC及实现原理
  9. android 耳返解决方案,vivo又出招手机音频领域:联合全民K歌发布首个安卓实时耳返方案...
  10. 【安全与风险】安全研究的新课题