Commit 31220b50b5

Jacob Young <jacobly0@users.noreply.github.com>
2024-08-22 02:59:41
Dwarf: cleanup emitted debug info
* reduce iteration cost by not tracking unused entries * avoid emitting unused abbrevs to `.debug_abbrev` * get the compiler executable passing `llvm-dwarfdump --verify` * make it possible to skip `.debug_line` padding much more quickly
1 parent 7cd1c88
Changed files (2)
lib
src
lib/std/dwarf.zig
@@ -89,6 +89,7 @@ pub const LNS = struct {
 };
 
 pub const LNE = struct {
+    pub const padding = 0x00;
     pub const end_sequence = 0x01;
     pub const set_address = 0x02;
     pub const define_file = 0x03;
src/link/Dwarf.zig
@@ -55,7 +55,10 @@ const ModInfo = struct {
 const DebugAbbrev = struct {
     section: Section,
     const unit: Unit.Index = @enumFromInt(0);
-    const entry: Entry.Index = @enumFromInt(0);
+
+    const header_bytes = 0;
+
+    const trailer_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.null));
 };
 
 const DebugAranges = struct {
@@ -119,8 +122,7 @@ const DebugLine = struct {
             1 + uleb128Bytes(DW.LNCT.path) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(DW.LNCT.directory_index) + uleb128Bytes(@intFromEnum(dir_index_info.form)) + uleb128Bytes(DW.LNCT.LLVM_source) + uleb128Bytes(DW.FORM.line_strp) + uleb128Bytes(file_count) + (dwarf.sectionOffsetBytes() + dir_index_info.bytes + dwarf.sectionOffsetBytes()) * file_count;
     }
 
-    const trailer_bytes = 1 + uleb128Bytes(0) +
-        1 + uleb128Bytes(1) + 1;
+    const trailer_bytes = 1 + uleb128Bytes(1) + 1;
 };
 
 const DebugLocLists = struct {
@@ -173,10 +175,15 @@ const StringSection = struct {
         errdefer _ = str_sec.map.pop();
         const entry: Entry.Index = @enumFromInt(gop.index);
         if (!gop.found_existing) {
-            assert(try str_sec.section.addEntry(unit, dwarf) == entry);
-            errdefer _ = str_sec.section.getUnit(unit).entries.pop();
-            const entry_ptr = str_sec.section.getUnit(unit).getEntry(entry);
-            assert(entry_ptr.off == str_sec.contents.items.len);
+            const unit_ptr = str_sec.section.getUnit(unit);
+            assert(try str_sec.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+            errdefer _ = unit_ptr.entries.pop();
+            const entry_ptr = unit_ptr.getEntry(entry);
+            if (unit_ptr.last.unwrap()) |last_entry|
+                unit_ptr.getEntry(last_entry).next = entry.toOptional();
+            entry_ptr.prev = unit_ptr.last;
+            unit_ptr.last = entry.toOptional();
+            entry_ptr.off = @intCast(str_sec.contents.items.len);
             entry_ptr.len = @intCast(str.len + 1);
             try str_sec.contents.ensureUnusedCapacity(dwarf.gpa, str.len + 1);
             str_sec.contents.appendSliceAssumeCapacity(str);
@@ -243,7 +250,7 @@ pub const Section = struct {
     fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index {
         const unit: Unit.Index = @enumFromInt(sec.units.items.len);
         const unit_ptr = try sec.units.addOne(dwarf.gpa);
-        errdefer sec.popUnit();
+        errdefer sec.popUnit(dwarf.gpa);
         unit_ptr.* = .{
             .prev = sec.last,
             .next = .none,
@@ -277,14 +284,11 @@ pub const Section = struct {
         if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;
     }
 
-    fn popUnit(sec: *Section) void {
-        const unit: Unit.Index = @enumFromInt(sec.units.items.len - 1);
-        sec.unlinkUnit(unit);
-        _ = sec.units.pop();
-    }
-
-    fn addEntry(sec: *Section, unit: Unit.Index, dwarf: *Dwarf) UpdateError!Entry.Index {
-        return sec.getUnit(unit).addEntry(sec, dwarf);
+    fn popUnit(sec: *Section, gpa: std.mem.Allocator) void {
+        const unit_index: Unit.Index = @enumFromInt(sec.units.items.len - 1);
+        sec.unlinkUnit(unit_index);
+        var unit = sec.units.pop();
+        unit.deinit(gpa);
     }
 
     pub fn getUnit(sec: *Section, unit: Unit.Index) *Unit {
@@ -293,7 +297,21 @@ pub const Section = struct {
 
     fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
         const unit_ptr = sec.getUnit(unit);
-        try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
+        const entry_ptr = unit_ptr.getEntry(entry);
+        if (contents.len > 0) {
+            if (entry_ptr.len == 0) {
+                assert(entry_ptr.prev == .none and entry_ptr.next == .none);
+                entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {
+                    const last_entry_ptr = unit_ptr.getEntry(last_entry);
+                    last_entry_ptr.next = entry.toOptional();
+                    break :off last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
+                } else 0;
+                entry_ptr.prev = unit_ptr.last;
+                unit_ptr.last = entry.toOptional();
+            }
+            try entry_ptr.replace(unit_ptr, sec, dwarf, contents);
+        }
+        assert(entry_ptr.len == contents.len);
     }
 
     fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
@@ -391,11 +409,11 @@ const Unit = struct {
         unit.* = undefined;
     }
 
-    fn addEntry(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!Entry.Index {
+    fn addEntry(unit: *Unit, gpa: std.mem.Allocator) std.mem.Allocator.Error!Entry.Index {
         const entry: Entry.Index = @enumFromInt(unit.entries.items.len);
-        const entry_ptr = try unit.entries.addOne(dwarf.gpa);
+        const entry_ptr = try unit.entries.addOne(gpa);
         entry_ptr.* = .{
-            .prev = unit.last,
+            .prev = .none,
             .next = .none,
             .off = 0,
             .len = 0,
@@ -404,14 +422,6 @@ const Unit = struct {
             .cross_section_relocs = .{},
             .external_relocs = .{},
         };
-        if (unit.last.unwrap()) |last_entry| {
-            const last_entry_ptr = unit.getEntry(last_entry);
-            last_entry_ptr.next = entry.toOptional();
-            entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
-        }
-        if (unit.first == .none)
-            unit.first = entry.toOptional();
-        unit.last = entry.toOptional();
         return entry;
     }
 
@@ -509,42 +519,52 @@ const Unit = struct {
             const last_entry_ptr = unit.getEntry(last_entry);
             break :end last_entry_ptr.off + last_entry_ptr.len;
         } else 0;
-        const end = if (unit.next.unwrap()) |next_unit|
-            sec.getUnit(next_unit).off
-        else
-            sec.len;
-        const trailer_len: usize = @intCast(end - start);
-        assert(trailer_len >= unit.trailer_len);
-        var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, trailer_len);
+        const end = if (unit.next.unwrap()) |next_unit| sec.getUnit(next_unit).off else sec.len;
+        const len: usize = @intCast(end - start);
+        assert(len >= unit.trailer_len);
+        if (sec == &dwarf.debug_line.section) {
+            var buf: [1 + uleb128Bytes(std.math.maxInt(u32)) + 1]u8 = undefined;
+            var fbs = std.io.fixedBufferStream(&buf);
+            const writer = fbs.writer();
+            writer.writeByte(DW.LNS.extended_op) catch unreachable;
+            const extended_op_bytes = fbs.pos;
+            var op_len_bytes: u5 = 1;
+            while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
+                .lt => break uleb128(writer, len - extended_op_bytes - op_len_bytes) catch unreachable,
+                .eq => {
+                    // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
+                    op_len_bytes += 1;
+                    std.leb.writeUnsignedExtended(buf[fbs.pos..][0..op_len_bytes], len - extended_op_bytes - op_len_bytes);
+                    fbs.pos += op_len_bytes;
+                    break;
+                },
+                .gt => op_len_bytes += 1,
+            };
+            assert(fbs.pos == extended_op_bytes + op_len_bytes);
+            writer.writeByte(DW.LNE.padding) catch unreachable;
+            assert(fbs.pos >= unit.trailer_len and fbs.pos <= len);
+            return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + start);
+        }
+        var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len);
         defer trailer.deinit();
-        const fill_byte: u8 = if (sec == &dwarf.debug_aranges.section) fill: {
+        const fill_byte: u8 = if (sec == &dwarf.debug_abbrev.section) fill: {
+            assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
+            trailer.appendAssumeCapacity(@intFromEnum(AbbrevCode.null));
+            break :fill @intFromEnum(AbbrevCode.null);
+        } else if (sec == &dwarf.debug_aranges.section) fill: {
             trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
             break :fill 0;
         } else if (sec == &dwarf.debug_info.section) fill: {
             assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
             trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
             break :fill @intFromEnum(AbbrevCode.null);
-        } else if (sec == &dwarf.debug_line.section) fill: {
-            unit.len -= unit.trailer_len;
-            const extra_len: u32 = @intCast((trailer_len - DebugLine.trailer_bytes) & 1);
-            unit.trailer_len = DebugLine.trailer_bytes + extra_len;
-            unit.len += unit.trailer_len;
-
-            // prevent end sequence from emitting an invalid file index
-            trailer.appendAssumeCapacity(DW.LNS.set_file);
-            uleb128(trailer.fixedWriter(), 0) catch unreachable;
-
-            trailer.appendAssumeCapacity(DW.LNS.extended_op);
-            std.leb.writeUnsignedExtended(trailer.addManyAsSliceAssumeCapacity(uleb128Bytes(1) + extra_len), 1);
-            trailer.appendAssumeCapacity(DW.LNE.end_sequence);
-            break :fill DW.LNS.extended_op;
         } else if (sec == &dwarf.debug_rnglists.section) fill: {
             trailer.appendAssumeCapacity(DW.RLE.end_of_list);
             break :fill DW.RLE.end_of_list;
         } else unreachable;
         assert(trailer.items.len == unit.trailer_len);
-        trailer.appendNTimesAssumeCapacity(fill_byte, trailer_len - trailer.items.len);
-        assert(trailer.items.len == trailer_len);
+        trailer.appendNTimesAssumeCapacity(fill_byte, len - trailer.items.len);
+        assert(trailer.items.len == len);
         try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
     }
 
@@ -625,45 +645,62 @@ const Entry = struct {
     };
 
     fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
+        assert(entry.len > 0);
         const start = entry.off + entry.len;
         const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
-        if (sec == &dwarf.debug_info.section) {
-            var buf: [
-                @max(
-                    uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
-                    uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
-                )
-            ]u8 = undefined;
-            var fbs = std.io.fixedBufferStream(&buf);
-            switch (len) {
-                0 => {},
-                1 => uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_1)) catch unreachable,
-                else => {
-                    uleb128(fbs.writer(), @intFromEnum(AbbrevCode.pad_n)) catch unreachable;
-                    const abbrev_code_bytes = fbs.pos;
-                    var block_len_bytes: u5 = 1;
-                    while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
-                        .lt => break uleb128(fbs.writer(), len - abbrev_code_bytes - block_len_bytes) catch unreachable,
-                        .eq => {
-                            // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
-                            block_len_bytes += 1;
-                            std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
-                            fbs.pos += block_len_bytes;
-                            break;
-                        },
-                        .gt => block_len_bytes += 1,
-                    };
-                    assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
-                },
-            }
-            assert(fbs.pos <= len);
-            try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
-        } else if (sec == &dwarf.debug_line.section) {
-            const buf = try dwarf.gpa.alloc(u8, len);
-            defer dwarf.gpa.free(buf);
-            @memset(buf, DW.LNS.const_add_pc);
-            try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
+        var buf: [
+            @max(
+                uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)),
+                uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) + uleb128Bytes(std.math.maxInt(u32)),
+                1 + uleb128Bytes(std.math.maxInt(u32)) + 1,
+            )
+        ]u8 = undefined;
+        var fbs = std.io.fixedBufferStream(&buf);
+        const writer = fbs.writer();
+        if (sec == &dwarf.debug_info.section) switch (len) {
+            0 => {},
+            1 => uleb128(writer, try dwarf.refAbbrevCode(.pad_1)) catch unreachable,
+            else => {
+                uleb128(writer, try dwarf.refAbbrevCode(.pad_n)) catch unreachable;
+                const abbrev_code_bytes = fbs.pos;
+                var block_len_bytes: u5 = 1;
+                while (true) switch (std.math.order(len - abbrev_code_bytes - block_len_bytes, @as(u32, 1) << 7 * block_len_bytes)) {
+                    .lt => break uleb128(writer, len - abbrev_code_bytes - block_len_bytes) catch unreachable,
+                    .eq => {
+                        // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
+                        block_len_bytes += 1;
+                        std.leb.writeUnsignedExtended(buf[fbs.pos..][0..block_len_bytes], len - abbrev_code_bytes - block_len_bytes);
+                        fbs.pos += block_len_bytes;
+                        break;
+                    },
+                    .gt => block_len_bytes += 1,
+                };
+                assert(fbs.pos == abbrev_code_bytes + block_len_bytes);
+            },
+        } else if (sec == &dwarf.debug_line.section) switch (len) {
+            0 => {},
+            1 => writer.writeByte(DW.LNS.const_add_pc) catch unreachable,
+            else => {
+                writer.writeByte(DW.LNS.extended_op) catch unreachable;
+                const extended_op_bytes = fbs.pos;
+                var op_len_bytes: u5 = 1;
+                while (true) switch (std.math.order(len - extended_op_bytes - op_len_bytes, @as(u32, 1) << 7 * op_len_bytes)) {
+                    .lt => break uleb128(writer, len - extended_op_bytes - op_len_bytes) catch unreachable,
+                    .eq => {
+                        // no length will ever work, so undercount and futz with the leb encoding to make up the missing byte
+                        op_len_bytes += 1;
+                        std.leb.writeUnsignedExtended(buf[fbs.pos..][0..op_len_bytes], len - extended_op_bytes - op_len_bytes);
+                        fbs.pos += op_len_bytes;
+                        break;
+                    },
+                    .gt => op_len_bytes += 1,
+                };
+                assert(fbs.pos == extended_op_bytes + op_len_bytes);
+                if (len > 2) writer.writeByte(DW.LNE.padding) catch unreachable;
+            },
         } else assert(!sec.pad_to_ideal and len == 0);
+        assert(fbs.pos <= len);
+        try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
     }
 
     fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
@@ -691,15 +728,7 @@ const Entry = struct {
             try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));
         }
         entry_ptr.len = @intCast(contents.len);
