Inspect DWARF Debug Data with llvm-dwarfdump-18

A crash report with no line numbers is a hint that the debug data needs checking, and llvm-dwarfdump-18 is the tool for that job. Use the installed LLVM 18.1.3 build to check a binary's DWARF data, find a function, list recorded source files, inspect section sizes and save a focused dump. Allow about fifteen minutes. You need a shell, the llvm-18 package, and an object file or executable that was built with debug information.

This guide only reads input files and writes output where you explicitly request it. It does not need sudo. Keep the original binary around: debug information may be stripped later, and llvm-dwarfdump-18 cannot reconstruct it once it is gone.

1. Check the installed command

Confirm that the command in your path is the LLVM 18 tool described by this guide:

$ command -v llvm-dwarfdump-18
/usr/bin/llvm-dwarfdump-18
$ llvm-dwarfdump-18 --version
Ubuntu LLVM version 18.1.3
  Optimized build.

The package version and build wording can vary with the distribution update. The options used below come from the installed LLVM 18 manpage. If command -v finds nothing, install the package through your normal package-management process, then repeat this check. Do not substitute an unqualified llvm-dwarfdump in a script unless you have checked which LLVM release it actually selects.

2. Get a safe test file

For a quick local test, compile a small C program with DWARF enabled. This creates files under /tmp and does not touch a system service or a project checkout:

$ workdir=$(mktemp -d /tmp/dwarfdump-demo.XXXXXX)
$ cat > "$workdir/sample.c" <<'EOF'
#include <stdio.h>
static int add(int a, int b) { return a + b; }
int main(void) { printf("%d\n", add(2, 3)); return 0; }
EOF
$ cc -g -O0 "$workdir/sample.c" -o "$workdir/sample"
$ file "$workdir/sample"
... with debug_info, not stripped ...

Use your own executable instead when investigating a real build. The -g compiler option is what makes this demonstration useful in the first place. If file reports a stripped binary, most debug queries will have little or nothing to show.

Checkpoint: Set workdir to the directory containing your test binary, or replace "$workdir/sample" in the following commands with an explicit path. Quote paths that may contain spaces.

3. Verify the debug information first

Run the built-in verifier before you try to interpret a large dump:

$ llvm-dwarfdump-18 --verify "$workdir/sample"
Verifying /tmp/dwarfdump-demo.XXXXXX/sample:  file format elf64-x86-64
Verifying .debug_abbrev...
Verifying .debug_info Unit Header Chain...
...
No errors.

The exact temporary path and the number of units vary. The useful result is No errors. and an exit status of zero. Capture the status immediately if a script needs it:

$ llvm-dwarfdump-18 --quiet --verify "$workdir/sample"
$ status=$?
$ printf 'verify status: %s\n' "$status"
verify status: 0

--quiet suppresses normal verifier output, which makes it convenient for automation. A non-zero status needs investigation; do not treat a passed verification as proof that every later query is trustworthy too.

4. Find a known function without dumping everything

Use --name when you know the exact DW_AT_name value you want. The option searches the accelerator tables where they are available:

$ llvm-dwarfdump-18 --name=add "$workdir/sample"
/tmp/dwarfdump-demo.XXXXXX/sample:  file format elf64-x86-64

0x000000ae: DW_TAG_subprogram
              DW_AT_name  ("add")
              DW_AT_decl_file  ("/tmp/dwarfdump-demo.XXXXXX/sample.c")
              DW_AT_decl_line  (2)

Addresses and offsets are properties of this particular build, so never compare them as stable identifiers. If the exact-name search finds nothing, try --name again without assuming a C or C++ source name survived compilation intact. The manpage describes --find as an accelerator-table search and points to --name as the slower, more complete alternative when those tables are unavailable.

For a case-insensitive regular-expression search, combine --regex, --ignore-case and --name:

$ llvm-dwarfdump-18 --regex --ignore-case --name='^add$' "$workdir/sample"

Keep the pattern quoted so the shell does not interpret regular-expression characters before the tool sees them. A regular expression can return more entries than an exact search, so inspect the names and declaration locations before drawing conclusions.

5. Inspect sources and section sizes

Two read-only summary options answer common triage questions without producing the whole tree. List source paths with --show-sources:

$ llvm-dwarfdump-18 --show-sources "$workdir/sample"
/tmp/dwarfdump-demo.XXXXXX/sample.c
/usr/include/stdio.h

Use --show-section-sizes to see where the debug data actually lives:

$ llvm-dwarfdump-18 --show-section-sizes "$workdir/sample"
SECTION          SIZE (b)
---------------  --------
.debug_info           228
...
 Total Size: 924

Your compiler, headers and optimisation settings will change the paths and numbers. These reports are useful for comparing builds, but a missing section is not automatically an error: a producer may omit optional sections, and a stripped release binary may contain none at all.

6. Dump one section, then save it if needed

When you need attributes rather than a summary, request one section. Start with --debug-info instead of --all; the latter dumps every supported debug section and can get very noisy very fast.

$ llvm-dwarfdump-18 --debug-info "$workdir/sample" | sed -n '1,28p'
/tmp/dwarfdump-demo.XXXXXX/sample:  file format elf64-x86-64

.debug_info contents:
0x00000000: Compile Unit: length = 0x000000e0, format = DWARF32,
version = 0x0005, unit_type = DW_UT_compile

Use --debug-line, --debug-abbrev, --debug-str or another section option from the manpage when that is the evidence you actually need. Options such as --show-children, --show-parents and --recurse-depth=N control selective displays; none of them repair incomplete debug data.

Redirect to a new file when another tool or a review needs the dump:

$ dumpfile="$workdir/debug-info.txt"
$ llvm-dwarfdump-18 --debug-info "$workdir/sample" > "$dumpfile"
$ test -s "$dumpfile" && sed -n '1,12p' "$dumpfile"

Shell redirection truncates an existing destination before the command even runs. Choose a new name, or check first with test ! -e "$dumpfile". If you only created the temporary demonstration directory, remove it after checking the results with rm -rf -- "$workdir"; that deletion is irreversible and must never be aimed at a project or system directory.

Common traps

Done means