重新编译后gdb找不到断言失败位置
Gdb cannot find assertion failure positions after recompiling
在我重新编译我的代码后,gdb 似乎无法找到断言失败的代码位置。更准确地说,我希望信号 raise 相对于断言失败的位置是
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的第一个运行上,找到位置,正确报回backtrace:
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 实例中发出 运行 命令。 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
在您更改 源文件并重新编译后,您生成的文件与加载到 GDB 的文件不同。
您需要停止 运行 调试并重新加载文件。
您不能将文件中先前定义的断点和观察点保存到 已更改 源,因为 gdb 实际上是在您的源中插入额外的代码以支持断点和注册器处理程序。
如果您更改源代码,则行为未定义,您需要重置这些断点。
关于在文件中保存断点可以参考gdb手册
Mark Plotnick 建议,但如果您更改文件(根据我的经验),它将不起作用
https://sourceware.org/gdb/onlinedocs/gdb/Save-Breakpoints.html
这是一个解决方法。由于 file
重新正确读取符号,而 run
没有,我们可以为命令 run
定义一个挂钩,以便在 file
之前执行:
define hook-run
pi gdb.execute("file %s" % gdb.current_progspace().filename)
end
在我重新编译我的代码后,gdb 似乎无法找到断言失败的代码位置。更准确地说,我希望信号 raise 相对于断言失败的位置是
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的第一个运行上,找到位置,正确报回backtrace:
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 实例中发出 运行 命令。 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
在您更改 源文件并重新编译后,您生成的文件与加载到 GDB 的文件不同。
您需要停止 运行 调试并重新加载文件。
您不能将文件中先前定义的断点和观察点保存到 已更改 源,因为 gdb 实际上是在您的源中插入额外的代码以支持断点和注册器处理程序。
如果您更改源代码,则行为未定义,您需要重置这些断点。
关于在文件中保存断点可以参考gdb手册 Mark Plotnick 建议,但如果您更改文件(根据我的经验),它将不起作用 https://sourceware.org/gdb/onlinedocs/gdb/Save-Breakpoints.html
这是一个解决方法。由于 file
重新正确读取符号,而 run
没有,我们可以为命令 run
定义一个挂钩,以便在 file
之前执行:
define hook-run
pi gdb.execute("file %s" % gdb.current_progspace().filename)
end