Ad

Can GCC Version Script Include Debug Symbols?

When building a shared library with GCC, without using a version script, we can split our debug symbols into separate .dbg files, allowing us to debug into crash dumps.

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

Now, we're exploring using the --version-script option to only export the public functions of our library

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

However, this appears to hide all the symbols (except fooInterface()), including dynamic and static debug symbols.

In many ways this is what we want, but is there any way to get the best of both worlds? 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?

Ad

Answer

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?

The linker version script (it's not a GCC version script) is completely orthogonal to having debug info.

That is: the exact same solution should work: link foo.so with the version script, then use objcopy to save debug info and remove unneeded symbols.

I just tested this on a trivial example, and it works:

$ 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

Observe that only fooInterface is exported from foo.so:

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

Observe that GDB has no trouble loading full symbols for 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();

If above example doesn't work for you, you probably have a buggy version of GDB or binutils.

If the example works, but your real library doesn't, then you are probably making a mistake somewhere during your build process.

Ad
source: stackoverflow.com
Ad