-        {
-            var prev_entry_ptr = entry_ptr;
-            while (prev_entry_ptr.prev.unwrap()) |prev_entry| {
-                prev_entry_ptr = unit.getEntry(prev_entry);
-                if (prev_entry_ptr.len == 0) continue;
-                try prev_entry_ptr.pad(unit, sec, dwarf);
-                break;
-            }
-        }
+        if (entry_ptr.prev.unwrap()) |prev_entry| try unit.getEntry(prev_entry).pad(unit, sec, dwarf);
         try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
         try entry_ptr.pad(unit, sec, dwarf);
         if (false) {
@@ -1039,7 +1068,10 @@ pub const WipNav = struct {
     func: InternPool.Index,
     func_sym_index: u32,
     func_high_reloc: u32,
-    inlined_funcs_high_reloc: std.ArrayListUnmanaged(u32),
+    inlined_funcs: std.ArrayListUnmanaged(struct {
+        abbrev_code: u32,
+        high_reloc: u32,
+    }),
     debug_info: std.ArrayListUnmanaged(u8),
     debug_line: std.ArrayListUnmanaged(u8),
     debug_loclists: std.ArrayListUnmanaged(u8),
@@ -1047,7 +1079,7 @@ pub const WipNav = struct {
 
     pub fn deinit(wip_nav: *WipNav) void {
         const gpa = wip_nav.dwarf.gpa;
-        if (wip_nav.func != .none) wip_nav.inlined_funcs_high_reloc.deinit(gpa);
+        if (wip_nav.func != .none) wip_nav.inlined_funcs.deinit(gpa);
         wip_nav.debug_info.deinit(gpa);
         wip_nav.debug_line.deinit(gpa);
         wip_nav.debug_loclists.deinit(gpa);
@@ -1066,15 +1098,14 @@ pub const WipNav = struct {
         ty: Type,
         loc: Loc,
     ) UpdateError!void {
-        wip_nav.any_children = true;
         assert(wip_nav.func != .none);
-        const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
-        try uleb128(diw, @intFromEnum(switch (tag) {
+        try wip_nav.abbrevCode(switch (tag) {
             inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)),
-        }));
+        });
         try wip_nav.strp(name);
         try wip_nav.refType(ty);
         try wip_nav.exprloc(loc);
+        wip_nav.any_children = true;
     }
 
     pub fn advancePCAndLine(
@@ -1136,9 +1167,10 @@ pub const WipNav = struct {
         const dwarf = wip_nav.dwarf;
         const zcu = wip_nav.pt.zcu;
         const diw = wip_nav.debug_info.writer(dwarf.gpa);
-        try wip_nav.inlined_funcs_high_reloc.ensureUnusedCapacity(dwarf.gpa, 1);
+        const inlined_func = try wip_nav.inlined_funcs.addOne(dwarf.gpa);
 
-        try uleb128(diw, @intFromEnum(AbbrevCode.inlined_func));
+        inlined_func.abbrev_code = @intCast(wip_nav.debug_info.items.len);
+        try wip_nav.abbrevCode(.inlined_func);
         try wip_nav.refNav(zcu.funcInfo(func).owner_nav);
         try uleb128(diw, zcu.navSrcLine(zcu.funcInfo(wip_nav.func).owner_nav) + line + 1);
         try uleb128(diw, column + 1);
@@ -1150,7 +1182,7 @@ pub const WipNav = struct {
             .target_off = code_off,
         });
         try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
-        wip_nav.inlined_funcs_high_reloc.appendAssumeCapacity(@intCast(external_relocs.items.len));
+        inlined_func.high_reloc = @intCast(external_relocs.items.len);
         external_relocs.appendAssumeCapacity(.{
             .source_off = @intCast(wip_nav.debug_info.items.len),
             .target_sym = wip_nav.func_sym_index,
@@ -1158,17 +1190,27 @@ pub const WipNav = struct {
         });
         try diw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
         try wip_nav.setInlineFunc(func);
+        wip_nav.any_children = false;
     }
 
     pub fn leaveInlineFunc(wip_nav: *WipNav, func: InternPool.Index, code_off: u64) UpdateError!void {
+        const inlined_func_bytes = comptime uleb128Bytes(@intFromEnum(AbbrevCode.inlined_func));
+        const inlined_func = wip_nav.inlined_funcs.pop();
         const external_relocs = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
-        external_relocs.items[wip_nav.inlined_funcs_high_reloc.pop()].target_off = code_off;
-        try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null));
+        external_relocs.items[inlined_func.high_reloc].target_off = code_off;
+        if (wip_nav.any_children)
+            try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), @intFromEnum(AbbrevCode.null))
+        else
+            std.leb.writeUnsignedFixed(
+                inlined_func_bytes,
+                wip_nav.debug_info.items[inlined_func.abbrev_code..][0..inlined_func_bytes],
+                try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func),
+            );
         try wip_nav.setInlineFunc(func);
