How to gdb with split debug files

So I have:

[profile.release]
split-debuginfo = "packed"
strip = true
debug = "full"

and cargo build --release produces a small binary and a big dwp file. So far so good.

So let's try to debug:

> gdb target/release/flakebox
GNU gdb (GDB) 13.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from target/release/flakebox...
(No debugging symbols found in target/release/flakebox)
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts
of file /home/dpc/lab/flakebox/target/release/flakebox.
Use `info auto-load python-scripts [REGEXP]' to list them.
(gdb) symbol-file target/release/flakebox.dwp
Reading symbols from target/release/flakebox.dwp...
(No debugging symbols found in target/release/flakebox.dwp)

And I don't seem to be able to actually load the symbols in the dwp. Is this some limitation or am I doing something wrong?

strip = "true" will strip all debuginfo, including those parts that are used by split dwarf to tie back the .dwo/.dwp files back to the executable. Unlike with gcc fission debuginfo (which is what linux distros generally), for split dwarf the external debuginfo file doesn't contain direct addresses, but references to debuginfo stubs inside the executable itself and thuse stubs then contain the actual addresses. The advantage of this is that the vast majority of the debuginfo isn't passed through the linker, making linking faster. The disadvantage is that the executables are bigger due to the mandatory debuginfo sections.

1 Like

From my observations:

DWARF split debug file (*.dwp or *.dwo) requires some debuginfo still intact in the final executable. Unfortunately, cargo seems to work just two ways:

  • either guts debuginfo completely (strip=true, strip="debuginfo" or strip="symbols"), rendering executable unusable for dwp file
  • or doesn't process at all (strip=false), making dwp file unnecessary, as executable contains everything within.

To work correctly, it would need dedicated stripping level between false and "debuginfo".

I managed to generate proper GNU (that's other than DWARF s.d.i) split debug info (with strip=false and debug = "full") with the following tiny script:

#!/bin/sh

if [ ! -x "$1" ]; then
   echo "USAGE: $0 EXECUTABLE_FILE"
   exit 1
fi

BASE="$1"
DBG="${BASE}.debug"

objcopy --only-keep-debug "${BASE}" "${DBG}"
objcopy --strip-debug --strip-unneeded --remove-section=".gnu_debuglink" --add-gnu-debuglink="${DBG}" "${BASE}"

EDIT: In the meantime @bjorn3 precised dwp wherabaouts.

strip=false + split-debuginfo=packed will put all debuginfo that can be put in the separate debuginfo file in the separate debuginfo file. The only thing strip could remove is the debuginfo that needs to be kept in the executable for split dwarf to keep working.

(To be fair, it does keep the full libstd debuginfo unless the standard library is recompiled with split-debuginfo=packed, but that isn't included in the split debuginfo file anyway so stripping that would break debugging too.)

1 Like

Thanks for clearing that up.

So I have (for default helloworld source of cargo new) :

  • strip=false + split-debuginfo=packed = 1,2M exec + 938k dwp
  • strip=false + no split whatsoever: = 2,1M exec
  • strip=false + manual split = 329K exec + 1,8M debug

Sums are ~constant, just split point moves (well, as expected, duh).