未从同一目录加载 C++ PDB 符号

Posted

技术标签:

【中文标题】未从同一目录加载 C++ PDB 符号【英文标题】:C++ PDB Symbols not loaded from same directory 【发布时间】:2018-05-16 01:36:05 【问题描述】:

我有一个 c++ 应用程序,它使用 g3log 库在发生崩溃时提供堆栈跟踪信息。我的发布配置还构建了完整的 pdb 文件,因此这是可能的。我的 app.exe 存储了 pdb 文件的完整路径,也就是说我没有使用 /PDBALTPATH:%_PDB%。

当我从任何文件夹路径运行 .exe 时,只要 .pdb 没有被移动,那么如果我强制崩溃,我会得到一个有意义的堆栈跟踪。现在,如果我将 .pdb 文件移动到与我的 .exe 相同的目录中,它将不再加载。我的猜测是与 .exe 中的路径不匹配。我以为会加载一个与.exe同名的.pdb文件,我想我错了。

我已经通过指定 /PDBALTPATH:%_PDB% 进行了测试,这样就没有路径信息,但是 .pdb 文件再次永远不会加载。

对于这两种情况,如果我附加了一个调试器,调试器中的一切都很好,但我的堆栈跟踪中却没有。

有没有办法让 .pdb 的“自动加载”(不知道如何调用它)从它与 .pdb 位于同一目录中的完整路径匹配时发生。这样我可以在需要时获得有意义的调用堆栈。

【问题讨论】:

据我了解,您正在尝试在没有调试器的情况下加载 PDB 文件。并且您希望通过该库记录可能的异常详细信息。我说的对吗? 这是正确的,正如我在帖子中提到的,当 .pdb 文件路径与 .exe 中引用的路径匹配时,这种情况已经发生。我只是希望它在 pdb 以某种方式位于同一文件夹中时也发生...... 【参考方案1】:

一般来说,您的用例看起来很奇怪。因为意外异常通常意味着未定义的状态,继续没有意义。因此,您可能需要保存转储并稍后使用您的 PDB 文件进行调查。

我不确定在您的开发环境中获取堆栈跟踪信息的内部机制。但通常,调试器会寻找 PDB 文件并尝试从不同位置加载它。而且,当您将 PDB 文件与 EXE 文件一起放置时,调试器就可以找到它。

例如,我的构建服务器在构建到本地符号服务器时会保存 PDB 文件。当我使用调试器调试故障转储时,它会正确获取所需的符号。

我从未尝试过做你想做的事情。事实上,它看起来像是在生产中调试构建,这不是一个好习惯。所以,我会考虑我上面描述的一种方法。

【讨论】:

在 windows 中可以使用 dbghelp.dll。然后在 stacktrace64() 函数的帮助下,您可以获得进程的调用堆栈。没有什么特别的,这就是它的完成方式。当然,这需要 pdb 文件,因此堆栈跟踪是有效的。因此,当在生产中发现问题时,尤其是在无法远程访问的地方,您可以指导客户添加 pdb 文件并在日志中获取有用的信息。 是的,我知道这是可能的。许多年前,我用它来为未处理的异常生成转储。但我的观点是使用用户的转储。因为不需要发布大的 PDB 文件,所以从转储文件中获取更多信息,例如加载的模块、所有线程的堆栈跟踪等。一旦发生不好的事情,你就会得到一个转储。客户无需放置 PDB 文件并重现操作。有些错误很难重现。 小型转储会很有用,但在某些情况下,在不同的地方无法访问互联网。相反,生成的日志文件可以在事后轻松发送,并且所述位置可以使用文本文件,而不是连接到外部服务器。【参考方案2】:

你可以设置这个路径; 设置 _NT_SYMBOL_PATH=C:\MySymbols,您的 pdb 文件就在那里。 最简单的方法,如果你不能设置这个路径,那么按照下面的步骤。

你提到:

当我从任何文件夹路径运行 .exe 时,只要 .pdb 没有被移动,那么如果我强制崩溃,我会得到一个有意义的堆栈跟踪。

因此,请始终确保您的应用从 .exe+.pdb 文件所在的目录运行。

您可以使用 GetModuleFileName+SetCurrentDirectory 来做到这一点。 这意味着,您的工作目录是不同的。 我的建议是,在您的应用程序中,获取“GetModuleFileName”。 然后使用 SetCurrentDirectory 将工作目录更改为 exe 路径。

【讨论】:

我将尝试设置路径,看看它是否有所作为。但是,这里的问题是 pdb 路径是硬编码在 .exe 文件中的。如果您使用任何文本编辑器打开它,它是可见的。虽然我可以更改 exe 的路径,但我需要“伪造”的是 pdb 的路径。它必须与 .exe 中硬编码的内容相匹配。【参考方案3】:

看来@prasad-mk 说对了一半。设置 _NT_SYMBOL_PATH 以某种方式强制加载我的 .pdb 符号,就像路径匹配的情况一样。

我发现的另一个选项是使用此实用程序 http://bytepointer.com/tools/index.htm#peupdate 更新路径以更新我的 pdb 的位置。

【讨论】:

以上是关于未从同一目录加载 C++ PDB 符号的主要内容,如果未能解决你的问题,请参考以下文章

未加载符号:未​​加载 libmex.pdb(throw_segv_longjmp_seh_filter() = EXCEPTION_CONTINUE_SEARCH:C++ 异常)

[原]排错实战——解救加载调试符号失败的IDA

VS“无法查找或打开PDB文件”问题

CLR 如何定位 pdb 符号文件

VS2010环境下C++工程相关问题汇总

pdb符号库文件详解