GCC 版本脚本可以包含调试符号吗?

Can GCC version script include debug symbols?

在使用 GCC 构建共享库时,无需使用版本脚本,我们可以将调试符号拆分为单独的 .dbg 文件,从而允许我们调试到故障转储中。

objcopy --only-keep-debug foo.so foo.dbg
objcopy --strip-unneeded foo.so
objcopy --add-gnu-debuglink=foo.dbg foo.so

现在,我们正在探索使用 --version-script 选项仅导出我们库的 public 函数

{
    global:
        extern "C" {
            fooInterface*;
        };
    local: *;
};

但是,这似乎隐藏了所有 符号(fooInterface() 除外),包括动态和静态调试符号。

在很多方面这就是我们想要的,但是有什么方法可以两全其美吗?是否有可能以仅导出 public 函数的共享库结束,同时仍然能够使用单独的 .dbg 文件调试故障转储?

Is it possible to end up with a shared library that only exports the public functions, while still being able to debug into crash dumps with a separate .dbg file?

linker 版本脚本(它不是 GCC 版本脚本)完全与调试信息正交。

即:完全相同的解决方案 应该工作:link foo.so 与版本脚本,然后使用 objcopy 保存调试信息并删除不需要的符号。

我刚刚在一个简单的例子上对此进行了测试,它有效:

$ cat foo.c
int bar()
{
  return 42;
}

int fooInterface()
{
  return bar();
}

$ gcc -g -fPIC -shared -o foo.so foo.c -Wl,--version-script=foo.lds 
$ objcopy --only-keep-debug foo.so foo.dbg
$ objcopy --strip-unneeded foo.so
$ objcopy --add-gnu-debuglink=foo.dbg foo.so

观察到只有 fooInterfacefoo.so 导出:

$ nm foo.so | grep ' T '
nm: foo.so: no symbols
$ nm -D foo.so | grep ' T '
0000000000001100 T fooInterface

观察到 GDB 加载 full 符号没有问题 foo.so:

$ gdb -q ./foo.so
Reading symbols from ./foo.so...
Reading symbols from /tmp/vs/foo.dbg...    <<<=== Note

(gdb) info func bar
All functions matching regular expression "bar":

File foo.c:
1:      int bar();

如果上面的例子对你不起作用,你可能有一个有问题的 GDB 或 binutils 版本。

如果示例有效,但您的真实库没有,那么您可能在构建过程中的某个地方犯了错误。