gdb即使使用-no-pie编译也无法插入断点



我正试图让gdb在Ubuntu 20.04上使用C++程序。我需要的是能够设置一个断点(例如,break main.cpp:3gdb命令(,然后设置run直到断点,但此时startrun都失败了,因为它们";无法插入断点"以及";无法访问内存";。对我来说,gdb即使有非常简单的例子也会失败。这是main.cpp的内容:

#include <iostream>
int main() {
std::cout << "Hello World!";
return 0;
}

我在某个地方发现,使用-no-pie可能有助于让gdb工作(带断点(,所以我通过运行g++ -ggdb3 -no-pie -o main main.cpp来编译程序(我还尝试了-g而不是-ggdb3,以及-fno-PIE而不是-no-pie(。当我尝试使用gdb时,它会抱怨"无法插入断点1":

gdb -q main
Reading symbols from main...
(gdb) start
Temporary breakpoint 1 at 0x1189: file main.cpp, line 3.
Starting program: /tmp/main 
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x1189

没有CCD_ 11的结果是一样的无论有没有-no-pie,唯一改变的是十六进制地址,没有-no-pie,它的低位像0x1189(如上所示(,有-no-pies,它可以是0x401176,但其他一切都完全一样,我一直得到";无法访问地址"处的存储器;在这两种情况下都发出警告

如果我使用starti而不是start,它一开始是有效的,但经过几次nexti迭代后,它会打印出通常的消息";无法插入断点":

gdb -q main
Reading symbols from main...
(gdb) starti
Starting program: /tmp/main 
Program stopped.
0x00007ffff7fd0100 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) nexti
0x00007ffff7fd0103 in ?? () from /lib64/ld-linux-x86-64.so.2
...
(gdb) nexti
Warning:
Cannot insert breakpoint 0.
Cannot access memory at address 0x4
0x00007ffff7fd0119 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) nexti
0x00007ffff7fd011c in ?? () from /lib64/ld-linux-x86-64.so.2
...
(gdb) nexti
Warning:
Cannot insert breakpoint 0.
Cannot access memory at address 0x1c
0x000055555556ca22 in ?? ()
(gdb) nexti
[Detaching after fork from child process 3829827]
...
[Detaching after fork from child process 3829840]
Hello World![Inferior 1 (process 3819010) exited normally]

所以我可以使用nexti,但不能使用next,而且显然不能插入断点。

我尝试了-Wl,-no-pie(通过运行g++ -Wl,-no-pie -ggdb3 -o main main.cpp;添加-no-pie不会更改任何内容(,但此选项会导致一个奇怪的链接器错误:

/usr/bin/ld: cannot find -lgcc_s
/usr/bin/ld: cannot find -lgcc_s
collect2: error: ld returned 1 exit status

当我搜索错误时,我只找到了尝试-no-pie而不是-Wl,-no-pie的建议,没有其他解决方案。由于调试C++程序是一项非常常见的活动,我觉得我错过了一些显而易见的东西,但到目前为止我还没有找到解决方案。

为了更容易理解我使用的确切命令,并明确我没有混淆目录,并显示我使用的g++和gdb的版本,这里是完整的终端日志:

$ ls
main.cpp
$ g++ --version | grep Ubuntu
g++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0
$ g++ -ggdb3 -no-pie -o main main.cpp
$ ls
main  main.cpp
$ gdb --version | grep Ubuntu
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
$ readelf -h main | grep 'Type: .*EXEC'
Type:                              EXEC (Executable file)
$ gdb -q main
Reading symbols from main...
(gdb) start
Temporary breakpoint 1 at 0x401176: file main.cpp, line 3.
Starting program: /tmp/main/main 
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x401176

为了完整性,我在没有-no-pie:的情况下尝试了同样的操作

$ rm main
$ g++ -ggdb3 -o main main.cpp
$ readelf -h main | grep 'Type: .*'
Type:                              DYN (Shared object file)
$ gdb -q main
Reading symbols from main...
(gdb) start
Temporary breakpoint 1 at 0x1189: file main.cpp, line 3.
Starting program: /tmp/main/main 
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x1189

正如您所看到的,使用或不使用-no-pie的唯一区别是内存地址,但问题和警告是相同的。如果没有-no-pie,这可能是意料之中的事,但我不明白如果我使用-no-pie编译,为什么会发生这种情况,以及我还能尝试解决什么问题

这:

g++ -ggdb3 -no-pie -o main main.cpp

应生成非PIE可执行文件。您应该能够通过查看readelf -h main | grep 'Type: .*EXEC'(PIE二进制文件具有ET_DYN类型(来验证它是否为PIE。

此:

Temporary breakpoint 1 at 0x1189: file main.cpp, line 3.

明确地是一个PIE二进制文件(在x86_64Linux上,非PIE二进制程序不会有低于0x40000的任何代码(。

结论:您正在调试错误的二进制文件(例如,您在与正在调试的目录不同的目录中编译main(,您没有说明全部情况。

最新更新