为什么在使用单独的调试符号文件时gdb“无法计算CFA”?

bar*_*ryd 3 c debugging gcc gdb

我正在尝试通过运行剥离的可执行文件生成的核心转储,使用剥离的可执行文件和单独的调试符号文件调用gdb。

但是,当我使用单独的调试符号文件时,gdb无法为我提供有关局部变量的信息。

这是完整显示我如何生成3个ELF文件和核心文件,然后在gdb中运行它们3次的日志。

  1. 首先,我只使用剥离后的可执行文件运行gdb,当然看不到任何文件名或行号,也无法检查变量。

  2. 然后,我使用剥离的可执行文件运行gdb,并从原始的未剥离的可执行文件中获取调试符号。这工作得很好,但是确实给出了有关内核和可执行文件可能不匹配的令人不安且显然毫无根据的警告。

  3. 最后,我使用剥离的可执行文件和单独的调试文件运行gdb。它仍然提供文件名和行号,但是我无法检查局部变量,并且收到“无法为此帧计算CFA”错误。

这是日志:

2016-09-16 16:01:45 barry@somehost ~/proj/segfault/segfault
$ cat segfault.c
#include <stdio.h>
int main(int argc, char **argv) {
    char *badpointer = (char *)0x2398723;
    printf("badpointer: %s\n", badpointer);
    return 0;
}

2016-09-16 16:03:31 barry@somehost ~/proj/segfault/segfault
$ gcc -g -o segfault segfault.c

2016-09-16 16:03:37 barry@somehost ~/proj/segfault/segfault
$ objcopy --strip-debug segfault segfault.stripped

2016-09-16 16:03:40 barry@somehost ~/proj/segfault/segfault
$ objcopy --only-keep-debug segfault segfault.debug

2016-09-16 16:03:43 barry@somehost ~/proj/segfault/segfault
$ ./segfault.stripped
Segmentation fault (core dumped)

2016-09-16 16:03:48 barry@somehost ~/proj/segfault/segfault
$ ll /tmp/core.segfault.stripp.11
-rw------- 1 barry bsm-it 188416 2016-09-16 16:03 /tmp/core.segfault.stripp.11

2016-09-16 16:03:51 barry@somehost ~/proj/segfault/segfault
$ gdb ./segfault.stripped /tmp/core.segfault.stripp.11
GNU gdb (GDB) Fedora (7.0.1-50.fc12)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/barry/proj/segfault/segfault/segfault.stripped...(no debugging symbols found)...done.

warning: core file may not match specified executable file.
Missing separate debuginfo for
Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/a6/8dce9115a92508af92ac4ccac24b9f0cc34d71
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./segfault.stripped'.
Program terminated with signal 11, Segmentation fault.
#0  0x00000035fec47cb7 in vfprintf () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.11.2-3.x86_64
(gdb) bt
#0  0x00000035fec47cb7 in vfprintf () from /lib64/libc.so.6
#1  0x00000035fec4ec4a in printf () from /lib64/libc.so.6
#2  0x00000000004004f4 in main ()
(gdb) up
#1  0x00000035fec4ec4a in printf () from /lib64/libc.so.6
(gdb) up
#2  0x00000000004004f4 in main ()
(gdb) p argc
No symbol table is loaded.  Use the "file" command.
(gdb) q

2016-09-16 16:04:19 barry@somehost ~/proj/segfault/segfault
$ gdb -q -e ./segfault.stripped -s ./segfault -c /tmp/core.segfault.stripp.11
Reading symbols from /home/barry/proj/segfault/segfault/segfault...done.

warning: core file may not match specified executable file.
Missing separate debuginfo for
Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/a6/8dce9115a92508af92ac4ccac24b9f0cc34d71
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./segfault.stripped'.
Program terminated with signal 11, Segmentation fault.
#0  0x00000035fec47cb7 in vfprintf () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.11.2-3.x86_64
(gdb) bt
#0  0x00000035fec47cb7 in vfprintf () from /lib64/libc.so.6
#1  0x00000035fec4ec4a in printf () from /lib64/libc.so.6
#2  0x00000000004004f4 in main (argc=1, argv=0x7fffd1c0a728) at segfault.c:4
(gdb) up
#1  0x00000035fec4ec4a in printf () from /lib64/libc.so.6
(gdb) up
#2  0x00000000004004f4 in main (argc=1, argv=0x7fffd1c0a728) at segfault.c:4
4       printf("badpointer: %s\n", badpointer);
(gdb) p argc
$1 = 1
(gdb) q