+        wip_nav.any_children = true;
     }
 
     pub fn setInlineFunc(wip_nav: *WipNav, func: InternPool.Index) UpdateError!void {
-        wip_nav.any_children = true;
         const zcu = wip_nav.pt.zcu;
         const dwarf = wip_nav.dwarf;
         if (wip_nav.func == func) return;
@@ -1219,6 +1261,10 @@ pub const WipNav = struct {
         wip_nav.func = func;
     }
 
+    fn abbrevCode(wip_nav: *WipNav, abbrev_code: AbbrevCode) UpdateError!void {
+        try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), try wip_nav.dwarf.refAbbrevCode(abbrev_code));
+    }
+
     fn infoSectionOffset(wip_nav: *WipNav, sec: Section.Index, unit: Unit.Index, entry: Entry.Index, off: u32) UpdateError!void {
         const dwarf = wip_nav.dwarf;
         const gpa = dwarf.gpa;
@@ -1336,7 +1382,7 @@ pub const WipNav = struct {
         loaded_enum: InternPool.LoadedEnumType,
         abbrev_code: std.enums.EnumFieldStruct(std.builtin.Signedness, AbbrevCode, null),
         field_index: usize,
-    ) std.mem.Allocator.Error!void {
+    ) UpdateError!void {
         const zcu = wip_nav.pt.zcu;
         const ip = &zcu.intern_pool;
         const diw = wip_nav.debug_info.writer(wip_nav.dwarf.gpa);
@@ -1344,9 +1390,9 @@ pub const WipNav = struct {
             .comptime_int_type => .signed,
             else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
         };
-        try uleb128(diw, @intFromEnum(switch (signedness) {
+        try wip_nav.abbrevCode(switch (signedness) {
             inline .signed, .unsigned => |ct_signedness| @field(abbrev_code, @tagName(ct_signedness)),
-        }));
+        });
         if (loaded_enum.values.len > 0) switch (ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage) {
             .u64 => |value| switch (signedness) {
                 .signed => try sleb128(diw, value),
@@ -1535,20 +1581,21 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
     dwarf.reloadSectionMetadata();
 
     dwarf.debug_abbrev.section.pad_to_ideal = false;
-    assert(try dwarf.debug_abbrev.section.addUnit(0, 0, dwarf) == DebugAbbrev.unit);
-    errdefer dwarf.debug_abbrev.section.popUnit();
-    assert(try dwarf.debug_abbrev.section.addEntry(DebugAbbrev.unit, dwarf) == DebugAbbrev.entry);
+    assert(try dwarf.debug_abbrev.section.addUnit(DebugAbbrev.header_bytes, DebugAbbrev.trailer_bytes, dwarf) == DebugAbbrev.unit);
+    errdefer dwarf.debug_abbrev.section.popUnit(dwarf.gpa);
+    for (std.enums.values(AbbrevCode)) |abbrev_code|
+        assert(@intFromEnum(try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).addEntry(dwarf.gpa)) == @intFromEnum(abbrev_code));
 
     dwarf.debug_aranges.section.pad_to_ideal = false;
     dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
 
     dwarf.debug_line_str.section.pad_to_ideal = false;
     assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
-    errdefer dwarf.debug_line_str.section.popUnit();
+    errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
 
     dwarf.debug_str.section.pad_to_ideal = false;
     assert(try dwarf.debug_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
-    errdefer dwarf.debug_str.section.popUnit();
+    errdefer dwarf.debug_str.section.popUnit(dwarf.gpa);
 
     dwarf.debug_loclists.section.pad_to_ideal = false;
 
@@ -1589,31 +1636,31 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
             DebugAranges.trailerBytes(dwarf),
             dwarf,
         ) == unit);
-        errdefer dwarf.debug_aranges.section.popUnit();
+        errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
         assert(try dwarf.debug_info.section.addUnit(
             DebugInfo.headerBytes(dwarf),
             DebugInfo.trailer_bytes,
             dwarf,
         ) == unit);
-        errdefer dwarf.debug_info.section.popUnit();
+        errdefer dwarf.debug_info.section.popUnit(dwarf.gpa);
         assert(try dwarf.debug_line.section.addUnit(
             DebugLine.headerBytes(dwarf, 5, 25),
             DebugLine.trailer_bytes,
             dwarf,
         ) == unit);
-        errdefer dwarf.debug_line.section.popUnit();
+        errdefer dwarf.debug_line.section.popUnit(dwarf.gpa);
         assert(try dwarf.debug_loclists.section.addUnit(
             DebugLocLists.headerBytes(dwarf),
             DebugLocLists.trailer_bytes,
             dwarf,
         ) == unit);
-        errdefer dwarf.debug_loclists.section.popUnit();
+        errdefer dwarf.debug_loclists.section.popUnit(dwarf.gpa);
         assert(try dwarf.debug_rnglists.section.addUnit(
             DebugRngLists.headerBytes(dwarf),
             DebugRngLists.trailer_bytes,
             dwarf,
         ) == unit);
-        errdefer dwarf.debug_rnglists.section.popUnit();
+        errdefer dwarf.debug_rnglists.section.popUnit(dwarf.gpa);
     }
     return unit;
 }
