简体   繁体   English

VC ++堆栈跟踪无法解析生产中的函数名称

[英]VC++ stack trace does not resolve function names on production

I recently implemented stack trace logging using boost's new stacktrace library : 我最近使用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
...

I have debugged boost implementation of stacktrace to find that the stack functions' addresses are retrieved with RtlCaptureStackBackTrace , which seems to be working fine. 我调试了stacktrace boost实现,发现使用RtlCaptureStackBackTrace检索堆栈函数的地址,这似乎工作正常。 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. 然后在frame_msvc.ipp文件中的boost::stacktrace::detail::to_string - > get_name_impl函数中检索函数名,该函数在内部使用库Dbgeng中的IDebugSymbols对象。 This interface declares a function IDebugSymbols::GetNameByOffset which is supposed to retrieve function name in format: Module!function . 此接口声明了一个函数IDebugSymbols::GetNameByOffset ,它应该以格式检索函数名: 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. 尽管已经将MyApplication.pdb文件与应用程序一起部署,但由于某种原因,它似乎无法检索符号数据。

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. 您可能已经注意到,函数名称(没有源文件和行号,我可以不用)可以检索静态链接的opencv库,但不是我自己的源。

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? 有没有人知道如何使这项工作无论运行时系统如何?

EDIT2: EDIT2:

It turns out that the source of the problem is in fact inability to load the .pdb file. 事实证明,问题的根源实际上无法加载.pdb文件。 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. 出于某种原因, IDebugClientIDebugControlIDebugSymbols ,无论哪个应该加载符号文件(在初始化用于检索boost::stacktrace::detail::to_string符号的debugging_symbols类期间按顺序创建),仅查找它位于可执行文件头的“Debugger Directories”部分中写入的位置。 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). 这是VS在链接期间创建的路径(我通过将文件复制到远程系统上的相同路径来测试它,然后才起作用)。

Is there a way to make it load .pdb file in the local directory of the executable? 有没有办法让它在可执行文件的本地目录中加载.pdb文件? Or perhaps it is possible to save relative path for the symbols file in the executable header? 或者也许可以在可执行标头中保存符号文件的相对路径?

EDIT: Adding MCVE: 编辑:添加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;
}

And linker options: 和链接器选项:

/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 

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不加载位于可执行文件目录中的符号文件,而只加载可移植可执行文件头中保存的符号文件(当我将.pdb文件复制到与开发时相同的路径时,它起作用了系统)。

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 "." 我通过创建自己的IDebugSymbols实例(我复制了从frame_msvc.ipp debugging_symbols::try_init_com创建它的代码)并修改最后一行添加“。”来解决这个问题。 (current directory) to symbol search path with IDebugSymbols::AppendSymbolPath : (当前目录)到IDebugSymbols::AppendSymbolPath符号搜索路径:

if (S_OK == iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr()))
    idebug->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. 在每次debugging_symbols::try_init_com调用期间,可以使用IDebugSymbols::GetSymbolPath检查路径中的部分。 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 "." 我还测试了IDebugSymbols::AppendSymbolPath检查当前路径字符串并且不附加重复项(再次找不到备份文档)所以它总是可以尝试附加“。”。 during object initialization. 对象初始化期间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM