如何 "unwind" gdb 中的核心转储
How to "unwind" a core dump in gdb
我不确定这是否是问题的正确措辞,但让我们以下面的示例为例,我有一个程序将 crash/abort:
#include <assert.h>
int main(void)
{
int z=2;
assert (z>5);
}
如果我通过调试编译它,然后 运行 它:
$ gcc -ggdb3 a.c -o a.o && ./a.o
a.o: a.c:8: main: Assertion `z>5' failed.
Aborted (core dumped)
现在我将在 gdb 中打开它,看看我是否可以检查程序:
$ gdb a.o core
Core was generated by `./a.o'.
Program terminated with signal SIGABRT, Aborted.
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
如果我现在“运行”带有 r
的程序,我会得到这样的东西(来自 gdb-dashboard 查看器):
我的问题是堆栈现在非常深入 C 运行time / linux:
─── Stack ──────────────────────────────────────────────────────────────────────────────────────────
[0] from 0x00007ffff7a22f47 in __GI_raise+199 at ../sysdeps/unix/sysv/linux/raise.c:51
[1] from 0x00007ffff7a248b1 in __GI_abort+321 at abort.c:79
[2] from 0x00007ffff7a1442a in __assert_fail_base+330 at assert.c:92
[3] from 0x00007ffff7a144a2 in __GI___assert_fail+66 at assert.c:101
[4] from 0x00005555555546ce in main+52 at a.c:8
我是否可以将堆栈展开到触发错误的位置:
[4] from 0x00005555555546ce in main+52 at a.c:8
这样我就可以看到当时的寄存器、变量等是什么?另一种表达问题的方式是“在检查核心转储/gdb 时如何忽略代码之外的东西”?
这里有一个尝试:
要向上或向下移动调用堆栈,请使用 up|down
。在这种情况下,我们执行 up 4
以返回到 main
:
>>> up 4
#4 0x000055555555467e in main () at a.c:7
7 assert (z>5);
info frame
和 info locals
可以告诉我们有关函数的高级信息:
>>> info locals
z = 2
__PRETTY_FUNCTION__ = "main"
>>> info frame
Stack level 4, frame at 0x7fffffffe0e0:
rip = 0x55555555467e in main (a.c:7); saved rip = 0x7ffff7a05b97
caller of frame at 0x7fffffffe0c0
source language c.
Arglist at 0x7fffffffe0d0, args:
Locals at 0x7fffffffe0d0, Previous frame's sp is 0x7fffffffe0e0
Saved registers:
rbp at 0x7fffffffe0d0, rip at 0x7fffffffe0d8
例如,鉴于上述情况,我们可以猜测未优化的程序集会将 z
放入 %rbp-4
并且我们可以在那里检查它的值:
>>> x/d $rbp-4
0x7fffffffe0cc: 2
# or, in long-form to ensure our rbp address above from `info` is the same:
>>> x/d 0x7fffffffe0d0-4
0x7fffffffe0cc: 2
我不确定这是否是问题的正确措辞,但让我们以下面的示例为例,我有一个程序将 crash/abort:
#include <assert.h>
int main(void)
{
int z=2;
assert (z>5);
}
如果我通过调试编译它,然后 运行 它:
$ gcc -ggdb3 a.c -o a.o && ./a.o
a.o: a.c:8: main: Assertion `z>5' failed.
Aborted (core dumped)
现在我将在 gdb 中打开它,看看我是否可以检查程序:
$ gdb a.o core
Core was generated by `./a.o'.
Program terminated with signal SIGABRT, Aborted.
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
如果我现在“运行”带有 r
的程序,我会得到这样的东西(来自 gdb-dashboard 查看器):
我的问题是堆栈现在非常深入 C 运行time / linux:
─── Stack ──────────────────────────────────────────────────────────────────────────────────────────
[0] from 0x00007ffff7a22f47 in __GI_raise+199 at ../sysdeps/unix/sysv/linux/raise.c:51
[1] from 0x00007ffff7a248b1 in __GI_abort+321 at abort.c:79
[2] from 0x00007ffff7a1442a in __assert_fail_base+330 at assert.c:92
[3] from 0x00007ffff7a144a2 in __GI___assert_fail+66 at assert.c:101
[4] from 0x00005555555546ce in main+52 at a.c:8
我是否可以将堆栈展开到触发错误的位置:
[4] from 0x00005555555546ce in main+52 at a.c:8
这样我就可以看到当时的寄存器、变量等是什么?另一种表达问题的方式是“在检查核心转储/gdb 时如何忽略代码之外的东西”?
这里有一个尝试:
要向上或向下移动调用堆栈,请使用
up|down
。在这种情况下,我们执行up 4
以返回到main
:>>> up 4 #4 0x000055555555467e in main () at a.c:7 7 assert (z>5);
info frame
和info locals
可以告诉我们有关函数的高级信息:>>> info locals z = 2 __PRETTY_FUNCTION__ = "main" >>> info frame Stack level 4, frame at 0x7fffffffe0e0: rip = 0x55555555467e in main (a.c:7); saved rip = 0x7ffff7a05b97 caller of frame at 0x7fffffffe0c0 source language c. Arglist at 0x7fffffffe0d0, args: Locals at 0x7fffffffe0d0, Previous frame's sp is 0x7fffffffe0e0 Saved registers: rbp at 0x7fffffffe0d0, rip at 0x7fffffffe0d8
例如,鉴于上述情况,我们可以猜测未优化的程序集会将
z
放入%rbp-4
并且我们可以在那里检查它的值:>>> x/d $rbp-4 0x7fffffffe0cc: 2 # or, in long-form to ensure our rbp address above from `info` is the same: >>> x/d 0x7fffffffe0d0-4 0x7fffffffe0cc: 2