无法使用GDB进入共享库中的函数

时间:2012-12-18 10:45:11

标签: c++ debugging gdb shared-libraries

我正在尝试调试使用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

my-program-src.cpp的第235行是class DerivedMySharedLib1.so的构造函数调用。

'class Derived'派生自{class 1}}

中的'class Base'

如果我现在步骤,程序将使用SIG SEGV(我正在尝试调试)退出`MySharedLib2.so',即:

MySharedLib2.so

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

Program received signal SIGSEGV, Segmentation fault. 0x0024c2fa in osal::MsgQMsg::id(unsigned int) () from /home/me/build-path/lib/libMySharedLib2.so 提供发生问题的函数的名称,但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

如果我更改Makefile以便构建档案库(即gcc -o /home/me/build-path/lib/libMySharedLib1.so -shared /home/me/build-path/obj/file.o -L/home/me/build-path/lib/ -m32 ),我可以按预期进入功能。

更多信息:

如果我手动尝试从共享库中添加符号,我会得到以下内容:

.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 的相同响应)

如果我可以在共享库中的函数中设置断点,GDB会按预期中断,但是如果我键入add-symbol-file GDB显示主应用程序代码中的调用行(即不在调用函数中的调用函数)共享库)。 GDB不抱怨没有找到源文件。

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

为什么我不能单步执行共享库中的代码?

3 个答案:

答案 0 :(得分:5)

如果共享库没有调试符号/信息,则默认情况下,gdb将跳过它而不是进入它。您可以使用 par(mfrow=c(2,2), ps = 7) par(mar=c(6,4,1,0)) #Plot for Confirmed Tick Data plot(tick1_data$Year, tick1_data$average_cases, main = "a", cex.main = 1/1.14, ## I'm not sure this is giving me 8 point font size ## type = "p", pch = 19, cex = 2, col = '#BF0436', xlab = "", ylab = "Average Confirmed Cases", ylim = c(0,308), bty = "n", xaxt = "n") mtext(side = 1, text = "Year", line = 5) par(bty = "n") axis(side = 1, at = seq(2006, 2017, by = 1), las = 2) rect(2004, -10, 2100, 50, border = NA, col = "#d3d3d365") lines(spline(2005:2017, tick1_data$average_cases, n = 100), col= "#BF0436", lwd = 2) (缩写为stepi)来代替单条指令。我发现.gdbinit文件中的以下命令很有用:

si

定义了命令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来逐步执行单个指令,然后反汇编要运行的下一条指令。尝试通过无调试信息的机器代码进行调试时非常有用。

答案 1 :(得分:1)

这是使用未使用调试语句编译的库通常遇到的问题。通常,gdb将遍历那些函数,而backtrace将仅在库调用的已加载内存中提供一个位置。这是因为没有这些符号,gdb就无法映射。

如果您具有库本身的源代码,请在激活调试标记的情况下重新编译它。根据您要调试的内容,这可能会将时序工件引入分析中。例如,如果您要在数据流传输到的某些缓冲区中调试段错误,则符号的存在会引入足够的等待时间以使缓冲区正确填充。

如果您没有源代码,这将是非常困难的挑战,但在许多情况下并非不可能。如果该库不是 stripped ,则回溯确实会提供足够的信息,以了解发生错误时正在执行哪些功能。这样,您就需要对执行进行反向工程,以便可以检查可用的任何源文件。根据您对ISA的熟悉程度,您可以通过查看组装说明来自己弄清其中一些细节。

最坏的情况是如果库完全被剥离。这是对所有已编译代码进行配对的过程,以便删除其中的所有人类可读(真正的文本字符串)引用。即使没有调试语句,编译器仍将使用函数名称保留标签,但是strip将使用唯一的整数替换标签(它留下了其他内容,但是我认为您可以理解我得到的内容)在这儿)。在这种情况下,gdb甚至无法在回溯中解析函数名。这是您对ISA的了解需要展现的地方,并且是您首次必须经过严格的逆向工程项目,然后才解决错误本身的原因。

在主要的麻烦类别(即,您没有源代码)中,您需要问自己一个重要问题:我负责修复不是我的代码吗?在大多数情况下,应集中精力确保该错误是可重现的,并提交错误报告;让该库的维护者找出来。如果您仍然负责解决整体错误,请集中精力处理可能造成的影响,并对无法解决的问题进行黑框处理;看看是否需要将输入约束到那些库调用,以便可以适当地防止或处理该错误。

答案 2 :(得分:0)

这可能是一个拼写错误,但是当您尝试加载符号时,您使用libMySharedLib2.so2而不是1

在任何情况下,您都应该使用g++来编译和链接c ++代码。此外,主程序不一定是pic,虽然它可能没有伤害。

对我来说如下:

$ 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输出略有编辑)