@@ -1658,7 +1705,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
         .func = .none,
         .func_sym_index = undefined,
         .func_high_reloc = undefined,
-        .inlined_funcs_high_reloc = undefined,
+        .inlined_funcs = undefined,
         .debug_info = .{},
         .debug_line = .{},
         .debug_loclists = .{},
@@ -1699,7 +1746,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
             } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
 
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
+            try wip_nav.abbrevCode(.decl_var);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1714,7 +1761,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
                 ty.abiAlignment(pt).toByteUnits().?);
             try diw.writeByte(@intFromBool(false));
             wip_nav.finishForward(ty_reloc_index);
-            try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
+            try wip_nav.abbrevCode(.is_const);
             try wip_nav.refType(ty);
         },
         .variable => |variable| {
@@ -1749,7 +1796,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
             } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
 
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_var));
+            try wip_nav.abbrevCode(.decl_var);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1799,10 +1846,10 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
             const func_type = ip.indexToKey(func.ty).func_type;
             wip_nav.func = nav_val.toIntern();
             wip_nav.func_sym_index = sym_index;
-            wip_nav.inlined_funcs_high_reloc = .{};
+            wip_nav.inlined_funcs = .{};
 
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_func));
+            try wip_nav.abbrevCode(.decl_func);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -1891,7 +1938,7 @@ pub fn finishWipNav(
         } else std.leb.writeUnsignedFixed(
             AbbrevCode.decl_bytes,
             wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
-            @intFromEnum(AbbrevCode.decl_func_empty),
+            try dwarf.refAbbrevCode(.decl_empty_func),
         );
 
         var aranges_entry = [1]u8{0} ** (8 + 8);
@@ -1967,7 +2014,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
         .func = .none,
         .func_sym_index = undefined,
         .func_high_reloc = undefined,
-        .inlined_funcs_high_reloc = undefined,
+        .inlined_funcs = undefined,
         .debug_info = .{},
         .debug_line = .{},
         .debug_loclists = .{},
@@ -1990,12 +2037,12 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                     ) != abbrev_code_buf.len) return error.InputOutput;
                     var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf);
                     const abbrev_code: AbbrevCode = @enumFromInt(
-                        try std.leb.readUleb128(@typeInfo(AbbrevCode).Enum.tag_type, abbrev_code_fbs.reader()),
+                        std.leb.readUleb128(@typeInfo(AbbrevCode).Enum.tag_type, abbrev_code_fbs.reader()) catch unreachable,
                     );
                     switch (abbrev_code) {
                         else => unreachable,
-                        .decl_func, .decl_func_empty => return,
-                        .decl_func_generic, .decl_func_generic_empty => {},
+                        .decl_func, .decl_empty_func => return,
+                        .decl_func_generic, .decl_empty_func_generic => {},
                     }
                 }
                 entry_ptr.clear();
@@ -2017,7 +2064,10 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
 
             const func_type = ip.indexToKey(func.ty).func_type;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (func_type.param_types.len > 0 or func_type.is_var_args) .decl_func_generic else .decl_func_generic_empty)));
+            try wip_nav.abbrevCode(if (func_type.param_types.len > 0 or func_type.is_var_args)
+                .decl_func_generic
+            else
+                .decl_empty_func_generic);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2027,10 +2077,10 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
             try wip_nav.refType(Type.fromInterned(func_type.return_type));
             if (func_type.param_types.len > 0 or func_type.is_var_args) {
                 for (0..func_type.param_types.len) |param_index| {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
+                    try wip_nav.abbrevCode(.func_type_param);
                     try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
                 }
-                if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
+                if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
                 try uleb128(diw, @intFromEnum(AbbrevCode.null));
             }
         },
@@ -2088,10 +2138,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
 
                 switch (loaded_struct.layout) {
                     .auto, .@"extern" => {
-                        try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
-                            .decl_namespace_struct
-                        else
-                            .decl_struct)));
+                        try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .decl_namespace_struct else .decl_struct);
                         try wip_nav.refType(Type.fromInterned(parent_type));
                         assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
                         try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2103,7 +2150,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                             try uleb128(diw, nav_val.toType().abiAlignment(pt).toByteUnits().?);
                             for (0..loaded_struct.field_types.len) |field_index| {
                                 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
-                                try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
+                                try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
                                 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
                                     const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
                                     defer dwarf.gpa.free(field_name);
@@ -2121,7 +2168,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                         }
                     },
                     .@"packed" => {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.decl_packed_struct));
+                        try wip_nav.abbrevCode(.decl_packed_struct);
                         try wip_nav.refType(Type.fromInterned(parent_type));
                         assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
                         try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2131,7 +2178,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                         try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
                         var field_bit_offset: u16 = 0;
                         for (0..loaded_struct.field_types.len) |field_index| {
-                            try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
+                            try wip_nav.abbrevCode(.packed_struct_field);
                             try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
                             const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
                             try wip_nav.refType(field_type);
@@ -2150,7 +2197,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+            try wip_nav.abbrevCode(.decl_alias);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2210,7 +2257,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 }
                 wip_nav.entry = nav_gop.value_ptr.*;
                 const diw = wip_nav.debug_info.writer(dwarf.gpa);
-                try uleb128(diw, @intFromEnum(AbbrevCode.decl_enum));
+                try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .decl_enum else .decl_empty_enum);
                 try wip_nav.refType(Type.fromInterned(parent_type));
                 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
                 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2225,7 +2272,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                     }, field_index);
                     try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
                 }
-                try uleb128(diw, @intFromEnum(AbbrevCode.null));
+                if (loaded_enum.names.len > 0) try uleb128(diw, @intFromEnum(AbbrevCode.null));
                 break :done;
             }
 
@@ -2235,7 +2282,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+            try wip_nav.abbrevCode(.decl_alias);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2293,7 +2340,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 }
                 wip_nav.entry = nav_gop.value_ptr.*;
                 const diw = wip_nav.debug_info.writer(dwarf.gpa);
