VC ++堆栈跟踪无法在生产时解析函数名称 [英] VC++ stack trace does not resolve function names on production

查看:72
本文介绍了VC ++堆栈跟踪无法在生产时解析函数名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近使用 boost的新功能实现了堆栈跟踪日志记录stacktrace库:

int debugErrorCallback(int status, const char* func_name, const char* err_msg, const char* file_name, int line, void* userdata)
{
    boost::stacktrace::stacktrace stacktrace(4, 10); //skipped 4 frames include cv::error, this function and 2 in boost::stacktrace ctor
    std::cout << boost::stacktrace::detail::to_string(stacktrace.as_vector().data(), 
                                                      stacktrace.size()) << std::endl;
}

已经在我的开发机器上对其进行了测试,并获得了完美的结果:

Having tested it on my development machine with perfect results:

0# cv::arithm_op at d:\src\opencv_24\modules\core\src\arithm.cpp:1293
1# cv::addWeighted at d:\src\opencv_24\modules\core\src\arithm.cpp:2127
2# MyApplication::myFunction at d:\src\path\to\my\file.cpp:226
3# MyApplication::myOtherFunction at d:\src\path\to\my\other_file.cpp:146
...

我将新的应用程序版本部署到生产中.不幸的是,在生产机器上,我模块中的框架仅解析为模块名称:

I deployed new application version to production. Unfortunately, on production machine stack frames in my module are only resolved to the module name:

0# cv::addWeighted in opencv_core2413
1# cv::addWeighted in opencv_core2413
2# 0x00007FF7D0A0B56B in MyApplication
3# 0x00007FF7D0A0B2ED in MyApplication
...

我已经调试了stacktrace的boost实现,以发现使用 IDebugSymbols::GetNameByOffset ,应该以以下格式检索函数名称:Module!function.不幸的是,它仅在我的开发环境中这样做,而仅在生产系统上返回模块名称.尽管已将MyApplication.pdb文件与应用程序一起部署,但由于某种原因似乎仍无法检索符号数据.

I have debugged boost implementation of stacktrace to find that the stack functions' addresses are retrieved with RtlCaptureStackBackTrace, which seems to be working fine. Function names are then retrieved in boost::stacktrace::detail::to_string -> get_name_impl function in frame_msvc.ipp file, which internally uses IDebugSymbols object from library Dbgeng. This interface declares a function IDebugSymbols::GetNameByOffset which is supposed to retrieve function name in format: Module!function. Unfortunately, it only does so on my development environment, while only returning module name on production systems. It seems like it's unable to retrieve symbols data for some reason, despite having deployed the MyApplication.pdb file along with the application.

您可能已经注意到,为静态链接的opencv库检索了函数名(没有源文件和行号,而我可能没有),而没有检索到我自己的源代码.

As you might have noticed, function name (without source file and line number, which I could live without) is retrieved for statically linked opencv library, but not for my own sources.

我找不到实现此功能的要求.不管运行时系统如何,有谁知道如何进行这项工作?

I could not find what are the requirements for this implementation to work. Does anyone have any idea how to make this work regardless of runtime system?

事实证明,问题的根源实际上是无法加载.pdb文件.由于某些原因IDebugClientIDebugControlIDebugSymbols(应该加载符号文件)(它们是在debugging_symbols类的初始化期间顺序创建的,用于在boost::stacktrace::detail::to_string中检索符号),它们看起来在可执行标头的调试器目录"部分中编写的位置中查找它.这是VS在链接期间创建的路径(我通过将文件复制到远程系统上的相同路径进行了测试,然后才起作用).

It turns out that the source of the problem is in fact inability to load the .pdb file. For some reason IDebugClient, IDebugControl or IDebugSymbols, whichever is supposed to load the symbols file (the are created in sequence during initialization of debugging_symbols class that is used to retrieve symbols in boost::stacktrace::detail::to_string), only looks for the it in the location written in the "Debugger Directories" section of the executable header. This is the path that VS creates in during linking (I tested it by copying the file to the same path on remote system and only then it worked).

是否有一种方法可以使它在可执行文件的本地目录中加载.pdb文件?还是有可能在可执行文件头中保存符号文件的相对路径?

Is there a way to make it load .pdb file in the local directory of the executable? Or perhaps it is possible to save relative path for the symbols file in the executable header?

添加MCVE:

#include "boost/stacktrace.hpp"
int main()
{
    boost::stacktrace::stacktrace stacktrace;
    std::cout << boost::stacktrace::detail::to_string(stacktrace.as_vector().data(), stacktrace.size()) << std::endl;
    return 0;
}

和链接器选项:

/OUT:"path\x64\Release\MiscTest.exe" /MANIFEST /LTCG:incremental /NXCOMPAT /PDB:"path\x64\Release\MiscTest.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG:FULL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /PGD:"path\x64\Release\MiscTest.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Release\MiscTest.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 

推荐答案

原因似乎是IDebugSymbols不会加载位于可执行文件目录中的符号文件,而只会加载可移植可执行文件头中的一个(当我将.pdb文件复制到与开发系统上相同的路径时,它起作用了.

It seems that the reason is that IDebugSymbols does not load symbol file located in the directory of the executable, but only the one saved in Portable Executable header (it worked when I copied the .pdb file into the same path as it is on my development system).

我通过创建自己的IDebugSymbols实例来解决此问题(我从IDebugSymbols::AppendSymbolPath的符号搜索路径:

I worked around this issue by creating my own IDebugSymbols instance (I copied the code creating it from frame_msvc.ipp debugging_symbols::try_init_com) and modifying the last line to add "." (current directory) to symbol search path with IDebugSymbols::AppendSymbolPath:

if (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr()))
    idebug->AppendSymbolPath(".");

在过程生命周期中仅需要执行一次-似乎符号路径字符串(或符号本身)已被缓存,但是我找不到确认它的文档.或者,存在.".每次debugging_symbols::try_init_com调用期间,都可以使用IDebugSymbols::GetSymbolPath检查路径中的零件.我还测试了IDebugSymbols::AppendSymbolPath检查当前路径字符串,并且不追加重复项(再次找不到文档来支持此操作),因此始终尝试追加."可能就足够了.在对象初始化期间.

This needs to be done only once during the process lifetime - it appears that the symbols paths string (or the symbols themselves) is cached, but I could not find documentation confirming it. Alternatively, the existence of "." part in the path could be checked with IDebugSymbols::GetSymbolPath during every debugging_symbols::try_init_com call. I also tested that IDebugSymbols::AppendSymbolPath checks current paths string and does not append duplicates (again could not find documentation to back this up) so it might be enough to always just try to append the "." during object initialization.

这篇关于VC ++堆栈跟踪无法在生产时解析函数名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