2016-09-16 16:04:39 barry@somehost ~/proj/segfault/segfault
$ gdb -q -e ./segfault.stripped -s ./segfault.debug -c /tmp/core.segfault.stripp.11
Reading symbols from /home/barry/proj/segfault/segfault/segfault.debug...done.

warning: core file may not match specified executable file.
Missing separate debuginfo for
Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/a6/8dce9115a92508af92ac4ccac24b9f0cc34d71
Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib64/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
Core was generated by `./segfault.stripped'.
Program terminated with signal 11, Segmentation fault.
#0  0x00000035fec47cb7 in vfprintf () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.11.2-3.x86_64
(gdb) bt
#0  0x00000035fec47cb7 in vfprintf () from /lib64/libc.so.6
#1  0x00000035fec4ec4a in printf () from /lib64/libc.so.6
#2  0x00000000004004f4 in main (argc=can't compute CFA for this frame
) at segfault.c:4
(gdb) up
#1  0x00000035fec4ec4a in printf () from /lib64/libc.so.6
(gdb) up
#2  0x00000000004004f4 in main (argc=can't compute CFA for this frame
) at segfault.c:4
4       printf("badpointer: %s\n", badpointer);
(gdb) p argc
can't compute CFA for this frame
(gdb) q
Run Code Online (Sandbox Code Playgroud)

我对此有一些疑问:

  1. 即使我使用与最初生成核心转储时使用的完全相同的可执行路径,为什么它仍显示警告“警告:核心文件可能与指定的可执行文件不匹配。”?
  2. 为什么在尝试检查局部变量时使用单独的调试符号(-s ./segfault.debug)导致错误“无法为该帧计算CFA”?

什么是CFA?

我使用错误的方法来生成调试符号文件吗?我确认使用“ objcopy --strip-debug”可以得到与“ strip -g”相同的结果。我是否使用正确的选项将调试信息输入gdb?

我的意图是将剥离的可执行文件安装在二进制兼容的生产系统上,并且由于段错误而产生的任何核心转储都可以复制回devel系统,在其中我们可以将它们与调试信息一起馈入gdb并分析崩溃位置并堆栈变量。但是作为第一步,我试图通过在开发系统上使用单独的调试信息文件来解决问题。

看起来,即使不使用核心文件,使用单独的调试符号文件也会导致“无法为此帧计算CFA”错误。

我的gcc版本:

2016-09-16 16:07:39 barry@somehost ~/proj/segfault/segfault
$ gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.4 20100630 (Red Hat 4.4.4-10) (GCC)
Run Code Online (Sandbox Code Playgroud)

我怀疑当objcopy实际上只将它们放在segfault.stripped文件中时,gdb可能正在寻找与segfault.debug文件中的变量相关的符号。如果是这种情况,也许对objcopy选项进行一些小的调整就可以将这些符号放在gdb所要查找的位置?

Rol*_*Kau 6

我赞扬您希望为部署到生产服务器的所有内容保留一组符号文件;我认为这是一种经常被忽视的做法,但您不会后悔-有一天它将为您节省很多调试麻烦。

由于过去我也遇到过类似的问题,尽管您的工具链非常古老,但我会尝试回答您的一些问题,如果您不介意我这么说,那么我不确定在这里实际适用的程度是多少。我还是会放在这里。

CFA =规范框架地址。这是指向每个局部变量相对的堆栈帧的基本指针。如果您已经完成了一些传统的x86汇编编程,则使用BP寄存器。因此,“无法为此帧计算CFA”基本上是“我知道这些局部变量,但不知道它们在堆栈中的位置”。

GDB中曾经有一些代码仅适用于DWARF-2调试格式,而不一致则至少触发了此特定错误。该限制是在不久前取消的,但您的版本中将不会进行更改。

另一件事是,存在关于调试变量的信息,调试信息并不总是生成的。不过,这通常会在较新的编译器中发生,因为它们会更好地进行优化。

通过这样的编译,我可以摆脱我的问题:

gcc -g3 -gdwarf-2 -fvar-tracking -fvar-tracking-assignments -o segfault segfault.c
Run Code Online (Sandbox Code Playgroud)

您也可以尝试看看这是否也解决了您的问题。

关于符号文件位置的消息;似乎调试器希望从系统目录中加载它。也许您必须使用以下命令将可执行文件链接到符号文件:

objcopy --add-gnu-debuglink=segfault.debug segfault
Run Code Online (Sandbox Code Playgroud)