-                try uleb128(diw, @intFromEnum(AbbrevCode.decl_union));
+                try wip_nav.abbrevCode(.decl_union);
                 try wip_nav.refType(Type.fromInterned(parent_type));
                 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
                 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2305,7 +2352,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
                 const loaded_tag = loaded_union.loadTagType(ip);
                 if (loaded_union.hasTag(ip)) {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+                    try wip_nav.abbrevCode(.tagged_union);
                     try wip_nav.infoSectionOffset(
                         .debug_info,
                         wip_nav.unit,
@@ -2313,7 +2360,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                         @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
                     );
                     {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                        try wip_nav.abbrevCode(.generated_field);
                         try wip_nav.strp("tag");
                         try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
                         try uleb128(diw, union_layout.tagOffset());
@@ -2324,7 +2371,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                                 .unsigned = .unsigned_tagged_union_field,
                             }, field_index);
                             {
-                                try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
+                                try wip_nav.abbrevCode(.struct_field);
                                 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
                                 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
                                 try wip_nav.refType(field_type);
@@ -2340,7 +2387,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                     if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
                         try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
                 } else for (0..loaded_union.field_types.len) |field_index| {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
+                    try wip_nav.abbrevCode(.untagged_union_field);
                     try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
                     const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
                     try wip_nav.refType(field_type);
@@ -2357,7 +2404,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+            try wip_nav.abbrevCode(.decl_alias);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2415,7 +2462,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 }
                 wip_nav.entry = nav_gop.value_ptr.*;
                 const diw = wip_nav.debug_info.writer(dwarf.gpa);
-                try uleb128(diw, @intFromEnum(AbbrevCode.decl_namespace_struct));
+                try wip_nav.abbrevCode(.decl_namespace_struct);
                 try wip_nav.refType(Type.fromInterned(parent_type));
                 assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
                 try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2432,7 +2479,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
                 nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
             wip_nav.entry = nav_gop.value_ptr.*;
             const diw = wip_nav.debug_info.writer(dwarf.gpa);
-            try uleb128(diw, @intFromEnum(AbbrevCode.decl_alias));
+            try wip_nav.abbrevCode(.decl_alias);
             try wip_nav.refType(Type.fromInterned(parent_type));
             assert(wip_nav.debug_info.items.len == DebugInfo.declEntryLineOff(dwarf));
             try diw.writeInt(u32, @intCast(loc.line + 1), dwarf.endian);
