Home / Alt manpages / dwp(1)

  • dwp(1)
  • User command
  • linux

Package split DWARF files with dwp without losing the build evidence

You will combine compiler-generated split DWARF files into one .dwp package, inspect the result, and verify it against an executable when the executable's debug references are ready. This guide uses GNU dwp from Ubuntu Binutils 2.42, supplied by Binutils packages version 2.42-4ubuntu2.10 on this machine.

Allow about fifteen minutes. You need a shell, dwp, a compiler that can produce split DWARF, and writable build space. The workflow is unprivileged. Do not use sudo: the output is a build artefact, not a system file.

1. Confirm the installed tool

Check the command and its version before putting it into a build script:

$ command -v dwp
/usr/bin/dwp
$ dwp --version
GNU dwp (GNU Binutils for Ubuntu) 2.42
$ dpkg-query -W -f='${Package} ${Version}\n' binutils-common
binutils-common 2.42-4ubuntu2.10

The three installed manpages for dwp, aarch64-linux-gnu-dwp and x86_64-linux-gnu-dwp describe the same option set. The target-prefixed names are useful when a cross-toolchain is selected explicitly; the operation below is otherwise the same.

Checkpoint

If dwp --version does not report the version you tested, stop and check that your build is using the intended toolchain.

2. Produce split DWARF files

GCC's -gsplit-dwarf leaves the normal object file alongside a separate .dwo file. This small example creates two independent compilation units:

$ build_dir=$(mktemp -d /tmp/dwp-build.XXXXXX)
$ printf '%s\n' 'int one(void) { return 1; }' > "$build_dir/one.c"
$ printf '%s\n' 'int two(void) { return 2; }' > "$build_dir/two.c"
$ gcc -gsplit-dwarf -g -O0 -c "$build_dir/one.c" -o "$build_dir/one.o"
$ gcc -gsplit-dwarf -g -O0 -c "$build_dir/two.c" -o "$build_dir/two.o"
$ find "$build_dir" -maxdepth 1 -type f -printf '%f\n' | sort
one.c
one.dwo
one.o
two.c
two.dwo
two.o

The .dwo files contain the split debug information. Keep them with the matching objects until packaging is complete. A missing or stale .dwo cannot be reconstructed from the source file by dwp.

3. Combine the .dwo files explicitly

Give -o the package name and list the inputs. This is the clearest form for a build system because the input set is visible in the command:

$ dwp -o "$build_dir/debug.dwp" \
    "$build_dir/one.dwo" "$build_dir/two.dwo"
$ file "$build_dir/debug.dwp"
/tmp/dwp-build.xxxxx/debug.dwp: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), stripped
$ readelf -S "$build_dir/debug.dwp" | grep -E '\.debug_(abbrev|line|str|cu_index|tu_index)'
  [ 1] .debug_abbrev.dwo
  [ 2] .debug_line.dwo
  [ 3] .debug_str_offsets.dwo
  [ 4] .debug_str.dwo
  [ 5] .debug_cu_index
  [ 6] .debug_tu_index

The temporary directory suffix and section numbering can differ. The useful checks are a successful exit, a non-empty relocatable ELF file, and DWARF sections including the CU and TU indexes. dwp does not produce a human-readable report by default.

For a build log, add -v. It prints the input paths while creating the package:

$ dwp -v -o "$build_dir/debug.dwp" \
    "$build_dir/one.dwo" "$build_dir/two.dwo"
/tmp/dwp-build.xxxxx/one.dwo
/tmp/dwp-build.xxxxx/two.dwo

4. Verify a package against an executable

--verify-only checks a package against an executable. With -e, pass the executable and name the package with -o:

$ dwp --verify-only -e /path/to/program \
    -o /path/to/program.dwp
$ printf 'verification status: %s\n' "$?"
verification status: 0

A non-zero status means the package could not be opened or did not satisfy the executable's references. Capture the status immediately. If you omit -o, dwp looks for the default name EXE.dwp, where EXE is the path passed to -e. That default is convenient only when your build deliberately uses it.

Safety boundary

Verification reads the files, but creating the package can overwrite an existing destination. Use a new name or a temporary output, then replace the published artefact only after the command succeeds:

$ dwp -o "$build_dir/debug.dwp.new" \
    "$build_dir/one.dwo" "$build_dir/two.dwo"
$ test -s "$build_dir/debug.dwp.new"
$ mv "$build_dir/debug.dwp.new" "$build_dir/debug.dwp"

If packaging fails, the old debug.dwp remains in place. Remove an abandoned .new file only after checking that no later command still needs it.

5. Use automatic discovery carefully

The alternative -e EXE form asks dwp to obtain the list of .dwo files from the executable and defaults the output to EXE.dwp:

$ dwp -e /path/to/program
$ test -s /path/to/program.dwp
$ printf 'package exists: %s\n' "$?"
package exists: 0

This is shorter, but it hides the input list and depends on correct split-DWARF references, matching files and the behaviour of the installed release. On this Ubuntu 2.42 build, a minimal GCC-produced executable triggered a segmentation fault during local testing of this path. Treat that as a toolchain defect, not as a reason to discard debug files. Prefer the explicit .dwo list for reproducible builds, and report the failing command with dwp --version if discovery crashes.

6. Diagnose common failures

  • No output file specified: add -o /path/to/package.dwp when supplying individual .dwo files. The input-only form cannot choose a destination.
  • Cannot open an input: check the exact path with ls -l /path/to/file.dwo. Do not substitute an object file for a missing .dwo.
  • Verification cannot open the package: either create the default EXE.dwp or pass the actual package with -o while using --verify-only -e EXE.
  • The package is unexpectedly small: inspect the input list, compiler flags and timestamps. A successful command is not proof that the intended compilation units were included.

Do not delete the .dwo files until the package has been checked and your debugger workflow has been tested. They are the recovery source if a package was built from the wrong directory or incomplete inputs.

Done means

  • The intended GNU dwp version and target were confirmed.
  • Each split-DWARF compilation unit produced a matching .dwo file.
  • An explicit input list produced a non-empty .dwp file with DWARF index sections.
  • Verification used --verify-only with the real executable and package paths.
  • The original debug inputs remain available, and replacement output was made atomically.