如何 "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 时如何忽略代码之外的东西”?

这里有一个尝试:

  1. 要向上或向下移动调用堆栈,请使用 up|down。在这种情况下,我们执行 up 4 以返回到 main:

    >>> up 4
    #4  0x000055555555467e in main () at a.c:7
    7           assert (z>5);
    
  2. info frameinfo 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
    
  3. 例如,鉴于上述情况,我们可以猜测未优化的程序集会将 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