A DWARF package file gathers the .dwo files of a whole program into one
file, usually named after the program with .dwp added and kept beside it.
It is defined in section 7.3.5 of
DWARF Version 5; tools such as
dwp and llvm-dwp make it. It is an object file of the same
format and byte order as the program,
holding only a file header, a section table, the debug sections and two index
sections.
Sections
A package holds at most one of each of these sections. Each is the concatenation of
the same section from every .dwo file. The single
.debug_str.dwo holds every string the units refer to through their
.debug_str_offsets.dwo contributions.
| Section | Holds |
|---|---|
.debug_info.dwo | All split compilation units and split type units. |
.debug_abbrev.dwo | Their abbreviation tables. |
.debug_line.dwo | Type-unit line tables. |
.debug_loclists.dwo | Location lists. |
.debug_rnglists.dwo | Range lists. |
.debug_str_offsets.dwo | String offsets for each unit. |
.debug_str.dwo | One merged string table. |
.debug_macro.dwo | Macro information. |
.debug_cu_index | Index from compilation unit ID (dwo_id) to that unit’s pieces. |
.debug_tu_index | Index from type signature to that type unit’s pieces. |
A compilation unit’s set may have pieces in .debug_info.dwo and
.debug_abbrev.dwo (both required), .debug_line.dwo,
.debug_loclists.dwo, .debug_rnglists.dwo,
.debug_str_offsets.dwo and .debug_macro.dwo. A type unit’s
set may have pieces in .debug_info.dwo and .debug_abbrev.dwo
(required), .debug_line.dwo and .debug_str_offsets.dwo.
Index sections
.debug_cu_index and .debug_tu_index have the same layout,
are aligned to 8 bytes, and are made of a header, a hash table of signatures, a
parallel table of row numbers, a table of offsets and a table of sizes.
Header
| Offset | Size | Name | Meaning |
|---|---|---|---|
| 0 | 2 | version | 5. This is the index’s own version, not the DWARF version. |
| 2 | 2 | padding | 0. |
| 4 | 4 | section_count (N) | Columns in the offset and size tables: how many sections are indexed. |
| 8 | 4 | unit_count (U) | Units in the index. |
| 12 | 4 | slot_count (S) | Slots in the hash table: a power of two, 2k, greater than 3U/2. |
Tables
| Offset | Size | Table | Meaning |
|---|---|---|---|
| 16 | 8 × S | hash table | One 64-bit signature per slot: a dwo_id in the CU index, a type signature in the TU index. An unused slot is 0. |
| 16 + 8S | 4 × S | parallel table | For each slot, the row number (from 1) of that unit in the offset and size tables; 0 for an unused slot. Signature 0 is valid, so a slot is unused only when its row number is 0. |
| 16 + 12S | 4 × N | offsets: header row | A section identifier for each column. |
| … | 4 × N × U | offsets: data rows | For each unit (rows 1 to U), the offset of its piece in each column’s section. |
| … | 4 × N × U | sizes | For each unit, in the same order, the size of each piece. |
All offsets read from a unit, such as its header’s debug_abbrev_offset,
its DW_AT_stmt_list and its list and string-offset positions, are relative
to the start of that unit’s piece of the section, as given by the offsets table.
Looking up a signature
With X the 8-byte signature read as an unsigned 64-bit number in the target byte order, and mask = S − 1:
- Primary hash H = X AND mask.
- Secondary hash H′ = ((X >> 32) AND mask) OR 1.
- If slot H holds X, use it. If slot H is unused, X is not in the index.
- Otherwise set H = (H + H′) mod S and go back to step 3.
Because H′ is odd and S a power of two, the search visits every slot, and since S > U it always ends.
X = 0x1234567890ABCDEF, S = 8, mask = 7
H = 0x...EF AND 7 = 7
H′ = (0x12345678 AND 7) OR 1 = 0 OR 1 = 1
probe slots 7, 0, 1, 2 … until X or an unused slot is found
Section identifiers
| Value | Version 5 (DWARF 5) | Version 2 (GNU, DWARF 4) |
|---|---|---|
| 1 | DW_SECT_INFO – .debug_info.dwo | DW_SECT_INFO – .debug_info.dwo |
| 2 | reserved | DW_SECT_TYPES – .debug_types.dwo |
| 3 | DW_SECT_ABBREV – .debug_abbrev.dwo | DW_SECT_ABBREV – .debug_abbrev.dwo |
| 4 | DW_SECT_LINE – .debug_line.dwo | DW_SECT_LINE – .debug_line.dwo |
| 5 | DW_SECT_LOCLISTS – .debug_loclists.dwo | DW_SECT_LOC – .debug_loc.dwo |
| 6 | DW_SECT_STR_OFFSETS – .debug_str_offsets.dwo | DW_SECT_STR_OFFSETS – .debug_str_offsets.dwo |
| 7 | DW_SECT_MACRO – .debug_macro.dwo | DW_SECT_MACINFO – .debug_macinfo.dwo |
| 8 | DW_SECT_RNGLISTS – .debug_rnglists.dwo | DW_SECT_MACRO – .debug_macro.dwo |
The GNU version 2 index, made for DWARF 4 split units, has the same layout except
that the first field is a 4-byte version of 2 with no padding
field. A reader can tell them apart by reading 4 bytes: 2 means version 2; otherwise
the first 2 bytes should be 5. In version 2 the type units are in
.debug_types.dwo, so the TU index points there.
Sources
DWARF Debugging Information Format,
Version 5, section 7.3.5 (package files, the CU and TU index sections, their
format, the lookup method) and table 7.1 (section identifiers). LLVM source:
DWARFUnitIndex.cpp (the version 2 header and section identifiers) and
BinaryFormat/Dwarf.def (DW_SECT_*). The lookup example is
worked by hand from the method.