| name | dwarf-debug-format |
| description | DWARF debug format skill for understanding debug information. Use when inspecting DWARF sections with dwarfdump, working with split DWARF (.dwo files), setting up debuginfod for remote symbol resolution, or understanding how DWARF interacts with LTO and symbol stripping. Activates on queries about DWARF, .debug_info, .debug_line, dwarfdump, split DWARF, .dwo files, debuginfod, or debug info stripping. |
DWARF Debug Format
Purpose
Guide agents through understanding and working with DWARF debug information: the key DWARF sections, using dwarfdump and readelf for inspection, split DWARF (.dwo files), debuginfod for remote symbol servers, and how LTO and stripping affect debug info.
Triggers
- "What are the DWARF sections in an ELF binary?"
- "How do I inspect DWARF debug info in a binary?"
- "How does split DWARF work?"
- "How do I set up debuginfod for automatic debug symbols?"
- "Why does GDB say 'no debugging symbols found'?"
- "How does LTO affect DWARF debug information?"
Workflow
1. DWARF sections overview
readelf -S prog | grep "\.debug"
2. Inspecting DWARF with dwarfdump
apt-get install dwarfdump
brew install libdwarf
dwarfdump prog
dwarfdump --debug-info prog
dwarfdump --debug-line prog
dwarfdump --debug-loc prog
dwarfdump --debug-frame prog
readelf --debug-dump=info prog | head -100
readelf --debug-dump=lines prog | head -50
llvm-dwarfdump prog
llvm-dwarfdump --debug-info prog | grep "DW_AT_name"
llvm-dwarfdump --statistics prog
3. Reading DWARF DIE structure
# Sample dwarfdump output for a variable
DW_TAG_compile_unit
DW_AT_producer : "GNU C17 13.2.0"
DW_AT_language : DW_LANG_C11
DW_AT_name : "main.c"
DW_AT_comp_dir : "/home/user/project"
DW_TAG_subprogram
DW_AT_name : "add"
DW_AT_type : <0x42> → points to int type DIE
DW_AT_low_pc : 0x401130 ← function start address
DW_AT_high_pc : 0x401150 ← function end address
DW_TAG_formal_parameter
DW_AT_name : "a"
DW_AT_type : <0x42>
DW_AT_location : DW_OP_reg5 (rdi) ← lives in register rdi
DW_TAG_formal_parameter
DW_AT_name : "b"
DW_AT_location : DW_OP_reg4 (rsi) ← lives in register rsi
Tags (DW_TAG_*): compile_unit, subprogram, variable, formal_parameter, typedef, structure_type, member, array_type, pointer_type, base_type
Attributes (DW_AT_*): name, type, location, low_pc, high_pc, byte_size, encoding, file, line
4. Split DWARF (.dwo files)
Split DWARF separates debug info from the linked binary into .dwo sidecar files, reducing linker input size:
gcc -g -gsplit-dwarf -O2 -c main.c -o main.o
gcc main.o -o prog
gdb prog
readelf -S prog | grep "\.gnu_debuglink\|dwo"
dwarfdump prog | grep "dwo_name"
dwp -o prog.dwp prog
llvm-dwp -o prog.dwp prog
5. debuginfod — remote debug symbol server
debuginfod serves debug symbols, source code, and executables via HTTP:
export DEBUGINFOD_URLS="https://debuginfod.elfutils.org/"
gdb /usr/bin/git
debuginfod-find debuginfo /usr/bin/git
debuginfod-find source /usr/bin/git
(gdb) set debuginfod enabled on
(gdb) set debuginfod verbose 1
debuginfod -d /var/cache/debuginfod -p 8002 /path/to/binaries/
export DEBUGINFOD_URLS="http://localhost:8002"
6. LTO and DWARF
LTO affects DWARF debug information significantly:
gcc -flto -O2 -g main.c util.c -o prog
clang -flto=thin -O2 -g main.c util.c -o prog
gcc -Og -g main.c util.c -o prog_debug
gcc -O2 -flto main.c util.c -o prog_fast
[profile.dev]
lto = "off"
7. Stripping and separate debug files
strip --strip-debug prog -o prog.stripped
objcopy --only-keep-debug prog prog.debug
strip --strip-debug prog
objcopy --add-gnu-debuglink=prog.debug prog
gdb prog
eu-strip -f prog.debug prog
readelf -n prog | grep "Debug\|debuglink"
llvm-dwarfdump --statistics prog | grep "file size"
size --format=SysV prog | sort -k2rn | head -15
Related skills
- Use
skills/debuggers/debug-optimized-builds for debugging with split-DWARF builds
- Use
skills/debuggers/core-dumps for using debuginfod with core dump analysis
- Use
skills/binaries/elf-inspection for general ELF section inspection
- Use
skills/build-systems/build-acceleration for split-DWARF to speed up linking