我的可执行文件包含符号表。但似乎堆栈跟踪已被破坏。
如何从该核心获取更多信息?例如,有没有办法检查堆?查看填充堆的对象实例以获取一些线索。无论如何,任何想法都会受到赞赏。
答案 0 :(得分:14)
我是一名生活中的C ++程序员,我遇到过这个问题的次数比我想承认的要多。您的应用程序正在粉碎堆栈中的巨大部分。机会是破坏堆栈的功能也会在返回时崩溃。原因是因为返回地址已被覆盖,这就是GDB的堆栈跟踪混乱的原因。
这是我调试此问题的方法:
1)逐步通过应用程序直到它崩溃。 (查找返回时崩溃的函数。)
2)确定函数后,在函数的第一行声明一个变量:
int canary=0;
(它必须是第一行的原因是该值必须位于堆栈的最顶层。这个“canary”将在函数的返回地址之前被覆盖。)
3)在金丝雀上放一个变量值表,通过函数和金丝雀!= 0,然后你发现你的缓冲区溢出了!另一种可能是它为canary!= 0设置变量断点并且只是正常运行程序,这有点容易,但不是所有IDE的支持变量断点。
编辑:我已经和我办公室的高级程序员交谈,以了解解析内存地址所需的核心转储。找出这些地址的一种方法是查看二进制文件的MAP文件,该文件是人类可读的。以下是使用gcc生成MAP文件的示例:
gcc -o foo -Wl,-Map,foo.map foo.c
这是一个难题,但仍然很难获得崩溃的函数的地址。如果您在现代平台上运行此应用程序,那么ASLR可能会使核心转储中的地址无效。 ASLR的一些实现将随机化二进制的函数地址,这使得核心转储绝对毫无价值。
答案 1 :(得分:4)
ex:gcc -Wall -g -c -o oke.o oke.c
3.确保您还具有-g选项以生成调试信息。您可以使用某些宏调用调试信息。以下宏对我非常有用:
__LINE__
:告诉你
__FILE__
:告诉你源文件
__func__
:告诉你功能
希望这会有所帮助
答案 2 :(得分:2)
TL; DR:函数中非常大的局部变量声明在堆栈上分配,在某些平台和编译器组合中,它可能会溢出并损坏堆栈。
只是为此问题添加另一个潜在原因。我最近调试了一个非常类似的问题。使用应用程序和核心文件运行gdb将产生如下结果:
Core was generated by `myExecutable myArguments'.
Program terminated with signal 6, Aborted.
#0 0x00002b075174ba45 in ?? ()
(gdb)
这是非常无益和令人失望的。经过几个小时的互联网搜索,我找到了一个论坛,讨论了我们使用的特定编译器(英特尔编译器)如何比其他编译器具有更小的默认堆栈大小,并且大型局部变量可能会超出并损坏堆栈。看看我们的代码,我找到了罪魁祸首:
void MyClass::MyMethod {
...
char charBuffer[MAX_BUFFER_SIZE];
...
}
宾果!我发现MAX_BUFFER_SIZE设置为10000000,因此在堆栈上分配了 的10MB局部变量! 在更改实现以使用shared_ptr并动态创建缓冲区后,突然间程序开始完美运作。
答案 3 :(得分:1)
尝试使用Valgrind内存调试器运行。
答案 4 :(得分:1)
要确认,您的可执行文件是否在发布模式下编译,即没有调试符号....这可以解释为什么会有?尝试使用-g
开关重新编译,其中包含调试信息并将其嵌入可执行文件中。除此之外,我不知道为什么你有'??'...
答案 5 :(得分:1)
不是真的。当然,你可以在记忆中挖掘并看看事物。但是如果没有堆栈跟踪,你就不知道你到底在哪里或参数值是什么。
但是,堆栈损坏这一事实告诉您需要查找写入堆栈的代码。
如果你有一个Unix系统,“valgrind”是找到这些问题的好工具。
答案 6 :(得分:0)
我假设您说“我的可执行文件包含符号表”,您使用-g编译和链接,并且您的二进制文件未被剥离。
我们可以确认一下: strings -a | grep function_name_you_know_should_exist
还尝试在核心上使用pstack,看看它是否能更好地获取callstack。在这种情况下,听起来你的gdb与你的gcc / g ++版本相比已经过时了。
答案 7 :(得分:0)
听起来你没有在你的机器上使用相同的glibc版本,就像核心文件在生产时崩溃一样。获取“ldd ./appname”输出的文件并将它们加载到您的机器上,然后告诉gdb在哪里查看;
set solib-absolute-prefix /path/to/libs