重新编译后,Gdb无法找到断言失败位置

时间:2018-02-02 14:38:51

标签: gdb fpic

在我重新编译代码之后,gdb似乎无法找到断言失败的代码位置。更确切地说,相对于断言失败,我预计信号的位置会增加

0x00007ffff7a5ff00 in raise () from /lib64/libc.so.`6

而我获得了

0x00007ffff7a5ff00 in ?? ()

例如,请考虑以下代码

#include <assert.h>

int main()
{
  assert(0);
  return 0;
}

使用调试符号编译并使用gdb进行调试。

> gcc -g main.c
> gdb a.out

在第一次运行gdb时,找到位置,并正确报告回溯:

GNU gdb (Gentoo 8.0.1 p1) 8.0.1 
...
(gdb) r
Starting program: /home/myself/a.out 
a.out: main.c:5: main: Assertion `0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7a5ff00 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff7a5ff00 in raise () from /lib64/libc.so.6
#1  0x00007ffff7a61baa in abort () from /lib64/libc.so.6
#2  0x00007ffff7a57cb7 in ?? () from /lib64/libc.so.6
#3  0x00007ffff7a57d72 in __assert_fail () from /lib64/libc.so.6
#4  0x00005555555546b3 in main () at main.c:5
(gdb)

当我重新编译代码时出现问题。重新编译后,我在同一个gdb实例中发出run命令。 Gdb重新读取符号,从头开始启动程序,但找不到正确的位置:

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
`/home/myself/a.out' has changed; re-reading symbols.
Starting program: /home/myself/a.out 
a.out: main.c:5: main: Assertion `0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7a5ff00 in ?? ()
(gdb) bt
#0  0x00007ffff7a5ff00 in ?? ()
#1  0x0000000000000000 in ?? ()
(gdb) up
Initial frame selected; you cannot go up.
(gdb) n
Cannot find bounds of current function

此时调试器无法使用。一个人不能上去,向前迈进。 作为一种解决方法,我可以手动重新加载文件,并再次找到位置。

(gdb) file a.out
Load new symbol table from "a.out"? (y or n) y
Reading symbols from a.out...done.
(gdb) r
Starting program: /home/myself/a.out 
a.out: main.c:5: main: Assertion `0' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7a5ff00 in raise () from /lib64/libc.so.6
(gdb) 

不幸的是,以这种方式重新加载文件后,gdb无法重置断点。

ERRATA CORRIGE:我在使用gdb 7.12.1重置断点时遇到了问题。升级到8.0.1后,问题就消失了。据说,这与错误修正https://sourceware.org/bugzilla/show_bug.cgi?id=21555有关。但是,无法正确找到断言失败的代码位置。

有没有人知道这里发生了什么?

这在系统更新后开始发生。系统更新将所有系统库(包括glibc)重新编译为与位置无关的代码,即使用-fPIC编译。

另外,我使用的gcc版本是6.4.0

2 个答案:

答案 0 :(得分:0)

这是一种解决方法。由于file正确地重新读取符号,而run没有,我们可以为命令run定义一个钩子,以便在执行file之前执行:{/ p>

define hook-run
  pi gdb.execute("file %s" % gdb.current_progspace().filename)
end

答案 1 :(得分:-1)

在您更改源文件并重新编译之后,您正在生成与加载到GDB的文件不同的文件。

您需要停止正在运行的调试停止并重新加载文件。

您无法将之前定义的断点和文件中的点保存到已更改源,因为gdb实际上是在源中插入其他代码以支持断点和注册商处理程序。

如果更改源,则行为未定义,您需要重置这些断点。

您可以参考gdb手册关于将文件中的断点保存为 Mark Plotnick建议,但是如果你改变文件就行不通(根据我的经验) https://sourceware.org/gdb/onlinedocs/gdb/Save-Breakpoints.html