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

2024-02-26

我最近使用实现了堆栈跟踪日志记录boost 的新 stacktrace 库 https://www.boost.org/doc/libs/develop/doc/html/stacktrace/getting_started.html:

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;
}

在我的开发机器上进行了测试,结果完美:

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
...

我将新的应用程序版本部署到生产环境中。不幸的是,在生产机器上,我的模块中的堆栈帧仅解析为模块名称:

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

我已经调试了boost的实现stacktrace发现堆栈函数的地址是用RtlCaptureStackBackTrace https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/nf-ntifs-rtlcapturestackbacktrace,这似乎工作正常。然后在中检索函数名称boost::stacktrace::detail::to_string -> get_name_impl函数在frame_msvc.ipp文件中,内部使用IDebugSymbols https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/dbgeng/nn-dbgeng-idebugsymbols来自 Dbgeng 库的对象。这个接口声明了一个函数IDebugSymbols::GetNameByOffset https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/content/dbgeng/nf-dbgeng-idebugsymbols-getnamebyoffset它应该以以下格式检索函数名称:Module!function。不幸的是,它仅在我的开发环境中执行此操作,而仅在生产系统上返回模块名称。尽管已将 MyApplication.pdb 文件与应用程序一起部署,但由于某种原因,它似乎无法检索符号数据。

正如您可能已经注意到的,函数名称(没有源文件和行号,我可以没有它们)是为静态链接的 opencv 库检索的,但不是为我自己的源检索的。

我找不到此实施工作的要求是什么。有谁知道如何使其工作而不管运行时系统如何?

EDIT2:

事实证明,问题的根源实际上是无法加载 .pdb 文件。因为某些原因IDebugClient, IDebugControl or IDebugSymbols,无论哪个应该加载符号文件(在初始化期间按顺序创建debugging_symbols用于检索符号的类boost::stacktrace::detail::to_string),仅在可执行文件头的“调试器目录”部分中写入的位置中查找它。这是 VS 在链接期间创建的路径(我通过将文件复制到远程系统上的同一路径来测试它,然后它才起作用)。

有没有办法让它加载可执行文件本地目录中的 .pdb 文件?或者也许可以在可执行头文件中保存符号文件的相对路径?

编辑: 添加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 文件复制到与我的开发系统上相同的路径时,它起作用)。

