【问题标题】:missing call stack frame with assert for gdb 7.6 on macmac 上 gdb 7.6 缺少带有断言的调用堆栈帧
【发布时间】:2014-01-03 17:40:31
【问题描述】:

当调试一个断言失败的程序时,我无法在 gdb 中获取调用堆栈。我在 Mavericks 上使用 Homebrew 的 g++4.8 和 gdb。

/usr/local/bin/g++-4.8 --version 
g++-4.8 (GCC) 4.8.2
/usr/local/bin/gdb --version
GNU gdb (GDB) 7.6.2

这是重构问题的最小测试

//test.cpp
#include <iostream>
#include <cassert>
int main()
{
  int i = 42;
  std::cout << "Hello World!" << i << std::endl;
  assert(0); // this also happens with abort() which assert(0) winds up calling
}

编译和使用

/usr/local/bin/g++-4.8 -g -c test.cpp -o test.o
/usr/local/bin/g++-4.8 -g test.o -o test       
/usr/local/bin/gdb test                        
(gdb) r
Starting program: /Users/pmelsted/tmp/test/test 
Hello World!42
Assertion failed: (0), function main, file test.cpp, line 7.

Program received signal SIGABRT, Aborted.
0x00007fff9447d866 in ?? ()
(gdb) where
#0  0x00007fff9447d866 in ?? ()
#1  0x00007fff9229835c in ?? ()
#2  0x0000000000000000 in ?? ()

【问题讨论】:

  • 我在不同的操作系统(Ubuntu 12.04,32 位)上按照您的步骤操作,无法重现该问题;很正常的堆栈转储。我必须承认这是 g++ (4.6.3) 和 gdb (7.4-2012.04) 的旧版本。只是一个想法:您是否尝试过选项-ggdb
  • -ggdb 在这里没有区别。我的感觉是,这与 mac 相关,因为任何如此简单的东西都无法通过 linux 上的测试。
  • 请检查您的可执行文件是否包含调试信息,按照此线程中的说明进行操作:stackoverflow.com/questions/8390881/… 关闭所有优化并尝试使用不同的调试选项和格式(-gdwarf-2-gstabs-gsplit-dwarf 等);见gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html
  • 这些选项都没有任何区别。 mac 上的 nm 程序没有 --debug-sym 选项。调试时,我可以单步调试并查看源代码,甚至打印变量的值,只是断言失败。
  • 这个本地安装的 gcc 是否带有自己的 libstdc++.so,还是使用操作系统提供的那个?那个库是用调试信息编译的吗?

标签: c++ macos gdb


【解决方案1】:

MacOS 上的 gdb 似乎无法正确显示 64 位程序的调用堆栈(或者调用堆栈在 assert() 函数调用后损坏)。这是程序稍作修改:

//test.cpp
#include <iostream>
#include <cassert>

int foo() {
        assert(0);
}
int bar() {
        return foo();
}
int main()
{
        int i = 42;
        std::cout << "Hello World!" << i << std::endl;
        return bar();
}

我已调用 g++ -g 15.cpp -m32 命令编译它并在 ggdb 下运行它。 bt full 命令显示调用堆栈如下:

(gdb) bt full
#0  0x9843f952 in ?? ()
No symbol table info available.
#1  0x96193340 in ?? ()
No symbol table info available.
#2  0x9615e43e in ?? ()
No symbol table info available.
#3  0x0000216f in foo () at 15.cpp:6
No locals.
#4  0x0000217b in bar () at 15.cpp:9
No locals.
#5  0x000021e4 in main () at 15.cpp:15
        i = 42
(gdb) quit

因此,所有调试符号都正确显示,前 3 个函数地址已更正并且没有名称,因为我的 libgcc 处于发布模式。

如果编译时不使用-m32键,调用栈如下:

(gdb) bt full
#0  0x00007fff8b442866 in ?? ()
No symbol table info available.
#1  0x00007fff8c64735c in ?? ()
No symbol table info available.
#2  0x0000000000000000 in ?? ()
No symbol table info available.

那肯定是调用栈错误,#2帧函数地址是0x0。因此,根本原因是 gdb 无法正确显示 64 位应用程序的调用堆栈。

【讨论】:

  • 知道根本原因很棒,谢谢!有谁知道是否有办法解决它?我宁愿不要在 32 位中进行所有调试。
【解决方案2】:

我找到了解决此问题的方法。只需在 gdb 中将断点设置为 abort() 函数即可:

b abort

然后当 assert 被调用时,它将在断点处停止,此时可以看到带有bt 的调用堆栈。

【讨论】:

    猜你喜欢
    • 2015-11-07
    • 2021-05-02
    • 1970-01-01
    • 2011-01-18
    • 2012-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    相关资源
    最近更新 更多