On Windows, debugger symbols aren't stored side-by-side with the executable data in the same file. They're stored in a .pdb file (short for "program database"). This is especially great if you distribute your program to end-users, but still want to be able to debug any crashes. Just keep the .pdb file somewhere save, and any crash log you get send can easily translated back into source locations.

On Linux, debug symbols are traditionally stored inside the executable, and stripped (using strip(1) ) before distributing. This takes away the possibility to debug any crash, send to you from the stripped executable.

Today I discovered a neat little trick to create something resembling PDBs on Linux, by making use of objcopy(1) . In our example, I already have compiled an executable a.out , which I want to distribute to my users:

$ ls -lah a.out -rwxr-xr-x 1 woot woot 30K May 5 11:26 a.out

As we can see, the executable, with debug symbols, has a size of 30k.

Now we extract the debug symbols into another file, using objcopy(1) :

$ objcopy --only-keep-debug a.out a.out.pdb $ strip a.out

As we can now see, our debug symbols are extracted and removed from a.out :

$ ls -lah . -rwxr-xr-x 1 woot woot 6.3K May 5 11:26 a.out -rwxr-xr-x 1 woot woot 28K May 5 11:25 a.out.pdb

If we now want to debug a.out , however, gdb(1) is telling us it's missing debug information:

$ gdb a.out Reading symbols from a.out...(no debugging symbols found)...done.

We need to attach the .pdb symbols to a.out . This can be achieved by making use of GNUs .gnu_debuglink directives:

$ objcopy --add-gnu-debuglink=a.out.pdb a.out

To confirm it's working, we start gdb(1) , to see whether it can now pick up any symbols:

$ gdb a.out Reading symbols from a.out...Reading symbols from /home/woot/tmp/pdbtest/a.out.pdb...done.

Lovely! Our a.out can now be distributed & debugged with external symbols.

Summary