我通过创建自己的解决方案解决了这个问题IDebugSymbols实例(我复制了创建它的代码框架_msvc.ipp https://github.com/boostorg/stacktrace/blob/7fedfa12654d18a9fa695de258763e93699c4636/include/boost/stacktrace/detail/frame_msvc.ipp#L118 debugging_symbols::try_init_com)并修改最后一行以添加“。” (当前目录)到符号搜索路径IDebugSymbols::AppendSymbolPath:

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

这在进程生命周期内只需要完成一次 - 似乎符号路径字符串(或符号本身)被缓存,但我找不到确认它的文档。或者,“.”的存在。路径中的部分可以通过检查IDebugSymbols::GetSymbolPath期间每debugging_symbols::try_init_com称呼。我也测试过IDebugSymbols::AppendSymbolPath检查当前路径字符串并且不附加重复项(再次找不到文档来支持这一点),因此始终尝试附加“.”可能就足够了。在对象初始化期间。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • Gradle 和多项目结构

    我试图了解应该如何进行以下项目设置 Top Android Project Project 1 Pure Java Modules Module A1 Module B1 Module Z1 Project 2 Android Librar
  • 如何在rails中后台运行rake任务

    这是我的命令 bundle exec rake resque work QUEUE trace 我想在我的服务器上作为后台进程运行此命令 请帮我 我经常使用的一个方法是 nohup bundle exec rake resque work
  • 如何创建 gzip 压缩的 HTTP::Response?

    我需要使用压缩数据创建 HTTP Response 我该如何对内容进行压缩 我是否只需添加适当的标头并使用 Compress Zlib 自行压缩它 或者 LWP 模块是否提供了处理此问题的方法 这是你需要的吗 您对数据进行压缩 设置内容编码
  • 从 Python 中打开的 Excel 文件中读取

    我有一个脚本每隔几个小时从 Excel 文件中提取数据 但是 如果这些 Excel 文件之一打开 我仍然希望能够读取它 在 python openpyxl 中 当我尝试执行此操作时 出现权限错误 以下是我尝试过的 我认为我可以捕获异常并创建
  • 暂停交易是什么意思?

    如果我们使用 Propagation Requires new 那么它会挂起现有事务并创建一个新事务 那么这意味着什么suspends a transaction 暂停的交易会怎样 幕后究竟发生了什么 update 暂停的事务持有的资源会发
  • scala 列表地图与mapConserve

    我试图理解mapConserve 据说 像xs map f 但如果函数f将所有元素映射到自身 则返回xs不变 来自List http www scala lang org api current index html scala colle
  • Java 8 - 无法在数组类型 Enum[] 上调用stream() [重复]

    这个问题在这里已经有答案了 为什么我无法调用stream 关于数组类型Enum DummyEnum array DummyEnum values array stream Compile Error ENUM public enum Dum
  • 如何使用 Java 获取我的电脑中可用串行端口的列表?

    我只是运行一些代码来获取计算机上的可用端口列表 当我有 3 个空闲的 com 端口时 它返回 false 我该如何解决这个问题 我的代码 public static void main String args SerialParameter
  • JavaScript 让 Firefox 开发者工具调试视图中的块作用域

    我正在调查该机构的工作情况let 块作用域在 JavaScript 中 特别是浏览器的调试视图如何显示信息 Using let在一个for循环创建一个块作用域 其中回调function timeoutHandler 可以访问 一切都很好 I
  • 格式化复数

    对于我的一个课程中的一个项目 我们必须输出最多五位小数的数字 输出可能是一个复数 而我无法弄清楚如何输出具有五位小数的复数 对于花车我知道它只是 print 0 5f variable name 复数有类似的东西吗 您可以使用如下所示的方法
  • 使用 Gradle 调用 powershell 脚本

    我是 Gradle 新手 所以请耐心等待 我只是想调用 ps1 文件来使用 gradle 执行 我将如何设置 build gradle 文件来执行同一目录中的 ps1 文件 提前致谢 你可以使用gradleExec https docs g
  • python in 和比较的运算符优先级

    以下比较产生True gt gt gt 1 in 11 True gt gt gt 1 in 11 True True 如果使用括号 我会得到一个 TypeError gt gt gt 1 in 11 True Traceback most
  • IBM Integration 总线 mqsicreatebar 及参考

    我对在我的环境中使用 mqsicreatebar 感到有点困惑 例如 我有以下文件结构 root Libraries Library1 Apps App1 project App1 是参考图书馆1 我想运行 mqsicreatebar 使其
  • 应用程序中的各个阶段在 Spark 中并行运行吗?

    我有一个疑问 阶段如何在 Spark 应用程序中执行 程序员可以定义的阶段执行是否具有一致性 或者是否由 Spark 引擎导出 检查这张图中的实体 阶段 分区 图片来源 http alvincjin blogspot in 2014 12
  • 显示宏选项

    在 Excel VBA 中 可以使用 MacroOptions 函数定义与宏或函数相关的一些信息 通过 VBA 输入后是否可以访问此类信息 谢谢 我已经搜索了一段时间但没有发现什么很棒的东西 我发现的唯一解决方法是使用 Chip Pears
  • 通过 URL 发布到 Reddit

    是否可以通过 URL 发布 Reddit 链接 例如对于 Facebook 你可以这样做 a href Share Stackoverflow on your profile a Reddit 是否有一个可以让我共享 URL 的等效端点 有
  • python 管道中的特征选择:如何确定特征名称?

    我使用 pipeline 和 grid search 选择最佳参数 然后使用这些参数来拟合最佳管道 best pipe 然而 由于 feature selection SelectKBest 处于管道中 因此尚未对 SelectKBest
  • 如何在 Android 上动态更新 ListView [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 在 Android 上 我怎样才能L
  • 在 C# 中实现生产者/消费者模式

    我该如何实施生产者 消费者C 中的模式使用活动和代表 使用这些设计模式时 在资源方面需要注意什么 有什么我需要注意的边缘情况吗 我知道这个线程有点老了 但由于我有时在搜索中遇到它 我决定为那些想知道如何实现简单的通用生产者 消费者作业队列的
  • VC++ 堆栈跟踪无法解析生产中的函数名称

    我最近使用实现了堆栈跟踪日志记录boost 的新 stacktrace 库 https www boost org doc libs develop doc html stacktrace getting started html int