@@ -2473,7 +2520,7 @@ fn updateType(
         .func = .none,
         .func_sym_index = undefined,
         .func_high_reloc = undefined,
-        .inlined_funcs_high_reloc = undefined,
+        .inlined_funcs = undefined,
         .debug_info = .{},
         .debug_line = .{},
         .debug_loclists = .{},
@@ -2493,7 +2540,7 @@ fn updateType(
 
     switch (ip.indexToKey(type_index)) {
         .int_type => |int_type| {
-            try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
+            try wip_nav.abbrevCode(.numeric_type);
             try wip_nav.strp(name);
             try diw.writeByte(switch (int_type.signedness) {
                 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
@@ -2505,7 +2552,7 @@ fn updateType(
         .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
             .One, .Many, .C => {
                 const ptr_child_type = Type.fromInterned(ptr_type.child);
-                try uleb128(diw, @intFromEnum(AbbrevCode.ptr_type));
+                try wip_nav.abbrevCode(.ptr_type);
                 try wip_nav.strp(name);
                 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
                     ptr_child_type.abiAlignment(pt).toByteUnits().?);
@@ -2517,7 +2564,7 @@ fn updateType(
                     @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
                 ) else try wip_nav.refType(ptr_child_type);
                 if (ptr_type.flags.is_const) {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.is_const));
+                    try wip_nav.abbrevCode(.is_const);
                     if (ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
                         .debug_info,
                         wip_nav.unit,
@@ -2526,21 +2573,21 @@ fn updateType(
                     ) else try wip_nav.refType(ptr_child_type);
                 }
                 if (ptr_type.flags.is_volatile) {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.is_volatile));
+                    try wip_nav.abbrevCode(.is_volatile);
                     try wip_nav.refType(ptr_child_type);
                 }
             },
             .Slice => {
-                try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
+                try wip_nav.abbrevCode(.struct_type);
                 try wip_nav.strp(name);
                 try uleb128(diw, ty.abiSize(pt));
                 try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
-                try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                try wip_nav.abbrevCode(.generated_field);
                 try wip_nav.strp("ptr");
                 const ptr_field_type = ty.slicePtrFieldType(zcu);
                 try wip_nav.refType(ptr_field_type);
                 try uleb128(diw, 0);
-                try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                try wip_nav.abbrevCode(.generated_field);
                 try wip_nav.strp("len");
                 const len_field_type = Type.usize;
                 try wip_nav.refType(len_field_type);
@@ -2549,28 +2596,28 @@ fn updateType(
             },
         },
         inline .array_type, .vector_type => |array_type, ty_tag| {
-            try uleb128(diw, @intFromEnum(AbbrevCode.array_type));
+            try wip_nav.abbrevCode(.array_type);
             try wip_nav.strp(name);
             try wip_nav.refType(Type.fromInterned(array_type.child));
             try diw.writeByte(@intFromBool(ty_tag == .vector_type));
-            try uleb128(diw, @intFromEnum(AbbrevCode.array_index));
+            try wip_nav.abbrevCode(.array_index);
             try wip_nav.refType(Type.usize);
             try uleb128(diw, array_type.len);
             try uleb128(diw, @intFromEnum(AbbrevCode.null));
         },
         .opt_type => |opt_child_type_index| {
             const opt_child_type = Type.fromInterned(opt_child_type_index);
-            try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
+            try wip_nav.abbrevCode(.union_type);
             try wip_nav.strp(name);
             try uleb128(diw, ty.abiSize(pt));
             try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
             if (opt_child_type.isNoReturn(zcu)) {
-                try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                try wip_nav.abbrevCode(.generated_field);
                 try wip_nav.strp("null");
                 try wip_nav.refType(Type.null);
                 try uleb128(diw, 0);
             } else {
-                try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+                try wip_nav.abbrevCode(.tagged_union);
                 try wip_nav.infoSectionOffset(
                     .debug_info,
                     wip_nav.unit,
@@ -2578,7 +2625,7 @@ fn updateType(
                     @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
                 );
                 {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                    try wip_nav.abbrevCode(.generated_field);
                     try wip_nav.strp("has_value");
                     const repr: enum { unpacked, error_set, pointer } = switch (opt_child_type_index) {
                         .anyerror_type => .error_set,
@@ -2609,19 +2656,19 @@ fn updateType(
                         },
                     }
 
-                    try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
+                    try wip_nav.abbrevCode(.unsigned_tagged_union_field);
                     try uleb128(diw, 0);
                     {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                        try wip_nav.abbrevCode(.generated_field);
                         try wip_nav.strp("null");
                         try wip_nav.refType(Type.null);
                         try uleb128(diw, 0);
                     }
                     try uleb128(diw, @intFromEnum(AbbrevCode.null));
 
-                    try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
+                    try wip_nav.abbrevCode(.tagged_union_default_field);
                     {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                        try wip_nav.abbrevCode(.generated_field);
                         try wip_nav.strp("?");
                         try wip_nav.refType(opt_child_type);
                         try uleb128(diw, 0);
@@ -2644,7 +2691,7 @@ fn updateType(
                 },
             };
 
-            try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
+            try wip_nav.abbrevCode(.union_type);
             try wip_nav.strp(name);
             if (error_union_type.error_set_type != .generic_poison_type and
                 error_union_type.payload_type != .generic_poison_type)
@@ -2656,7 +2703,7 @@ fn updateType(
                 try uleb128(diw, 1);
             }
             {
-                try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+                try wip_nav.abbrevCode(.tagged_union);
                 try wip_nav.infoSectionOffset(
                     .debug_info,
                     wip_nav.unit,
@@ -2664,7 +2711,7 @@ fn updateType(
                     @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
                 );
                 {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                    try wip_nav.abbrevCode(.generated_field);
                     try wip_nav.strp("is_error");
                     try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
                         .signedness = .unsigned,
@@ -2672,19 +2719,19 @@ fn updateType(
                     } })));
                     try uleb128(diw, error_union_error_set_offset);
 
-                    try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_tagged_union_field));
+                    try wip_nav.abbrevCode(.unsigned_tagged_union_field);
                     try uleb128(diw, 0);
                     {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                        try wip_nav.abbrevCode(.generated_field);
                         try wip_nav.strp("value");
                         try wip_nav.refType(error_union_payload_type);
                         try uleb128(diw, error_union_payload_offset);
                     }
                     try uleb128(diw, @intFromEnum(AbbrevCode.null));
 
-                    try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union_default_field));
+                    try wip_nav.abbrevCode(.tagged_union_default_field);
                     {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                        try wip_nav.abbrevCode(.generated_field);
                         try wip_nav.strp("error");
                         try wip_nav.refType(error_union_error_set_type);
                         try uleb128(diw, error_union_error_set_offset);
@@ -2715,7 +2762,7 @@ fn updateType(
             .c_longdouble,
             .bool,
             => {
-                try uleb128(diw, @intFromEnum(AbbrevCode.numeric_type));
+                try wip_nav.abbrevCode(.numeric_type);
                 try wip_nav.strp(name);
                 try diw.writeByte(if (type_index == .bool_type)
                     DW.ATE.boolean
@@ -2742,7 +2789,7 @@ fn updateType(
             .enum_literal,
             .generic_poison,
             => {
-                try uleb128(diw, @intFromEnum(AbbrevCode.void_type));
+                try wip_nav.abbrevCode(.void_type);
                 try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
             },
             .anyerror => return, // delay until flush
@@ -2752,15 +2799,19 @@ fn updateType(
         .union_type,
         .opaque_type,
         => unreachable,
-        .anon_struct_type => |anon_struct_type| {
-            try uleb128(diw, @intFromEnum(AbbrevCode.struct_type));
+        .anon_struct_type => |anon_struct_type| if (anon_struct_type.types.len == 0) {
+            try wip_nav.abbrevCode(.namespace_struct_type);
+            try wip_nav.strp(name);
+            try diw.writeByte(@intFromBool(false));
+        } else {
+            try wip_nav.abbrevCode(.struct_type);
             try wip_nav.strp(name);
             try uleb128(diw, ty.abiSize(pt));
             try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
             var field_byte_offset: u64 = 0;
             for (0..anon_struct_type.types.len) |field_index| {
                 const comptime_value = anon_struct_type.values.get(ip)[field_index];
-                try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (comptime_value != .none) .struct_field_comptime else .struct_field)));
+                try wip_nav.abbrevCode(if (comptime_value != .none) .struct_field_comptime else .struct_field);
                 if (anon_struct_type.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
                     const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
                     defer dwarf.gpa.free(field_name);
@@ -2780,7 +2831,7 @@ fn updateType(
         },
         .enum_type => {
             const loaded_enum = ip.loadEnumType(type_index);
-            try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
+            try wip_nav.abbrevCode(.enum_type);
             try wip_nav.strp(name);
             try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
             for (0..loaded_enum.names.len) |field_index| {
@@ -2794,7 +2845,7 @@ fn updateType(
         },
         .func_type => |func_type| {
             const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
-            try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_nullary) .nullary_func_type else .func_type)));
+            try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
             try wip_nav.strp(name);
             try diw.writeByte(@intFromEnum(@as(DW.CC, switch (func_type.cc) {
                 .Unspecified, .C => .normal,
@@ -2814,15 +2865,15 @@ fn updateType(
             try wip_nav.refType(Type.fromInterned(func_type.return_type));
             if (!is_nullary) {
                 for (0..func_type.param_types.len) |param_index| {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.func_type_param));
+                    try wip_nav.abbrevCode(.func_type_param);
                     try wip_nav.refType(Type.fromInterned(func_type.param_types.get(ip)[param_index]));
                 }
-                if (func_type.is_var_args) try uleb128(diw, @intFromEnum(AbbrevCode.is_var_args));
+                if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
                 try uleb128(diw, @intFromEnum(AbbrevCode.null));
             }
         },
         .error_set_type => |error_set_type| {
-            try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (error_set_type.names.len > 0) .enum_type else .empty_enum_type)));
+            try wip_nav.abbrevCode(if (error_set_type.names.len > 0) .enum_type else .empty_enum_type);
             try wip_nav.strp(name);
             try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
                 .signedness = .unsigned,
@@ -2830,7 +2881,7 @@ fn updateType(
             } })));
             for (0..error_set_type.names.len) |field_index| {
                 const field_name = error_set_type.names.get(ip)[field_index];
-                try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
+                try wip_nav.abbrevCode(.unsigned_enum_field);
                 try uleb128(diw, ip.getErrorValueIfExists(field_name).?);
                 try wip_nav.strp(field_name.toSlice(ip));
             }
@@ -2838,11 +2889,11 @@ fn updateType(
         },
         .inferred_error_set_type => |func| switch (ip.funcIesResolvedUnordered(func)) {
             .none => {
-                try uleb128(diw, @intFromEnum(AbbrevCode.void_type));
+                try wip_nav.abbrevCode(.void_type);
                 try wip_nav.strp(name);
             },
             else => |ies| {
-                try uleb128(diw, @intFromEnum(AbbrevCode.inferred_error_set_type));
+                try wip_nav.abbrevCode(.inferred_error_set_type);
                 try wip_nav.strp(name);
                 try wip_nav.refType(Type.fromInterned(ies));
             },
@@ -2894,7 +2945,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
             .func = .none,
             .func_sym_index = undefined,
             .func_high_reloc = undefined,
-            .inlined_funcs_high_reloc = undefined,
+            .inlined_funcs = undefined,
             .debug_info = .{},
             .debug_line = .{},
             .debug_loclists = .{},
@@ -2905,7 +2956,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
         const loaded_struct = ip.loadStructType(type_index);
 
         const diw = wip_nav.debug_info.writer(dwarf.gpa);
-        try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0) .namespace_file else .file)));
+        try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .namespace_file else .file);
         const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
         try uleb128(diw, file_gop.index);
         try wip_nav.strp(loaded_struct.name.toSlice(ip));
@@ -2914,7 +2965,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
             try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
             for (0..loaded_struct.field_types.len) |field_index| {
                 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
-                try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
+                try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
                 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
                     const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
                     defer dwarf.gpa.free(field_name);
@@ -2957,7 +3008,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
             .func = .none,
             .func_sym_index = undefined,
             .func_high_reloc = undefined,
-            .inlined_funcs_high_reloc = undefined,
+            .inlined_funcs = undefined,
             .debug_info = .{},
             .debug_line = .{},
             .debug_loclists = .{},
@@ -2973,17 +3024,14 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                 const loaded_struct = ip.loadStructType(type_index);
                 switch (loaded_struct.layout) {
                     .auto, .@"extern" => {
-                        try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (loaded_struct.field_types.len == 0)
-                            .namespace_struct_type
-                        else
-                            .struct_type)));
+                        try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .namespace_struct_type else .struct_type);
                         try wip_nav.strp(name);
                         if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
                             try uleb128(diw, ty.abiSize(pt));
                             try uleb128(diw, ty.abiAlignment(pt).toByteUnits().?);
                             for (0..loaded_struct.field_types.len) |field_index| {
                                 const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
-                                try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (is_comptime) .struct_field_comptime else .struct_field)));
+                                try wip_nav.abbrevCode(if (is_comptime) .struct_field_comptime else .struct_field);
                                 if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| try wip_nav.strp(field_name.toSlice(ip)) else {
                                     const field_name = try std.fmt.allocPrint(dwarf.gpa, "{d}", .{field_index});
                                     defer dwarf.gpa.free(field_name);
@@ -3001,12 +3049,12 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                         }
                     },
                     .@"packed" => {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.packed_struct_type));
