独立共享库运行时,gdb无法加载符号

4
我有一个PIC共享库,它也有一个main函数。
#include <dtest2.h>
#include <stdio.h>
extern const char elf_interpreter[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";

int dtestfunc1(int x,int y) {
  int i=0;
  int sum = 0;
  for(i=0;i<=x;i++) {
    sum+=y;
    sum+=dtestfunc2(x,y);

  }
  return sum;
}

int main (int argc, char const* argv[])
{
  printf("starting sharedlib main\n");
  int val = dtestfunc1(4,5);
  printf("val = %d\n",val);
  _exit(0);
}

这个库链接了另一个共享库libdtest2,它实现了从dtestfunc1调用的dtestfunc2
如果我直接在dtestfunc1上运行gdb,
gdb libdtest1.so

在gdb中,libdtest2.so的符号没有被加载。因此,我无法进入dtestfunc1,如果我按s,函数就会执行并退出。

如果我创建一个驱动程序,在共享库上调用dlopen,那么在执行dlopen后,gdb会正确加载符号,一切正常。

  1. 为什么gdb在这两种情况下的行为不同?
  2. 如果我直接在共享库上运行gdb,如何手动指向共享库?

注意:这只是一个玩具示例,反映了我在一个更大的共享库中遇到的问题。所有的二进制文件和库都使用-ggdb3标志编译。

编辑:我的共享库是可运行的。我在源代码中使用extern定义添加了适当的解释器路径。我使用gcc -ggdb3 -O0 -shared -Wl,-soname,libdtest1.so.1 -ldtest2 -L/usr/lib -Wl,-e,main -o libdtest1.so.1.0 dtest1.o编译它。我可以运行它,并且它能够完美地执行。在这里,运行共享库不是问题所在。


我的gdb有点生疏,但是手动执行的命令是“file”(问题#2)。如果是这样,你可以使用“.gdbinit”文件来使它更容易。 - donjuedo
2个回答

6
为什么 gdb 在这两种情况下表现不同?
因为您没有正确构建 libdtest1.so,以便 GDB 可以与其一起使用。
具体来说,您的 libdtest1.so 在其动态部分中缺少 DT_DEBUG 条目,您可以执行以下操作进行确认:
readelf -d libdtest1.so | grep DEBUG

你不应该看到任何东西。在一个正确构建的可运行的libdtest1.so中(你可以使用-pie标志来构建它),输出应该是这样的:
 0x00000015 (DEBUG)                      0x0

运行时加载程序将DT_DEBUG更新为其r_debug结构的指针,这允许GDB找到其他已加载的共享库。如果没有DT_DEBUG,GDB将找不到它们。
术语:这不是一个DEBUG部分。它是.dynamic部分中的DT_DEBUG条目。
由于-shared覆盖了-pie,因此它仍然缺失。请从链接行中删除-shared
您也不需要-Wl,-e,main,也不需要指定.interp——GCC会为您执行此操作。
正确的链接命令:
gcc -ggdb3 -O0 -pie -rdynamic dtest1.c -I. -Wl,-soname,libdtest1.so.1 \
  -L/usr/lib -ldtest2 -o libdtest1.so.1.0

链接行中源和库的顺序很重要,你的顺序是错误的。

额外的好处是,现在你的主函数将收到正确的 argcargv[] 值,而不是虚假的值。


我已确保我的库是可运行的。我可以运行它,它不会崩溃。我使用gcc -ggdb3 -O0 -shared -Wl,-soname,libdtest1.so.1 -ldtest2 -L/usr/lib -Wl,-e,main -o libdtest1.so.1.0 dtest1.o进行编译。顺便说一句,如果程序在运行时立即崩溃,为什么要问关于gdb未能进入函数的问题呢? - woodstok
@MIkhail 我已经更新了答案。“为什么我会问一个问题…”我不知道。为什么你会问一个问题并省略回答它所需的必要细节(构建命令)? - Employed Russian
我明白了。抱歉。 - woodstok
在添加了饼图标志后,我的构建命令是 gcc -ggdb3 -O0 -pie -shared -Wl,-soname,libdtest1.so.1 -ldtest2 -L/usr/lib -Wl,-e,main -o libdtest1.so.1.0 dtest1.c -I. 。调试部分仍然缺失。有任何想法为什么它仍然缺失? - woodstok
谢谢。现在so文件已经有了DT_DEBUG部分 :) :)。但是我现在不能将共享库与其他二进制文件链接起来。当我使用-ldtest1标志连接时,它会给出“undefined reference to dtestfunc1”的错误提示。 - woodstok
显示剩余2条评论

0

简单的解决方法是......使用(对于gcc)参数“-ggdb”重新编译库,然后gdb将拥有所有可用的符号。


所有二进制文件都使用-ggdb编译。 - woodstok
1
那是一个完全错误的答案。 - Employed Russian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接