为什么 GDB 在遇到 `main` 之前不能解析这个符号?为什么 valgrind 根本无法解决它?

Why can't GDB resolve this symbol until it hits `main`? Why can't valgrind resolve it at all?

我正在尝试 an Valgrind 无法解析通过某些库传递的函数的符号。我得到这样的输出:

==83597== 920 bytes in 1 blocks are possibly lost in loss record 750 of 864
==83597==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==83597==    by 0x548EF93: myproject_malloc (mysourcefile.c:48)
==83597==    by 0x4F13FD5: ??? (in /path/to/project/library-version.so)
==83597==    by 0x54542FF: ??? (in /path/to/project/library-version.so)
==83597==    by 0x4F536CA: ??? (in /path/to/project/library-version.so)
==83597==    by 0x54542FF: ??? (in /path/to/project/library-version.so)

library-version.so 中的一个函数是 do_init()library-version.so 通过 LD_PRELOAD 加载。我发现当我 运行 我的程序在 gdb 下时,如果我试图在 do_init 处设置一个断点,一旦我启动程序,它会抱怨找不到符号,但是如果我在 main 处放置一个断点并等待它到达那个点,那么它就会起作用。

例如:

(gdb) break do_init
Function "do_init" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) break main
Breakpoint 1 at 0x400b50: file runner.c, line 13.
(gdb) run
... a bunch of output from the stuff in LD_PRELOAD ...
Breakpoint 1, main (argc=1, argv=0x7fffffffe028) at myprogram.c:13
13      return do_some_stuff();
(gdb) break do_init
Breakpoint 2 at 0x7ffff7658de0: file my/library/initializer.c, line 25.

所以这引出了两个问题:

  1. do_init 似乎被动态链接器引入了。我怎样才能找出发生在初始化过程的哪一步?这个项目中使用了许多库,这些库使用 __attribute__((constructor)) 定义函数,并且它们与链接器脚本粘合在一起。

  2. 为什么 Valgrind 不能像 GDB 那样看到动态链接器加载的符号?我 99% 确定没有任何东西被 dlclose'd,而且我认为 LD_PRELOAD 下的任何东西无论如何都会对 Valgrind 可见。

事实证明,由于恰好同时出现了一大堆奇怪的配置选项,library-version.so 的程序部分 header 包含了 .text部分被标记为 rwx 权限而不是 r-x 权限。 Valgrind 认为 .text 节在 amd64 机器上不能有 rwx 权限,所以它在尝试加载调试符号时忽略它们。

我认为这是 Valgrind 中的一个错误,因为 .text 具有 rwx 权限的部分根据相关标准是完全有效的;事实证明,已经有一份报告 filed here,我对此进行了扩展。