+                        try wip_nav.abbrevCode(.packed_struct_type);
                         try wip_nav.strp(name);
                         try wip_nav.refType(Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
                         var field_bit_offset: u16 = 0;
                         for (0..loaded_struct.field_types.len) |field_index| {
-                            try uleb128(diw, @intFromEnum(@as(AbbrevCode, .packed_struct_field)));
+                            try wip_nav.abbrevCode(.packed_struct_field);
                             try wip_nav.strp(loaded_struct.fieldName(ip, field_index).unwrap().?.toSlice(ip));
                             const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
                             try wip_nav.refType(field_type);
@@ -3019,7 +3067,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
             },
             .enum_type => {
                 const loaded_enum = ip.loadEnumType(type_index);
-                try uleb128(diw, @intFromEnum(AbbrevCode.enum_type));
+                try wip_nav.abbrevCode(.enum_type);
                 try wip_nav.strp(name);
                 try wip_nav.refType(Type.fromInterned(loaded_enum.tag_ty));
                 for (0..loaded_enum.names.len) |field_index| {
@@ -3033,14 +3081,14 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
             },
             .union_type => {
                 const loaded_union = ip.loadUnionType(type_index);
-                try uleb128(diw, @intFromEnum(AbbrevCode.union_type));
+                try wip_nav.abbrevCode(.union_type);
                 try wip_nav.strp(name);
                 const union_layout = pt.getUnionLayout(loaded_union);
                 try uleb128(diw, union_layout.abi_size);
                 try uleb128(diw, union_layout.abi_align.toByteUnits().?);
                 const loaded_tag = loaded_union.loadTagType(ip);
                 if (loaded_union.hasTag(ip)) {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.tagged_union));
+                    try wip_nav.abbrevCode(.tagged_union);
                     try wip_nav.infoSectionOffset(
                         .debug_info,
                         wip_nav.unit,
@@ -3048,7 +3096,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                         @intCast(wip_nav.debug_info.items.len + dwarf.sectionOffsetBytes()),
                     );
                     {
-                        try uleb128(diw, @intFromEnum(AbbrevCode.generated_field));
+                        try wip_nav.abbrevCode(.generated_field);
                         try wip_nav.strp("tag");
                         try wip_nav.refType(Type.fromInterned(loaded_union.enum_tag_ty));
                         try uleb128(diw, union_layout.tagOffset());
@@ -3059,7 +3107,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                                 .unsigned = .unsigned_tagged_union_field,
                             }, field_index);
                             {
-                                try uleb128(diw, @intFromEnum(AbbrevCode.struct_field));
+                                try wip_nav.abbrevCode(.struct_field);
                                 try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
                                 const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
                                 try wip_nav.refType(field_type);
@@ -3075,7 +3123,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                     if (ip.indexToKey(loaded_union.enum_tag_ty).enum_type == .generated_tag)
                         try wip_nav.pending_types.append(dwarf.gpa, loaded_union.enum_tag_ty);
                 } else for (0..loaded_union.field_types.len) |field_index| {
-                    try uleb128(diw, @intFromEnum(AbbrevCode.untagged_union_field));
+                    try wip_nav.abbrevCode(.untagged_union_field);
                     try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
                     const field_type = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
                     try wip_nav.refType(field_type);
@@ -3085,7 +3133,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
                 try uleb128(diw, @intFromEnum(AbbrevCode.null));
             },
             .opaque_type => {
-                try uleb128(diw, @intFromEnum(AbbrevCode.namespace_struct_type));
+                try wip_nav.abbrevCode(.namespace_struct_type);
                 try wip_nav.strp(name);
                 try diw.writeByte(@intFromBool(true));
             },
@@ -3121,6 +3169,23 @@ pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
     _ = nav_index;
 }
 
+fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(AbbrevCode).Enum.tag_type {
+    assert(abbrev_code != .null);
+    const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
+    if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);
+    var debug_abbrev = std.ArrayList(u8).init(dwarf.gpa);
+    defer debug_abbrev.deinit();
+    const daw = debug_abbrev.writer();
+    const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
+    try uleb128(daw, @intFromEnum(abbrev_code));
+    try uleb128(daw, @intFromEnum(abbrev.tag));
+    try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
+    for (abbrev.attrs) |*attr| inline for (attr) |info| try uleb128(daw, @intFromEnum(info));
+    for (0..2) |_| try uleb128(daw, 0);
+    try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev.items);
+    return @intFromEnum(abbrev_code);
+}
+
 pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
     const ip = &pt.zcu.intern_pool;
     if (dwarf.types.get(.anyerror_type)) |entry| {
@@ -3133,7 +3198,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
             .func = .none,
             .func_sym_index = undefined,
             .func_high_reloc = undefined,
-            .inlined_funcs_high_reloc = undefined,
+            .inlined_funcs = undefined,
             .debug_info = .{},
             .debug_line = .{},
             .debug_loclists = .{},
@@ -3142,14 +3207,14 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
         defer wip_nav.deinit();
         const diw = wip_nav.debug_info.writer(dwarf.gpa);
         const global_error_set_names = ip.global_error_set.getNamesFromMainThread();
-        try uleb128(diw, @intFromEnum(@as(AbbrevCode, if (global_error_set_names.len > 0) .enum_type else .empty_enum_type)));
+        try wip_nav.abbrevCode(if (global_error_set_names.len > 0) .enum_type else .empty_enum_type);
         try wip_nav.strp("anyerror");
         try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
             .signedness = .unsigned,
             .bits = pt.zcu.errorSetBits(),
         } })));
         for (global_error_set_names, 1..) |name, value| {
-            try uleb128(diw, @intFromEnum(AbbrevCode.unsigned_enum_field));
+            try wip_nav.abbrevCode(.unsigned_enum_field);
             try uleb128(diw, value);
             try wip_nav.strp(name.toSlice(ip));
         }
@@ -3173,21 +3238,6 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
 
     var header = std.ArrayList(u8).init(dwarf.gpa);
     defer header.deinit();
-    if (dwarf.debug_abbrev.section.dirty) {
-        for (1.., &AbbrevCode.abbrevs) |code, *abbrev| {
-            try uleb128(header.writer(), code);
-            try uleb128(header.writer(), @intFromEnum(abbrev.tag));
-            try header.append(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no);
-            for (abbrev.attrs) |*attr| {
-                try uleb128(header.writer(), @intFromEnum(attr[0]));
-                try uleb128(header.writer(), @intFromEnum(attr[1]));
-            }
-            try header.appendSlice(&.{ 0, 0 });
-        }
-        try header.append(@intFromEnum(AbbrevCode.null));
-        try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, DebugAbbrev.entry, dwarf, header.items);
-        dwarf.debug_abbrev.section.dirty = false;
-    }
     if (dwarf.debug_aranges.section.dirty) {
         for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
             const unit: Unit.Index = @enumFromInt(unit_index);
@@ -3245,11 +3295,10 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
                 .source_off = @intCast(header.items.len),
                 .target_sec = .debug_abbrev,
                 .target_unit = DebugAbbrev.unit,
-                .target_entry = DebugAbbrev.entry.toOptional(),
             });
             header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
             const compile_unit_off: u32 = @intCast(header.items.len);
-            uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.compile_unit)) catch unreachable;
+            uleb128(header.fixedWriter(), try dwarf.refAbbrevCode(.compile_unit)) catch unreachable;
             header.appendAssumeCapacity(DW.LANG.Zig);
             unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
                 .source_off = @intCast(header.items.len),
@@ -3292,7 +3341,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
             });
             header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
             uleb128(header.fixedWriter(), 0) catch unreachable;
-            uleb128(header.fixedWriter(), @intFromEnum(AbbrevCode.module)) catch unreachable;
+            uleb128(header.fixedWriter(), try dwarf.refAbbrevCode(.module)) catch unreachable;
             unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
                 .source_off = @intCast(header.items.len),
                 .target_sec = .debug_str,
