热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

无法查找或打开pdb文件。_CrashDump调试:SymbolServer/SourceServer、PDB原理分析

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

63d484917573093b381f5b6056274e50.png

背景

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

目的

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

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

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


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

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

Download Debugging Tools for Windows - WinDbg - Windows drivers

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

82978ac8836c21cf8d75d65d32406af7.png

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

5f61f08c3f18f4a9f5bcbd21f449a456.png

2. 准备一个脚本,用symstore把Binaries和PDB存入符号服务器,比如这样:

@echo off
rem 脚本传入参数(按顺序):
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 Kits10Debuggersx64symstore.exe"
set AGESTORE_EXE="C:Program Files (x86)Windows Kits10Debuggersx64agestore.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 ...UE4EpicEngineBinaries
> upload_symbols.bat ...UE4EpicEnginePlugins

3. 设置好符号服务器的文件服务器,可以简单地用Samba协议(Windows共享文件夹)或者用IIS或者Apache弄一个。


在VS中设置符号服务器

以VS2019为例,在 工具->选项->调试->符号 把刚才的服务器地址(确保有访问权限)设置好:

5fb0d35885b5ba615300916d211d7651.gif

小技巧:勾选Load only specified modules,可以显著加速调试载入module的时间。在需要查看符号时,再右键加载所需的module:

b441e27f68871a003b1055272506a01e.png

就能看到符号名字了:

d5dcef8cff146b024b9761fcf1e42748.png

参考官方文档:

https://docs.microsoft.com/en-us/windows/win32/debug/using-symstore


源码匹配

此时很可能因为pdb中的源码路径和你本地的不一致,导致找不到源码,如下图:

72f81f086692e245c198c6f488298bdd.png

此时除了一个个地去找源码路径之外,有两种方法可以让VS自动定位到所需的源码:

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

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

01d16932d2aeda88e45b1e853483cc21.png

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= /symbols= /debug

27ecb73bb2bd37946e67e390850e4b16.png

此时应该会看到PDB被修改了。

可以用pdbstr.exe检查被写入的内容:

pdbstr.exe -r -p:

-s:srcsrv

此时的PDB将比编译生成的PDB多出一些信息。

a61b92160151333f699550595caf84d7.png

PDB就准备完成了。

注意svnindex.cmd的source路径只能是SVN根目录。

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

  1. 准备svn.exe,并加入到PATH;
  2. 在VS中启用Source Server的支持;

3b76e830ef7e536128a51584c464bad9.png

设置完成。

在调试Dump时,会提取PDB中的指令。这可能会带来代码注入风险。比如你调试一个未知来源的程序,自带PDB,这个PDB中是可以嵌入任意代码的。

c50be7a392a15d8550caf0b6732ddaa0.png

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下,不会自动清理,时间长了请自行手动清理。

7421f78bc7bed51364034b2600288c94.png

参考资料

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简单来说就是进程的内存镜像。把这个进程的虚拟内存(代码段、数据段、堆、栈、全局段等等)部分或者全部转储到磁盘文件,以便进行死后调试。

577928c309432c4a48b31d7d7a48cd03.png

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:

38710d77b0decd6aca83f5b3a01ca9b6.png

但假如我想随意生成Dump呢?比如没有Crash而是假死了,怎么知道问题出在哪呢?

有很多种方式可以做到,我个人比较常用的是:

  • 用VS Attach上去,然后Debug->Break All->Save Dump As。可以创建Mini Dump或者Full Dump;
  • 用任务管理器,右键对应的进程->Create dump file。只能创建Full Dump;

ea4347773f7dbd94eaed9691474389d9.png

其他的方法可以参考这里:

https://www.wintellect.com/how-to-capture-a-minidump-let-me-count-the-ways/


结束

感谢阅读!希望大家能有所收获,不正之处还请指教。



推荐阅读
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • 高效解决应用崩溃问题!友盟新版错误分析工具全面升级
    友盟推出的最新版错误分析工具,专为移动开发者设计,提供强大的Crash收集与分析功能。该工具能够实时监控App运行状态,快速发现并修复错误,显著提升应用的稳定性和用户体验。 ... [详细]
  • andr ... [详细]
  • PHP 5.5.0rc1 发布:深入解析 Zend OPcache
    2013年5月9日,PHP官方发布了PHP 5.5.0rc1和PHP 5.4.15正式版,这两个版本均支持64位环境。本文将详细介绍Zend OPcache的功能及其在Windows环境下的配置与测试。 ... [详细]
  • 本文详细介绍了如何在CentOS 7操作系统上安装和配置Grafana,包括必要的依赖项安装、插件管理以及服务启动等步骤。 ... [详细]
  • 本文探讨了 Spring Boot 应用程序在不同配置下支持的最大并发连接数,重点分析了内置服务器(如 Tomcat、Jetty 和 Undertow)的默认设置及其对性能的影响。 ... [详细]
  • 解决网站乱码问题的综合指南
    本文总结了导致网站乱码的常见原因,并提供了详细的解决方案,包括文件编码、HTML元标签设置、服务器响应头配置、数据库字符集调整以及PHP与MySQL交互时的编码处理。 ... [详细]
  • 微软Exchange服务器遭遇2022年版“千年虫”漏洞
    微软Exchange服务器在新年伊始遭遇了一个类似于‘千年虫’的日期处理漏洞,导致邮件传输受阻。该问题主要影响配置了FIP-FS恶意软件引擎的Exchange 2016和2019版本。 ... [详细]
  • 优化局域网SSH连接延迟问题的解决方案
    本文介绍了解决局域网内SSH连接到服务器时出现长时间等待问题的方法。通过调整配置和优化网络设置,可以显著缩短SSH连接的时间。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 本文探讨了高质量C/C++编程的最佳实践,并详细分析了常见的内存错误及其解决方案。通过深入理解内存管理和故障排除技巧,开发者可以编写更健壮的程序。 ... [详细]
  • 深入解析Nginx中的Location指令及其属性
    本文将详细探讨Nginx配置文件中关键的location指令,包括其三种匹配方式(精准匹配、普通匹配和正则匹配),以及如何在实际应用中灵活运用这些匹配规则。此外,还将介绍location下的重要子元素如root、alias和proxy_pass,并解释相关参数的使用方法。 ... [详细]
  • 通过Web界面管理Linux日志的解决方案
    本指南介绍了一种利用rsyslog、MariaDB和LogAnalyzer搭建集中式日志管理平台的方法,使用户可以通过Web界面查看和分析Linux系统的日志记录。此方案不仅适用于服务器环境,还提供了详细的步骤来确保系统的稳定性和安全性。 ... [详细]
  • 创建项目:Visual Studio Online 入门指南
    本文介绍如何使用微软的 Visual Studio Online(VSO)创建和管理开发项目。作为一款基于云计算的开发平台,VSO 提供了丰富的工具和服务,简化了项目的配置和部署流程。 ... [详细]
  • 在尝试用另一台电脑的MySQL文件替换本地D:\xampp\mysql目录后,MySQL服务无法启动。错误提示显示MySQL意外关闭,可能是由于端口冲突、依赖缺失、权限问题或崩溃等原因引起。 ... [详细]
author-avatar
松原电信曹玉威_203
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有