无法与GDB一起进入共享库中的函数

Unable to step into a function in a shared library with GDB

本文关键字:共享 函数 GDB 一起      更新时间:2023-10-16

我正在尝试调试一个使用GDB从多个共享库构建的应用程序。

gdb:启动

prompt$ gdb
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-50.el6)
Copyright (C) 2010 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/>.

告诉GDB要调试的程序:

(gdb) file /home/me/build-path/my-program
Reading symbols from /home/me/build-path/my-program...done.

在应用程序中设置断点:

(gdb) my-program-src.cpp:57
breakpoint 1 at 0x819df9b: file src/my-program-src.cpp, line 57

运行程序:

(gdb) run 
Starting program: /home/me/build-path/my-program

程序在断点处停止,如预期:

Breakpoint 1 MyClass:func(this-0xffffc1c0) at src/my-program-src.cpp:235

CCD_ 1的行235是对处于CCD_ 3中的CCD_ 2的构造函数调用。

"class Derived"派生自MySharedLib2.so中的"class Base">

如果我现在单步执行,程序将在"MySharedLib2.so"中退出,并带有SIG SEGV(这是我试图调试的),即:

Program received signal SIGSEGV, Segmentation fault.
0x0024c2fa in osal::MsgQMsg::id(unsigned int) () from /home/me/build-path/lib/libMySharedLib2.so

GDB没有介入任何一个共享库。

bt给出了发生问题的函数的名称,但list显示了my-program-src.cpp中的代码

所有代码都使用以下选项编译:

gcc -MD -D__LINUX__  -g -Wall -Wextra -Iinc -m32 -fpic -I../../public_inc /home/me/src/file.c -o /home/me/build-path/obj/file.o

共享库与以下选项链接:

gcc -o /home/me/build-path/lib/libMySharedLib1.so -shared /home/me/build-path/obj/file.o -L/home/me/build-path/lib/ -m32

如果我更改Makefiles以构建归档库(即.a),我可以按预期进入函数。

进一步信息:

如果我手动尝试添加共享库中的符号,我会得到以下信息:

(gdb) add-symbol-file  /home/me/build-path/lib/libMySharedLib2.so
The address where /home/me/build-path/lib/libMySharedLib2.so has been loaded is missing

(注意:一旦遇到断点,我就会从add-symbol-file得到相同的响应)

如果我可以在共享库中的函数中设置断点,GDB会按预期中断,但如果我键入my-program-src.cpp0,GDB将在主应用程序代码中显示调用行(即不在共享库内的调用函数)。GDB不会抱怨找不到源文件。

为什么我不能进入我的共享库

为什么我不能遍历共享库中的代码

如果共享库没有调试符号/info,gdb默认情况下会跳过它,而不是进入它。您可以使用stepi(缩写为si)来逐个指令执行。我发现.gdbinit文件中的以下命令很有用:

define sx
si
x /1i $pc
end
document sx
Step one instruction and print next instruction
end
define nx
ni
x /1i $pc
end
document nx
Step one instruction running through calls and print next instruction
end

它定义了命令sx/nx逐指令执行,然后分解下一条要运行的指令。当尝试在没有调试信息的情况下通过机器代码进行调试时非常有用。

这可能是一个拼写错误,但您在尝试加载符号时使用了带有2libMySharedLib2.so,而不是1

在任何情况下,都应该使用g++来编译和链接c++代码。此外,主程序不一定是图片,尽管这可能不会有什么坏处。

它对我的作用如下:

$ cat >lib.h
class Base
{
int _x;
public:
Base(int);
};
class Derived : public Base
{
public:
Derived(int x);
};
$ cat >lib.cpp
#include "lib.h"
Base::Base(int x)
{
_x = *reinterpret_cast<int*>(x);
}
Derived::Derived(int x) : Base(x)
{
}
$ cat >main.cpp
#include "lib.h"
int main(int, char**)
{
Derived d(0);
return 0;
}
$ g++ -shared -fpic -m32 -g -Wall -o libMySharedLib1.so lib.cpp
$ g++ -m32 -g -Wall -L. -l MySharedLib1 main.cpp
$ LD_LIBRARY_PATH=$PWD gdb ./a.out
GNU gdb (GDB) 7.3.50.20111117-cvs-debian
Copyright (C) 2011 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-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from a.out...done.
(gdb) r
Starting program: a.out     
Program received signal SIGSEGV, Segmentation fault.
0xf7fdb552 in Base::Base (this=0xffffd83c, x=0) at lib.cpp:5
5           _x = *reinterpret_cast<int*>(x);
(gdb) bt
#0  0xf7fdb552 in Base::Base (this=0xffffd83c, x=0) at lib.cpp:5
#1  0xf7fdb5ba in Derived::Derived (this=0xffffd83c, x=0) at lib.cpp:8
#2  0x08048591 in main () at main.cpp:5
(gdb) br main
Breakpoint 1 at 0x804857d: file main.cpp, line 5.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: a.out     
Breakpoint 1, main () at main.cpp:5
5           Derived d(0);
(gdb) s
Derived::Derived (this=0xffffd83c, x=0) at lib.cpp:8
8       Derived::Derived(int x) : Base(x)
(gdb) s
Base::Base (this=0xffffd83c, x=0) at lib.cpp:5
5           _x = *reinterpret_cast<int*>(x);

(gdb输出略有编辑)

这是使用未使用调试语句编译的库时通常会遇到的问题。一般来说,gdb将接管这些函数,回溯将只在库调用的加载内存中提供一个位置。这是因为没有这些符号,gdb就没有什么可映射的了。

如果您拥有库本身的源代码,请在激活调试标志的情况下重新编译它。根据您正在调试的内容,这可能会在分析中引入定时工件。例如,如果您正在调试数据流式传输到的某个缓冲区中的segfault,则符号的存在将引入足够的延迟,使缓冲区能够正确填充。

如果您没有源代码,这是非常具有挑战性的,但在许多情况下并非不可能。如果库没有被剥离,那么回溯确实提供了足够的信息来了解发生错误时哪些函数正在执行。这样,您就需要对执行进行反向工程,以便可以查看任何可用的源文件。根据您对ISA的熟悉程度,您可以通过查看组装说明来自己梳理出其中的一些细节。

最坏的情况是库被完全剥离。这是一个将所有编译后的代码配对的过程,以便删除其中所有人类可读的(实际上是文本字符串)引用。即使在没有调试语句的情况下,编译器仍然会留下带有函数名称的标签,但strip会用一个唯一的整数替换这些标签(它留下了其他内容,但我想你可以理解我在这里得到的内容)。在这种情况下,gdb甚至无法解析回溯中的函数名。这就是你对ISA的理解需要闪光的地方,也是你在解决错误本身的原因之前首先必须经过严格的逆向工程项目的时候。

在大麻烦类(也就是说,你没有源代码)中,你需要问自己一个重要的问题:我是否负责修复不是我的代码在大多数情况下,重点确保错误是可复制的,并提交错误报告;让库的维护人员来解决这个问题。如果你仍然有责任修复整个错误,那么关注你能影响的,黑盒你不能;看看是否需要将输入约束到那些库调用,以便适当地防止或处理错误。