【问题标题】:How can iterate the stack frames manually in C?如何在 C 中手动迭代堆栈帧?
【发布时间】:2015-01-06 14:07:48
【问题描述】:

在应用程序中处理信号时,我可以在调试器中正确看到回溯。但是回溯系统调用没有正确显示堆栈帧。gdb 存储堆栈帧的方式和回溯系统调用如何转储它们有区别吗?

【问题讨论】:

  • 我正在加载一个共享对象,该对象覆盖/安装它自己的信号处理程序并从中链接我的信号处理程序。共享对象是专有的,我没有代码访问它。没有回溯()正在加载的共享对象返回的计数为 14,这是正确的。但是当调用共享对象信号处理程序时,它会干净地删除信号处理程序下方的 8 帧。只是想找出打印正确信息的方法。
  • 可能专有共享对象是经过优化且没有帧指针的编译。所以你很不幸,因为你对此无能为力(除了避免使用专有软件,只使用免费软件)。
  • 请编辑您的问题以改进它。还要解释为什么要迭代堆栈帧......

标签: c linux gcc gdb backtrace


【解决方案1】:

您不能可移植地遍历C99C11 中的堆栈帧。

首先,因为 C 标准中不保证任何 call stack。 (可以想象一些 C 编译器进行整个程序分析并在堆栈无用时避免堆栈,例如,如果不能发生递归;我不知道这样的 C 编译器)。参见例如this C FAQ question 用于奇怪的 C 实现。

然后,因为编译器有时可能会做一些optimizations,例如inline 一些调用(甚至是未标记为inline 的函数,特别是在请求link-time optimizations 并将-flto 传递给gcc 时),或者有时发出tail-calls(并且GCC 可以同时执行这两种操作)。您可以禁用优化,但会损失很多性能。优化的编译器只会将一些变量放在寄存器中,并为多个变量重用一些堆栈槽。

最后,在某些架构(例如 32 位 x86)上,某些代码(特别是某些库代码,例如在 libc 内部)可能会使用 -fomit-frame-pointer 编译,然后没有它就无法获取帧信息.

您可以在GCC 内使用libbacktrace by Ian Taylor;您也可以使用GNU glibc 中的backtrace(3) 函数;您甚至可以在使用GCC 编译时使用可用的return address builtins。但所有这些工具可能不适用于优化代码。

实际上,如果你真的需要一些回溯,要么自己实现(我在我过时的 MELT 系统中实现了,它的 C++ 代码是通过将本地打包到一些本地 struct 中来生成的),或者避免优化太多,例如仅使用 gcc -g -O1 编译。

请注意,backtrace不是system call(在syscalls(2) 中列出)而是glibc 特定的库函数。

请仔细阅读signal(7)sigreturn(2)。可以从信号处理程序(直接或间接)可靠地调用(直接或间接)的(异步信号安全)函数很少,backtrace(或printf不是在其中。在实践中,便携式信号处理程序通常应该设置一些 volatile sigatomic_t 标志,您应该在其他地方进行测试 - 或调用 siglongjmp(3)

【讨论】:

    【解决方案2】:

    当您使用-g 选项时,调试器会使用一组额外的额外数据,这些数据由编译器通过 gcc 放入二进制文件中。回溯调用不使用此数据,仅使用基本链接器信息。这意味着,例如,任何静态数据都不能通过回溯查看,但可以通过 gdb 查看,这也导致各种优化破坏了 gdb 通过显式知识解决的回溯。

    请记住,gdb 是特定于某种语言和编译器的,而 backtrace 更便于移植。

    参见 backtrace http://linux.die.net/man/3/backtrace 的手册页:

    帧指针的省略(正如 gcc(1) 的任何非零优化级别所暗示的那样)可能会导致违反这些假设。

    如果回溯调用想要使用此信息,它将不得不强制您始终使用调试符号进行编译,并且会产生更大的开销和许多其他问题。

    【讨论】:

      【解决方案3】:

      问题可能是, 到执行回溯时,您的堆栈可能已严重损坏。

      只需在函数中获取局部变量的地址。计算堆栈大小。从添加它 局部变量地址并打印在加法和位置变量地址之间的那些;。

      你的堆栈打印出来了 :)

      【讨论】:

        猜你喜欢
        • 2018-08-26
        • 1970-01-01
        • 2014-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-28
        • 2012-10-09
        相关资源
        最近更新 更多