DWARF is designed to have limited dependency on tools. A linker just has to concatenate the data sections, resolve symbol and inter-section relocations. But that does cause lots of repeated data structures (types) and the linker has to process a lot of references/relocations. To counter that .debug_types and DebugFission were introduced. First as GNU extensions then added to DWARF4 and DWARF5. Lots of details changed. These techniques can be used with separate .dwo files, or since DWARF5 in each .o file. This does introduce some extra complexity. We have to add various levels of indirection for types, strings, addresses and inter-section references. And with split-dwarf between the .o object files, executable and .dwo files. Some of the de-duplication of data is pushed to the DWARF consumer, or might need a slightly smarter post-processor to merge the duplication of types and data (there can be thousands of split-dwarf .dwo files). We will go over the techniques that are now implemented in GCC. Which versions of GCC implement what. Why the indirection tables are actually cheaper than traditional relocations. Where they aren't used yet, but probably should. The current state of DWARF consumers (gdb, elfutils, etc.) and auxiliary post-processing tools (dwp and dwz).