@@ -3306,6 +3355,11 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
         }
         dwarf.debug_info.section.dirty = false;
     }
+    if (dwarf.debug_abbrev.section.dirty) {
+        assert(!dwarf.debug_info.section.dirty);
+        try dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).writeTrailer(&dwarf.debug_abbrev.section, dwarf);
+        dwarf.debug_abbrev.section.dirty = false;
+    }
     if (dwarf.debug_str.section.dirty) {
         const contents = dwarf.debug_str.contents.items;
         try dwarf.debug_str.section.resize(dwarf, contents.len);
@@ -3313,8 +3367,11 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
         dwarf.debug_str.section.dirty = false;
     }
     if (dwarf.debug_line.section.dirty) {
-        for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit|
-            try unit.resizeHeader(&dwarf.debug_line.section, dwarf, DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())));
+        for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| try unit.resizeHeader(
+            &dwarf.debug_line.section,
+            dwarf,
+            DebugLine.headerBytes(dwarf, @intCast(mod_info.dirs.count()), @intCast(mod_info.files.count())),
+        );
         for (dwarf.mods.values(), dwarf.debug_line.section.units.items) |mod_info, *unit| {
             unit.clear();
             try unit.cross_section_relocs.ensureTotalCapacity(dwarf.gpa, 2 * (1 + mod_info.files.count()));
@@ -3333,14 +3390,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
             }
             std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
             header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
-            switch (dwarf.format) {
-                inline .@"32", .@"64" => |format| std.mem.writeInt(
-                    SectionOffset(format),
-                    header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
-                    @intCast(unit.header_len - header.items.len),
-                    dwarf.endian,
-                ),
-            }
+            dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), unit.header_len - header.items.len);
             const StandardOpcode = DeclValEnum(DW.LNS);
             header.appendSliceAssumeCapacity(&[_]u8{
                 dwarf.debug_line.header.minimum_instruction_length,
@@ -3422,6 +3472,9 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
         try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off);
         dwarf.debug_line_str.section.dirty = false;
     }
+    if (dwarf.debug_loclists.section.dirty) {
+        dwarf.debug_loclists.section.dirty = false;
+    }
     if (dwarf.debug_rnglists.section.dirty) {
         for (dwarf.debug_rnglists.section.units.items) |*unit| {
             header.clearRetainingCapacity();
@@ -3440,19 +3493,20 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
             std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);
             header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
             std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);
-            switch (dwarf.format) {
-                inline .@"32", .@"64" => |format| std.mem.writeInt(
-                    SectionOffset(format),
-                    header.addManyAsArrayAssumeCapacity(@sizeOf(SectionOffset(format))),
-                    @sizeOf(SectionOffset(format)),
-                    dwarf.endian,
-                ),
-            }
+            dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), dwarf.sectionOffsetBytes() * 1);
             try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
             try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
         }
         dwarf.debug_rnglists.section.dirty = false;
     }
+    assert(!dwarf.debug_abbrev.section.dirty);
+    assert(!dwarf.debug_aranges.section.dirty);
+    assert(!dwarf.debug_info.section.dirty);
+    assert(!dwarf.debug_line.section.dirty);
+    assert(!dwarf.debug_line_str.section.dirty);
+    assert(!dwarf.debug_loclists.section.dirty);
+    assert(!dwarf.debug_rnglists.section.dirty);
+    assert(!dwarf.debug_str.section.dirty);
 }
 
 pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
@@ -3491,7 +3545,7 @@ fn DeclValEnum(comptime T: type) type {
     } });
 }
 
-const AbbrevCode = enum(u8) {
+const AbbrevCode = enum {
     null,
     // padding codes must be one byte uleb128 values to function
     pad_1,
@@ -3499,15 +3553,16 @@ const AbbrevCode = enum(u8) {
     // decl codes are assumed to all have the same uleb128 length
     decl_alias,
     decl_enum,
+    decl_empty_enum,
     decl_namespace_struct,
     decl_struct,
     decl_packed_struct,
     decl_union,
     decl_var,
     decl_func,
-    decl_func_empty,
+    decl_empty_func,
     decl_func_generic,
-    decl_func_generic_empty,
+    decl_empty_func_generic,
     // the rest are unrestricted
     compile_unit,
     module,
@@ -3542,11 +3597,12 @@ const AbbrevCode = enum(u8) {
     struct_type,
     packed_struct_type,
     union_type,
+    empty_inlined_func,
     inlined_func,
     local_arg,
     local_var,
 
-    const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_func_generic_empty));
+    const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_empty_func_generic));
 
     const Attr = struct {
         DeclValEnum(DW.AT),
@@ -3586,6 +3642,12 @@ const AbbrevCode = enum(u8) {
                 .{ .type, .ref_addr },
             },
         },
+        .decl_empty_enum = .{
+            .tag = .enumeration_type,
+            .attrs = decl_abbrev_common_attrs ++ .{
+                .{ .type, .ref_addr },
+            },
+        },
         .decl_namespace_struct = .{
             .tag = .structure_type,
             .attrs = decl_abbrev_common_attrs ++ .{
@@ -3638,7 +3700,7 @@ const AbbrevCode = enum(u8) {
                 .{ .noreturn, .flag },
             },
         },
-        .decl_func_empty = .{
+        .decl_empty_func = .{
             .tag = .subprogram,
             .attrs = decl_abbrev_common_attrs ++ .{
                 .{ .linkage_name, .strp },
@@ -3657,7 +3719,7 @@ const AbbrevCode = enum(u8) {
                 .{ .type, .ref_addr },
             },
         },
-        .decl_func_generic_empty = .{
+        .decl_empty_func_generic = .{
             .tag = .subprogram,
             .attrs = decl_abbrev_common_attrs ++ .{
                 .{ .type, .ref_addr },
@@ -3918,6 +3980,16 @@ const AbbrevCode = enum(u8) {
                 .{ .alignment, .udata },
             },
         },
+        .empty_inlined_func = .{
+            .tag = .inlined_subroutine,
+            .attrs = &.{
+                .{ .abstract_origin, .ref_addr },
+                .{ .call_line, .udata },
+                .{ .call_column, .udata },
+                .{ .low_pc, .addr },
+                .{ .high_pc, .addr },
+            },
+        },
         .inlined_func = .{
             .tag = .inlined_subroutine,
             .children = true,
@@ -3946,7 +4018,7 @@ const AbbrevCode = enum(u8) {
             },
         },
         .null = undefined,
-    }).values[1..].*;
+    });
 };
 
 fn getFile(dwarf: *Dwarf) ?std.fs.File {
@@ -3955,11 +4027,11 @@ fn getFile(dwarf: *Dwarf) ?std.fs.File {
 }
 
 fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
-    const entry = try dwarf.debug_aranges.section.addEntry(unit, dwarf);
-    assert(try dwarf.debug_info.section.addEntry(unit, dwarf) == entry);
-    assert(try dwarf.debug_line.section.addEntry(unit, dwarf) == entry);
-    assert(try dwarf.debug_loclists.section.addEntry(unit, dwarf) == entry);
-    assert(try dwarf.debug_rnglists.section.addEntry(unit, dwarf) == entry);
+    const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
+    assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+    assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+    assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
+    assert(try dwarf.debug_rnglists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
     return entry;
 }
 
@@ -3993,13 +4065,6 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
     };
 }
 
-fn SectionOffset(comptime format: DW.Format) type {
-    return switch (format) {
-        .@"32" => u32,
-        .@"64" => u64,
-    };
-}
-
 fn uleb128Bytes(value: anytype) u32 {
     var cw = std.io.countingWriter(std.io.null_writer);
     try uleb128(cw.writer(), value);